kendo.sortable.js 22.6 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425
/** 
 * Kendo UI v2016.1.112 (http://www.telerik.com/kendo-ui)                                                                                                                                               
 * Copyright 2016 Telerik AD. All rights reserved.                                                                                                                                                      
 *                                                                                                                                                                                                      
 * Kendo UI commercial licenses may be obtained at                                                                                                                                                      
 * http://www.telerik.com/purchase/license-agreement/kendo-ui-complete                                                                                                                                  
 * If you do not own a commercial license, this file shall be governed by the trial license terms.                                                                                                      
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       
                                                                                                                                                                                                       

*/
(function (f, define) {
    define('kendo.sortable', ['kendo.draganddrop'], f);
}(function () {
    var __meta__ = {
        id: 'sortable',
        name: 'Sortable',
        category: 'framework',
        depends: ['draganddrop']
    };
    (function ($, undefined) {
        var kendo = window.kendo, Widget = kendo.ui.Widget, START = 'start', BEFORE_MOVE = 'beforeMove', MOVE = 'move', END = 'end', CHANGE = 'change', CANCEL = 'cancel', ACTION_SORT = 'sort', ACTION_REMOVE = 'remove', ACTION_RECEIVE = 'receive', DEFAULT_FILTER = '>*', MISSING_INDEX = -1;
        function containsOrEqualTo(parent, child) {
            try {
                return $.contains(parent, child) || parent == child;
            } catch (e) {
                return false;
            }
        }
        function defaultHint(element) {
            return element.clone();
        }
        function defaultPlaceholder(element) {
            return element.clone().removeAttr('id').css('visibility', 'hidden');
        }
        var Sortable = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                if (!that.options.placeholder) {
                    that.options.placeholder = defaultPlaceholder;
                }
                if (!that.options.hint) {
                    that.options.hint = defaultHint;
                }
                that.draggable = that._createDraggable();
            },
            events: [
                START,
                BEFORE_MOVE,
                MOVE,
                END,
                CHANGE,
                CANCEL
            ],
            options: {
                name: 'Sortable',
                hint: null,
                placeholder: null,
                filter: DEFAULT_FILTER,
                holdToDrag: false,
                disabled: null,
                container: null,
                connectWith: null,
                handler: null,
                cursorOffset: null,
                axis: null,
                ignore: null,
                autoScroll: false,
                cursor: 'auto',
                moveOnDragEnter: false
            },
            destroy: function () {
                this.draggable.destroy();
                Widget.fn.destroy.call(this);
            },
            _createDraggable: function () {
                var that = this, element = that.element, options = that.options;
                return new kendo.ui.Draggable(element, {
                    filter: options.filter,
                    hint: kendo.isFunction(options.hint) ? options.hint : $(options.hint),
                    holdToDrag: options.holdToDrag,
                    container: options.container ? $(options.container) : null,
                    cursorOffset: options.cursorOffset,
                    axis: options.axis,
                    ignore: options.ignore,
                    autoScroll: options.autoScroll,
                    dragstart: $.proxy(that._dragstart, that),
                    dragcancel: $.proxy(that._dragcancel, that),
                    drag: $.proxy(that._drag, that),
                    dragend: $.proxy(that._dragend, that)
                });
            },
            _dragstart: function (e) {
                var draggedElement = this.draggedElement = e.currentTarget, disabled = this.options.disabled, handler = this.options.handler, _placeholder = this.options.placeholder, placeholder = this.placeholder = kendo.isFunction(_placeholder) ? $(_placeholder.call(this, draggedElement)) : $(_placeholder);
                if (disabled && draggedElement.is(disabled)) {
                    e.preventDefault();
                } else if (handler && !$(e.initialTarget).is(handler)) {
                    e.preventDefault();
                } else {
                    if (this.trigger(START, {
                            item: draggedElement,
                            draggableEvent: e
                        })) {
                        e.preventDefault();
                    } else {
                        draggedElement.css('display', 'none');
                        draggedElement.before(placeholder);
                        this._setCursor();
                    }
                }
            },
            _dragcancel: function () {
                this._cancel();
                this.trigger(CANCEL, { item: this.draggedElement });
                this._resetCursor();
            },
            _drag: function (e) {
                var draggedElement = this.draggedElement, target = this._findTarget(e), targetCenter, cursorOffset = {
                        left: e.x.location,
                        top: e.y.location
                    }, offsetDelta, axisDelta = {
                        x: e.x.delta,
                        y: e.y.delta
                    }, direction, sibling, getSibling, axis = this.options.axis, moveOnDragEnter = this.options.moveOnDragEnter, eventData = {
                        item: draggedElement,
                        list: this,
                        draggableEvent: e
                    };
                if (axis === 'x' || axis === 'y') {
                    this._movementByAxis(axis, cursorOffset, axisDelta[axis], eventData);
                    return;
                }
                if (target) {
                    targetCenter = this._getElementCenter(target.element);
                    offsetDelta = {
                        left: Math.round(cursorOffset.left - targetCenter.left),
                        top: Math.round(cursorOffset.top - targetCenter.top)
                    };
                    $.extend(eventData, { target: target.element });
                    if (target.appendToBottom) {
                        this._movePlaceholder(target, null, eventData);
                        return;
                    }
                    if (target.appendAfterHidden) {
                        this._movePlaceholder(target, 'next', eventData);
                    }
                    if (this._isFloating(target.element)) {
                        if (axisDelta.x < 0 && (moveOnDragEnter || offsetDelta.left < 0)) {
                            direction = 'prev';
                        } else if (axisDelta.x > 0 && (moveOnDragEnter || offsetDelta.left > 0)) {
                            direction = 'next';
                        }
                    } else {
                        if (axisDelta.y < 0 && (moveOnDragEnter || offsetDelta.top < 0)) {
                            direction = 'prev';
                        } else if (axisDelta.y > 0 && (moveOnDragEnter || offsetDelta.top > 0)) {
                            direction = 'next';
                        }
                    }
                    if (direction) {
                        getSibling = direction === 'prev' ? jQuery.fn.prev : jQuery.fn.next;
                        sibling = getSibling.call(target.element);
                        while (sibling.length && !sibling.is(':visible')) {
                            sibling = getSibling.call(sibling);
                        }
                        if (sibling[0] != this.placeholder[0]) {
                            this._movePlaceholder(target, direction, eventData);
                        }
                    }
                }
            },
            _dragend: function (e) {
                var placeholder = this.placeholder, draggedElement = this.draggedElement, draggedIndex = this.indexOf(draggedElement), placeholderIndex = this.indexOf(placeholder), connectWith = this.options.connectWith, connectedList, isDefaultPrevented, eventData, connectedListEventData;
                this._resetCursor();
                eventData = {
                    action: ACTION_SORT,
                    item: draggedElement,
                    oldIndex: draggedIndex,
                    newIndex: placeholderIndex,
                    draggableEvent: e
                };
                if (placeholderIndex >= 0) {
                    isDefaultPrevented = this.trigger(END, eventData);
                } else {
                    connectedList = placeholder.parents(connectWith).getKendoSortable();
                    eventData.action = ACTION_REMOVE;
                    connectedListEventData = $.extend({}, eventData, {
                        action: ACTION_RECEIVE,
                        oldIndex: MISSING_INDEX,
                        newIndex: connectedList.indexOf(placeholder)
                    });
                    isDefaultPrevented = !(!this.trigger(END, eventData) && !connectedList.trigger(END, connectedListEventData));
                }
                if (isDefaultPrevented || placeholderIndex === draggedIndex) {
                    this._cancel();
                    return;
                }
                placeholder.replaceWith(draggedElement);
                draggedElement.show();
                this.draggable.dropped = true;
                eventData = {
                    action: this.indexOf(draggedElement) != MISSING_INDEX ? ACTION_SORT : ACTION_REMOVE,
                    item: draggedElement,
                    oldIndex: draggedIndex,
                    newIndex: this.indexOf(draggedElement),
                    draggableEvent: e
                };
                this.trigger(CHANGE, eventData);
                if (connectedList) {
                    connectedListEventData = $.extend({}, eventData, {
                        action: ACTION_RECEIVE,
                        oldIndex: MISSING_INDEX,
                        newIndex: connectedList.indexOf(draggedElement)
                    });
                    connectedList.trigger(CHANGE, connectedListEventData);
                }
            },
            _findTarget: function (e) {
                var element = this._findElementUnderCursor(e), items, connectWith = this.options.connectWith, node;
                if ($.contains(this.element[0], element)) {
                    items = this.items();
                    node = items.filter(element)[0] || items.has(element)[0];
                    return node ? {
                        element: $(node),
                        sortable: this
                    } : null;
                } else if (this.element[0] == element && this._isEmpty()) {
                    return {
                        element: this.element,
                        sortable: this,
                        appendToBottom: true
                    };
                } else if (this.element[0] == element && this._isLastHidden()) {
                    node = this.items().eq(0);
                    return {
                        element: node,
                        sortable: this,
                        appendAfterHidden: true
                    };
                } else if (connectWith) {
                    return this._searchConnectedTargets(element, e);
                }
            },
            _findElementUnderCursor: function (e) {
                var elementUnderCursor = kendo.elementUnderCursor(e), draggable = e.sender;
                if (containsOrEqualTo(draggable.hint[0], elementUnderCursor)) {
                    draggable.hint.hide();
                    elementUnderCursor = kendo.elementUnderCursor(e);
                    if (!elementUnderCursor) {
                        elementUnderCursor = kendo.elementUnderCursor(e);
                    }
                    draggable.hint.show();
                }
                return elementUnderCursor;
            },
            _searchConnectedTargets: function (element, e) {
                var connected = $(this.options.connectWith), sortableInstance, items, node;
                for (var i = 0; i < connected.length; i++) {
                    sortableInstance = connected.eq(i).getKendoSortable();
                    if ($.contains(connected[i], element)) {
                        if (sortableInstance) {
                            items = sortableInstance.items();
                            node = items.filter(element)[0] || items.has(element)[0];
                            if (node) {
                                sortableInstance.placeholder = this.placeholder;
                                return {
                                    element: $(node),
                                    sortable: sortableInstance
                                };
                            } else {
                                return null;
                            }
                        }
                    } else if (connected[i] == element) {
                        if (sortableInstance && sortableInstance._isEmpty()) {
                            return {
                                element: connected.eq(i),
                                sortable: sortableInstance,
                                appendToBottom: true
                            };
                        } else if (this._isCursorAfterLast(sortableInstance, e)) {
                            node = sortableInstance.items().last();
                            return {
                                element: node,
                                sortable: sortableInstance
                            };
                        }
                    }
                }
            },
            _isCursorAfterLast: function (sortable, e) {
                var lastItem = sortable.items().last(), cursorOffset = {
                        left: e.x.location,
                        top: e.y.location
                    }, lastItemOffset, delta;
                lastItemOffset = kendo.getOffset(lastItem);
                lastItemOffset.top += lastItem.outerHeight();
                lastItemOffset.left += lastItem.outerWidth();
                if (this._isFloating(lastItem)) {
                    delta = lastItemOffset.left - cursorOffset.left;
                } else {
                    delta = lastItemOffset.top - cursorOffset.top;
                }
                return delta < 0 ? true : false;
            },
            _movementByAxis: function (axis, cursorOffset, delta, eventData) {
                var cursorPosition = axis === 'x' ? cursorOffset.left : cursorOffset.top, target = delta < 0 ? this.placeholder.prev() : this.placeholder.next(), targetCenter;
                if (target.length && !target.is(':visible')) {
                    target = delta < 0 ? target.prev() : target.next();
                }
                $.extend(eventData, { target: target });
                targetCenter = this._getElementCenter(target);
                if (targetCenter) {
                    targetCenter = axis === 'x' ? targetCenter.left : targetCenter.top;
                }
                if (target.length && delta < 0 && cursorPosition - targetCenter < 0) {
                    this._movePlaceholder({
                        element: target,
                        sortable: this
                    }, 'prev', eventData);
                } else if (target.length && delta > 0 && cursorPosition - targetCenter > 0) {
                    this._movePlaceholder({
                        element: target,
                        sortable: this
                    }, 'next', eventData);
                }
            },
            _movePlaceholder: function (target, direction, eventData) {
                var placeholder = this.placeholder;
                if (!target.sortable.trigger(BEFORE_MOVE, eventData)) {
                    if (!direction) {
                        target.element.append(placeholder);
                    } else if (direction === 'prev') {
                        target.element.before(placeholder);
                    } else if (direction === 'next') {
                        target.element.after(placeholder);
                    }
                    target.sortable.trigger(MOVE, eventData);
                }
            },
            _setCursor: function () {
                var cursor = this.options.cursor, body;
                if (cursor && cursor !== 'auto') {
                    body = $(document.body);
                    this._originalCursorType = body.css('cursor');
                    body.css({ 'cursor': cursor });
                    if (!this._cursorStylesheet) {
                        this._cursorStylesheet = $('<style>* { cursor: ' + cursor + ' !important; }</style>');
                    }
                    this._cursorStylesheet.appendTo(body);
                }
            },
            _resetCursor: function () {
                if (this._originalCursorType) {
                    $(document.body).css('cursor', this._originalCursorType);
                    this._originalCursorType = null;
                    this._cursorStylesheet.remove();
                }
            },
            _getElementCenter: function (element) {
                var center = element.length ? kendo.getOffset(element) : null;
                if (center) {
                    center.top += element.outerHeight() / 2;
                    center.left += element.outerWidth() / 2;
                }
                return center;
            },
            _isFloating: function (item) {
                return /left|right/.test(item.css('float')) || /inline|table-cell/.test(item.css('display'));
            },
            _cancel: function () {
                this.draggedElement.show();
                this.placeholder.remove();
            },
            _items: function () {
                var filter = this.options.filter, items;
                if (filter) {
                    items = this.element.find(filter);
                } else {
                    items = this.element.children();
                }
                return items;
            },
            indexOf: function (element) {
                var items = this._items(), placeholder = this.placeholder, draggedElement = this.draggedElement;
                if (placeholder && element[0] == placeholder[0]) {
                    return items.not(draggedElement).index(element);
                } else {
                    return items.not(placeholder).index(element);
                }
            },
            items: function () {
                var placeholder = this.placeholder, items = this._items();
                if (placeholder) {
                    items = items.not(placeholder);
                }
                return items;
            },
            _isEmpty: function () {
                return !this.items().length;
            },
            _isLastHidden: function () {
                return this.items().length === 1 && this.items().is(':hidden');
            }
        });
        kendo.ui.plugin(Sortable);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));