123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439 |
- /**
- * Copyright © Magento, Inc. All rights reserved.
- * See COPYING.txt for license details.
- */
- /**
- * @api
- */
- define([
- 'ko',
- 'jquery',
- 'underscore',
- 'uiElement',
- 'Magento_Ui/js/lib/view/utils/async'
- ], function (ko, $, _, Element) {
- 'use strict';
- var transformProp;
- /**
- * Get element context
- */
- function getContext(elem) {
- return ko.contextFor(elem);
- }
- /**
- * Defines supported css 'transform' property.
- *
- * @returns {String|Undefined}
- */
- transformProp = (function () {
- var style = document.createElement('div').style,
- base = 'Transform',
- vendors = ['webkit', 'moz', 'ms', 'o'],
- vi = vendors.length,
- property;
- if (typeof style.transform !== 'undefined') {
- return 'transform';
- }
- while (vi--) {
- property = vendors[vi] + base;
- if (typeof style[property] !== 'undefined') {
- return property;
- }
- }
- })();
- return Element.extend({
- defaults: {
- separatorsClass: {
- top: '_dragover-top',
- bottom: '_dragover-bottom'
- },
- step: 'auto',
- tableClass: 'table.admin__dynamic-rows',
- recordsCache: [],
- draggableElement: {},
- draggableElementClass: '_dragged',
- elemPositions: [],
- listens: {
- '${ $.recordsProvider }:elems': 'setCacheRecords'
- },
- modules: {
- parentComponent: '${ $.recordsProvider }'
- }
- },
- /**
- * Initialize component
- *
- * @returns {Object} Chainable.
- */
- initialize: function () {
- _.bindAll(
- this,
- 'mousemoveHandler',
- 'mouseupHandler'
- );
- this._super()
- .body = $('body');
- return this;
- },
- /**
- * Calls 'initObservable' of parent, initializes 'options' and 'initialOptions'
- * properties, calls 'setOptions' passing options to it
- *
- * @returns {Object} Chainable.
- */
- initObservable: function () {
- this._super()
- .observe([
- 'recordsCache'
- ]);
- return this;
- },
- /**
- * Init listens to start drag
- *
- * @param {Object} elem - DOM element
- * @param {Object} data - element data
- */
- initListeners: function (elem, data) {
- $(elem).on('mousedown touchstart', this.mousedownHandler.bind(this, data, elem));
- },
- /**
- * Mouse down handler
- *
- * @param {Object} data - element data
- * @param {Object} elem - element
- * @param {Object} event - key down event
- */
- mousedownHandler: function (data, elem, event) {
- var recordNode = this.getRecordNode(elem),
- originRecord = $(elem).parents('tr').eq(0),
- drEl = this.draggableElement,
- $table = $(elem).parents('table').eq(0),
- $tableWrapper = $table.parent();
- this.disableScroll();
- $(recordNode).addClass(this.draggableElementClass);
- $(originRecord).addClass(this.draggableElementClass);
- this.step = this.step === 'auto' ? originRecord.height() / 2 : this.step;
- drEl.originRow = originRecord;
- drEl.instance = recordNode = this.processingStyles(recordNode, elem);
- drEl.instanceCtx = this.getRecord(originRecord[0]);
- drEl.eventMousedownY = this.getPageY(event);
- drEl.minYpos =
- $table.offset().top - originRecord.offset().top + $table.children('thead').outerHeight();
- drEl.maxYpos = drEl.minYpos + $table.children('tbody').outerHeight() - originRecord.outerHeight();
- $tableWrapper.append(recordNode);
- this.body.bind('mousemove touchmove', this.mousemoveHandler);
- this.body.bind('mouseup touchend', this.mouseupHandler);
- },
- /**
- * Mouse move handler
- *
- * @param {Object} event - mouse move event
- */
- mousemoveHandler: function (event) {
- var depEl = this.draggableElement,
- pageY = this.getPageY(event),
- positionY = pageY - depEl.eventMousedownY,
- processingPositionY = positionY + 'px',
- processingMaxYpos = depEl.maxYpos + 'px',
- processingMinYpos = depEl.minYpos + 'px',
- depElement = this.getDepElement(depEl.instance, positionY, depEl.originRow);
- if (depElement) {
- depEl.depElement ? depEl.depElement.elem.removeClass(depEl.depElement.className) : false;
- depEl.depElement = depElement;
- depEl.depElement.insert !== 'none' ? depEl.depElement.elem.addClass(depElement.className) : false;
- } else if (depEl.depElement && depEl.depElement.insert !== 'none') {
- depEl.depElement.elem.removeClass(depEl.depElement.className);
- depEl.depElement.insert = 'none';
- }
- if (positionY > depEl.minYpos && positionY < depEl.maxYpos) {
- $(depEl.instance)[0].style[transformProp] = 'translateY(' + processingPositionY + ')';
- } else if (positionY < depEl.minYpos) {
- $(depEl.instance)[0].style[transformProp] = 'translateY(' + processingMinYpos + ')';
- } else if (positionY >= depEl.maxYpos) {
- $(depEl.instance)[0].style[transformProp] = 'translateY(' + processingMaxYpos + ')';
- }
- },
- /**
- * Mouse up handler
- */
- mouseupHandler: function (event) {
- var depElementCtx,
- drEl = this.draggableElement,
- pageY = this.getPageY(event),
- positionY = pageY - drEl.eventMousedownY;
- this.enableScroll();
- drEl.depElement = this.getDepElement(drEl.instance, positionY, this.draggableElement.originRow);
- drEl.instance.remove();
- if (drEl.depElement) {
- depElementCtx = this.getRecord(drEl.depElement.elem[0]);
- drEl.depElement.elem.removeClass(drEl.depElement.className);
- if (drEl.depElement.insert !== 'none') {
- this.setPosition(drEl.depElement.elem, depElementCtx, drEl);
- }
- }
- drEl.originRow.removeClass(this.draggableElementClass);
- this.body.unbind('mousemove touchmove', this.mousemoveHandler);
- this.body.unbind('mouseup touchend', this.mouseupHandler);
- this.draggableElement = {};
- },
- /**
- * Set position to element
- *
- * @param {Object} depElem - dep element
- * @param {Object} depElementCtx - dep element context
- * @param {Object} dragData - data draggable element
- */
- setPosition: function (depElem, depElementCtx, dragData) {
- var depElemPosition = ~~depElementCtx.position;
- if (dragData.depElement.insert === 'after') {
- dragData.instanceCtx.position = depElemPosition + 1;
- } else if (dragData.depElement.insert === 'before') {
- dragData.instanceCtx.position = depElemPosition;
- }
- },
- /**
- * Get dependency element
- *
- * @param {Object} curInstance - current element instance
- * @param {Number} position
- * @param {Object} row
- */
- getDepElement: function (curInstance, position, row) {
- var tableSelector = this.tableClass + ' tr',
- $table = $(row).parents('table').eq(0),
- $curInstance = $(curInstance),
- recordsCollection = $table.find('table').length ?
- $table.find('tbody > tr').filter(function (index, elem) {
- return !$(elem).parents(tableSelector).length;
- }) :
- $table.find('tbody > tr'),
- curInstancePositionTop = $curInstance.position().top,
- curInstancePositionBottom = curInstancePositionTop + $curInstance.height();
- if (position < 0) {
- return this._getDepElement(recordsCollection, 'before', curInstancePositionTop);
- } else if (position > 0) {
- return this._getDepElement(recordsCollection, 'after', curInstancePositionBottom);
- }
- },
- /**
- * Get dependency element private
- *
- * @param {Array} collection - record collection
- * @param {String} position - position to add
- * @param {Number} dragPosition - position drag element
- */
- _getDepElement: function (collection, position, dragPosition) {
- var rec,
- rangeEnd,
- rangeStart,
- result,
- className,
- i = 0,
- length = collection.length;
- for (i; i < length; i++) {
- rec = collection.eq(i);
- if (position === 'before') {
- rangeStart = collection.eq(i).position().top - this.step;
- rangeEnd = rangeStart + this.step * 2;
- className = this.separatorsClass.top;
- } else if (position === 'after') {
- rangeEnd = rec.position().top + rec.height() + this.step;
- rangeStart = rangeEnd - this.step * 2;
- className = this.separatorsClass.bottom;
- }
- if (dragPosition > rangeStart && dragPosition < rangeEnd) {
- result = {
- elem: rec,
- insert: rec[0] === this.draggableElement.originRow[0] ? 'none' : position,
- className: className
- };
- }
- }
- return result;
- },
- /**
- * Set default position of draggable element
- *
- * @param {Object} elem - current element instance
- * @param {Object} data - current element data
- */
- _setDefaultPosition: function (elem, data) {
- var originRecord = $(elem).parents('tr').eq(0),
- position = originRecord.position();
- ++position.top;
- $(data).css(position);
- },
- /**
- * Set records to cache
- *
- * @param {Object} records - record instance
- */
- setCacheRecords: function (records) {
- this.recordsCache(records);
- },
- /**
- * Set styles to draggable element
- *
- * @param {Object} data - data
- * @param {Object} elem - elem instance
- * @returns {Object} instance data.
- */
- processingStyles: function (data, elem) {
- var table = $(elem).parents('table').eq(0),
- columns = table.find('th'),
- recordColumns = $(data).find('td');
- this._setDefaultPosition(elem, $(data));
- this._setColumnsWidth(columns, recordColumns);
- this._setTableWidth(table, $(data));
- return data;
- },
- /**
- * Set table width.
- *
- * @param {Object} originalTable - original record instance
- * @param {Object} recordTable - draggable record instance
- */
- _setTableWidth: function (originalTable, recordTable) {
- recordTable.outerWidth(originalTable.outerWidth());
- },
- /**
- * Set columns width.
- *
- * @param {Object} originColumns - original record instance
- * @param {Object} recordColumns - draggable record instance
- */
- _setColumnsWidth: function (originColumns, recordColumns) {
- var i = 0,
- length = originColumns.length;
- for (i; i < length; i++) {
- recordColumns.eq(i).outerWidth(originColumns.eq(i).outerWidth());
- }
- },
- /**
- * Get copy original record
- *
- * @param {Object} record - original record instance
- * @returns {Object} draggable record instance
- */
- getRecordNode: function (record) {
- var $record = $(record),
- table = $record.parents('table')[0].cloneNode(true),
- $table = $(table);
- $table.find('tr').remove();
- $table.append($record.parents('tr')[0].cloneNode(true));
- return table;
- },
- /**
- * Get record context by element
- *
- * @param {Object} elem - original element
- * @returns {Object} draggable record context
- */
- getRecord: function (elem) {
- var ctx = getContext(elem),
- index = _.isFunction(ctx.$index) ? ctx.$index() : ctx.$index;
- return this.recordsCache()[index];
- },
- /**
- * Get correct page Y
- *
- * @param {Object} event - current event
- * @returns {integer}
- */
- getPageY: function (event) {
- var pageY;
- if (event.type.indexOf('touch') >= 0) {
- if (event.originalEvent.touches[0]) {
- pageY = event.originalEvent.touches[0].pageY;
- } else {
- pageY = event.originalEvent.changedTouches[0].pageY;
- }
- } else {
- pageY = event.pageY;
- }
- return pageY;
- },
- /**
- * Disable page scrolling
- */
- disableScroll: function () {
- document.body.addEventListener('touchmove', this.preventDefault, {
- passive: false
- });
- },
- /**
- * Enable page scrolling
- */
- enableScroll: function () {
- document.body.removeEventListener('touchmove', this.preventDefault, {
- passive: false
- });
- },
- /**
- * Prevent default function
- *
- * @param {Object} event - event object
- */
- preventDefault: function (event) {
- event.preventDefault();
- }
- });
- });
|