MDL-51803 core: integration review

This commit is contained in:
Marina Glancy 2018-10-02 11:23:18 +02:00
parent 539cb25050
commit 6b9cb2481c
4 changed files with 117 additions and 72 deletions

View File

@ -1 +1 @@
define(["jquery"],function(a){var b={SCROLL_THRESHOLD:30,SCROLL_FREQUENCY:1e3/60,SCROLL_SPEED:.5,scrollingId:null,scrollAmount:0,callback:null,start:function(c){a(window).on("mousemove",b.mouseMove),a(window).on("touchmove",b.touchMove),b.callback=c},stop:function(){a(window).off("mousemove",b.mouseMove),a(window).off("touchmove",b.touchMove),null!==b.scrollingId&&b.stopScrolling()},touchMove:function(a){for(var c=0;c<a.changedTouches.length;c++)b.handleMove(a.changedTouches[c].clientX,a.changedTouches[c].clientY)},mouseMove:function(a){b.handleMove(a.clientX,a.clientY)},handleMove:function(c,d){d<b.SCROLL_THRESHOLD?b.scrollAmount=-Math.min(b.SCROLL_THRESHOLD-d,b.SCROLL_THRESHOLD):d>a(window).height()-b.SCROLL_THRESHOLD?b.scrollAmount=Math.min(d-(a(window).height()-b.SCROLL_THRESHOLD),b.SCROLL_THRESHOLD):b.scrollAmount=0,b.scrollAmount&&null===b.scrollingId?b.startScrolling():b.scrollAmount||null===b.scrollingId||b.stopScrolling()},startScrolling:function(){var c=a(document).height-a(window).height;b.scrollingId=window.setInterval(function(){var d=a(window).scrollTop(),e=Math.round(b.scrollAmount*b.SCROLL_SPEED);if(d+e<0&&(e=-d),d+e>c&&(e=c-d),0!==e){a(window).scrollTop(d+e);var f=a(window).scrollTop()-d;0!==f&&b.callback&&b.callback(f)}},b.SCROLL_FREQUENCY)},stopScrolling:function(){window.clearInterval(b.scrollingId),b.scrollingId=null}};return b});
define(["jquery"],function(a){var b={SCROLL_THRESHOLD:30,SCROLL_FREQUENCY:1e3/60,SCROLL_SPEED:.5,scrollingId:null,scrollAmount:0,callback:null,start:function(c){a(window).on("mousemove",b.mouseMove),a(window).on("touchmove",b.touchMove),b.callback=c},stop:function(){a(window).off("mousemove",b.mouseMove),a(window).off("touchmove",b.touchMove),null!==b.scrollingId&&b.stopScrolling()},touchMove:function(a){for(var c=0;c<a.changedTouches.length;c++)b.handleMove(a.changedTouches[c].clientX,a.changedTouches[c].clientY)},mouseMove:function(a){b.handleMove(a.clientX,a.clientY)},handleMove:function(c,d){d<b.SCROLL_THRESHOLD?b.scrollAmount=-Math.min(b.SCROLL_THRESHOLD-d,b.SCROLL_THRESHOLD):d>a(window).height()-b.SCROLL_THRESHOLD?b.scrollAmount=Math.min(d-(a(window).height()-b.SCROLL_THRESHOLD),b.SCROLL_THRESHOLD):b.scrollAmount=0,b.scrollAmount&&null===b.scrollingId?b.startScrolling():b.scrollAmount||null===b.scrollingId||b.stopScrolling()},startScrolling:function(){var c=a(document).height-a(window).height;b.scrollingId=window.setInterval(function(){var d=a(window).scrollTop(),e=Math.round(b.scrollAmount*b.SCROLL_SPEED);if(d+e<0&&(e=-d),d+e>c&&(e=c-d),0!==e){a(window).scrollTop(d+e);var f=a(window).scrollTop()-d;0!==f&&b.callback&&b.callback(f)}},b.SCROLL_FREQUENCY)},stopScrolling:function(){window.clearInterval(b.scrollingId),b.scrollingId=null}};return{start:b.start,stop:b.stop}});

File diff suppressed because one or more lines are too long

View File

@ -74,7 +74,7 @@ define(['jquery'], function($) {
* This should be called in response to mouse down or touch start.
*
* @public
* @param {Object} callback Optional callback that is called every time it scrolls
* @param {Function} callback Optional callback that is called every time it scrolls
*/
start: function(callback) {
$(window).on('mousemove', autoscroll.mouseMove);
@ -188,5 +188,22 @@ define(['jquery'], function($) {
}
};
return autoscroll;
return {
/**
* Starts automatic scrolling if user moves near edge of window.
* This should be called in response to mouse down or touch start.
*
* @public
* @param {Function} callback Optional callback that is called every time it scrolls
*/
start: autoscroll.start,
/**
* Stops automatic scrolling. This should be called in response to mouse up or touch end.
*
* @public
*/
stop: autoscroll.stop,
};
});

View File

@ -52,23 +52,11 @@ function($, log, autoScroll, str, ModalFactory, ModalEvents, Notification) {
/**
* Default parameters
*
* @property {String} listSelector CSS selector for sortable lists, must be specified during initialization.
* @property {String} moveHandlerSelector CSS selector for a drag handle. By default the whole item is a handle.
* Without drag handle sorting is not accessible!
* @property {Boolean|Function} isHorizontal Set to true if the list is horizontal
* (can also be a callback with list as an argument)
* @property {Boolean} autoScroll Engages autoscroll module for automatic vertical scrolling of the whole page
* @property {Function} elementNameCallback Should return a string or Promise. Used for move dialogue title and
* destination name
* @property {Function} destinationNameCallback Callback that returns a string or Promise with the label
* for the move destination
* @property {Function} moveDialogueTitleCallback Should return a string or Promise. Used to form move dialogue title
*
* @private
* @type {Object}
*/
var defaultParameters = {
listSelector: null,
targetListSelector: null,
moveHandlerSelector: null,
isHorizontal: false,
autoScroll: true,
@ -99,12 +87,12 @@ function($, log, autoScroll, str, ModalFactory, ModalEvents, Notification) {
* @type {Object}
*/
var CSS = {
keyboardDragClass: 'dragdrop-keyboard-drag', /* Class of the list of destinations in the popup */
isDraggedClass: 'sortable-list-is-dragged', /* Class added to the element that is dragged. */
currentPositionClass: 'sortable-list-current-position', /* Class added to the current position of a dragged element. */
sourceListClass: 'sortable-list-source', /* Class added to the list where dragging was started from. */
targetListClass: 'sortable-list-target', /* Class added to all lists where item can be dropped. */
overElementClass: 'sortable-list-over-element' /* Class added to the list element when the dragged element is above it. */
keyboardDragClass: 'dragdrop-keyboard-drag',
isDraggedClass: 'sortable-list-is-dragged',
currentPositionClass: 'sortable-list-current-position',
sourceListClass: 'sortable-list-source',
targetListClass: 'sortable-list-target',
overElementClass: 'sortable-list-over-element'
};
/**
@ -113,7 +101,7 @@ function($, log, autoScroll, str, ModalFactory, ModalEvents, Notification) {
* @private
* @type {Object}
*/
var params = {};
var config = {};
/**
* Stores information about currently dragged item
@ -152,14 +140,16 @@ function($, log, autoScroll, str, ModalFactory, ModalEvents, Notification) {
* @private
*/
var resetDraggedClasses = function() {
var lists = $(params.listSelector);
lists.children()
.removeClass(params.isDraggedClass)
.removeClass(params.currentPositionClass)
.removeClass(params.overElementClass);
lists
.removeClass(params.targetListClass)
.removeClass(params.sourceListClass);
var classes = [
config.isDraggedClass,
config.currentPositionClass,
config.overElementClass,
config.targetListClass,
config.sourceListClass
];
for (var i in classes) {
$('.' + classes[i]).removeClass(classes[i]);
}
if (proxy) {
proxy.remove();
proxy = $();
@ -213,7 +203,7 @@ function($, log, autoScroll, str, ModalFactory, ModalEvents, Notification) {
* @param {Event} evt
*/
var dragStartHandler = function(evt) {
params = evt.data.params;
config = evt.data.config;
if (info !== null) {
if (info.type === 'click') {
// Ignore double click.
@ -225,16 +215,20 @@ function($, log, autoScroll, str, ModalFactory, ModalEvents, Notification) {
}
if (evt.type === 'mousedown' && evt.which !== 1) {
// We only need left mouse click.
// We only need left mouse click. If this is a mousedown event with right/middle click ignore it.
return;
}
calculatePositionOnPage(evt);
var movedElement = $(evt.currentTarget);
var movedElement = $(evt.target).closest($(evt.currentTarget).children());
if (!movedElement.length) {
// Can't find the element user wants to drag. They clicked on the list but outside of any element of the list.
return;
}
// Check that we grabbed the element by the handle.
if (params.moveHandlerSelector !== null) {
if (!$(evt.target).closest(params.moveHandlerSelector, movedElement).length) {
if (config.moveHandlerSelector !== null) {
if (!$(evt.target).closest(config.moveHandlerSelector, movedElement).length) {
return;
}
}
@ -258,14 +252,18 @@ function($, log, autoScroll, str, ModalFactory, ModalEvents, Notification) {
startTime: new Date().getTime()
};
$(params.listSelector).addClass(params.targetListClass);
$(config.targetListSelector).addClass(config.targetListClass);
var offset = movedElement.offset();
movedElement.addClass(params.currentPositionClass);
movedElement.addClass(config.currentPositionClass);
proxyDelta = {x: offset.left - evt.pageX, y: offset.top - evt.pageY};
proxy = $();
var thisDragCounter = dragCounter;
setTimeout(function() {
// This mousedown event may in fact be a beginning of a 'click' event. Use timeout before showing the
// dragged object so we can catch click event. When timeout finishes make sure that click event
// has not happened during this half a second.
// Verify dragcounter to make sure the user did not manage to do two very fast drag actions one after another.
if (info === null || info.type === 'click' || info.type === 'keypress' || dragCounter !== thisDragCounter) {
return;
}
@ -279,8 +277,8 @@ function($, log, autoScroll, str, ModalFactory, ModalEvents, Notification) {
$('body').on('keypress', dragcancelHandler);
// Start autoscrolling. Every time the page is scrolled emulate the mousemove event.
if (params.autoScroll) {
autoScroll.start(function () {
if (config.autoScroll) {
autoScroll.start(function() {
$('body').trigger('mousemove');
});
}
@ -295,8 +293,8 @@ function($, log, autoScroll, str, ModalFactory, ModalEvents, Notification) {
var createProxy = function() {
proxy = info.element.clone();
info.sourceList.append(proxy);
proxy.removeAttr('id').removeClass(params.currentPositionClass)
.addClass(params.isDraggedClass).css({position: 'fixed'});
proxy.removeAttr('id').removeClass(config.currentPositionClass)
.addClass(config.isDraggedClass).css({position: 'fixed'});
proxy.offset({top: proxyDelta.y + lastEvent.pageY, left: proxyDelta.x + lastEvent.pageX});
};
@ -316,13 +314,11 @@ function($, log, autoScroll, str, ModalFactory, ModalEvents, Notification) {
}
evt.preventDefault();
evt.stopPropagation();
params = evt.data.params;
config = evt.data.config;
// Find the element that this draghandle belongs to.
var sourceList = $(evt.currentTarget).closest(params.listSelector),
movedElement = sourceList.children().filter(function() {
return $.contains(this, evt.currentTarget);
});
var sourceList = $(evt.currentTarget).closest(config.listSelector),
movedElement = $(evt.target).closest(sourceList.children());
if (!movedElement.length) {
return;
}
@ -392,7 +388,7 @@ function($, log, autoScroll, str, ModalFactory, ModalEvents, Notification) {
* @return {Boolean}
*/
var isListHorizontal = function(element) {
var isHorizontal = params.isHorizontal;
var isHorizontal = config.isHorizontal;
if (isHorizontal === true || isHorizontal === false) {
return isHorizontal;
}
@ -416,12 +412,12 @@ function($, log, autoScroll, str, ModalFactory, ModalEvents, Notification) {
var element = $(document.elementFromPoint(evt.clientX, evt.clientY));
// Find the list element and the list over the mouse position.
var current = element.closest('.' + params.targetListClass + ' > :not(.' + params.isDraggedClass + ')'),
currentList = element.closest('.' + params.targetListClass);
var current = element.closest('.' + config.targetListClass + ' > :not(.' + config.isDraggedClass + ')'),
currentList = element.closest('.' + config.targetListClass);
// Add the specified class to the list element we are hovering.
$('.' + params.overElementClass).removeClass(params.overElementClass);
current.addClass(params.overElementClass);
$('.' + config.overElementClass).removeClass(config.overElementClass);
current.addClass(config.overElementClass);
// Move proxy to the current position.
proxy.offset({top: proxyDelta.y + evt.pageY, left: proxyDelta.x + evt.pageX});
@ -436,7 +432,7 @@ function($, log, autoScroll, str, ModalFactory, ModalEvents, Notification) {
if (coordinates) {
var parent = current.parent(),
ratio = isListHorizontal(parent) ? coordinates.xRatio : coordinates.yRatio,
subList = current.find('.' + params.targetListClass),
subList = current.find('.' + config.targetListClass),
isNotCurrent = function() {
return this !== info.element[0];
},
@ -510,7 +506,7 @@ function($, log, autoScroll, str, ModalFactory, ModalEvents, Notification) {
*/
var finishDragging = function() {
resetDraggedClasses();
if (params.autoScroll) {
if (config.autoScroll) {
autoScroll.stop();
}
$('body').off('mousemove touchmove mouseup touchend', dragHandler);
@ -569,7 +565,7 @@ function($, log, autoScroll, str, ModalFactory, ModalEvents, Notification) {
* @return {Promise}
*/
var getElementName = function(element) {
return convertToPromise(params.elementNameCallback(element));
return convertToPromise(config.elementNameCallback(element));
};
/**
@ -583,7 +579,7 @@ function($, log, autoScroll, str, ModalFactory, ModalEvents, Notification) {
* @return {Promise}
*/
var getDestinationName = function(parentElement, afterElement) {
return convertToPromise(params.destinationNameCallback(parentElement, afterElement));
return convertToPromise(config.destinationNameCallback(parentElement, afterElement));
};
/**
@ -594,7 +590,7 @@ function($, log, autoScroll, str, ModalFactory, ModalEvents, Notification) {
* @return {Promise}
*/
var getMoveDialogueTitle = function(element) {
return convertToPromise(params.moveDialogueTitleCallback(element));
return convertToPromise(config.moveDialogueTitleCallback(element));
};
/**
@ -606,21 +602,21 @@ function($, log, autoScroll, str, ModalFactory, ModalEvents, Notification) {
*/
var getDestinationsList = function(modal) {
var addedLists = [],
targets = $(params.listSelector),
list = $('<ul/>').addClass(params.keyboardDragClass),
targets = $(config.targetListSelector),
list = $('<ul/>').addClass(config.keyboardDragClass),
createLink = function(parentElement, beforeElement, afterElement) {
if (beforeElement.is(info.element) || afterElement.is(info.element)) {
return;
}
var li = $('<li/>').appendTo(list);
var a = $('<a href="#"/>')
.click(function(e) {
.on('click', function(e) {
e.preventDefault();
e.stopPropagation();
moveElement(parentElement, beforeElement);
info.endTime = new Date().getTime();
info.dropped = true;
info.element.find(params.moveHandlerSelector).focus();
info.element.find(config.moveHandlerSelector).focus();
executeCallback('drop');
modal.hide();
})
@ -668,24 +664,56 @@ function($, log, autoScroll, str, ModalFactory, ModalEvents, Notification) {
modal.setLarge();
modal.show();
return modal;
});
}).catch(Notification.exception);
};
return {
/**
* Initialise sortable list.
*
* @param {Object} params Parameters for the list. See defaultParameters above for examples.
* @param {(String|jQuery|Element)} root JQuery/DOM element representing sortable list (i.e. <ul>, <tbody>) or CSS selector
* @param {Object} config Parameters for the list. See defaultParameters above for examples.
* @property {(String|jQuery|Element)} config.targetListSelector target lists, by default same as root
* @property {String} config.moveHandlerSelector CSS selector for a drag handle. By default the whole item is a handle.
* Without drag handle sorting is not accessible!
* @property {(Boolean|Function)} config.isHorizontal Set to true if the list is horizontal
* (can also be a callback with list as an argument)
* @property {Boolean} config.autoScroll Engages autoscroll module for automatic vertical scrolling of the
* whole page, by default true
* @property {Function} config.elementNameCallback Should return a string or Promise. Used for move dialogue title and
* destination name
* @property {Function} config.destinationNameCallback Callback that returns a string or Promise with the label
* for the move destination
* @property {Function} config.moveDialogueTitleCallback Should return a string or Promise. Used to form move dialogue title
* @property {String} config.keyboardDragClass Class of the list of destinations in the popup
* (default 'dragdrop-keyboard-drag')
* @property {String} config.isDraggedClass Class added to the element that is dragged
* (default 'sortable-list-is-dragged')
* @property {String} config.currentPositionClass Class added to the current position of a dragged element
* (default 'sortable-list-current-position')
* @property {String} config.sourceListClass Class added to the list where dragging was started from
* (default 'sortable-list-source')
* @property {String} config.targetListClass Class added to all lists where item can be dropped
* (default 'sortable-list-target')
* @property {String} config.overElementClass Class added to the list element when the dragged element is above it
* (default 'sortable-list-over-element')
*/
init: function(params) {
if (typeof params.listSelector === 'undefined') {
log.error('Parameter listSelector must be specified');
return;
init: function(root, config) {
if (typeof config === 'undefined' || !config) {
config = {};
}
params = $.extend({}, defaultParameters, CSS, params);
$(params.listSelector).on('mousedown touchstart', '> *', {params: params}, dragStartHandler);
if (params.moveHandlerSelector !== null) {
$(params.listSelector).on('click keypress', params.moveHandlerSelector, {params: params}, clickHandler);
config = $.extend({}, defaultParameters, CSS, config);
config.listSelector = root;
if (!config.targetListSelector) {
config.targetListSelector = root;
}
if (typeof config.listSelector === 'object') {
$(config.listSelector).on('mousedown touchstart', {config: config}, dragStartHandler);
} else {
$('body').on('mousedown touchstart', config.listSelector, {config: config}, dragStartHandler);
}
if (config.moveHandlerSelector !== null) {
$('body').on('click keypress', config.moveHandlerSelector, {config: config}, clickHandler);
}
}
};