diff --git a/.jshintrc b/.jshintrc
index e870dcc..3f67a09 100644
--- a/.jshintrc
+++ b/.jshintrc
@@ -1,9 +1,9 @@
{
"strict": true,
- "newcap": false, // "Tolerate uncapitalized constructors"
+ "newcap": false,
"node": true,
- "expr": true, // - true && call() "Expected an assignment or function call and instead saw an expression."
- "supernew": true, // - "Missing '()' invoking a constructor."
+ "expr": true,
+ "supernew": true,
"laxbreak": true,
"white": true,
"globals": {
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..ef9d5d1
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,18 @@
+# Contribution Guidelines
+
+
+### Issue
+
+ 1. Try [dev](https://github.com/RubaXa/Sortable/tree/dev/)-branch, perhaps the problem has been solved;
+ 2. [Use the search](https://github.com/RubaXa/Sortable/search?q=problem), maybe already have an answer;
+ 3. If not found, create example on [jsbin.com](http://jsbin.com/zunibaxada/1/edit?html,js,output) and describe the problem.
+
+
+---
+
+
+### Pull Request
+
+ 1. Before PR run `grunt`;
+ 2. Only into [dev](https://github.com/RubaXa/Sortable/tree/dev/)-branch.
+
diff --git a/Gruntfile.js b/Gruntfile.js
index 0f1db6c..26e1656 100755
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -5,7 +5,16 @@ module.exports = function (grunt) {
pkg: grunt.file.readJSON('package.json'),
version: {
- src: ['<%= pkg.exportName %>.js', '*.json']
+ js: {
+ src: ['<%= pkg.exportName %>.js', '*.json']
+ },
+ cdn: {
+ options: {
+ prefix: '(cdnjs\\.cloudflare\\.com\\/ajax\\/libs\\/Sortable|cdn\\.jsdelivr\\.net\\/sortable)\\/',
+ replace: '[0-9\\.]+'
+ },
+ src: ['README.md']
+ }
},
jshint: {
diff --git a/README.md b/README.md
index d548c23..720c880 100644
--- a/README.md
+++ b/README.md
@@ -6,18 +6,30 @@ Demo: http://rubaxa.github.io/Sortable/
## Features
- * Supports touch devices and [modern](http://caniuse.com/#search=drag) browsers
+ * Supports touch devices and [modern](http://caniuse.com/#search=drag) browsers (including IE9)
* Can drag from one list to another or within the same list
* CSS animation when moving items
* Supports drag handles *and selectable text* (better than voidberg's html5sortable)
* Smart auto-scrolling
* Built using native HTML5 drag and drop API
- * Supports [Meteor](meteor/README.md) and [AngularJS](#ng)
+ * Supports [Meteor](meteor/README.md), [AngularJS](#ng) and [React](#react)
* Supports any CSS library, e.g. [Bootstrap](#bs)
* Simple API
+ * [CDN](#cdn)
* No jQuery (but there is [support](#jq))
+
+
+
+### Articles
+ * [Sortable v1.0 — New capabilities](https://github.com/RubaXa/Sortable/wiki/Sortable-v1.0-—-New-capabilities/) (December 22, 2014)
+ * [Sorting with the help of HTML5 Drag'n'Drop API](https://github.com/RubaXa/Sortable/wiki/Sorting-with-the-help-of-HTML5-Drag'n'Drop-API/) (December 23, 2013)
+
+
+
+
+
### Usage
```html
@@ -274,7 +286,13 @@ angular.module('myApp', ['ng-sortable'])
$scope.items = ['item 1', 'item 2'];
$scope.foo = ['foo 1', '..'];
$scope.bar = ['bar 1', '..'];
- $scope.barConfig = { group: 'foobar', animation: 150 };
+ $scope.barConfig = {
+ group: 'foobar',
+ animation: 150,
+ onSort: function (/** ngSortEvent */evt){
+ // @see https://github.com/RubaXa/Sortable/blob/master/ng-sortable.js#L18-L24
+ }
+ };
}]);
```
@@ -282,6 +300,92 @@ angular.module('myApp', ['ng-sortable'])
---
+
+### Support React
+Include [react-sortable-mixin.js](react-sortable-mixin.js).
+See [more options](react-sortable-mixin.js#L26).
+
+
+```jsx
+var SortableList = React.createClass({
+ mixins: [SortableMixin],
+
+ getInitialState: function() {
+ return {
+ items: ['Mixin', 'Sortable']
+ };
+ },
+
+ handleSort: function (/** Event */evt) { /*..*/ },
+
+ render: function() {
+ return {
+ this.state.items.map(function (text) {
+ return - {text}
+ })
+ }
+ }
+});
+
+React.render(, document.body);
+
+
+//
+// Groups
+//
+var AllUsers = React.createClass({
+ mixins: [SortableMixin],
+
+ sortableOptions: {
+ ref: "user",
+ group: "shared",
+ model: "users"
+ },
+
+ getInitialState: function() {
+ return { users: ['Abbi', 'Adela', 'Bud', 'Cate', 'Davis', 'Eric']; };
+ },
+
+ render: function() {
+ return (
+ Users
+ {
+ this.state.users.map(function (text) {
+ return - {text}
+ })
+ }
+ );
+ }
+});
+
+var ApprovedUsers = React.createClass({
+ mixins: [SortableMixin],
+ sortableOptions: { group: "shared" },
+
+ getInitialState: function() {
+ return { items: ['Hal', 'Judy']; };
+ },
+
+ render: function() {
+ return {
+ this.state.items.map(function (text) {
+ return - {text}
+ })
+ }
+ }
+});
+
+React.render(, document.body);
+```
+
+
+---
+
+
### Method
@@ -424,6 +528,25 @@ Link to the active instance.
* toggleClass(el`:HTMLElement`, name`:String`, state`:Boolean`) — add or remove one classes from each element
+---
+
+
+
+### CDN
+
+```html
+
+
+
+
+
+
+
+
+
+
+```
+
---
@@ -457,6 +580,14 @@ Now you can use `jquery.fn.sortable.js`:
---
+### Contributing (Issue/PR)
+
+Please, [read this](CONTRIBUTING.md).
+
+
+---
+
+
## MIT LICENSE
Copyright 2013-2015 Lebedev Konstantin
http://rubaxa.github.io/Sortable/
diff --git a/Sortable.js b/Sortable.js
index 3176f3a..fbd588a 100644
--- a/Sortable.js
+++ b/Sortable.js
@@ -28,9 +28,11 @@
ghostEl,
cloneEl,
rootEl,
- scrollEl,
nextEl,
+ scrollEl,
+ scrollParentEl,
+
lastEl,
lastCSS,
@@ -48,7 +50,9 @@
win = window,
document = win.document,
parseInt = win.parseInt,
- supportIEdnd = !!document.createElement('div').dragDrop,
+
+ supportDraggable = !!('draggable' in document.createElement('div')),
+
_silent = false,
@@ -74,7 +78,82 @@
abs = Math.abs,
slice = [].slice,
- touchDragOverListeners = []
+ touchDragOverListeners = [],
+
+ _autoScroll = _throttle(function (/**Event*/evt, /**Object*/options, /**HTMLElement*/rootEl) {
+ // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521
+ if (rootEl && options.scroll) {
+ var el,
+ rect,
+ sens = options.scrollSensitivity,
+ speed = options.scrollSpeed,
+
+ x = evt.clientX,
+ y = evt.clientY,
+
+ winWidth = window.innerWidth,
+ winHeight = window.innerHeight,
+
+ vx,
+ vy
+ ;
+
+ // Delect scrollEl
+ if (scrollParentEl !== rootEl) {
+ scrollEl = options.scroll;
+ scrollParentEl = rootEl;
+
+ if (scrollEl === true) {
+ scrollEl = rootEl;
+
+ do {
+ if ((scrollEl.offsetWidth < scrollEl.scrollWidth) ||
+ (scrollEl.offsetHeight < scrollEl.scrollHeight)
+ ) {
+ break;
+ }
+ /* jshint boss:true */
+ } while (scrollEl = scrollEl.parentNode);
+ }
+ }
+
+ 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 (!(vx || vy)) {
+ vx = (winWidth - x <= sens) - (x <= sens);
+ vy = (winHeight - y <= sens) - (y <= sens);
+
+ /* jshint expr:true */
+ (vx || vy) && (el = win);
+ }
+
+
+ if (autoScroll.vx !== vx || autoScroll.vy !== vy || autoScroll.el !== el) {
+ autoScroll.el = el;
+ autoScroll.vx = vx;
+ autoScroll.vy = vy;
+
+ 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)
;
@@ -139,8 +218,9 @@
}, this);
- // Export group name
- el[expando] = group.name + ' ' + (group.put.join ? group.put.join(' ') : '');
+ // Export options
+ options.groups = ' ' + group.name + (group.put.join ? ' ' + group.put.join(' ') : '') + ' ';
+ el[expando] = options;
// Bind all private methods
@@ -154,10 +234,9 @@
// Bind events
_on(el, 'mousedown', this._onTapStart);
_on(el, 'touchstart', this._onTapStart);
- supportIEdnd && _on(el, 'selectstart', this._onTapStart);
- _on(el, 'dragover', this._onDragOver);
- _on(el, 'dragenter', this._onDragOver);
+ _on(el, 'dragover', this);
+ _on(el, 'dragenter', this);
touchDragOverListeners.push(this._onDragOver);
@@ -171,13 +250,15 @@
_dragStarted: function () {
- // Apply effect
- _toggleClass(dragEl, this.options.ghostClass, true);
+ if (rootEl && dragEl) {
+ // Apply effect
+ _toggleClass(dragEl, this.options.ghostClass, true);
- Sortable.active = this;
+ Sortable.active = this;
- // Drag start event
- _dispatchEvent(rootEl, 'start', dragEl, rootEl, oldIndex);
+ // Drag start event
+ _dispatchEvent(rootEl, 'start', dragEl, rootEl, oldIndex);
+ }
},
@@ -229,9 +310,6 @@
// Prepare `dragstart`
if (target && !dragEl && (target.parentNode === el)) {
- // IE 9 Support
- (type === 'selectstart') && target.dragDrop();
-
tapEvt = evt;
rootEl = this.el;
@@ -254,7 +332,7 @@
clientY: touch.clientY
};
- this._onDragStart(tapEvt, true);
+ this._onDragStart(tapEvt, 'touch');
evt.preventDefault();
}
@@ -265,8 +343,9 @@
_on(dragEl, 'dragend', this);
_on(rootEl, 'dragstart', this._onDragStart);
- _on(document, 'dragover', this);
-
+ if (!supportDraggable) {
+ this._onDragStart(tapEvt, true);
+ }
try {
if (document.selection) {
@@ -285,12 +364,12 @@
var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY),
parent = target,
- groupName = this.options.group.name,
+ groupName = ' ' + this.options.group.name + '',
i = touchDragOverListeners.length;
if (parent) {
do {
- if ((' ' + parent[expando] + ' ').indexOf(groupName) > -1) {
+ if (parent[expando] && parent[expando].groups.indexOf(groupName) > -1) {
while (i--) {
touchDragOverListeners[i]({
clientX: touchEvt.clientX,
@@ -316,10 +395,10 @@
_onTouchMove: function (/**TouchEvent*/evt) {
if (tapEvt) {
- var touch = evt.touches[0],
+ var touch = evt.touches ? evt.touches[0] : evt,
dx = touch.clientX - tapEvt.clientX,
dy = touch.clientY - tapEvt.clientY,
- translate3d = 'translate3d(' + dx + 'px,' + dy + 'px,0)';
+ translate3d = evt.touches ? 'translate3d(' + dx + 'px,' + dy + 'px,0)' : 'translate(' + dx + 'px,' + dy + 'px)';
touchEvt = touch;
@@ -328,13 +407,12 @@
_css(ghostEl, 'msTransform', translate3d);
_css(ghostEl, 'transform', translate3d);
- this._onDrag(touch);
evt.preventDefault();
}
},
- _onDragStart: function (/**Event*/evt, /**boolean*/isTouch) {
+ _onDragStart: function (/**Event*/evt, /**boolean*/useFallback) {
var dataTransfer = evt.dataTransfer,
options = this.options;
@@ -346,7 +424,7 @@
rootEl.insertBefore(cloneEl, dragEl);
}
- if (isTouch) {
+ if (useFallback) {
var rect = dragEl.getBoundingClientRect(),
css = _css(dragEl),
ghostRect;
@@ -368,10 +446,16 @@
_css(ghostEl, 'width', rect.width * 2 - ghostRect.width);
_css(ghostEl, 'height', rect.height * 2 - ghostRect.height);
- // Bind touch events
- _on(document, 'touchmove', this._onTouchMove);
- _on(document, 'touchend', this._onDrop);
- _on(document, 'touchcancel', this._onDrop);
+ if (useFallback === 'touch') {
+ // Bind touch events
+ _on(document, 'touchmove', this._onTouchMove);
+ _on(document, 'touchend', this._onDrop);
+ _on(document, 'touchcancel', this._onDrop);
+ } else {
+ // Old brwoser
+ _on(document, 'mousemove', this._onTouchMove);
+ _on(document, 'mouseup', this._onDrop);
+ }
this._loopId = setInterval(this._emulateDragOver, 150);
}
@@ -384,75 +468,9 @@
_on(document, 'drop', this);
}
- scrollEl = options.scroll;
-
- if (scrollEl === true) {
- scrollEl = rootEl;
-
- do {
- if ((scrollEl.offsetWidth < scrollEl.scrollWidth) ||
- (scrollEl.offsetHeight < scrollEl.scrollHeight)
- ) {
- break;
- }
- /* jshint boss:true */
- } while (scrollEl = scrollEl.parentNode);
- }
-
setTimeout(this._dragStarted, 0);
},
- _onDrag: _throttle(function (/**Event*/evt) {
- // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521
- if (rootEl && this.options.scroll) {
- var el,
- rect,
- options = this.options,
- sens = options.scrollSensitivity,
- speed = options.scrollSpeed,
-
- x = evt.clientX,
- y = evt.clientY,
-
- winWidth = window.innerWidth,
- winHeight = window.innerHeight,
-
- vx = (winWidth - x <= sens) - (x <= sens),
- vy = (winHeight - y <= sens) - (y <= sens)
- ;
-
- if (vx || vy) {
- 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;
-
- 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),
-
-
_onDragOver: function (/**Event*/evt) {
var el = this.el,
target,
@@ -464,12 +482,16 @@
isOwner = (activeGroup === group),
canSort = options.sort;
+ if (evt.dataTransfer && evt.dataTransfer.effectAllowed !== 'move') {
+ return;
+ }
+
if (evt.preventDefault !== void 0) {
evt.preventDefault();
!options.dragoverBubble && evt.stopPropagation();
}
- if (!_silent && activeGroup && !options.disabled &&
+ if (activeGroup && !options.disabled &&
(isOwner
? canSort || (revert = !rootEl.contains(dragEl))
: activeGroup.pull && groupPut && (
@@ -479,6 +501,13 @@
) &&
(evt.rootEl === void 0 || evt.rootEl === this.el)
) {
+ // Smart auto-scrolling
+ _autoScroll(evt, options, this.el);
+
+ if (_silent) {
+ return;
+ }
+
target = _closest(evt.target, options.draggable, el);
dragRect = dragEl.getBoundingClientRect();
@@ -574,6 +603,7 @@
clearTimeout(target.animated);
target.animated = setTimeout(function () {
_css(target, 'transition', '');
+ _css(target, 'transform', '');
target.animated = false;
}, ms);
}
@@ -595,8 +625,7 @@
// Unbind events
_off(document, 'drop', this);
- _off(document, 'dragover', this);
-
+ _off(document, 'mousemove', this._onTouchMove);
_off(el, 'dragstart', this._onDragStart);
this._offUpEvents();
@@ -644,13 +673,16 @@
Sortable.active && _dispatchEvent(rootEl, 'end', dragEl, rootEl, oldIndex, newIndex);
}
- // Set NULL
+ // Nulling
rootEl =
dragEl =
ghostEl =
nextEl =
cloneEl =
+ scrollEl =
+ scrollParentEl =
+
tapEvt =
touchEvt =
@@ -669,8 +701,8 @@
handleEvent: function (/**Event*/evt) {
var type = evt.type;
- if (type === 'dragover') {
- this._onDrag(evt);
+ if (type === 'dragover' || type === 'dragenter') {
+ this._onDragOver(evt);
_globalDragOver(evt);
}
else if (type === 'drop' || type === 'dragend') {
@@ -774,10 +806,9 @@
_off(el, 'mousedown', this._onTapStart);
_off(el, 'touchstart', this._onTapStart);
- _off(el, 'selectstart', this._onTapStart);
- _off(el, 'dragover', this._onDragOver);
- _off(el, 'dragenter', this._onDragOver);
+ _off(el, 'dragover', this);
+ _off(el, 'dragenter', this);
//remove draggable attributes
Array.prototype.forEach.call(el.querySelectorAll('[draggable]'), function (el) {
@@ -997,7 +1028,7 @@
};
- Sortable.version = '1.0.1';
+ Sortable.version = '1.1.0';
/**
diff --git a/Sortable.min.js b/Sortable.min.js
index 56d114b..f607599 100644
--- a/Sortable.min.js
+++ b/Sortable.min.js
@@ -1,2 +1,2 @@
-/*! Sortable 1.0.1 - 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,b){this.el=a,this.options=b=b||{};var d={group:Math.random(),sort:!0,disabled:!1,store:null,handle:null,scroll:!0,scrollSensitivity:30,scrollSpeed:10,draggable:/[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)},dropBubble:!1,dragoverBubble:!1};for(var e in d)!(e in b)&&(b[e]=d[e]);var g=b.group;g&&"object"==typeof g||(g=b.group={name:g}),["pull","put"].forEach(function(a){a in g||(g[a]=!0)}),L.forEach(function(d){b[d]=c(this,b[d]||M),f(a,d.substr(2).toLowerCase(),b[d])},this),a[E]=g.name+" "+(g.put.join?g.put.join(" "):"");for(var h in this)"_"===h.charAt(0)&&(this[h]=c(this,this[h]));f(a,"mousedown",this._onTapStart),f(a,"touchstart",this._onTapStart),I&&f(a,"selectstart",this._onTapStart),f(a,"dragover",this._onDragOver),f(a,"dragenter",this._onDragOver),P.push(this._onDragOver),b.store&&this.sort(b.store.get(this))}function b(a){s&&s.state!==a&&(i(s,"display",a?"none":""),!a&&s.state&&t.insertBefore(s,q),s.state=a)}function c(a,b){var c=O.call(arguments,2);return b.bind?b.bind.apply(b,[a].concat(c)):function(){return b.apply(a,c.concat(O.call(arguments)))}}function d(a,b,c){if(a){c=c||G,b=b.split(".");var d=b.shift().toUpperCase(),e=new RegExp("\\s("+b.join("|")+")\\s","g");do if(">*"===d&&a.parentNode===c||(""===d||a.nodeName.toUpperCase()==d)&&(!b.length||((" "+a.className+" ").match(e)||[]).length==b.length))return a;while(a!==c&&(a=a.parentNode))}return null}function e(a){a.dataTransfer.dropEffect="move",a.preventDefault()}function f(a,b,c){a.addEventListener(b,c,!1)}function g(a,b,c){a.removeEventListener(b,c,!1)}function h(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 i(a,b,c){var d=a&&a.style;if(d){if(void 0===c)return G.defaultView&&G.defaultView.getComputedStyle?c=G.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 j(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 k(a){a.draggable=!1}function l(){J=!1}function m(a,b){var c=a.lastElementChild,d=c.getBoundingClientRect();return b.clientY-(d.top+d.height)>5&&c}function n(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 o(a){for(var b=0;a&&(a=a.previousElementSibling)&&"TEMPLATE"!==a.nodeName.toUpperCase();)b++;return b}function p(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 q,r,s,t,u,v,w,x,y,z,A,B,C,D={},E="Sortable"+(new Date).getTime(),F=window,G=F.document,H=F.parseInt,I=!!G.createElement("div").dragDrop,J=!1,K=function(a,b,c,d,e,f){var g=G.createEvent("Event");g.initEvent(b,!0,!0),g.item=c||a,g.from=d||a,g.clone=s,g.oldIndex=e,g.newIndex=f,a.dispatchEvent(g)},L="onAdd onUpdate onRemove onStart onEnd onFilter onSort".split(" "),M=function(){},N=Math.abs,O=[].slice,P=[];return a.prototype={constructor:a,_dragStarted:function(){h(q,this.options.ghostClass,!0),a.active=this,K(t,"start",q,t,y)},_onTapStart:function(a){var b=a.type,c=a.touches&&a.touches[0],e=(c||a).target,g=e,h=this.options,i=this.el,l=h.filter;if(!("mousedown"===b&&0!==a.button||h.disabled)){if(h.handle&&(e=d(e,h.handle,i)),e=d(e,h.draggable,i),y=o(e),"function"==typeof l){if(l.call(this,a,e,this))return K(g,"filter",e,i,y),void a.preventDefault()}else if(l&&(l=l.split(",").some(function(a){return a=d(g,a.trim(),i),a?(K(a,"filter",e,i,y),!0):void 0})))return void a.preventDefault();if(e&&!q&&e.parentNode===i){"selectstart"===b&&e.dragDrop(),B=a,t=this.el,q=e,v=q.nextSibling,A=this.options.group,q.draggable=!0,h.ignore.split(",").forEach(function(a){j(e,a.trim(),k)}),c&&(B={target:e,clientX:c.clientX,clientY:c.clientY},this._onDragStart(B,!0),a.preventDefault()),f(G,"mouseup",this._onDrop),f(G,"touchend",this._onDrop),f(G,"touchcancel",this._onDrop),f(q,"dragend",this),f(t,"dragstart",this._onDragStart),f(G,"dragover",this);try{G.selection?G.selection.empty():window.getSelection().removeAllRanges()}catch(m){}}}},_emulateDragOver:function(){if(C){i(r,"display","none");var a=G.elementFromPoint(C.clientX,C.clientY),b=a,c=this.options.group.name,d=P.length;if(b)do{if((" "+b[E]+" ").indexOf(c)>-1){for(;d--;)P[d]({clientX:C.clientX,clientY:C.clientY,target:a,rootEl:b});break}a=b}while(b=b.parentNode);i(r,"display","")}},_onTouchMove:function(a){if(B){var b=a.touches[0],c=b.clientX-B.clientX,d=b.clientY-B.clientY,e="translate3d("+c+"px,"+d+"px,0)";C=b,i(r,"webkitTransform",e),i(r,"mozTransform",e),i(r,"msTransform",e),i(r,"transform",e),this._onDrag(b),a.preventDefault()}},_onDragStart:function(a,b){var c=a.dataTransfer,d=this.options;if(this._offUpEvents(),"clone"==A.pull&&(s=q.cloneNode(!0),i(s,"display","none"),t.insertBefore(s,q)),b){var e,g=q.getBoundingClientRect(),h=i(q);r=q.cloneNode(!0),i(r,"top",g.top-H(h.marginTop,10)),i(r,"left",g.left-H(h.marginLeft,10)),i(r,"width",g.width),i(r,"height",g.height),i(r,"opacity","0.8"),i(r,"position","fixed"),i(r,"zIndex","100000"),t.appendChild(r),e=r.getBoundingClientRect(),i(r,"width",2*g.width-e.width),i(r,"height",2*g.height-e.height),f(G,"touchmove",this._onTouchMove),f(G,"touchend",this._onDrop),f(G,"touchcancel",this._onDrop),this._loopId=setInterval(this._emulateDragOver,150)}else c&&(c.effectAllowed="move",d.setData&&d.setData.call(this,c,q)),f(G,"drop",this);if(u=d.scroll,u===!0){u=t;do if(u.offsetWidth=i-g)-(e>=g),l=(e>=j-h)-(e>=h);k||l?b=F:u&&(b=u,c=u.getBoundingClientRect(),k=(N(c.right-g)<=e)-(N(c.left-g)<=e),l=(N(c.bottom-h)<=e)-(N(c.top-h)<=e)),(D.vx!==k||D.vy!==l||D.el!==b)&&(D.el=b,D.vx=k,D.vy=l,clearInterval(D.pid),b&&(D.pid=setInterval(function(){b===F?F.scrollTo(F.scrollX+k*f,F.scrollY+l*f):(l&&(b.scrollTop+=l*f),k&&(b.scrollLeft+=k*f))},24)))}},30),_onDragOver:function(a){var c,e,f,g=this.el,h=this.options,j=h.group,k=j.put,n=A===j,o=h.sort;if(void 0!==a.preventDefault&&(a.preventDefault(),!h.dragoverBubble&&a.stopPropagation()),!J&&A&&(n?o||(f=!t.contains(q)):A.pull&&k&&(A.name===j.name||k.indexOf&&~k.indexOf(A.name)))&&(void 0===a.rootEl||a.rootEl===this.el)){if(c=d(a.target,h.draggable,g),e=q.getBoundingClientRect(),f)return b(!0),void(s||v?t.insertBefore(q,s||v):o||t.appendChild(q));if(0===g.children.length||g.children[0]===r||g===a.target&&(c=m(g,a))){if(c){if(c.animated)return;u=c.getBoundingClientRect()}b(n),g.appendChild(q),this._animate(e,q),c&&this._animate(u,c)}else if(c&&!c.animated&&c!==q&&void 0!==c.parentNode[E]){w!==c&&(w=c,x=i(c));var p,u=c.getBoundingClientRect(),y=u.right-u.left,z=u.bottom-u.top,B=/left|right|inline/.test(x.cssFloat+x.display),C=c.offsetWidth>q.offsetWidth,D=c.offsetHeight>q.offsetHeight,F=(B?(a.clientX-u.left)/y:(a.clientY-u.top)/z)>.5,G=c.nextElementSibling;J=!0,setTimeout(l,30),b(n),p=B?c.previousElementSibling===q&&!C||F&&C:G!==q&&!D||F&&D,p&&!G?g.appendChild(q):c.parentNode.insertBefore(q,p?G:c),this._animate(e,q),this._animate(u,c)}}},_animate:function(a,b){var c=this.options.animation;if(c){var d=b.getBoundingClientRect();i(b,"transition","none"),i(b,"transform","translate3d("+(a.left-d.left)+"px,"+(a.top-d.top)+"px,0)"),b.offsetWidth,i(b,"transition","all "+c+"ms"),i(b,"transform","translate3d(0,0,0)"),clearTimeout(b.animated),b.animated=setTimeout(function(){i(b,"transition",""),b.animated=!1},c)}},_offUpEvents:function(){g(G,"mouseup",this._onDrop),g(G,"touchmove",this._onTouchMove),g(G,"touchend",this._onDrop),g(G,"touchcancel",this._onDrop)},_onDrop:function(b){var c=this.el,d=this.options;clearInterval(this._loopId),clearInterval(D.pid),g(G,"drop",this),g(G,"dragover",this),g(c,"dragstart",this._onDragStart),this._offUpEvents(),b&&(b.preventDefault(),!d.dropBubble&&b.stopPropagation(),r&&r.parentNode.removeChild(r),q&&(g(q,"dragend",this),k(q),h(q,this.options.ghostClass,!1),t!==q.parentNode?(z=o(q),K(q.parentNode,"sort",q,t,y,z),K(t,"sort",q,t,y,z),K(q,"add",q,t,y,z),K(t,"remove",q,t,y,z)):(s&&s.parentNode.removeChild(s),q.nextSibling!==v&&(z=o(q),K(t,"update",q,t,y,z),K(t,"sort",q,t,y,z))),a.active&&K(t,"end",q,t,y,z)),t=q=r=v=s=B=C=w=x=A=a.active=null,this.save())},handleEvent:function(a){var b=a.type;"dragover"===b?(this._onDrag(a),e(a)):("drop"===b||"dragend"===b)&&this._onDrop(a)},toArray:function(){for(var a,b=[],c=this.el.children,e=0,f=c.length;f>e;e++)a=c[e],d(a,this.options.draggable,this.el)&&b.push(a.getAttribute("data-id")||n(a));return b},sort:function(a){var b={},c=this.el;this.toArray().forEach(function(a,e){var f=c.children[e];d(f,this.options.draggable,c)&&(b[a]=f)},this),a.forEach(function(a){b[a]&&(c.removeChild(b[a]),c.appendChild(b[a]))})},save:function(){var a=this.options.store;a&&a.set(this)},closest:function(a,b){return d(a,b||this.options.draggable,this.el)},option:function(a,b){var c=this.options;return void 0===b?c[a]:void(c[a]=b)},destroy:function(){var a=this.el,b=this.options;L.forEach(function(c){g(a,c.substr(2).toLowerCase(),b[c])}),g(a,"mousedown",this._onTapStart),g(a,"touchstart",this._onTapStart),g(a,"selectstart",this._onTapStart),g(a,"dragover",this._onDragOver),g(a,"dragenter",this._onDragOver),Array.prototype.forEach.call(a.querySelectorAll("[draggable]"),function(a){a.removeAttribute("draggable")}),P.splice(P.indexOf(this._onDragOver),1),this._onDrop(),this.el=null}},a.utils={on:f,off:g,css:i,find:j,bind:c,is:function(a,b){return!!d(a,b,a)},throttle:p,closest:d,toggleClass:h,dispatchEvent:K,index:o},a.version="1.0.1",a.create=function(b,c){return new a(b,c)},a});
\ No newline at end of file
+/*! Sortable 1.1.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,b){this.el=a,this.options=b=b||{};var d={group:Math.random(),sort:!0,disabled:!1,store:null,handle:null,scroll:!0,scrollSensitivity:30,scrollSpeed:10,draggable:/[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)},dropBubble:!1,dragoverBubble:!1};for(var e in d)!(e in b)&&(b[e]=d[e]);var g=b.group;g&&"object"==typeof g||(g=b.group={name:g}),["pull","put"].forEach(function(a){a in g||(g[a]=!0)}),M.forEach(function(d){b[d]=c(this,b[d]||N),f(a,d.substr(2).toLowerCase(),b[d])},this),b.groups=" "+g.name+(g.put.join?" "+g.put.join(" "):"")+" ",a[F]=b;for(var h in this)"_"===h.charAt(0)&&(this[h]=c(this,this[h]));f(a,"mousedown",this._onTapStart),f(a,"touchstart",this._onTapStart),f(a,"dragover",this),f(a,"dragenter",this),Q.push(this._onDragOver),b.store&&this.sort(b.store.get(this))}function b(a){s&&s.state!==a&&(i(s,"display",a?"none":""),!a&&s.state&&t.insertBefore(s,q),s.state=a)}function c(a,b){var c=P.call(arguments,2);return b.bind?b.bind.apply(b,[a].concat(c)):function(){return b.apply(a,c.concat(P.call(arguments)))}}function d(a,b,c){if(a){c=c||H,b=b.split(".");var d=b.shift().toUpperCase(),e=new RegExp("\\s("+b.join("|")+")\\s","g");do if(">*"===d&&a.parentNode===c||(""===d||a.nodeName.toUpperCase()==d)&&(!b.length||((" "+a.className+" ").match(e)||[]).length==b.length))return a;while(a!==c&&(a=a.parentNode))}return null}function e(a){a.dataTransfer.dropEffect="move",a.preventDefault()}function f(a,b,c){a.addEventListener(b,c,!1)}function g(a,b,c){a.removeEventListener(b,c,!1)}function h(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 i(a,b,c){var d=a&&a.style;if(d){if(void 0===c)return H.defaultView&&H.defaultView.getComputedStyle?c=H.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 j(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 k(a){a.draggable=!1}function l(){K=!1}function m(a,b){var c=a.lastElementChild,d=c.getBoundingClientRect();return b.clientY-(d.top+d.height)>5&&c}function n(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 o(a){for(var b=0;a&&(a=a.previousElementSibling);)"TEMPLATE"!==a.nodeName.toUpperCase()&&b++;return b}function p(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 q,r,s,t,u,v,w,x,y,z,A,B,C,D,E={},F="Sortable"+(new Date).getTime(),G=window,H=G.document,I=G.parseInt,J=!!("draggable"in H.createElement("div")),K=!1,L=function(a,b,c,d,e,f){var g=H.createEvent("Event");g.initEvent(b,!0,!0),g.item=c||a,g.from=d||a,g.clone=s,g.oldIndex=e,g.newIndex=f,a.dispatchEvent(g)},M="onAdd onUpdate onRemove onStart onEnd onFilter onSort".split(" "),N=function(){},O=Math.abs,P=[].slice,Q=[],R=p(function(a,b,c){if(c&&b.scroll){var d,e,f,g,h=b.scrollSensitivity,i=b.scrollSpeed,j=a.clientX,k=a.clientY,l=window.innerWidth,m=window.innerHeight;if(w!==c&&(v=b.scroll,w=c,v===!0)){v=c;do if(v.offsetWidth=l-j)-(h>=j),g=(h>=m-k)-(h>=k),(f||g)&&(d=G)),(E.vx!==f||E.vy!==g||E.el!==d)&&(E.el=d,E.vx=f,E.vy=g,clearInterval(E.pid),d&&(E.pid=setInterval(function(){d===G?G.scrollTo(G.scrollX+f*i,G.scrollY+g*i):(g&&(d.scrollTop+=g*i),f&&(d.scrollLeft+=f*i))},24)))}},30);return a.prototype={constructor:a,_dragStarted:function(){t&&q&&(h(q,this.options.ghostClass,!0),a.active=this,L(t,"start",q,t,z))},_onTapStart:function(a){var b=a.type,c=a.touches&&a.touches[0],e=(c||a).target,g=e,h=this.options,i=this.el,l=h.filter;if(!("mousedown"===b&&0!==a.button||h.disabled)){if(h.handle&&(e=d(e,h.handle,i)),e=d(e,h.draggable,i),z=o(e),"function"==typeof l){if(l.call(this,a,e,this))return L(g,"filter",e,i,z),void a.preventDefault()}else if(l&&(l=l.split(",").some(function(a){return a=d(g,a.trim(),i),a?(L(a,"filter",e,i,z),!0):void 0})))return void a.preventDefault();if(e&&!q&&e.parentNode===i){C=a,t=this.el,q=e,u=q.nextSibling,B=this.options.group,q.draggable=!0,h.ignore.split(",").forEach(function(a){j(e,a.trim(),k)}),c&&(C={target:e,clientX:c.clientX,clientY:c.clientY},this._onDragStart(C,"touch"),a.preventDefault()),f(H,"mouseup",this._onDrop),f(H,"touchend",this._onDrop),f(H,"touchcancel",this._onDrop),f(q,"dragend",this),f(t,"dragstart",this._onDragStart),J||this._onDragStart(C,!0);try{H.selection?H.selection.empty():window.getSelection().removeAllRanges()}catch(m){}}}},_emulateDragOver:function(){if(D){i(r,"display","none");var a=H.elementFromPoint(D.clientX,D.clientY),b=a,c=" "+this.options.group.name,d=Q.length;if(b)do{if(b[F]&&b[F].groups.indexOf(c)>-1){for(;d--;)Q[d]({clientX:D.clientX,clientY:D.clientY,target:a,rootEl:b});break}a=b}while(b=b.parentNode);i(r,"display","")}},_onTouchMove:function(a){if(C){var b=a.touches?a.touches[0]:a,c=b.clientX-C.clientX,d=b.clientY-C.clientY,e=a.touches?"translate3d("+c+"px,"+d+"px,0)":"translate("+c+"px,"+d+"px)";D=b,i(r,"webkitTransform",e),i(r,"mozTransform",e),i(r,"msTransform",e),i(r,"transform",e),a.preventDefault()}},_onDragStart:function(a,b){var c=a.dataTransfer,d=this.options;if(this._offUpEvents(),"clone"==B.pull&&(s=q.cloneNode(!0),i(s,"display","none"),t.insertBefore(s,q)),b){var e,g=q.getBoundingClientRect(),h=i(q);r=q.cloneNode(!0),i(r,"top",g.top-I(h.marginTop,10)),i(r,"left",g.left-I(h.marginLeft,10)),i(r,"width",g.width),i(r,"height",g.height),i(r,"opacity","0.8"),i(r,"position","fixed"),i(r,"zIndex","100000"),t.appendChild(r),e=r.getBoundingClientRect(),i(r,"width",2*g.width-e.width),i(r,"height",2*g.height-e.height),"touch"===b?(f(H,"touchmove",this._onTouchMove),f(H,"touchend",this._onDrop),f(H,"touchcancel",this._onDrop)):(f(H,"mousemove",this._onTouchMove),f(H,"mouseup",this._onDrop)),this._loopId=setInterval(this._emulateDragOver,150)}else c&&(c.effectAllowed="move",d.setData&&d.setData.call(this,c,q)),f(H,"drop",this);setTimeout(this._dragStarted,0)},_onDragOver:function(a){var c,e,f,g=this.el,h=this.options,j=h.group,k=j.put,n=B===j,o=h.sort;if(!(a.dataTransfer&&"move"!==a.dataTransfer.effectAllowed||(void 0!==a.preventDefault&&(a.preventDefault(),!h.dragoverBubble&&a.stopPropagation()),!B||h.disabled||!(n?o||(f=!t.contains(q)):B.pull&&k&&(B.name===j.name||k.indexOf&&~k.indexOf(B.name)))||void 0!==a.rootEl&&a.rootEl!==this.el))){if(R(a,h,this.el),K)return;if(c=d(a.target,h.draggable,g),e=q.getBoundingClientRect(),f)return b(!0),void(s||u?t.insertBefore(q,s||u):o||t.appendChild(q));if(0===g.children.length||g.children[0]===r||g===a.target&&(c=m(g,a))){if(c){if(c.animated)return;v=c.getBoundingClientRect()}b(n),g.appendChild(q),this._animate(e,q),c&&this._animate(v,c)}else if(c&&!c.animated&&c!==q&&void 0!==c.parentNode[F]){x!==c&&(x=c,y=i(c));var p,v=c.getBoundingClientRect(),w=v.right-v.left,z=v.bottom-v.top,A=/left|right|inline/.test(y.cssFloat+y.display),C=c.offsetWidth>q.offsetWidth,D=c.offsetHeight>q.offsetHeight,E=(A?(a.clientX-v.left)/w:(a.clientY-v.top)/z)>.5,G=c.nextElementSibling;K=!0,setTimeout(l,30),b(n),p=A?c.previousElementSibling===q&&!C||E&&C:G!==q&&!D||E&&D,p&&!G?g.appendChild(q):c.parentNode.insertBefore(q,p?G:c),this._animate(e,q),this._animate(v,c)}}},_animate:function(a,b){var c=this.options.animation;if(c){var d=b.getBoundingClientRect();i(b,"transition","none"),i(b,"transform","translate3d("+(a.left-d.left)+"px,"+(a.top-d.top)+"px,0)"),b.offsetWidth,i(b,"transition","all "+c+"ms"),i(b,"transform","translate3d(0,0,0)"),clearTimeout(b.animated),b.animated=setTimeout(function(){i(b,"transition",""),i(b,"transform",""),b.animated=!1},c)}},_offUpEvents:function(){g(H,"mouseup",this._onDrop),g(H,"touchmove",this._onTouchMove),g(H,"touchend",this._onDrop),g(H,"touchcancel",this._onDrop)},_onDrop:function(b){var c=this.el,d=this.options;clearInterval(this._loopId),clearInterval(E.pid),g(H,"drop",this),g(H,"mousemove",this._onTouchMove),g(c,"dragstart",this._onDragStart),this._offUpEvents(),b&&(b.preventDefault(),!d.dropBubble&&b.stopPropagation(),r&&r.parentNode.removeChild(r),q&&(g(q,"dragend",this),k(q),h(q,this.options.ghostClass,!1),t!==q.parentNode?(A=o(q),L(q.parentNode,"sort",q,t,z,A),L(t,"sort",q,t,z,A),L(q,"add",q,t,z,A),L(t,"remove",q,t,z,A)):(s&&s.parentNode.removeChild(s),q.nextSibling!==u&&(A=o(q),L(t,"update",q,t,z,A),L(t,"sort",q,t,z,A))),a.active&&L(t,"end",q,t,z,A)),t=q=r=u=s=v=w=C=D=x=y=B=a.active=null,this.save())},handleEvent:function(a){var b=a.type;"dragover"===b||"dragenter"===b?(this._onDragOver(a),e(a)):("drop"===b||"dragend"===b)&&this._onDrop(a)},toArray:function(){for(var a,b=[],c=this.el.children,e=0,f=c.length;f>e;e++)a=c[e],d(a,this.options.draggable,this.el)&&b.push(a.getAttribute("data-id")||n(a));return b},sort:function(a){var b={},c=this.el;this.toArray().forEach(function(a,e){var f=c.children[e];d(f,this.options.draggable,c)&&(b[a]=f)},this),a.forEach(function(a){b[a]&&(c.removeChild(b[a]),c.appendChild(b[a]))})},save:function(){var a=this.options.store;a&&a.set(this)},closest:function(a,b){return d(a,b||this.options.draggable,this.el)},option:function(a,b){var c=this.options;return void 0===b?c[a]:void(c[a]=b)},destroy:function(){var a=this.el,b=this.options;M.forEach(function(c){g(a,c.substr(2).toLowerCase(),b[c])}),g(a,"mousedown",this._onTapStart),g(a,"touchstart",this._onTapStart),g(a,"dragover",this),g(a,"dragenter",this),Array.prototype.forEach.call(a.querySelectorAll("[draggable]"),function(a){a.removeAttribute("draggable")}),Q.splice(Q.indexOf(this._onDragOver),1),this._onDrop(),this.el=null}},a.utils={on:f,off:g,css:i,find:j,bind:c,is:function(a,b){return!!d(a,b,a)},throttle:p,closest:d,toggleClass:h,dispatchEvent:L,index:o},a.version="1.1.0",a.create=function(b,c){return new a(b,c)},a});
\ No newline at end of file
diff --git a/bower.json b/bower.json
index cb0e811..a5ffef4 100644
--- a/bower.json
+++ b/bower.json
@@ -1,7 +1,7 @@
{
"name": "Sortable",
"main": "Sortable.js",
- "version": "1.0.1",
+ "version": "1.1.0",
"homepage": "http://rubaxa.github.io/Sortable/",
"authors": [
"RubaXa "
diff --git a/component.json b/component.json
index e9fc86e..4eb1e0d 100644
--- a/component.json
+++ b/component.json
@@ -1,7 +1,7 @@
{
"name": "Sortable",
"main": "Sortable.js",
- "version": "1.0.1",
+ "version": "1.1.0",
"homepage": "http://rubaxa.github.io/Sortable/",
"repo": "RubaXa/Sortable",
"authors": [
diff --git a/index.html b/index.html
index 3c143d9..3e83346 100644
--- a/index.html
+++ b/index.html
@@ -7,8 +7,8 @@
Sortable. No jQuery.
-
-
+
+
diff --git a/ng-sortable.js b/ng-sortable.js
index ecbf23b..a872561 100644
--- a/ng-sortable.js
+++ b/ng-sortable.js
@@ -9,11 +9,21 @@
factory(angular, Sortable);
}
else if (typeof define === 'function' && define.amd) {
- define(['angular', 'sortable'], factory);
+ define(['angular', './Sortable'], factory);
}
})(function (angular, Sortable) {
'use strict';
+
+ /**
+ * @typedef {Object} ngSortEvent
+ * @property {*} model List item
+ * @property {Object|Array} models List of items
+ * @property {number} oldIndex before sort
+ * @property {number} newIndex after sort
+ */
+
+
angular.module('ng-sortable', [])
.constant('$version', '0.3.5')
.directive('ngSortable', ['$parse', function ($parse) {
@@ -29,6 +39,11 @@
);
})[0];
+ if (!ngRepeat) {
+ // Without ng-repeat
+ return null;
+ }
+
// tests: http://jsbin.com/kosubutilo/1/edit?js,output
ngRepeat = ngRepeat.nodeValue.match(/ngRepeat:\s*(?:\(.*?,\s*)?([^\s)]+)[\s)]+in\s+([^\s|]+)/);
@@ -58,12 +73,25 @@
;
- 'Start End Add Update Remove Sort'.split(' ').forEach(function (name) {
- options['on' + name] = options['on' + name] || function () {};
- });
+ function _emitEvent(/**Event*/evt, /*Mixed*/item) {
+ var name = 'on' + evt.type.charAt(0).toUpperCase() + evt.type.substr(1);
+ /* jshint expr:true */
+ options[name] && options[name]({
+ model: item,
+ models: source && source.items(),
+ oldIndex: evt.oldIndex,
+ newIndex: evt.newIndex
+ });
+ }
+
+
+ function _sync(/**Event*/evt) {
+ if (!source) {
+ // Without ng-repeat
+ return;
+ }
- function _sync(evt) {
var oldIndex = evt.oldIndex,
newIndex = evt.newIndex,
items = source.items();
@@ -77,6 +105,7 @@
if (evt.clone) {
evt.from.removeChild(evt.clone);
+ removed = angular.copy(removed);
}
else {
prevItems.splice(oldIndex, 1);
@@ -100,27 +129,27 @@
}, {
onStart: function (/**Event*/evt) {
nextSibling = evt.item.nextSibling;
- options.onStart(source.items());
+ _emitEvent(evt);
scope.$apply();
},
- onEnd: function () {
- options.onEnd(source.items());
+ onEnd: function (/**Event*/evt) {
+ _emitEvent(evt, removed);
scope.$apply();
},
onAdd: function (/**Event*/evt) {
_sync(evt);
- options.onAdd(source.items(), removed);
+ _emitEvent(evt, removed);
scope.$apply();
},
onUpdate: function (/**Event*/evt) {
_sync(evt);
- options.onUpdate(source.items(), source.item(evt.item));
+ _emitEvent(evt, source && source.item(evt.item));
},
- onRemove: function () {
- options.onRemove(source.items(), removed);
+ onRemove: function (/**Event*/evt) {
+ _emitEvent(evt, removed);
},
- onSort: function () {
- options.onSort(source.items());
+ onSort: function (/**Event*/evt) {
+ _emitEvent(evt, source && source.item(evt.item));
}
}));
diff --git a/package.json b/package.json
index f282697..52009c2 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "sortablejs",
"exportName": "Sortable",
- "version": "1.0.1",
+ "version": "1.1.0",
"devDependencies": {
"grunt": "*",
"grunt-version": "*",
@@ -23,8 +23,11 @@
"sortable",
"reorder",
"drag",
+ "meteor",
+ "angular",
"ng-srotable",
- "angular"
+ "react",
+ "mixin"
],
"author": "Konstantin Lebedev ",
"license": "MIT",
diff --git a/react-sortable-mixin.js b/react-sortable-mixin.js
new file mode 100644
index 0000000..47d1c36
--- /dev/null
+++ b/react-sortable-mixin.js
@@ -0,0 +1,147 @@
+/**
+ * @author RubaXa
+ * @licence MIT
+ */
+
+(function (factory) {
+ 'use strict';
+
+ if (typeof module != 'undefined' && typeof module.exports != 'undefined') {
+ module.exports = factory(require('./Sortable'));
+ }
+ else if (typeof define === 'function' && define.amd) {
+ define(['./Sortable'], factory);
+ }
+ else {
+ /* jshint sub:true */
+ window['SortableMixin'] = factory(Sortable);
+ }
+})(function (/** Sortable */Sortable) {
+ 'use strict';
+
+ var _nextSibling;
+
+ var _activeComponent;
+
+ var _defaultOptions = {
+ ref: 'list',
+ model: 'items',
+
+ animation: 100,
+ onStart: 'handleStart',
+ onEnd: 'handleEnd',
+ onAdd: 'handleAdd',
+ onUpdate: 'handleUpdate',
+ onRemove: 'handleRemove',
+ onSort: 'handleSort',
+ onFilter: 'handleFilter'
+ };
+
+
+ function _getModelName(component) {
+ return component.sortableOptions && component.sortableOptions.model || _defaultOptions.model;
+ }
+
+
+ function _getModelItems(component) {
+ var name = _getModelName(component),
+ items = component.state && component.state[name] || component.props[name];
+
+ return items.slice();
+ }
+
+
+ function _extend(dst, src) {
+ for (var key in src) {
+ if (src.hasOwnProperty(key)) {
+ dst[key] = src[key];
+ }
+ }
+
+ return dst;
+ }
+
+
+ /**
+ * Simple and easy mixin-wrapper for rubaxa/Sortable library, in order to
+ * make reorderable drag-and-drop lists on modern browsers and touch devices.
+ *
+ * @mixin
+ */
+ var SortableMixin = {
+ sortableMixinVersion: '0.1.0',
+
+
+ /**
+ * @type {Sortable}
+ * @private
+ */
+ _sortableInstance: null,
+
+
+ componentDidMount: function () {
+ var options = _extend(_extend({}, _defaultOptions), this.sortableOptions || {}),
+ copyOptions = _extend({}, options),
+
+ emitEvent = function (/** string */type, /** Event */evt) {
+ var method = this[options[type]];
+ method && method.call(this, evt, this._sortableInstance);
+ }.bind(this);
+
+
+ // Bind callbacks so that "this" refers to the component
+ 'onStart onEnd onAdd onSort onUpdate onRemove onFilter'.split(' ').forEach(function (/** string */name) {
+ copyOptions[name] = function (evt) {
+ if (name === 'onStart') {
+ _nextSibling = evt.item.nextElementSibling;
+ _activeComponent = this;
+ }
+ else if (name === 'onAdd' || name === 'onUpdate') {
+ evt.from.insertBefore(evt.item, _nextSibling);
+
+ var newState = {},
+ remoteState = {},
+ oldIndex = evt.oldIndex,
+ newIndex = evt.newIndex,
+ items = _getModelItems(this),
+ remoteItems,
+ item;
+
+ if (name === 'onAdd') {
+ remoteItems = _getModelItems(_activeComponent);
+ item = remoteItems.splice(oldIndex, 1)[0];
+ items.splice(newIndex, 0, item);
+
+ remoteState[_getModelName(_activeComponent)] = remoteItems;
+ }
+ else {
+ items.splice(newIndex, 0, items.splice(oldIndex, 1)[0]);
+ }
+
+ newState[_getModelName(this)] = items;
+ this.setState(newState);
+ (this !== _activeComponent) && _activeComponent.setState(remoteState);
+ }
+
+ setTimeout(function () {
+ emitEvent(name, evt);
+ }, 0);
+ }.bind(this);
+ }, this);
+
+
+ /** @namespace this.refs — http://facebook.github.io/react/docs/more-about-refs.html */
+ this._sortableInstance = Sortable.create((this.refs[options.ref] || this).getDOMNode(), copyOptions);
+ },
+
+
+ componentWillUnmount: function () {
+ this._sortableInstance.destroy();
+ this._sortableInstance = null;
+ }
+ };
+
+
+ // Export
+ return SortableMixin;
+});
diff --git a/st/app.js b/st/app.js
index 109c70b..fe50fe9 100644
--- a/st/app.js
+++ b/st/app.js
@@ -1,5 +1,41 @@
(function () {
+ 'use strict';
+
var byId = function (id) { return document.getElementById(id); },
+
+ loadScripts = function (desc, callback) {
+ var deps = [], key, idx = 0;
+
+ for (key in desc) {
+ deps.push(key);
+ }
+
+ (function _next() {
+ var pid,
+ name = deps[idx],
+ script = document.createElement('script');
+
+ script.type = 'text/javascript';
+ script.src = desc[deps[idx]];
+
+ pid = setInterval(function () {
+ if (window[name]) {
+ clearTimeout(pid);
+
+ deps[idx++] = window[name];
+
+ if (deps[idx]) {
+ _next();
+ } else {
+ callback.apply(null, deps);
+ }
+ }
+ }, 30);
+
+ document.getElementsByTagName('head')[0].appendChild(script);
+ })()
+ },
+
console = window.console;
@@ -162,6 +198,7 @@
})();
+
// Background
document.addEventListener("DOMContentLoaded", function () {
function setNoiseBackground(el, width, height, opacity) {