diff --git a/app/assets/javascripts/_practice_editor_utilities.es6 b/app/assets/javascripts/_practice_editor_utilities.es6
deleted file mode 100644
index aa041c152..000000000
--- a/app/assets/javascripts/_practice_editor_utilities.es6
+++ /dev/null
@@ -1,44 +0,0 @@
-$(document).arrive('.fields', (newElem) => {
- window.MutationObserver = window.MutationObserver
- || window.WebKitMutationObserver
- || window.MozMutationObserver;
- // Find the element that you want to "watch"
- var target = newElem, // document.querySelector('.fields'),
-// create an observer instance
- observer = new MutationObserver(function(mutation) {
- /** this is the callback where you
- do what you need to do.
- The argument is an array of MutationRecords where the affected attribute is
- named "attributeName". There is a few other properties in a record
- but I'll let you work it out yourself.
- **/
- if (mutation[0].target.style.display === 'none' && !mutation[0].target.classList.value.includes('sortable-dragging')) {
- let $parent = $(newElem).parent();
- $(newElem).appendTo('ul.trash-can');
- $(newElem).find('input').prop('required', false);
- $(newElem).find('textarea').prop('required', false);
- $(document).unbindArrive('.fields', newElem);
- $parent.children('li').map(function(index){
- $(this).find('input[class*="position"]').val(index + 1);
- return "resources[]=" + $(this).data("id");
- }).get().join("&");
- observer.disconnect();
- }
- }),
-// configuration of the observer:
- config = {
- attributes: true // this is to watch for attribute changes.
- };
- // pass in the element you wanna watch as well as the options
- observer.observe(target, config);
- // later, you can stop observing
- // observer.disconnect();
-});
-
-function initSortable(ulId) {
- sortable(ulId, {
- forcePlaceholderSize: true,
- placeholder: '
',
- handle: '.position-arrows'
- });
-}
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index be13643fc..75d0f9608 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -43,7 +43,6 @@
//= require reportAbuse
//= require turbolinksScrollTop
//= require save-editor-progress
-//= require html5sortable
//= require search
//= require modernizr-custom
//= require object_fit_polyfill
diff --git a/app/assets/javascripts/html5sortable.js b/app/assets/javascripts/html5sortable.js
deleted file mode 100644
index 5603a2b19..000000000
--- a/app/assets/javascripts/html5sortable.js
+++ /dev/null
@@ -1,1214 +0,0 @@
-/*
- * HTML5Sortable package
- * https://github.com/lukasoppermann/html5sortable
- *
- * Maintained by Lukas Oppermann
- *
- * Released under the MIT license.
- */
-var sortable = (function () {
- 'use strict';
-
- /**
- * Get or set data on element
- * @param {HTMLElement} element
- * @param {string} key
- * @param {any} value
- * @return {*}
- */
- function addData(element, key, value) {
- if (value === undefined) {
- return element && element.h5s && element.h5s.data && element.h5s.data[key];
- }
- else {
- element.h5s = element.h5s || {};
- element.h5s.data = element.h5s.data || {};
- element.h5s.data[key] = value;
- }
- }
- /**
- * Remove data from element
- * @param {HTMLElement} element
- */
- function removeData(element) {
- if (element.h5s) {
- delete element.h5s.data;
- }
- }
-
- /* eslint-env browser */
- /**
- * Filter only wanted nodes
- * @param {NodeList|HTMLCollection|Array} nodes
- * @param {String} selector
- * @returns {Array}
- */
- var _filter = (function (nodes, selector) {
- if (!(nodes instanceof NodeList || nodes instanceof HTMLCollection || nodes instanceof Array)) {
- throw new Error('You must provide a nodeList/HTMLCollection/Array of elements to be filtered.');
- }
- if (typeof selector !== 'string') {
- return Array.from(nodes);
- }
- return Array.from(nodes).filter(function (item) { return item.nodeType === 1 && item.matches(selector); });
- });
-
- /* eslint-env browser */
- var stores = new Map();
- /**
- * Stores data & configurations per Sortable
- * @param {Object} config
- */
- var Store = /** @class */ (function () {
- function Store() {
- this._config = new Map(); // eslint-disable-line no-undef
- this._placeholder = undefined; // eslint-disable-line no-undef
- this._data = new Map(); // eslint-disable-line no-undef
- }
- Object.defineProperty(Store.prototype, "config", {
- /**
- * get the configuration map of a class instance
- * @method config
- * @return {object}
- */
- get: function () {
- // transform Map to object
- var config = {};
- this._config.forEach(function (value, key) {
- config[key] = value;
- });
- // return object
- return config;
- },
- /**
- * set the configuration of a class instance
- * @method config
- * @param {object} config object of configurations
- */
- set: function (config) {
- if (typeof config !== 'object') {
- throw new Error('You must provide a valid configuration object to the config setter.');
- }
- // combine config with default
- var mergedConfig = Object.assign({}, config);
- // add config to map
- this._config = new Map(Object.entries(mergedConfig));
- },
- enumerable: true,
- configurable: true
- });
- /**
- * set individual configuration of a class instance
- * @method setConfig
- * @param key valid configuration key
- * @param value any value
- * @return void
- */
- Store.prototype.setConfig = function (key, value) {
- if (!this._config.has(key)) {
- throw new Error("Trying to set invalid configuration item: " + key);
- }
- // set config
- this._config.set(key, value);
- };
- /**
- * get an individual configuration of a class instance
- * @method getConfig
- * @param key valid configuration key
- * @return any configuration value
- */
- Store.prototype.getConfig = function (key) {
- if (!this._config.has(key)) {
- throw new Error("Invalid configuration item requested: " + key);
- }
- return this._config.get(key);
- };
- Object.defineProperty(Store.prototype, "placeholder", {
- /**
- * get the placeholder for a class instance
- * @method placeholder
- * @return {HTMLElement|null}
- */
- get: function () {
- return this._placeholder;
- },
- /**
- * set the placeholder for a class instance
- * @method placeholder
- * @param {HTMLElement} placeholder
- * @return {void}
- */
- set: function (placeholder) {
- if (!(placeholder instanceof HTMLElement) && placeholder !== null) {
- throw new Error('A placeholder must be an html element or null.');
- }
- this._placeholder = placeholder;
- },
- enumerable: true,
- configurable: true
- });
- /**
- * set an data entry
- * @method setData
- * @param {string} key
- * @param {any} value
- * @return {void}
- */
- Store.prototype.setData = function (key, value) {
- if (typeof key !== 'string') {
- throw new Error("The key must be a string.");
- }
- this._data.set(key, value);
- };
- /**
- * get an data entry
- * @method getData
- * @param {string} key an existing key
- * @return {any}
- */
- Store.prototype.getData = function (key) {
- if (typeof key !== 'string') {
- throw new Error("The key must be a string.");
- }
- return this._data.get(key);
- };
- /**
- * delete an data entry
- * @method deleteData
- * @param {string} key an existing key
- * @return {boolean}
- */
- Store.prototype.deleteData = function (key) {
- if (typeof key !== 'string') {
- throw new Error("The key must be a string.");
- }
- return this._data.delete(key);
- };
- return Store;
- }());
- /**
- * @param {HTMLElement} sortableElement
- * @returns {Class: Store}
- */
- var store = (function (sortableElement) {
- // if sortableElement is wrong type
- if (!(sortableElement instanceof HTMLElement)) {
- throw new Error('Please provide a sortable to the store function.');
- }
- // create new instance if not avilable
- if (!stores.has(sortableElement)) {
- stores.set(sortableElement, new Store());
- }
- // return instance
- return stores.get(sortableElement);
- });
-
- /**
- * @param {Array|HTMLElement} element
- * @param {Function} callback
- * @param {string} event
- */
- function addEventListener(element, eventName, callback) {
- if (element instanceof Array) {
- for (var i = 0; i < element.length; ++i) {
- addEventListener(element[i], eventName, callback);
- }
- return;
- }
- element.addEventListener(eventName, callback);
- store(element).setData("event" + eventName, callback);
- }
- /**
- * @param {Array|HTMLElement} element
- * @param {string} eventName
- */
- function removeEventListener(element, eventName) {
- if (element instanceof Array) {
- for (var i = 0; i < element.length; ++i) {
- removeEventListener(element[i], eventName);
- }
- return;
- }
- element.removeEventListener(eventName, store(element).getData("event" + eventName));
- store(element).deleteData("event" + eventName);
- }
-
- /**
- * @param {Array|HTMLElement} element
- * @param {string} attribute
- * @param {string} value
- */
- function addAttribute(element, attribute, value) {
- if (element instanceof Array) {
- for (var i = 0; i < element.length; ++i) {
- addAttribute(element[i], attribute, value);
- }
- return;
- }
- element.setAttribute(attribute, value);
- }
- /**
- * @param {Array|HTMLElement} element
- * @param {string} attribute
- */
- function removeAttribute(element, attribute) {
- if (element instanceof Array) {
- for (var i = 0; i < element.length; ++i) {
- removeAttribute(element[i], attribute);
- }
- return;
- }
- element.removeAttribute(attribute);
- }
-
- /**
- * @param {HTMLElement} element
- * @returns {Object}
- */
- var _offset = (function (element) {
- if (!element.parentElement || element.getClientRects().length === 0) {
- throw new Error('target element must be part of the dom');
- }
- var rect = element.getClientRects()[0];
- return {
- left: rect.left + window.pageXOffset,
- right: rect.right + window.pageXOffset,
- top: rect.top + window.pageYOffset,
- bottom: rect.bottom + window.pageYOffset
- };
- });
-
- /**
- * Creates and returns a new debounced version of the passed function which will postpone its execution until after wait milliseconds have elapsed
- * @param {Function} func to debounce
- * @param {number} time to wait before calling function with latest arguments, 0 - no debounce
- * @returns {function} - debounced function
- */
- var _debounce = (function (func, wait) {
- if (wait === void 0) { wait = 0; }
- var timeout;
- return function () {
- var args = [];
- for (var _i = 0; _i < arguments.length; _i++) {
- args[_i] = arguments[_i];
- }
- clearTimeout(timeout);
- timeout = setTimeout(function () {
- func.apply(void 0, args);
- }, wait);
- };
- });
-
- /* eslint-env browser */
- /**
- * Get position of the element relatively to its sibling elements
- * @param {HTMLElement} element
- * @returns {number}
- */
- var _index = (function (element, elementList) {
- if (!(element instanceof HTMLElement) || !(elementList instanceof NodeList || elementList instanceof HTMLCollection || elementList instanceof Array)) {
- throw new Error('You must provide an element and a list of elements.');
- }
- return Array.from(elementList).indexOf(element);
- });
-
- /* eslint-env browser */
- /**
- * Test whether element is in DOM
- * @param {HTMLElement} element
- * @returns {boolean}
- */
- var isInDom = (function (element) {
- if (!(element instanceof HTMLElement)) {
- throw new Error('Element is not a node element.');
- }
- return element.parentNode !== null;
- });
-
- /* eslint-env browser */
- /**
- * Insert node before or after target
- * @param {HTMLElement} referenceNode - reference element
- * @param {HTMLElement} newElement - element to be inserted
- * @param {String} position - insert before or after reference element
- */
- var insertNode = function (referenceNode, newElement, position) {
- if (!(referenceNode instanceof HTMLElement) || !(referenceNode.parentElement instanceof HTMLElement)) {
- throw new Error('target and element must be a node');
- }
- referenceNode.parentElement.insertBefore(newElement, (position === 'before' ? referenceNode : referenceNode.nextElementSibling));
- };
- /**
- * Insert before target
- * @param {HTMLElement} target
- * @param {HTMLElement} element
- */
- var insertBefore = function (target, element) { return insertNode(target, element, 'before'); };
- /**
- * Insert after target
- * @param {HTMLElement} target
- * @param {HTMLElement} element
- */
- var insertAfter = function (target, element) { return insertNode(target, element, 'after'); };
-
- /* eslint-env browser */
- /**
- * Filter only wanted nodes
- * @param {HTMLElement} sortableContainer
- * @param {Function} customSerializer
- * @returns {Array}
- */
- var _serialize = (function (sortableContainer, customItemSerializer, customContainerSerializer) {
- if (customItemSerializer === void 0) { customItemSerializer = function (serializedItem, sortableContainer) { return serializedItem; }; }
- if (customContainerSerializer === void 0) { customContainerSerializer = function (serializedContainer) { return serializedContainer; }; }
- // check for valid sortableContainer
- if (!(sortableContainer instanceof HTMLElement) || !sortableContainer.isSortable === true) {
- throw new Error('You need to provide a sortableContainer to be serialized.');
- }
- // check for valid serializers
- if (typeof customItemSerializer !== 'function' || typeof customContainerSerializer !== 'function') {
- throw new Error('You need to provide a valid serializer for items and the container.');
- }
- // get options
- var options = addData(sortableContainer, 'opts');
- var item = options.items;
- // serialize container
- var items = _filter(sortableContainer.children, item);
- var serializedItems = items.map(function (item) {
- return {
- parent: sortableContainer,
- node: item,
- html: item.outerHTML,
- index: _index(item, items)
- };
- });
- // serialize container
- var container = {
- node: sortableContainer,
- itemCount: serializedItems.length
- };
- return {
- container: customContainerSerializer(container),
- items: serializedItems.map(function (item) { return customItemSerializer(item, sortableContainer); })
- };
- });
-
- /* eslint-env browser */
- /**
- * create a placeholder element
- * @param {HTMLElement} sortableElement a single sortable
- * @param {string|undefined} placeholder a string representing an html element
- * @param {string} placeholderClasses a string representing the classes that should be added to the placeholder
- */
- var _makePlaceholder = (function (sortableElement, placeholder, placeholderClass) {
- var _a;
- if (placeholderClass === void 0) { placeholderClass = 'sortable-placeholder'; }
- if (!(sortableElement instanceof HTMLElement)) {
- throw new Error('You must provide a valid element as a sortable.');
- }
- // if placeholder is not an element
- if (!(placeholder instanceof HTMLElement) && placeholder !== undefined) {
- throw new Error('You must provide a valid element as a placeholder or set ot to undefined.');
- }
- // if no placeholder element is given
- if (placeholder === undefined) {
- if (['UL', 'OL'].includes(sortableElement.tagName)) {
- placeholder = document.createElement('li');
- }
- else if (['TABLE', 'TBODY'].includes(sortableElement.tagName)) {
- placeholder = document.createElement('tr');
- // set colspan to always all rows, otherwise the item can only be dropped in first column
- placeholder.innerHTML = ' | ';
- }
- else {
- placeholder = document.createElement('div');
- }
- }
- // add classes to placeholder
- if (typeof placeholderClass === 'string') {
- (_a = placeholder.classList).add.apply(_a, placeholderClass.split(' '));
- }
- return placeholder;
- });
-
- /* eslint-env browser */
- /**
- * Get height of an element including padding
- * @param {HTMLElement} element an dom element
- */
- var _getElementHeight = (function (element) {
- if (!(element instanceof HTMLElement)) {
- throw new Error('You must provide a valid dom element');
- }
- // get calculated style of element
- var style = window.getComputedStyle(element);
- // pick applicable properties, convert to int and reduce by adding
- return ['height', 'padding-top', 'padding-bottom']
- .map(function (key) {
- var int = parseInt(style.getPropertyValue(key), 10);
- return isNaN(int) ? 0 : int;
- })
- .reduce(function (sum, value) { return sum + value; });
- });
-
- /* eslint-env browser */
- /**
- * get handle or return item
- * @param {Array} items
- * @param {string} selector
- */
- var _getHandles = (function (items, selector) {
- if (!(items instanceof Array)) {
- throw new Error('You must provide a Array of HTMLElements to be filtered.');
- }
- if (typeof selector !== 'string') {
- return items;
- }
- return items
- // remove items without handle from array
- .filter(function (item) {
- return item.querySelector(selector) instanceof HTMLElement ||
- (item.shadowRoot && item.shadowRoot.querySelector(selector) instanceof HTMLElement);
- })
- // replace item with handle in array
- .map(function (item) {
- return item.querySelector(selector) || (item.shadowRoot && item.shadowRoot.querySelector(selector));
- });
- });
-
- /**
- * @param {Event} event
- * @returns {HTMLElement}
- */
- var getEventTarget = (function (event) {
- return (event.composedPath && event.composedPath()[0]) || event.target;
- });
-
- /* eslint-env browser */
- /**
- * defaultDragImage returns the current item as dragged image
- * @param {HTMLElement} draggedElement - the item that the user drags
- * @param {object} elementOffset - an object with the offsets top, left, right & bottom
- * @param {Event} event - the original drag event object
- * @return {object} with element, posX and posY properties
- */
- var defaultDragImage = function (draggedElement, elementOffset, event) {
- return {
- element: draggedElement,
- posX: event.pageX - elementOffset.left,
- posY: event.pageY - elementOffset.top
- };
- };
- /**
- * attaches an element as the drag image to an event
- * @param {Event} event - the original drag event object
- * @param {HTMLElement} draggedElement - the item that the user drags
- * @param {Function} customDragImage - function to create a custom dragImage
- * @return void
- */
- var setDragImage = (function (event, draggedElement, customDragImage) {
- // check if event is provided
- if (!(event instanceof Event)) {
- throw new Error('setDragImage requires a DragEvent as the first argument.');
- }
- // check if draggedElement is provided
- if (!(draggedElement instanceof HTMLElement)) {
- throw new Error('setDragImage requires the dragged element as the second argument.');
- }
- // set default function of none provided
- if (!customDragImage) {
- customDragImage = defaultDragImage;
- }
- // check if setDragImage method is available
- if (event.dataTransfer && event.dataTransfer.setDragImage) {
- // get the elements offset
- var elementOffset = _offset(draggedElement);
- // get the dragImage
- var dragImage = customDragImage(draggedElement, elementOffset, event);
- // check if custom function returns correct values
- if (!(dragImage.element instanceof HTMLElement) || typeof dragImage.posX !== 'number' || typeof dragImage.posY !== 'number') {
- throw new Error('The customDragImage function you provided must return and object with the properties element[string], posX[integer], posY[integer].');
- }
- // needs to be set for HTML5 drag & drop to work
- event.dataTransfer.effectAllowed = 'copyMove';
- // Firefox requires it to use the event target's id for the data
- event.dataTransfer.setData('text/plain', getEventTarget(event).id);
- // set the drag image on the event
- event.dataTransfer.setDragImage(dragImage.element, dragImage.posX, dragImage.posY);
- }
- });
-
- /**
- * Check if curList accepts items from destList
- * @param {sortable} destination the container an item is move to
- * @param {sortable} origin the container an item comes from
- */
- var _listsConnected = (function (destination, origin) {
- // check if valid sortable
- if (destination.isSortable === true) {
- var acceptFrom = store(destination).getConfig('acceptFrom');
- // check if acceptFrom is valid
- if (acceptFrom !== null && acceptFrom !== false && typeof acceptFrom !== 'string') {
- throw new Error('HTML5Sortable: Wrong argument, "acceptFrom" must be "null", "false", or a valid selector string.');
- }
- if (acceptFrom !== null) {
- return acceptFrom !== false && acceptFrom.split(',').filter(function (sel) {
- return sel.length > 0 && origin.matches(sel);
- }).length > 0;
- }
- // drop in same list
- if (destination === origin) {
- return true;
- }
- // check if lists are connected with connectWith
- if (store(destination).getConfig('connectWith') !== undefined && store(destination).getConfig('connectWith') !== null) {
- return store(destination).getConfig('connectWith') === store(origin).getConfig('connectWith');
- }
- }
- return false;
- });
-
- /**
- * default configurations
- */
- var defaultConfiguration = {
- items: null,
- // deprecated
- connectWith: null,
- // deprecated
- disableIEFix: null,
- acceptFrom: null,
- copy: false,
- placeholder: null,
- placeholderClass: 'sortable-placeholder',
- draggingClass: 'sortable-dragging',
- hoverClass: false,
- debounce: 0,
- throttleTime: 100,
- maxItems: 0,
- itemSerializer: undefined,
- containerSerializer: undefined,
- customDragImage: null
- };
-
- /**
- * make sure a function is only called once within the given amount of time
- * @param {Function} fn the function to throttle
- * @param {number} threshold time limit for throttling
- */
- // must use function to keep this context
- function _throttle (fn, threshold) {
- var _this = this;
- if (threshold === void 0) { threshold = 250; }
- // check function
- if (typeof fn !== 'function') {
- throw new Error('You must provide a function as the first argument for throttle.');
- }
- // check threshold
- if (typeof threshold !== 'number') {
- throw new Error('You must provide a number as the second argument for throttle.');
- }
- var lastEventTimestamp = null;
- return function () {
- var args = [];
- for (var _i = 0; _i < arguments.length; _i++) {
- args[_i] = arguments[_i];
- }
- var now = Date.now();
- if (lastEventTimestamp === null || now - lastEventTimestamp >= threshold) {
- lastEventTimestamp = now;
- fn.apply(_this, args);
- }
- };
- }
-
- /* eslint-env browser */
- /**
- * enable or disable hoverClass on mouseenter/leave if container Items
- * @param {sortable} sortableContainer a valid sortableContainer
- * @param {boolean} enable enable or disable event
- */
- // export default (sortableContainer: sortable, enable: boolean) => {
- var enableHoverClass = (function (sortableContainer, enable) {
- if (typeof store(sortableContainer).getConfig('hoverClass') === 'string') {
- var hoverClasses_1 = store(sortableContainer).getConfig('hoverClass').split(' ');
- // add class on hover
- if (enable === true) {
- addEventListener(sortableContainer, 'mousemove', _throttle(function (event) {
- // check of no mouse button was pressed when mousemove started == no drag
- if (event.buttons === 0) {
- _filter(sortableContainer.children, store(sortableContainer).getConfig('items')).forEach(function (item) {
- var _a, _b;
- if (item !== event.target) {
- (_a = item.classList).remove.apply(_a, hoverClasses_1);
- }
- else {
- (_b = item.classList).add.apply(_b, hoverClasses_1);
- }
- });
- }
- }, store(sortableContainer).getConfig('throttleTime')));
- // remove class on leave
- addEventListener(sortableContainer, 'mouseleave', function () {
- _filter(sortableContainer.children, store(sortableContainer).getConfig('items')).forEach(function (item) {
- var _a;
- (_a = item.classList).remove.apply(_a, hoverClasses_1);
- });
- });
- // remove events
- }
- else {
- removeEventListener(sortableContainer, 'mousemove');
- removeEventListener(sortableContainer, 'mouseleave');
- }
- }
- });
-
- /* eslint-env browser */
- /*
- * variables global to the plugin
- */
- var dragging;
- var draggingHeight;
- /*
- * Keeps track of the initialy selected list, where 'dragstart' event was triggered
- * It allows us to move the data in between individual Sortable List instances
- */
- // Origin List - data from before any item was changed
- var originContainer;
- var originIndex;
- var originElementIndex;
- var originItemsBeforeUpdate;
- // Previous Sortable Container - we dispatch as sortenter event when a
- // dragged item enters a sortableContainer for the first time
- var previousContainer;
- // Destination List - data from before any item was changed
- var destinationItemsBeforeUpdate;
- /**
- * remove event handlers from items
- * @param {Array|NodeList} items
- */
- var _removeItemEvents = function (items) {
- removeEventListener(items, 'dragstart');
- removeEventListener(items, 'dragend');
- removeEventListener(items, 'dragover');
- removeEventListener(items, 'dragenter');
- removeEventListener(items, 'drop');
- removeEventListener(items, 'mouseenter');
- removeEventListener(items, 'mouseleave');
- };
- /**
- * _getDragging returns the current element to drag or
- * a copy of the element.
- * Is Copy Active for sortable
- * @param {HTMLElement} draggedItem - the item that the user drags
- * @param {HTMLElement} sortable a single sortable
- */
- var _getDragging = function (draggedItem, sortable) {
- var ditem = draggedItem;
- if (store(sortable).getConfig('copy') === true) {
- ditem = draggedItem.cloneNode(true);
- addAttribute(ditem, 'aria-copied', 'true');
- draggedItem.parentElement.appendChild(ditem);
- ditem.style.display = 'none';
- ditem.oldDisplay = draggedItem.style.display;
- }
- return ditem;
- };
- /**
- * Remove data from sortable
- * @param {HTMLElement} sortable a single sortable
- */
- var _removeSortableData = function (sortable) {
- removeData(sortable);
- removeAttribute(sortable, 'aria-dropeffect');
- };
- /**
- * Remove data from items
- * @param {Array|HTMLElement} items
- */
- var _removeItemData = function (items) {
- removeAttribute(items, 'aria-grabbed');
- removeAttribute(items, 'aria-copied');
- removeAttribute(items, 'draggable');
- removeAttribute(items, 'role');
- };
- /**
- * find sortable from element. travels up parent element until found or null.
- * @param {HTMLElement} element a single sortable
- * @param {Event} event - the current event. We need to pass it to be able to
- * find Sortable whith shadowRoot (document fragment has no parent)
- */
- function findSortable(element, event) {
- if (event.composedPath) {
- return event.composedPath().find(function (el) { return el.isSortable; });
- }
- while (element.isSortable !== true) {
- element = element.parentElement;
- }
- return element;
- }
- /**
- * Dragging event is on the sortable element. finds the top child that
- * contains the element.
- * @param {HTMLElement} sortableElement a single sortable
- * @param {HTMLElement} element is that being dragged
- */
- function findDragElement(sortableElement, element) {
- var options = addData(sortableElement, 'opts');
- var items = _filter(sortableElement.children, options.items);
- var itemlist = items.filter(function (ele) {
- return ele.contains(element) || (ele.shadowRoot && ele.shadowRoot.contains(element));
- });
- return itemlist.length > 0 ? itemlist[0] : element;
- }
- /**
- * Destroy the sortable
- * @param {HTMLElement} sortableElement a single sortable
- */
- var _destroySortable = function (sortableElement) {
- var opts = addData(sortableElement, 'opts') || {};
- var items = _filter(sortableElement.children, opts.items);
- var handles = _getHandles(items, opts.handle);
- // remove event handlers & data from sortable
- removeEventListener(sortableElement, 'dragover');
- removeEventListener(sortableElement, 'dragenter');
- removeEventListener(sortableElement, 'drop');
- // remove event data from sortable
- _removeSortableData(sortableElement);
- // remove event handlers & data from items
- removeEventListener(handles, 'mousedown');
- _removeItemEvents(items);
- _removeItemData(items);
- };
- /**
- * Enable the sortable
- * @param {HTMLElement} sortableElement a single sortable
- */
- var _enableSortable = function (sortableElement) {
- var opts = addData(sortableElement, 'opts');
- var items = _filter(sortableElement.children, opts.items);
- var handles = _getHandles(items, opts.handle);
- addAttribute(sortableElement, 'aria-dropeffect', 'move');
- addData(sortableElement, '_disabled', 'false');
- addAttribute(handles, 'draggable', 'true');
- // @todo: remove this fix
- // IE FIX for ghost
- // can be disabled as it has the side effect that other events
- // (e.g. click) will be ignored
- if (opts.disableIEFix === false) {
- var spanEl = (document || window.document).createElement('span');
- if (typeof spanEl.dragDrop === 'function') {
- addEventListener(handles, 'mousedown', function () {
- if (items.indexOf(this) !== -1) {
- this.dragDrop();
- }
- else {
- var parent = this.parentElement;
- while (items.indexOf(parent) === -1) {
- parent = parent.parentElement;
- }
- parent.dragDrop();
- }
- });
- }
- }
- };
- /**
- * Disable the sortable
- * @param {HTMLElement} sortableElement a single sortable
- */
- var _disableSortable = function (sortableElement) {
- var opts = addData(sortableElement, 'opts');
- var items = _filter(sortableElement.children, opts.items);
- var handles = _getHandles(items, opts.handle);
- addAttribute(sortableElement, 'aria-dropeffect', 'none');
- addData(sortableElement, '_disabled', 'true');
- addAttribute(handles, 'draggable', 'false');
- removeEventListener(handles, 'mousedown');
- };
- /**
- * Reload the sortable
- * @param {HTMLElement} sortableElement a single sortable
- * @description events need to be removed to not be double bound
- */
- var _reloadSortable = function (sortableElement) {
- var opts = addData(sortableElement, 'opts');
- var items = _filter(sortableElement.children, opts.items);
- var handles = _getHandles(items, opts.handle);
- addData(sortableElement, '_disabled', 'false');
- // remove event handlers from items
- _removeItemEvents(items);
- removeEventListener(handles, 'mousedown');
- // remove event handlers from sortable
- removeEventListener(sortableElement, 'dragover');
- removeEventListener(sortableElement, 'dragenter');
- removeEventListener(sortableElement, 'drop');
- };
- /**
- * Public sortable object
- * @param {Array|NodeList} sortableElements
- * @param {object|string} options|method
- */
- function sortable(sortableElements, options) {
- // get method string to see if a method is called
- var method = String(options);
- options = options || {};
- // check if the user provided a selector instead of an element
- if (typeof sortableElements === 'string') {
- sortableElements = document.querySelectorAll(sortableElements);
- }
- // if the user provided an element, return it in an array to keep the return value consistant
- if (sortableElements instanceof HTMLElement) {
- sortableElements = [sortableElements];
- }
- sortableElements = Array.prototype.slice.call(sortableElements);
- if (/serialize/.test(method)) {
- return sortableElements.map(function (sortableContainer) {
- var opts = addData(sortableContainer, 'opts');
- return _serialize(sortableContainer, opts.itemSerializer, opts.containerSerializer);
- });
- }
- sortableElements.forEach(function (sortableElement) {
- if (/enable|disable|destroy/.test(method)) {
- return sortable[method](sortableElement);
- }
- // log deprecation
- ['connectWith', 'disableIEFix'].forEach(function (configKey) {
- if (options.hasOwnProperty(configKey) && options[configKey] !== null) {
- console.warn("HTML5Sortable: You are using the deprecated configuration \"" + configKey + "\". This will be removed in an upcoming version, make sure to migrate to the new options when updating.");
- }
- });
- // merge options with default options
- options = Object.assign({}, defaultConfiguration, store(sortableElement).config, options);
- // init data store for sortable
- store(sortableElement).config = options;
- // set options on sortable
- addData(sortableElement, 'opts', options);
- // property to define as sortable
- sortableElement.isSortable = true;
- // reset sortable
- _reloadSortable(sortableElement);
- // initialize
- var listItems = _filter(sortableElement.children, options.items);
- // create element if user defined a placeholder element as a string
- var customPlaceholder;
- if (options.placeholder !== null && options.placeholder !== undefined) {
- var tempContainer = document.createElement(sortableElement.tagName);
- if (options.placeholder instanceof HTMLElement) {
- tempContainer.appendChild(options.placeholder);
- }
- else {
- tempContainer.innerHTML = options.placeholder;
- }
- customPlaceholder = tempContainer.children[0];
- }
- // add placeholder
- store(sortableElement).placeholder = _makePlaceholder(sortableElement, customPlaceholder, options.placeholderClass);
- addData(sortableElement, 'items', options.items);
- if (options.acceptFrom) {
- addData(sortableElement, 'acceptFrom', options.acceptFrom);
- }
- else if (options.connectWith) {
- addData(sortableElement, 'connectWith', options.connectWith);
- }
- _enableSortable(sortableElement);
- addAttribute(listItems, 'role', 'option');
- addAttribute(listItems, 'aria-grabbed', 'false');
- // enable hover class
- enableHoverClass(sortableElement, true);
- /*
- Handle drag events on draggable items
- Handle is set at the sortableElement level as it will bubble up
- from the item
- */
- addEventListener(sortableElement, 'dragstart', function (e) {
- // ignore dragstart events
- var target = getEventTarget(e);
- if (target.isSortable === true) {
- return;
- }
- e.stopImmediatePropagation();
- if ((options.handle && !target.matches(options.handle)) || target.getAttribute('draggable') === 'false') {
- return;
- }
- var sortableContainer = findSortable(target, e);
- var dragItem = findDragElement(sortableContainer, target);
- // grab values
- originItemsBeforeUpdate = _filter(sortableContainer.children, options.items);
- originIndex = originItemsBeforeUpdate.indexOf(dragItem);
- originElementIndex = _index(dragItem, sortableContainer.children);
- originContainer = sortableContainer;
- // add transparent clone or other ghost to cursor
- setDragImage(e, dragItem, options.customDragImage);
- // cache selsection & add attr for dragging
- draggingHeight = _getElementHeight(dragItem);
- dragItem.classList.add(options.draggingClass);
- dragging = _getDragging(dragItem, sortableContainer);
- addAttribute(dragging, 'aria-grabbed', 'true');
- // dispatch sortstart event on each element in group
- sortableContainer.dispatchEvent(new CustomEvent('sortstart', {
- detail: {
- origin: {
- elementIndex: originElementIndex,
- index: originIndex,
- container: originContainer
- },
- item: dragging,
- originalTarget: target
- }
- }));
- });
- /*
- We are capturing targetSortable before modifications with 'dragenter' event
- */
- addEventListener(sortableElement, 'dragenter', function (e) {
- var target = getEventTarget(e);
- var sortableContainer = findSortable(target, e);
- if (sortableContainer && sortableContainer !== previousContainer) {
- destinationItemsBeforeUpdate = _filter(sortableContainer.children, addData(sortableContainer, 'items'))
- .filter(function (item) { return item !== store(sortableElement).placeholder; });
- sortableContainer.dispatchEvent(new CustomEvent('sortenter', {
- detail: {
- origin: {
- elementIndex: originElementIndex,
- index: originIndex,
- container: originContainer
- },
- destination: {
- container: sortableContainer,
- itemsBeforeUpdate: destinationItemsBeforeUpdate
- },
- item: dragging,
- originalTarget: target
- }
- }));
- }
- previousContainer = sortableContainer;
- });
- /*
- * Dragend Event - https://developer.mozilla.org/en-US/docs/Web/Events/dragend
- * Fires each time dragEvent end, or ESC pressed
- * We are using it to clean up any draggable elements and placeholders
- */
- addEventListener(sortableElement, 'dragend', function (e) {
- if (!dragging) {
- return;
- }
- dragging.classList.remove(options.draggingClass);
- addAttribute(dragging, 'aria-grabbed', 'false');
- if (dragging.getAttribute('aria-copied') === 'true' && addData(dragging, 'dropped') !== 'true') {
- dragging.remove();
- }
- dragging.style.display = dragging.oldDisplay;
- delete dragging.oldDisplay;
- var visiblePlaceholder = Array.from(stores.values()).map(function (data) { return data.placeholder; })
- .filter(function (placeholder) { return placeholder instanceof HTMLElement; })
- .filter(isInDom)[0];
- if (visiblePlaceholder) {
- visiblePlaceholder.remove();
- }
- // dispatch sortstart event on each element in group
- sortableElement.dispatchEvent(new CustomEvent('sortstop', {
- detail: {
- origin: {
- elementIndex: originElementIndex,
- index: originIndex,
- container: originContainer
- },
- item: dragging
- }
- }));
- previousContainer = null;
- dragging = null;
- draggingHeight = null;
- });
- /*
- * Drop Event - https://developer.mozilla.org/en-US/docs/Web/Events/drop
- * Fires when valid drop target area is hit
- */
- addEventListener(sortableElement, 'drop', function (e) {
- if (!_listsConnected(sortableElement, dragging.parentElement)) {
- return;
- }
- e.preventDefault();
- e.stopPropagation();
- addData(dragging, 'dropped', 'true');
- // get the one placeholder that is currently visible
- var visiblePlaceholder = Array.from(stores.values()).map(function (data) {
- return data.placeholder;
- })
- // filter only HTMLElements
- .filter(function (placeholder) { return placeholder instanceof HTMLElement; })
- // filter only elements in DOM
- .filter(isInDom)[0];
- // attach element after placeholder
- insertAfter(visiblePlaceholder, dragging);
- // remove placeholder from dom
- visiblePlaceholder.remove();
- /*
- * Fires Custom Event - 'sortstop'
- */
- sortableElement.dispatchEvent(new CustomEvent('sortstop', {
- detail: {
- origin: {
- elementIndex: originElementIndex,
- index: originIndex,
- container: originContainer
- },
- item: dragging
- }
- }));
- var placeholder = store(sortableElement).placeholder;
- var originItems = _filter(originContainer.children, options.items)
- .filter(function (item) { return item !== placeholder; });
- var destinationContainer = this.isSortable === true ? this : this.parentElement;
- var destinationItems = _filter(destinationContainer.children, addData(destinationContainer, 'items'))
- .filter(function (item) { return item !== placeholder; });
- var destinationElementIndex = _index(dragging, Array.from(dragging.parentElement.children)
- .filter(function (item) { return item !== placeholder; }));
- var destinationIndex = _index(dragging, destinationItems);
- /*
- * When a list item changed container lists or index within a list
- * Fires Custom Event - 'sortupdate'
- */
- if (originElementIndex !== destinationElementIndex || originContainer !== destinationContainer) {
- sortableElement.dispatchEvent(new CustomEvent('sortupdate', {
- detail: {
- origin: {
- elementIndex: originElementIndex,
- index: originIndex,
- container: originContainer,
- itemsBeforeUpdate: originItemsBeforeUpdate,
- items: originItems
- },
- destination: {
- index: destinationIndex,
- elementIndex: destinationElementIndex,
- container: destinationContainer,
- itemsBeforeUpdate: destinationItemsBeforeUpdate,
- items: destinationItems
- },
- item: dragging
- }
- }));
- }
- });
- var debouncedDragOverEnter = _debounce(function (sortableElement, element, pageY) {
- if (!dragging) {
- return;
- }
- // set placeholder height if forcePlaceholderSize option is set
- if (options.forcePlaceholderSize) {
- store(sortableElement).placeholder.style.height = draggingHeight + 'px';
- }
- // if element the draggedItem is dragged onto is within the array of all elements in list
- // (not only items, but also disabled, etc.)
- if (Array.from(sortableElement.children).indexOf(element) > -1) {
- var thisHeight = _getElementHeight(element);
- var placeholderIndex = _index(store(sortableElement).placeholder, element.parentElement.children);
- var thisIndex = _index(element, element.parentElement.children);
- // Check if `element` is bigger than the draggable. If it is, we have to define a dead zone to prevent flickering
- if (thisHeight > draggingHeight) {
- // Dead zone?
- var deadZone = thisHeight - draggingHeight;
- var offsetTop = _offset(element).top;
- if (placeholderIndex < thisIndex && pageY < offsetTop) {
- return;
- }
- if (placeholderIndex > thisIndex &&
- pageY > offsetTop + thisHeight - deadZone) {
- return;
- }
- }
- if (dragging.oldDisplay === undefined) {
- dragging.oldDisplay = dragging.style.display;
- }
- if (dragging.style.display !== 'none') {
- dragging.style.display = 'none';
- }
- // To avoid flicker, determine where to position the placeholder
- // based on where the mouse pointer is relative to the elements
- // vertical center.
- var placeAfter = false;
- try {
- var elementMiddle = _offset(element).top + element.offsetHeight / 2;
- placeAfter = pageY >= elementMiddle;
- }
- catch (e) {
- placeAfter = placeholderIndex < thisIndex;
- }
- if (placeAfter) {
- insertAfter(element, store(sortableElement).placeholder);
- }
- else {
- insertBefore(element, store(sortableElement).placeholder);
- }
- // get placeholders from all stores & remove all but current one
- Array.from(stores.values())
- // remove empty values
- .filter(function (data) { return data.placeholder !== undefined; })
- // foreach placeholder in array if outside of current sorableContainer -> remove from DOM
- .forEach(function (data) {
- if (data.placeholder !== store(sortableElement).placeholder) {
- data.placeholder.remove();
- }
- });
- }
- else {
- // get all placeholders from store
- var placeholders = Array.from(stores.values())
- .filter(function (data) { return data.placeholder !== undefined; })
- .map(function (data) {
- return data.placeholder;
- });
- // check if element is not in placeholders
- if (placeholders.indexOf(element) === -1 && sortableElement === element && !_filter(element.children, options.items).length) {
- placeholders.forEach(function (element) { return element.remove(); });
- element.appendChild(store(sortableElement).placeholder);
- }
- }
- }, options.debounce);
- // Handle dragover and dragenter events on draggable items
- var onDragOverEnter = function (e) {
- var element = e.target;
- var sortableElement = element.isSortable === true ? element : findSortable(element, e);
- element = findDragElement(sortableElement, element);
- if (!dragging || !_listsConnected(sortableElement, dragging.parentElement) || addData(sortableElement, '_disabled') === 'true') {
- return;
- }
- var options = addData(sortableElement, 'opts');
- if (parseInt(options.maxItems) && _filter(sortableElement.children, addData(sortableElement, 'items')).length >= parseInt(options.maxItems) && dragging.parentElement !== sortableElement) {
- return;
- }
- e.preventDefault();
- e.stopPropagation();
- e.dataTransfer.dropEffect = store(sortableElement).getConfig('copy') === true ? 'copy' : 'move';
- debouncedDragOverEnter(sortableElement, element, e.pageY);
- };
- addEventListener(listItems.concat(sortableElement), 'dragover', onDragOverEnter);
- addEventListener(listItems.concat(sortableElement), 'dragenter', onDragOverEnter);
- });
- return sortableElements;
- }
- sortable.destroy = function (sortableElement) {
- _destroySortable(sortableElement);
- };
- sortable.enable = function (sortableElement) {
- _enableSortable(sortableElement);
- };
- sortable.disable = function (sortableElement) {
- _disableSortable(sortableElement);
- };
- /* START.TESTS_ONLY */
- sortable.__testing = {
- // add internal methods here for testing purposes
- _data: addData,
- _removeItemEvents: _removeItemEvents,
- _removeItemData: _removeItemData,
- _removeSortableData: _removeSortableData
- };
-
- return sortable;
-
-}());
diff --git a/app/assets/javascripts/practice_editor_contact.es6 b/app/assets/javascripts/practice_editor_contact.es6
index b1f83ffb6..d37e404b1 100644
--- a/app/assets/javascripts/practice_editor_contact.es6
+++ b/app/assets/javascripts/practice_editor_contact.es6
@@ -4,37 +4,13 @@
function removeBulletPointFromNewLi() {
$document.arrive('.practice-editor-contact-li', (newElem) => {
$(newElem).appendTo('#sortable_contacts');
- initSortable('#sortable_contacts');
$(newElem).css('list-style', 'none');
$document.unbindArrive('.practice-editor-contact-li', newElem);
});
}
- function dragAndDropContactListItems() {
- initSortable('#sortable_contacts');
-
- if (typeof sortable('#sortable_contacts')[0] != 'undefined'){
- sortable('#sortable_contacts')[0].addEventListener('sortstart', function(e) {
- console.log('starting sort', e)
- });
-
- sortable('#sortable_contacts')[0].addEventListener('sortupdate', function(e) {
- var dataIDList = $(this).children('li').map(function(index){
- $(this).find( '.contact-position' ).val(index + 1)
- return "contacts[]=" + $(this).data("id");
- }).get().join("&");
- // Rails.ajax({
- // url: $(this).data("url"),
- // type: "PATCH",
- // data: dataIDList,
- // });
- });
- }
- }
-
function loadPracticeContactFunctions() {
removeBulletPointFromNewLi();
- dragAndDropContactListItems();
}
$document.on('turbolinks:load', loadPracticeContactFunctions);
diff --git a/app/assets/javascripts/practice_editor_risk_mitigation.es6 b/app/assets/javascripts/practice_editor_risk_mitigation.es6
index 6ed466d09..3dbdc8b22 100644
--- a/app/assets/javascripts/practice_editor_risk_mitigation.es6
+++ b/app/assets/javascripts/practice_editor_risk_mitigation.es6
@@ -14,7 +14,6 @@
$document.arrive('.fields', (newElement) => {
// add separator to previous element if another risk mitigation exists
$(newElement).appendTo('#sortable_risk_mitigations');
- initSortable('#sortable_risk_mitigations');
let multipleRiskMitigationExists = $('.practice-editor-risk-mitigation-li').length >= 1
if (multipleRiskMitigationExists) {
let separator = ''
@@ -48,28 +47,6 @@
});
}
- function dragAndDropRiskMitigationListItems() {
- initSortable('#sortable_risk_mitigations');
-
- if (typeof sortable('#sortable_risk_mitigations')[0] != 'undefined') {
- sortable('#sortable_risk_mitigations')[0].addEventListener('sortstart', function (e) {
- console.log('starting sort', e)
- });
-
- sortable('#sortable_risk_mitigations')[0].addEventListener('sortupdate', function (e) {
- $(this).children('li').map(function (index) {
- $(this).find('.risk-mitigation-position').val(index + 1)
- return "risk_mitigations[]=" + $(this).data("id");
- }).get().join("&");
- // Rails.ajax({
- // url: $(this).data("url"),
- // type: "PATCH",
- // data: dataIDList,
- // });
- });
- }
- }
-
function attachDeleteEntryHandler(elem) {
$(elem).on('click', (e) => {
let $previousLi = $(e.target).closest('.practice-editor-risk-mitigation-li').filter(":visible").prev('.practice-editor-risk-mitigation-li').filter(":visible");
@@ -94,7 +71,6 @@
function loadPracticeEditorRiskMitiFunctions() {
hideAddLinksAndShowRiskMitiFields();
attachDeleteEntryHandler('.risk-mitigation-trash');
- // dragAndDropRiskMitigationListItems();
}
$document.on('turbolinks:load', loadPracticeEditorRiskMitiFunctions);
diff --git a/app/assets/javascripts/practice_editor_timeline.es6 b/app/assets/javascripts/practice_editor_timeline.es6
index 3ad297a8b..31e3ffebd 100644
--- a/app/assets/javascripts/practice_editor_timeline.es6
+++ b/app/assets/javascripts/practice_editor_timeline.es6
@@ -4,7 +4,6 @@
function removeBulletPointFromNewLi() {
$document.arrive('.practice-editor-timeline-li', (newElem) => {
$(newElem).appendTo('#sortable_timelines');
- initSortable('#sortable_timelines');
$(newElem).css('list-style', 'none')
$document.unbindArrive('.practice-editor-timeline-li', newElem);
});
diff --git a/app/views/practices/_contact.js.erb b/app/views/practices/_contact.js.erb
index 66c6af0ef..2376f3519 100644
--- a/app/views/practices/_contact.js.erb
+++ b/app/views/practices/_contact.js.erb
@@ -72,7 +72,6 @@ function showFieldsOnPageLoad() {
<% if @practice.va_employees.empty? %>
$('.add-va-employee-link').click();
$('.practice-editor-contact-li').appendTo('#sortable_contacts');
- initSortable('#sortable_contacts');
<% end %>
}
diff --git a/app/views/practices/form/about.html.erb b/app/views/practices/form/about.html.erb
index d7c2d25e0..7df43ea99 100644
--- a/app/views/practices/form/about.html.erb
+++ b/app/views/practices/form/about.html.erb
@@ -39,7 +39,7 @@
-
+
<%= f.fields_for :va_employees, wrapper: false do |vae| %>
<%
vae_id = vae.object.id || "new_va_employees"
@@ -60,7 +60,7 @@
<% end %>
<% end %>
<% end %>
- - role="option" data-id="<%= vae_id %>">
+
- data-id="<%= vae_id %>">