@shopify/draggable
Version:
The JavaScript Drag & Drop library your grandparents warned you about.
600 lines (496 loc) • 15.4 kB
JavaScript
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define("Snappable", [], factory);
else if(typeof exports === 'object')
exports["Snappable"] = factory();
else
root["Snappable"] = factory();
})(window, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ }
/******/ };
/******/
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/
/******/ // create a fake namespace object
/******/ // mode & 1: value is a module id, require it
/******/ // mode & 2: merge all properties of value into the ns
/******/ // mode & 4: return value when already ns object
/******/ // mode & 8|1: behave like require
/******/ __webpack_require__.t = function(value, mode) {
/******/ if(mode & 1) value = __webpack_require__(value);
/******/ if(mode & 8) return value;
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ var ns = Object.create(null);
/******/ __webpack_require__.r(ns);
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ return ns;
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 7);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _SnappableEvent = __webpack_require__(6);
Object.keys(_SnappableEvent).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
Object.defineProperty(exports, key, {
enumerable: true,
get: function () {
return _SnappableEvent[key];
}
});
});
/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {
;
Object.defineProperty(exports, "__esModule", {
value: true
});
/**
* All draggable plugins inherit from this class.
* @abstract
* @class AbstractPlugin
* @module AbstractPlugin
*/
class AbstractPlugin {
/**
* AbstractPlugin constructor.
* @constructs AbstractPlugin
* @param {Draggable} draggable - Draggable instance
*/
constructor(draggable) {
/**
* Draggable instance
* @property draggable
* @type {Draggable}
*/
this.draggable = draggable;
}
/**
* Override to add listeners
* @abstract
*/
attach() {
throw new Error('Not Implemented');
}
/**
* Override to remove listeners
* @abstract
*/
detach() {
throw new Error('Not Implemented');
}
}
exports.default = AbstractPlugin;
/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _AbstractPlugin = __webpack_require__(1);
var _AbstractPlugin2 = _interopRequireDefault(_AbstractPlugin);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
exports.default = _AbstractPlugin2.default;
/***/ }),
/* 3 */
/***/ (function(module, exports, __webpack_require__) {
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _AbstractPlugin = __webpack_require__(2);
var _AbstractPlugin2 = _interopRequireDefault(_AbstractPlugin);
var _SnappableEvent = __webpack_require__(0);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const onDragStart = Symbol('onDragStart');
const onDragStop = Symbol('onDragStop');
const onDragOver = Symbol('onDragOver');
const onDragOut = Symbol('onDragOut');
const onMirrorCreated = Symbol('onMirrorCreated');
const onMirrorDestroy = Symbol('onMirrorDestroy');
/**
* Snappable plugin which snaps draggable elements into place
* @class Snappable
* @module Snappable
* @extends AbstractPlugin
*/
class Snappable extends _AbstractPlugin2.default {
/**
* Snappable constructor.
* @constructs Snappable
* @param {Draggable} draggable - Draggable instance
*/
constructor(draggable) {
super(draggable);
/**
* Keeps track of the first source element
* @property {HTMLElement|null} firstSource
*/
this.firstSource = null;
/**
* Keeps track of the mirror element
* @property {HTMLElement} mirror
*/
this.mirror = null;
this[onDragStart] = this[onDragStart].bind(this);
this[onDragStop] = this[onDragStop].bind(this);
this[onDragOver] = this[onDragOver].bind(this);
this[onDragOut] = this[onDragOut].bind(this);
this[onMirrorCreated] = this[onMirrorCreated].bind(this);
this[onMirrorDestroy] = this[onMirrorDestroy].bind(this);
}
/**
* Attaches plugins event listeners
*/
attach() {
this.draggable.on('drag:start', this[onDragStart]).on('drag:stop', this[onDragStop]).on('drag:over', this[onDragOver]).on('drag:out', this[onDragOut]).on('droppable:over', this[onDragOver]).on('droppable:out', this[onDragOut]).on('mirror:created', this[onMirrorCreated]).on('mirror:destroy', this[onMirrorDestroy]);
}
/**
* Detaches plugins event listeners
*/
detach() {
this.draggable.off('drag:start', this[onDragStart]).off('drag:stop', this[onDragStop]).off('drag:over', this[onDragOver]).off('drag:out', this[onDragOut]).off('droppable:over', this[onDragOver]).off('droppable:out', this[onDragOut]).off('mirror:created', this[onMirrorCreated]).off('mirror:destroy', this[onMirrorDestroy]);
}
/**
* Drag start handler
* @private
* @param {DragStartEvent} event - Drag start event
*/
[onDragStart](event) {
if (event.canceled()) {
return;
}
this.firstSource = event.source;
}
/**
* Drag stop handler
* @private
* @param {DragStopEvent} event - Drag stop event
*/
[onDragStop]() {
this.firstSource = null;
}
/**
* Drag over handler
* @private
* @param {DragOverEvent|DroppableOverEvent} event - Drag over event
*/
[onDragOver](event) {
if (event.canceled()) {
return;
}
const source = event.source || event.dragEvent.source;
if (source === this.firstSource) {
this.firstSource = null;
return;
}
const snapInEvent = new _SnappableEvent.SnapInEvent({
dragEvent: event,
snappable: event.over || event.droppable
});
this.draggable.trigger(snapInEvent);
if (snapInEvent.canceled()) {
return;
}
if (this.mirror) {
this.mirror.style.display = 'none';
}
source.classList.remove(this.draggable.getClassNameFor('source:dragging'));
source.classList.add(this.draggable.getClassNameFor('source:placed'));
// Need to cancel this in drag out
setTimeout(() => {
source.classList.remove(this.draggable.getClassNameFor('source:placed'));
}, this.draggable.options.placedTimeout);
}
/**
* Drag out handler
* @private
* @param {DragOutEvent|DroppableOutEvent} event - Drag out event
*/
[onDragOut](event) {
if (event.canceled()) {
return;
}
const source = event.source || event.dragEvent.source;
const snapOutEvent = new _SnappableEvent.SnapOutEvent({
dragEvent: event,
snappable: event.over || event.droppable
});
this.draggable.trigger(snapOutEvent);
if (snapOutEvent.canceled()) {
return;
}
if (this.mirror) {
this.mirror.style.display = '';
}
source.classList.add(this.draggable.getClassNameFor('source:dragging'));
}
/**
* Mirror created handler
* @param {MirrorCreatedEvent} mirrorEvent
* @private
*/
[onMirrorCreated]({ mirror }) {
this.mirror = mirror;
}
/**
* Mirror destroy handler
* @param {MirrorDestroyEvent} mirrorEvent
* @private
*/
[onMirrorDestroy]() {
this.mirror = null;
}
}
exports.default = Snappable;
/***/ }),
/* 4 */
/***/ (function(module, exports, __webpack_require__) {
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
const canceled = Symbol('canceled');
/**
* All events fired by draggable inherit this class. You can call `cancel()` to
* cancel a specific event or you can check if an event has been canceled by
* calling `canceled()`.
* @abstract
* @class AbstractEvent
* @module AbstractEvent
*/
class AbstractEvent {
/**
* AbstractEvent constructor.
* @constructs AbstractEvent
* @param {object} data - Event data
*/
/**
* Event type
* @static
* @abstract
* @property type
* @type {String}
*/
constructor(data) {
this[canceled] = false;
this.data = data;
}
/**
* Read-only type
* @abstract
* @return {String}
*/
/**
* Event cancelable
* @static
* @abstract
* @property cancelable
* @type {Boolean}
*/
get type() {
return this.constructor.type;
}
/**
* Read-only cancelable
* @abstract
* @return {Boolean}
*/
get cancelable() {
return this.constructor.cancelable;
}
/**
* Cancels the event instance
* @abstract
*/
cancel() {
this[canceled] = true;
}
/**
* Check if event has been canceled
* @abstract
* @return {Boolean}
*/
canceled() {
return Boolean(this[canceled]);
}
/**
* Returns new event instance with existing event data.
* This method allows for overriding of event data.
* @param {Object} data
* @return {AbstractEvent}
*/
clone(data) {
return new this.constructor(_extends({}, this.data, data));
}
}
exports.default = AbstractEvent;
AbstractEvent.type = 'event';
AbstractEvent.cancelable = false;
/***/ }),
/* 5 */
/***/ (function(module, exports, __webpack_require__) {
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _AbstractEvent = __webpack_require__(4);
var _AbstractEvent2 = _interopRequireDefault(_AbstractEvent);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
exports.default = _AbstractEvent2.default;
/***/ }),
/* 6 */
/***/ (function(module, exports, __webpack_require__) {
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.SnapOutEvent = exports.SnapInEvent = exports.SnapEvent = undefined;
var _AbstractEvent = __webpack_require__(5);
var _AbstractEvent2 = _interopRequireDefault(_AbstractEvent);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Base snap event
* @class SnapEvent
* @module SnapEvent
* @extends AbstractEvent
*/
class SnapEvent extends _AbstractEvent2.default {
/**
* Drag event that triggered this snap event
* @property dragEvent
* @type {DragEvent}
* @readonly
*/
get dragEvent() {
return this.data.dragEvent;
}
/**
* Snappable element
* @property snappable
* @type {HTMLElement}
* @readonly
*/
get snappable() {
return this.data.snappable;
}
}
exports.SnapEvent = SnapEvent; /**
* Snap in event
* @class SnapInEvent
* @module SnapInEvent
* @extends SnapEvent
*/
SnapEvent.type = 'snap';
class SnapInEvent extends SnapEvent {}
exports.SnapInEvent = SnapInEvent; /**
* Snap out event
* @class SnapOutEvent
* @module SnapOutEvent
* @extends SnapEvent
*/
SnapInEvent.type = 'snap:in';
SnapInEvent.cancelable = true;
class SnapOutEvent extends SnapEvent {}
exports.SnapOutEvent = SnapOutEvent;
SnapOutEvent.type = 'snap:out';
SnapOutEvent.cancelable = true;
/***/ }),
/* 7 */
/***/ (function(module, exports, __webpack_require__) {
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _SnappableEvent = __webpack_require__(0);
Object.keys(_SnappableEvent).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
Object.defineProperty(exports, key, {
enumerable: true,
get: function () {
return _SnappableEvent[key];
}
});
});
var _Snappable = __webpack_require__(3);
var _Snappable2 = _interopRequireDefault(_Snappable);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
exports.default = _Snappable2.default;
/***/ })
/******/ ]);
});