angular-legacy-sortablejs
Advanced tools
Comparing version 0.4.0 to 0.4.1
@@ -38,152 +38,171 @@ /** | ||
var removed, | ||
nextSibling, | ||
getSourceFactory = function getSourceFactory(el, scope) { | ||
var ngRepeat = [].filter.call(el.childNodes, function (node) { | ||
return ( | ||
(node.nodeType === 8) && | ||
(node.nodeValue.indexOf('ngRepeat:') !== -1) | ||
); | ||
nextSibling; | ||
function getNgRepeatExpression(node) { | ||
return node.getAttribute('ng-repeat') || node.getAttribute('data-ng-repeat') || node.getAttribute('x-ng-repeat'); | ||
} | ||
// Export | ||
return { | ||
restrict: 'AC', | ||
scope: { ngSortable: "=?" }, | ||
priority: 1001, | ||
compile: function ($element, $attr) { | ||
var ngRepeat = [].filter.call($element[0].childNodes, function (node) { | ||
return node.nodeType === Node.ELEMENT_NODE && getNgRepeatExpression(node); | ||
})[0]; | ||
if (!ngRepeat) { | ||
// Without ng-repeat | ||
return function () { | ||
return null; | ||
}; | ||
return; | ||
} | ||
// tests: http://jsbin.com/kosubutilo/1/edit?js,output | ||
ngRepeat = ngRepeat.nodeValue.match(/ngRepeat:\s*(?:\(.*?,\s*)?([^\s)]+)[\s)]+in\s+([^\s|]+)/); | ||
var match = getNgRepeatExpression(ngRepeat) | ||
.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+track\s+by\s+([\s\S]+?))?\s*$/); | ||
var itemsExpr = $parse(ngRepeat[2]); | ||
if (!match) { | ||
return; | ||
} | ||
return function () { | ||
return itemsExpr(scope.$parent) || []; | ||
}; | ||
}; | ||
var rhs = match[2]; | ||
return function postLink(scope, $el) { | ||
var itemsExpr = $parse(rhs); | ||
var getSource = function getSource() { | ||
return itemsExpr(scope.$parent) || []; | ||
}; | ||
// Export | ||
return { | ||
restrict: 'AC', | ||
scope: { ngSortable: "=?" }, | ||
link: function (scope, $el) { | ||
var el = $el[0], | ||
options = angular.extend(scope.ngSortable || {}, ngSortableConfig), | ||
watchers = [], | ||
getSource = getSourceFactory(el, scope), | ||
sortable | ||
; | ||
el[expando] = getSource; | ||
var el = $el[0], | ||
options = angular.extend(scope.ngSortable || {}, ngSortableConfig), | ||
watchers = [], | ||
offDestroy, | ||
sortable | ||
; | ||
function _emitEvent(/**Event*/evt, /*Mixed*/item) { | ||
var name = 'on' + evt.type.charAt(0).toUpperCase() + evt.type.substr(1); | ||
var source = getSource(); | ||
el[expando] = getSource; | ||
/* jshint expr:true */ | ||
options[name] && options[name]({ | ||
model: item || source[evt.newIndex], | ||
models: source, | ||
oldIndex: evt.oldIndex, | ||
newIndex: evt.newIndex | ||
}); | ||
} | ||
function _emitEvent(/**Event*/evt, /*Mixed*/item) { | ||
var name = 'on' + evt.type.charAt(0).toUpperCase() + evt.type.substr(1); | ||
var source = getSource(); | ||
/* jshint expr:true */ | ||
options[name] && options[name]({ | ||
model: item || source[evt.newIndex], | ||
models: source, | ||
oldIndex: evt.oldIndex, | ||
newIndex: evt.newIndex, | ||
originalEvent: evt | ||
}); | ||
} | ||
function _sync(/**Event*/evt) { | ||
var items = getSource(); | ||
if (!items) { | ||
// Without ng-repeat | ||
return; | ||
} | ||
function _sync(/**Event*/evt) { | ||
var items = getSource(); | ||
var oldIndex = evt.oldIndex, | ||
newIndex = evt.newIndex; | ||
if (!items) { | ||
// Without ng-repeat | ||
return; | ||
} | ||
if (el !== evt.from) { | ||
var prevItems = evt.from[expando](); | ||
var oldIndex = evt.oldIndex, | ||
newIndex = evt.newIndex; | ||
removed = prevItems[oldIndex]; | ||
if (el !== evt.from) { | ||
var prevItems = evt.from[expando](); | ||
if (evt.clone) { | ||
removed = angular.copy(removed); | ||
prevItems.splice(Sortable.utils.index(evt.clone), 0, prevItems.splice(oldIndex, 1)[0]); | ||
evt.from.removeChild(evt.clone); | ||
removed = prevItems[oldIndex]; | ||
if (evt.clone) { | ||
removed = angular.copy(removed); | ||
prevItems.splice(Sortable.utils.index(evt.clone, sortable.options.draggable), 0, prevItems.splice(oldIndex, 1)[0]); | ||
evt.from.removeChild(evt.clone); | ||
} | ||
else { | ||
prevItems.splice(oldIndex, 1); | ||
} | ||
items.splice(newIndex, 0, removed); | ||
evt.from.insertBefore(evt.item, nextSibling); // revert element | ||
} | ||
else { | ||
prevItems.splice(oldIndex, 1); | ||
items.splice(newIndex, 0, items.splice(oldIndex, 1)[0]); | ||
// move ng-repeat comment node to right position | ||
if (nextSibling.nodeType === Node.COMMENT_NODE) { | ||
evt.from.insertBefore(nextSibling, evt.item.nextSibling); | ||
} | ||
} | ||
items.splice(newIndex, 0, removed); | ||
evt.from.insertBefore(evt.item, nextSibling); // revert element | ||
scope.$apply(); | ||
} | ||
else { | ||
items.splice(newIndex, 0, items.splice(oldIndex, 1)[0]); | ||
} | ||
scope.$apply(); | ||
} | ||
function _destroy() { | ||
offDestroy(); | ||
angular.forEach(watchers, function (/** Function */unwatch) { | ||
unwatch(); | ||
}); | ||
sortable = Sortable.create(el, Object.keys(options).reduce(function (opts, name) { | ||
opts[name] = opts[name] || options[name]; | ||
return opts; | ||
}, { | ||
onStart: function (/**Event*/evt) { | ||
nextSibling = evt.from === evt.item.parentNode ? evt.item.nextSibling : evt.clone.nextSibling; | ||
_emitEvent(evt); | ||
scope.$apply(); | ||
}, | ||
onEnd: function (/**Event*/evt) { | ||
_emitEvent(evt, removed); | ||
scope.$apply(); | ||
}, | ||
onAdd: function (/**Event*/evt) { | ||
_sync(evt); | ||
_emitEvent(evt, removed); | ||
scope.$apply(); | ||
}, | ||
onUpdate: function (/**Event*/evt) { | ||
_sync(evt); | ||
_emitEvent(evt); | ||
}, | ||
onRemove: function (/**Event*/evt) { | ||
_emitEvent(evt, removed); | ||
}, | ||
onSort: function (/**Event*/evt) { | ||
_emitEvent(evt); | ||
sortable.destroy(); | ||
el[expando] = null; | ||
el = null; | ||
watchers = null; | ||
sortable = null; | ||
nextSibling = null; | ||
} | ||
})); | ||
$el.on('$destroy', function () { | ||
angular.forEach(watchers, function (/** Function */unwatch) { | ||
unwatch(); | ||
}); | ||
sortable.destroy(); | ||
// Initialization | ||
sortable = Sortable.create(el, Object.keys(options).reduce(function (opts, name) { | ||
opts[name] = opts[name] || options[name]; | ||
return opts; | ||
}, { | ||
onStart: function (/**Event*/evt) { | ||
nextSibling = evt.from === evt.item.parentNode ? evt.item.nextSibling : evt.clone.nextSibling; | ||
_emitEvent(evt); | ||
scope.$apply(); | ||
}, | ||
onEnd: function (/**Event*/evt) { | ||
_emitEvent(evt, removed); | ||
scope.$apply(); | ||
}, | ||
onAdd: function (/**Event*/evt) { | ||
_sync(evt); | ||
_emitEvent(evt, removed); | ||
scope.$apply(); | ||
}, | ||
onUpdate: function (/**Event*/evt) { | ||
_sync(evt); | ||
_emitEvent(evt); | ||
}, | ||
onRemove: function (/**Event*/evt) { | ||
_emitEvent(evt, removed); | ||
}, | ||
onSort: function (/**Event*/evt) { | ||
_emitEvent(evt); | ||
} | ||
})); | ||
el[expando] = null; | ||
el = null; | ||
watchers = null; | ||
sortable = null; | ||
nextSibling = null; | ||
}); | ||
// Create watchers for `options` | ||
angular.forEach([ | ||
'sort', 'disabled', 'draggable', 'handle', 'animation', 'group', 'ghostClass', 'filter', | ||
'onStart', 'onEnd', 'onAdd', 'onUpdate', 'onRemove', 'onSort', 'onMove', 'onClone', 'setData' | ||
], function (name) { | ||
watchers.push(scope.$watch('ngSortable.' + name, function (value) { | ||
if (value !== void 0) { | ||
options[name] = value; | ||
angular.forEach([ | ||
'sort', 'disabled', 'draggable', 'handle', 'animation', 'group', 'ghostClass', 'filter', | ||
'onStart', 'onEnd', 'onAdd', 'onUpdate', 'onRemove', 'onSort' | ||
], function (name) { | ||
watchers.push(scope.$watch('ngSortable.' + name, function (value) { | ||
if (value !== void 0) { | ||
options[name] = value; | ||
if (!/^on[A-Z]/.test(name)) { | ||
sortable.option(name, value); | ||
} | ||
} | ||
})); | ||
}); | ||
if (!/^on[A-Z]/.test(name)) { | ||
sortable.option(name, value); | ||
} | ||
} | ||
})); | ||
}); | ||
offDestroy = scope.$on('$destroy', _destroy); | ||
} | ||
} | ||
@@ -190,0 +209,0 @@ }; |
{ | ||
"name": "angular-legacy-sortablejs", | ||
"version": "0.4.0", | ||
"version": "0.4.1", | ||
"description": "Angular (legacy) directive for SortableJS.", | ||
@@ -5,0 +5,0 @@ "main": "angular-legacy-sortable.js", |
7276
171