Commit c1a9ec901fbaffa802c29f5986f28de8a34ed094
1 parent
6ae22fe0
this is solution for the bug touch with labex
Showing
3 changed files
with
410 additions
and
8 deletions
400-SOURCECODE/AIAHTML5.Web/app/controllers/LabExercController.js
... | ... | @@ -401,7 +401,7 @@ function ($scope, $rootScope, pages, log, $http,$timeout, DataService, $filter, |
401 | 401 | |
402 | 402 | this.style.opacity = '0.4'; |
403 | 403 | var $ua = navigator.userAgent; |
404 | - if ($.browser.msie || ($ua.match(/(iPod|iPhone|iPad|android)/i))) { | |
404 | + if ($.browser.msie) { | |
405 | 405 | localStorage.setItem("text", this.innerHTML); |
406 | 406 | } |
407 | 407 | else |
... | ... | @@ -471,7 +471,7 @@ function ($scope, $rootScope, pages, log, $http,$timeout, DataService, $filter, |
471 | 471 | |
472 | 472 | var keywords = $location.search(); |
473 | 473 | var $ua = navigator.userAgent; |
474 | - if ($.browser.msie || ($ua.match(/(iPod|iPhone|iPad|android)/i))) { | |
474 | + if ($.browser.msie) { | |
475 | 475 | dataText = localStorage.getItem("text"); |
476 | 476 | localStorage.setItem("text", ''); |
477 | 477 | } |
... | ... | @@ -1051,9 +1051,6 @@ AIA.directive('draggable', function () { |
1051 | 1051 | link: function ($scope, element, attrs) { |
1052 | 1052 | element[0].addEventListener('dragstart', $scope.handleDragStart, false); |
1053 | 1053 | element[0].addEventListener('dragend', $scope.handleDragEnd, false); |
1054 | - | |
1055 | - element[0].addEventListener('touchstart', $scope.handleDragStart, false); | |
1056 | - element[0].addEventListener('touchend', $scope.handleDragEnd, false); | |
1057 | 1054 | } |
1058 | 1055 | } |
1059 | 1056 | }); |
... | ... | @@ -1063,9 +1060,6 @@ AIA.directive('droppable', function () { |
1063 | 1060 | link: function ($scope, element, attrs) { |
1064 | 1061 | element[0].addEventListener('drop', $scope.handleDrop, false); |
1065 | 1062 | element[0].addEventListener('dragover', $scope.handleDragOver, false); |
1066 | - | |
1067 | - element[0].addEventListener('touchmove', $scope.handleDragOver, false); | |
1068 | - element[0].addEventListener('touchend', $scope.handleDrop, false); | |
1069 | 1063 | } |
1070 | 1064 | } |
1071 | 1065 | }); | ... | ... |
400-SOURCECODE/AIAHTML5.Web/app/views/LabExerc/LabExerc-view.html
400-SOURCECODE/AIAHTML5.Web/libs/DragDropTouch.js
0 → 100644
1 | +var DragDropTouch; | |
2 | +(function (DragDropTouch_1) { | |
3 | + 'use strict'; | |
4 | + /** | |
5 | + * Object used to hold the data that is being dragged during drag and drop operations. | |
6 | + * | |
7 | + * It may hold one or more data items of different types. For more information about | |
8 | + * drag and drop operations and data transfer objects, see | |
9 | + * <a href="https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer">HTML Drag and Drop API</a>. | |
10 | + * | |
11 | + * This object is created automatically by the @see:DragDropTouch singleton and is | |
12 | + * accessible through the @see:dataTransfer property of all drag events. | |
13 | + */ | |
14 | + var DataTransfer = (function () { | |
15 | + function DataTransfer() { | |
16 | + this._dropEffect = 'move'; | |
17 | + this._effectAllowed = 'all'; | |
18 | + this._data = {}; | |
19 | + } | |
20 | + Object.defineProperty(DataTransfer.prototype, "dropEffect", { | |
21 | + /** | |
22 | + * Gets or sets the type of drag-and-drop operation currently selected. | |
23 | + * The value must be 'none', 'copy', 'link', or 'move'. | |
24 | + */ | |
25 | + get: function () { | |
26 | + return this._dropEffect; | |
27 | + }, | |
28 | + set: function (value) { | |
29 | + this._dropEffect = value; | |
30 | + }, | |
31 | + enumerable: true, | |
32 | + configurable: true | |
33 | + }); | |
34 | + Object.defineProperty(DataTransfer.prototype, "effectAllowed", { | |
35 | + /** | |
36 | + * Gets or sets the types of operations that are possible. | |
37 | + * Must be one of 'none', 'copy', 'copyLink', 'copyMove', 'link', | |
38 | + * 'linkMove', 'move', 'all' or 'uninitialized'. | |
39 | + */ | |
40 | + get: function () { | |
41 | + return this._effectAllowed; | |
42 | + }, | |
43 | + set: function (value) { | |
44 | + this._effectAllowed = value; | |
45 | + }, | |
46 | + enumerable: true, | |
47 | + configurable: true | |
48 | + }); | |
49 | + Object.defineProperty(DataTransfer.prototype, "types", { | |
50 | + /** | |
51 | + * Gets an array of strings giving the formats that were set in the @see:dragstart event. | |
52 | + */ | |
53 | + get: function () { | |
54 | + return Object.keys(this._data); | |
55 | + }, | |
56 | + enumerable: true, | |
57 | + configurable: true | |
58 | + }); | |
59 | + /** | |
60 | + * Removes the data associated with a given type. | |
61 | + * | |
62 | + * The type argument is optional. If the type is empty or not specified, the data | |
63 | + * associated with all types is removed. If data for the specified type does not exist, | |
64 | + * or the data transfer contains no data, this method will have no effect. | |
65 | + * | |
66 | + * @param type Type of data to remove. | |
67 | + */ | |
68 | + DataTransfer.prototype.clearData = function (type) { | |
69 | + if (type != null) { | |
70 | + delete this._data[type]; | |
71 | + } | |
72 | + else { | |
73 | + this._data = null; | |
74 | + } | |
75 | + }; | |
76 | + /** | |
77 | + * Retrieves the data for a given type, or an empty string if data for that type does | |
78 | + * not exist or the data transfer contains no data. | |
79 | + * | |
80 | + * @param type Type of data to retrieve. | |
81 | + */ | |
82 | + DataTransfer.prototype.getData = function (type) { | |
83 | + return this._data[type] || ''; | |
84 | + }; | |
85 | + /** | |
86 | + * Set the data for a given type. | |
87 | + * | |
88 | + * For a list of recommended drag types, please see | |
89 | + * https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Recommended_Drag_Types. | |
90 | + * | |
91 | + * @param type Type of data to add. | |
92 | + * @param value Data to add. | |
93 | + */ | |
94 | + DataTransfer.prototype.setData = function (type, value) { | |
95 | + this._data[type] = value; | |
96 | + }; | |
97 | + /** | |
98 | + * Set the image to be used for dragging if a custom one is desired. | |
99 | + * | |
100 | + * @param img An image element to use as the drag feedback image. | |
101 | + * @param offsetX The horizontal offset within the image. | |
102 | + * @param offsetY The vertical offset within the image. | |
103 | + */ | |
104 | + DataTransfer.prototype.setDragImage = function (img, offsetX, offsetY) { | |
105 | + var ddt = DragDropTouch._instance; | |
106 | + ddt._imgCustom = img; | |
107 | + ddt._imgOffset = { x: offsetX, y: offsetY }; | |
108 | + }; | |
109 | + return DataTransfer; | |
110 | + }()); | |
111 | + DragDropTouch_1.DataTransfer = DataTransfer; | |
112 | + /** | |
113 | + * Defines a class that adds support for touch-based HTML5 drag/drop operations. | |
114 | + * | |
115 | + * The @see:DragDropTouch class listens to touch events and raises the | |
116 | + * appropriate HTML5 drag/drop events as if the events had been caused | |
117 | + * by mouse actions. | |
118 | + * | |
119 | + * The purpose of this class is to enable using existing, standard HTML5 | |
120 | + * drag/drop code on mobile devices running IOS or Android. | |
121 | + * | |
122 | + * To use, include the DragDropTouch.js file on the page. The class will | |
123 | + * automatically start monitoring touch events and will raise the HTML5 | |
124 | + * drag drop events (dragstart, dragenter, dragleave, drop, dragend) which | |
125 | + * should be handled by the application. | |
126 | + * | |
127 | + * For details and examples on HTML drag and drop, see | |
128 | + * https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Drag_operations. | |
129 | + */ | |
130 | + var DragDropTouch = (function () { | |
131 | + /** | |
132 | + * Initializes the single instance of the @see:DragDropTouch class. | |
133 | + */ | |
134 | + function DragDropTouch() { | |
135 | + this._lastClick = 0; | |
136 | + // enforce singleton pattern | |
137 | + if (DragDropTouch._instance) { | |
138 | + throw 'DragDropTouch instance already created.'; | |
139 | + } | |
140 | + // detect passive event support | |
141 | + // https://github.com/Modernizr/Modernizr/issues/1894 | |
142 | + var supportsPassive = false; | |
143 | + document.addEventListener('test', function () { }, { | |
144 | + get passive() { | |
145 | + supportsPassive = true; | |
146 | + return true; | |
147 | + } | |
148 | + }); | |
149 | + // listen to touch events | |
150 | + if ('ontouchstart' in document) { | |
151 | + var d = document, ts = this._touchstart.bind(this), tm = this._touchmove.bind(this), te = this._touchend.bind(this), opt = supportsPassive ? { passive: false, capture: false } : false; | |
152 | + d.addEventListener('touchstart', ts, opt); | |
153 | + d.addEventListener('touchmove', tm, opt); | |
154 | + d.addEventListener('touchend', te); | |
155 | + d.addEventListener('touchcancel', te); | |
156 | + } | |
157 | + } | |
158 | + /** | |
159 | + * Gets a reference to the @see:DragDropTouch singleton. | |
160 | + */ | |
161 | + DragDropTouch.getInstance = function () { | |
162 | + return DragDropTouch._instance; | |
163 | + }; | |
164 | + // ** event handlers | |
165 | + DragDropTouch.prototype._touchstart = function (e) { | |
166 | + var _this = this; | |
167 | + if (this._shouldHandle(e)) { | |
168 | + // raise double-click and prevent zooming | |
169 | + if (Date.now() - this._lastClick < DragDropTouch._DBLCLICK) { | |
170 | + if (this._dispatchEvent(e, 'dblclick', e.target)) { | |
171 | + e.preventDefault(); | |
172 | + this._reset(); | |
173 | + return; | |
174 | + } | |
175 | + } | |
176 | + // clear all variables | |
177 | + this._reset(); | |
178 | + // get nearest draggable element | |
179 | + var src = this._closestDraggable(e.target); | |
180 | + if (src) { | |
181 | + // give caller a chance to handle the hover/move events | |
182 | + if (!this._dispatchEvent(e, 'mousemove', e.target) && | |
183 | + !this._dispatchEvent(e, 'mousedown', e.target)) { | |
184 | + // get ready to start dragging | |
185 | + this._dragSource = src; | |
186 | + this._ptDown = this._getPoint(e); | |
187 | + this._lastTouch = e; | |
188 | + e.preventDefault(); | |
189 | + // show context menu if the user hasn't started dragging after a while | |
190 | + setTimeout(function () { | |
191 | + if (_this._dragSource == src && _this._img == null) { | |
192 | + if (_this._dispatchEvent(e, 'contextmenu', src)) { | |
193 | + _this._reset(); | |
194 | + } | |
195 | + } | |
196 | + }, DragDropTouch._CTXMENU); | |
197 | + } | |
198 | + } | |
199 | + } | |
200 | + }; | |
201 | + DragDropTouch.prototype._touchmove = function (e) { | |
202 | + if (this._shouldHandle(e)) { | |
203 | + // see if target wants to handle move | |
204 | + var target = this._getTarget(e); | |
205 | + if (this._dispatchEvent(e, 'mousemove', target)) { | |
206 | + this._lastTouch = e; | |
207 | + e.preventDefault(); | |
208 | + return; | |
209 | + } | |
210 | + // start dragging | |
211 | + if (this._dragSource && !this._img) { | |
212 | + var delta = this._getDelta(e); | |
213 | + if (delta > DragDropTouch._THRESHOLD) { | |
214 | + this._dispatchEvent(e, 'dragstart', this._dragSource); | |
215 | + this._createImage(e); | |
216 | + this._dispatchEvent(e, 'dragenter', target); | |
217 | + } | |
218 | + } | |
219 | + // continue dragging | |
220 | + if (this._img) { | |
221 | + this._lastTouch = e; | |
222 | + e.preventDefault(); // prevent scrolling | |
223 | + if (target != this._lastTarget) { | |
224 | + this._dispatchEvent(this._lastTouch, 'dragleave', this._lastTarget); | |
225 | + this._dispatchEvent(e, 'dragenter', target); | |
226 | + this._lastTarget = target; | |
227 | + } | |
228 | + this._moveImage(e); | |
229 | + this._dispatchEvent(e, 'dragover', target); | |
230 | + } | |
231 | + } | |
232 | + }; | |
233 | + DragDropTouch.prototype._touchend = function (e) { | |
234 | + if (this._shouldHandle(e)) { | |
235 | + // see if target wants to handle up | |
236 | + if (this._dispatchEvent(this._lastTouch, 'mouseup', e.target)) { | |
237 | + e.preventDefault(); | |
238 | + return; | |
239 | + } | |
240 | + // user clicked the element but didn't drag, so clear the source and simulate a click | |
241 | + if (!this._img) { | |
242 | + this._dragSource = null; | |
243 | + this._dispatchEvent(this._lastTouch, 'click', e.target); | |
244 | + this._lastClick = Date.now(); | |
245 | + } | |
246 | + // finish dragging | |
247 | + this._destroyImage(); | |
248 | + if (this._dragSource) { | |
249 | + if (e.type.indexOf('cancel') < 0) { | |
250 | + this._dispatchEvent(this._lastTouch, 'drop', this._lastTarget); | |
251 | + } | |
252 | + this._dispatchEvent(this._lastTouch, 'dragend', this._dragSource); | |
253 | + this._reset(); | |
254 | + } | |
255 | + } | |
256 | + }; | |
257 | + // ** utilities | |
258 | + // ignore events that have been handled or that involve more than one touch | |
259 | + DragDropTouch.prototype._shouldHandle = function (e) { | |
260 | + return e && | |
261 | + !e.defaultPrevented && | |
262 | + e.touches && e.touches.length < 2; | |
263 | + }; | |
264 | + // clear all members | |
265 | + DragDropTouch.prototype._reset = function () { | |
266 | + this._destroyImage(); | |
267 | + this._dragSource = null; | |
268 | + this._lastTouch = null; | |
269 | + this._lastTarget = null; | |
270 | + this._ptDown = null; | |
271 | + this._dataTransfer = new DataTransfer(); | |
272 | + }; | |
273 | + // get point for a touch event | |
274 | + DragDropTouch.prototype._getPoint = function (e, page) { | |
275 | + if (e && e.touches) { | |
276 | + e = e.touches[0]; | |
277 | + } | |
278 | + return { x: page ? e.pageX : e.clientX, y: page ? e.pageY : e.clientY }; | |
279 | + }; | |
280 | + // get distance between the current touch event and the first one | |
281 | + DragDropTouch.prototype._getDelta = function (e) { | |
282 | + var p = this._getPoint(e); | |
283 | + return Math.abs(p.x - this._ptDown.x) + Math.abs(p.y - this._ptDown.y); | |
284 | + }; | |
285 | + // get the element at a given touch event | |
286 | + DragDropTouch.prototype._getTarget = function (e) { | |
287 | + var pt = this._getPoint(e), el = document.elementFromPoint(pt.x, pt.y); | |
288 | + while (el && getComputedStyle(el).pointerEvents == 'none') { | |
289 | + el = el.parentElement; | |
290 | + } | |
291 | + return el; | |
292 | + }; | |
293 | + // create drag image from source element | |
294 | + DragDropTouch.prototype._createImage = function (e) { | |
295 | + // just in case... | |
296 | + if (this._img) { | |
297 | + this._destroyImage(); | |
298 | + } | |
299 | + // create drag image from custom element or drag source | |
300 | + var src = this._imgCustom || this._dragSource; | |
301 | + this._img = src.cloneNode(true); | |
302 | + this._copyStyle(src, this._img); | |
303 | + this._img.style.top = this._img.style.left = '-9999px'; | |
304 | + // if creating from drag source, apply offset and opacity | |
305 | + if (!this._imgCustom) { | |
306 | + var rc = src.getBoundingClientRect(), pt = this._getPoint(e); | |
307 | + this._imgOffset = { x: pt.x - rc.left, y: pt.y - rc.top }; | |
308 | + this._img.style.opacity = DragDropTouch._OPACITY.toString(); | |
309 | + } | |
310 | + // add image to document | |
311 | + this._moveImage(e); | |
312 | + document.body.appendChild(this._img); | |
313 | + }; | |
314 | + // dispose of drag image element | |
315 | + DragDropTouch.prototype._destroyImage = function () { | |
316 | + if (this._img && this._img.parentElement) { | |
317 | + this._img.parentElement.removeChild(this._img); | |
318 | + } | |
319 | + this._img = null; | |
320 | + this._imgCustom = null; | |
321 | + }; | |
322 | + // move the drag image element | |
323 | + DragDropTouch.prototype._moveImage = function (e) { | |
324 | + var _this = this; | |
325 | + if (this._img) { | |
326 | + requestAnimationFrame(function () { | |
327 | + var pt = _this._getPoint(e, true), s = _this._img.style; | |
328 | + s.position = 'absolute'; | |
329 | + s.pointerEvents = 'none'; | |
330 | + s.zIndex = '999999'; | |
331 | + s.left = Math.round(pt.x - _this._imgOffset.x) + 'px'; | |
332 | + s.top = Math.round(pt.y - _this._imgOffset.y) + 'px'; | |
333 | + }); | |
334 | + } | |
335 | + }; | |
336 | + // copy properties from an object to another | |
337 | + DragDropTouch.prototype._copyProps = function (dst, src, props) { | |
338 | + for (var i = 0; i < props.length; i++) { | |
339 | + var p = props[i]; | |
340 | + dst[p] = src[p]; | |
341 | + } | |
342 | + }; | |
343 | + DragDropTouch.prototype._copyStyle = function (src, dst) { | |
344 | + // remove potentially troublesome attributes | |
345 | + DragDropTouch._rmvAtts.forEach(function (att) { | |
346 | + dst.removeAttribute(att); | |
347 | + }); | |
348 | + // copy canvas content | |
349 | + if (src instanceof HTMLCanvasElement) { | |
350 | + var cSrc = src, cDst = dst; | |
351 | + cDst.width = cSrc.width; | |
352 | + cDst.height = cSrc.height; | |
353 | + cDst.getContext('2d').drawImage(cSrc, 0, 0); | |
354 | + } | |
355 | + // copy style (without transitions) | |
356 | + var cs = getComputedStyle(src); | |
357 | + for (var i = 0; i < cs.length; i++) { | |
358 | + var key = cs[i]; | |
359 | + if (key.indexOf('transition') < 0) { | |
360 | + dst.style[key] = cs[key]; | |
361 | + } | |
362 | + } | |
363 | + dst.style.pointerEvents = 'none'; | |
364 | + // and repeat for all children | |
365 | + for (var i = 0; i < src.children.length; i++) { | |
366 | + this._copyStyle(src.children[i], dst.children[i]); | |
367 | + } | |
368 | + }; | |
369 | + DragDropTouch.prototype._dispatchEvent = function (e, type, target) { | |
370 | + if (e && target) { | |
371 | + var evt = document.createEvent('Event'), t = e.touches ? e.touches[0] : e; | |
372 | + evt.initEvent(type, true, true); | |
373 | + evt.button = 0; | |
374 | + evt.which = evt.buttons = 1; | |
375 | + this._copyProps(evt, e, DragDropTouch._kbdProps); | |
376 | + this._copyProps(evt, t, DragDropTouch._ptProps); | |
377 | + evt.dataTransfer = this._dataTransfer; | |
378 | + target.dispatchEvent(evt); | |
379 | + return evt.defaultPrevented; | |
380 | + } | |
381 | + return false; | |
382 | + }; | |
383 | + // gets an element's closest draggable ancestor | |
384 | + DragDropTouch.prototype._closestDraggable = function (e) { | |
385 | + for (; e; e = e.parentElement) { | |
386 | + if (e.hasAttribute('draggable') && e.draggable) { | |
387 | + return e; | |
388 | + } | |
389 | + } | |
390 | + return null; | |
391 | + }; | |
392 | + return DragDropTouch; | |
393 | + }()); | |
394 | + /*private*/ DragDropTouch._instance = new DragDropTouch(); // singleton | |
395 | + // constants | |
396 | + DragDropTouch._THRESHOLD = 5; // pixels to move before drag starts | |
397 | + DragDropTouch._OPACITY = 0.5; // drag image opacity | |
398 | + DragDropTouch._DBLCLICK = 500; // max ms between clicks in a double click | |
399 | + DragDropTouch._CTXMENU = 900; // ms to hold before raising 'contextmenu' event | |
400 | + // copy styles/attributes from drag source to drag image element | |
401 | + DragDropTouch._rmvAtts = 'id,class,style,draggable'.split(','); | |
402 | + // synthesize and dispatch an event | |
403 | + // returns true if the event has been handled (e.preventDefault == true) | |
404 | + DragDropTouch._kbdProps = 'altKey,ctrlKey,metaKey,shiftKey'.split(','); | |
405 | + DragDropTouch._ptProps = 'pageX,pageY,clientX,clientY,screenX,screenY'.split(','); | |
406 | + DragDropTouch_1.DragDropTouch = DragDropTouch; | |
407 | +})(DragDropTouch || (DragDropTouch = {})); | |
0 | 408 | \ No newline at end of file | ... | ... |