| 1 | efrain | 1 | YUI.add('tree-sortable', function (Y, NAME) {
 | 
        
           |  |  | 2 |   | 
        
           |  |  | 3 | /*jshint expr:true, onevar:false */
 | 
        
           |  |  | 4 |   | 
        
           |  |  | 5 | /**
 | 
        
           |  |  | 6 | Extension for `Tree` that makes nodes sortable.
 | 
        
           |  |  | 7 |   | 
        
           |  |  | 8 | @module tree
 | 
        
           |  |  | 9 | @submodule tree-sortable
 | 
        
           |  |  | 10 | @main tree-sortable
 | 
        
           |  |  | 11 | **/
 | 
        
           |  |  | 12 |   | 
        
           |  |  | 13 | /**
 | 
        
           |  |  | 14 | Extension for `Tree` that makes nodes sortable.
 | 
        
           |  |  | 15 |   | 
        
           |  |  | 16 | @class Tree.Sortable
 | 
        
           |  |  | 17 | @constructor
 | 
        
           |  |  | 18 | @param {Object} [config] Configuration options.
 | 
        
           |  |  | 19 | @param {Function} [config.sortComparator] Default comparator function to use
 | 
        
           |  |  | 20 |     when sorting a node's children if the node itself doesn't have a custom
 | 
        
           |  |  | 21 |     comparator function. If not specified, insertion order will be used by
 | 
        
           |  |  | 22 |     default.
 | 
        
           |  |  | 23 | @param {Boolean} [config.sortReverse=false] If `true`, node children will be
 | 
        
           |  |  | 24 |     sorted in reverse (descending) order by default. Otherwise they'll be sorted
 | 
        
           |  |  | 25 |     in ascending order.
 | 
        
           |  |  | 26 | @extensionfor Tree
 | 
        
           |  |  | 27 | **/
 | 
        
           |  |  | 28 |   | 
        
           |  |  | 29 | /**
 | 
        
           |  |  | 30 | Fired after a node's children are re-sorted.
 | 
        
           |  |  | 31 |   | 
        
           |  |  | 32 | @event sort
 | 
        
           |  |  | 33 | @param {Tree.Node} node Node whose children were sorted.
 | 
        
           |  |  | 34 | @param {Boolean} reverse `true` if the children were sorted in reverse
 | 
        
           |  |  | 35 |     (descending) order, `false` otherwise.
 | 
        
           |  |  | 36 | @param {String} src Source of the event.
 | 
        
           |  |  | 37 | **/
 | 
        
           |  |  | 38 | var EVT_SORT = 'sort';
 | 
        
           |  |  | 39 |   | 
        
           |  |  | 40 | function Sortable() {}
 | 
        
           |  |  | 41 |   | 
        
           |  |  | 42 | Sortable.prototype = {
 | 
        
           |  |  | 43 |     // -- Public Properties ----------------------------------------------------
 | 
        
           |  |  | 44 |   | 
        
           |  |  | 45 |     /**
 | 
        
           |  |  | 46 |     If `true`, node children will be sorted in reverse (descending) order by
 | 
        
           |  |  | 47 |     default. Otherwise they'll be sorted in ascending order.
 | 
        
           |  |  | 48 |   | 
        
           |  |  | 49 |     @property {Boolean} sortReverse
 | 
        
           |  |  | 50 |     @default false
 | 
        
           |  |  | 51 |     **/
 | 
        
           |  |  | 52 |     sortReverse: false,
 | 
        
           |  |  | 53 |   | 
        
           |  |  | 54 |     // -- Lifecycle ------------------------------------------------------------
 | 
        
           |  |  | 55 |     initializer: function (config) {
 | 
        
           |  |  | 56 |         this.nodeExtensions = this.nodeExtensions.concat(Y.Tree.Node.Sortable);
 | 
        
           |  |  | 57 |   | 
        
           |  |  | 58 |         if (config) {
 | 
        
           |  |  | 59 |             if (config.sortComparator) {
 | 
        
           |  |  | 60 |                 this.sortComparator = config.sortComparator;
 | 
        
           |  |  | 61 |             }
 | 
        
           |  |  | 62 |   | 
        
           |  |  | 63 |             if ('sortReverse' in config) {
 | 
        
           |  |  | 64 |                 this.sortReverse = config.sortReverse;
 | 
        
           |  |  | 65 |             }
 | 
        
           |  |  | 66 |         }
 | 
        
           |  |  | 67 |     },
 | 
        
           |  |  | 68 |   | 
        
           |  |  | 69 |     // -- Public Methods -------------------------------------------------------
 | 
        
           |  |  | 70 |   | 
        
           |  |  | 71 |     /**
 | 
        
           |  |  | 72 |     Sorts the children of every node in this tree.
 | 
        
           |  |  | 73 |   | 
        
           |  |  | 74 |     A `sort` event will be fired for each node whose children are sorted, which
 | 
        
           |  |  | 75 |     can get very noisy. If this is a large tree, you may want to set the
 | 
        
           |  |  | 76 |     `silent` option to `true` to suppress these events.
 | 
        
           |  |  | 77 |   | 
        
           |  |  | 78 |     @method sort
 | 
        
           |  |  | 79 |     @param {Object} [options] Options.
 | 
        
           |  |  | 80 |         @param {Boolean} [options.silent] If `true`, no `sort` events will be
 | 
        
           |  |  | 81 |             fired.
 | 
        
           |  |  | 82 |         @param {Function} [options.sortComparator] Custom comparator function to
 | 
        
           |  |  | 83 |             use. If specified, this will become the new comparator function for
 | 
        
           |  |  | 84 |             each node, overwriting any previous comparator function that was set
 | 
        
           |  |  | 85 |             for the node.
 | 
        
           |  |  | 86 |         @param {Boolean} [options.sortReverse] If `true`, children will be
 | 
        
           |  |  | 87 |             sorted in reverse (descending) order. Otherwise they'll be sorted in
 | 
        
           |  |  | 88 |             ascending order. This will become each node's new sort order,
 | 
        
           |  |  | 89 |             overwriting any previous sort order that was set for the node.
 | 
        
           |  |  | 90 |         @param {String} [options.src] Source of the sort operation. Will be
 | 
        
           |  |  | 91 |             passed along to the `sort` event facade.
 | 
        
           |  |  | 92 |     @chainable
 | 
        
           |  |  | 93 |     **/
 | 
        
           |  |  | 94 |     sort: function (options) {
 | 
        
           |  |  | 95 |         return this.sortNode(this.rootNode, Y.merge(options, {deep: true}));
 | 
        
           |  |  | 96 |     },
 | 
        
           |  |  | 97 |   | 
        
           |  |  | 98 |     /**
 | 
        
           |  |  | 99 |     Default comparator function to use when sorting a node's children if the
 | 
        
           |  |  | 100 |     node itself doesn't have a custom comparator function.
 | 
        
           |  |  | 101 |   | 
        
           |  |  | 102 |     If not specified, insertion order will be used by default.
 | 
        
           |  |  | 103 |   | 
        
           |  |  | 104 |     @method sortComparator
 | 
        
           |  |  | 105 |     @param {Tree.Node} node Node being sorted.
 | 
        
           |  |  | 106 |     @return {Number|String} Value by which the node should be sorted relative to
 | 
        
           |  |  | 107 |         its siblings.
 | 
        
           |  |  | 108 |     **/
 | 
        
           |  |  | 109 |     sortComparator: function (node) {
 | 
        
           |  |  | 110 |         return node.index();
 | 
        
           |  |  | 111 |     },
 | 
        
           |  |  | 112 |   | 
        
           |  |  | 113 |     /**
 | 
        
           |  |  | 114 |     Sorts the children of the specified node.
 | 
        
           |  |  | 115 |   | 
        
           |  |  | 116 |     By default, only the node's direct children are sorted. To sort all nodes in
 | 
        
           |  |  | 117 |     the hierarchy (children, children's children, etc.), set the `deep` option
 | 
        
           |  |  | 118 |     to `true`. If this is a very deep hierarchy, you may also want to set
 | 
        
           |  |  | 119 |     `silent` to true to avoid generating a flood of `sort` events.
 | 
        
           |  |  | 120 |   | 
        
           |  |  | 121 |     @method sortNode
 | 
        
           |  |  | 122 |     @param {Tree.Node} node Node whose children should be sorted.
 | 
        
           |  |  | 123 |     @param {Object} [options] Options.
 | 
        
           |  |  | 124 |         @param {Boolean} [options.deep=false] If `true`, all of this node's
 | 
        
           |  |  | 125 |             children (and their children, and so on) will be traversed and
 | 
        
           |  |  | 126 |             re-sorted as well.
 | 
        
           |  |  | 127 |         @param {Boolean} [options.silent] If `true`, no `sort` event will be
 | 
        
           |  |  | 128 |             fired.
 | 
        
           |  |  | 129 |         @param {Function} [options.sortComparator] Custom comparator function to
 | 
        
           |  |  | 130 |             use. If specified, this will become the node's new comparator
 | 
        
           |  |  | 131 |             function, overwriting any previous comparator function that was set
 | 
        
           |  |  | 132 |             for the node.
 | 
        
           |  |  | 133 |         @param {Boolean} [options.sortReverse] If `true`, children will be
 | 
        
           |  |  | 134 |             sorted in reverse (descending) order. Otherwise they'll be sorted in
 | 
        
           |  |  | 135 |             ascending order. This will become the node's new sort order,
 | 
        
           |  |  | 136 |             overwriting any previous sort order that was set for the node.
 | 
        
           |  |  | 137 |         @param {String} [options.src] Source of the sort operation. Will be
 | 
        
           |  |  | 138 |             passed along to the `sort` event facade.
 | 
        
           |  |  | 139 |     @chainable
 | 
        
           |  |  | 140 |     **/
 | 
        
           |  |  | 141 |     sortNode: function (node, options) {
 | 
        
           |  |  | 142 |         // Nothing to do if the node has no children.
 | 
        
           |  |  | 143 |         if (!node.children.length) {
 | 
        
           |  |  | 144 |             return this;
 | 
        
           |  |  | 145 |         }
 | 
        
           |  |  | 146 |   | 
        
           |  |  | 147 |         options || (options = {});
 | 
        
           |  |  | 148 |   | 
        
           |  |  | 149 |         if (options.deep) {
 | 
        
           |  |  | 150 |             // Unset the `deep` option so we don't cause an infinite loop.
 | 
        
           |  |  | 151 |             options = Y.merge(options, {deep: false});
 | 
        
           |  |  | 152 |   | 
        
           |  |  | 153 |             var self = this;
 | 
        
           |  |  | 154 |   | 
        
           |  |  | 155 |             // Traverse and sort all nodes (including this one).
 | 
        
           |  |  | 156 |             this.traverseNode(node, function (nodeToSort) {
 | 
        
           |  |  | 157 |                 self.sortNode(nodeToSort, options);
 | 
        
           |  |  | 158 |             });
 | 
        
           |  |  | 159 |   | 
        
           |  |  | 160 |             return this;
 | 
        
           |  |  | 161 |         }
 | 
        
           |  |  | 162 |   | 
        
           |  |  | 163 |         var comparator = this._getSortComparator(node, options),
 | 
        
           |  |  | 164 |             reverse;
 | 
        
           |  |  | 165 |   | 
        
           |  |  | 166 |         if ('sortReverse' in options) {
 | 
        
           |  |  | 167 |             reverse = node.sortReverse = options.sortReverse;
 | 
        
           |  |  | 168 |         } else if ('sortReverse' in node) {
 | 
        
           |  |  | 169 |             reverse = node.sortReverse;
 | 
        
           |  |  | 170 |         } else {
 | 
        
           |  |  | 171 |             reverse = this.sortReverse;
 | 
        
           |  |  | 172 |         }
 | 
        
           |  |  | 173 |   | 
        
           |  |  | 174 |         node.children.sort(Y.rbind(this._sort, this, comparator, reverse));
 | 
        
           |  |  | 175 |         node._isIndexStale = true;
 | 
        
           |  |  | 176 |   | 
        
           |  |  | 177 |         if (!options.silent) {
 | 
        
           |  |  | 178 |             this.fire(EVT_SORT, {
 | 
        
           |  |  | 179 |                 node   : node,
 | 
        
           |  |  | 180 |                 reverse: !!reverse,
 | 
        
           |  |  | 181 |                 src    : options.src
 | 
        
           |  |  | 182 |             });
 | 
        
           |  |  | 183 |         }
 | 
        
           |  |  | 184 |   | 
        
           |  |  | 185 |         return this;
 | 
        
           |  |  | 186 |     },
 | 
        
           |  |  | 187 |   | 
        
           |  |  | 188 |     // -- Protected Methods ----------------------------------------------------
 | 
        
           |  |  | 189 |   | 
        
           |  |  | 190 |     /**
 | 
        
           |  |  | 191 |     Compares value _a_ to value _b_ for sorting purposes.
 | 
        
           |  |  | 192 |   | 
        
           |  |  | 193 |     Values are assumed to be the result of calling a sortComparator function.
 | 
        
           |  |  | 194 |   | 
        
           |  |  | 195 |     @method _compare
 | 
        
           |  |  | 196 |     @param {Mixed} a First value to compare.
 | 
        
           |  |  | 197 |     @param {Mixed} b Second value to compare.
 | 
        
           |  |  | 198 |     @return {Number} `-1` if _a_ should come before _b_, `0` if they're
 | 
        
           |  |  | 199 |         equivalent, `1` if _a_ should come after _b_.
 | 
        
           |  |  | 200 |     @protected
 | 
        
           |  |  | 201 |     **/
 | 
        
           |  |  | 202 |     _compare: function (a, b) {
 | 
        
           |  |  | 203 |         return a < b ? -1 : (a > b ? 1 : 0);
 | 
        
           |  |  | 204 |     },
 | 
        
           |  |  | 205 |   | 
        
           |  |  | 206 |     /**
 | 
        
           |  |  | 207 |     Compares value _a_ to value _b_ for sorting purposes, but sorts them in
 | 
        
           |  |  | 208 |     reverse (descending) order.
 | 
        
           |  |  | 209 |   | 
        
           |  |  | 210 |     Values are assumed to be the result of calling a sortComparator function.
 | 
        
           |  |  | 211 |   | 
        
           |  |  | 212 |     @method _compareReverse
 | 
        
           |  |  | 213 |     @param {Mixed} a First value to compare.
 | 
        
           |  |  | 214 |     @param {Mixed} b Second value to compare.
 | 
        
           |  |  | 215 |     @return {Number} `-1` if _a_ should come before _b_, `0` if they're
 | 
        
           |  |  | 216 |         equivalent, `1` if _a_ should come after _b_.
 | 
        
           |  |  | 217 |     @protected
 | 
        
           |  |  | 218 |     **/
 | 
        
           |  |  | 219 |     _compareReverse: function (a, b) {
 | 
        
           |  |  | 220 |         return b < a ? -1 : (b > a ? 1 : 0);
 | 
        
           |  |  | 221 |     },
 | 
        
           |  |  | 222 |   | 
        
           |  |  | 223 |     /**
 | 
        
           |  |  | 224 |     Overrides `Tree#_getDefaultNodeIndex()` to provide insertion-time sorting
 | 
        
           |  |  | 225 |     for nodes inserted without an explicit index.
 | 
        
           |  |  | 226 |   | 
        
           |  |  | 227 |     @method _getDefaultNodeIndex
 | 
        
           |  |  | 228 |     @param {Tree.Node} parent Parent node.
 | 
        
           |  |  | 229 |     @param {Tree.Node} node Node being inserted.
 | 
        
           |  |  | 230 |     @param {Object} [options] Options passed to `insertNode()`.
 | 
        
           |  |  | 231 |     @return {Number} Index at which _node_ should be inserted into _parent_'s
 | 
        
           |  |  | 232 |         `children` array.
 | 
        
           |  |  | 233 |     @protected
 | 
        
           |  |  | 234 |     **/
 | 
        
           |  |  | 235 |     _getDefaultNodeIndex: function (parent, node) {
 | 
        
           |  |  | 236 |         /*jshint bitwise:false */
 | 
        
           |  |  | 237 |   | 
        
           |  |  | 238 |         var children   = parent.children,
 | 
        
           |  |  | 239 |             comparator = this._getSortComparator(parent),
 | 
        
           |  |  | 240 |             max        = children.length,
 | 
        
           |  |  | 241 |             min        = 0,
 | 
        
           |  |  | 242 |             reverse    = 'sortReverse' in parent ? parent.sortReverse : this.sortReverse;
 | 
        
           |  |  | 243 |   | 
        
           |  |  | 244 |         if (!max) {
 | 
        
           |  |  | 245 |             return max;
 | 
        
           |  |  | 246 |         }
 | 
        
           |  |  | 247 |   | 
        
           |  |  | 248 |         // Special case: if the sortComparator is the default sortComparator,
 | 
        
           |  |  | 249 |         // cheat and just return the first or last index of the children array.
 | 
        
           |  |  | 250 |         //
 | 
        
           |  |  | 251 |         // This is necessary because the default sortComparator relies on
 | 
        
           |  |  | 252 |         // the node's index, which is always -1 for uninserted nodes.
 | 
        
           |  |  | 253 |         if (comparator._unboundComparator === Sortable.prototype.sortComparator) {
 | 
        
           |  |  | 254 |             return reverse ? 0 : max;
 | 
        
           |  |  | 255 |         }
 | 
        
           |  |  | 256 |   | 
        
           |  |  | 257 |         var compare = reverse ? this._compareReverse : this._compare,
 | 
        
           |  |  | 258 |             needle  = comparator(node);
 | 
        
           |  |  | 259 |   | 
        
           |  |  | 260 |         // Perform an iterative binary search to determine the correct position
 | 
        
           |  |  | 261 |         // for the node based on the return value of the comparator function.
 | 
        
           |  |  | 262 |         var middle;
 | 
        
           |  |  | 263 |   | 
        
           |  |  | 264 |         while (min < max) {
 | 
        
           |  |  | 265 |             middle = (min + max) >> 1; // Divide by two and discard remainder.
 | 
        
           |  |  | 266 |   | 
        
           |  |  | 267 |             if (compare(comparator(children[middle]), needle) < 0) {
 | 
        
           |  |  | 268 |                 min = middle + 1;
 | 
        
           |  |  | 269 |             } else {
 | 
        
           |  |  | 270 |                 max = middle;
 | 
        
           |  |  | 271 |             }
 | 
        
           |  |  | 272 |         }
 | 
        
           |  |  | 273 |   | 
        
           |  |  | 274 |         return min;
 | 
        
           |  |  | 275 |     },
 | 
        
           |  |  | 276 |   | 
        
           |  |  | 277 |     /**
 | 
        
           |  |  | 278 |     Returns a sort comparator function derived from the given _node_ and
 | 
        
           |  |  | 279 |     _options_, and bound to the correct `thisObj` based on where it was found.
 | 
        
           |  |  | 280 |   | 
        
           |  |  | 281 |     @method _getSortComparator
 | 
        
           |  |  | 282 |     @param {Tree.Node} node Node on which to look for a `sortComparator`
 | 
        
           |  |  | 283 |         function.
 | 
        
           |  |  | 284 |     @param {Object} [options] Options object on which to look for a
 | 
        
           |  |  | 285 |         `sortComparator` function.
 | 
        
           |  |  | 286 |     @return {Function} Properly bound sort comparator function.
 | 
        
           |  |  | 287 |     @protected
 | 
        
           |  |  | 288 |     **/
 | 
        
           |  |  | 289 |     _getSortComparator: function (node, options) {
 | 
        
           |  |  | 290 |         var boundComparator,
 | 
        
           |  |  | 291 |             comparator,
 | 
        
           |  |  | 292 |             thisObj;
 | 
        
           |  |  | 293 |   | 
        
           |  |  | 294 |         if (options && options.sortComparator) {
 | 
        
           |  |  | 295 |             comparator = node.sortComparator = options.sortComparator;
 | 
        
           |  |  | 296 |         } else if (node.sortComparator) {
 | 
        
           |  |  | 297 |             comparator = node.sortComparator;
 | 
        
           |  |  | 298 |             thisObj    = node;
 | 
        
           |  |  | 299 |         } else {
 | 
        
           |  |  | 300 |             comparator = this.sortComparator;
 | 
        
           |  |  | 301 |             thisObj    = this;
 | 
        
           |  |  | 302 |         }
 | 
        
           |  |  | 303 |   | 
        
           |  |  | 304 |         boundComparator = function () {
 | 
        
           |  |  | 305 |             return comparator.apply(thisObj, arguments);
 | 
        
           |  |  | 306 |         };
 | 
        
           |  |  | 307 |   | 
        
           |  |  | 308 |         boundComparator._unboundComparator = comparator;
 | 
        
           |  |  | 309 |   | 
        
           |  |  | 310 |         return boundComparator;
 | 
        
           |  |  | 311 |     },
 | 
        
           |  |  | 312 |   | 
        
           |  |  | 313 |     /**
 | 
        
           |  |  | 314 |     Array sort function used by `sortNode()` to re-sort a node's children.
 | 
        
           |  |  | 315 |   | 
        
           |  |  | 316 |     @method _sort
 | 
        
           |  |  | 317 |     @param {Tree.Node} a First node to compare.
 | 
        
           |  |  | 318 |     @param {Tree.Node} b Second node to compare.
 | 
        
           |  |  | 319 |     @param {Function} comparator Comparator function.
 | 
        
           |  |  | 320 |     @param {Boolean} [reverse=false] If `true`, this will be a reverse
 | 
        
           |  |  | 321 |         (descending) comparison.
 | 
        
           |  |  | 322 |     @return {Number} `-1` if _a_ is less than _b_, `0` if equal, `1` if greater.
 | 
        
           |  |  | 323 |     @protected
 | 
        
           |  |  | 324 |     **/
 | 
        
           |  |  | 325 |     _sort: function (a, b, comparator, reverse) {
 | 
        
           |  |  | 326 |         return this[reverse ? '_compareReverse' : '_compare'](
 | 
        
           |  |  | 327 |             comparator(a), comparator(b));
 | 
        
           |  |  | 328 |     }
 | 
        
           |  |  | 329 | };
 | 
        
           |  |  | 330 |   | 
        
           |  |  | 331 | Y.Tree.Sortable = Sortable;
 | 
        
           |  |  | 332 | /**
 | 
        
           |  |  | 333 | @module tree
 | 
        
           |  |  | 334 | @submodule tree-sortable
 | 
        
           |  |  | 335 | **/
 | 
        
           |  |  | 336 |   | 
        
           |  |  | 337 | /**
 | 
        
           |  |  | 338 | `Tree.Node` extension that adds methods useful for nodes in trees that use the
 | 
        
           |  |  | 339 | `Tree.Sortable` extension.
 | 
        
           |  |  | 340 |   | 
        
           |  |  | 341 | @class Tree.Node.Sortable
 | 
        
           |  |  | 342 | @constructor
 | 
        
           |  |  | 343 | @extensionfor Tree.Node
 | 
        
           |  |  | 344 | **/
 | 
        
           |  |  | 345 |   | 
        
           |  |  | 346 | function NodeSortable() {}
 | 
        
           |  |  | 347 |   | 
        
           |  |  | 348 | NodeSortable.prototype = {
 | 
        
           |  |  | 349 |     /**
 | 
        
           |  |  | 350 |     Sorts this node's children.
 | 
        
           |  |  | 351 |   | 
        
           |  |  | 352 |     @method sort
 | 
        
           |  |  | 353 |     @param {Object} [options] Options.
 | 
        
           |  |  | 354 |         @param {Boolean} [options.silent] If `true`, no `sort` event will be
 | 
        
           |  |  | 355 |             fired.
 | 
        
           |  |  | 356 |         @param {Function} [options.sortComparator] Custom comparator function to
 | 
        
           |  |  | 357 |             use. If specified, this will become the node's new comparator
 | 
        
           |  |  | 358 |             function, overwriting any previous comparator function that was set
 | 
        
           |  |  | 359 |             for the node.
 | 
        
           |  |  | 360 |         @param {Boolean} [options.sortReverse] If `true`, children will be
 | 
        
           |  |  | 361 |             sorted in reverse (descending) order. Otherwise they'll be sorted in
 | 
        
           |  |  | 362 |             ascending order. This will become the node's new sort order,
 | 
        
           |  |  | 363 |             overwriting any previous sort order that was set for the node.
 | 
        
           |  |  | 364 |         @param {String} [options.src] Source of the sort operation. Will be
 | 
        
           |  |  | 365 |             passed along to the `sort` event facade.
 | 
        
           |  |  | 366 |     @chainable
 | 
        
           |  |  | 367 |     **/
 | 
        
           |  |  | 368 |     sort: function (options) {
 | 
        
           |  |  | 369 |         this.tree.sortNode(this, options);
 | 
        
           |  |  | 370 |         return this;
 | 
        
           |  |  | 371 |     }
 | 
        
           |  |  | 372 | };
 | 
        
           |  |  | 373 |   | 
        
           |  |  | 374 | Y.Tree.Node.Sortable = NodeSortable;
 | 
        
           |  |  | 375 |   | 
        
           |  |  | 376 |   | 
        
           |  |  | 377 | }, '3.18.1', {"requires": ["tree"]});
 |