diff --git a/README.md b/README.md index 5d1561d..d7bb8c1 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,8 @@ Note2: (*Update: 0.9.0 adds code to automatically strip leading/trailing whitesp * **isEnabled** - specify whether the sortable widget should be enabled. If this is an observable, then it will enable/disable the widget when the observable's value changes. This option can be passed in the binding or configured globally by setting `ko.bindingHandlers.sortable.isEnabled`. +* **strategyMove** - specify whether dropping an item within the same list should move the same item to the new index rather than removing and re-adding the item in the new location (which is the default and causes the item to be re-rendered). This option can be passed in the binding or configured globally by setting `ko.bindingHandlers.sortable.strategyMove`. The default value is `false`. + * **options** - specify any additional options to pass on to the `.sortable` jQuery UI call. These options can be specified in the binding or specified globally by setting `ko.bindingHandlers.sortable.options`. * **afterAdd, beforeRemove, afterRender, includeDestroyed, templateEngine, as** - this binding will pass these options on to the template binding. diff --git a/build/knockout-sortable.js b/build/knockout-sortable.js index 4d1363b..ac37bc6 100644 --- a/build/knockout-sortable.js +++ b/build/knockout-sortable.js @@ -247,73 +247,73 @@ if (arg && arg.cancelDrop) { return; } - - //if the strategy option is unset or false, employ the order strategy involving removal and insertion of items - if(!sortable.hasOwnProperty("strategyMove") || sortable.strategyMove === false) - { - //do the actual move - if (targetIndex >= 0) { - if (sourceParent) { - sourceParent.splice(sourceIndex, 1); - - //if using deferred updates plugin, force updates - if (ko.processAllDeferredBindingUpdates) { - ko.processAllDeferredBindingUpdates(); - } - } - - targetParent.splice(targetIndex, 0, item); - } - - //rendering is handled by manipulating the observableArray; ignore dropped element - dataSet(el, ITEMKEY, null); - } - else { //employ the strategy of moving items - if (targetIndex >= 0) { - if (sourceParent) { - if (sourceParent !== targetParent) { - // moving from one list to another - - sourceParent.splice(sourceIndex, 1); - - //if using deferred updates plugin, force updates - if (ko.processAllDeferredBindingUpdates) { - ko.processAllDeferredBindingUpdates(); - } - - targetParent.splice(targetIndex, 0, item); - - //rendering is handled by manipulating the observableArray; ignore dropped element - dataSet(el, ITEMKEY, null); - ui.item.remove(); - } - else { - // moving within same list - var underlyingList = unwrap(sourceParent); - - // notify 'beforeChange' subscribers - sourceParent.valueWillMutate(); - - // move from source index ... - underlyingList.splice(sourceIndex, 1); - // ... to target index - underlyingList.splice(targetIndex, 0, item); - - // notify subscribers - sourceParent.valueHasMutated(); - } - } - else { - // drop new element from outside - targetParent.splice(targetIndex, 0, item); - - //rendering is handled by manipulating the observableArray; ignore dropped element - dataSet(el, ITEMKEY, null); - ui.item.remove(); - } - } - } - + + //if the strategy option is unset or false, employ the order strategy involving removal and insertion of items + if (!sortable.hasOwnProperty("strategyMove") || sortable.strategyMove === false) { + //do the actual move + if (targetIndex >= 0) { + if (sourceParent) { + sourceParent.splice(sourceIndex, 1); + + //if using deferred updates plugin, force updates + if (ko.processAllDeferredBindingUpdates) { + ko.processAllDeferredBindingUpdates(); + } + } + + targetParent.splice(targetIndex, 0, item); + } + + //rendering is handled by manipulating the observableArray; ignore dropped element + dataSet(el, ITEMKEY, null); + } + else { //employ the strategy of moving items + console.log( "strategy move" ); + if (targetIndex >= 0) { + if (sourceParent) { + if (sourceParent !== targetParent) { + // moving from one list to another + + sourceParent.splice(sourceIndex, 1); + + //if using deferred updates plugin, force updates + if (ko.processAllDeferredBindingUpdates) { + ko.processAllDeferredBindingUpdates(); + } + + targetParent.splice(targetIndex, 0, item); + + //rendering is handled by manipulating the observableArray; ignore dropped element + dataSet(el, ITEMKEY, null); + ui.item.remove(); + } + else { + // moving within same list + var underlyingList = unwrap(sourceParent); + + // notify 'beforeChange' subscribers + sourceParent.valueWillMutate(); + + // move from source index ... + underlyingList.splice(sourceIndex, 1); + // ... to target index + underlyingList.splice(targetIndex, 0, item); + + // notify subscribers + sourceParent.valueHasMutated(); + } + } + else { + // drop new element from outside + targetParent.splice(targetIndex, 0, item); + + //rendering is handled by manipulating the observableArray; ignore dropped element + dataSet(el, ITEMKEY, null); + ui.item.remove(); + } + } + } + //if using deferred updates plugin, force updates if (ko.processAllDeferredBindingUpdates) { ko.processAllDeferredBindingUpdates(); diff --git a/build/knockout-sortable.min.js b/build/knockout-sortable.min.js index a442748..9e21363 100644 --- a/build/knockout-sortable.min.js +++ b/build/knockout-sortable.min.js @@ -1,2 +1,2 @@ // knockout-sortable 0.13.0 | (c) 2016 Ryan Niemeyer | http://www.opensource.org/licenses/mit-license -!function(a){if("function"==typeof define&&define.amd)define(["knockout","jquery","jquery-ui/sortable","jquery-ui/draggable"],a);else if("function"==typeof require&&"object"==typeof exports&&"object"==typeof module){var b=require("knockout"),c=require("jquery");require("jquery-ui/sortable"),require("jquery-ui/draggable"),a(b,c)}else a(window.ko,window.jQuery)}(function(a,b){var c="ko_sortItem",d="ko_sourceIndex",e="ko_sortList",f="ko_parentList",g="ko_dragItem",h=a.utils.unwrapObservable,i=a.utils.domData.get,j=a.utils.domData.set,k=b.ui&&b.ui.version,l=k&&k.indexOf("1.6.")&&k.indexOf("1.7.")&&(k.indexOf("1.8.")||"1.8.24"===k),m=function(b,d){a.utils.arrayForEach(b,function(a){1===a.nodeType&&(j(a,c,d),j(a,f,i(a.parentNode,e)))})},n=function(b,c){var d,e={},f=h(b())||{};return f.data?(e[c]=f.data,e.name=f.template):e[c]=b(),a.utils.arrayForEach(["afterAdd","afterRender","as","beforeRemove","includeDestroyed","templateEngine","templateOptions","nodes"],function(b){f.hasOwnProperty(b)?e[b]=f[b]:a.bindingHandlers.sortable.hasOwnProperty(b)&&(e[b]=a.bindingHandlers.sortable[b])}),"foreach"===c&&(e.afterRender?(d=e.afterRender,e.afterRender=function(a,b){m.call(b,a,b),d.call(b,a,b)}):e.afterRender=m),e},o=function(a,b){var c=h(b);if(c)for(var d=0;a>d;d++)c[d]&&h(c[d]._destroy)&&a++;return a},p=function(c,d){var e,f;d?(f=document.getElementById(d),f&&(e=new a.templateSources.domElement(f),e.text(b.trim(e.text())))):b(c).contents().each(function(){this&&1!==this.nodeType&&c.removeChild(this)})};a.bindingHandlers.sortable={init:function(k,m,q,r,s){var t,u,v=b(k),w=h(m())||{},x=n(m,"foreach"),y={};p(k,x.name),b.extend(!0,y,a.bindingHandlers.sortable),w.options&&y.options&&(a.utils.extend(y.options,w.options),delete w.options),a.utils.extend(y,w),y.connectClass&&(a.isObservable(y.allowDrop)||"function"==typeof y.allowDrop)?a.computed({read:function(){var b=h(y.allowDrop),c="function"==typeof b?b.call(this,x.foreach):b;a.utils.toggleDomNodeCssClass(k,y.connectClass,c)},disposeWhenNodeIsRemoved:k},this):a.utils.toggleDomNodeCssClass(k,y.connectClass,y.allowDrop),a.bindingHandlers.template.init(k,function(){return x},q,r,s),t=y.options.start,u=y.options.update,y.options.helper=function(a,c){return c.is("tr")&&c.children().each(function(){b(this).width(b(this).width())}),c};var z=setTimeout(function(){var m;v.sortable(a.utils.extend(y.options,{start:function(b,c){var e=c.item[0];j(e,d,a.utils.arrayIndexOf(c.item.parent().children(),e)),c.item.find("input:focus").change(),t&&t.apply(this,arguments)},receive:function(a,b){m=i(b.item[0],g),m&&(m.clone&&(m=m.clone()),y.dragged&&(m=y.dragged.call(this,m,a,b)||m))},update:function(g,k){var n,p,q,r,s,t=k.item[0],v=k.item.parent()[0],w=i(t,c)||m;if(m=null,w&&this===v||!l&&b.contains(this,v)){if(n=i(t,f),q=i(t,d),p=i(t.parentNode,e),r=a.utils.arrayIndexOf(k.item.parent().children(),t),x.includeDestroyed||(q=o(q,n),r=o(r,p)),(y.beforeMove||y.afterMove)&&(s={item:w,sourceParent:n,sourceParentNode:n&&k.sender||t.parentNode,sourceIndex:q,targetParent:p,targetIndex:r,cancelDrop:!1},y.beforeMove&&y.beforeMove.call(this,s,g,k)),n?b(n===p?this:k.sender||this).sortable("cancel"):b(t).remove(),s&&s.cancelDrop)return;if(y.hasOwnProperty("strategyMove")&&y.strategyMove!==!1){if(r>=0)if(n)if(n!==p)n.splice(q,1),a.processAllDeferredBindingUpdates&&a.processAllDeferredBindingUpdates(),p.splice(r,0,w),j(t,c,null),k.item.remove();else{var z=h(n);n.valueWillMutate(),z.splice(q,1),z.splice(r,0,w),n.valueHasMutated()}else p.splice(r,0,w),j(t,c,null),k.item.remove()}else r>=0&&(n&&(n.splice(q,1),a.processAllDeferredBindingUpdates&&a.processAllDeferredBindingUpdates()),p.splice(r,0,w)),j(t,c,null);a.processAllDeferredBindingUpdates&&a.processAllDeferredBindingUpdates(),y.afterMove&&y.afterMove.call(this,s,g,k)}u&&u.apply(this,arguments)},connectWith:y.connectClass?"."+y.connectClass:!1})),void 0!==y.isEnabled&&a.computed({read:function(){v.sortable(h(y.isEnabled)?"enable":"disable")},disposeWhenNodeIsRemoved:k})},0);return a.utils.domNodeDisposal.addDisposeCallback(k,function(){(v.data("ui-sortable")||v.data("sortable"))&&v.sortable("destroy"),a.utils.toggleDomNodeCssClass(k,y.connectClass,!1),clearTimeout(z)}),{controlsDescendantBindings:!0}},update:function(b,c,d,f,g){var h=n(c,"foreach");j(b,e,h.foreach),a.bindingHandlers.template.update(b,function(){return h},d,f,g)},connectClass:"ko_container",allowDrop:!0,afterMove:null,beforeMove:null,options:{}},a.bindingHandlers.draggable={init:function(c,d,e,f,i){var k=h(d())||{},l=k.options||{},m=a.utils.extend({},a.bindingHandlers.draggable.options),o=n(d,"data"),p=k.connectClass||a.bindingHandlers.draggable.connectClass,q=void 0!==k.isEnabled?k.isEnabled:a.bindingHandlers.draggable.isEnabled;return k="data"in k?k.data:k,j(c,g,k),a.utils.extend(m,l),m.connectToSortable=p?"."+p:!1,b(c).draggable(m),void 0!==q&&a.computed({read:function(){b(c).draggable(h(q)?"enable":"disable")},disposeWhenNodeIsRemoved:c}),a.utils.domNodeDisposal.addDisposeCallback(c,function(){b(c).draggable("destroy")}),a.bindingHandlers.template.init(c,function(){return o},e,f,i)},update:function(b,c,d,e,f){var g=n(c,"data");return a.bindingHandlers.template.update(b,function(){return g},d,e,f)},connectClass:a.bindingHandlers.sortable.connectClass,options:{helper:"clone"}}}); \ No newline at end of file +!function(a){if("function"==typeof define&&define.amd)define(["knockout","jquery","jquery-ui/sortable","jquery-ui/draggable"],a);else if("function"==typeof require&&"object"==typeof exports&&"object"==typeof module){var b=require("knockout"),c=require("jquery");require("jquery-ui/sortable"),require("jquery-ui/draggable"),a(b,c)}else a(window.ko,window.jQuery)}(function(a,b){var c="ko_sortItem",d="ko_sourceIndex",e="ko_sortList",f="ko_parentList",g="ko_dragItem",h=a.utils.unwrapObservable,i=a.utils.domData.get,j=a.utils.domData.set,k=b.ui&&b.ui.version,l=k&&k.indexOf("1.6.")&&k.indexOf("1.7.")&&(k.indexOf("1.8.")||"1.8.24"===k),m=function(b,d){a.utils.arrayForEach(b,function(a){1===a.nodeType&&(j(a,c,d),j(a,f,i(a.parentNode,e)))})},n=function(b,c){var d,e={},f=h(b())||{};return f.data?(e[c]=f.data,e.name=f.template):e[c]=b(),a.utils.arrayForEach(["afterAdd","afterRender","as","beforeRemove","includeDestroyed","templateEngine","templateOptions","nodes"],function(b){f.hasOwnProperty(b)?e[b]=f[b]:a.bindingHandlers.sortable.hasOwnProperty(b)&&(e[b]=a.bindingHandlers.sortable[b])}),"foreach"===c&&(e.afterRender?(d=e.afterRender,e.afterRender=function(a,b){m.call(b,a,b),d.call(b,a,b)}):e.afterRender=m),e},o=function(a,b){var c=h(b);if(c)for(var d=0;a>d;d++)c[d]&&h(c[d]._destroy)&&a++;return a},p=function(c,d){var e,f;d?(f=document.getElementById(d),f&&(e=new a.templateSources.domElement(f),e.text(b.trim(e.text())))):b(c).contents().each(function(){this&&1!==this.nodeType&&c.removeChild(this)})};a.bindingHandlers.sortable={init:function(k,m,q,r,s){var t,u,v=b(k),w=h(m())||{},x=n(m,"foreach"),y={};p(k,x.name),b.extend(!0,y,a.bindingHandlers.sortable),w.options&&y.options&&(a.utils.extend(y.options,w.options),delete w.options),a.utils.extend(y,w),y.connectClass&&(a.isObservable(y.allowDrop)||"function"==typeof y.allowDrop)?a.computed({read:function(){var b=h(y.allowDrop),c="function"==typeof b?b.call(this,x.foreach):b;a.utils.toggleDomNodeCssClass(k,y.connectClass,c)},disposeWhenNodeIsRemoved:k},this):a.utils.toggleDomNodeCssClass(k,y.connectClass,y.allowDrop),a.bindingHandlers.template.init(k,function(){return x},q,r,s),t=y.options.start,u=y.options.update,y.options.helper=function(a,c){return c.is("tr")&&c.children().each(function(){b(this).width(b(this).width())}),c};var z=setTimeout(function(){var m;v.sortable(a.utils.extend(y.options,{start:function(b,c){var e=c.item[0];j(e,d,a.utils.arrayIndexOf(c.item.parent().children(),e)),c.item.find("input:focus").change(),t&&t.apply(this,arguments)},receive:function(a,b){m=i(b.item[0],g),m&&(m.clone&&(m=m.clone()),y.dragged&&(m=y.dragged.call(this,m,a,b)||m))},update:function(g,k){var n,p,q,r,s,t=k.item[0],v=k.item.parent()[0],w=i(t,c)||m;if(m=null,w&&this===v||!l&&b.contains(this,v)){if(n=i(t,f),q=i(t,d),p=i(t.parentNode,e),r=a.utils.arrayIndexOf(k.item.parent().children(),t),x.includeDestroyed||(q=o(q,n),r=o(r,p)),(y.beforeMove||y.afterMove)&&(s={item:w,sourceParent:n,sourceParentNode:n&&k.sender||t.parentNode,sourceIndex:q,targetParent:p,targetIndex:r,cancelDrop:!1},y.beforeMove&&y.beforeMove.call(this,s,g,k)),n?b(n===p?this:k.sender||this).sortable("cancel"):b(t).remove(),s&&s.cancelDrop)return;if(y.hasOwnProperty("strategyMove")&&y.strategyMove!==!1){if(console.log("strategy move"),r>=0)if(n)if(n!==p)n.splice(q,1),a.processAllDeferredBindingUpdates&&a.processAllDeferredBindingUpdates(),p.splice(r,0,w),j(t,c,null),k.item.remove();else{var z=h(n);n.valueWillMutate(),z.splice(q,1),z.splice(r,0,w),n.valueHasMutated()}else p.splice(r,0,w),j(t,c,null),k.item.remove()}else r>=0&&(n&&(n.splice(q,1),a.processAllDeferredBindingUpdates&&a.processAllDeferredBindingUpdates()),p.splice(r,0,w)),j(t,c,null);a.processAllDeferredBindingUpdates&&a.processAllDeferredBindingUpdates(),y.afterMove&&y.afterMove.call(this,s,g,k)}u&&u.apply(this,arguments)},connectWith:y.connectClass?"."+y.connectClass:!1})),void 0!==y.isEnabled&&a.computed({read:function(){v.sortable(h(y.isEnabled)?"enable":"disable")},disposeWhenNodeIsRemoved:k})},0);return a.utils.domNodeDisposal.addDisposeCallback(k,function(){(v.data("ui-sortable")||v.data("sortable"))&&v.sortable("destroy"),a.utils.toggleDomNodeCssClass(k,y.connectClass,!1),clearTimeout(z)}),{controlsDescendantBindings:!0}},update:function(b,c,d,f,g){var h=n(c,"foreach");j(b,e,h.foreach),a.bindingHandlers.template.update(b,function(){return h},d,f,g)},connectClass:"ko_container",allowDrop:!0,afterMove:null,beforeMove:null,options:{}},a.bindingHandlers.draggable={init:function(c,d,e,f,i){var k=h(d())||{},l=k.options||{},m=a.utils.extend({},a.bindingHandlers.draggable.options),o=n(d,"data"),p=k.connectClass||a.bindingHandlers.draggable.connectClass,q=void 0!==k.isEnabled?k.isEnabled:a.bindingHandlers.draggable.isEnabled;return k="data"in k?k.data:k,j(c,g,k),a.utils.extend(m,l),m.connectToSortable=p?"."+p:!1,b(c).draggable(m),void 0!==q&&a.computed({read:function(){b(c).draggable(h(q)?"enable":"disable")},disposeWhenNodeIsRemoved:c}),a.utils.domNodeDisposal.addDisposeCallback(c,function(){b(c).draggable("destroy")}),a.bindingHandlers.template.init(c,function(){return o},e,f,i)},update:function(b,c,d,e,f){var g=n(c,"data");return a.bindingHandlers.template.update(b,function(){return g},d,e,f)},connectClass:a.bindingHandlers.sortable.connectClass,options:{helper:"clone"}}}); \ No newline at end of file diff --git a/src/knockout-sortable.js b/src/knockout-sortable.js index 3e7c0e2..a3b4ab8 100644 --- a/src/knockout-sortable.js +++ b/src/knockout-sortable.js @@ -246,73 +246,73 @@ if (arg && arg.cancelDrop) { return; } - - //if the strategy option is unset or false, employ the order strategy involving removal and insertion of items - if(!sortable.hasOwnProperty("strategyMove") || sortable.strategyMove === false) - { - //do the actual move - if (targetIndex >= 0) { - if (sourceParent) { - sourceParent.splice(sourceIndex, 1); - - //if using deferred updates plugin, force updates - if (ko.processAllDeferredBindingUpdates) { - ko.processAllDeferredBindingUpdates(); - } - } - - targetParent.splice(targetIndex, 0, item); - } - - //rendering is handled by manipulating the observableArray; ignore dropped element - dataSet(el, ITEMKEY, null); - } - else { //employ the strategy of moving items - if (targetIndex >= 0) { - if (sourceParent) { - if (sourceParent !== targetParent) { - // moving from one list to another - - sourceParent.splice(sourceIndex, 1); - - //if using deferred updates plugin, force updates - if (ko.processAllDeferredBindingUpdates) { - ko.processAllDeferredBindingUpdates(); - } - - targetParent.splice(targetIndex, 0, item); - - //rendering is handled by manipulating the observableArray; ignore dropped element - dataSet(el, ITEMKEY, null); - ui.item.remove(); - } - else { - // moving within same list - var underlyingList = unwrap(sourceParent); - - // notify 'beforeChange' subscribers - sourceParent.valueWillMutate(); - - // move from source index ... - underlyingList.splice(sourceIndex, 1); - // ... to target index - underlyingList.splice(targetIndex, 0, item); - - // notify subscribers - sourceParent.valueHasMutated(); - } - } - else { - // drop new element from outside - targetParent.splice(targetIndex, 0, item); - - //rendering is handled by manipulating the observableArray; ignore dropped element - dataSet(el, ITEMKEY, null); - ui.item.remove(); - } - } - } - + + //if the strategy option is unset or false, employ the order strategy involving removal and insertion of items + if (!sortable.hasOwnProperty("strategyMove") || sortable.strategyMove === false) { + //do the actual move + if (targetIndex >= 0) { + if (sourceParent) { + sourceParent.splice(sourceIndex, 1); + + //if using deferred updates plugin, force updates + if (ko.processAllDeferredBindingUpdates) { + ko.processAllDeferredBindingUpdates(); + } + } + + targetParent.splice(targetIndex, 0, item); + } + + //rendering is handled by manipulating the observableArray; ignore dropped element + dataSet(el, ITEMKEY, null); + } + else { //employ the strategy of moving items + console.log( "strategy move" ); + if (targetIndex >= 0) { + if (sourceParent) { + if (sourceParent !== targetParent) { + // moving from one list to another + + sourceParent.splice(sourceIndex, 1); + + //if using deferred updates plugin, force updates + if (ko.processAllDeferredBindingUpdates) { + ko.processAllDeferredBindingUpdates(); + } + + targetParent.splice(targetIndex, 0, item); + + //rendering is handled by manipulating the observableArray; ignore dropped element + dataSet(el, ITEMKEY, null); + ui.item.remove(); + } + else { + // moving within same list + var underlyingList = unwrap(sourceParent); + + // notify 'beforeChange' subscribers + sourceParent.valueWillMutate(); + + // move from source index ... + underlyingList.splice(sourceIndex, 1); + // ... to target index + underlyingList.splice(targetIndex, 0, item); + + // notify subscribers + sourceParent.valueHasMutated(); + } + } + else { + // drop new element from outside + targetParent.splice(targetIndex, 0, item); + + //rendering is handled by manipulating the observableArray; ignore dropped element + dataSet(el, ITEMKEY, null); + ui.item.remove(); + } + } + } + //if using deferred updates plugin, force updates if (ko.processAllDeferredBindingUpdates) { ko.processAllDeferredBindingUpdates();