未验证 提交 c3d1ea7f 编写于 作者: O owen-m1 提交者: GitHub

plugin API revamp (#1595)

上级 211b0300
......@@ -27,7 +27,7 @@ let autoScrolls = [],
function AutoScrollPlugin() {
function AutoScroll() {
this.options = {
this.defaults = {
scroll: true,
scrollSensitivity: 30,
scrollSpeed: 10,
......@@ -47,7 +47,7 @@ function AutoScrollPlugin() {
if (this.sortable.nativeDraggable) {
on(document, 'dragover', this._handleAutoScroll);
} else {
if (this.sortable.options.supportPointer) {
if (this.options.supportPointer) {
on(document, 'pointermove', this._handleFallbackAutoScroll);
} else if (originalEvent.touches) {
on(document, 'touchmove', this._handleFallbackAutoScroll);
......@@ -59,7 +59,7 @@ function AutoScrollPlugin() {
dragOverCompleted({ originalEvent }) {
// For when bubbling is canceled and using fallback (fallback 'touchmove' always reached)
if (!this.sortable.options.dragOverBubble && !originalEvent.rootEl) {
if (!this.options.dragOverBubble && !originalEvent.rootEl) {
this._handleAutoScroll(originalEvent);
}
},
......@@ -107,7 +107,7 @@ function AutoScrollPlugin() {
// MACOS Safari does not have autoscroll,
// Firefox and Chrome are good
if (fallback || Edge || IE11OrLess || Safari) {
autoScroll(evt, this.sortable.options, elem, fallback);
autoScroll(evt, this.options, elem, fallback);
// Listener for pointer element change
let ogElemScroller = getParentAutoScrollElement(elem, true);
......@@ -127,18 +127,18 @@ function AutoScrollPlugin() {
ogElemScroller = newElem;
clearAutoScrolls();
}
autoScroll(evt, this.sortable.options, newElem, fallback);
autoScroll(evt, this.options, newElem, fallback);
}, 10);
lastAutoScrollX = x;
lastAutoScrollY = y;
}
} else {
// if DnD is enabled (and browser has good autoscrolling), first autoscroll will already scroll, so get parent autoscroll of first autoscroll
if (!this.sortable.options.bubbleScroll || getParentAutoScrollElement(elem, true) === getWindowScrollingElement()) {
if (!this.options.bubbleScroll || getParentAutoScrollElement(elem, true) === getWindowScrollingElement()) {
clearAutoScrolls();
return;
}
autoScroll(evt, this.sortable.options, getParentAutoScrollElement(elem, false), false);
autoScroll(evt, this.options, getParentAutoScrollElement(elem, false), false);
}
}
};
......
......@@ -45,7 +45,7 @@ function MultiDragPlugin() {
on(document, 'keydown', this._checkKeyDown);
on(document, 'keyup', this._checkKeyUp);
this.options = {
this.defaults = {
selectedClass: 'sortable-selected',
multiDragKey: null,
setData(dataTransfer, dragEl) {
......@@ -75,7 +75,7 @@ function MultiDragPlugin() {
this.isMultiDrag = ~multiDragElements.indexOf(dragEl);
},
setupClone({ sortable }) {
setupClone({ sortable, cancel }) {
if (!this.isMultiDrag) return;
for (let i = 0; i < multiDragElements.length; i++) {
multiDragClones.push(clone(multiDragElements[i]));
......@@ -85,27 +85,27 @@ function MultiDragPlugin() {
multiDragClones[i].draggable = false;
multiDragClones[i].style['will-change'] = '';
toggleClass(multiDragClones[i], sortable.options.selectedClass, false);
multiDragElements[i] === dragEl && toggleClass(multiDragClones[i], sortable.options.chosenClass, false);
toggleClass(multiDragClones[i], this.options.selectedClass, false);
multiDragElements[i] === dragEl && toggleClass(multiDragClones[i], this.options.chosenClass, false);
}
sortable._hideClone();
return true;
cancel();
},
clone({ sortable, rootEl, dispatchSortableEvent }) {
clone({ sortable, rootEl, dispatchSortableEvent, cancel }) {
if (!this.isMultiDrag) return;
if (!sortable.options.removeCloneOnHide) {
if (!this.options.removeCloneOnHide) {
if (multiDragElements.length && multiDragSortable === sortable) {
insertMultiDragClones(true, rootEl);
dispatchSortableEvent('clone');
return true;
cancel();
}
}
},
showClone({ cloneNowShown, rootEl }) {
showClone({ cloneNowShown, rootEl, cancel }) {
if (!this.isMultiDrag) return;
insertMultiDragClones(false, rootEl);
multiDragClones.forEach(clone => {
......@@ -114,21 +114,21 @@ function MultiDragPlugin() {
cloneNowShown();
clonesHidden = false;
return true;
cancel();
},
hideClone({ sortable, cloneNowHidden }) {
hideClone({ sortable, cloneNowHidden, cancel }) {
if (!this.isMultiDrag) return;
multiDragClones.forEach(clone => {
css(clone, 'display', 'none');
if (sortable.options.removeCloneOnHide && clone.parentNode) {
if (this.options.removeCloneOnHide && clone.parentNode) {
clone.parentNode.removeChild(clone);
}
});
cloneNowHidden();
clonesHidden = true;
return true;
cancel();
},
dragStartGlobal({ sortable }) {
......@@ -149,7 +149,7 @@ function MultiDragPlugin() {
dragStarted({ sortable }) {
if (!this.isMultiDrag) return;
if (sortable.options.sort) {
if (this.options.sort) {
// Capture rects,
// hide multi drag elements (by positioning them absolute),
// set multi drag elements rects to dragRect,
......@@ -159,7 +159,7 @@ function MultiDragPlugin() {
sortable.captureAnimationState();
if (sortable.options.animation) {
if (this.options.animation) {
multiDragElements.forEach(multiDragElement => {
if (multiDragElement === dragEl) return;
css(multiDragElement, 'position', 'absolute');
......@@ -177,26 +177,27 @@ function MultiDragPlugin() {
}
}
sortable.animateAll(function() {
sortable.animateAll(() => {
folding = false;
initialFolding = false;
if (sortable.options.animation) {
if (this.options.animation) {
multiDragElements.forEach(multiDragElement => {
unsetRect(multiDragElement);
});
}
// Remove all auxiliary multidrag items from el, if sorting enabled
if (sortable.options.sort) {
if (this.options.sort) {
removeMultiDragElements();
}
});
},
dragOver({ target, completed }) {
dragOver({ target, completed, cancel }) {
if (folding && ~multiDragElements.indexOf(target)) {
return completed(false);
completed(false);
cancel();
}
},
......@@ -216,12 +217,12 @@ function MultiDragPlugin() {
fromSortable.removeAnimationState(multiDragElement);
});
folding = false;
insertMultiDragElements(!sortable.options.removeCloneOnHide, rootEl);
insertMultiDragElements(!this.options.removeCloneOnHide, rootEl);
}
},
dragOverCompleted({ sortable, isOwner, insertion, activeSortable, parentEl, putSortable }) {
let options = sortable.options;
let options = this.options;
if (insertion) {
// Clones must be hidden before folding animation to capture dragRectAbsolute properly
if (isOwner) {
......@@ -301,7 +302,7 @@ function MultiDragPlugin() {
if (!evt) return;
let options = sortable.options,
let options = this.options,
children = parentEl.children;
// Multi-drag selection
......@@ -344,7 +345,7 @@ function MultiDragPlugin() {
multiDragElements.push(children[i]);
dispatchEvent({
sortable: sortable,
sortable,
rootEl,
name: 'select',
targetEl: children[i],
......@@ -375,7 +376,7 @@ function MultiDragPlugin() {
// Do not "unfold" after around dragEl if reverted
if ((parentEl[expando].options.sort || parentEl !== rootEl) && multiDragElements.length > 1) {
let dragRect = getRect(dragEl),
multiDragIndex = index(dragEl, ':not(.' + sortable.options.selectedClass + ')');
multiDragIndex = index(dragEl, ':not(.' + this.options.selectedClass + ')');
if (!initialFolding && options.animation) dragEl.thisAnimationDuration = null;
......@@ -472,14 +473,14 @@ function MultiDragPlugin() {
if (multiDragSortable !== this.sortable) return;
// Only deselect if target is not item in this sortable
if (evt && closest(evt.target, this.sortable.options.draggable, this.sortable.el, false)) return;
if (evt && closest(evt.target, this.options.draggable, this.sortable.el, false)) return;
// Only deselect if left click
if (evt && evt.button !== 0) return;
while (multiDragElements.length) {
let el = multiDragElements[0];
toggleClass(el, this.sortable.options.selectedClass, false);
toggleClass(el, this.options.selectedClass, false);
multiDragElements.shift();
dispatchEvent({
sortable: this.sortable,
......@@ -492,13 +493,13 @@ function MultiDragPlugin() {
},
_checkKeyDown(evt) {
if (evt.key === this.sortable.options.multiDragKey) {
if (evt.key === this.options.multiDragKey) {
this.multiDragKeyDown = true;
}
},
_checkKeyUp(evt) {
if (evt.key === this.sortable.options.multiDragKey) {
if (evt.key === this.options.multiDragKey) {
this.multiDragKeyDown = false;
}
}
......@@ -534,7 +535,7 @@ function MultiDragPlugin() {
multiDragElements.splice(index, 1);
}
},
eventOptions() {
eventProperties() {
const oldIndicies = [],
newIndicies = [];
......
......@@ -33,7 +33,7 @@ Revert.prototype = {
if (putSortable) {
putSortable.captureAnimationState();
}
let nextSibling = getChild(this.sortable.el, this.startIndex, this.sortable.options);
let nextSibling = getChild(this.sortable.el, this.startIndex, this.options);
if (nextSibling) {
this.sortable.el.insertBefore(dragEl, nextSibling);
......
......@@ -8,6 +8,8 @@ Sortable plugins are plugins that can be directly mounted to the Sortable class.
`el: HTMLElement` — The element that the sortable is being initialized on
`options: Object` — The options object that the user has passed into Sortable (not merged with defaults yet)
## Static Properties
The constructor function passed to `Sortable.mount` may contain several static properties and methods. The following static properties may be defined:
......@@ -16,10 +18,10 @@ The constructor function passed to `Sortable.mount` may contain several static p
The name of the option that the user will use in their sortable's options to enable the plugin. Should start with a lower case and be camel-cased. For example: `'multiDrag'`. This is also the property name that the plugin's instance will be under in a sortable instance (ex. `sortableInstance.multiDrag`).
`utils: Object`
Object containing functions that will be added to the `Sortable.utils` default object on the Sortable class.
Object containing functions that will be added to the `Sortable.utils` static object on the Sortable class.
`eventOptions(eventName: String): Function`
A function that is called whenever Sortable fires an event. This function should return an object to be combined with the event object that Sortable will emit. The function will be called in the context of the Sortable that is firing the event (ie. the `this` keyword will be the Sortable calling the event).
A function that is called whenever Sortable fires an event. This function should return an object to be combined with the event object that Sortable will emit. The function will be called in the context of the instance of the plugin on the Sortable that is firing the event (ie. the `this` keyword will be the plugin instance).
`initializeByDefault: Boolean`
Determines whether or not the plugin will always be initialized on every new Sortable instance. If this option is enabled, it does not mean that by default the plugin will be enabled on the Sortable - this must still be done in the options via the plugin's `pluginName`, or it can be enabled by default if your plugin specifies it's pluginName as a default option that is truthy. Since the plugin will already be initialized on every Sortable instance, it can also be enabled dynamically via `sortableInstance.option('pluginName', true)`.
......@@ -51,11 +53,11 @@ Plugin.optionModifiers = {
```
## Plugin Options
Plugins may have custom options or override the defaults of certain options. In order to do this, there must be an `options` object on the initialized plugin. This can be set in the plugin's prototype, or during the initialization of the plugin (when the `el` is available). For example:
Plugins may have custom default options or may override the defaults of other options. In order to do this, there must be a `defaults` object on the initialized plugin. This can be set in the plugin's prototype, or during the initialization of the plugin (when the `el` is available). For example:
```js
function myPlugin(el) {
this.options = {
function myPlugin(sortable, el, options) {
this.defaults = {
color: el.style.backgroundColor
};
}
......@@ -67,7 +69,7 @@ Sortable.mount(myPlugin);
## Plugin Events
### Context
The events will be fired in the context of their own parent object (ie. context is not changed), however the plugin instance's Sortable instance is available under `this.sortable`.
The events will be fired in the context of their own parent object (ie. context is not changed), however the plugin instance's Sortable instance is available under `this.sortable`. Likewise, the options are available under `this.options`.
### Event List
The following table contains details on the events that a plugin may handle in the prototype of the plugin's constructor function.
......
......@@ -8,7 +8,7 @@ let lastSwapEl;
function SwapPlugin() {
function Swap() {
this.options = {
this.defaults = {
swapClass: 'sortable-swap-highlight'
};
}
......@@ -17,10 +17,10 @@ function SwapPlugin() {
dragStart({ dragEl }) {
lastSwapEl = dragEl;
},
dragOverValid({ completed, target, onMove, activeSortable, changed }) {
dragOverValid({ completed, target, onMove, activeSortable, changed, cancel }) {
if (!activeSortable.options.swap) return;
let el = this.sortable.el,
options = this.sortable.options;
options = this.options;
if (target && target !== el) {
let prevSwapEl = lastSwapEl;
if (onMove(target) !== false) {
......@@ -36,11 +36,12 @@ function SwapPlugin() {
}
changed();
return completed(true);
completed(true);
cancel();
},
drop({ activeSortable, putSortable, dragEl }) {
let toSortable = (putSortable || this.sortable);
let options = this.sortable.options;
let options = this.options;
lastSwapEl && toggleClass(lastSwapEl, options.swapClass, false);
if (lastSwapEl && (options.swap || putSortable && putSortable.options.swap)) {
if (dragEl !== lastSwapEl) {
......@@ -60,7 +61,7 @@ function SwapPlugin() {
return Object.assign(Swap, {
pluginName: 'swap',
eventOptions() {
eventProperties() {
return {
swapItem: lastSwapEl
};
......
......@@ -8,7 +8,7 @@ export default function dispatchEvent(
targetEl, cloneEl, toEl, fromEl,
oldIndex, newIndex,
oldDraggableIndex, newDraggableIndex,
originalEvent, putSortable, eventOptions
originalEvent, putSortable, extraEventProperties
}
) {
sortable = (sortable || (rootEl && rootEl[expando]));
......@@ -42,9 +42,9 @@ export default function dispatchEvent(
evt.originalEvent = originalEvent;
evt.pullMode = putSortable ? putSortable.lastPutMode : undefined;
let allEventOptions = { ...eventOptions, ...PluginManager.getEventOptions(name, sortable) };
for (let option in allEventOptions) {
evt[option] = allEventOptions[option];
let allEventProperties = { ...extraEventProperties, ...PluginManager.getEventProperties(name, sortable) };
for (let option in allEventProperties) {
evt[option] = allEventProperties[option];
}
if (rootEl) {
......
......@@ -16,6 +16,9 @@ export default {
},
pluginEvent(eventName, sortable, evt) {
this.eventCanceled = false;
evt.cancel = () => {
this.eventCanceled = true;
};
const eventNameGlobal = eventName + 'Global';
plugins.forEach(plugin => {
if (!sortable[plugin.pluginName]) return;
......@@ -23,7 +26,7 @@ export default {
if (
sortable[plugin.pluginName][eventNameGlobal]
) {
this.eventCanceled = !!sortable[plugin.pluginName][eventNameGlobal]({ sortable, ...evt });
sortable[plugin.pluginName][eventNameGlobal]({ sortable, ...evt });
}
// Only fire plugin event if plugin is enabled in this sortable,
......@@ -32,21 +35,22 @@ export default {
sortable.options[plugin.pluginName] &&
sortable[plugin.pluginName][eventName]
) {
this.eventCanceled = this.eventCanceled || !!sortable[plugin.pluginName][eventName]({ sortable, ...evt });
sortable[plugin.pluginName][eventName]({ sortable, ...evt });
}
});
},
initializePlugins(sortable, el, defaults) {
initializePlugins(sortable, el, defaults, options) {
plugins.forEach(plugin => {
const pluginName = plugin.pluginName;
if (!sortable.options[pluginName] && !plugin.initializeByDefault) return;
let initialized = new plugin(sortable, el);
let initialized = new plugin(sortable, el, sortable.options);
initialized.sortable = sortable;
initialized.options = sortable.options;
sortable[pluginName] = initialized;
// Add default options from plugin
Object.assign(defaults, initialized.options);
Object.assign(defaults, initialized.defaults);
});
for (let option in sortable.options) {
......@@ -57,14 +61,14 @@ export default {
}
}
},
getEventOptions(name, sortable) {
let eventOptions = {};
getEventProperties(name, sortable) {
let eventProperties = {};
plugins.forEach(plugin => {
if (typeof(plugin.eventOptions) !== 'function') return;
Object.assign(eventOptions, plugin.eventOptions.call(sortable, name));
if (typeof(plugin.eventProperties) !== 'function') return;
Object.assign(eventProperties, plugin.eventProperties.call(sortable[plugin.pluginName], name));
});
return eventOptions;
return eventProperties;
},
modifyOption(sortable, name, value) {
let modifiedValue;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册