PluginProbe ʕ •ᴥ•ʔ
Nested Pages / trunk
Nested Pages vtrunk
3.2.14 3.1.8 3.1.9 3.2.0 3.2.1 3.2.10 3.2.11 3.2.12 3.2.13 3.2.2 3.2.3 3.2.4 3.2.5 3.2.6 3.2.7 3.2.8 3.2.9 trunk 1.0 1.1 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 1.1.9 1.2.0 1.2.1 1.3.0 1.3.1 1.3.10 1.3.11 1.3.12 1.3.13 1.3.14 1.3.15 1.3.2 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.3.1 1.6.3.2 1.6.4 1.6.5 1.6.5.1 1.6.5.2 1.6.6 1.6.7 1.6.8 1.7.0 1.7.1 2.0.1 2.0.2 2.0.3 2.0.4 3.0.1 3.0.10 3.0.11 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.10 3.1.11 3.1.12 3.1.13 3.1.14 3.1.15 3.1.16 3.1.17 3.1.18 3.1.19 3.1.2 3.1.20 3.1.21 3.1.22 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7
wp-nested-pages / assets / js / lib / jquery.mjs.nestedSortable.js
wp-nested-pages / assets / js / lib Last commit date
jquery.mjs.nestedSortable.js 4 years ago jquery.ui.touch-punch.min.js 11 years ago nestedpages-factory.js 3 years ago nestedpages.bulk-actions.js 4 years ago nestedpages.check-all.js 9 years ago nestedpages.clone.js 3 years ago nestedpages.confirm-delete.js 8 years ago nestedpages.dropdowns.js 8 years ago nestedpages.formatter.js 3 years ago nestedpages.hidden-item-count.js 9 years ago nestedpages.manual-sync.js 9 years ago nestedpages.menu-links.js 3 years ago nestedpages.menu-search.js 1 year ago nestedpages.menu-toggle.js 8 years ago nestedpages.modals.js 8 years ago nestedpages.move-post.js 8 years ago nestedpages.nesting.js 3 years ago nestedpages.new-post.js 6 years ago nestedpages.page-toggle.js 4 years ago nestedpages.post-search.js 9 years ago nestedpages.quickedit-link.js 8 years ago nestedpages.quickedit-post.js 3 years ago nestedpages.settings-admin-customization.js 6 years ago nestedpages.settings-reset.js 6 years ago nestedpages.settings.js 3 years ago nestedpages.sync-menu-setting.js 8 years ago nestedpages.tabs.js 6 years ago nestedpages.trash-with-children.js 6 years ago nestedpages.trash.js 8 years ago nestedpages.userprefs-reset.js 7 years ago nestedpages.wpml.js 8 years ago
jquery.mjs.nestedSortable.js
913 lines
1 /*
2 * jQuery UI Nested Sortable
3 * v 2.1a / 2016-02-04
4 * https://github.com/ilikenwf/nestedSortable
5 *
6 * Depends on:
7 * jquery.ui.sortable.js 1.10+
8 *
9 * Copyright (c) 2010-2016 Manuele J Sarfatti and contributors
10 * Licensed under the MIT License
11 * http://www.opensource.org/licenses/mit-license.php
12 */
13 (function( factory ) {
14 "use strict";
15
16 if ( typeof define === "function" && define.amd ) {
17
18 // AMD. Register as an anonymous module.
19 define([
20 "jquery",
21 "jquery-ui/ui/sortable"
22 ], factory );
23 } else {
24
25 // Browser globals
26 factory( window.jQuery );
27 }
28 }(function($) {
29 "use strict";
30
31 function isOverAxis( x, reference, size ) {
32 return ( x > reference ) && ( x < ( reference + size ) );
33 }
34
35 $.widget("mjs.nestedSortable", $.extend({}, $.ui.sortable.prototype, {
36
37 options: {
38 disableParentChange: false,
39 doNotClear: false,
40 expandOnHover: 700,
41 isAllowed: function() { return true; },
42 isTree: false,
43 listType: "ol",
44 maxLevels: 0,
45 protectRoot: false,
46 rootID: null,
47 rtl: false,
48 startCollapsed: false,
49 tabSize: 20,
50
51 branchClass: "mjs-nestedSortable-branch",
52 collapsedClass: "mjs-nestedSortable-collapsed",
53 disableNestingClass: "mjs-nestedSortable-no-nesting",
54 errorClass: "mjs-nestedSortable-error",
55 expandedClass: "mjs-nestedSortable-expanded",
56 hoveringClass: "mjs-nestedSortable-hovering",
57 leafClass: "mjs-nestedSortable-leaf",
58 disabledClass: "mjs-nestedSortable-disabled"
59 },
60
61 _create: function() {
62 var self = this,
63 err;
64
65 this.element.data("ui-sortable", this.element.data("mjs-nestedSortable"));
66
67 // mjs - prevent browser from freezing if the HTML is not correct
68 if (!this.element.is(this.options.listType)) {
69 err = "nestedSortable: " +
70 "Please check that the listType option is set to your actual list type";
71
72 throw new Error(err);
73 }
74
75 // if we have a tree with expanding/collapsing functionality,
76 // force 'intersect' tolerance method
77 if (this.options.isTree && this.options.expandOnHover) {
78 this.options.tolerance = "intersect";
79 }
80
81 $.ui.sortable.prototype._create.apply(this, arguments);
82
83 // prepare the tree by applying the right classes
84 // (the CSS is responsible for actual hide/show functionality)
85 if (this.options.isTree) {
86 $(this.items).each(function() {
87 var $li = this.item,
88 hasCollapsedClass = $li.hasClass(self.options.collapsedClass),
89 hasExpandedClass = $li.hasClass(self.options.expandedClass);
90
91 if ($li.children(self.options.listType).length) {
92 $li.addClass(self.options.branchClass);
93 // expand/collapse class only if they have children
94
95 if ( !hasCollapsedClass && !hasExpandedClass ) {
96 if (self.options.startCollapsed) {
97 $li.addClass(self.options.collapsedClass);
98 } else {
99 $li.addClass(self.options.expandedClass);
100 }
101 }
102 } else {
103 $li.addClass(self.options.leafClass);
104 }
105 });
106 }
107 },
108
109 _destroy: function() {
110 this.element
111 .removeData("mjs-nestedSortable")
112 .removeData("ui-sortable");
113 return $.ui.sortable.prototype._destroy.apply(this, arguments);
114 },
115
116 _mouseDrag: function(event) {
117 var i,
118 item,
119 itemElement,
120 intersection,
121 self = this,
122 o = this.options,
123 scrolled = false,
124 $document = $(document),
125 previousTopOffset,
126 parentItem,
127 level,
128 childLevels,
129 itemAfter,
130 itemBefore,
131 newList,
132 method,
133 a,
134 previousItem,
135 nextItem,
136 helperIsNotSibling;
137
138 //Compute the helpers position
139 this.position = this._generatePosition(event);
140 this.positionAbs = this._convertPositionTo("absolute");
141
142 if (!this.lastPositionAbs) {
143 this.lastPositionAbs = this.positionAbs;
144 }
145
146 //Do scrolling
147 if (this.options.scroll) {
148 if (this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {
149
150 if (
151 (
152 this.overflowOffset.top +
153 this.scrollParent[0].offsetHeight
154 ) -
155 event.pageY <
156 o.scrollSensitivity
157 ) {
158 scrolled = this.scrollParent.scrollTop() + o.scrollSpeed;
159 this.scrollParent.scrollTop(scrolled);
160 } else if (
161 event.pageY -
162 this.overflowOffset.top <
163 o.scrollSensitivity
164 ) {
165 scrolled = this.scrollParent.scrollTop() - o.scrollSpeed;
166 this.scrollParent.scrollTop(scrolled);
167 }
168
169 if (
170 (
171 this.overflowOffset.left +
172 this.scrollParent[0].offsetWidth
173 ) -
174 event.pageX <
175 o.scrollSensitivity
176 ) {
177 scrolled = this.scrollParent.scrollLeft() + o.scrollSpeed;
178 this.scrollParent.scrollLeft(scrolled);
179 } else if (
180 event.pageX -
181 this.overflowOffset.left <
182 o.scrollSensitivity
183 ) {
184 scrolled = this.scrollParent.scrollLeft() - o.scrollSpeed;
185 this.scrollParent.scrollLeft(scrolled);
186 }
187
188 } else {
189
190 if (
191 event.pageY -
192 $document.scrollTop() <
193 o.scrollSensitivity
194 ) {
195 scrolled = $document.scrollTop() - o.scrollSpeed;
196 $document.scrollTop(scrolled);
197 } else if (
198 $(window).height() -
199 (
200 event.pageY -
201 $document.scrollTop()
202 ) <
203 o.scrollSensitivity
204 ) {
205 scrolled = $document.scrollTop() + o.scrollSpeed;
206 $document.scrollTop(scrolled);
207 }
208
209 if (
210 event.pageX -
211 $document.scrollLeft() <
212 o.scrollSensitivity
213 ) {
214 scrolled = $document.scrollLeft() - o.scrollSpeed;
215 $document.scrollLeft(scrolled);
216 } else if (
217 $(window).width() -
218 (
219 event.pageX -
220 $document.scrollLeft()
221 ) <
222 o.scrollSensitivity
223 ) {
224 scrolled = $document.scrollLeft() + o.scrollSpeed;
225 $document.scrollLeft(scrolled);
226 }
227
228 }
229
230 if (scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
231 $.ui.ddmanager.prepareOffsets(this, event);
232 }
233 }
234
235 //Regenerate the absolute position used for position checks
236 this.positionAbs = this._convertPositionTo("absolute");
237
238 // mjs - find the top offset before rearrangement,
239 previousTopOffset = this.placeholder.offset().top;
240
241 //Set the helper position
242 if (!this.options.axis || this.options.axis !== "y") {
243 this.helper[0].style.left = this.position.left + "px";
244 }
245 if (!this.options.axis || this.options.axis !== "x") {
246 this.helper[0].style.top = (this.position.top) + "px";
247 }
248
249 // mjs - check and reset hovering state at each cycle
250 this.hovering = this.hovering ? this.hovering : null;
251 this.mouseentered = this.mouseentered ? this.mouseentered : false;
252
253 // mjs - let's start caching some variables
254 (function() {
255 var _parentItem = this.placeholder.parent().parent();
256 if (_parentItem && _parentItem.closest(".ui-sortable").length) {
257 parentItem = _parentItem;
258 }
259 }.call(this));
260
261 level = this._getLevel(this.placeholder);
262 childLevels = this._getChildLevels(this.helper);
263 newList = document.createElement(o.listType);
264
265 // dragDirection object is required by jquery.ui.sortable.js 1.13+
266 this.dragDirection = {
267 vertical: this._getDragVerticalDirection(),
268 horizontal: this._getDragHorizontalDirection()
269 };
270
271 //Rearrange
272 for (i = this.items.length - 1; i >= 0; i--) {
273
274 //Cache variables and intersection, continue if no intersection
275 item = this.items[i];
276 itemElement = item.item[0];
277 intersection = this._intersectsWithPointer(item);
278 if (!intersection) {
279 continue;
280 }
281
282 // Only put the placeholder inside the current Container, skip all
283 // items form other containers. This works because when moving
284 // an item from one container to another the
285 // currentContainer is switched before the placeholder is moved.
286 //
287 // Without this moving items in "sub-sortables" can cause the placeholder to jitter
288 // beetween the outer and inner container.
289 if (item.instance !== this.currentContainer) {
290 continue;
291 }
292
293 // No action if intersected item is disabled
294 // and the element above or below in the direction we're going is also disabled
295 if (itemElement.className.indexOf(o.disabledClass) !== -1) {
296 // Note: intersection hardcoded direction values from
297 // jquery.ui.sortable.js:_intersectsWithPointer
298 if (intersection === 2) {
299 // Going down
300 itemAfter = this.items[i + 1];
301 if (itemAfter && itemAfter.item.hasClass(o.disabledClass)) {
302 continue;
303 }
304
305 } else if (intersection === 1) {
306 // Going up
307 itemBefore = this.items[i - 1];
308 if (itemBefore && itemBefore.item.hasClass(o.disabledClass)) {
309 continue;
310 }
311 }
312 }
313
314 method = intersection === 1 ? "next" : "prev";
315
316 // cannot intersect with itself
317 // no useless actions that have been done before
318 // no action if the item moved is the parent of the item checked
319 if (itemElement !== this.currentItem[0] &&
320 this.placeholder[method]()[0] !== itemElement &&
321 !$.contains(this.placeholder[0], itemElement) &&
322 (
323 this.options.type === "semi-dynamic" ?
324 !$.contains(this.element[0], itemElement) :
325 true
326 )
327 ) {
328
329 // mjs - we are intersecting an element:
330 // trigger the mouseenter event and store this state
331 if (!this.mouseentered) {
332 $(itemElement).mouseenter();
333 this.mouseentered = true;
334 }
335
336 // mjs - if the element has children and they are hidden,
337 // show them after a delay (CSS responsible)
338 if (o.isTree && $(itemElement).hasClass(o.collapsedClass) && o.expandOnHover) {
339 if (!this.hovering) {
340 $(itemElement).addClass(o.hoveringClass);
341 this.hovering = window.setTimeout(function() {
342 $(itemElement)
343 .removeClass(o.collapsedClass)
344 .addClass(o.expandedClass);
345
346 self.refreshPositions();
347 self._trigger("expand", event, [self._uiHash(), itemElement]);
348 }, o.expandOnHover);
349 }
350 }
351
352 this.direction = intersection === 1 ? "down" : "up";
353
354 // mjs - rearrange the elements and reset timeouts and hovering state
355 if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) {
356 $(itemElement).mouseleave();
357 this.mouseentered = false;
358 $(itemElement).removeClass(o.hoveringClass);
359 if (this.hovering) {
360 window.clearTimeout(this.hovering);
361 }
362 this.hovering = null;
363
364 // mjs - do not switch container if
365 // it's a root item and 'protectRoot' is true
366 // or if it's not a root item but we are trying to make it root
367 if (o.protectRoot &&
368 !(
369 this.currentItem[0].parentNode === this.element[0] &&
370 // it's a root item
371 itemElement.parentNode !== this.element[0]
372 // it's intersecting a non-root item
373 )
374 ) {
375 if (this.currentItem[0].parentNode !== this.element[0] &&
376 itemElement.parentNode === this.element[0]
377 ) {
378
379 if ( !$(itemElement).children(o.listType).length) {
380 itemElement.appendChild(newList);
381 if (o.isTree) {
382 $(itemElement)
383 .removeClass(o.leafClass)
384 .addClass(o.branchClass + " " + o.expandedClass);
385 }
386 }
387
388 if (this.direction === "down") {
389 a = $(itemElement).prev().children(o.listType);
390 } else {
391 a = $(itemElement).children(o.listType);
392 }
393
394 if (a[0] !== undefined) {
395 this._rearrange(event, null, a);
396 }
397
398 } else {
399 this._rearrange(event, item);
400 }
401 } else if (!o.protectRoot) {
402 this._rearrange(event, item);
403 }
404 } else {
405 break;
406 }
407
408 // Clear emtpy ul's/ol's
409 this._clearEmpty(itemElement);
410
411 this._trigger("change", event, this._uiHash());
412 break;
413 }
414 }
415
416 // mjs - to find the previous sibling in the list,
417 // keep backtracking until we hit a valid list item.
418 (function() {
419 var _previousItem = this.placeholder.prev();
420 if (_previousItem.length) {
421 previousItem = _previousItem;
422 } else {
423 previousItem = null;
424 }
425 }.call(this));
426
427 if (previousItem != null) {
428 while (
429 previousItem[0].nodeName.toLowerCase() !== "li" ||
430 previousItem[0].className.indexOf(o.disabledClass) !== -1 ||
431 previousItem[0] === this.currentItem[0] ||
432 previousItem[0] === this.helper[0]
433 ) {
434 if (previousItem[0].previousSibling) {
435 previousItem = $(previousItem[0].previousSibling);
436 } else {
437 previousItem = null;
438 break;
439 }
440 }
441 }
442
443 // mjs - to find the next sibling in the list,
444 // keep stepping forward until we hit a valid list item.
445 (function() {
446 var _nextItem = this.placeholder.next();
447 if (_nextItem.length) {
448 nextItem = _nextItem;
449 } else {
450 nextItem = null;
451 }
452 }.call(this));
453
454 if (nextItem != null) {
455 while (
456 nextItem[0].nodeName.toLowerCase() !== "li" ||
457 nextItem[0].className.indexOf(o.disabledClass) !== -1 ||
458 nextItem[0] === this.currentItem[0] ||
459 nextItem[0] === this.helper[0]
460 ) {
461 if (nextItem[0].nextSibling) {
462 nextItem = $(nextItem[0].nextSibling);
463 } else {
464 nextItem = null;
465 break;
466 }
467 }
468 }
469
470 this.beyondMaxLevels = 0;
471
472 // mjs - if the item is moved to the left, send it one level up
473 // but only if it's at the bottom of the list
474 if (parentItem != null &&
475 nextItem == null &&
476 !(o.protectRoot && parentItem[0].parentNode == this.element[0]) &&
477 (
478 o.rtl &&
479 (
480 this.positionAbs.left +
481 this.helper.outerWidth() > parentItem.offset().left +
482 parentItem.outerWidth()
483 ) ||
484 !o.rtl && (this.positionAbs.left < parentItem.offset().left)
485 )
486 ) {
487
488 parentItem.after(this.placeholder[0]);
489 helperIsNotSibling = !parentItem
490 .children(o.listItem)
491 .children("li:visible:not(.ui-sortable-helper)")
492 .length;
493 if (o.isTree && helperIsNotSibling) {
494 parentItem
495 .removeClass(this.options.branchClass + " " + this.options.expandedClass)
496 .addClass(this.options.leafClass);
497 }
498 if(typeof parentItem !== 'undefined')
499 this._clearEmpty(parentItem[0]);
500 this._trigger("change", event, this._uiHash());
501 // mjs - if the item is below a sibling and is moved to the right,
502 // make it a child of that sibling
503 } else if (previousItem != null &&
504 !previousItem.hasClass(o.disableNestingClass) &&
505 (
506 previousItem.children(o.listType).length &&
507 previousItem.children(o.listType).is(":visible") ||
508 !previousItem.children(o.listType).length
509 ) &&
510 !(o.protectRoot && this.currentItem[0].parentNode === this.element[0]) &&
511 (
512 o.rtl &&
513 (
514 this.positionAbs.left +
515 this.helper.outerWidth() <
516 previousItem.offset().left +
517 previousItem.outerWidth() -
518 o.tabSize
519 ) ||
520 !o.rtl &&
521 (this.positionAbs.left > previousItem.offset().left + o.tabSize)
522 )
523 ) {
524
525 this._isAllowed(previousItem, level, level + childLevels + 1);
526
527 if (!previousItem.children(o.listType).length) {
528 previousItem[0].appendChild(newList);
529 if (o.isTree) {
530 previousItem
531 .removeClass(o.leafClass)
532 .addClass(o.branchClass + " " + o.expandedClass);
533 }
534 }
535
536 // mjs - if this item is being moved from the top, add it to the top of the list.
537 if (previousTopOffset && (previousTopOffset <= previousItem.offset().top)) {
538 previousItem.children(o.listType).prepend(this.placeholder);
539 } else {
540 // mjs - otherwise, add it to the bottom of the list.
541 previousItem.children(o.listType)[0].appendChild(this.placeholder[0]);
542 }
543 if(typeof parentItem !== 'undefined')
544 this._clearEmpty(parentItem[0]);
545 this._trigger("change", event, this._uiHash());
546 } else {
547 this._isAllowed(parentItem, level, level + childLevels);
548 }
549
550 //Post events to containers
551 this._contactContainers(event);
552
553 //Interconnect with droppables
554 if ($.ui.ddmanager) {
555 $.ui.ddmanager.drag(this, event);
556 }
557
558 //Call callbacks
559 this._trigger("sort", event, this._uiHash());
560
561 this.lastPositionAbs = this.positionAbs;
562 return false;
563
564 },
565
566 _mouseStop: function(event) {
567 // mjs - if the item is in a position not allowed, send it back
568 if (this.beyondMaxLevels) {
569
570 this.placeholder.removeClass(this.options.errorClass);
571
572 if (this.domPosition.prev) {
573 $(this.domPosition.prev).after(this.placeholder);
574 } else {
575 $(this.domPosition.parent).prepend(this.placeholder);
576 }
577
578 this._trigger("revert", event, this._uiHash());
579
580 }
581
582 // mjs - clear the hovering timeout, just to be sure
583 $("." + this.options.hoveringClass)
584 .mouseleave()
585 .removeClass(this.options.hoveringClass);
586
587 this.mouseentered = false;
588 if (this.hovering) {
589 window.clearTimeout(this.hovering);
590 }
591 this.hovering = null;
592
593 this._relocate_event = event;
594 this._pid_current = $(this.domPosition.parent).parent().attr("id");
595 this._sort_current = this.domPosition.prev ? $(this.domPosition.prev).next().index() : 0;
596 $.ui.sortable.prototype._mouseStop.apply(this, arguments); //asybnchronous execution, @see _clear for the relocate event.
597 },
598
599 // mjs - this function is slightly modified
600 // to make it easier to hover over a collapsed element and have it expand
601 _intersectsWithSides: function(item) {
602
603 var half = this.options.isTree ? .8 : .5,
604 isOverBottomHalf = isOverAxis(
605 this.positionAbs.top + this.offset.click.top,
606 item.top + (item.height * half),
607 item.height
608 ),
609 isOverTopHalf = isOverAxis(
610 this.positionAbs.top + this.offset.click.top,
611 item.top - (item.height * half),
612 item.height
613 ),
614 isOverRightHalf = isOverAxis(
615 this.positionAbs.left + this.offset.click.left,
616 item.left + (item.width / 2),
617 item.width
618 ),
619 verticalDirection = this._getDragVerticalDirection(),
620 horizontalDirection = this._getDragHorizontalDirection();
621
622 if (this.floating && horizontalDirection) {
623 return (
624 (horizontalDirection === "right" && isOverRightHalf) ||
625 (horizontalDirection === "left" && !isOverRightHalf)
626 );
627 } else {
628 return verticalDirection && (
629 (verticalDirection === "down" && isOverBottomHalf) ||
630 (verticalDirection === "up" && isOverTopHalf)
631 );
632 }
633
634 },
635
636 _contactContainers: function() {
637
638 if (this.options.protectRoot && this.currentItem[0].parentNode === this.element[0] ) {
639 return;
640 }
641
642 $.ui.sortable.prototype._contactContainers.apply(this, arguments);
643
644 },
645
646 _clear: function() {
647 var i,
648 item;
649
650 $.ui.sortable.prototype._clear.apply(this, arguments);
651
652 //relocate event
653 if (!(this._pid_current === this._uiHash().item.parent().parent().attr("id") &&
654 this._sort_current === this._uiHash().item.index())) {
655 this._trigger("relocate", this._relocate_event, this._uiHash());
656 }
657
658 // mjs - clean last empty ul/ol
659 for (i = this.items.length - 1; i >= 0; i--) {
660 item = this.items[i].item[0];
661 this._clearEmpty(item);
662 }
663
664 },
665
666 serialize: function(options) {
667
668 var o = $.extend({}, this.options, options),
669 items = this._getItemsAsjQuery(o && o.connected),
670 str = [];
671
672 $(items).each(function() {
673 var res = ($(o.item || this).attr(o.attribute || "id") || "")
674 .match(o.expression || (/(.+)[-=_](.+)/)),
675 pid = ($(o.item || this).parent(o.listType)
676 .parent(o.items)
677 .attr(o.attribute || "id") || "")
678 .match(o.expression || (/(.+)[-=_](.+)/));
679
680 if (res) {
681 str.push(
682 (
683 (o.key || res[1]) +
684 "[" +
685 (o.key && o.expression ? res[1] : res[2]) + "]"
686 ) +
687 "=" +
688 (pid ? (o.key && o.expression ? pid[1] : pid[2]) : o.rootID));
689 }
690 });
691
692 if (!str.length && o.key) {
693 str.push(o.key + "=");
694 }
695
696 return str.join("&");
697
698 },
699
700 toHierarchy: function(options) {
701
702 var o = $.extend({}, this.options, options),
703 ret = [];
704
705 $(this.element).children(o.items).each(function() {
706 var level = _recursiveItems(this);
707 ret.push(level);
708 });
709
710 return ret;
711
712 function _recursiveItems(item) {
713 var id = ($(item).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[-=_](.+)/)),
714 currentItem;
715
716 var data = $(item).data();
717 if (data.nestedSortableItem) {
718 delete data.nestedSortableItem; // Remove the nestedSortableItem object from the data
719 }
720
721 if (id) {
722 currentItem = {
723 "id": id[2]
724 };
725
726 currentItem = $.extend({}, currentItem, data); // Combine the two objects
727
728 if ($(item).children(o.listType).children(o.items).length > 0) {
729 currentItem.children = [];
730 $(item).children(o.listType).children(o.items).each(function() {
731 var level = _recursiveItems(this);
732 currentItem.children.push(level);
733 });
734 }
735 return currentItem;
736 }
737 }
738 },
739
740 toArray: function(options) {
741
742 var o = $.extend({}, this.options, options),
743 sDepth = o.startDepthCount || 0,
744 ret = [],
745 left = 1;
746
747 if (!o.excludeRoot) {
748 ret.push({
749 "item_id": o.rootID,
750 "parent_id": null,
751 "depth": sDepth,
752 "left": left,
753 "right": ($(o.items, this.element).length + 1) * 2
754 });
755 left++;
756 }
757
758 $(this.element).children(o.items).each(function() {
759 left = _recursiveArray(this, sDepth, left);
760 });
761
762 ret = ret.sort(function(a, b) { return (a.left - b.left); });
763
764 return ret;
765
766 function _recursiveArray(item, depth, _left) {
767
768 var right = _left + 1,
769 id,
770 pid,
771 parentItem;
772
773 if ($(item).children(o.listType).children(o.items).length > 0) {
774 depth++;
775 $(item).children(o.listType).children(o.items).each(function() {
776 right = _recursiveArray($(this), depth, right);
777 });
778 depth--;
779 }
780
781 id = ($(item).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[-=_](.+)/));
782
783 if (depth === sDepth) {
784 pid = o.rootID;
785 } else {
786 parentItem = ($(item).parent(o.listType)
787 .parent(o.items)
788 .attr(o.attribute || "id"))
789 .match(o.expression || (/(.+)[-=_](.+)/));
790 pid = parentItem[2];
791 }
792
793 if (id) {
794 var data = $(item).children('div').data();
795 var itemObj = $.extend( data, {
796 "id":id[2],
797 "parent_id":pid,
798 "depth":depth,
799 "left":_left,
800 "right":right
801 } );
802 ret.push( itemObj );
803 }
804
805 _left = right + 1;
806 return _left;
807 }
808
809 },
810
811 _clearEmpty: function (item) {
812 function replaceClass(elem, search, replace, swap) {
813 if (swap) {
814 search = [replace, replace = search][0];
815 }
816
817 $(elem).removeClass(search).addClass(replace);
818 }
819
820 var o = this.options,
821 childrenList = $(item).children(o.listType),
822 hasChildren = childrenList.has('li').length;
823
824 var doNotClear =
825 o.doNotClear ||
826 hasChildren ||
827 o.protectRoot && $(item)[0] === this.element[0];
828
829 if (o.isTree) {
830 replaceClass(item, o.branchClass, o.leafClass, doNotClear);
831 }
832
833 if (!doNotClear) {
834 childrenList.parent().removeClass(o.expandedClass);
835 childrenList.remove();
836 }
837 },
838
839 _getLevel: function(item) {
840
841 var level = 1,
842 list;
843
844 if (this.options.listType) {
845 list = item.closest(this.options.listType);
846 while (list && list.length > 0 && !list.is(".ui-sortable")) {
847 level++;
848 list = list.parent().closest(this.options.listType);
849 }
850 }
851
852 return level;
853 },
854
855 _getChildLevels: function(parent, depth) {
856 var self = this,
857 o = this.options,
858 result = 0;
859 depth = depth || 0;
860
861 $(parent).children(o.listType).children(o.items).each(function(index, child) {
862 result = Math.max(self._getChildLevels(child, depth + 1), result);
863 });
864
865 return depth ? result + 1 : result;
866 },
867
868 _isAllowed: function(parentItem, level, levels) {
869 var o = this.options,
870 // this takes into account the maxLevels set to the recipient list
871 maxLevels = this
872 .placeholder
873 .closest(".ui-sortable")
874 .nestedSortable("option", "maxLevels"),
875
876 // Check if the parent has changed to prevent it, when o.disableParentChange is true
877 oldParent = this.currentItem.parent().parent(),
878 disabledByParentchange = o.disableParentChange && (
879 //From somewhere to somewhere else, except the root
880 typeof parentItem !== 'undefined' && !oldParent.is(parentItem) ||
881 typeof parentItem === 'undefined' && oldParent.is("li") //From somewhere to the root
882 );
883 // mjs - is the root protected?
884 // mjs - are we nesting too deep?
885 if (
886 disabledByParentchange ||
887 !o.isAllowed(this.placeholder, parentItem, this.currentItem)
888 ) {
889 this.placeholder.addClass(o.errorClass);
890 if (maxLevels < levels && maxLevels !== 0) {
891 this.beyondMaxLevels = levels - maxLevels;
892 } else {
893 this.beyondMaxLevels = 1;
894 }
895 } else {
896 if (maxLevels < levels && maxLevels !== 0) {
897 this.placeholder.addClass(o.errorClass);
898 this.beyondMaxLevels = levels - maxLevels;
899 } else {
900 this.placeholder.removeClass(o.errorClass);
901 this.beyondMaxLevels = 0;
902 }
903 }
904 }
905
906 }));
907
908 $.mjs.nestedSortable.prototype.options = $.extend(
909 {},
910 $.ui.sortable.prototype.options,
911 $.mjs.nestedSortable.prototype.options
912 );
913 }));