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