toolshed-8.x-1.x-dev/js/DragDrop.js

js/DragDrop.js
"use strict";

(({
  Toolshed
}) => {
  /**
   * Object wrapping a DOM element to implement a droppable container for
   * accepting draggable instances.
   */
  class Droppable {
    /**
     * Create a new instance of a droppable for containing draggables.
     *
     * @param {Element} el
     *   DOM element to treat as the droppable.
     * @param {Object} opts
     *   Configuration options to control how this droppable behaves.
     */
    constructor(el, opts = {}) {
      this.el = el;
      this.opts = {
        ...opts
      };
      this.id = el.dataset.containerId;
      this.items = [];
      this.children = [];
    }
    getId() {
      return this.id;
    }
    getItems() {
      return this.items;
    }
    getChildren() {
      return this.children;
    }
    attachItem(item, pos) {
      const el = item.getElement();
      if ((pos || pos === 0) && this.items.length > pos) {
        this.el.insertBefore(el, this.items[pos].getElement());
        this.items.splice(pos, 0, el);
      } else {
        this.el.appendChild(item.getElement());
        this.items.push(item);
        pos = this.items.length - 1;
      }
      item.attach(this, pos);
    }
    detachItem(item) {
      for (let i = 0; i < this.items.length; ++i) {
        if (this.items[i] === item) {
          this.items.splice(i, 1);
          break;
        }
      }
      this.el.removeChild(item.getElement());
      item.detach();
    }
  }

  /**
   * A element that is draggable and can get placed into {Droppable} objects.
   */
  class Draggable {
    /**
     * Get the active dragging object instance, if there is a dragging action
     * in progress. There will only be a single draggable actively being dragged
     * at any given time.
     *
     * @return {Draggable|null}
     *   Return the draggable instance if there is one, otherwise return {null}.
     */
    static get dragging() {
      return this._dragging;
    }

    /**
     * Get the currently active dragging tracking to this draggable object.
     * This property is global because there should only be 1 active dragging
     * activity for the entire application, even if it is accross multiple
     * drag and drop sets.
     *
     * @param {Draggable|null} draggable
     *   Set the {Draggable} element as actively being dragged. Passing {null}
     *   as the parameter here is the same as unsetting cancelling any current
     *   dragging activity and clearing this property.
     */
    static set dragging(draggable) {
      if (this._dragging) {
        const oldDrag = this._dragging;
        oldDrag.cancelDrag(false);
      }
      this._dragging = draggable;
    }

    /**
     * Construct a new draggable handler.
     *
     * @param {Element} el
     *   The element to attach the draggable behaviors to.
     * @param {Object} opts
     *   The options for the draggable behaviors.
     */
    constructor(el, opts = {}) {
      this.el = el;
      this.opts = {
        inputSelector: 'input.drag-parent',
        ...opts
      };
      this.parent = null;
      this.pos = 0;
      this.input = this.el.querySelector(this.opts.inputSelector);
    }
    getElement() {
      return this.el;
    }
    attach(droppable, pos) {
      this.parent = droppable;
      this.pos = pos;
      this.input.value = `${droppable.getId()}:${pos}`;
    }
    detach() {
      this.parent = null;
      this.pos = 0;
      this.input.value = '';
    }

    /**
     * Cancel the dragging action if it's been dragged.
     */
    cancelDrag() {
      if (this.placeholder) {
        this.placeholder.parentNode.removeChild(this.placeholder);
      }
    }
  }

  // Export the drag and drop definitions to the Toolshed namespace.
  Toolshed.Droppable = Droppable;
  Toolshed.Draggable = Draggable;
})(Drupal);
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRHJhZ0Ryb3AuanMiLCJuYW1lcyI6WyJUb29sc2hlZCIsIkRyb3BwYWJsZSIsImNvbnN0cnVjdG9yIiwiZWwiLCJvcHRzIiwiaWQiLCJkYXRhc2V0IiwiY29udGFpbmVySWQiLCJpdGVtcyIsImNoaWxkcmVuIiwiZ2V0SWQiLCJnZXRJdGVtcyIsImdldENoaWxkcmVuIiwiYXR0YWNoSXRlbSIsIml0ZW0iLCJwb3MiLCJnZXRFbGVtZW50IiwibGVuZ3RoIiwiaW5zZXJ0QmVmb3JlIiwic3BsaWNlIiwiYXBwZW5kQ2hpbGQiLCJwdXNoIiwiYXR0YWNoIiwiZGV0YWNoSXRlbSIsImkiLCJyZW1vdmVDaGlsZCIsImRldGFjaCIsIkRyYWdnYWJsZSIsImRyYWdnaW5nIiwiX2RyYWdnaW5nIiwiZHJhZ2dhYmxlIiwib2xkRHJhZyIsImNhbmNlbERyYWciLCJpbnB1dFNlbGVjdG9yIiwicGFyZW50IiwiaW5wdXQiLCJxdWVyeVNlbGVjdG9yIiwiZHJvcHBhYmxlIiwidmFsdWUiLCJwbGFjZWhvbGRlciIsInBhcmVudE5vZGUiLCJEcnVwYWwiXSwic291cmNlcyI6WyJEcmFnRHJvcC5lczYuanMiXSwic291cmNlc0NvbnRlbnQiOlsiKCh7IFRvb2xzaGVkIH0pID0+IHtcbiAgLyoqXG4gICAqIE9iamVjdCB3cmFwcGluZyBhIERPTSBlbGVtZW50IHRvIGltcGxlbWVudCBhIGRyb3BwYWJsZSBjb250YWluZXIgZm9yXG4gICAqIGFjY2VwdGluZyBkcmFnZ2FibGUgaW5zdGFuY2VzLlxuICAgKi9cbiAgY2xhc3MgRHJvcHBhYmxlIHtcbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYSBuZXcgaW5zdGFuY2Ugb2YgYSBkcm9wcGFibGUgZm9yIGNvbnRhaW5pbmcgZHJhZ2dhYmxlcy5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7RWxlbWVudH0gZWxcbiAgICAgKiAgIERPTSBlbGVtZW50IHRvIHRyZWF0IGFzIHRoZSBkcm9wcGFibGUuXG4gICAgICogQHBhcmFtIHtPYmplY3R9IG9wdHNcbiAgICAgKiAgIENvbmZpZ3VyYXRpb24gb3B0aW9ucyB0byBjb250cm9sIGhvdyB0aGlzIGRyb3BwYWJsZSBiZWhhdmVzLlxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKGVsLCBvcHRzID0ge30pIHtcbiAgICAgIHRoaXMuZWwgPSBlbDtcbiAgICAgIHRoaXMub3B0cyA9IHtcbiAgICAgICAgLi4ub3B0cyxcbiAgICAgIH07XG5cbiAgICAgIHRoaXMuaWQgPSBlbC5kYXRhc2V0LmNvbnRhaW5lcklkO1xuICAgICAgdGhpcy5pdGVtcyA9IFtdO1xuICAgICAgdGhpcy5jaGlsZHJlbiA9IFtdO1xuICAgIH1cblxuICAgIGdldElkKCkge1xuICAgICAgcmV0dXJuIHRoaXMuaWQ7XG4gICAgfVxuXG4gICAgZ2V0SXRlbXMoKSB7XG4gICAgICByZXR1cm4gdGhpcy5pdGVtcztcbiAgICB9XG5cbiAgICBnZXRDaGlsZHJlbigpIHtcbiAgICAgIHJldHVybiB0aGlzLmNoaWxkcmVuO1xuICAgIH1cblxuICAgIGF0dGFjaEl0ZW0oaXRlbSwgcG9zKSB7XG4gICAgICBjb25zdCBlbCA9IGl0ZW0uZ2V0RWxlbWVudCgpO1xuXG4gICAgICBpZiAoKHBvcyB8fCBwb3MgPT09IDApICYmIHRoaXMuaXRlbXMubGVuZ3RoID4gcG9zKSB7XG4gICAgICAgIHRoaXMuZWwuaW5zZXJ0QmVmb3JlKGVsLCB0aGlzLml0ZW1zW3Bvc10uZ2V0RWxlbWVudCgpKTtcbiAgICAgICAgdGhpcy5pdGVtcy5zcGxpY2UocG9zLCAwLCBlbCk7XG4gICAgICB9XG4gICAgICBlbHNlIHtcbiAgICAgICAgdGhpcy5lbC5hcHBlbmRDaGlsZChpdGVtLmdldEVsZW1lbnQoKSk7XG4gICAgICAgIHRoaXMuaXRlbXMucHVzaChpdGVtKTtcbiAgICAgICAgcG9zID0gdGhpcy5pdGVtcy5sZW5ndGggLSAxO1xuICAgICAgfVxuXG4gICAgICBpdGVtLmF0dGFjaCh0aGlzLCBwb3MpO1xuICAgIH1cblxuICAgIGRldGFjaEl0ZW0oaXRlbSkge1xuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLml0ZW1zLmxlbmd0aDsgKytpKSB7XG4gICAgICAgIGlmICh0aGlzLml0ZW1zW2ldID09PSBpdGVtKSB7XG4gICAgICAgICAgdGhpcy5pdGVtcy5zcGxpY2UoaSwgMSk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgdGhpcy5lbC5yZW1vdmVDaGlsZChpdGVtLmdldEVsZW1lbnQoKSk7XG4gICAgICBpdGVtLmRldGFjaCgpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBBIGVsZW1lbnQgdGhhdCBpcyBkcmFnZ2FibGUgYW5kIGNhbiBnZXQgcGxhY2VkIGludG8ge0Ryb3BwYWJsZX0gb2JqZWN0cy5cbiAgICovXG4gIGNsYXNzIERyYWdnYWJsZSB7XG4gICAgLyoqXG4gICAgICogR2V0IHRoZSBhY3RpdmUgZHJhZ2dpbmcgb2JqZWN0IGluc3RhbmNlLCBpZiB0aGVyZSBpcyBhIGRyYWdnaW5nIGFjdGlvblxuICAgICAqIGluIHByb2dyZXNzLiBUaGVyZSB3aWxsIG9ubHkgYmUgYSBzaW5nbGUgZHJhZ2dhYmxlIGFjdGl2ZWx5IGJlaW5nIGRyYWdnZWRcbiAgICAgKiBhdCBhbnkgZ2l2ZW4gdGltZS5cbiAgICAgKlxuICAgICAqIEByZXR1cm4ge0RyYWdnYWJsZXxudWxsfVxuICAgICAqICAgUmV0dXJuIHRoZSBkcmFnZ2FibGUgaW5zdGFuY2UgaWYgdGhlcmUgaXMgb25lLCBvdGhlcndpc2UgcmV0dXJuIHtudWxsfS5cbiAgICAgKi9cbiAgICBzdGF0aWMgZ2V0IGRyYWdnaW5nKCkge1xuICAgICAgcmV0dXJuIHRoaXMuX2RyYWdnaW5nO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldCB0aGUgY3VycmVudGx5IGFjdGl2ZSBkcmFnZ2luZyB0cmFja2luZyB0byB0aGlzIGRyYWdnYWJsZSBvYmplY3QuXG4gICAgICogVGhpcyBwcm9wZXJ0eSBpcyBnbG9iYWwgYmVjYXVzZSB0aGVyZSBzaG91bGQgb25seSBiZSAxIGFjdGl2ZSBkcmFnZ2luZ1xuICAgICAqIGFjdGl2aXR5IGZvciB0aGUgZW50aXJlIGFwcGxpY2F0aW9uLCBldmVuIGlmIGl0IGlzIGFjY3Jvc3MgbXVsdGlwbGVcbiAgICAgKiBkcmFnIGFuZCBkcm9wIHNldHMuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge0RyYWdnYWJsZXxudWxsfSBkcmFnZ2FibGVcbiAgICAgKiAgIFNldCB0aGUge0RyYWdnYWJsZX0gZWxlbWVudCBhcyBhY3RpdmVseSBiZWluZyBkcmFnZ2VkLiBQYXNzaW5nIHtudWxsfVxuICAgICAqICAgYXMgdGhlIHBhcmFtZXRlciBoZXJlIGlzIHRoZSBzYW1lIGFzIHVuc2V0dGluZyBjYW5jZWxsaW5nIGFueSBjdXJyZW50XG4gICAgICogICBkcmFnZ2luZyBhY3Rpdml0eSBhbmQgY2xlYXJpbmcgdGhpcyBwcm9wZXJ0eS5cbiAgICAgKi9cbiAgICBzdGF0aWMgc2V0IGRyYWdnaW5nKGRyYWdnYWJsZSkge1xuICAgICAgaWYgKHRoaXMuX2RyYWdnaW5nKSB7XG4gICAgICAgIGNvbnN0IG9sZERyYWcgPSB0aGlzLl9kcmFnZ2luZztcblxuICAgICAgICBvbGREcmFnLmNhbmNlbERyYWcoZmFsc2UpO1xuICAgICAgfVxuXG4gICAgICB0aGlzLl9kcmFnZ2luZyA9IGRyYWdnYWJsZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDb25zdHJ1Y3QgYSBuZXcgZHJhZ2dhYmxlIGhhbmRsZXIuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge0VsZW1lbnR9IGVsXG4gICAgICogICBUaGUgZWxlbWVudCB0byBhdHRhY2ggdGhlIGRyYWdnYWJsZSBiZWhhdmlvcnMgdG8uXG4gICAgICogQHBhcmFtIHtPYmplY3R9IG9wdHNcbiAgICAgKiAgIFRoZSBvcHRpb25zIGZvciB0aGUgZHJhZ2dhYmxlIGJlaGF2aW9ycy5cbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihlbCwgb3B0cyA9IHt9KSB7XG4gICAgICB0aGlzLmVsID0gZWw7XG4gICAgICB0aGlzLm9wdHMgPSB7XG4gICAgICAgIGlucHV0U2VsZWN0b3I6ICdpbnB1dC5kcmFnLXBhcmVudCcsXG4gICAgICAgIC4uLm9wdHMsXG4gICAgICB9O1xuXG4gICAgICB0aGlzLnBhcmVudCA9IG51bGw7XG4gICAgICB0aGlzLnBvcyA9IDA7XG4gICAgICB0aGlzLmlucHV0ID0gdGhpcy5lbC5xdWVyeVNlbGVjdG9yKHRoaXMub3B0cy5pbnB1dFNlbGVjdG9yKTtcbiAgICB9XG5cbiAgICBnZXRFbGVtZW50KCkge1xuICAgICAgcmV0dXJuIHRoaXMuZWw7XG4gICAgfVxuXG4gICAgYXR0YWNoKGRyb3BwYWJsZSwgcG9zKSB7XG4gICAgICB0aGlzLnBhcmVudCA9IGRyb3BwYWJsZTtcbiAgICAgIHRoaXMucG9zID0gcG9zO1xuICAgICAgdGhpcy5pbnB1dC52YWx1ZSA9IGAke2Ryb3BwYWJsZS5nZXRJZCgpfToke3Bvc31gO1xuICAgIH1cblxuICAgIGRldGFjaCgpIHtcbiAgICAgIHRoaXMucGFyZW50ID0gbnVsbDtcbiAgICAgIHRoaXMucG9zID0gMDtcbiAgICAgIHRoaXMuaW5wdXQudmFsdWUgPSAnJztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDYW5jZWwgdGhlIGRyYWdnaW5nIGFjdGlvbiBpZiBpdCdzIGJlZW4gZHJhZ2dlZC5cbiAgICAgKi9cbiAgICBjYW5jZWxEcmFnKCkge1xuICAgICAgaWYgKHRoaXMucGxhY2Vob2xkZXIpIHtcbiAgICAgICAgdGhpcy5wbGFjZWhvbGRlci5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKHRoaXMucGxhY2Vob2xkZXIpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8vIEV4cG9ydCB0aGUgZHJhZyBhbmQgZHJvcCBkZWZpbml0aW9ucyB0byB0aGUgVG9vbHNoZWQgbmFtZXNwYWNlLlxuICBUb29sc2hlZC5Ecm9wcGFibGUgPSBEcm9wcGFibGU7XG4gIFRvb2xzaGVkLkRyYWdnYWJsZSA9IERyYWdnYWJsZTtcbn0pKERydXBhbCk7XG4iXSwi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

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc