![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/old/vendor/magento/module-ui/view/base/web/js/timeline/ |
/** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /** * @api */ define([ 'ko', 'Magento_Ui/js/lib/view/utils/async', 'underscore', 'Magento_Ui/js/lib/view/utils/raf', 'uiRegistry', 'uiClass' ], function (ko, $, _, raf, registry, Class) { 'use strict'; var hasClassList = (function () { var list = document.createElement('_').classList; return !!list && !list.toggle('_test', false); })(); /** * Polyfill of the 'classList.toggle' method. * * @param {HTMLElement} elem */ function toggleClass(elem) { var classList = elem.classList, args = Array.prototype.slice.call(arguments, 1), $elem; if (hasClassList) { classList.toggle.apply(classList, args); } else { $elem = $(elem); $elem.toggleClass.apply($elem, args); } } return Class.extend({ defaults: { selectors: { content: '.timeline-content', timeUnit: '.timeline-unit', item: '.timeline-item:not([data-role=no-data-msg])', event: '.timeline-event' } }, /** * Initializes TimelineView component. * * @returns {TimelineView} Chainable. */ initialize: function () { _.bindAll( this, 'refresh', 'initContent', 'initItem', 'initTimeUnit', 'getItemBindings', 'updateItemsPosition', 'onScaleChange', 'onEventElementRender', 'onWindowResize', 'onContentScroll', 'onDataReloaded', 'onToStartClick', 'onToEndClick' ); this._super() .initModel() .waitContent(); return this; }, /** * Applies listeners for the model properties changes. * * @returns {TimelineView} Chainable. */ initModel: function () { var model = registry.get(this.model); model.on('scale', this.onScaleChange); model.source.on('reloaded', this.onDataReloaded); this.model = model; return this; }, /** * Applies DOM watcher for the * content element rendering. * * @returns {TimelineView} Chainable. */ waitContent: function () { $.async({ selector: this.selectors.content, component: this.model }, this.initContent); return this; }, /** * Initializes timelines' content element. * * @param {HTMLElement} content * @returns {TimelineView} Chainable. */ initContent: function (content) { this.$content = content; $(content).on('scroll', this.onContentScroll); $(window).on('resize', this.onWindowResize); $.async(this.selectors.item, content, this.initItem); $.async(this.selectors.event, content, this.onEventElementRender); $.async(this.selectors.timeUnit, content, this.initTimeUnit); this.refresh(); return this; }, /** * Initializes timeline item element, * e.g. establishes event listeners and applies data bindings. * * @param {HTMLElement} elem * @returns {TimelineView} Chainable. */ initItem: function (elem) { $(elem) .bindings(this.getItemBindings) .on('click', '._toend', this.onToEndClick) .on('click', '._tostart', this.onToStartClick); return this; }, /** * Initializes timeline unit element. * * @param {HTMLElement} elem * @returns {TimelineView} Chainable. */ initTimeUnit: function (elem) { $(elem).bindings(this.getTimeUnitBindings()); return this; }, /** * Updates items positions in a * loop if state of a view has changed. */ refresh: function () { raf(this.refresh); if (this._update) { this._update = false; this.updateItemsPosition(); } }, /** * Returns object width additional bindings * for a timeline unit element. * * @returns {Object} */ getTimeUnitBindings: function () { return { style: { width: ko.computed(function () { return this.getTimeUnitWidth() + '%'; }.bind(this)) } }; }, /** * Returns object with additional * bindings for a timeline item element. * * @param {Object} ctx * @returns {Object} */ getItemBindings: function (ctx) { return { style: { width: ko.computed(function () { return this.getItemWidth(ctx.$row()) + '%'; }.bind(this)), 'margin-left': ko.computed(function () { return this.getItemMargin(ctx.$row()) + '%'; }.bind(this)) } }; }, /** * Calculates width in percents of a timeline unit element. * * @returns {Number} */ getTimeUnitWidth: function () { return 100 / this.model.scale; }, /** * Calculates width of a record in percents. * * @param {Object} record * @returns {String} */ getItemWidth: function (record) { var days = 0; if (record) { days = this.model.getDaysLength(record); } return this.getTimeUnitWidth() * days; }, /** * Calculates left margin value for provided record. * * @param {Object} record * @returns {String} */ getItemMargin: function (record) { var offset = 0; if (record) { offset = this.model.getStartDelta(record); } return this.getTimeUnitWidth() * offset; }, /** * Returns collection of currently available * timeline item elements. * * @returns {Array<HTMLElement>} */ getItems: function () { var items = this.$content.querySelectorAll(this.selectors.item); return _.toArray(items); }, /** * Updates positions of timeline elements. * * @returns {TimelineView} Chainable. */ updateItemsPosition: function () { this.getItems() .forEach(this.updatePositionFor, this); return this; }, /** * Updates position of provided timeline element. * * @param {HTMLElement} $elem * @returns {TimelineView} Chainable. */ updatePositionFor: function ($elem) { var $event = $elem.querySelector(this.selectors.event), leftEdge = this.getLeftEdgeFor($elem), rightEdge = this.getRightEdgeFor($elem); if ($event) { $event.style.left = Math.max(-leftEdge, 0) + 'px'; $event.style.right = Math.max(rightEdge, 0) + 'px'; } toggleClass($elem, '_scroll-start', leftEdge < 0); toggleClass($elem, '_scroll-end', rightEdge > 0); return this; }, /** * Scrolls content area to the start of provided element. * * @param {HTMLElement} elem * @returns {TimelineView} */ toStartOf: function (elem) { var leftEdge = this.getLeftEdgeFor(elem); this.$content.scrollLeft += leftEdge; return this; }, /** * Scrolls content area to the end of provided element. * * @param {HTMLElement} elem * @returns {TimelineView} */ toEndOf: function (elem) { var rightEdge = this.getRightEdgeFor(elem); this.$content.scrollLeft += rightEdge + 1; return this; }, /** * Calculates location of the left edge of an element * relative to the contents' left edge. * * @param {HTMLElement} elem * @returns {Number} */ getLeftEdgeFor: function (elem) { var leftOffset = elem.getBoundingClientRect().left; return leftOffset - this.$content.getBoundingClientRect().left; }, /** * Calculates location of the right edge of an element * relative to the contents' right edge. * * @param {HTMLElement} elem * @returns {Number} */ getRightEdgeFor: function (elem) { var elemWidth = elem.offsetWidth, leftEdge = this.getLeftEdgeFor(elem); return leftEdge + elemWidth - this.$content.offsetWidth; }, /** * 'To Start' button 'click' event handler. * * @param {jQueryEvent} event */ onToStartClick: function (event) { var elem = event.originalEvent.currentTarget; event.stopPropagation(); this.toStartOf(elem); }, /** * 'To End' button 'click' event handler. * * @param {jQueryEvent} event */ onToEndClick: function (event) { var elem = event.originalEvent.currentTarget; event.stopPropagation(); this.toEndOf(elem); }, /** * Handler of the scale value 'change' event. */ onScaleChange: function () { this._update = true; }, /** * Callback function which is invoked * when event element was rendered. */ onEventElementRender: function () { this._update = true; }, /** * Window 'resize' event handler. */ onWindowResize: function () { this._update = true; }, /** * Content container 'scroll' event handler. */ onContentScroll: function () { this._update = true; }, /** * Data 'reload' event handler. */ onDataReloaded: function () { this._update = true; } }); });