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