diff --git a/Sortable.js b/Sortable.js index 2a565763a..12708b158 100644 --- a/Sortable.js +++ b/Sortable.js @@ -246,6 +246,8 @@ ghostClass: 'sortable-ghost', chosenClass: 'sortable-chosen', dragClass: 'sortable-drag', + validGroupClass: 'sortable-valid', + invalidGroupClass: 'sortable-invalid', ignore: 'a, img', filter: null, animation: 0, @@ -288,9 +290,10 @@ if (this.nativeDraggable) { _on(el, 'dragover', this); _on(el, 'dragenter', this); + _on(el, 'dragleave', this); } - touchDragOverListeners.push(this._onDragOver); + touchDragOverListeners.push(this._onDragOver, this._onDragLeave); // Restore sorting options.store && this.sort(options.store.get(this)); @@ -666,6 +669,9 @@ ) && (evt.rootEl === void 0 || evt.rootEl === this.el) // touch fallback ) { + _toggleClass(el, options.invalidGroupClass, false); + _toggleClass(el, options.validGroupClass, true); + // Smart auto-scrolling _autoScroll(evt, options, this.el); @@ -776,6 +782,20 @@ } } } + else { + _toggleClass(el, options.validGroupClass, false); + _toggleClass(el, options.invalidGroupClass, true); + } + }, + + _onDragLeave: function () { + var el = this.el, + options = this.options; + + _toggleClass(el, options.invalidGroupClass, false); + _toggleClass(el, options.validGroupClass, false); + + el = null; }, _animate: function (prevRect, target) { @@ -817,6 +837,8 @@ var el = this.el, options = this.options; + this._onDragLeave(); + clearInterval(this._loopId); clearInterval(autoScroll.pid); clearTimeout(this._dragStartTimer); @@ -889,7 +911,7 @@ newIndex = oldIndex; } - _dispatchEvent(this, rootEl, 'end', dragEl, rootEl, oldIndex, newIndex); + _dispatchEvent(this, parentEl, 'end', dragEl, rootEl, oldIndex, newIndex); // Save sorting this.save(); @@ -929,14 +951,28 @@ handleEvent: function (/**Event*/evt) { var type = evt.type; - if (type === 'dragover' || type === 'dragenter') { - if (dragEl) { - this._onDragOver(evt); - _globalDragOver(evt); - } - } - else if (type === 'drop' || type === 'dragend') { - this._onDrop(evt); + switch (type) { + case 'dragenter': + if (dragEl) { + this._onDragOver(evt); + _globalDragOver(evt); + } + break; + + case 'dragleave': + if (evt.target.tagName.toLowerCase() === this.options.draggable) { + evt.preventDefault(); + evt.stopPropagation(); + } + else { + this._onDragLeave(evt); + } + break; + + case 'drop': + case 'dragend': + this._onDrop(evt); + break; } }, @@ -1051,6 +1087,7 @@ }); touchDragOverListeners.splice(touchDragOverListeners.indexOf(this._onDragOver), 1); + touchDragOverListeners.splice(touchDragOverListeners.indexOf(this._onDragLeave), 1); this._onDrop(); diff --git a/st/app.css b/st/app.css index 1de653029..81dc4218a 100644 --- a/st/app.css +++ b/st/app.css @@ -51,6 +51,10 @@ ul { opacity: .2; } +.sortable-invalid > * { + pointer-events: none; +} + #foo .sortable-drag { background: #daf4ff; }