From 423d903ebc7de28708aba5edcb14c0284abd81ee Mon Sep 17 00:00:00 2001 From: RubaXa Date: Sun, 30 Nov 2014 23:37:52 +0300 Subject: [PATCH 1/9] + Smart auto-scrolling --- README.md | 4 +++ Sortable.js | 93 +++++++++++++++++++++++++++++++++++++++++++++---- Sortable.min.js | 2 +- 3 files changed, 92 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index c33a67a..4252a2f 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ Sortable is a minimalist JavaScript library for reorderable drag-and-drop lists. * Supports touch devices and [modern](http://caniuse.com/#search=drag) browsers * Can drag from one list to another or within the same list * Animation moving items when sorting (css animation) + * Smart auto-scrolling * Built using native HTML5 drag and drop API * Support [AngularJS](#ng) * Simple API @@ -36,6 +37,9 @@ var sortabel = new Sortable(el, { group: "name", // or { name: "..", pull: [true, false, clone], put: [true, false, array] } sort: true, // sorting inside list store: null, // @see Store + scroll: true, // or HTMLElement + scrollSensitivity: 30, // px, how near the mouse must be to an edge to start scrolling. + scrollSpeed: 10, // px animation: 150, // ms, animation speed moving items when sorting, `0` — without animation handle: ".my-handle", // Restricts sort start click/touch to the specified element filter: ".ignor-elements", // Selectors that do not lead to dragging (String or Function) diff --git a/Sortable.js b/Sortable.js index d5d5817..0b6ccde 100644 --- a/Sortable.js +++ b/Sortable.js @@ -28,6 +28,7 @@ ghostEl, cloneEl, rootEl, + scrollEl, nextEl, lastEl, @@ -60,6 +61,8 @@ _customEvents = 'onAdd onUpdate onRemove onStart onEnd onFilter onSort'.split(' '), noop = function () {}, + + abs = Math.abs, slice = [].slice, touchDragOverListeners = [] @@ -83,6 +86,9 @@ sort: true, store: null, handle: null, + scroll: true, + scrollSensitivity: 30, + scrollSpeed: 10, draggable: el.children[0] && el.children[0].nodeName || (/[uo]l/i.test(el.nodeName) ? 'li' : '*'), ghostClass: 'sortable-ghost', ignore: 'a, img', @@ -229,8 +235,9 @@ _on(document, 'touchend', this._onDrop); _on(document, 'touchcancel', this._onDrop); - _on(this.el, 'dragstart', this._onDragStart); - _on(this.el, 'dragend', this._onDrop); + _on(rootEl, 'dragstart', this._onDragStart); + _on(rootEl, 'dragend', this._onDrop); + _on(document, 'dragover', _globalDragOver); @@ -351,10 +358,58 @@ _on(document, 'drop', this._onDrop); } - setTimeout(this._applyEffects); + setTimeout(this._applyEffects, 0); + + scrollEl = options.scroll; + + if (scrollEl === true) { + scrollEl = dragEl; + + do { + if ((scrollEl.offsetWidth < scrollEl.scrollWidth) || + (scrollEl.offsetHeight < scrollEl.scrollHeight) + ) { + break; + } + /* jshint boss:true */ + } while (scrollEl = scrollEl.parentNode); + } }, + _onDrag: _throttle(function (/**Event*/evt) { + if (rootEl && this.options.scroll) { + var options = this.options, + sens = options.scrollSensitivity, + speed = options.scrollSpeed, + rect = rootEl.getBoundingClientRect(), + + x = evt.clientX, + y = evt.clientY, + + winWidth = window.innerWidth, + winHeight = window.innerHeight, + + vx = (winWidth - x <= sens) ? (rect.right > winWidth) : -(rect.left < 0 && x <= sens), + vy = (winHeight - y <= sens) ? (rect.bottom > winHeight) : -(rect.top < 0 && y <= sens) + ; + + + if (vx || vy) { + win.scrollTo(win.scrollX + vx * speed, win.scrollY + vy * speed); + } + else if (scrollEl) { + rect = scrollEl.getBoundingClientRect(); + vx = (abs(rect.right - x) <= sens) - (abs(rect.left - x) <= sens); + vy = (abs(rect.bottom - y) <= sens) - (abs(rect.top - y) <= sens); + + vy && (scrollEl.scrollTop += vy * speed); + vx && (scrollEl.scrollLeft += vx * speed); + } + } + }, 30), + + _onDragOver: function (/**Event*/evt) { var el = this.el, target, @@ -365,6 +420,9 @@ groupPut = group.put, isOwner = (activeGroup === group); + // Because bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521 + this._onDrag(evt); + if (!_silent && (activeGroup.name === group.name || groupPut && groupPut.indexOf && groupPut.indexOf(activeGroup.name) > -1) && (isOwner && (options.sort || (revert = !rootEl.contains(dragEl))) || groupPut && activeGroup.pull) && @@ -476,9 +534,9 @@ _off(document, 'drop', this._onDrop); _off(document, 'dragover', _globalDragOver); - _off(this.el, 'dragend', this._onDrop); - _off(this.el, 'dragstart', this._onDragStart); - _off(this.el, 'selectstart', this._onTapStart); + _off(rootEl, 'dragend', this._onDrop); + _off(rootEl, 'dragstart', this._onDragStart); + _off(rootEl, 'selectstart', this._onTapStart); this._offUpEvents(); @@ -764,6 +822,28 @@ } + function _throttle(callback, ms) { + var args, _this; + + return function () { + if (args === void 0) { + args = arguments; + _this = this; + + setTimeout(function () { + if (args.length === 1) { + callback.call(_this, args[0]); + } else { + callback.apply(_this, args); + } + + args = void 0; + }, ms); + } + }; + } + + // Export utils Sortable.utils = { on: _on, @@ -771,6 +851,7 @@ css: _css, find: _find, bind: _bind, + throttle: _throttle, closest: _closest, toggleClass: _toggleClass, dispatchEvent: _dispatchEvent diff --git a/Sortable.min.js b/Sortable.min.js index 0421e4b..660798f 100644 --- a/Sortable.min.js +++ b/Sortable.min.js @@ -1,2 +1,2 @@ /*! Sortable 0.6.0 - MIT | git://github.com/rubaxa/Sortable.git */ -!function(a){"use strict";"function"==typeof define&&define.amd?define(a):"undefined"!=typeof module&&"undefined"!=typeof module.exports?module.exports=a():"undefined"!=typeof Package?Sortable=a():window.Sortable=a()}(function(){"use strict";function a(a,c){this.el=a,this.options=c=c||{};var d={group:Math.random(),sort:!0,store:null,handle:null,draggable:a.children[0]&&a.children[0].nodeName||(/[uo]l/i.test(a.nodeName)?"li":"*"),ghostClass:"sortable-ghost",ignore:"a, img",filter:null,animation:0,setData:function(a,b){a.setData("Text",b.textContent)}};for(var f in d)!(f in c)&&(c[f]=d[f]);c.group.name||(c.group={name:c.group}),["pull","put"].forEach(function(a){a in c.group||(c.group[a]=!0)}),E.forEach(function(d){c[d]=b(this,c[d]||F),e(a,d.substr(2).toLowerCase(),c[d])},this),a[x]=c.group.name;for(var g in this)"_"===g.charAt(0)&&(this[g]=b(this,this[g]));e(a,"mousedown",this._onTapStart),e(a,"touchstart",this._onTapStart),B&&e(a,"selectstart",this._onTapStart),e(a,"dragover",this._onDragOver),e(a,"dragenter",this._onDragOver),H.push(this._onDragOver),c.store&&this.sort(c.store.get(this))}function b(a,b){var c=G.call(arguments,2);return b.bind?b.bind.apply(b,[a].concat(c)):function(){return b.apply(a,c.concat(G.call(arguments)))}}function c(a,b,c){if("*"===b)return a;if(a){c=c||z,b=b.split(".");var d=b.shift().toUpperCase(),e=new RegExp("\\s("+b.join("|")+")\\s","g");do if(!(""!==d&&a.nodeName!=d||b.length&&((" "+a.className+" ").match(e)||[]).length!=b.length))return a;while(a!==c&&(a=a.parentNode))}return null}function d(a){a.dataTransfer.dropEffect="move",a.preventDefault()}function e(a,b,c){a.addEventListener(b,c,!1)}function f(a,b,c){a.removeEventListener(b,c,!1)}function g(a,b,c){if(a)if(a.classList)a.classList[c?"add":"remove"](b);else{var d=(" "+a.className+" ").replace(/\s+/g," ").replace(" "+b+" ","");a.className=d+(c?" "+b:"")}}function h(a,b,c){var d=a&&a.style;if(d){if(void 0===c)return z.defaultView&&z.defaultView.getComputedStyle?c=z.defaultView.getComputedStyle(a,""):a.currentStyle&&(c=a.currentStyle),void 0===b?c:c[b];b in d||(b="-webkit-"+b),d[b]=c+("string"==typeof c?"":"px")}}function i(a,b,c){if(a){var d=a.getElementsByTagName(b),e=0,f=d.length;if(c)for(;f>e;e++)c(d[e],e);return d}return[]}function j(a){a.draggable=!1}function k(){C=!1}function l(a,b){var c=a.lastElementChild,d=c.getBoundingClientRect();return b.clientY-(d.top+d.height)>5&&c}function m(a){for(var b=a.tagName+a.className+a.src+a.href+a.textContent,c=b.length,d=0;c--;)d+=b.charCodeAt(c);return d.toString(36)}var n,o,p,q,r,s,t,u,v,w,x="Sortable"+(new Date).getTime(),y=window,z=y.document,A=y.parseInt,B=!!z.createElement("div").dragDrop,C=!1,D=function(a,b,c,d){var e=z.createEvent("Event");e.initEvent(b,!0,!0),e.item=c||a,e.from=d||a,a.dispatchEvent(e)},E="onAdd onUpdate onRemove onStart onEnd onFilter onSort".split(" "),F=function(){},G=[].slice,H=[];return a.prototype={constructor:a,_applyEffects:function(){g(n,this.options.ghostClass,!0)},_onTapStart:function(a){var b=a.touches&&a.touches[0],f=(b||a).target,g=this.options,k=this.el,l=g.filter;if("mousedown"!==a.type||0===a.button){if("function"==typeof l){if(l.call(this,f,this))return D(k,"filter",f),void 0}else if(l&&(l=l.split(",").filter(function(a){return c(f,a.trim(),k)}),l.length))return D(k,"filter",f),void 0;if(g.handle&&(f=c(f,g.handle,k)),f=c(f,g.draggable,k),f&&"selectstart"==a.type&&"A"!=f.tagName&&"IMG"!=f.tagName&&f.dragDrop(),f&&!n&&f.parentNode===k){v=a,q=this.el,n=f,r=n.nextSibling,u=this.options.group,n.draggable=!0,g.ignore.split(",").forEach(function(a){i(f,a.trim(),j)}),b&&(v={target:f,clientX:b.clientX,clientY:b.clientY},this._onDragStart(v,!0),a.preventDefault()),e(z,"mouseup",this._onDrop),e(z,"touchend",this._onDrop),e(z,"touchcancel",this._onDrop),e(this.el,"dragstart",this._onDragStart),e(this.el,"dragend",this._onDrop),e(z,"dragover",d);try{z.selection?z.selection.empty():window.getSelection().removeAllRanges()}catch(m){}D(n,"start"),"clone"==u.pull&&(p=n.cloneNode(!0),h(p,"display","none"),q.insertBefore(p,n))}}},_emulateDragOver:function(){if(w){h(o,"display","none");var a=z.elementFromPoint(w.clientX,w.clientY),b=a,c=this.options.group.name,d=H.length;if(b)do{if(b[x]===c){for(;d--;)H[d]({clientX:w.clientX,clientY:w.clientY,target:a,rootEl:b});break}a=b}while(b=b.parentNode);h(o,"display","")}},_onTouchMove:function(a){if(v){var b=a.touches[0],c=b.clientX-v.clientX,d=b.clientY-v.clientY,e="translate3d("+c+"px,"+d+"px,0)";w=b,h(o,"webkitTransform",e),h(o,"mozTransform",e),h(o,"msTransform",e),h(o,"transform",e),a.preventDefault()}},_onDragStart:function(a,b){var c=a.dataTransfer,d=this.options;if(this._offUpEvents(),b){var f,g=n.getBoundingClientRect(),i=h(n);o=n.cloneNode(!0),h(o,"top",g.top-A(i.marginTop,10)),h(o,"left",g.left-A(i.marginLeft,10)),h(o,"width",g.width),h(o,"height",g.height),h(o,"opacity","0.8"),h(o,"position","fixed"),h(o,"zIndex","100000"),q.appendChild(o),f=o.getBoundingClientRect(),h(o,"width",2*g.width-f.width),h(o,"height",2*g.height-f.height),e(z,"touchmove",this._onTouchMove),e(z,"touchend",this._onDrop),e(z,"touchcancel",this._onDrop),this._loopId=setInterval(this._emulateDragOver,150)}else c.effectAllowed="move",d.setData&&d.setData.call(this,c,n),e(z,"drop",this._onDrop);setTimeout(this._applyEffects)},_onDragOver:function(a){var b,d,e,f=this.el,g=this.options,i=g.group,j=i.put,m=u===i;if(!C&&(u.name===i.name||j&&j.indexOf&&j.indexOf(u.name)>-1)&&(m&&(g.sort||(e=!q.contains(n)))||j&&u.pull)&&(void 0===a.rootEl||a.rootEl===this.el)){if(b=c(a.target,g.draggable,f),d=n.getBoundingClientRect(),p&&p.state!==m&&(h(p,"display",m?"none":""),!m&&p.state&&q.insertBefore(p,n),p.state=m),e&&p)return q.insertBefore(n,p),void 0;if(0===f.children.length||f.children[0]===o||f===a.target&&(b=l(f,a))){if(b){if(b.animated)return;v=b.getBoundingClientRect()}f.appendChild(n),this._animate(d,n),b&&this._animate(v,b)}else if(b&&!b.animated&&b!==n&&void 0!==b.parentNode[x]){s!==b&&(s=b,t=h(b));var r,v=b.getBoundingClientRect(),w=v.right-v.left,y=v.bottom-v.top,z=/left|right|inline/.test(t.cssFloat+t.display),A=b.offsetWidth>n.offsetWidth,B=b.offsetHeight>n.offsetHeight,D=(z?(a.clientX-v.left)/w:(a.clientY-v.top)/y)>.5,E=b.nextElementSibling;C=!0,setTimeout(k,30),r=z?b.previousElementSibling===n&&!A||D&&A:E!==n&&!B||D&&B,r&&!E?f.appendChild(n):b.parentNode.insertBefore(n,r?E:b),this._animate(d,n),this._animate(v,b)}}},_animate:function(a,b){var c=this.options.animation;if(c){var d=b.getBoundingClientRect();h(b,"transition","none"),h(b,"transform","translate3d("+(a.left-d.left)+"px,"+(a.top-d.top)+"px,0)"),b.offsetWidth,h(b,"transition","all "+c+"ms"),h(b,"transform","translate3d(0,0,0)"),clearTimeout(b.animated),b.animated=setTimeout(function(){h(b,"transition",""),b.animated=!1},c)}},_offUpEvents:function(){f(z,"mouseup",this._onDrop),f(z,"touchmove",this._onTouchMove),f(z,"touchend",this._onDrop),f(z,"touchcancel",this._onDrop)},_onDrop:function(a){clearInterval(this._loopId),f(z,"drop",this._onDrop),f(z,"dragover",d),f(this.el,"dragend",this._onDrop),f(this.el,"dragstart",this._onDragStart),f(this.el,"selectstart",this._onTapStart),this._offUpEvents(),a&&(a.preventDefault(),a.stopPropagation(),o&&o.parentNode.removeChild(o),n&&(j(n),g(n,this.options.ghostClass,!1),q.contains(n)?n.nextSibling!==r&&(D(n,"update"),D(n,"sort"),p&&p.parentNode.removeChild(p)):(D(n,"sort"),D(q,"sort"),D(n,"add",n,q),D(q,"remove",n)),D(q,"end")),q=n=o=r=p=v=w=s=t=u=null,this.options.store&&this.options.store.set(this))},toArray:function(){for(var a,b=[],d=this.el.children,e=0,f=d.length;f>e;e++)a=d[e],c(a,this.options.draggable,this.el)&&b.push(a.getAttribute("data-id")||m(a));return b},sort:function(a){var b={},d=this.el;this.toArray().forEach(function(a,e){var f=d.children[e];c(f,this.options.draggable,d)&&(b[a]=f)},this),a.forEach(function(a){b[a]&&(d.removeChild(b[a]),d.appendChild(b[a]))})},closest:function(a,b){return c(a,b||this.options.draggable,this.el)},destroy:function(){var a=this.el,b=this.options;E.forEach(function(c){f(a,c.substr(2).toLowerCase(),b[c])}),f(a,"mousedown",this._onTapStart),f(a,"touchstart",this._onTapStart),f(a,"selectstart",this._onTapStart),f(a,"dragover",this._onDragOver),f(a,"dragenter",this._onDragOver),Array.prototype.forEach.call(a.querySelectorAll("[draggable]"),function(a){a.removeAttribute("draggable")}),H.splice(H.indexOf(this._onDragOver),1),this._onDrop(),this.el=null}},a.utils={on:e,off:f,css:h,find:i,bind:b,closest:c,toggleClass:g,dispatchEvent:D},a.version="0.6.0",a.create=function(b,c){return new a(b,c)},a}); \ No newline at end of file +!function(a){"use strict";"function"==typeof define&&define.amd?define(a):"undefined"!=typeof module&&"undefined"!=typeof module.exports?module.exports=a():"undefined"!=typeof Package?Sortable=a():window.Sortable=a()}(function(){"use strict";function a(a,c){this.el=a,this.options=c=c||{};var d={group:Math.random(),sort:!0,store:null,handle:null,scroll:!0,scrollSensitivity:30,scrollSpeed:10,draggable:a.children[0]&&a.children[0].nodeName||(/[uo]l/i.test(a.nodeName)?"li":"*"),ghostClass:"sortable-ghost",ignore:"a, img",filter:null,animation:0,setData:function(a,b){a.setData("Text",b.textContent)}};for(var f in d)!(f in c)&&(c[f]=d[f]);c.group.name||(c.group={name:c.group}),["pull","put"].forEach(function(a){a in c.group||(c.group[a]=!0)}),G.forEach(function(d){c[d]=b(this,c[d]||H),e(a,d.substr(2).toLowerCase(),c[d])},this),a[z]=c.group.name;for(var g in this)"_"===g.charAt(0)&&(this[g]=b(this,this[g]));e(a,"mousedown",this._onTapStart),e(a,"touchstart",this._onTapStart),D&&e(a,"selectstart",this._onTapStart),e(a,"dragover",this._onDragOver),e(a,"dragenter",this._onDragOver),K.push(this._onDragOver),c.store&&this.sort(c.store.get(this))}function b(a,b){var c=J.call(arguments,2);return b.bind?b.bind.apply(b,[a].concat(c)):function(){return b.apply(a,c.concat(J.call(arguments)))}}function c(a,b,c){if("*"===b)return a;if(a){c=c||B,b=b.split(".");var d=b.shift().toUpperCase(),e=new RegExp("\\s("+b.join("|")+")\\s","g");do if(!(""!==d&&a.nodeName!=d||b.length&&((" "+a.className+" ").match(e)||[]).length!=b.length))return a;while(a!==c&&(a=a.parentNode))}return null}function d(a){a.dataTransfer.dropEffect="move",a.preventDefault()}function e(a,b,c){a.addEventListener(b,c,!1)}function f(a,b,c){a.removeEventListener(b,c,!1)}function g(a,b,c){if(a)if(a.classList)a.classList[c?"add":"remove"](b);else{var d=(" "+a.className+" ").replace(/\s+/g," ").replace(" "+b+" ","");a.className=d+(c?" "+b:"")}}function h(a,b,c){var d=a&&a.style;if(d){if(void 0===c)return B.defaultView&&B.defaultView.getComputedStyle?c=B.defaultView.getComputedStyle(a,""):a.currentStyle&&(c=a.currentStyle),void 0===b?c:c[b];b in d||(b="-webkit-"+b),d[b]=c+("string"==typeof c?"":"px")}}function i(a,b,c){if(a){var d=a.getElementsByTagName(b),e=0,f=d.length;if(c)for(;f>e;e++)c(d[e],e);return d}return[]}function j(a){a.draggable=!1}function k(){E=!1}function l(a,b){var c=a.lastElementChild,d=c.getBoundingClientRect();return b.clientY-(d.top+d.height)>5&&c}function m(a){for(var b=a.tagName+a.className+a.src+a.href+a.textContent,c=b.length,d=0;c--;)d+=b.charCodeAt(c);return d.toString(36)}function n(a,b){var c,d;return function(){void 0===c&&(c=arguments,d=this,setTimeout(function(){1===c.length?a.call(d,c[0]):a.apply(d,c),c=void 0},b))}}var o,p,q,r,s,t,u,v,w,x,y,z="Sortable"+(new Date).getTime(),A=window,B=A.document,C=A.parseInt,D=!!B.createElement("div").dragDrop,E=!1,F=function(a,b,c,d){var e=B.createEvent("Event");e.initEvent(b,!0,!0),e.item=c||a,e.from=d||a,a.dispatchEvent(e)},G="onAdd onUpdate onRemove onStart onEnd onFilter onSort".split(" "),H=function(){},I=Math.abs,J=[].slice,K=[];return a.prototype={constructor:a,_applyEffects:function(){g(o,this.options.ghostClass,!0)},_onTapStart:function(a){var b=a.touches&&a.touches[0],f=(b||a).target,g=this.options,k=this.el,l=g.filter;if("mousedown"!==a.type||0===a.button){if("function"==typeof l){if(l.call(this,f,this))return F(k,"filter",f),void 0}else if(l&&(l=l.split(",").filter(function(a){return c(f,a.trim(),k)}),l.length))return F(k,"filter",f),void 0;if(g.handle&&(f=c(f,g.handle,k)),f=c(f,g.draggable,k),f&&"selectstart"==a.type&&"A"!=f.tagName&&"IMG"!=f.tagName&&f.dragDrop(),f&&!o&&f.parentNode===k){x=a,r=this.el,o=f,t=o.nextSibling,w=this.options.group,o.draggable=!0,g.ignore.split(",").forEach(function(a){i(f,a.trim(),j)}),b&&(x={target:f,clientX:b.clientX,clientY:b.clientY},this._onDragStart(x,!0),a.preventDefault()),e(B,"mouseup",this._onDrop),e(B,"touchend",this._onDrop),e(B,"touchcancel",this._onDrop),e(r,"dragstart",this._onDragStart),e(r,"dragend",this._onDrop),e(B,"dragover",d);try{B.selection?B.selection.empty():window.getSelection().removeAllRanges()}catch(m){}F(o,"start"),"clone"==w.pull&&(q=o.cloneNode(!0),h(q,"display","none"),r.insertBefore(q,o))}}},_emulateDragOver:function(){if(y){h(p,"display","none");var a=B.elementFromPoint(y.clientX,y.clientY),b=a,c=this.options.group.name,d=K.length;if(b)do{if(b[z]===c){for(;d--;)K[d]({clientX:y.clientX,clientY:y.clientY,target:a,rootEl:b});break}a=b}while(b=b.parentNode);h(p,"display","")}},_onTouchMove:function(a){if(x){var b=a.touches[0],c=b.clientX-x.clientX,d=b.clientY-x.clientY,e="translate3d("+c+"px,"+d+"px,0)";y=b,h(p,"webkitTransform",e),h(p,"mozTransform",e),h(p,"msTransform",e),h(p,"transform",e),a.preventDefault()}},_onDragStart:function(a,b){var c=a.dataTransfer,d=this.options;if(this._offUpEvents(),b){var f,g=o.getBoundingClientRect(),i=h(o);p=o.cloneNode(!0),h(p,"top",g.top-C(i.marginTop,10)),h(p,"left",g.left-C(i.marginLeft,10)),h(p,"width",g.width),h(p,"height",g.height),h(p,"opacity","0.8"),h(p,"position","fixed"),h(p,"zIndex","100000"),r.appendChild(p),f=p.getBoundingClientRect(),h(p,"width",2*g.width-f.width),h(p,"height",2*g.height-f.height),e(B,"touchmove",this._onTouchMove),e(B,"touchend",this._onDrop),e(B,"touchcancel",this._onDrop),this._loopId=setInterval(this._emulateDragOver,150)}else c.effectAllowed="move",d.setData&&d.setData.call(this,c,o),e(B,"drop",this._onDrop);if(setTimeout(this._applyEffects,0),s=d.scroll,s===!0){s=o;do if(s.offsetWidth=h-f?e.right>h:-(e.left<0&&c>=f),k=c>=i-g?e.bottom>i:-(e.top<0&&c>=g);j||k?A.scrollTo(A.scrollX+j*d,A.scrollY+k*d):s&&(e=s.getBoundingClientRect(),j=(I(e.right-f)<=c)-(I(e.left-f)<=c),k=(I(e.bottom-g)<=c)-(I(e.top-g)<=c),k&&(s.scrollTop+=k*d),j&&(s.scrollLeft+=j*d))}},30),_onDragOver:function(a){var b,d,e,f=this.el,g=this.options,i=g.group,j=i.put,m=w===i;if(this._onDrag(a),!E&&(w.name===i.name||j&&j.indexOf&&j.indexOf(w.name)>-1)&&(m&&(g.sort||(e=!r.contains(o)))||j&&w.pull)&&(void 0===a.rootEl||a.rootEl===this.el)){if(b=c(a.target,g.draggable,f),d=o.getBoundingClientRect(),q&&q.state!==m&&(h(q,"display",m?"none":""),!m&&q.state&&r.insertBefore(q,o),q.state=m),e&&q)return r.insertBefore(o,q),void 0;if(0===f.children.length||f.children[0]===p||f===a.target&&(b=l(f,a))){if(b){if(b.animated)return;s=b.getBoundingClientRect()}f.appendChild(o),this._animate(d,o),b&&this._animate(s,b)}else if(b&&!b.animated&&b!==o&&void 0!==b.parentNode[z]){u!==b&&(u=b,v=h(b));var n,s=b.getBoundingClientRect(),t=s.right-s.left,x=s.bottom-s.top,y=/left|right|inline/.test(v.cssFloat+v.display),A=b.offsetWidth>o.offsetWidth,B=b.offsetHeight>o.offsetHeight,C=(y?(a.clientX-s.left)/t:(a.clientY-s.top)/x)>.5,D=b.nextElementSibling;E=!0,setTimeout(k,30),n=y?b.previousElementSibling===o&&!A||C&&A:D!==o&&!B||C&&B,n&&!D?f.appendChild(o):b.parentNode.insertBefore(o,n?D:b),this._animate(d,o),this._animate(s,b)}}},_animate:function(a,b){var c=this.options.animation;if(c){var d=b.getBoundingClientRect();h(b,"transition","none"),h(b,"transform","translate3d("+(a.left-d.left)+"px,"+(a.top-d.top)+"px,0)"),b.offsetWidth,h(b,"transition","all "+c+"ms"),h(b,"transform","translate3d(0,0,0)"),clearTimeout(b.animated),b.animated=setTimeout(function(){h(b,"transition",""),b.animated=!1},c)}},_offUpEvents:function(){f(B,"mouseup",this._onDrop),f(B,"touchmove",this._onTouchMove),f(B,"touchend",this._onDrop),f(B,"touchcancel",this._onDrop)},_onDrop:function(a){clearInterval(this._loopId),f(B,"drop",this._onDrop),f(B,"dragover",d),f(r,"dragend",this._onDrop),f(r,"dragstart",this._onDragStart),f(r,"selectstart",this._onTapStart),this._offUpEvents(),a&&(a.preventDefault(),a.stopPropagation(),p&&p.parentNode.removeChild(p),o&&(j(o),g(o,this.options.ghostClass,!1),r.contains(o)?o.nextSibling!==t&&(F(o,"update"),F(o,"sort"),q&&q.parentNode.removeChild(q)):(F(o,"sort"),F(r,"sort"),F(o,"add",o,r),F(r,"remove",o)),F(r,"end")),r=o=p=t=q=x=y=u=v=w=null,this.options.store&&this.options.store.set(this))},toArray:function(){for(var a,b=[],d=this.el.children,e=0,f=d.length;f>e;e++)a=d[e],c(a,this.options.draggable,this.el)&&b.push(a.getAttribute("data-id")||m(a));return b},sort:function(a){var b={},d=this.el;this.toArray().forEach(function(a,e){var f=d.children[e];c(f,this.options.draggable,d)&&(b[a]=f)},this),a.forEach(function(a){b[a]&&(d.removeChild(b[a]),d.appendChild(b[a]))})},closest:function(a,b){return c(a,b||this.options.draggable,this.el)},destroy:function(){var a=this.el,b=this.options;G.forEach(function(c){f(a,c.substr(2).toLowerCase(),b[c])}),f(a,"mousedown",this._onTapStart),f(a,"touchstart",this._onTapStart),f(a,"selectstart",this._onTapStart),f(a,"dragover",this._onDragOver),f(a,"dragenter",this._onDragOver),Array.prototype.forEach.call(a.querySelectorAll("[draggable]"),function(a){a.removeAttribute("draggable")}),K.splice(K.indexOf(this._onDragOver),1),this._onDrop(),this.el=null}},a.utils={on:e,off:f,css:h,find:i,bind:b,throttle:n,closest:c,toggleClass:g,dispatchEvent:F},a.version="0.6.0",a.create=function(b,c){return new a(b,c)},a}); \ No newline at end of file From 5e993ec504c2cc056235056e5d90bd6e05c6efc0 Mon Sep 17 00:00:00 2001 From: RubaXa Date: Tue, 2 Dec 2014 09:47:15 +0300 Subject: [PATCH 2/9] #134: window scroll --- Sortable.js | 55 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/Sortable.js b/Sortable.js index 0b6ccde..a6266ca 100644 --- a/Sortable.js +++ b/Sortable.js @@ -35,6 +35,7 @@ lastCSS, activeGroup, + autoScroll = {}, tapEvt, touchEvt, @@ -238,7 +239,7 @@ _on(rootEl, 'dragstart', this._onDragStart); _on(rootEl, 'dragend', this._onDrop); - _on(document, 'dragover', _globalDragOver); + _on(document, 'dragover', this); try { @@ -311,6 +312,7 @@ _css(ghostEl, 'msTransform', translate3d); _css(ghostEl, 'transform', translate3d); + this._onDrag(touch); evt.preventDefault(); } }, @@ -376,13 +378,14 @@ } }, - _onDrag: _throttle(function (/**Event*/evt) { + // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521 if (rootEl && this.options.scroll) { - var options = this.options, + var el, + rect, + options = this.options, sens = options.scrollSensitivity, speed = options.scrollSpeed, - rect = rootEl.getBoundingClientRect(), x = evt.clientX, y = evt.clientY, @@ -390,21 +393,37 @@ winWidth = window.innerWidth, winHeight = window.innerHeight, - vx = (winWidth - x <= sens) ? (rect.right > winWidth) : -(rect.left < 0 && x <= sens), - vy = (winHeight - y <= sens) ? (rect.bottom > winHeight) : -(rect.top < 0 && y <= sens) + vx = (winWidth - x <= sens) - (x <= sens), + vy = (winHeight - y <= sens) - (y <= sens) ; - if (vx || vy) { - win.scrollTo(win.scrollX + vx * speed, win.scrollY + vy * speed); + el = win; } else if (scrollEl) { + el = scrollEl; rect = scrollEl.getBoundingClientRect(); vx = (abs(rect.right - x) <= sens) - (abs(rect.left - x) <= sens); vy = (abs(rect.bottom - y) <= sens) - (abs(rect.top - y) <= sens); + } + + if (autoScroll.vx !== vx || autoScroll.vy !== vy || autoScroll.el !== el) { + autoScroll.el = el; + autoScroll.vx = vx; + autoScroll.vy = vy; - vy && (scrollEl.scrollTop += vy * speed); - vx && (scrollEl.scrollLeft += vx * speed); + clearInterval(autoScroll.pid); + + if (el) { + autoScroll.pid = setInterval(function () { + if (el === win) { + win.scrollTo(win.scrollX + vx * speed, win.scrollY + vy * speed); + } else { + vy && (el.scrollTop += vy * speed); + vx && (el.scrollLeft += vx * speed); + } + }, 24); + } } } }, 30), @@ -420,9 +439,6 @@ groupPut = group.put, isOwner = (activeGroup === group); - // Because bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521 - this._onDrag(evt); - if (!_silent && (activeGroup.name === group.name || groupPut && groupPut.indexOf && groupPut.indexOf(activeGroup.name) > -1) && (isOwner && (options.sort || (revert = !rootEl.contains(dragEl))) || groupPut && activeGroup.pull) && @@ -529,10 +545,11 @@ _onDrop: function (/**Event*/evt) { clearInterval(this._loopId); + clearInterval(autoScroll.pid); // Unbind events _off(document, 'drop', this._onDrop); - _off(document, 'dragover', _globalDragOver); + _off(document, 'dragover', this); _off(rootEl, 'dragend', this._onDrop); _off(rootEl, 'dragstart', this._onDragStart); @@ -592,6 +609,16 @@ }, + handleEvent: function (/**Event*/evt) { + var type = evt.type; + + if (type === 'dragover') { + this._onDrag(evt); + _globalDragOver(evt); + } + }, + + /** * Serializes the item into an array of string. * @returns {String[]} From cfd9b520a8b0ec2a7d30acccb6a6851a674b3bfc Mon Sep 17 00:00:00 2001 From: RubaXa Date: Tue, 2 Dec 2014 17:41:04 +0300 Subject: [PATCH 3/9] #134: * scrollEl detect --- Sortable.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sortable.js b/Sortable.js index a6266ca..4119d97 100644 --- a/Sortable.js +++ b/Sortable.js @@ -365,7 +365,7 @@ scrollEl = options.scroll; if (scrollEl === true) { - scrollEl = dragEl; + scrollEl = rootEl; do { if ((scrollEl.offsetWidth < scrollEl.scrollWidth) || From 332fc25db87cadb2a375444d1b5273feff090397 Mon Sep 17 00:00:00 2001 From: RubaXa Date: Tue, 2 Dec 2014 18:45:05 +0300 Subject: [PATCH 4/9] #134: fixed destroy --- Sortable.js | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/Sortable.js b/Sortable.js index 4119d97..0dd667a 100644 --- a/Sortable.js +++ b/Sortable.js @@ -49,14 +49,14 @@ _silent = false, - _dispatchEvent = function (rootEl, name, targetEl, fromEl) { + _dispatchEvent = function (el, name, targetEl, fromEl) { var evt = document.createEvent('Event'); evt.initEvent(name, true, true); - evt.item = targetEl || rootEl; - evt.from = fromEl || rootEl; + evt.item = targetEl || el; + evt.from = fromEl || el; - rootEl.dispatchEvent(evt); + el.dispatchEvent(evt); }, _customEvents = 'onAdd onUpdate onRemove onStart onEnd onFilter onSort'.split(' '), @@ -357,7 +357,7 @@ dataTransfer.effectAllowed = 'move'; options.setData && options.setData.call(this, dataTransfer, dragEl); - _on(document, 'drop', this._onDrop); + _on(document, 'drop', this); } setTimeout(this._applyEffects, 0); @@ -365,7 +365,7 @@ scrollEl = options.scroll; if (scrollEl === true) { - scrollEl = rootEl; + scrollEl = dragEl; do { if ((scrollEl.offsetWidth < scrollEl.scrollWidth) || @@ -544,16 +544,17 @@ }, _onDrop: function (/**Event*/evt) { + var el = this.el; + clearInterval(this._loopId); clearInterval(autoScroll.pid); // Unbind events - _off(document, 'drop', this._onDrop); + _off(document, 'drop', this); _off(document, 'dragover', this); - _off(rootEl, 'dragend', this._onDrop); - _off(rootEl, 'dragstart', this._onDragStart); - _off(rootEl, 'selectstart', this._onTapStart); + _off(el, 'dragend', this._onDrop); + _off(el, 'dragstart', this._onDragStart); this._offUpEvents(); @@ -616,6 +617,9 @@ this._onDrag(evt); _globalDragOver(evt); } + else if (type === 'drop') { + this._onDrop(evt); + } }, From 07ff86a424e500ad146e6cb3b077555077224bb0 Mon Sep 17 00:00:00 2001 From: RubaXa Date: Tue, 2 Dec 2014 19:40:29 +0300 Subject: [PATCH 5/9] #134: revert scrollEl delect --- Sortable.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sortable.js b/Sortable.js index 0dd667a..0b5bf0a 100644 --- a/Sortable.js +++ b/Sortable.js @@ -365,7 +365,7 @@ scrollEl = options.scroll; if (scrollEl === true) { - scrollEl = dragEl; + scrollEl = rootEl; do { if ((scrollEl.offsetWidth < scrollEl.scrollWidth) || From 4084d84508125f01ec6fc713265d240a6b82093c Mon Sep 17 00:00:00 2001 From: RubaXa Date: Wed, 10 Dec 2014 17:45:18 +0300 Subject: [PATCH 6/9] + og:image --- index.html | 1 + st/og-image.png | Bin 0 -> 12039 bytes 2 files changed, 1 insertion(+) create mode 100644 st/og-image.png diff --git a/index.html b/index.html index ce2590a..5f8151d 100644 --- a/index.html +++ b/index.html @@ -3,6 +3,7 @@ + Sortable. No jQuery. diff --git a/st/og-image.png b/st/og-image.png new file mode 100644 index 0000000000000000000000000000000000000000..7d7a51da9a6fb573a5df0a4ea189dafa51e7231a GIT binary patch literal 12039 zcmdUVS5Q<@*JXo%-ZgKnG6ZhGBt+mfRk?N{S6r@a~5D0|g8T_dR1cFZj zE+{b(c=9v-elGY&-~oH4MGXG@i7nrP-z2VZeGdqPj23s{4b23egNH1h3VNQJF4msj z=I&OICzdX+tZpmXxm$U=xI1{+zcq z_&|i)wowiOxea;t^of>F+UAU!qtSQ^_c2G&?+VUAB9(7B>izCJa5;PNm`Wz~;CM$o z;eFccjNiL+nAOEX8EkAkuZ0r)`WljfO%+dt_@>%1R=Yhc{x&cZb+0<|Lqx=_t3e2t z(8JrcnFMjd-&m?{PV%6>etEU}P&BHiigP`!=hU>WNQPZ5PD?=}X{6L}?o6`Hqc7v^ zXgk8|9Q(?4`vzWcw$OvsYY@o0XK)B42T1_At^8l{Mmbalvd5ZCX}%tb>EBPpc8<1^ zn_Eer?RUrrgd+1?FivOqNr_^e*lo4O)&muak$zsZ+;9Vg2tSC)Y4{ zq$Ou2$Bm|1KbM!;WSbw5&4*Ag^XMO^1-PFbQTA6;v!z)$)KY&cg7WD~UZs5hyV($Q z6=;}wJRFtXqV~^0>1#FFVHd|tgSxmyZieyC^4V^Ie=(9UMcq6W6e=5IWGFGx7Ub=F zCe?)K@g+hl!&j@_?~@T;kQ4dpjLZ9+EmD_VKAZGOpxc!)H0la`)c)Fu*iC@s9}zGCZ8qlTNP?WE}g3gMMoy@(4-9b=}O zJ)_srCPiOnI5@F-4Rk2peQ5LfbXM#a->71N1@u=MO4UBfQ+UdX6m!W-G7`zs(W>mS z_M0tw>D06c+j(_jS^w;6$wtL}^Vb|_9vKbEm?Py!$mFywthM7vwfWm9mGl5sM6nU+ zJVtg+Rl-(;d5dqOL!__Pxw)&kIw0fzt)uaR2xNq4xHf|>Q2-}e3BDTQB{+>U;TT&& z_v20K%wo%s`3>hou?}|Kae0X#1zN!z;eIRaA}`pgyC`z0wj}a(>Dc6qKSx5JZq?2} zA9KH=G;+?!gJwJ5jg*7}G$kM)*>3>l^wbA7j#U-83ZJ%JU01s9115|TuO?OEHQo~V z+YSuo>YRN*cD}HF7#+$cUie96O89>3BtqS!EPQ99r-<}I=sh(1N3YsG5-ITbAuDQQ z&TgyE*-g}Mn03T|Px0t1c_oEC#b;%ak55Q~JJ!;8tyhPN$y+rvrDcftYx!@{pbV!G zd7lks`n0ulEx3nb|B#PseFViVTXJ6WoYg%hQ4%ueD#YtK={9OuCMvvd84n3--he zmoE=^6yU3G-0veZGrHT3DbO=7t1YH^NH4SntmO526T+hyDZT9Tm=^G7C3ER$*~U~8 zJzq;B#b>=U+KEYwE2bu9h0=q2-+O1a8DPY7UcMBtx>;ns^**qT1vSM^(dj$ZJ@VHa zaY6p^B?SqULmuMwfzB8eIv0aKnJwJE)Rrv(%+{lV_6R8+t9sDYK6)N2Sro!rcBcE@9g$eEzmg&j}TRYO`TdmJq0)ph03y)tVkqE4OX-aurO%H)RS>!k6n zo~CJR3wI~M{moX^z6o2g+i7hn=@w`WX?Wpi_4Xo4 zAV8pcSl@-H#=@$lA!`RsXpS|9!BXEp&mU)+D4+_Gv(+=|Qht4ZF4a%yZseB45iC${ zqQC}CmOFN1@33?7v#W`|PuYhH|18$p)2%1wUop!oxCTrvy-piUVbb6juK zc_gjvL*UEwH0>9w;SI_<$RPjH&j_(dp0Z5~^(>W`w~E_f#|HVpkUg zW1O*cqsTr0a?PKFXJrKNva^%3c5-iQ9oo)yBQDj~lc9ea>XML1u`i9LXO&l|+r}-4 zWgnVde-Sp_Sn-CRTl$gXRIWtn$}iv2-ZanSm<8#&5d^dfw; zyYGW#ciuUnQQ2%2UT=Hec^noUcF9VXyRx1+gf=)eK_WlpZ5fQ&=ZfY+)$Hd}eZ4*T zCHFTySB;8e`n3M2F1?6JyU#59HJ}zjtV^r?SJmq?%S{+8DcW5SrCRu|OY7O5vw~HU zcwJrDd$pbE7fybmH3_=QG3>*wT6ycgK3+(_ze7uFkbt;hWU>KM=5 zPd$%)2o3r6rQ4%p$4gfr&yNPow~kxBuI1uoV@h06-*;zwQ_53fz_D5Ug_6b=K23(l z)~728;x?(zOEb#2ekZ(W4|B#%gQq&y;+cINziy z{mJujUY3t%>K<%Gan;@_PpNQ)SKsoCT5yfhu-IKZ?l|sP$ci;P{x`E!bf?DJ?QV<1 zG76dx-_^^{g6TLReOq^Hc6 zW+_a)$CAvp9UzN<-lVn8r+74wq9^P&tFyESgWJm6-);U_E%5xy(&pI%O3Al}s0HOy zn9O_m;2Q4NWhI>9Nu7~#1L4ia=)PslYNwA1h3FR^O%ZOb*aC1MkH$y2=j9N9%OaY2x&o7@rCRs;1`cw-R=jt(bDG%Ls`2mspr@+vv(oiE2NsaVaFiDOTbpF=p9Ept}Au%3$u1*X^ zCS{V%yIeI<15{iP-QpV=GA?XIx=m*%`YU}MJ_|fwHVBH%TLrvjpiecQl$0_BJNf6R zqkp_s=x9th8a9}iGHF)4xuvXag>+*B{^7tA>$_qh{N8JCY{Y8RfS%4IS&e%%qE{7g zBotW@C)&-YTRqnqpc(IGR*>DKGrm}CKuRLQl1w?T#J!-&raP`p^9qS%Yp73%aY#3` zZS}RES3lgq?3Ofn+3}N66r28wZP0Km{HlPan9)9SA5fBu@70F+@Y7I(5ORGGdxI8H zU_dq>(~kM)Z&g;Sx{>To%-ut^yyHAlEuOek>-cASonh-~go6FOt}9dTyf@hC=RvWd z3thz+G5j~<7HM$<*Ly~(XA7+J%97gBO`19Swbp*5&31IP>huUi7jNjh3VkBl`EGPK zb@{Wsi4y@q;vW%ccC5}A&=_}-WLKa02@%T;ee{0G_iftfDW!=ii#Miz%t!HwNSs9V zFp&%}1BMs3@Ex66vj4`IK?;+BnnUalN=(h&?(!-K`V0HzW|sf#>@j#C*}^KtR;0tH z%U&wx^AfAO4qLj)ZbFvrYR{I{2>1(6U3k=OtZpY&w?6RV<|Lm$hd_~z@SF!F12F^C zsL=AGy~Di$Fkn5sA_GLiAk;IawcG2U28gO(A15E6q8cqQv4bQ`ymRGmv5+H zW#rKxKaA&=EEf~up|FXS)%)P-)}DS#sF_Jzw#+J>hBh2PP5L<%_k!}HV)Ea*RdbS) zBi3Gz$;fPCRp!3$*gn6}R`2-EN1TL&Bg>#CP`n(oqQ1%I4O&Gl$Im%~8dG= zM#OZlO0wICOZLV3!|-EEMh7rMgVj@0r3OQu-lH+puX;LkyPHzAap7gYpYjFo7D8W`?6j|bSO1dD?#|s z7_B_%H=*#YqOq#hP*W4q`E7wsnJ)wNlY`h4E>3FgQY-W9WQIQtgiiqFky!|{HS*R@ z?aos51d{E!u=1i!7j7a|$p6P+ID%F&e)5G5*&N;i-$ zj?QRHx%^zHp>uQTB@F+Cp?*KDFVDT-3GxzWYNvkB(YIYvawU_t;Dlvbau!njWk}a~ zgVU3SciF?~NCJZ@L-h$Ksw20=#?*uA_4gy{Nw4ostZl~bd$$GL6}xE{O+r%RXeEs_ zHCC0~RyeF*S3GwMV3~Q4`uVcHd2DXcOakZ|QyT3TK5~HTdPY5kEi81Ov8g{>E%g;< zwtZ5Xp-rdJCpF$?asM%(OhAx`-@3FxBlZiu_Fe|2u>3upKf^Wf?kV=XViJ=is#OIS zl+j%PxiXi>_1os^#WoIEosZv`g0$%5l3l~Rw8VztOW`kG=dus{@h|)|Mn8|f9%g^$ zP$F{Xo?~C(davz|kboBL>aS7Rc6JxXsqSmKw7nX=&J_wqMfQ2`zB|)$O+J!pz-#>a?-j4yKZ5T3h|^s zT8)5q*yJyg@|}vjpX8qlKeU2E$oC@ErF#+;7*`Mb11!^C(`Mr{Bm06UH$$wK`0K5L zZbGx~7k-3CN_?9;Hw^0?{EUz$?zIr#rN^FnF-8YB*NQCD^7_8N0nL6^SbHQY zI8?M`-`KzO+oOo2sjK)7pYCu>job$4=I%;;YNH~v0M}v5XP&T~ce6+%o7nu!Y8abm z60VziZF`Gkw+~G2&q||I$MlklxSG$?%GMJalo3wI+7x{XpbT!uN z_5zix$9s82Bv7R577&e{LMP^ynQ`IGncOw#$0RVAiUzMo%lT$2o8tVJPlB}#s;$lT zC``?!y*I*2CScISSbUQP0YvE&d;OV@)r-cTlto>>>M;BZnKM$6^**fU(MAK`+3wBD z>_2;i4`9l`^*{%a7GT7Hx}P*;@$*y1%*?3aNz=^?zaNef?)QT}o7ZJR2V|hx3WZy1 zphe&DB!dG1f~W+Mjq_2@K^CUDEHJn8#20go3sRvbK;mf?=NFTBB<|XaN$wk+Qub@rj5S}l z1$LePa||4{rfUHSh2-+6VW04-C^Va*N&7~Jxmtwsqn6cJ3a>x=8$BluDrts{nOUxT z@W9*!gI=L)*iay~45Ztn&i_OXZmS&+Mq&kGby^(MO4(550xLnkB?!WFm#epht#UI6 zdC=qoejuCK>qcwlQJY-#trCTK2!6?zE*q^Iuy7rKb$r8P-IzKV9LOJgPJl?3ZLG zBgTe@%?%-ul$&1T;@aI?$APZ?KHI0=c{A5g>j;n;R|a*8Q1+QlO5;!sD7X2UM|+7U zC2uOGm`vhcXm`}0RBeFT{n)i8e@GfrPZp@mVFUSVd zW<*6(hKnM51Kwo;4*y-}?Q&&zDv~T$#Z-+!@IwB|2;)aaMp115xs7e z_{F&U*9>U7gEYA^dl6Klz#8A4bdj}=D(^K|I)t#lP6XT<9^XbYTPhIgcU)ov!DC;<> zH431HpKbn&$1ob`n_+;kcx`$7F0iXdf|8e4LGq-Lc@H_OOXDplT z_EI-8-gdH;0Q)Fl6Q-$er1AQL9&KsjP>o_>i&yl^DTRl~xRxjV+EvSwyi<}~CKsA6 zmsj0+n6#8)UI;R{JzCWo-Zv5Selv(c5g@KVXM(!qjn zIz4Ytdj`a{g4N|yJ|+4~8e{&N_icWdc|AsQsD1Oob2+|nzqJ2|Rm$BP={~;HT6^*u z%4Z4nw32R;`{rSy-934NuzW1p#U{L?!!U`12499luTZ()LL!FmQ`Zmc19FuI)|s)6i!Y>yxGNen!iLhj)oR!Y zUg?ZS*eDX^ZmySN`EougbsR0j;j5wc{Jb>%KoDD%H8IPH!k(6wI0-UZ)wL`blv!&R zE2=#cpZ(c%3s<|^{%tZDUHcUK3KBW#*l^;;^6Dn-sci!jig~oe^YwBACTF%(^1|5= zXhgS3)>$Eaux}{(jZbhvIaAkVvz1?r99H{D^ti+N@9%`_>_xW{F3kV3X-PvCQKeXZ zlKjJaP%MRO?sB36b*~_ydVk|z{H!j~UP+nFyj5Jax6gF^nj=kpddH*hqNjBl9lJIh zoOHk9*DwMV!(0{CP9xR&bUjmT&uv(Y6E|Bwg~?AgjBY@S5)b(3_;d-cFMkgg<}a^tH*N$}cEv6Md4lB**j2rkXR3%&=%gS@4sh5VPhDHyui zX)`{_+@72Jvp>45s1h=t+;(2>j9t%y1aIAcp?VRt=|7t>9@ye9d+_g~v>Y`yrW-4J zsVzO-c6FQ|pgkAuAAe@PQ7kz1NDPuiHhao`wIRLfZ*qUTOZtW%dN#5pzCR^8@cf2( z(C}3S1Rv7=iJ2Brn2-1GQfK0{=<;~c&@}AK&@fiI^dhadqF6q&^ehmK!7{8Q>^{R2@aSc%Ii1QfILv2^eAc!~;|?{2gLE z0$Xa@;8q$rvwC8Z?{I3ltTQA*urXFT7)kwYJ$BnQRo3Zf*9<=$EF#gpTXKy;(%!r; zTd3u1KgB_Wa<~pV1b6X?d%;`VWXMA{@G*i^0dk)biWgi74X#myLxKhFAs}`UaS#aM zcn{>m+4do}_!>lB<^R(ciz1QLYmCTh!9Jv}Y1%EUIeFrSxHw8MuOj&Of|A48xc9-jQ3|*x#9$FI37Xc5)7L5O6j@;6SPA)zrTGf9d!HXWbfZo329l@Swn;EVVWPg-5+nv{~Wyd&o%8$8LkGpqGAtZ z6PT-K-g0uLINc#e(3){d2V~Kyvdpw?bf#xyZlMR|JTgk3hmV^exXu?c*(q#H(@4&^ zS`;W!uJ9P2^tPU`OG@3$=)3hH_{lvrRh$`U=t;k;u_>za-h8tybEQQUOYmo$m`pb4 zKoC`lUV6gbr^nP|_?C>lBn(^>r$ViV%cfUW*j@Ik?JJkeSmet%d%fm>d^RwqFdN>F zu~KCrZpSx$4+mSjB6l2@n4w7O_v{&`r`wXLjQcE7>ZGz~mvtx?GOtax>lU|Y%@Xo> zu5I&|M)YrupdAFI_kS%iF|OtLr5c*51vsA1x&rgF$V%M=bG*{?iSa#XPu{_XX!z{U zsQI~Xdqr60dLa$e){jS7^e z$zRErfAmlr1N^4me{pL(s4cLX-dRcKTeUU5f_rY`t-#%;(di;o!!`@KQtGNzRsak? z`mN{9`Q0c-Or_#A4myS0qBsUR6TdZe_E_6$B`1=ZcO#7Dc2;!y_7c59`rafYLdf?zT9uOf1J{e?4vSa^voCM4Y*>I!@?WMXqIv@I-C-bA?&X(5 z+X4_Qe(`ZCIG3U=6kk)tRo<-P=2WMdpBCW8bvk{J%6#a)N(03sEi=V6D;DtBCo3WC4N*&li~F7Po~uJw&qsTImUWIt zo9c*MwHBYigYh@Kfk_LM6^fMb5%aZ48P5bVJm*72TZpAOIpsnQn#|quNBAN@Sbl2H zTRD88ip*>~W$3yeoAhby2vDAwn9v+0OsBQ3+QQyKOx5JS=v?5$=3io0 zGWflqIL&!N{1FYX8GB!=#77JoWT|t374!oB6=R(o%r3wR>a#`e7nCG1qBma2vkUgJ zQ-f`W!EQ?&N~`v(DcJ~$jDXm`I;9G7Z#_tkn-@(5#|tPmac2P_gb4 zOth-KY7up_ZB8rFDLAx}@cA3*TJ!MMd)5rnPO2o2&?jgd<<#%|NZEIUAPMe$&i4@0 zSl0!n8+RE)ZAu>4zFx$h*HG@`^%&aPQZt!nna}-uTGe*DKQHgKCd>8b@ZdMMMo6QY zPS6pV5gzfc_uJ0SHDRb=Rsgu=^!GSD7xrSB=J#U!z}3Wao$xkr0lGY3{2uWwMfo>G zijUpSRHdg2E*}}Sy1D#akpLUKS#s}2D(Z)ArV^tk)ZY>*{&~G4cb{dN?Um%&!t;6n zWMwnc>d)>G1Bdux3ml@Q4mVX1p&^RvR0*iUleJB*NgLD>vp1Su<{SoLy&ZM`$rHLt z(5YiD(ucYNpJT=gg!oSNb`URM*lMwx%+!el_ul3J$iU7HA&!fG*+(%kUSIjRZjEE( zP?_lR&D1nvCH9owfzO)*TYM1~5&5Y8)+>HZ=yf?@0(clQr)Bpm>E^~LLsK!3D2vU@{O56xM9}*6DjM`lqCBJqEJfLd&)cFaBv2NbG`6+_g zw{Rp9Mm2`&zZ{M+Mg!y7J<09_;84-bpB-h;*jCqYQ(zL7!e);Q%e*>_#VLq?o#`o= zUVR5~agb|be7JxtV(Hi6VqbHNQ1u5ahNBkCdlXQl$K0cWH=`T?!_{XG>lGaIrVA_A zG@~UY8#jBsWhvSaN5lX2WdqlecRX`Wk`4hZ%AvB`0}Ny+)773l4k5N;v$`|RVwSymH) z`?JavIxA*MO5QQFW(dP$VT>DL?YHq>mw%l-CEg%@>XRF?tGMura z&WAIbK|1p2%0uE!l=*wk0Z~4W5ZGN0lfjXd19!7IfNGOdpyno1|2A&`5qj!qR76a% zcz7{nTG*jahIkE-KA^^he7mIdJ6zCMg>TXy&`E&Ihe68$qSI9%&bq?e0c3n?{!0;> z4_w|Mveyf^KX2h0DtG8y(iUuWzbwL8O zT0DJMGfbw-L60SI&7kl_A*ilWSSvy9@fs)_@cb|D>HAo)UnmJgQJwp%Y{3)&-t7NG z`ApgxXk=6{UnLxY@VeX7D=LKAp`p#90>)9YD#)I1N$V|iY`un70L}aY&DX}^6sN1? z%UggyfqEaX=%h^gND);ybY9Uj1v603n$ke)p{r8u<4M3vfOc>haUS4ROWI0cSF{(~ zIlKEYjO`DA%$Ym^BsEyd_ZYG6%$Y*&VosouCjBGI9sx=UkP`i;;D97p&2Da5epz}) z1mKC_N!nVRr;2@nxt29KMM@k*I$^v*qUeH{0w??oUWF;hQ-aqgRu{xGP)@m65N+=T zUb4W(DkLaX=m71Gzvm8T4)ZS`k zy%tAg$9Xn6{WGna;v)kJFnrJC@OGu8{}8(ujt5Vens$B|WX4+806SSR(X;1=#5+F% zlyJ%OvheIn<0E&!Y;rJ1V=OMr&36yePbYBV3uqvjXa3tvjCNydCu=(fuRa51Jd3#U zVvn_!0_&l`L_fUO8blF|v91f=IbshiW5@;yYBi@hPH4+&pgH`7JmnXW6uNzU6!+*0 zZ6q6*uL_Rw9lti#)W~>&Nz6=5lO~mXhm*Z$6^Qr`k3yTNtIV5C&z);yl|)U*31CTS zeRg^xE|U9OL+SqrudwIX30=cqICuk@!n3l_0d>&E)fT(+`vA!HT_|4TUz~adD81^j z>?G@YVa-3?su`I__%soSUX9n>|rA|!lnrCW>qub6RQu~tF0E3W; z@QH2XvX;Jp6*FuD$cUC3V&iiYyUKM{pNC;SgY-*_`t&J0SYV)HqWS34SQzp_6<7m+ z*NVhYGD0=>dmyQpBUa-5IM|!)wGR+AjUxakhX@hAZ(l3%Eiiq%e-A5q>-mjm3UOqR z8g!8acp{@Q(1Rl_=&HKX*uhdASTQcVeGJD>`X(~cL2~fF4t3ijXaKlc|A;{El(u?~ z{eY-GQbYq$JN_MB52`oU)d;YVe~yE&4nz&Kg0Z2C1^b?64yOubIL{SE0OAY>4=H%* zkf6vfLsdQaFQDIm`No~cKzhgwFgnFdT@Hp{vxYtQtdcwf%-g-xbnJLm_VU`IEpU~S z*ZW%_k92kMaPUKy%Q~#H;`^DL9qe5^VJCnLNV;4em~Ppv>|Hl9_fY+vJxJ-8i(xjxWc}btvO=qkjuqr-V3qj*N_$#T-e|5o8gAZ3?az&l6x1 z)!fLqnKd;`fGf#NbsgOya&v`^5?|;ilE4gu;Tzu$C@{MEzE~U}k zf2&TMkje+RkNm%RjaE0mtZ_i+!PEDBIyOVzxE_R1V$If!f>D6bQu93UK>8u%&X-O$ zzzV|;vjQ)ExLf6|80bINz0aN{0lwS40?&4#oYBDX4nFk}-tHI;`lbJvA=re5mh|UP z1B4D7$GGOJxf4BgO^6SPWC3N&(qh^ragAramS><%$#`Qk%?5e=up$n047vBMH3GT! z@p>EPsEq_t)5rf9LVcGL0s)^C{~vEeD@t?hX7~GL4kj#)#Mb9?)wU`B+A<<19triy zod4T@!j2zJ2sI}@PYv2tWB0?LWdmt0mt~DuzYhu#S9+MGrJpsagvt;wl7%z>?^}OE z^~CZR*^9YM@>A+y8ZMCb+@K9Mc{u&wA`WmNt7SKE9a6J>uBJ+HN`1QEa=92p$sV|O zl0|i`9bpAS3R_Ty`bkFgoO!g6h*UnAw~E0Z$EJa{vGU literal 0 HcmV?d00001 From 3e32753867cd04cba1d9655813f84df0ff9b63f1 Mon Sep 17 00:00:00 2001 From: RubaXa Date: Wed, 10 Dec 2014 23:06:12 +0300 Subject: [PATCH 7/9] * support group.put for touch --- Sortable.js | 46 ++++++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/Sortable.js b/Sortable.js index ea51817..fb81187 100644 --- a/Sortable.js +++ b/Sortable.js @@ -104,7 +104,8 @@ setData: function (dataTransfer, dragEl) { dataTransfer.setData('Text', dragEl.textContent); } - }; + }, + group; // Set default options @@ -116,11 +117,12 @@ if (!options.group.name) { options.group = { name: options.group }; } + group = options.group; ['pull', 'put'].forEach(function (key) { - if (!(key in options.group)) { - options.group[key] = true; + if (!(key in group)) { + group[key] = true; } }); @@ -133,7 +135,7 @@ // Export group name - el[expando] = options.group.name; + el[expando] = group.name + ' ' + (group.put.join ? group.put.join(' ') : ''); // Bind all private methods @@ -249,8 +251,8 @@ _on(document, 'touchend', this._onDrop); _on(document, 'touchcancel', this._onDrop); + _on(dragEl, 'dragend', this); _on(rootEl, 'dragstart', this._onDragStart); - _on(rootEl, 'dragend', this._onDrop); _on(document, 'dragover', this); @@ -282,29 +284,19 @@ _css(ghostEl, 'display', 'none'); var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY), - parent = target, + parent = target.parentNode, groupName = this.options.group.name, i = touchDragOverListeners.length; - if (parent) { - do { - if (parent[expando] === groupName) { - while (i--) { - touchDragOverListeners[i]({ - clientX: touchEvt.clientX, - clientY: touchEvt.clientY, - target: target, - rootEl: parent - }); - } - - break; - } - - target = parent; // store last element + if (parent && (' ' + parent[expando] + ' ').indexOf(groupName) > -1) { + while (i--) { + touchDragOverListeners[i]({ + clientX: touchEvt.clientX, + clientY: touchEvt.clientY, + target: target, + rootEl: parent + }); } - /* jshint boss:true */ - while (parent = parent.parentNode); } _css(ghostEl, 'display', ''); @@ -579,7 +571,6 @@ _off(document, 'drop', this); _off(document, 'dragover', this); - _off(el, 'dragend', this._onDrop); _off(el, 'dragstart', this._onDragStart); this._offUpEvents(); @@ -591,8 +582,11 @@ ghostEl && ghostEl.parentNode.removeChild(ghostEl); if (dragEl) { + _off(dragEl, 'dragend', this); + // get the index of the dragged element within its parent var newIndex = _index(dragEl); + _disableDraggable(dragEl); _toggleClass(dragEl, this.options.ghostClass, false); @@ -647,7 +641,7 @@ this._onDrag(evt); _globalDragOver(evt); } - else if (type === 'drop') { + else if (type === 'drop' || type === 'dragend') { this._onDrop(evt); } }, From 3f7f9ef08fc4145e651f35d723a8af37b515030a Mon Sep 17 00:00:00 2001 From: RubaXa Date: Wed, 10 Dec 2014 23:47:03 +0300 Subject: [PATCH 8/9] #162: + '>*' support for closest --- Sortable.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Sortable.js b/Sortable.js index fb81187..77541d3 100644 --- a/Sortable.js +++ b/Sortable.js @@ -96,7 +96,7 @@ scroll: true, scrollSensitivity: 30, scrollSpeed: 10, - draggable: el.children[0] && el.children[0].nodeName || (/[uo]l/i.test(el.nodeName) ? 'li' : '*'), + draggable: /[uo]l/i.test(el.nodeName) ? 'li' : '>*', ghostClass: 'sortable-ghost', ignore: 'a, img', filter: null, @@ -762,10 +762,7 @@ function _closest(/**HTMLElement*/el, /**String*/selector, /**HTMLElement*/ctx) { - if (selector === '*') { - return el; - } - else if (el) { + if (el) { ctx = ctx || document; selector = selector.split('.'); @@ -774,8 +771,10 @@ do { if ( - (tag === '' || el.nodeName == tag) && - (!selector.length || ((' ' + el.className + ' ').match(re) || []).length == selector.length) + (tag === '>*' && el.parentNode === ctx) || ( + (tag === '' || el.nodeName == tag) && + (!selector.length || ((' ' + el.className + ' ').match(re) || []).length == selector.length) + ) ) { return el; } From a5ee80e72351d5fc8e2c33066276d3b2f066121e Mon Sep 17 00:00:00 2001 From: RubaXa Date: Thu, 11 Dec 2014 11:41:34 +0300 Subject: [PATCH 9/9] #167: + ghostClass, scroll, scrollSensitivity, scrollSpeed --- README.md | 48 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b58b94a..aefdd7b 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ var sortable = new Sortable(el, { handle: ".my-handle", // Drag handle selector within list items filter: ".ignore-elements", // Selectors that do not lead to dragging (String or Function) draggable: ".item", // Specifies which items inside the element should be sortable - ghostClass: "sortable-ghost", // Class name for the drop placeholder - jsbin.com/luxero/3 + ghostClass: "sortable-ghost", // Class name for the drop placeholder scroll: true, // or HTMLElement scrollSensitivity: 30, // px, how near the mouse must be to an edge to start scrolling. @@ -198,6 +198,52 @@ Sortable.create(list, { --- +#### `ghostClass` option +Class name for the drop placeholder. + +Demo: http://jsbin.com/boqugumiqi/1/edit?css,js,output + +```css +.ghost { + opacity: 0.4; +} +``` + +```js +Sortable.create(list, { + ghostClass: "ghost" +}); +``` + + +--- + + +#### `scroll` option +If set to `true`, the page (or sortable-area) scrolls when coming to an edge. + +Demo: + - `window`: http://jsbin.com/boqugumiqi/1/edit?html,js,output + - `overflow: hidden`: http://jsbin.com/kohamakiwi/1/edit?html,js,output + + +--- + + +#### `scrollSensitivity` option +Defines how near the mouse must be to an edge to start scrolling. + + +--- + + +#### `scrollSpeed` option +The speed at which the window should scroll once the mouse pointer gets within the `scrollSensitivity` distance. + + +--- + + ### Support AngularJS Include [ng-sortable.js](ng-sortable.js)