Rev 1 | AutorÃa | Comparar con el anterior | Ultima modificación | Ver Log |
{"version":3,"file":"sortable_list.min.js","sources":["../src/sortable_list.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * A javascript module to handle list items drag and drop\n *\n * Example of usage:\n *\n * Create a list (for example `<ul>` or `<tbody>`) where each draggable element has a drag handle.\n * The best practice is to use
the template core/drag_handle:\n * $OUTPUT->render_from_template('core/drag_handle', ['movetitle' => get_string('movecontent', 'moodle', ELEMENTNAME)]);\n *\n * Attach this JS module to this list:\n *\n * Space between define and ( critical in comment but not allowed in code in order to function\n * correctly with Moodle's requirejs.php\n *\n * For the full list of possible parameters see var defaultParameters below.\n *\n * The following jQuery events are fired:\n * - SortableList.EVENTS.DRAGSTART : when user started dragging a list element\n * - SortableList.EVENTS.DRAG : when user dragged a list element to a new position\n * - SortableList.EVENTS.DROP : when user dropped a list element\n * - SortableList.EVENTS.DROPEND : when user finished dragging - either fired right after dropping or\n * if \"Esc\" was pressed during dragging\n *\n * @example\n * define (['jquery', 'core/sortable_list'], function($, SortableList) {\n * var list = new SortableList('ul.my-awesome-list'); //
source list (usually <ul> or <tbody>) - selector or element\n *\n * // Listen to the events when element is dragged.\n * $('ul.my-awesome-list > *').on(SortableList.EVENTS.DROP, function(evt, info) {\n * console.log(info);\n * });\n *\n * // Advanced usage. Overwrite methods getElementName, getDestinationName, moveDialogueTitle, for example:\n * list.getElementName = function(element) {\n * return $.Deferred().resolve(element.attr('data-name'));\n * }\n * });\n *\n * @module core/sortable_list\n * @class core/sortable_list\n * @copyright 2018 Marina Glancy\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([\n 'jquery',\n 'core/log',\n 'core/autoscroll',\n 'core/event_dispatcher',\n 'core/str',\n 'core/modal_cancel',\n 'core/modal_events',\n 'core/notification',\n], function($, log, autoScroll, EventDispatcher, str, ModalCancel, ModalEvents, Notification) {\n\n /**\n * Default parameters\n
*\n * @private\n * @type {Object}\n */\n var defaultParameters = {\n targetListSelector: null,\n moveHandlerSelector: '[data-drag-type=move]',\n isHorizontal: false,\n autoScroll: true\n };\n\n /**\n * Class names for different elements that may be changed during sorting\n *\n * @private\n * @type {Object}\n */\n var CSS = {\n keyboardDragClass: 'dragdrop-keyboard-drag',\n isDraggedClass: 'sortable-list-is-dragged',\n isDroppedClass: 'sortable-list-is-dropped',\n currentPositionClass: 'sortable-list-current-position',\n sourceListClass: 'sortable-list-source',\n targetListClass: 'sortable-list-target',\n overElementClass: 'sortable-list-over-element'\n };\n\n /**\n * Test the browser support for options objects on event listeners.\n * @return {Boolean}\n */\n var eventListenerOptionsSupported = function() {\n var passivesupported = false,\n options,\n
testeventname = \"testpassiveeventoptions\";\n\n // Options support testing example from:\n // https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener\n\n try {\n options = Object.defineProperty({}, \"passive\", {\n // eslint-disable-next-line getter-return\n get: function() {\n passivesupported = true;\n }\n });\n\n // We use an event name that is not likely to conflict with any real event.\n document.addEventListener(testeventname, options, options);\n // We remove the event listener as we have tested the options already.\n document.removeEventListener(testeventname, options, options);\n } catch (err) {\n // It's already false.\n passivesupported = false;\n }\n return passivesupported;\n };\n\n /**\n * Allow to create non-passive touchstart listeners and prevent page scrol
ling when dragging\n * From: https://stackoverflow.com/a/48098097\n *\n * @param {string} eventname\n * @returns {object}\n */\n var registerNotPassiveListeners = function(eventname) {\n return {\n setup: function(x, ns, handle) {\n if (ns.includes('notPassive')) {\n this.addEventListener(eventname, handle, {passive: false});\n return true;\n } else {\n return false;\n }\n }\n };\n };\n\n if (eventListenerOptionsSupported) {\n $.event.special.touchstart = registerNotPassiveListeners('touchstart');\n $.event.special.touchmove = registerNotPassiveListeners('touchmove');\n $.event.special.touchend = registerNotPassiveListeners('touchend');\n }\n\n /**\n * Initialise sortable list.\n *\n * @param {(String|jQuery|Element)} root JQuery/DOM element representing sortable list (i.e. <ul>, <tbody>) or CSS selector\n
* @param {Object} config Parameters for the list. See defaultParameters above for examples.\n * @param {(String|jQuery|Element)} config.targetListSelector target lists, by default same as root\n * @param {String} config.moveHandlerSelector CSS selector for a drag handle. By default '[data-drag-type=move]'\n * @param {String} config.listSelector CSS selector for target lists. By default the same as root\n * @param {(Boolean|Function)} config.isHorizontal Set to true if the list is horizontal (can also be a callback\n * with list as an argument)\n * @param {Boolean} config.autoScroll Engages autoscroll module for automatic vertical scrolling of the whole page,\n * by default true\n */\n var SortableList = function(root, config) {\n\n this.info = null;\n this.proxy = null;\n this.proxyDelta = null;\n this.dragCounter = 0;\n this.lastEvent = null;\n\n
this.config = $.extend({}, defaultParameters, config || {});\n this.config.listSelector = root;\n if (!this.config.targetListSelector) {\n this.config.targetListSelector = root;\n }\n if (typeof this.config.listSelector === 'object') {\n // The root is an element on the page. Register a listener for this element.\n $(this.config.listSelector).on('mousedown touchstart.notPassive', $.proxy(this.dragStartHandler, this));\n } else {\n // The root is a CSS selector. Register a listener that picks up the element dynamically.\n $('body').on('mousedown touchstart.notPassive', this.config.listSelector, $.proxy(this.dragStartHandler, this));\n }\n if (this.config.moveHandlerSelector !== null) {\n $('body').on('click keypress', this.config.moveHandlerSelector, $.proxy(this.clickHandler, this));\n }\n\n };\n\n /**\n * Events fired by this entity\n *\n * @public\n * @type {O
bject}\n */\n SortableList.EVENTS = {\n // Legacy jQuery events.\n DRAGSTART: 'sortablelist-dragstart',\n DRAG: 'sortablelist-drag',\n DROP: 'sortablelist-drop',\n DRAGEND: 'sortablelist-dragend',\n // Native Javascript events.\n elementDragStart: 'core/sortable_list:dragStart',\n elementDrag: 'core/sortable_list:drag',\n elementDrop: 'core/sortable_list:drop',\n elementDragEnd: 'core/sortable_list:dragEnd',\n };\n\n /**\n * Resets the temporary classes assigned during dragging\n * @private\n */\n SortableList.prototype.resetDraggedClasses = function() {\n var classes = [\n CSS.isDraggedClass,\n CSS.currentPositionClass,\n CSS.overElementClass,\n CSS.targetListClass,\n ];\n for (var i in classes) {\n $('.' + classes[i]).removeClass(classes[i]);\n }\n if (this.proxy) {\n this.proxy.remove();\n this.pro
xy = $();\n }\n };\n\n /**\n * Calculates evt.pageX, evt.pageY, evt.clientX and evt.clientY\n *\n * For touch events pageX and pageY are taken from the first touch;\n * For the emulated mousemove event they are taken from the last real event.\n *\n * @private\n * @param {Event} evt\n */\n SortableList.prototype.calculatePositionOnPage = function(evt) {\n\n if (evt.originalEvent && evt.originalEvent.touches && evt.originalEvent.touches[0] !== undefined) {\n // This is a touchmove or touchstart event, get position from the first touch position.\n var touch = evt.originalEvent.touches[0];\n evt.pageX = touch.pageX;\n evt.pageY = touch.pageY;\n }\n\n if (evt.pageX === undefined) {\n // Information is not present in case of touchend or when event was emulated by autoScroll.\n // Take the absolute mouse position from the last event.\n evt.pageX = this.lastEvent.pageX;\n
evt.pageY = this.lastEvent.pageY;\n } else {\n this.lastEvent = evt;\n }\n\n if (evt.clientX === undefined) {\n // If not provided in event calculate relative mouse position.\n evt.clientX = Math.round(evt.pageX - $(window).scrollLeft());\n evt.clientY = Math.round(evt.pageY - $(window).scrollTop());\n }\n };\n\n /**\n * Handler from dragstart event\n *\n * @private\n * @param {Event} evt\n */\n SortableList.prototype.dragStartHandler = function(evt) {\n if (this.info !== null) {\n if (this.info.type === 'click' || this.info.type === 'touchend') {\n // Ignore double click.\n return;\n }\n // Mouse down or touch while already dragging, cancel previous dragging.\n this.moveElement(this.info.sourceList, this.info.sourceNextElement);\n this.finishDragging();\n }\n\n if (evt.type === 'mousedown' &&
evt.which !== 1) {\n // We only need left mouse click. If this is a mousedown event with right/middle click ignore it.\n return;\n }\n\n this.calculatePositionOnPage(evt);\n var movedElement = $(evt.target).closest($(evt.currentTarget).children());\n if (!movedElement.length) {\n // Can't find the element user wants to drag. They clicked on the list but outside of any element of the list.\n return;\n }\n\n // Check that we grabbed the element by the handle.\n if (this.config.moveHandlerSelector !== null) {\n if (!$(evt.target).closest(this.config.moveHandlerSelector, movedElement).length) {\n return;\n }\n }\n\n evt.stopPropagation();\n evt.preventDefault();\n\n // Information about moved element with original location.\n // This object is passed to event observers.\n this.dragCounter++;\n this.info = {\n element: movedEl
ement,\n sourceNextElement: movedElement.next(),\n sourceList: movedElement.parent(),\n targetNextElement: movedElement.next(),\n targetList: movedElement.parent(),\n type: evt.type,\n dropped: false,\n startX: evt.pageX,\n startY: evt.pageY,\n startTime: new Date().getTime()\n };\n\n $(this.config.targetListSelector).addClass(CSS.targetListClass);\n\n var offset = movedElement.offset();\n movedElement.addClass(CSS.currentPositionClass);\n this.proxyDelta = {x: offset.left - evt.pageX, y: offset.top - evt.pageY};\n this.proxy = $();\n var thisDragCounter = this.dragCounter;\n setTimeout($.proxy(function() {\n // This mousedown event may in fact be a beginning of a 'click' event. Use timeout before showing the\n // dragged object so we can catch click event. When timeout finishes make sure that click event\n // has not happe
ned during this half a second.\n // Verify dragcounter to make sure the user did not manage to do two very fast drag actions one after another.\n if (this.info === null || this.info.type === 'click' || this.info.type === 'keypress'\n || this.dragCounter !== thisDragCounter) {\n return;\n }\n\n // Create a proxy - the copy of the dragged element that moves together with a mouse.\n this.createProxy();\n }, this), 500);\n\n // Start drag.\n $(window).on('mousemove touchmove.notPassive mouseup touchend.notPassive', $.proxy(this.dragHandler, this));\n $(window).on('keypress', $.proxy(this.dragcancelHandler, this));\n\n // Start autoscrolling. Every time the page is scrolled emulate the mousemove event.\n if (this.config.autoScroll) {\n autoScroll.start(function() {\n $(window).trigger('mousemove');\n });\n }\n\n this.executeCallback(So
rtableList.EVENTS.elementDragStart);\n };\n\n /**\n * Creates a \"proxy\" object - a copy of the element that is being moved that always follows the mouse\n * @private\n */\n SortableList.prototype.createProxy = function() {\n this.proxy = this.info.element.clone();\n this.info.sourceList.append(this.proxy);\n this.proxy.removeAttr('id').removeClass(CSS.currentPositionClass)\n .addClass(CSS.isDraggedClass).css({position: 'fixed'});\n this.proxy.offset({top: this.proxyDelta.y + this.lastEvent.pageY, left: this.proxyDelta.x + this.lastEvent.pageX});\n };\n\n /**\n * Handler for click event - when user clicks on the drag handler or presses Enter on keyboard\n *\n * @private\n * @param {Event} evt\n */\n SortableList.prototype.clickHandler = function(evt) {\n if (evt.type === 'keypress' && evt.originalEvent.keyCode !== 13 && evt.originalEvent.keyCode !== 32) {\n return;\n }\n if (this.info !==
null) {\n // Ignore double click.\n return;\n }\n\n // Find the element that this draghandle belongs to.\n var clickedElement = $(evt.target).closest(this.config.moveHandlerSelector),\n sourceList = clickedElement.closest(this.config.listSelector),\n movedElement = clickedElement.closest(sourceList.children());\n if (!movedElement.length) {\n return;\n }\n\n evt.preventDefault();\n evt.stopPropagation();\n\n // Store information about moved element with original location.\n this.dragCounter++;\n this.info = {\n element: movedElement,\n sourceNextElement: movedElement.next(),\n sourceList: sourceList,\n targetNextElement: movedElement.next(),\n targetList: sourceList,\n dropped: false,\n type: evt.type,\n startTime: new Date().getTime()\n };\n\n this.executeCallback(SortableList.EVENTS
.elementDragStart);\n this.displayMoveDialogue(clickedElement);\n };\n\n /**\n * Finds the position of the mouse inside the element - on the top, on the bottom, on the right or on the left\\\n *\n * Used to determine if the moved element should be moved after or before the current element\n *\n * @private\n * @param {Number} pageX\n * @param {Number} pageY\n * @param {jQuery} element\n * @returns {(Object|null)}\n */\n SortableList.prototype.getPositionInNode = function(pageX, pageY, element) {\n if (!element.length) {\n return null;\n }\n var node = element[0],\n offset = 0,\n rect = node.getBoundingClientRect(),\n y = pageY - (rect.top + window.scrollY),\n x = pageX - (rect.left + window.scrollX);\n if (x >= -offset && x <= rect.width + offset && y >= -offset && y <= rect.height + offset) {\n return {\n x: x,\n y: y,\n
xRatio: rect.width ? (x / rect.width) : 0,\n yRatio: rect.height ? (y / rect.height) : 0\n };\n }\n return null;\n };\n\n /**\n * Check if list is horizontal\n *\n * @param {jQuery} element\n * @return {Boolean}\n */\n SortableList.prototype.isListHorizontal = function(element) {\n var isHorizontal = this.config.isHorizontal;\n if (isHorizontal === true || isHorizontal === false) {\n return isHorizontal;\n }\n return isHorizontal(element);\n };\n\n /**\n * Handler for events mousemove touchmove mouseup touchend\n *\n * @private\n * @param {Event} evt\n */\n SortableList.prototype.dragHandler = function(evt) {\n\n evt.preventDefault();\n evt.stopPropagation();\n\n this.calculatePositionOnPage(evt);\n\n // We can not use evt.target here because it will most likely be our proxy.\n // Move the proxy out of the way so we can find the eleme
nt at the current mouse position.\n this.proxy.offset({top: -1000, left: -1000});\n // Find the element at the current mouse position.\n var element = $(document.elementFromPoint(evt.clientX, evt.clientY));\n\n // Find the list element and the list over the mouse position.\n var mainElement = this.info.element[0],\n isNotSelf = function() {\n return this !== mainElement;\n },\n current = element.closest('.' + CSS.targetListClass + ' > :not(.' + CSS.isDraggedClass + ')').filter(isNotSelf),\n currentList = element.closest('.' + CSS.targetListClass),\n proxy = this.proxy,\n isNotProxy = function() {\n return !proxy || !proxy.length || this !== proxy[0];\n };\n\n // Add the specified class to the list element we are hovering.\n $('.' + CSS.overElementClass).removeClass(CSS.overElementClass);\n current.addClass(CSS.overElementClass);\n\n // Move
proxy to the current position.\n this.proxy.offset({top: this.proxyDelta.y + evt.pageY, left: this.proxyDelta.x + evt.pageX});\n\n if (currentList.length && !currentList.children().filter(isNotProxy).length) {\n // Mouse is over an empty list.\n this.moveElement(currentList, $());\n } else if (current.length === 1 && !this.info.element.find(current[0]).length) {\n // Mouse is over an element in a list - find whether we should move the current position\n // above or below this element.\n var coordinates = this.getPositionInNode(evt.pageX, evt.pageY, current);\n if (coordinates) {\n var parent = current.parent(),\n ratio = this.isListHorizontal(parent) ? coordinates.xRatio : coordinates.yRatio,\n subList = current.find('.' + CSS.targetListClass),\n subListEmpty = !subList.children().filter(isNotProxy).filter(isNotSelf).length;\n if (subLis
t.length && subListEmpty && ratio > 0.2 && ratio < 0.8) {\n // This is an element that is a parent of an empty list and we are around the middle of this element.\n // Treat it as if we are over this empty list.\n this.moveElement(subList, $());\n } else if (ratio > 0.5) {\n // Insert after this element.\n this.moveElement(parent, current.next().filter(isNotProxy));\n } else {\n // Insert before this element.\n this.moveElement(parent, current);\n }\n }\n }\n\n if (evt.type === 'mouseup' || evt.type === 'touchend') {\n // Drop the moved element.\n this.info.endX = evt.pageX;\n this.info.endY = evt.pageY;\n this.info.endTime = new Date().getTime();\n this.info.dropped = true;\n this.info.positionChanged = this.hasPositionChanged(this.info);\n
var oldinfo = this.info;\n this.executeCallback(SortableList.EVENTS.elementDrop);\n this.finishDragging();\n\n if (evt.type === 'touchend'\n && this.config.moveHandlerSelector !== null\n && (oldinfo.endTime - oldinfo.startTime < 500)\n && !oldinfo.positionChanged) {\n // The click event is not triggered on touch screens because we call preventDefault in touchstart handler.\n // If the touchend quickly followed touchstart without moving, consider it a \"click\".\n this.clickHandler(evt);\n } else if (oldinfo.positionChanged) {\n mainElement.classList.add(CSS.isDroppedClass);\n }\n }\n };\n\n /**\n * Checks if the position of the dragged element in the list has changed\n *\n * @private\n * @param {Object} info\n * @return {Boolean}\n */\n SortableList.prototype.hasPositionChanged = function(info)
{\n return info.sourceList[0] !== info.targetList[0] ||\n info.sourceNextElement.length !== info.targetNextElement.length ||\n (info.sourceNextElement.length && info.sourceNextElement[0] !== info.targetNextElement[0]);\n };\n\n /**\n * Moves the current position of the dragged element\n *\n * @private\n * @param {jQuery} parentElement\n * @param {jQuery} beforeElement\n */\n SortableList.prototype.moveElement = function(parentElement, beforeElement) {\n var dragEl = this.info.element;\n if (beforeElement.length && beforeElement[0] === dragEl[0]) {\n // Insert before the current position of the dragged element - nothing to do.\n return;\n }\n if (parentElement[0] === this.info.targetList[0] &&\n beforeElement.length === this.info.targetNextElement.length &&\n beforeElement[0] === this.info.targetNextElement[0]) {\n // Insert in the same location as the curren
t position - nothing to do.\n return;\n }\n\n if (beforeElement.length) {\n // Move the dragged element before the specified element.\n parentElement[0].insertBefore(dragEl[0], beforeElement[0]);\n } else if (this.proxy && this.proxy.parent().length && this.proxy.parent()[0] === parentElement[0]) {\n // We need to move to the end of the list but the last element in this list is a proxy.\n // Always leave the proxy in the end of the list.\n parentElement[0].insertBefore(dragEl[0], this.proxy[0]);\n } else {\n // Insert in the end of a list (when proxy is in another list).\n parentElement[0].appendChild(dragEl[0]);\n }\n\n // Save the current position of the dragged element in the list.\n this.info.targetList = parentElement;\n this.info.targetNextElement = beforeElement;\n this.executeCallback(SortableList.EVENTS.elementDrag);\n };\n\n /**\n * Finish
dragging (when dropped or cancelled).\n * @private\n */\n SortableList.prototype.finishDragging = function() {\n this.resetDraggedClasses();\n if (this.config.autoScroll) {\n autoScroll.stop();\n }\n $(window).off('mousemove touchmove.notPassive mouseup touchend.notPassive', $.proxy(this.dragHandler, this));\n $(window).off('keypress', $.proxy(this.dragcancelHandler, this));\n this.executeCallback(SortableList.EVENTS.elementDragEnd);\n this.info = null;\n };\n\n /**\n * Executes callback specified in sortable list parameters\n *\n * @private\n * @param {String} eventName\n */\n SortableList.prototype.executeCallback = function(eventName) {\n EventDispatcher.dispatchEvent(eventName, this.info, this.info.element[0]);\n\n // The following event trigger is legacy and will be removed in the future.\n // This approach provides a backwards-compatibility layer for the new events.\n // Code
should be updated to make use of native events.\n const legacyEventNamesMap = new Map([\n [SortableList.EVENTS.elementDragStart, SortableList.EVENTS.DRAGSTART],\n [SortableList.EVENTS.elementDrag, SortableList.EVENTS.DRAG],\n [SortableList.EVENTS.elementDrop, SortableList.EVENTS.DROP],\n [SortableList.EVENTS.elementDragEnd, SortableList.EVENTS.DRAGEND],\n ]);\n this.info.element.trigger(legacyEventNamesMap.get(eventName), this.info);\n };\n\n /**\n * Handler from keypress event (cancel dragging when Esc is pressed)\n *\n * @private\n * @param {Event} evt\n */\n SortableList.prototype.dragcancelHandler = function(evt) {\n if (evt.type !== 'keypress' || evt.originalEvent.keyCode !== 27) {\n // Only cancel dragging when Esc was pressed.\n return;\n }\n // Dragging was cancelled. Return item to the original position.\n this.moveElement(this.info.sourceList, this.info.sou
rceNextElement);\n this.finishDragging();\n };\n\n /**\n * Returns the name of the current element to be used in the move dialogue\n *\n * @public\n * @param {jQuery} element\n * @return {Promise}\n */\n SortableList.prototype.getElementName = function(element) {\n return $.Deferred().resolve(element.text());\n };\n\n /**\n * Returns the label for the potential move destination, i.e. \"After ElementX\" or \"To the top of the list\"\n *\n * Note that we use \"after\" in the label for better UX\n *\n * @public\n * @param {jQuery} parentElement\n * @param {jQuery} afterElement\n * @return {Promise}\n */\n SortableList.prototype.getDestinationName = function(parentElement, afterElement) {\n if (!afterElement.length) {\n return str.get_string('movecontenttothetop', 'moodle');\n } else {\n return this.getElementName(afterElement)\n .then(function(name) {\n
return str.get_string('movecontentafter', 'moodle', name);\n });\n }\n };\n\n /**\n * Returns the title for the move dialogue (\"Move elementY\")\n *\n * @public\n * @param {jQuery} element\n * @param {jQuery} handler\n * @return {Promise}\n */\n SortableList.prototype.getMoveDialogueTitle = function(element, handler) {\n if (handler.attr('title')) {\n return $.Deferred().resolve(handler.attr('title'));\n }\n return this.getElementName(element).then(function(name) {\n return str.get_string('movecontent', 'moodle', name);\n });\n };\n\n /**\n * Returns the list of possible move destinations\n *\n * @private\n * @return {Promise}\n */\n SortableList.prototype.getDestinationsList = function() {\n var addedLists = [],\n targets = $(this.config.targetListSelector),\n destinations = $('<ul/>').addClass(CSS.keyboardDragClass),\n result =
$.when().then(function() {\n return destinations;\n }),\n createLink = $.proxy(function(parentElement, beforeElement, afterElement) {\n if (beforeElement.is(this.info.element) || afterElement.is(this.info.element)) {\n // Can not move before or after itself.\n return;\n }\n if ($.contains(this.info.element[0], parentElement[0])) {\n // Can not move to its own child.\n return;\n }\n result = result\n .then($.proxy(function() {\n return this.getDestinationName(parentElement, afterElement);\n }, this))\n .then(function(txt) {\n var li = $('<li/>').appendTo(destinations);\n var a = $('<a href=\"#\"/>').attr('data-core_sortable_list-quickmove', 1).appendTo(li);\n a.data('parent-element', parentElement).data('b
efore-element', beforeElement).text(txt);\n return destinations;\n });\n }, this),\n addList = function() {\n // Destination lists may be nested. We want to add all move destinations in the same\n // order they appear on the screen for the user.\n if ($.inArray(this, addedLists) !== -1) {\n return;\n }\n addedLists.push(this);\n var list = $(this),\n children = list.children();\n children.each(function() {\n var element = $(this);\n createLink(list, element, element.prev());\n // Add all nested lists.\n element.find(targets).each(addList);\n });\n createLink(list, $(), children.last());\n };\n targets.each(addList);\n return result;\n };\n\n /**\n * Displays the dialogue to
move element.\n * @param {jQuery} clickedElement element to return focus to after the modal is closed\n * @private\n */\n SortableList.prototype.displayMoveDialogue = function(clickedElement) {\n ModalCancel.create({\n title: this.getMoveDialogueTitle(this.info.element, clickedElement),\n body: this.getDestinationsList()\n }).then($.proxy(function(modal) {\n var quickMoveHandler = $.proxy(function(e) {\n e.preventDefault();\n e.stopPropagation();\n this.moveElement($(e.currentTarget).data('parent-element'), $(e.currentTarget).data('before-element'));\n this.info.endTime = new Date().getTime();\n this.info.positionChanged = this.hasPositionChanged(this.info);\n this.info.dropped = true;\n clickedElement.focus();\n this.executeCallback(SortableList.EVENTS.elementDrop);\n modal.hide();\n }, this);\n
modal.getRoot().on('click', '[data-core_sortable_list-quickmove]', quickMoveHandler);\n modal.getRoot().on(ModalEvents.hidden, $.proxy(function() {\n // Always destroy when hidden, it is generated dynamically each time.\n modal.getRoot().off('click', '[data-core_sortable_list-quickmove]', quickMoveHandler);\n modal.destroy();\n this.finishDragging();\n }, this));\n modal.setLarge();\n modal.show();\n return modal;\n }, this)).catch(Notification.exception);\n };\n\n return SortableList;\n\n});\n"],"names":["define","$","log","autoScroll","EventDispatcher","str","ModalCancel","ModalEvents","Notification","defaultParameters","targetListSelector","moveHandlerSelector","isHorizontal","CSS","registerNotPassiveListeners","eventname","setup","x","ns","handle","includes","addEventListener","passive","options","passivesupported","Object","defineProperty","get","document","removeEventListe
ner","err","event","special","touchstart","touchmove","touchend","SortableList","root","config","info","proxy","proxyDelta","dragCounter","lastEvent","extend","listSelector","this","on","dragStartHandler","clickHandler","EVENTS","DRAGSTART","DRAG","DROP","DRAGEND","elementDragStart","elementDrag","elementDrop","elementDragEnd","prototype","resetDraggedClasses","classes","i","removeClass","remove","calculatePositionOnPage","evt","originalEvent","touches","undefined","touch","pageX","pageY","clientX","Math","round","window","scrollLeft","clientY","scrollTop","type","moveElement","sourceList","sourceNextElement","finishDragging","which","movedElement","target","closest","currentTarget","children","length","stopPropagation","preventDefault","element","next","parent","targetNextElement","targetList","dropped","startX","startY","startTime","Date","getTime","addClass","offset","left","y","top","thisDragCounter","setTimeout","createProxy","dragHandler","dragcancelHandler","start","trigger","executeCallback","clone",
"append","removeAttr","css","position","keyCode","clickedElement","displayMoveDialogue","getPositionInNode","rect","getBoundingClientRect","scrollY","scrollX","width","height","xRatio","yRatio","isListHorizontal","elementFromPoint","mainElement","isNotSelf","current","filter","currentList","isNotProxy","find","coordinates","ratio","subList","subListEmpty","endX","endY","endTime","positionChanged","hasPositionChanged","oldinfo","classList","add","parentElement","beforeElement","dragEl","insertBefore","appendChild","stop","off","eventName","dispatchEvent","legacyEventNamesMap","Map","getElementName","Deferred","resolve","text","getDestinationName","afterElement","then","name","get_string","getMoveDialogueTitle","handler","attr","getDestinationsList","addedLists","targets","destinations","result","when","createLink","is","contains","txt","li","appendTo","data","addList","inArray","push","list","each","prev","last","create","title","body","modal","quickMoveHandler","e","focus","hide","getRoot","hidden","destroy"
,"setLarge","show","catch","exception"],"mappings":"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"}