greensock-rails 1.15.1.0 → 1.16.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  /*!
2
- * VERSION: 0.11.0
3
- * DATE: 2015-01-20
2
+ * VERSION: 0.12.0
3
+ * DATE: 2015-03-01
4
4
  * UPDATES AND DOCS AT: http://greensock.com
5
5
  *
6
6
  * Requires TweenLite and CSSPlugin version 1.11.0 or later (TweenMax contains both TweenLite and CSSPlugin). ThrowPropsPlugin is required for momentum-based continuation of movement after the mouse/touch is released (ThrowPropsPlugin is a membership benefit of Club GreenSock - http://www.greensock.com/club/).
@@ -31,7 +31,8 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
31
31
  _RAD2DEG = 180 / Math.PI,
32
32
  _max = 999999999999999,
33
33
  _getTime = Date.now || function() {return new Date().getTime();},
34
- _isOldIE = (!_doc.addEventListener && _doc.all),
34
+ _isOldIE = !!(!_doc.addEventListener && _doc.all),
35
+ _placeholderDiv = _doc.createElement("div"),
35
36
  _renderQueue = [],
36
37
  _lookup = {}, //when a Draggable is created, the target gets a unique _gsDragID property that allows gets associated with the Draggable instance for quick lookups in Draggable.get(). This avoids circular references that could cause gc problems.
37
38
  _lookupCount = 0,
@@ -40,6 +41,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
40
41
  _prefix,
41
42
  _isMultiTouching,
42
43
  _lastDragTime = 0,
44
+ _windowProxy = {}, //memory/performance optimizatin - we reuse this object during autoScroll to store window-related bounds/offsets.
43
45
  _slice = function(a) { //don't use Array.prototype.slice.call(target, 0) because that doesn't work in IE8 with a NodeList that's returned by querySelectorAll()
44
46
  if (typeof(a) === "string") {
45
47
  a = TweenLite.selector(a);
@@ -97,6 +99,42 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
97
99
  _getDocScrollLeft = function() {
98
100
  return (window.pageXOffset != null) ? window.pageXOffset : (_doc.scrollLeft != null) ? _doc.scrollLeft : _docElement.scrollLeft || _doc.body.scrollLeft || 0;
99
101
  },
102
+ _addScrollListener = function(e, callback) {
103
+ _addListener(e, "scroll", callback);
104
+ if (!_isRoot(e.parentNode)) {
105
+ _addScrollListener(e.parentNode, callback);
106
+ }
107
+ },
108
+ _removeScrollListener = function(e, callback) {
109
+ _removeListener(e, "scroll", callback);
110
+ if (!_isRoot(e.parentNode)) {
111
+ _removeScrollListener(e.parentNode, callback);
112
+ }
113
+ },
114
+ _isRoot = function (e) {
115
+ return !!(!e || e === _docElement || e === _doc || e === _doc.body || e === window || !e.nodeType || !e.parentNode);
116
+ },
117
+ _getMaxScroll = function(element, axis) {
118
+ var dim = (axis === "x") ? "Width" : "Height",
119
+ scroll = "scroll" + dim,
120
+ client = "client" + dim,
121
+ body = _doc.body;
122
+ return Math.max(0, _isRoot(element) ? Math.max(_docElement[scroll], body[scroll]) - (window["inner" + dim] || _docElement[client] || body[client]) : element[scroll] - element[client]);
123
+ },
124
+ _recordMaxScrolls = function(e) { //records _gsMaxScrollX and _gsMaxScrollY properties for the element and all ancestors up the chain so that we can cap it, otherwise dragging beyond the edges with autoScroll on can endlessly scroll.
125
+ var isRoot = _isRoot(e),
126
+ x = _getMaxScroll(e, "x"),
127
+ y = _getMaxScroll(e, "y");
128
+ if (isRoot) {
129
+ e = _windowProxy;
130
+ } else {
131
+ _recordMaxScrolls(e.parentNode);
132
+ }
133
+ e._gsMaxScrollX = x;
134
+ e._gsMaxScrollY = y;
135
+ e._gsScrollX = e.scrollLeft || 0;
136
+ e._gsScrollY = e.scrollTop || 0;
137
+ },
100
138
 
101
139
  //just used for IE8 and earlier to normalize events and populate pageX/pageY
102
140
  _populateIEEvent = function(e, preventDefault) {
@@ -196,7 +234,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
196
234
  if (_getStyle(t, "position", true) !== "absolute") { return 0; }
197
235
  var dim = ((p === "left") ? "Left" : "Top"),
198
236
  v = _getStyle(t, "margin" + dim, true);
199
- return t["offset" + dim] - (_convertToPixels(t, p, parseFloat(v), v.replace(_suffixExp, "")) || 0);
237
+ return t["offset" + dim] - (_convertToPixels(t, p, parseFloat(v), (v + "").replace(_suffixExp, "")) || 0);
200
238
  },
201
239
 
202
240
  _getStyle = function(element, prop, keepUnits) {
@@ -267,22 +305,49 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
267
305
  svg.appendChild(e);
268
306
  return svg;
269
307
  }()),
270
- _getSVGOffsets = function(e) { //SVG elements don't always report offsetTop/offsetLeft/offsetParent at all (I'm looking at you, Firefox 29), so we have to do some work to manufacture those values.
308
+ _SVGElement = window.SVGElement,
309
+ _isSVG = function(e) {
310
+ return !!(_SVGElement && typeof(e.getBBox) === "function" && e.getCTM && (!e.parentNode || (e.parentNode.getBBox && e.parentNode.getCTM)));
311
+ },
312
+ _svgAttributes = ["class","viewBox","width","height","xml:space"],
313
+ _getSVGOffsets = function(e) { //SVG elements don't always report offsetTop/offsetLeft/offsetParent at all (I'm looking at you, Firefox 29), so we have to do some work to manufacture those values. You can pass any SVG element and it'll spit back an object with offsetTop, offsetLeft, offsetParent, scaleX, and scaleY properties. We need the scaleX and scaleY to handle the way SVG can resize itself based on the container.
271
314
  if (!e.getBoundingClientRect || !e.parentNode) {
272
- return {offsetTop:0, offsetLeft:0, offsetParent:_docElement};
315
+ return {offsetTop:0, offsetLeft:0, scaleX:1, scaleY:1, offsetParent:_docElement};
316
+ }
317
+ if (e._gsSVGData && e._gsSVGData.lastUpdate === TweenLite.ticker.frame) {
318
+ return e._gsSVGData;
273
319
  }
274
320
  var curElement = e,
275
321
  prevCSS = e.style.cssText,
276
- eRect, parentRect, offsetParent;
322
+ data = e._gsSVGData = e._gsSVGData || {},
323
+ eRect, parentRect, offsetParent, rRect, i, a;
324
+ if ((e.nodeName + "").toLowerCase() !== "svg" && e.getBBox) { //if it's a nested/child SVG element, we must find the parent SVG canvas and measure the offset from there.
325
+ curElement = e.parentNode;
326
+ eRect = e.getBBox();
327
+ while (curElement && (curElement.nodeName + "").toLowerCase() !== "svg") {
328
+ curElement = curElement.parentNode;
329
+ }
330
+ data = _getSVGOffsets(curElement);
331
+ return {offsetTop:eRect.y * data.scaleY, offsetLeft:eRect.x * data.scaleX, scaleX:data.scaleX, scaleY:data.scaleY, offsetParent:curElement || _docElement};
332
+ }
277
333
  while (!curElement.offsetParent && curElement.parentNode) {
278
334
  curElement = curElement.parentNode;
279
335
  }
280
- e.parentNode.insertBefore(_dummySVGRect, e); //Firefox measures things based NOT on the <svg> itself, but on the bounds of the child elements, so we add a dummy SVG object temporarily in the original one's spot which has a 1x1 <rect> in the upper left corner to make sure we're getting accurate results.
336
+ e.parentNode.insertBefore(_dummySVGRect, e); //Firefox measures things based NOT on the <svg> itself, but on the bounds of the child elements, so we add a dummy SVG object temporarily in the original one's spot which has a 10x10 <rect> in the upper left corner to make sure we're getting accurate results.
281
337
  e.parentNode.removeChild(e);
282
338
  _dummySVGRect.style.cssText = prevCSS;
283
339
  _dummySVGRect.style[_transformProp] = "none";
284
- _dummySVGRect.setAttribute("class", e.getAttribute("class"));
340
+ i = _svgAttributes.length;
341
+ while (--i > -1) {
342
+ a = e.getAttribute(_svgAttributes[i]);
343
+ if (a) {
344
+ _dummySVGRect.setAttribute(_svgAttributes[i], a);
345
+ } else {
346
+ _dummySVGRect.removeAttribute(_svgAttributes[i]);
347
+ }
348
+ }
285
349
  eRect = _dummySVGRect.getBoundingClientRect();
350
+ rRect = _dummySVGRect.firstChild.getBoundingClientRect();
286
351
  offsetParent = curElement.offsetParent;
287
352
  if (offsetParent) {
288
353
  if (offsetParent === _doc.body && _docElement) {
@@ -294,7 +359,13 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
294
359
  }
295
360
  _dummySVGRect.parentNode.insertBefore(e, _dummySVGRect);
296
361
  e.parentNode.removeChild(_dummySVGRect);
297
- return {offsetLeft:eRect.left - parentRect.left, offsetTop:eRect.top - parentRect.top, offsetParent:curElement.offsetParent || _docElement};
362
+ data.scaleX = rRect.width / 10;
363
+ data.scaleY = rRect.height / 10;
364
+ data.offsetLeft = eRect.left - parentRect.left;
365
+ data.offsetTop = eRect.top - parentRect.top;
366
+ data.offsetParent = curElement.offsetParent || _docElement;
367
+ data.lastUpdate = TweenLite.ticker.frame;
368
+ return data;
298
369
  },
299
370
  _getOffsetTransformOrigin = function(e, decoratee) {
300
371
  decoratee = decoratee || {};
@@ -312,8 +383,21 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
312
383
  if (x === "center" || isNaN(parseFloat(x))) { //remember, the user could flip-flop the values and say "bottom center" or "center bottom", etc. "center" is ambiguous because it could be used to describe horizontal or vertical, hence the isNaN(). If there's an "=" sign in the value, it's relative.
313
384
  x = "50%";
314
385
  }
315
- decoratee.x = ((x.indexOf("%") !== -1) ? e.offsetWidth * parseFloat(x) / 100 : parseFloat(x));
316
- decoratee.y = ((y.indexOf("%") !== -1) ? e.offsetHeight * parseFloat(y) / 100 : parseFloat(y));
386
+ if (e.getBBox && _isSVG(e)) { //SVG elements must be handled in a special way because their origins are calculated from the parent SVG canvas origin
387
+ if (!e._gsTransform) {
388
+ TweenLite.set(e, {x:"+=0"}); //forces creation of the _gsTransform where we store all the transform components including xOrigin and yOrigin for SVG elements, as of GSAP 1.15.0 which also takes care of calculating the origin from the upper left corner of the SVG canvas.
389
+ if (e._gsTransform.xOrigin === undefined) {
390
+ console.log("Draggable requires at least GSAP 1.16.0");
391
+ }
392
+ }
393
+ v = e.getBBox();
394
+ a = _getSVGOffsets(e);
395
+ decoratee.x = (e._gsTransform.xOrigin - v.x) * a.scaleX;
396
+ decoratee.y = (e._gsTransform.yOrigin - v.y) * a.scaleY;
397
+ } else {
398
+ decoratee.x = ((x.indexOf("%") !== -1) ? e.offsetWidth * parseFloat(x) / 100 : parseFloat(x));
399
+ decoratee.y = ((y.indexOf("%") !== -1) ? e.offsetHeight * parseFloat(y) / 100 : parseFloat(y));
400
+ }
317
401
  return decoratee;
318
402
  },
319
403
  _getOffset2DMatrix = function(e, offsetOrigin, parentOffsetOrigin) {
@@ -329,7 +413,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
329
413
  }
330
414
  if (offsetOrigin) {
331
415
  parent = e.parentNode;
332
- offsets = (e.offsetLeft === undefined && e.nodeName.toLowerCase() === "svg") ? _getSVGOffsets(e) : e;
416
+ offsets = ((e.getBBox && _isSVG(e)) || (e.offsetLeft === undefined && (e.nodeName + "").toLowerCase() === "svg")) ? _getSVGOffsets(e) : e;
333
417
  offsetParent = offsets.offsetParent;
334
418
  isRoot = (parent === _docElement || parent === _doc.body);
335
419
 
@@ -524,6 +608,8 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
524
608
  for (i = 0; i < l; i++) {
525
609
  a[i] = snap[i] * factor;
526
610
  }
611
+ max += 1.1; //allow 1.1 pixels of wiggle room when snapping in order to work around some browser inconsistencies in the way bounds are reported which can make them roughly a pixel off. For example, if "snap:[-$('#menu').width(), 0]" was defined and #menu had a wrapper that was used as the bounds, some browsers would be one pixel off, making the minimum -752 for example when snap was [-753,0], thus instead of snapping to -753, it would snap to 0 since -753 was below the minimum.
612
+ min -= 1.1;
527
613
  } else if (typeof(snap) === "function") {
528
614
  vars.end = function(value) {
529
615
  return snap.call(draggable, value) * factor; //we need to ensure that we can scope the function call to the Draggable instance itself so that users can access important values like maxX, minX, maxY, minY, x, and y from within that function.
@@ -544,9 +630,19 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
544
630
  return vars;
545
631
  },
546
632
 
547
- _isClickable = function(e) { //sometimes it's convenient to mark an element as clickable by adding a data-clickable="true" attribute (in which case we won't preventDefault() the mouse/touch event). This method checks if the element is an <a>, <input>, or <button> or has an onclick or has the data-clickable attribute set to true (or any of its parent elements).
633
+ _isClickable = function(e) { //sometimes it's convenient to mark an element as clickable by adding a data-clickable="true" attribute (in which case we won't preventDefault() the mouse/touch event). This method checks if the element is an <a>, <input>, or <button> or has an onclick or has the data-clickable or contentEditable attribute set to true (or any of its parent elements).
548
634
  var data;
549
- return (!e || !e.getAttribute || e.nodeName === "BODY") ? false : ((data = e.getAttribute("data-clickable")) === "true" || (data !== "false" && (e.onclick || _clickableTagExp.test(e.nodeName + "")))) ? true : _isClickable(e.parentNode);
635
+ return (!e || !e.getAttribute || e.nodeName === "BODY") ? false : ((data = e.getAttribute("data-clickable")) === "true" || (data !== "false" && (e.onclick || _clickableTagExp.test(e.nodeName + "") || e.getAttribute("contentEditable") === "true"))) ? true : _isClickable(e.parentNode);
636
+ },
637
+
638
+ _setSelectable = function(elements, selectable) {
639
+ var i = elements.length,
640
+ e;
641
+ while (--i > -1) {
642
+ e = elements[i];
643
+ e.ondragstart = e.onselectstart = selectable ? null : _emptyFunc;
644
+ _setStyle(e, "userSelect", (selectable ? "text" : "none"));
645
+ }
550
646
  },
551
647
 
552
648
  _addPaddingBR,
@@ -757,6 +853,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
757
853
  style.display = "inline-block";
758
854
  style.position = "relative";
759
855
  style.overflow = "visible";
856
+ style.verticalAlign = "top";
760
857
  style.width = "100%";
761
858
  style.paddingRight = extraPadRight + "px";
762
859
  //some browsers neglect to factor in the bottom padding when calculating the scrollHeight, so we need to add that padding to the content when that happens. Allow a 2px margin for error
@@ -773,6 +870,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
773
870
  maxLeft = element.scrollWidth - elementWidth;
774
871
  maxTop = element.scrollHeight - elementHeight;
775
872
  contentHeight = content.offsetHeight;
873
+ style.display = "block";
776
874
  if (x || y) {
777
875
  this.left(x);
778
876
  this.top(y);
@@ -801,10 +899,12 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
801
899
  this.dragResistance = parseFloat(vars.dragResistance) || 0;
802
900
  this.edgeResistance = isNaN(vars.edgeResistance) ? 1 : parseFloat(vars.edgeResistance) || 0;
803
901
  this.lockAxis = vars.lockAxis;
902
+ this.autoScroll = vars.autoScroll || 0;
903
+ this.lockedAxis = null;
804
904
  var type = (vars.type || (_isOldIE ? "top,left" : "x,y")).toLowerCase(),
805
905
  xyMode = (type.indexOf("x") !== -1 || type.indexOf("y") !== -1),
806
906
  rotationMode = (type.indexOf("rotation") !== -1),
807
- xProp = xyMode ? "x" : "left",
907
+ xProp = rotationMode ? "rotation" : xyMode ? "x" : "left",
808
908
  yProp = xyMode ? "y" : "top",
809
909
  allowX = (type.indexOf("x") !== -1 || type.indexOf("left") !== -1 || type === "scroll"),
810
910
  allowY = (type.indexOf("y") !== -1 || type.indexOf("top") !== -1 || type === "scroll"),
@@ -813,10 +913,59 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
813
913
  triggers = _slice(vars.trigger || vars.handle || target),
814
914
  killProps = {},
815
915
  dragEndTime = 0,
816
- enabled, scrollProxy, startMouseX, startMouseY, startElementX, startElementY, hasBounds, hasDragCallback, maxX, minX, maxY, minY, tempVars, cssVars, touch, touchID, rotationOrigin, dirty, old, snapX, snapY, isClicking, touchEventTarget, lockedAxis, matrix, interrupted,
916
+ checkAutoScrollBounds = false,
917
+ isClickable = vars.clickableTest || _isClickable,
918
+ enabled, scrollProxy, startPointerX, startPointerY, startElementX, startElementY, hasBounds, hasDragCallback, maxX, minX, maxY, minY, tempVars, cssVars, touch, touchID, rotationOrigin, dirty, old, snapX, snapY, isClicking, touchEventTarget, matrix, interrupted, clickTime, startScrollTop, startScrollLeft, applyObj,
817
919
 
818
920
  //this method gets called on every tick of TweenLite.ticker which allows us to synchronize the renders to the core engine (which is typically synchronized with the display refresh via requestAnimationFrame). This is an optimization - it's better than applying the values inside the "mousemove" or "touchmove" event handler which may get called many times inbetween refreshes.
819
921
  render = function(suppressEvents) {
922
+ if (self.autoScroll && self.isDragging && (dirty || checkAutoScrollBounds)) {
923
+ var e = target,
924
+ autoScrollFactor = self.autoScroll * 15, //multiplying by 15 just gives us a better "feel" speed-wise.
925
+ parent, isRoot, rect, pointerX, pointerY, changeX, changeY, gap;
926
+ checkAutoScrollBounds = false;
927
+ _windowProxy.scrollTop = ((window.pageYOffset != null) ? window.pageYOffset : (_docElement.scrollTop != null) ? _docElement.scrollTop : _doc.body.scrollTop);
928
+ _windowProxy.scrollLeft = ((window.pageXOffset != null) ? window.pageXOffset : (_docElement.scrollLeft != null) ? _docElement.scrollLeft : _doc.body.scrollLeft);
929
+ pointerX = self.pointerX - _windowProxy.scrollLeft;
930
+ pointerY = self.pointerY - _windowProxy.scrollTop;
931
+ while (e && !isRoot) { //walk up the chain and sense wherever the pointer is within 40px of an edge that's scrollable.
932
+ isRoot = _isRoot(e.parentNode);
933
+ parent = isRoot ? _windowProxy : e.parentNode;
934
+ rect = isRoot ? {bottom:Math.max(_docElement.clientHeight, window.innerHeight || 0), right: Math.max(_docElement.clientWidth, window.innerWidth || 0), left:0, top:0} : parent.getBoundingClientRect();
935
+ changeX = changeY = 0;
936
+ if (allowY) {
937
+ if (pointerY > rect.bottom - 40 && (gap = parent._gsMaxScrollY - parent.scrollTop)) {
938
+ checkAutoScrollBounds = true;
939
+ changeY = Math.min(gap, (autoScrollFactor * (1 - Math.max(0, (rect.bottom - pointerY)) / 40)) | 0);
940
+ } else if (pointerY < rect.top + 40 && parent.scrollTop) {
941
+ checkAutoScrollBounds = true;
942
+ changeY = -Math.min(parent.scrollTop, (autoScrollFactor * (1 - Math.max(0, (pointerY - rect.top)) / 40)) | 0);
943
+ }
944
+ if (changeY) {
945
+ parent.scrollTop += changeY;
946
+ }
947
+ }
948
+
949
+ if (allowX) {
950
+ if (pointerX > rect.right - 40 && (gap = parent._gsMaxScrollX - parent.scrollLeft)) {
951
+ checkAutoScrollBounds = true;
952
+ changeX = Math.min(gap, (autoScrollFactor * (1 - Math.max(0, (rect.right - pointerX)) / 40)) | 0);
953
+ } else if (pointerX < rect.left + 40 && parent.scrollLeft) {
954
+ checkAutoScrollBounds = true;
955
+ changeX = -Math.min(parent.scrollLeft, (autoScrollFactor * (1 - Math.max(0, (pointerX - rect.left)) / 40)) | 0);
956
+ }
957
+ if (changeX) {
958
+ parent.scrollLeft += changeX;
959
+ }
960
+ }
961
+
962
+ if (isRoot && (changeX || changeY)) {
963
+ window.scrollTo(parent.scrollLeft, parent.scrollTop);
964
+ setPointerPosition(self.pointerX + changeX, self.pointerY + changeY);
965
+ }
966
+ e = parent;
967
+ }
968
+ }
820
969
  if (dirty) {
821
970
  var x = self.x,
822
971
  y = self.y,
@@ -828,8 +977,8 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
828
977
  y = 0;
829
978
  }
830
979
  if (rotationMode) {
831
- cssVars.rotation = self.rotation = self.x;
832
- TweenLite.set(target, tempVars);
980
+ applyObj.data.rotation = self.rotation = x;
981
+ applyObj.setRatio(1); //note: instead of doing TweenLite.set(), as a performance optimization we skip right to the method that renders the transforms inside CSSPlugin. For old versions of IE, though, we do a normal TweenLite.set() to leverage its ability to re-reroute to an IE-specific 2D renderer.
833
982
  } else {
834
983
  if (scrollProxy) {
835
984
  if (allowY) {
@@ -840,12 +989,12 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
840
989
  }
841
990
  } else if (xyMode) {
842
991
  if (allowY) {
843
- cssVars.y = y;
992
+ applyObj.data.y = y;
844
993
  }
845
994
  if (allowX) {
846
- cssVars.x = x;
995
+ applyObj.data.x = x;
847
996
  }
848
- TweenLite.set(target, tempVars);
997
+ applyObj.setRatio(1); //note: instead of doing TweenLite.set(), as a performance optimization we skip right to the method that renders the transforms inside CSSPlugin. For old versions of IE, though, we do a normal TweenLite.set() to leverage its ability to re-reroute to an IE-specific 2D renderer.
849
998
  } else {
850
999
  if (allowY) {
851
1000
  target.style.top = y + "px";
@@ -865,16 +1014,13 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
865
1014
  //copies the x/y from the element (whether that be transforms, top/left, or ScrollProxy's top/left) to the Draggable's x and y (and rotation if necessary) properties so that they reflect reality and it also (optionally) applies any snapping necessary. This is used by the ThrowPropsPlugin tween in an onUpdate to ensure things are synced and snapped.
866
1015
  syncXY = function(skipOnUpdate, skipSnap) {
867
1016
  var snappedValue;
1017
+ if (!target._gsTransform && (xyMode || rotationMode)) { //just in case the _gsTransform got wiped, like if the user called clearProps on the transform or something (very rare), doing an x tween forces a re-parsing of the transforms and population of the _gsTransform.
1018
+ TweenLite.set(target, {x:"+=0"});
1019
+ }
868
1020
  if (xyMode) {
869
- if (!target._gsTransform) { //just in case the _gsTransform got wiped, like if the user called clearProps on the transform or something (very rare), doing an x tween forces a re-parsing of the transforms and population of the _gsTransform.
870
- TweenLite.set(target, {x:"+=0"});
871
- }
872
1021
  self.y = target._gsTransform.y;
873
1022
  self.x = target._gsTransform.x;
874
1023
  } else if (rotationMode) {
875
- if (!target._gsTransform) { //just in case the _gsTransform got wiped, like if the user called clearProps on the transform or something (very rare), doing an x tween forces a re-parsing of the transforms and population of the _gsTransform.
876
- TweenLite.set(target, {x:"+=0"});
877
- }
878
1024
  self.x = self.rotation = target._gsTransform.rotation;
879
1025
  } else if (scrollProxy) {
880
1026
  self.y = scrollProxy.top();
@@ -983,10 +1129,10 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
983
1129
  throwProps.rotation = _parseThrowProps(self, snapIsRaw ? snap : snap.rotation, maxX, minX, 1, forceZeroVelocity);
984
1130
  } else {
985
1131
  if (allowX) {
986
- throwProps[xProp] = _parseThrowProps(self, snapIsRaw ? snap : snap.x || snap.left || snap.scrollLeft, maxX, minX, scrollProxy ? -1 : 1, forceZeroVelocity || (self.lockAxis && lockedAxis === "x"));
1132
+ throwProps[xProp] = _parseThrowProps(self, snapIsRaw ? snap : snap.x || snap.left || snap.scrollLeft, maxX, minX, scrollProxy ? -1 : 1, forceZeroVelocity || (self.lockAxis && self.lockedAxis === "x"));
987
1133
  }
988
1134
  if (allowY) {
989
- throwProps[yProp] = _parseThrowProps(self, snapIsRaw ? snap : snap.y || snap.top || snap.scrollTop, maxY, minY, scrollProxy ? -1 : 1, forceZeroVelocity || (self.lockAxis && lockedAxis === "y"));
1135
+ throwProps[yProp] = _parseThrowProps(self, snapIsRaw ? snap : snap.y || snap.top || snap.scrollTop, maxY, minY, scrollProxy ? -1 : 1, forceZeroVelocity || (self.lockAxis && self.lockedAxis === "y"));
990
1136
  }
991
1137
  }
992
1138
  }
@@ -1040,8 +1186,10 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1040
1186
  rotationOrigin = _localToGlobal(target, {x:0, y:0});
1041
1187
  syncXY(true, true);
1042
1188
  startElementX = self.x; //starting rotation (x always refers to rotation in type:"rotation", measured in degrees)
1043
- startElementY = self.y = Math.atan2(rotationOrigin.y - startMouseY, startMouseX - rotationOrigin.x) * _RAD2DEG;
1189
+ startElementY = self.y = Math.atan2(rotationOrigin.y - startPointerY, startPointerX - rotationOrigin.x) * _RAD2DEG;
1044
1190
  } else {
1191
+ startScrollTop = target.parentNode ? target.parentNode.scrollTop || 0 : 0;
1192
+ startScrollLeft = target.parentNode ? target.parentNode.scrollLeft || 0 : 0;
1045
1193
  startElementY = _getStyle(target, yProp); //record the starting top and left values so that we can just add the mouse's movement to them later.
1046
1194
  startElementX = _getStyle(target, xProp);
1047
1195
  }
@@ -1116,14 +1264,19 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1116
1264
 
1117
1265
  }
1118
1266
  _addListener(_doc, "mouseup", onRelease);
1119
- isClicking = (_isClickable(e.target) && !vars.dragClickables);
1267
+ if (e && e.target) {
1268
+ _addListener(e.target, "mouseup", onRelease); //we also have to listen directly on the element because some browsers don't bubble up the event to the _doc on elements with contentEditable="true"
1269
+ }
1270
+ isClicking = (isClickable.call(self, e.target) && !vars.dragClickables);
1120
1271
  if (isClicking) {
1121
1272
  _addListener(e.target, "change", onRelease); //in some browsers, when you mousedown on a <select> element, no mouseup gets dispatched! So we listen for a "change" event instead.
1273
+ _dispatchEvent(self, "press", "onPress");
1274
+ _setSelectable(triggers, true); //accommodates things like inputs and elements with contentEditable="true" (otherwise user couldn't drag to select text)
1122
1275
  return;
1123
1276
  }
1124
1277
  if (_isOldIE) {
1125
1278
  e = _populateIEEvent(e, true);
1126
- } else if (scrollProxy && !(e.touches && e.touches.length > _dragCount + 1)) { //in some mobile browsers, e.preventDefault() when pressing on a link (or element with an onclick) will cause the link not to work. Only preventDefault() on scroll-type interactions, otherwise things like touch checkboxes and inputs don't work.
1279
+ } else { //if (scrollProxy && !(e.touches && e.touches.length > _dragCount + 1)) { //in some mobile browsers, e.preventDefault() when pressing on a link (or element with an onclick) will cause the link not to work. Only preventDefault() on scroll-type interactions, otherwise things like touch checkboxes and inputs don't work.
1127
1280
  e.preventDefault();
1128
1281
  if (e.preventManipulation) {
1129
1282
  e.preventManipulation(); //for some Microsoft browsers
@@ -1139,13 +1292,20 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1139
1292
  }
1140
1293
  _dragCount++;
1141
1294
  _addToRenderQueue(render); //causes the Draggable to render on each "tick" of TweenLite.ticker (performance optimization - updating values in a mousemove can cause them to happen too frequently, like multiple times between frame redraws which is wasteful, and it also prevents values from updating properly in IE8)
1142
- startMouseY = self.pointerY = e.pageY; //record the starting x and y so that we can calculate the movement from the original in _onMouseMove
1143
- startMouseX = self.pointerX = e.pageX;
1295
+ startPointerY = self.pointerY = e.pageY; //record the starting x and y so that we can calculate the movement from the original in _onMouseMove
1296
+ startPointerX = self.pointerX = e.pageX;
1297
+ if (self.autoScroll && !rotationMode && !scrollProxy && target.parentNode && !target.getBBox) {
1298
+ _recordMaxScrolls(target.parentNode);
1299
+ if (target.parentNode._gsMaxScrollX && !_placeholderDiv.parentNode) { //add a placeholder div to prevent the parent container from collapsing when the user drags the element left.
1300
+ _placeholderDiv.style.width = (target.parentNode.scrollWidth) + "px";
1301
+ target.parentNode.appendChild(_placeholderDiv);
1302
+ }
1303
+ }
1144
1304
  recordStartPositions();
1145
1305
  if (matrix) {
1146
- temp = startMouseX * matrix[0] + startMouseY * matrix[2] + matrix[4];
1147
- startMouseY = startMouseX * matrix[1] + startMouseY * matrix[3] + matrix[5];
1148
- startMouseX = temp;
1306
+ temp = startPointerX * matrix[0] + startPointerY * matrix[2] + matrix[4];
1307
+ startPointerY = startPointerX * matrix[1] + startPointerY * matrix[3] + matrix[5];
1308
+ startPointerX = temp;
1149
1309
  }
1150
1310
  if (self.tween) {
1151
1311
  self.tween.kill();
@@ -1154,7 +1314,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1154
1314
  if (scrollProxy) {
1155
1315
  TweenLite.killTweensOf(target, true, {scrollTo:1}); //just in case the original target's scroll position is being tweened somewhere else.
1156
1316
  }
1157
- self.tween = lockedAxis = null;
1317
+ self.tween = self.lockedAxis = null;
1158
1318
  if (vars.zIndexBoost || (!rotationMode && !scrollProxy && vars.zIndexBoost !== false)) {
1159
1319
  target.style.zIndex = Draggable.zIndex++;
1160
1320
  }
@@ -1171,7 +1331,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1171
1331
 
1172
1332
  //called every time the mouse/touch moves
1173
1333
  onMove = function(e) {
1174
- if (!enabled || _isMultiTouching || !self.isPressed) {
1334
+ if (!enabled || _isMultiTouching || !self.isPressed || !e) {
1175
1335
  return;
1176
1336
  }
1177
1337
  if (_isOldIE) {
@@ -1184,9 +1344,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1184
1344
  }
1185
1345
  self.pointerEvent = e;
1186
1346
  var touches = e.changedTouches,
1187
- dragTolerance = 1 - self.dragResistance,
1188
- edgeTolerance = 1 - self.edgeResistance,
1189
- xChange, yChange, x, y, i, dif, mouseX, mouseY, temp;
1347
+ i;
1190
1348
  if (touches) { //touch events store the data slightly differently
1191
1349
  e = touches[0];
1192
1350
  if (e !== touch && e.identifier !== touchID) { //Usually changedTouches[0] will be what we're looking for, but in case it's not, look through the rest of the array...(and Android browsers don't reuse the event like iOS)
@@ -1199,11 +1357,22 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1199
1357
  } else if (e.pointerId && touchID && e.pointerId !== touchID) { //for some Microsoft browsers, we must attach the listener to the doc rather than the trigger so that when the finger moves outside the bounds of the trigger, things still work. So if the event we're receiving has a pointerId that doesn't match the touchID, ignore it (for multi-touch)
1200
1358
  return;
1201
1359
  }
1202
- mouseX = self.pointerX = e.pageX;
1203
- mouseY = self.pointerY = e.pageY;
1360
+ if (self.autoScroll) {
1361
+ checkAutoScrollBounds = true;
1362
+ }
1363
+ setPointerPosition(e.pageX, e.pageY);
1364
+ },
1365
+
1366
+ setPointerPosition = function(pointerX, pointerY) {
1367
+ var dragTolerance = 1 - self.dragResistance,
1368
+ edgeTolerance = 1 - self.edgeResistance,
1369
+ xChange, yChange, x, y, dif, temp;
1370
+
1371
+ self.pointerX = pointerX;
1372
+ self.pointerY = pointerY;
1204
1373
 
1205
1374
  if (rotationMode) {
1206
- y = Math.atan2(rotationOrigin.y - e.pageY, e.pageX - rotationOrigin.x) * _RAD2DEG;
1375
+ y = Math.atan2(rotationOrigin.y - pointerY, pointerX - rotationOrigin.x) * _RAD2DEG;
1207
1376
  dif = self.y - y;
1208
1377
  self.y = y;
1209
1378
  if (dif > 180) {
@@ -1215,12 +1384,12 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1215
1384
 
1216
1385
  } else {
1217
1386
  if (matrix) {
1218
- temp = mouseX * matrix[0] + mouseY * matrix[2] + matrix[4];
1219
- mouseY = mouseX * matrix[1] + mouseY * matrix[3] + matrix[5];
1220
- mouseX = temp;
1387
+ temp = pointerX * matrix[0] + pointerY * matrix[2] + matrix[4];
1388
+ pointerY = pointerX * matrix[1] + pointerY * matrix[3] + matrix[5];
1389
+ pointerX = temp;
1221
1390
  }
1222
- yChange = (mouseY - startMouseY);
1223
- xChange = (mouseX - startMouseX);
1391
+ yChange = (pointerY - startPointerY);
1392
+ xChange = (pointerX - startPointerX);
1224
1393
  if (yChange < minimumMovement && yChange > -minimumMovement) {
1225
1394
  yChange = 0;
1226
1395
  }
@@ -1228,12 +1397,12 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1228
1397
  xChange = 0;
1229
1398
  }
1230
1399
  if (self.lockAxis && (xChange || yChange)) {
1231
- if (lockedAxis === "y" || (!lockedAxis && Math.abs(xChange) > Math.abs(yChange) && allowX)) {
1400
+ if (self.lockedAxis === "y" || (!self.lockedAxis && Math.abs(xChange) > Math.abs(yChange) && allowX)) {
1232
1401
  yChange = 0;
1233
- lockedAxis = "y";
1402
+ self.lockedAxis = "y";
1234
1403
  } else if (allowY) {
1235
1404
  xChange = 0;
1236
- lockedAxis = "x";
1405
+ self.lockedAxis = "x";
1237
1406
  }
1238
1407
  }
1239
1408
  x = startElementX + xChange * dragTolerance;
@@ -1288,7 +1457,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1288
1457
  self.isPressed = false;
1289
1458
  var originalEvent = e,
1290
1459
  wasDragging = self.isDragging,
1291
- touches, i, syntheticEvent;
1460
+ touches, i, syntheticEvent, eventTarget;
1292
1461
  if (touchEventTarget) {
1293
1462
  _removeListener(touchEventTarget, "touchend", onRelease);
1294
1463
  _removeListener(touchEventTarget, "touchmove", onMove);
@@ -1298,11 +1467,18 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1298
1467
  _removeListener(_doc, "mousemove", onMove);
1299
1468
  }
1300
1469
  _removeListener(_doc, "mouseup", onRelease);
1470
+ if (e && e.target) {
1471
+ _removeListener(e.target, "mouseup", onRelease);
1472
+ }
1301
1473
  dirty = false;
1474
+ if (_placeholderDiv.parentNode) { //_placeholderDiv just props open auto-scrolling containers so they don't collapse as the user drags left/up.
1475
+ _placeholderDiv.parentNode.removeChild(_placeholderDiv);
1476
+ }
1302
1477
  if (isClicking) {
1303
1478
  if (e) {
1304
1479
  _removeListener(e.target, "change", onRelease);
1305
1480
  }
1481
+ _setSelectable(triggers, false);
1306
1482
  _dispatchEvent(self, "release", "onRelease");
1307
1483
  _dispatchEvent(self, "click", "onClick");
1308
1484
  isClicking = false;
@@ -1345,16 +1521,18 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1345
1521
  }
1346
1522
  _dispatchEvent(self, "release", "onRelease");
1347
1523
  _dispatchEvent(self, "click", "onClick");
1348
- if (originalEvent.target.click) { //some browsers (like mobile Safari) don't properly trigger the click event
1349
- originalEvent.target.click();
1524
+ eventTarget = originalEvent.target || originalEvent.srcElement || target; //old IE uses srcElement
1525
+ if (eventTarget.click) { //some browsers (like mobile Safari) don't properly trigger the click event
1526
+ eventTarget.click();
1350
1527
  } else if (_doc.createEvent) {
1351
1528
  syntheticEvent = _doc.createEvent("MouseEvents");
1352
1529
  syntheticEvent.initEvent("click", true, true);
1353
- originalEvent.target.dispatchEvent(syntheticEvent);
1530
+ eventTarget.dispatchEvent(syntheticEvent);
1354
1531
  }
1532
+ clickTime = _getTime();
1355
1533
  } else {
1356
1534
  animate(vars.throwProps); //will skip if throwProps isn't defined or ThrowPropsPlugin isn't loaded.
1357
- if (!_isOldIE && originalEvent && (vars.dragClickables || !_isClickable(originalEvent.target)) && wasDragging) {
1535
+ if (!_isOldIE && originalEvent && (vars.dragClickables || !isClickable.call(self, originalEvent.target)) && wasDragging) {
1358
1536
  originalEvent.preventDefault();
1359
1537
  if (originalEvent.preventManipulation) {
1360
1538
  originalEvent.preventManipulation(); //for some Microsoft browsers
@@ -1368,10 +1546,30 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1368
1546
  return true;
1369
1547
  },
1370
1548
 
1549
+ updateScroll = function(e) {
1550
+ if (e && self.isDragging) {
1551
+ var parent = e.target || e.srcElement || target.parentNode,
1552
+ deltaX = parent.scrollLeft - parent._gsScrollX,
1553
+ deltaY = parent.scrollTop - parent._gsScrollY;
1554
+ if (deltaX || deltaY) {
1555
+ startPointerX -= deltaX;
1556
+ startPointerY -= deltaY;
1557
+ parent._gsScrollX += deltaX;
1558
+ parent._gsScrollY += deltaY;
1559
+ setPointerPosition(self.pointerX, self.pointerY);
1560
+ }
1561
+ }
1562
+ },
1563
+
1371
1564
  onClick = function(e) {
1372
- if (self.isPressed || _getTime() - dragEndTime < 20) {
1565
+ var time = _getTime(),
1566
+ recentlyClicked = time - clickTime < 40;
1567
+ if (self.isPressed || time - dragEndTime < 20 || recentlyClicked) {
1373
1568
  if (e.preventDefault) {
1374
1569
  e.preventDefault();
1570
+ if (recentlyClicked) {
1571
+ e.stopImmediatePropagation(); //otherwise some browsers bubble up click events, creating a duplicate.
1572
+ }
1375
1573
  } else {
1376
1574
  e.returnValue = false;
1377
1575
  }
@@ -1405,6 +1603,32 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1405
1603
  return Draggable.hitTest(self.target, target, threshold);
1406
1604
  };
1407
1605
 
1606
+ this.getDirection = function(from, diagonalThreshold) { //from can be "start" (default), "velocity", or an element
1607
+ var mode = (from === "velocity" && ThrowPropsPlugin) ? from : (typeof(from) === "object" && !rotationMode) ? "element" : "start",
1608
+ xChange, yChange, ratio, direction, r1, r2;
1609
+ if (mode === "element") {
1610
+ r1 = _parseRect(self.target);
1611
+ r2 = _parseRect(from);
1612
+ }
1613
+ xChange = (mode === "start") ? self.x - startElementX : (mode === "velocity") ? ThrowPropsPlugin.getVelocity(this.target, xProp) : (r1.left + r1.width / 2) - (r2.left + r2.width / 2);
1614
+ if (rotationMode) {
1615
+ return xChange < 0 ? "counter-clockwise" : "clockwise";
1616
+ } else {
1617
+ diagonalThreshold = diagonalThreshold || 2;
1618
+ yChange = (mode === "start") ? self.y - startElementY : (mode === "velocity") ? ThrowPropsPlugin.getVelocity(this.target, yProp) : (r1.top + r1.height / 2) - (r2.top + r2.height / 2);
1619
+ ratio = Math.abs(xChange / yChange);
1620
+ direction = (ratio < 1 / diagonalThreshold) ? "" : (xChange < 0) ? "left" : "right";
1621
+ if (ratio < diagonalThreshold) {
1622
+ if (direction !== "") {
1623
+ direction += "-";
1624
+ }
1625
+ direction += (yChange < 0) ? "up" : "down";
1626
+ }
1627
+ }
1628
+ return direction;
1629
+ };
1630
+
1631
+
1408
1632
  this.applyBounds = function(newBounds) {
1409
1633
  var x, y;
1410
1634
  if (newBounds && vars.bounds !== newBounds) {
@@ -1446,9 +1670,13 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1446
1670
  var x = self.x,
1447
1671
  y = self.y;
1448
1672
  updateMatrix();
1673
+ updateScroll();
1449
1674
  if (applyBounds) {
1450
1675
  self.applyBounds();
1451
1676
  } else {
1677
+ if (dirty) {
1678
+ render();
1679
+ }
1452
1680
  syncXY(true);
1453
1681
  }
1454
1682
  if (self.isPressed && ((allowX && Math.abs(x - self.x) > 0.01) || (allowY && (Math.abs(y - self.y) > 0.01 && !rotationMode)))) {
@@ -1469,12 +1697,12 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1469
1697
  if (!rotationMode) {
1470
1698
  _setStyle(trigger, "cursor", vars.cursor || "move");
1471
1699
  }
1472
- trigger.ondragstart = trigger.onselectstart = _emptyFunc; //prevent text selection (and prevent IE from dragging images)
1473
- _setStyle(trigger, "userSelect", "none");
1474
1700
  _setStyle(trigger, "touchCallout", "none");
1475
1701
  _setStyle(trigger, "touchAction", "none");
1476
1702
  }
1703
+ _setSelectable(triggers, false);
1477
1704
  }
1705
+ _addScrollListener(self.target, updateScroll);
1478
1706
  enabled = true;
1479
1707
  if (ThrowPropsPlugin && type !== "soft") {
1480
1708
  ThrowPropsPlugin.track(scrollProxy || target, (xyMode ? "x,y" : rotationMode ? "rotation" : "top,left"));
@@ -1488,6 +1716,12 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1488
1716
  scrollProxy.element._gsDragID = id;
1489
1717
  }
1490
1718
  TweenLite.set(target, {x:"+=0"}); //simply ensures that there's a _gsTransform on the element.
1719
+ applyObj = {
1720
+ t:target,
1721
+ data:_isOldIE ? cssVars : target._gsTransform,
1722
+ tween:{},
1723
+ setRatio:(_isOldIE ? function() { TweenLite.set(target, tempVars); } : CSSPlugin._internals.set3DTransformRatio)
1724
+ };
1491
1725
  this.update(true);
1492
1726
  return self;
1493
1727
  };
@@ -1505,14 +1739,13 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1505
1739
  i = triggers.length;
1506
1740
  while (--i > -1) {
1507
1741
  trigger = triggers[i];
1508
- trigger.ondragstart = trigger.onselectstart = null;
1509
- _setStyle(trigger, "userSelect", "text");
1510
1742
  _setStyle(trigger, "touchCallout", "default");
1511
1743
  _setStyle(trigger, "MSTouchAction", "auto");
1512
1744
  _removeListener(trigger, "mousedown", onPress);
1513
1745
  _removeListener(trigger, "touchstart", onPress);
1514
1746
  _removeListener(trigger, "click", onClick);
1515
1747
  }
1748
+ _setSelectable(triggers, true);
1516
1749
  if (touchEventTarget) {
1517
1750
  _removeListener(touchEventTarget, "touchcancel", onRelease);
1518
1751
  _removeListener(touchEventTarget, "touchend", onRelease);
@@ -1521,6 +1754,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1521
1754
  _removeListener(_doc, "mouseup", onRelease);
1522
1755
  _removeListener(_doc, "mousemove", onMove);
1523
1756
  }
1757
+ _removeScrollListener(target, updateScroll);
1524
1758
  enabled = false;
1525
1759
  if (ThrowPropsPlugin && type !== "soft") {
1526
1760
  ThrowPropsPlugin.untrack(scrollProxy || target, (xyMode ? "x,y" : rotationMode ? "rotation" : "top,left"));
@@ -1588,7 +1822,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1588
1822
  p.constructor = Draggable;
1589
1823
  p.pointerX = p.pointerY = 0;
1590
1824
  p.isDragging = p.isPressed = false;
1591
- Draggable.version = "0.11.0";
1825
+ Draggable.version = "0.12.0";
1592
1826
  Draggable.zIndex = 1000;
1593
1827
 
1594
1828
  _addListener(_doc, "touchcancel", function() {
@@ -1634,7 +1868,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1634
1868
  return r;
1635
1869
  };
1636
1870
 
1637
- Draggable.hitTest = function(obj1, obj2, threshold) { //
1871
+ Draggable.hitTest = function(obj1, obj2, threshold) {
1638
1872
  if (obj1 === obj2) {
1639
1873
  return false;
1640
1874
  }
@@ -1661,6 +1895,8 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1661
1895
  return (overlap.width > threshold && overlap.height > threshold);
1662
1896
  };
1663
1897
 
1898
+ _placeholderDiv.style.cssText = "visibility:hidden; height:1px; top:-1px; pointer-events:none; position:relative; clear:both;";
1899
+
1664
1900
  return Draggable;
1665
1901
 
1666
1902
  }, true);