00001
00008 (function (factory) {
00009 "use strict";
00010
00011 if (typeof define === "function" && define.amd) {
00012 define(factory);
00013 }
00014 else if (typeof module != "undefined" && typeof module.exports != "undefined") {
00015 module.exports = factory();
00016 }
00017 else if (typeof Package !== "undefined") {
00018 Sortable = factory();
00019 }
00020 else {
00021
00022 window["Sortable"] = factory();
00023 }
00024 })(function () {
00025 "use strict";
00026
00027 var dragEl,
00028 parentEl,
00029 ghostEl,
00030 cloneEl,
00031 rootEl,
00032 nextEl,
00033
00034 scrollEl,
00035 scrollParentEl,
00036
00037 lastEl,
00038 lastCSS,
00039 lastParentCSS,
00040
00041 oldIndex,
00042 newIndex,
00043
00044 activeGroup,
00045 autoScroll = {},
00046
00047 tapEvt,
00048 touchEvt,
00049
00050 moved,
00051
00053 RSPACE = /\s+/g,
00054
00055 expando = 'Sortable' + (new Date).getTime(),
00056
00057 win = window,
00058 document = win.document,
00059 parseInt = win.parseInt,
00060
00061 supportDraggable = !!('draggable' in document.createElement('div')),
00062 supportCssPointerEvents = (function (el) {
00063 el = document.createElement('x');
00064 el.style.cssText = 'pointer-events:auto';
00065 return el.style.pointerEvents === 'auto';
00066 })(),
00067
00068 _silent = false,
00069
00070 abs = Math.abs,
00071 slice = [].slice,
00072
00073 touchDragOverListeners = [],
00074
00075 _autoScroll = _throttle(function (evt, options, rootEl) {
00076
00077 if (rootEl && options.scroll) {
00078 var el,
00079 rect,
00080 sens = options.scrollSensitivity,
00081 speed = options.scrollSpeed,
00082
00083 x = evt.clientX,
00084 y = evt.clientY,
00085
00086 winWidth = window.innerWidth,
00087 winHeight = window.innerHeight,
00088
00089 vx,
00090 vy
00091 ;
00092
00093
00094 if (scrollParentEl !== rootEl) {
00095 scrollEl = options.scroll;
00096 scrollParentEl = rootEl;
00097
00098 if (scrollEl === true) {
00099 scrollEl = rootEl;
00100
00101 do {
00102 if ((scrollEl.offsetWidth < scrollEl.scrollWidth) ||
00103 (scrollEl.offsetHeight < scrollEl.scrollHeight)
00104 ) {
00105 break;
00106 }
00107
00108 } while (scrollEl = scrollEl.parentNode);
00109 }
00110 }
00111
00112 if (scrollEl) {
00113 el = scrollEl;
00114 rect = scrollEl.getBoundingClientRect();
00115 vx = (abs(rect.right - x) <= sens) - (abs(rect.left - x) <= sens);
00116 vy = (abs(rect.bottom - y) <= sens) - (abs(rect.top - y) <= sens);
00117 }
00118
00119
00120 if (!(vx || vy)) {
00121 vx = (winWidth - x <= sens) - (x <= sens);
00122 vy = (winHeight - y <= sens) - (y <= sens);
00123
00124
00125 (vx || vy) && (el = win);
00126 }
00127
00128
00129 if (autoScroll.vx !== vx || autoScroll.vy !== vy || autoScroll.el !== el) {
00130 autoScroll.el = el;
00131 autoScroll.vx = vx;
00132 autoScroll.vy = vy;
00133
00134 clearInterval(autoScroll.pid);
00135
00136 if (el) {
00137 autoScroll.pid = setInterval(function () {
00138 if (el === win) {
00139 win.scrollTo(win.pageXOffset + vx * speed, win.pageYOffset + vy * speed);
00140 } else {
00141 vy && (el.scrollTop += vy * speed);
00142 vx && (el.scrollLeft += vx * speed);
00143 }
00144 }, 24);
00145 }
00146 }
00147 }
00148 }, 30),
00149
00150 _prepareGroup = function (options) {
00151 var group = options.group;
00152
00153 if (!group || typeof group != 'object') {
00154 group = options.group = {name: group};
00155 }
00156
00157 ['pull', 'put'].forEach(function (key) {
00158 if (!(key in group)) {
00159 group[key] = true;
00160 }
00161 });
00162
00163 options.groups = ' ' + group.name + (group.put.join ? ' ' + group.put.join(' ') : '') + ' ';
00164 }
00165 ;
00166
00167
00168
00174 function Sortable(el, options) {
00175 if (!(el && el.nodeType && el.nodeType === 1)) {
00176 throw 'Sortable: `el` must be HTMLElement, and not ' + {}.toString.call(el);
00177 }
00178
00179 this.el = el;
00180 this.options = options = _extend({}, options);
00181
00182
00183
00184 el[expando] = this;
00185
00186
00187
00188 var defaults = {
00189 group: Math.random(),
00190 sort: true,
00191 disabled: false,
00192 store: null,
00193 handle: null,
00194 scroll: true,
00195 scrollSensitivity: 30,
00196 scrollSpeed: 10,
00197 draggable: /[uo]l/i.test(el.nodeName) ? 'li' : '>*',
00198 ghostClass: 'sortable-ghost',
00199 chosenClass: 'sortable-chosen',
00200 ignore: 'a, img',
00201 filter: null,
00202 animation: 0,
00203 setData: function (dataTransfer, dragEl) {
00204 dataTransfer.setData('Text', dragEl.textContent);
00205 },
00206 dropBubble: false,
00207 dragoverBubble: false,
00208 dataIdAttr: 'data-id',
00209 delay: 0,
00210 forceFallback: false,
00211 fallbackClass: 'sortable-fallback',
00212 fallbackOnBody: false
00213 };
00214
00215
00216
00217 for (var name in defaults) {
00218 !(name in options) && (options[name] = defaults[name]);
00219 }
00220
00221 _prepareGroup(options);
00222
00223
00224 for (var fn in this) {
00225 if (fn.charAt(0) === '_') {
00226 this[fn] = this[fn].bind(this);
00227 }
00228 }
00229
00230
00231 this.nativeDraggable = options.forceFallback ? false : supportDraggable;
00232
00233
00234 _on(el, 'mousedown', this._onTapStart);
00235 _on(el, 'touchstart', this._onTapStart);
00236
00237 if (this.nativeDraggable) {
00238 _on(el, 'dragover', this);
00239 _on(el, 'dragenter', this);
00240 }
00241
00242 touchDragOverListeners.push(this._onDragOver);
00243
00244
00245 options.store && this.sort(options.store.get(this));
00246 }
00247
00248
00249 Sortable.prototype = {
00250 constructor: Sortable,
00251
00252 _onTapStart: function (evt) {
00253 var _this = this,
00254 el = this.el,
00255 options = this.options,
00256 type = evt.type,
00257 touch = evt.touches && evt.touches[0],
00258 target = (touch || evt).target,
00259 originalTarget = target,
00260 filter = options.filter;
00261
00262
00263 if (type === 'mousedown' && evt.button !== 0 || options.disabled) {
00264 return;
00265 }
00266
00267 target = _closest(target, options.draggable, el);
00268
00269 if (!target) {
00270 return;
00271 }
00272
00273
00274 oldIndex = _index(target);
00275
00276
00277 if (typeof filter === 'function') {
00278 if (filter.call(this, evt, target, this)) {
00279 _dispatchEvent(_this, originalTarget, 'filter', target, el, oldIndex);
00280 evt.preventDefault();
00281 return;
00282 }
00283 }
00284 else if (filter) {
00285 filter = filter.split(',').some(function (criteria) {
00286 criteria = _closest(originalTarget, criteria.trim(), el);
00287
00288 if (criteria) {
00289 _dispatchEvent(_this, criteria, 'filter', target, el, oldIndex);
00290 return true;
00291 }
00292 });
00293
00294 if (filter) {
00295 evt.preventDefault();
00296 return;
00297 }
00298 }
00299
00300
00301 if (options.handle && !_closest(originalTarget, options.handle, el)) {
00302 return;
00303 }
00304
00305
00306
00307 this._prepareDragStart(evt, touch, target);
00308 },
00309
00310 _prepareDragStart: function (evt, touch, target) {
00311 var _this = this,
00312 el = _this.el,
00313 options = _this.options,
00314 ownerDocument = el.ownerDocument,
00315 dragStartFn;
00316
00317 if (target && !dragEl && (target.parentNode === el)) {
00318 tapEvt = evt;
00319
00320 rootEl = el;
00321 dragEl = target;
00322 parentEl = dragEl.parentNode;
00323 nextEl = dragEl.nextSibling;
00324 activeGroup = options.group;
00325
00326 dragStartFn = function () {
00327
00328
00329 _this._disableDelayedDrag();
00330
00331
00332 dragEl.draggable = true;
00333
00334
00335 _toggleClass(dragEl, _this.options.chosenClass, true);
00336
00337
00338 _this._triggerDragStart(touch);
00339 };
00340
00341
00342 options.ignore.split(',').forEach(function (criteria) {
00343 _find(dragEl, criteria.trim(), _disableDraggable);
00344 });
00345
00346 _on(ownerDocument, 'mouseup', _this._onDrop);
00347 _on(ownerDocument, 'touchend', _this._onDrop);
00348 _on(ownerDocument, 'touchcancel', _this._onDrop);
00349
00350 if (options.delay) {
00351
00352
00353
00354 _on(ownerDocument, 'mouseup', _this._disableDelayedDrag);
00355 _on(ownerDocument, 'touchend', _this._disableDelayedDrag);
00356 _on(ownerDocument, 'touchcancel', _this._disableDelayedDrag);
00357 _on(ownerDocument, 'mousemove', _this._disableDelayedDrag);
00358 _on(ownerDocument, 'touchmove', _this._disableDelayedDrag);
00359
00360 _this._dragStartTimer = setTimeout(dragStartFn, options.delay);
00361 } else {
00362 dragStartFn();
00363 }
00364 }
00365 },
00366
00367 _disableDelayedDrag: function () {
00368 var ownerDocument = this.el.ownerDocument;
00369
00370 clearTimeout(this._dragStartTimer);
00371 _off(ownerDocument, 'mouseup', this._disableDelayedDrag);
00372 _off(ownerDocument, 'touchend', this._disableDelayedDrag);
00373 _off(ownerDocument, 'touchcancel', this._disableDelayedDrag);
00374 _off(ownerDocument, 'mousemove', this._disableDelayedDrag);
00375 _off(ownerDocument, 'touchmove', this._disableDelayedDrag);
00376 },
00377
00378 _triggerDragStart: function (touch) {
00379 if (touch) {
00380
00381 tapEvt = {
00382 target: dragEl,
00383 clientX: touch.clientX,
00384 clientY: touch.clientY
00385 };
00386
00387 this._onDragStart(tapEvt, 'touch');
00388 }
00389 else if (!this.nativeDraggable) {
00390 this._onDragStart(tapEvt, true);
00391 }
00392 else {
00393 _on(dragEl, 'dragend', this);
00394 _on(rootEl, 'dragstart', this._onDragStart);
00395 }
00396
00397 try {
00398 if (document.selection) {
00399 document.selection.empty();
00400 } else {
00401 window.getSelection().removeAllRanges();
00402 }
00403 } catch (err) {
00404 }
00405 },
00406
00407 _dragStarted: function () {
00408 if (rootEl && dragEl) {
00409
00410 _toggleClass(dragEl, this.options.ghostClass, true);
00411
00412 Sortable.active = this;
00413
00414
00415 _dispatchEvent(this, rootEl, 'start', dragEl, rootEl, oldIndex);
00416 }
00417 },
00418
00419 _emulateDragOver: function () {
00420 if (touchEvt) {
00421 if (this._lastX === touchEvt.clientX && this._lastY === touchEvt.clientY) {
00422 return;
00423 }
00424
00425 this._lastX = touchEvt.clientX;
00426 this._lastY = touchEvt.clientY;
00427
00428 if (!supportCssPointerEvents) {
00429 _css(ghostEl, 'display', 'none');
00430 }
00431
00432 var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY),
00433 parent = target,
00434 groupName = ' ' + this.options.group.name + '',
00435 i = touchDragOverListeners.length;
00436
00437 if (parent) {
00438 do {
00439 if (parent[expando] && parent[expando].options.groups.indexOf(groupName) > -1) {
00440 while (i--) {
00441 touchDragOverListeners[i]({
00442 clientX: touchEvt.clientX,
00443 clientY: touchEvt.clientY,
00444 target: target,
00445 rootEl: parent
00446 });
00447 }
00448
00449 break;
00450 }
00451
00452 target = parent;
00453 }
00454
00455 while (parent = parent.parentNode);
00456 }
00457
00458 if (!supportCssPointerEvents) {
00459 _css(ghostEl, 'display', '');
00460 }
00461 }
00462 },
00463
00464
00465 _onTouchMove: function (evt) {
00466 if (tapEvt) {
00467
00468 if (!Sortable.active) {
00469 this._dragStarted();
00470 }
00471
00472
00473 this._appendGhost();
00474
00475 var touch = evt.touches ? evt.touches[0] : evt,
00476 dx = touch.clientX - tapEvt.clientX,
00477 dy = touch.clientY - tapEvt.clientY,
00478 translate3d = evt.touches ? 'translate3d(' + dx + 'px,' + dy + 'px,0)' : 'translate(' + dx + 'px,' + dy + 'px)';
00479
00480 moved = true;
00481 touchEvt = touch;
00482
00483 _css(ghostEl, 'webkitTransform', translate3d);
00484 _css(ghostEl, 'mozTransform', translate3d);
00485 _css(ghostEl, 'msTransform', translate3d);
00486 _css(ghostEl, 'transform', translate3d);
00487
00488 evt.preventDefault();
00489 }
00490 },
00491
00492 _appendGhost: function () {
00493 if (!ghostEl) {
00494 var rect = dragEl.getBoundingClientRect(),
00495 css = _css(dragEl),
00496 options = this.options,
00497 ghostRect;
00498
00499 ghostEl = dragEl.cloneNode(true);
00500
00501 _toggleClass(ghostEl, options.ghostClass, false);
00502 _toggleClass(ghostEl, options.fallbackClass, true);
00503
00504 _css(ghostEl, 'top', rect.top - parseInt(css.marginTop, 10));
00505 _css(ghostEl, 'left', rect.left - parseInt(css.marginLeft, 10));
00506 _css(ghostEl, 'width', rect.width);
00507 _css(ghostEl, 'height', rect.height);
00508 _css(ghostEl, 'opacity', '0.8');
00509 _css(ghostEl, 'position', 'fixed');
00510 _css(ghostEl, 'zIndex', '100000');
00511 _css(ghostEl, 'pointerEvents', 'none');
00512
00513 options.fallbackOnBody && document.body.appendChild(ghostEl) || rootEl.appendChild(ghostEl);
00514
00515
00516 ghostRect = ghostEl.getBoundingClientRect();
00517 _css(ghostEl, 'width', rect.width * 2 - ghostRect.width);
00518 _css(ghostEl, 'height', rect.height * 2 - ghostRect.height);
00519 }
00520 },
00521
00522 _onDragStart: function (evt, useFallback) {
00523 var dataTransfer = evt.dataTransfer,
00524 options = this.options;
00525
00526 this._offUpEvents();
00527
00528 if (activeGroup.pull == 'clone') {
00529 cloneEl = dragEl.cloneNode(true);
00530 _css(cloneEl, 'display', 'none');
00531 rootEl.insertBefore(cloneEl, dragEl);
00532 }
00533
00534 if (useFallback) {
00535
00536 if (useFallback === 'touch') {
00537
00538 _on(document, 'touchmove', this._onTouchMove);
00539 _on(document, 'touchend', this._onDrop);
00540 _on(document, 'touchcancel', this._onDrop);
00541 } else {
00542
00543 _on(document, 'mousemove', this._onTouchMove);
00544 _on(document, 'mouseup', this._onDrop);
00545 }
00546
00547 this._loopId = setInterval(this._emulateDragOver, 50);
00548 }
00549 else {
00550 if (dataTransfer) {
00551 dataTransfer.effectAllowed = 'move';
00552 options.setData && options.setData.call(this, dataTransfer, dragEl);
00553 }
00554
00555 _on(document, 'drop', this);
00556 setTimeout(this._dragStarted, 0);
00557 }
00558 },
00559
00560 _onDragOver: function (evt) {
00561 var el = this.el,
00562 target,
00563 dragRect,
00564 revert,
00565 options = this.options,
00566 group = options.group,
00567 groupPut = group.put,
00568 isOwner = (activeGroup === group),
00569 canSort = options.sort;
00570
00571 if (evt.preventDefault !== void 0) {
00572 evt.preventDefault();
00573 !options.dragoverBubble && evt.stopPropagation();
00574 }
00575
00576 moved = true;
00577
00578 if (activeGroup && !options.disabled &&
00579 (isOwner
00580 ? canSort || (revert = !rootEl.contains(dragEl))
00581 : activeGroup.pull && groupPut && (
00582 (activeGroup.name === group.name) ||
00583 (groupPut.indexOf && ~groupPut.indexOf(activeGroup.name))
00584 )
00585 ) &&
00586 (evt.rootEl === void 0 || evt.rootEl === this.el)
00587 ) {
00588
00589 _autoScroll(evt, options, this.el);
00590
00591 if (_silent) {
00592 return;
00593 }
00594
00595 target = _closest(evt.target, options.draggable, el);
00596 dragRect = dragEl.getBoundingClientRect();
00597
00598 if (revert) {
00599 _cloneHide(true);
00600
00601 if (cloneEl || nextEl) {
00602 rootEl.insertBefore(dragEl, cloneEl || nextEl);
00603 }
00604 else if (!canSort) {
00605 rootEl.appendChild(dragEl);
00606 }
00607
00608 return;
00609 }
00610
00611
00612 if ((el.children.length === 0) || (el.children[0] === ghostEl) ||
00613 (el === evt.target) && (target = _ghostIsLast(el, evt))
00614 ) {
00615
00616 if (target) {
00617 if (target.animated) {
00618 return;
00619 }
00620
00621 targetRect = target.getBoundingClientRect();
00622 }
00623
00624 _cloneHide(isOwner);
00625
00626 if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect) !== false) {
00627 if (!dragEl.contains(el)) {
00628 el.appendChild(dragEl);
00629 parentEl = el;
00630 }
00631
00632 this._animate(dragRect, dragEl);
00633 target && this._animate(targetRect, target);
00634 }
00635 }
00636 else if (target && !target.animated && target !== dragEl && (target.parentNode[expando] !== void 0)) {
00637 if (lastEl !== target) {
00638 lastEl = target;
00639 lastCSS = _css(target);
00640 lastParentCSS = _css(target.parentNode);
00641 }
00642
00643
00644 var targetRect = target.getBoundingClientRect(),
00645 width = targetRect.right - targetRect.left,
00646 height = targetRect.bottom - targetRect.top,
00647 floating = /left|right|inline/.test(lastCSS.cssFloat + lastCSS.display)
00648 || (lastParentCSS.display == 'flex' && lastParentCSS['flex-direction'].indexOf('row') === 0),
00649 isWide = (target.offsetWidth > dragEl.offsetWidth),
00650 isLong = (target.offsetHeight > dragEl.offsetHeight),
00651 halfway = (floating ? (evt.clientX - targetRect.left) / width : (evt.clientY - targetRect.top) / height) > 0.5,
00652 nextSibling = target.nextElementSibling,
00653 moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect),
00654 after
00655 ;
00656
00657 if (moveVector !== false) {
00658 _silent = true;
00659 setTimeout(_unsilent, 30);
00660
00661 _cloneHide(isOwner);
00662
00663 if (moveVector === 1 || moveVector === -1) {
00664 after = (moveVector === 1);
00665 }
00666 else if (floating) {
00667 var elTop = dragEl.offsetTop,
00668 tgTop = target.offsetTop;
00669
00670 if (elTop === tgTop) {
00671 after = (target.previousElementSibling === dragEl) && !isWide || halfway && isWide;
00672 } else {
00673 after = tgTop > elTop;
00674 }
00675 } else {
00676 after = (nextSibling !== dragEl) && !isLong || halfway && isLong;
00677 }
00678
00679 if (!dragEl.contains(el)) {
00680 if (after && !nextSibling) {
00681 el.appendChild(dragEl);
00682 } else {
00683 target.parentNode.insertBefore(dragEl, after ? nextSibling : target);
00684 }
00685 }
00686
00687 parentEl = dragEl.parentNode;
00688
00689 this._animate(dragRect, dragEl);
00690 this._animate(targetRect, target);
00691 }
00692 }
00693 }
00694 },
00695
00696 _animate: function (prevRect, target) {
00697 var ms = this.options.animation;
00698
00699 if (ms) {
00700 var currentRect = target.getBoundingClientRect();
00701
00702 _css(target, 'transition', 'none');
00703 _css(target, 'transform', 'translate3d('
00704 + (prevRect.left - currentRect.left) + 'px,'
00705 + (prevRect.top - currentRect.top) + 'px,0)'
00706 );
00707
00708 target.offsetWidth;
00709
00710 _css(target, 'transition', 'all ' + ms + 'ms');
00711 _css(target, 'transform', 'translate3d(0,0,0)');
00712
00713 clearTimeout(target.animated);
00714 target.animated = setTimeout(function () {
00715 _css(target, 'transition', '');
00716 _css(target, 'transform', '');
00717 target.animated = false;
00718 }, ms);
00719 }
00720 },
00721
00722 _offUpEvents: function () {
00723 var ownerDocument = this.el.ownerDocument;
00724
00725 _off(document, 'touchmove', this._onTouchMove);
00726 _off(ownerDocument, 'mouseup', this._onDrop);
00727 _off(ownerDocument, 'touchend', this._onDrop);
00728 _off(ownerDocument, 'touchcancel', this._onDrop);
00729 },
00730
00731 _onDrop: function (evt) {
00732 var el = this.el,
00733 options = this.options;
00734
00735 clearInterval(this._loopId);
00736 clearInterval(autoScroll.pid);
00737 clearTimeout(this._dragStartTimer);
00738
00739
00740 _off(document, 'mousemove', this._onTouchMove);
00741
00742 if (this.nativeDraggable) {
00743 _off(document, 'drop', this);
00744 _off(el, 'dragstart', this._onDragStart);
00745 }
00746
00747 this._offUpEvents();
00748
00749 if (evt) {
00750 if (moved) {
00751 evt.preventDefault();
00752 !options.dropBubble && evt.stopPropagation();
00753 }
00754
00755 ghostEl && ghostEl.parentNode.removeChild(ghostEl);
00756
00757 if (dragEl) {
00758 if (this.nativeDraggable) {
00759 _off(dragEl, 'dragend', this);
00760 }
00761
00762 _disableDraggable(dragEl);
00763
00764
00765 _toggleClass(dragEl, this.options.ghostClass, false);
00766 _toggleClass(dragEl, this.options.chosenClass, false);
00767
00768 if (rootEl !== parentEl) {
00769 newIndex = _index(dragEl);
00770
00771 if (newIndex >= 0) {
00772
00773 _dispatchEvent(null, parentEl, 'sort', dragEl, rootEl, oldIndex, newIndex);
00774 _dispatchEvent(this, rootEl, 'sort', dragEl, rootEl, oldIndex, newIndex);
00775
00776
00777 _dispatchEvent(null, parentEl, 'add', dragEl, rootEl, oldIndex, newIndex);
00778
00779
00780 _dispatchEvent(this, rootEl, 'remove', dragEl, rootEl, oldIndex, newIndex);
00781 }
00782 }
00783 else {
00784
00785 cloneEl && cloneEl.parentNode.removeChild(cloneEl);
00786
00787 if (dragEl.nextSibling !== nextEl) {
00788
00789 newIndex = _index(dragEl);
00790
00791 if (newIndex >= 0) {
00792
00793 _dispatchEvent(this, rootEl, 'update', dragEl, rootEl, oldIndex, newIndex);
00794 _dispatchEvent(this, rootEl, 'sort', dragEl, rootEl, oldIndex, newIndex);
00795 }
00796 }
00797 }
00798
00799 if (Sortable.active) {
00800 if (newIndex === null || newIndex === -1) {
00801 newIndex = oldIndex;
00802 }
00803
00804 _dispatchEvent(this, rootEl, 'end', dragEl, rootEl, oldIndex, newIndex);
00805
00806
00807 this.save();
00808 }
00809 }
00810
00811
00812 rootEl =
00813 dragEl =
00814 parentEl =
00815 ghostEl =
00816 nextEl =
00817 cloneEl =
00818
00819 scrollEl =
00820 scrollParentEl =
00821
00822 tapEvt =
00823 touchEvt =
00824
00825 moved =
00826 newIndex =
00827
00828 lastEl =
00829 lastCSS =
00830
00831 activeGroup =
00832 Sortable.active = null;
00833 }
00834 },
00835
00836
00837 handleEvent: function (evt) {
00838 var type = evt.type;
00839
00840 if (type === 'dragover' || type === 'dragenter') {
00841 if (dragEl) {
00842 this._onDragOver(evt);
00843 _globalDragOver(evt);
00844 }
00845 }
00846 else if (type === 'drop' || type === 'dragend') {
00847 this._onDrop(evt);
00848 }
00849 },
00850
00851
00856 toArray: function () {
00857 var order = [],
00858 el,
00859 children = this.el.children,
00860 i = 0,
00861 n = children.length,
00862 options = this.options;
00863
00864 for (; i < n; i++) {
00865 el = children[i];
00866 if (_closest(el, options.draggable, this.el)) {
00867 order.push(el.getAttribute(options.dataIdAttr) || _generateId(el));
00868 }
00869 }
00870
00871 return order;
00872 },
00873
00874
00879 sort: function (order) {
00880 var items = {}, rootEl = this.el;
00881
00882 this.toArray().forEach(function (id, i) {
00883 var el = rootEl.children[i];
00884
00885 if (_closest(el, this.options.draggable, rootEl)) {
00886 items[id] = el;
00887 }
00888 }, this);
00889
00890 order.forEach(function (id) {
00891 if (items[id]) {
00892 rootEl.removeChild(items[id]);
00893 rootEl.appendChild(items[id]);
00894 }
00895 });
00896 },
00897
00898
00902 save: function () {
00903 var store = this.options.store;
00904 store && store.set(this);
00905 },
00906
00907
00914 closest: function (el, selector) {
00915 return _closest(el, selector || this.options.draggable, this.el);
00916 },
00917
00918
00925 option: function (name, value) {
00926 var options = this.options;
00927
00928 if (value === void 0) {
00929 return options[name];
00930 } else {
00931 options[name] = value;
00932
00933 if (name === 'group') {
00934 _prepareGroup(options);
00935 }
00936 }
00937 },
00938
00939
00943 destroy: function () {
00944 var el = this.el;
00945
00946 el[expando] = null;
00947
00948 _off(el, 'mousedown', this._onTapStart);
00949 _off(el, 'touchstart', this._onTapStart);
00950
00951 if (this.nativeDraggable) {
00952 _off(el, 'dragover', this);
00953 _off(el, 'dragenter', this);
00954 }
00955
00956
00957 Array.prototype.forEach.call(el.querySelectorAll('[draggable]'), function (el) {
00958 el.removeAttribute('draggable');
00959 });
00960
00961 touchDragOverListeners.splice(touchDragOverListeners.indexOf(this._onDragOver), 1);
00962
00963 this._onDrop();
00964
00965 this.el = el = null;
00966 }
00967 };
00968
00969
00970 function _cloneHide(state) {
00971 if (cloneEl && (cloneEl.state !== state)) {
00972 _css(cloneEl, 'display', state ? 'none' : '');
00973 !state && cloneEl.state && rootEl.insertBefore(cloneEl, dragEl);
00974 cloneEl.state = state;
00975 }
00976 }
00977
00978
00979 function _closest(el, selector, ctx) {
00980 if (el) {
00981 ctx = ctx || document;
00982 selector = selector.split('.');
00983
00984 var tag = selector.shift().toUpperCase(),
00985 re = new RegExp('\\s(' + selector.join('|') + ')(?=\\s)', 'g');
00986
00987 do {
00988 if (
00989 (tag === '>*' && el.parentNode === ctx) || (
00990 (tag === '' || el.nodeName.toUpperCase() == tag) &&
00991 (!selector.length || ((' ' + el.className + ' ').match(re) || []).length == selector.length)
00992 )
00993 ) {
00994 return el;
00995 }
00996 }
00997 while (el !== ctx && (el = el.parentNode));
00998 }
00999
01000 return null;
01001 }
01002
01003
01004 function _globalDragOver(evt) {
01005 if (evt.dataTransfer) {
01006 evt.dataTransfer.dropEffect = 'move';
01007 }
01008 evt.preventDefault();
01009 }
01010
01011
01012 function _on(el, event, fn) {
01013 el.addEventListener(event, fn, false);
01014 }
01015
01016
01017 function _off(el, event, fn) {
01018 el.removeEventListener(event, fn, false);
01019 }
01020
01021
01022 function _toggleClass(el, name, state) {
01023 if (el) {
01024 if (el.classList) {
01025 el.classList[state ? 'add' : 'remove'](name);
01026 }
01027 else {
01028 var className = (' ' + el.className + ' ').replace(RSPACE, ' ').replace(' ' + name + ' ', ' ');
01029 el.className = (className + (state ? ' ' + name : '')).replace(RSPACE, ' ');
01030 }
01031 }
01032 }
01033
01034
01035 function _css(el, prop, val) {
01036 var style = el && el.style;
01037
01038 if (style) {
01039 if (val === void 0) {
01040 if (document.defaultView && document.defaultView.getComputedStyle) {
01041 val = document.defaultView.getComputedStyle(el, '');
01042 }
01043 else if (el.currentStyle) {
01044 val = el.currentStyle;
01045 }
01046
01047 return prop === void 0 ? val : val[prop];
01048 }
01049 else {
01050 if (!(prop in style)) {
01051 prop = '-webkit-' + prop;
01052 }
01053
01054 style[prop] = val + (typeof val === 'string' ? '' : 'px');
01055 }
01056 }
01057 }
01058
01059
01060 function _find(ctx, tagName, iterator) {
01061 if (ctx) {
01062 var list = ctx.getElementsByTagName(tagName), i = 0, n = list.length;
01063
01064 if (iterator) {
01065 for (; i < n; i++) {
01066 iterator(list[i], i);
01067 }
01068 }
01069
01070 return list;
01071 }
01072
01073 return [];
01074 }
01075
01076
01077
01078 function _dispatchEvent(sortable, rootEl, name, targetEl, fromEl, startIndex, newIndex) {
01079 var evt = document.createEvent('Event'),
01080 options = (sortable || rootEl[expando]).options,
01081 onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1);
01082
01083 evt.initEvent(name, true, true);
01084
01085 evt.to = rootEl;
01086 evt.from = fromEl || rootEl;
01087 evt.item = targetEl || rootEl;
01088 evt.clone = cloneEl;
01089
01090 evt.oldIndex = startIndex;
01091 evt.newIndex = newIndex;
01092
01093 rootEl.dispatchEvent(evt);
01094
01095 if (options[onName]) {
01096 options[onName].call(sortable, evt);
01097 }
01098 }
01099
01100
01101 function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect) {
01102 var evt,
01103 sortable = fromEl[expando],
01104 onMoveFn = sortable.options.onMove,
01105 retVal;
01106
01107 evt = document.createEvent('Event');
01108 evt.initEvent('move', true, true);
01109
01110 evt.to = toEl;
01111 evt.from = fromEl;
01112 evt.dragged = dragEl;
01113 evt.draggedRect = dragRect;
01114 evt.related = targetEl || toEl;
01115 evt.relatedRect = targetRect || toEl.getBoundingClientRect();
01116
01117 fromEl.dispatchEvent(evt);
01118
01119 if (onMoveFn) {
01120 retVal = onMoveFn.call(sortable, evt);
01121 }
01122
01123 return retVal;
01124 }
01125
01126
01127 function _disableDraggable(el) {
01128 el.draggable = false;
01129 }
01130
01131
01132 function _unsilent() {
01133 _silent = false;
01134 }
01135
01136
01138 function _ghostIsLast(el, evt) {
01139 var lastEl = el.lastElementChild,
01140 rect = lastEl.getBoundingClientRect();
01141
01142 return ((evt.clientY - (rect.top + rect.height) > 5) || (evt.clientX - (rect.right + rect.width) > 5)) && lastEl;
01143 }
01144
01145
01152 function _generateId(el) {
01153 var str = el.tagName + el.className + el.src + el.href + el.textContent,
01154 i = str.length,
01155 sum = 0;
01156
01157 while (i--) {
01158 sum += str.charCodeAt(i);
01159 }
01160
01161 return sum.toString(36);
01162 }
01163
01169 function _index(el) {
01170 var index = 0;
01171
01172 if (!el || !el.parentNode) {
01173 return -1;
01174 }
01175
01176 while (el && (el = el.previousElementSibling)) {
01177 if (el.nodeName.toUpperCase() !== 'TEMPLATE') {
01178 index++;
01179 }
01180 }
01181
01182 return index;
01183 }
01184
01185 function _throttle(callback, ms) {
01186 var args, _this;
01187
01188 return function () {
01189 if (args === void 0) {
01190 args = arguments;
01191 _this = this;
01192
01193 setTimeout(function () {
01194 if (args.length === 1) {
01195 callback.call(_this, args[0]);
01196 } else {
01197 callback.apply(_this, args);
01198 }
01199
01200 args = void 0;
01201 }, ms);
01202 }
01203 };
01204 }
01205
01206 function _extend(dst, src) {
01207 if (dst && src) {
01208 for (var key in src) {
01209 if (src.hasOwnProperty(key)) {
01210 dst[key] = src[key];
01211 }
01212 }
01213 }
01214
01215 return dst;
01216 }
01217
01218
01219
01220 Sortable.utils = {
01221 on: _on,
01222 off: _off,
01223 css: _css,
01224 find: _find,
01225 is: function (el, selector) {
01226 return !!_closest(el, selector, el);
01227 },
01228 extend: _extend,
01229 throttle: _throttle,
01230 closest: _closest,
01231 toggleClass: _toggleClass,
01232 index: _index
01233 };
01234
01235
01241 Sortable.create = function (el, options) {
01242 return new Sortable(el, options);
01243 };
01244
01245
01246
01247 Sortable.version = '1.4.2';
01248 return Sortable;
01249 });