diff options
author | Olivier Lamy <olamy@apache.org> | 2013-05-02 06:41:53 +0000 |
---|---|---|
committer | Olivier Lamy <olamy@apache.org> | 2013-05-02 06:41:53 +0000 |
commit | 6100dd6b54f9bb40b106716d237c8ae1296aeae0 (patch) | |
tree | e243ea016aa3f8179926dcb77c3269856f3b3007 | |
parent | 4aca37189a65f3d4f59e5c040e0b93486b52c478 (diff) | |
download | archiva-6100dd6b54f9bb40b106716d237c8ae1296aeae0.tar.gz archiva-6100dd6b54f9bb40b106716d237c8ae1296aeae0.zip |
use knockout-sortable 0.7.2
git-svn-id: https://svn.apache.org/repos/asf/archiva/trunk@1478283 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r-- | archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/knockout-sortable.js | 558 |
1 files changed, 291 insertions, 267 deletions
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/knockout-sortable.js b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/knockout-sortable.js index f4259528b..287e5664f 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/knockout-sortable.js +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/js/knockout-sortable.js @@ -1,285 +1,309 @@ -//knockout-sortable 0.6.6 | (c) 2012 Ryan Niemeyer | http://www.opensource.org/licenses/mit-license +//knockout-sortable 0.7.2 | (c) 2012 Ryan Niemeyer | http://www.opensource.org/licenses/mit-license (function(factory) { - if (typeof define === "function" && define.amd) { - // AMD anonymous module - define(["knockout", "jquery", "jquery.ui"], factory); + if (typeof define === "function" && define.amd) { + // AMD anonymous module + define(["knockout", "jquery", "jquery.ui"], factory); + } else { + // No module loader (plain <script> tag) - put directly in global namespace + factory(window.ko, jQuery); + } +})(function(ko, $, undefined) { + var ITEMKEY = "ko_sortItem", + LISTKEY = "ko_sortList", + PARENTKEY = "ko_parentList", + DRAGKEY = "ko_dragItem", + unwrap = ko.utils.unwrapObservable; + + //internal afterRender that adds meta-data to children + var addMetaDataAfterRender = function(elements, data) { + ko.utils.arrayForEach(elements, function(element) { + if (element.nodeType === 1) { + ko.utils.domData.set(element, ITEMKEY, data); + ko.utils.domData.set(element, PARENTKEY, ko.utils.domData.get(element.parentNode, LISTKEY)); + } + }); + }; + + //prepare the proper options for the template binding + var prepareTemplateOptions = function(valueAccessor, dataName) { + var result = {}, + options = unwrap(valueAccessor()), + actualAfterRender; + + //build our options to pass to the template engine + if (options.data) { + result[dataName] = options.data; + result.name = options.template; } else { - // No module loader (plain <script> tag) - put directly in global namespace - factory(window.ko, jQuery); + result[dataName] = valueAccessor(); } -})(function(ko, $, undefined) { - var ITEMKEY = "ko_sortItem", - LISTKEY = "ko_sortList", - PARENTKEY = "ko_parentList", - DRAGKEY = "ko_dragItem"; - - //internal afterRender that adds meta-data to children - var addMetaDataAfterRender = function(elements, data) { - ko.utils.arrayForEach(elements, function(element) { - if (element.nodeType === 1) { - ko.utils.domData.set(element, ITEMKEY, data); - ko.utils.domData.set(element, PARENTKEY, ko.utils.domData.get(element.parentNode, LISTKEY)); - } - }); - }; - - //prepare the proper options for the template binding - var prepareTemplateOptions = function(valueAccessor, dataName) { - var result = {}, - options = ko.utils.unwrapObservable(valueAccessor()), - actualAfterRender; - - //build our options to pass to the template engine - if (options.data) { - result[dataName] = options.data; - result.name = options.template; - } else { - result[dataName] = valueAccessor(); - } - ko.utils.arrayForEach(["afterAdd", "afterRender", "beforeRemove", "includeDestroyed", "templateEngine", "templateOptions"], function (option) { - result[option] = options[option] || ko.bindingHandlers.sortable[option]; - }); - - //use an afterRender function to add meta-data - if (dataName === "foreach") { - if (result.afterRender) { - //wrap the existing function, if it was passed - actualAfterRender = result.afterRender; - result.afterRender = function(element, data) { - addMetaDataAfterRender.call(data, element, data); - actualAfterRender.call(data, element, data); - }; - } else { - result.afterRender = addMetaDataAfterRender; - } + ko.utils.arrayForEach(["afterAdd", "afterRender", "as", "beforeRemove", "includeDestroyed", "templateEngine", "templateOptions"], function (option) { + result[option] = options[option] || ko.bindingHandlers.sortable[option]; + }); + + //use an afterRender function to add meta-data + if (dataName === "foreach") { + if (result.afterRender) { + //wrap the existing function, if it was passed + actualAfterRender = result.afterRender; + result.afterRender = function(element, data) { + addMetaDataAfterRender.call(data, element, data); + actualAfterRender.call(data, element, data); + }; + } else { + result.afterRender = addMetaDataAfterRender; + } + } + + //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 $element = $(element), + value = unwrap(valueAccessor()) || {}, + templateOptions = prepareTemplateOptions(valueAccessor, "foreach"), + sortable = {}, + startActual, updateActual; + + //remove leading/trailing text nodes from anonymous templates + ko.utils.arrayForEach(element.childNodes, function(node) { + if (node && node.nodeType === 3) { + node.parentNode.removeChild(node); } + }); + + //build a new object that has the global options with overrides from the binding + $.extend(true, sortable, ko.bindingHandlers.sortable); + if (value.options && sortable.options) { + ko.utils.extend(sortable.options, value.options); + delete value.options; + } + ko.utils.extend(sortable, value); + + //if allowDrop is an observable or a function, then execute it in a computed observable + if (sortable.connectClass && (ko.isObservable(sortable.allowDrop) || typeof sortable.allowDrop == "function")) { + ko.computed({ + read: function() { + var value = unwrap(sortable.allowDrop), + shouldAdd = typeof value == "function" ? value.call(this, templateOptions.foreach) : value; + ko.utils.toggleDomNodeCssClass(element, sortable.connectClass, shouldAdd); + }, + disposeWhenNodeIsRemoved: element + }, this); + } else { + ko.utils.toggleDomNodeCssClass(element, sortable.connectClass, sortable.allowDrop); + } + + //wrap the template binding + ko.bindingHandlers.template.init(element, function() { return templateOptions; }, allBindingsAccessor, data, context); + + //keep a reference to start/update functions that might have been passed in + startActual = sortable.options.start; + updateActual = sortable.options.update; + + //initialize sortable binding after template binding has rendered in update function + var createTimeout = setTimeout(function() { + var dragItem; + $element.sortable(ko.utils.extend(sortable.options, { + start: function(event, ui) { + //make sure that fields have a chance to update model + ui.item.find("input:focus").change(); + if (startActual) { + startActual.apply(this, arguments); + } + }, + receive: function(event, ui) { + dragItem = ko.utils.domData.get(ui.item[0], DRAGKEY); + if (dragItem) { + //copy the model item, if a clone option is provided + if (dragItem.clone) { + dragItem = dragItem.clone(); + } + + //configure a handler to potentially manipulate item before drop + if (sortable.dragged) { + dragItem = sortable.dragged.call(this, dragItem, event, ui) || dragItem; + } + } + }, + update: function(event, ui) { + var sourceParent, targetParent, targetIndex, i, targetUnwrapped, arg, + el = ui.item[0], + parentEl = ui.item.parent()[0], + item = ko.utils.domData.get(el, ITEMKEY) || dragItem; + + dragItem = null; + + //make sure that moves only run once, as update fires on multiple containers + if (item && (this === parentEl || $.contains(this, parentEl))) { + //identify parents + sourceParent = ko.utils.domData.get(el, PARENTKEY); + targetParent = ko.utils.domData.get(el.parentNode, LISTKEY); + targetIndex = ko.utils.arrayIndexOf(ui.item.parent().children(), el); + + //take destroyed items into consideration + if (!templateOptions.includeDestroyed) { + targetUnwrapped = targetParent(); + for (i = 0; i < targetIndex; i++) { + //add one for every destroyed item we find before the targetIndex in the target array + if (targetUnwrapped[i] && unwrap(targetUnwrapped[i]._destroy)) { + targetIndex++; + } + } + } + + if (sortable.beforeMove || sortable.afterMove) { + arg = { + item: item, + sourceParent: sourceParent, + sourceParentNode: sourceParent && el.parentNode, + sourceIndex: sourceParent && sourceParent.indexOf(item), + targetParent: targetParent, + targetIndex: targetIndex, + cancelDrop: false + }; + } + + if (sortable.beforeMove) { + sortable.beforeMove.call(this, arg, event, ui); + if (arg.cancelDrop) { + //call cancel on the correct list + if (arg.sourceParent) { + $(arg.sourceParent === arg.targetParent ? this : ui.sender).sortable('cancel'); + } + //for a draggable item just remove the element + else { + $(el).remove(); + } + + return; + } + } - //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 $element = $(element), - value = ko.utils.unwrapObservable(valueAccessor()) || {}, - templateOptions = prepareTemplateOptions(valueAccessor, "foreach"), - sortable = {}, - startActual, updateActual; - - //remove leading/trailing text nodes from anonymous templates - ko.utils.arrayForEach(element.childNodes, function(node) { - if (node && node.nodeType === 3) { - node.parentNode.removeChild(node); + if (targetIndex >= 0) { + if (sourceParent) { + sourceParent.remove(item); + + //if using deferred updates plugin, force updates + if (ko.processAllDeferredBindingUpdates) { + ko.processAllDeferredBindingUpdates(); + } } - }); - //build a new object that has the global options with overrides from the binding - $.extend(true, sortable, ko.bindingHandlers.sortable); - if (value.options && sortable.options) { - ko.utils.extend(sortable.options, value.options); - delete value.options; + targetParent.splice(targetIndex, 0, item); + } + + //rendering is handled by manipulating the observableArray; ignore dropped element + ko.utils.domData.set(el, ITEMKEY, null); + ui.item.remove(); + + //if using deferred updates plugin, force updates + if (ko.processAllDeferredBindingUpdates) { + ko.processAllDeferredBindingUpdates(); + } + + //allow binding to accept a function to execute after moving the item + if (sortable.afterMove) { + sortable.afterMove.call(this, arg, event, ui); + } } - ko.utils.extend(sortable, value); - //if allowDrop is an observable or a function, then execute it in a computed observable - if (sortable.connectClass && (ko.isObservable(sortable.allowDrop) || typeof sortable.allowDrop == "function")) { - ko.computed({ - read: function() { - var value = ko.utils.unwrapObservable(sortable.allowDrop), - shouldAdd = typeof value == "function" ? value.call(this, templateOptions.foreach) : value; - ko.utils.toggleDomNodeCssClass(element, sortable.connectClass, shouldAdd); - }, - disposeWhenNodeIsRemoved: element - }, this); - } else { - ko.utils.toggleDomNodeCssClass(element, sortable.connectClass, sortable.allowDrop); + if (updateActual) { + updateActual.apply(this, arguments); } + }, + connectWith: sortable.connectClass ? "." + sortable.connectClass : false + })); - //wrap the template binding - ko.bindingHandlers.template.init(element, function() { return templateOptions; }, allBindingsAccessor, data, context); - - //keep a reference to start/update functions that might have been passed in - startActual = sortable.options.start; - updateActual = sortable.options.update; - - //initialize sortable binding after template binding has rendered in update function - setTimeout(function() { - var dragItem; - $element.sortable(ko.utils.extend(sortable.options, { - start: function(event, ui) { - //make sure that fields have a chance to update model - ui.item.find("input:focus").change(); - if (startActual) { - startActual.apply(this, arguments); - } - }, - receive: function(event, ui) { - dragItem = ko.utils.domData.get(ui.item[0], DRAGKEY); - if (dragItem && dragItem.clone) { - dragItem = dragItem.clone(); - } - }, - update: function(event, ui) { - var sourceParent, targetParent, targetIndex, i, targetUnwrapped, arg, - el = ui.item[0], - item = ko.utils.domData.get(el, ITEMKEY) || dragItem; - - dragItem = null; - - if (this === ui.item.parent()[0] && item) { - //identify parents - sourceParent = ko.utils.domData.get(el, PARENTKEY); - targetParent = ko.utils.domData.get(el.parentNode, LISTKEY); - targetIndex = ko.utils.arrayIndexOf(ui.item.parent().children(), el); - - //take destroyed items into consideration - if (!templateOptions.includeDestroyed) { - if(targetParent){ - targetUnwrapped = $.isFunction(targetParent)?targetParent():targetParent; - for (i = 0; i < targetIndex; i++) { - //add one for every destroyed item we find before the targetIndex in the target array - if (targetUnwrapped[i] && targetUnwrapped[i]._destroy) { - targetIndex++; - } - } - } - } - - if (sortable.beforeMove || sortable.afterMove) { - arg = { - item: item, - sourceParent: sourceParent, - sourceParentNode: sourceParent && el.parentNode, - sourceIndex: sourceParent && sourceParent.indexOf(item), - targetParent: targetParent, - targetIndex: targetIndex, - cancelDrop: false - }; - } - - if (sortable.beforeMove) { - sortable.beforeMove.call(this, arg, event, ui); - if (arg.cancelDrop) { - //call cancel on the correct list - if (arg.sourceParent) { - $(arg.sourceParent === arg.targetParent ? this : ui.sender).sortable('cancel'); - } - //for a draggable item just remove the element - else { - $(el).remove(); - } - - return; - } - } - - if (targetIndex >= 0) { - if (sourceParent) { - if( $.isFunction(sourceParent.remove)) sourceParent.remove(item); - } - - targetParent.splice(targetIndex, 0, item); - } - - //rendering is handled by manipulating the observableArray; ignore dropped element - ko.utils.domData.set(el, ITEMKEY, null); - ui.item.remove(); - - //allow binding to accept a function to execute after moving the item - if (sortable.afterMove) { - sortable.afterMove.call(this, arg, event, ui); - } - } - - if (updateActual) { - updateActual.apply(this, arguments); - } - }, - connectWith: sortable.connectClass ? "." + sortable.connectClass : false - })); - - //handle enabling/disabling sorting - if (sortable.isEnabled !== undefined) { - ko.computed({ + //handle enabling/disabling sorting + if (sortable.isEnabled !== undefined) { + ko.computed({ read: function() { - $element.sortable(ko.utils.unwrapObservable(sortable.isEnabled) ? "enable" : "disable"); + $element.sortable(unwrap(sortable.isEnabled) ? "enable" : "disable"); }, disposeWhenNodeIsRemoved: element - }); - } - }, 0); - - //handle disposal - ko.utils.domNodeDisposal.addDisposeCallback(element, function() { - $element.sortable("destroy"); - }); - - return { 'controlsDescendantBindings': true }; - }, - update: function(element, valueAccessor, allBindingsAccessor, data, context) { - var templateOptions = prepareTemplateOptions(valueAccessor, "foreach"); - - //attach meta-data - ko.utils.domData.set(element, LISTKEY, templateOptions.foreach); - - //call template binding's update with correct options - ko.bindingHandlers.template.update(element, function() { return templateOptions; }, allBindingsAccessor, data, context); - }, - connectClass: 'ko_container', - allowDrop: true, - afterMove: null, - beforeMove: null, - options: {} - }; - - //create a draggable that is appropriate for dropping into a sortable - ko.bindingHandlers.draggable = { - init: function(element, valueAccessor, allBindingsAccessor, data, context) { - var value = ko.utils.unwrapObservable(valueAccessor()) || {}, - options = value.options || {}, - draggableOptions = ko.utils.extend({}, ko.bindingHandlers.draggable.options), - templateOptions = prepareTemplateOptions(valueAccessor, "data"), - connectClass = value.connectClass || ko.bindingHandlers.draggable.connectClass, - isEnabled = value.isEnabled !== undefined ? value.isEnabled : ko.bindingHandlers.draggable.isEnabled; - - value = value.data || value; - - //set meta-data - ko.utils.domData.set(element, DRAGKEY, value); - - //override global options with override options passed in - ko.utils.extend(draggableOptions, options); - - //setup connection to a sortable - - draggableOptions.connectToSortable = connectClass ? "." + connectClass : false; - - //initialize draggable - $(element).draggable(draggableOptions); - - //handle enabling/disabling sorting - if (isEnabled !== undefined) { - ko.computed({ - read: function() { - $(element).draggable(ko.utils.unwrapObservable(isEnabled) ? "enable" : "disable"); - }, - disposeWhenNodeIsRemoved: element - }); - } - - return ko.bindingHandlers.template.init(element, function() { return templateOptions; }, allBindingsAccessor, data, context); - }, - update: function(element, valueAccessor, allBindingsAccessor, data, context) { - var templateOptions = prepareTemplateOptions(valueAccessor, "data"); + }); + } + }, 0); - return ko.bindingHandlers.template.update(element, function() { return templateOptions; }, allBindingsAccessor, data, context); - }, - connectClass: ko.bindingHandlers.sortable.connectClass, - options: { - helper: "clone" + //handle disposal + ko.utils.domNodeDisposal.addDisposeCallback(element, function() { + //only call destroy if sortable has been created + if ($element.data("sortable")) { + $element.sortable("destroy"); } - }; -}); + //do not create the sortable if the element has been removed from DOM + clearTimeout(createTimeout); + }); + + return { 'controlsDescendantBindings': true }; + }, + update: function(element, valueAccessor, allBindingsAccessor, data, context) { + var templateOptions = prepareTemplateOptions(valueAccessor, "foreach"); + + //attach meta-data + ko.utils.domData.set(element, LISTKEY, templateOptions.foreach); + + //call template binding's update with correct options + ko.bindingHandlers.template.update(element, function() { return templateOptions; }, allBindingsAccessor, data, context); + }, + connectClass: 'ko_container', + allowDrop: true, + afterMove: null, + beforeMove: null, + options: {} + }; + + //create a draggable that is appropriate for dropping into a sortable + ko.bindingHandlers.draggable = { + init: function(element, valueAccessor, allBindingsAccessor, data, context) { + var value = unwrap(valueAccessor()) || {}, + options = value.options || {}, + draggableOptions = ko.utils.extend({}, ko.bindingHandlers.draggable.options), + templateOptions = prepareTemplateOptions(valueAccessor, "data"), + connectClass = value.connectClass || ko.bindingHandlers.draggable.connectClass, + isEnabled = value.isEnabled !== undefined ? value.isEnabled : ko.bindingHandlers.draggable.isEnabled; + + value = value.data || value; + + //set meta-data + ko.utils.domData.set(element, DRAGKEY, value); + + //override global options with override options passed in + ko.utils.extend(draggableOptions, options); + + //setup connection to a sortable + draggableOptions.connectToSortable = connectClass ? "." + connectClass : false; + + //initialize draggable + $(element).draggable(draggableOptions); + + //handle enabling/disabling sorting + if (isEnabled !== undefined) { + ko.computed({ + read: function() { + $(element).draggable(unwrap(isEnabled) ? "enable" : "disable"); + }, + disposeWhenNodeIsRemoved: element + }); + } + + return ko.bindingHandlers.template.init(element, function() { return templateOptions; }, allBindingsAccessor, data, context); + }, + update: function(element, valueAccessor, allBindingsAccessor, data, context) { + var templateOptions = prepareTemplateOptions(valueAccessor, "data"); + + return ko.bindingHandlers.template.update(element, function() { return templateOptions; }, allBindingsAccessor, data, context); + }, + connectClass: ko.bindingHandlers.sortable.connectClass, + options: { + helper: "clone" + } + }; + +});
\ No newline at end of file |