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 %>">
      @@ -122,7 +122,7 @@
      -
        +
          <%= f.fields_for :practice_emails, wrapper: false do |pe| %> <% pe_id = pe.object.id || "new_practice_emails" @@ -143,7 +143,7 @@ <% end %> <% end %> <% end %> -
        • role="option" data-id="<%= pe_id %>"> +
        • data-id="<%= pe_id %>">
          <%= pe.label :address, 'Copied (cc’ed) email address', class: 'usa-label pe-address-label margin-top-0' %> diff --git a/app/views/practices/implementation_forms/_resources.html.erb b/app/views/practices/implementation_forms/_resources.html.erb index 01345ce89..fc48cc706 100644 --- a/app/views/practices/implementation_forms/_resources.html.erb +++ b/app/views/practices/implementation_forms/_resources.html.erb @@ -1,6 +1,3 @@ -<% provide :head_tags do %> - <%= javascript_include_tag '_practice_editor_utilities', 'data-turbolinks-track': 'reload' %> -<% end %> <% resource_type = resource_type resource_type_label = resource_type_label diff --git a/app/views/practices/implementation_forms/_risks_and_mitigations.html.erb b/app/views/practices/implementation_forms/_risks_and_mitigations.html.erb index 2e3346602..b9262f221 100644 --- a/app/views/practices/implementation_forms/_risks_and_mitigations.html.erb +++ b/app/views/practices/implementation_forms/_risks_and_mitigations.html.erb @@ -1,6 +1,5 @@ <% provide :head_tags do %> <%= javascript_include_tag 'practice_editor_risk_mitigation', 'data-turbolinks-track': 'reload' %> - <%= javascript_include_tag '_practice_editor_utilities', 'data-turbolinks-track': 'reload' %> <% end %>
          @@ -10,7 +9,7 @@

          Risks and Mitigations -
            +
              <%= f.fields_for :risk_mitigations, wrapper: false do |rm| %> <% rm_id = rm.object.id @@ -35,7 +34,7 @@ <% end %> <% end %> <% end %> -
            • +
            • <%= rm.hidden_field :id %> <%= rm.hidden_field :position, class: 'risk-mitigation-position' %>
              diff --git a/app/views/practices/implementation_forms/_timeline.html.erb b/app/views/practices/implementation_forms/_timeline.html.erb index f4d65b6b4..7a42230bc 100644 --- a/app/views/practices/implementation_forms/_timeline.html.erb +++ b/app/views/practices/implementation_forms/_timeline.html.erb @@ -1,6 +1,5 @@ <% provide :head_tags do %> <%= javascript_include_tag 'practice_editor_timeline', 'data-turbolinks-track': 'reload' %> - <%= javascript_include_tag '_practice_editor_utilities', 'data-turbolinks-track': 'reload' %> <% end %>
              @@ -12,7 +11,7 @@
              Timeline
              -
                +
                  <%= f.fields_for :timelines, wrapper: false do |tl| %> <% tl_id = tl.object.id diff --git a/app/views/practices/introduction_forms/_other_categories.html.erb b/app/views/practices/introduction_forms/_other_categories.html.erb index ea02229a4..f387de922 100644 --- a/app/views/practices/introduction_forms/_other_categories.html.erb +++ b/app/views/practices/introduction_forms/_other_categories.html.erb @@ -1,6 +1,3 @@ -<% provide :head_tags do %> - <%= javascript_include_tag '_practice_editor_utilities', 'data-turbolinks-track': 'reload' %> -<% end %> <% parent_category_name = parent_category.name.downcase parent_category_id = parent_category.id