+++ /dev/null
-//knockout-sortable | (c) 2012 Ryan Niemeyer | http://www.opensource.org/licenses/mit-license
-(function(ko, $, undefined) {
-var prepareTemplateOptions = function(valueAccessor) {
- var result = {},
- options = ko.utils.unwrapObservable(valueAccessor());
-
- //build our options to pass to the template engine
- if (options.data) {
- result.foreach = options.data;
- result.name = options.template;
- result.afterAdd = options.afterAdd;
- result.beforeRemove = options.beforeRemove;
- result.afterRender = options.afterRender;
- result.includeDestroyed = options.includeDestroyed;
- result.templateEngine = options.templateEngine;
- } else {
- result.foreach = valueAccessor();
- }
-
- //use an afterRender function to add meta-data
- if (options.afterRender) {
- //wrap the existing function, if it was passed
- result.afterRender = function(element, data) {
- ko.bindingHandlers.sortable.afterRender.call(data, element, data);
- options.afterRender.call(data, element, data);
- };
- } else {
- result.afterRender = ko.bindingHandlers.sortable.afterRender;
- }
-
- //return options to pass to the template binding
- return result;
-};
-
-//connect items with observableArrays
-ko.bindingHandlers.sortable = {
- init: function(element, valueAccessor, allBindingsAccessor, data, context) {
- var value = ko.utils.unwrapObservable(valueAccessor()),
- templateOptions = prepareTemplateOptions(valueAccessor),
- sortable = ko.bindingHandlers.sortable,
- connectClass = value.connectClass || sortable.connectClass,
- allowDrop = value.allowDrop === undefined ? sortable.allowDrop : value.allowDrop,
- beforeMove = value.beforeMove || sortable.beforeMove,
- afterMove = value.afterMove || sortable.afterMove,
- options = value.options || sortable.options;
-
- //if allowDrop is an observable or a function, then execute it in a computed observable
- if (ko.isObservable(allowDrop) || typeof allowDrop == "function") {
- ko.computed({
- read: function() {
- var value = ko.utils.unwrapObservable(allowDrop),
- shouldAdd = typeof value == "function" ? value.call(this, templateOptions.foreach) : value;
- ko.utils.toggleDomNodeCssClass(element, connectClass, shouldAdd);
- },
- disposeWhenNodeIsRemoved: element
- }, this);
- } else {
- ko.utils.toggleDomNodeCssClass(element, connectClass, allowDrop);
- }
-
- //attach meta-data
- $(element).data("ko_sortList", templateOptions.foreach);
- $(element).sortable(ko.utils.extend(options, {
- update: function(event, ui) {
- var sourceParent, targetParent, targetIndex, arg,
- item = ui.item.data("ko_sortItem");
-
- if (item) {
- //identify parents
- sourceParent = ui.item.data("ko_parentList");
- targetParent = ui.item.parent().data("ko_sortList");
- targetIndex = ko.utils.arrayIndexOf(ui.item.parent().children(), ui.item[0]);
-
- if (beforeMove || afterMove) {
- arg = {
- item: item,
- sourceParent: sourceParent,
- sourceIndex: sourceParent.indexOf(item),
- targetParent: targetParent,
- targetIndex: targetIndex,
- cancelDrop: false
- };
- }
-
- if (beforeMove) {
- beforeMove.call(this, arg, event, ui);
- if (arg.cancelDrop) {
- $(ui.sender).sortable('cancel');
- return;
- }
- }
-
- if (targetIndex >= 0) {
- sourceParent.remove(item);
- targetParent.splice(targetIndex, 0, item);
- }
- //rendering is handled by manipulating the observableArray; ignore dropped element
- ui.item.remove();
-
- //allow binding to accept a function to execute after moving the item
- if (afterMove) {
- afterMove.call(this, arg, event, ui);
- }
- }
- },
- connectWith: "." + connectClass
- }));
-
- //handle disposal
- ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
- $(element).sortable("destroy");
- });
- //we are wrapping the template binding
- return ko.bindingHandlers.template.init(element, function() { return templateOptions; }, allBindingsAccessor, data, context);
- },
- update: function(element, valueAccessor, allBindingsAccessor, data, context) {
- var templateOptions = prepareTemplateOptions(valueAccessor);
-
- //call the actual template binding
- ko.bindingHandlers.template.update(element, function() { return templateOptions; }, allBindingsAccessor, data, context);
- },
- afterRender: function(elements, data) {
- ko.utils.arrayForEach(elements, function(element) {
- if (element.nodeType === 1) {
- $(element).data("ko_sortItem", data);
- $(element).data("ko_parentList", $(element).parent().data("ko_sortList"));
- }
- });
- },
- connectClass: 'ko_container',
- allowDrop: true,
- afterMove: null,
- beforeMove: null,
- options: {}
-};
-})(ko, jQuery);
\ No newline at end of file