123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606 |
- /**
- * Copyright © Magento, Inc. All rights reserved.
- * See COPYING.txt for license details.
- */
- /**
- * @api
- */
- define([
- 'underscore',
- 'Magento_Ui/js/lib/view/utils/async',
- 'Magento_Ui/js/lib/view/utils/raf',
- 'rjsResolver',
- 'uiCollection'
- ], function (_, $, raf, resolver, Collection) {
- 'use strict';
- var transformProp;
- /**
- * Defines supported css 'transform' property.
- *
- * @returns {String|Undefined}
- */
- transformProp = (function () {
- var style = document.documentElement.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;
- }
- }
- })();
- /**
- * Moves specified DOM element to the x and y coordinates.
- *
- * @param {HTMLElement} elem - Element to be relocated.
- * @param {Number} x - X coordinate.
- * @param {Number} y - Y coordinate.
- */
- function locate(elem, x, y) {
- var value = 'translate(' + x + 'px,' + y + 'px)';
- elem.style[transformProp] = value;
- }
- return Collection.extend({
- defaults: {
- template: 'ui/grid/toolbar',
- stickyTmpl: 'ui/grid/sticky/sticky',
- tableSelector: 'table',
- columnsProvider: 'ns = ${ $.ns }, componentType = columns',
- refreshFPS: 15,
- sticky: false,
- visible: false,
- _resized: true,
- _scrolled: true,
- _tableScrolled: true,
- _requiredNodes: {
- '$stickyToolbar': true,
- '$stickyTable': true,
- '$table': true,
- '$sticky': true
- },
- stickyClass: {
- 'sticky-header': true
- }
- },
- /**
- * Initializes sticky toolbar component.
- *
- * @returns {Sticky} Chainable.
- */
- initialize: function () {
- this._super();
- if (this.sticky) {
- this.waitDOMElements()
- .then(this.run.bind(this));
- }
- return this;
- },
- /**
- * Establishes DOM elements wait process.
- *
- * @returns {jQueryPromise} Promise which will be resolved
- * when all of the required DOM elements are defined.
- */
- waitDOMElements: function () {
- var _domPromise = $.Deferred();
- _.bindAll(this, 'setStickyTable', 'setTableNode');
- $.async({
- ctx: ':not([data-role="sticky-el-root"])',
- component: this.columnsProvider,
- selector: this.tableSelector
- }, this.setTableNode);
- $.async({
- ctx: '[data-role="sticky-el-root"]',
- component: this.columnsProvider,
- selector: this.tableSelector
- }, this.setStickyTable);
- this._domPromise = _domPromise;
- return _domPromise.promise();
- },
- /**
- * Defines left caption element.
- *
- * @param {HTMLElement} node
- */
- setLeftCap: function (node) {
- this.$leftCap = node;
- },
- /**
- * Defines right caption element.
- *
- * @param {HTMLElement} node
- */
- setRightCap: function (node) {
- this.$rightCap = node;
- },
- /**
- * Defines original table element.
- *
- * @param {HTMLTableElement} node
- */
- setTableNode: function (node) {
- this.$cols = node.tHead.children[0].cells;
- this.$tableContainer = node.parentNode;
- this.setNode('$table', node);
- },
- /**
- * Defines sticky table element.
- *
- * @param {HTMLTableElement} node
- */
- setStickyTable: function (node) {
- this.$stickyCols = node.tHead.children[0].cells;
- this.setNode('$stickyTable', node);
- },
- /**
- * Defines sticky toolbar node.
- *
- * @param {HTMLElement} node
- */
- setStickyToolbarNode: function (node) {
- this.setNode('$stickyToolbar', node);
- },
- /**
- * Defines sticky element container.
- *
- * @param {HTMLElement} node
- */
- setStickyNode: function (node) {
- this.setNode('$sticky', node);
- },
- /**
- * Defines toolbar element container.
- *
- * @param {HTMLElement} node
- */
- setToolbarNode: function (node) {
- this.$toolbar = node;
- },
- /**
- * Sets provided node as a value of 'key' property and
- * performs check for required DOM elements.
- *
- * @param {String} key - Properties key.
- * @param {HTMLElement} node - DOM element.
- */
- setNode: function (key, node) {
- var nodes = this._requiredNodes,
- promise = this._domPromise,
- defined;
- this[key] = node;
- defined = _.every(nodes, function (enabled, name) {
- return enabled ? this[name] : true;
- }, this);
- if (defined) {
- resolver(promise.resolve, promise);
- }
- },
- /**
- * Starts refresh process of the sticky element
- * and assigns DOM elements events handlers.
- */
- run: function () {
- _.bindAll(
- this,
- 'refresh',
- '_onWindowResize',
- '_onWindowScroll',
- '_onTableScroll'
- );
- $(window).on({
- scroll: this._onWindowScroll,
- resize: this._onWindowResize
- });
- $(this.$tableContainer).on('scroll', this._onTableScroll);
- this.refresh();
- this.checkTableWidth();
- },
- /**
- * Refreshes state of the sticky element and
- * invokes DOM elements events handlers
- * if corresponding event has been triggered.
- */
- refresh: function () {
- if (!raf(this.refresh, this.refreshFPS)) {
- return;
- }
- if (this._scrolled) {
- this.onWindowScroll();
- }
- if (this._tableScrolled) {
- this.onTableScroll();
- }
- if (this._resized) {
- this.onWindowResize();
- }
- if (this.visible) {
- this.checkTableWidth();
- }
- },
- /**
- * Shows sticky toolbar.
- *
- * @returns {Sticky} Chainable.
- */
- show: function () {
- this.visible = true;
- this.$sticky.style.display = '';
- this.$toolbar.style.visibility = 'hidden';
- return this;
- },
- /**
- * Hides sticky toolbar.
- *
- * @returns {Sticky} Chainable.
- */
- hide: function () {
- this.visible = false;
- this.$sticky.style.display = 'none';
- this.$toolbar.style.visibility = '';
- return this;
- },
- /**
- * Checks if sticky toolbar covers original elements.
- *
- * @returns {Boolean}
- */
- isCovered: function () {
- var stickyTop = this._stickyTableTop + this._wScrollTop;
- return stickyTop > this._tableTop;
- },
- /**
- * Updates offset of the sticky table element.
- *
- * @returns {Sticky} Chainable.
- */
- updateStickyTableOffset: function () {
- var style,
- top;
- if (this.visible) {
- top = this.$stickyTable.getBoundingClientRect().top;
- } else {
- style = this.$sticky.style;
- style.visibility = 'hidden';
- style.display = '';
- top = this.$stickyTable.getBoundingClientRect().top;
- style.display = 'none';
- style.visibility = '';
- }
- this._stickyTableTop = top;
- return this;
- },
- /**
- * Updates offset of the original table element.
- *
- * @returns {Sticky} Chainable.
- */
- updateTableOffset: function () {
- var box = this.$table.getBoundingClientRect(),
- top = box.top + this._wScrollTop;
- if (this._tableTop !== top) {
- this._tableTop = top;
- this.onTableTopChange(top);
- }
- return this;
- },
- /**
- * Checks if width of the table or it's columns has changed.
- *
- * @returns {Sticky} Chainable.
- */
- checkTableWidth: function () {
- var cols = this.$cols,
- total = cols.length,
- rightBorder = cols[total - 2].offsetLeft,
- tableWidth = this.$table.offsetWidth;
- if (this._tableWidth !== tableWidth) {
- this._tableWidth = tableWidth;
- this.onTableWidthChange(tableWidth);
- }
- if (this._rightBorder !== rightBorder) {
- this._rightBorder = rightBorder;
- this.onColumnsWidthChange();
- }
- return this;
- },
- /**
- * Updates width of the sticky table.
- *
- * @returns {Sticky} Chainable.
- */
- updateTableWidth: function () {
- this.$stickyTable.style.width = this._tableWidth + 'px';
- if (this._tableWidth < this._toolbarWidth) {
- this.checkToolbarSize();
- }
- return this;
- },
- /**
- * Updates width of the sticky columns.
- *
- * @returns {Sticky} Chainable.
- */
- updateColumnsWidth: function () {
- var cols = this.$cols,
- index = cols.length,
- stickyCols = this.$stickyCols;
- while (index--) {
- stickyCols[index].width = cols[index].offsetWidth;
- }
- return this;
- },
- /**
- * Upadates size of the sticky toolbar element
- * and invokes corresponding 'change' event handlers.
- *
- * @returns {Sticky} Chainable.
- */
- checkToolbarSize: function () {
- var width = this.$tableContainer.offsetWidth;
- if (this._toolbarWidth !== width) {
- this._toolbarWidth = width;
- this.onToolbarWidthChange(width);
- }
- return this;
- },
- /**
- * Toggles sticky toolbar visibility if it's necessary.
- *
- * @returns {Sticky} Chainable.
- */
- updateVisibility: function () {
- if (this.visible !== this.isCovered()) {
- this.visible ? this.hide() : this.show();
- }
- return this;
- },
- /**
- * Updates position of the left cover area.
- *
- * @returns {Sticky} Chainable.
- */
- updateLeftCap: function () {
- locate(this.$leftCap, -this._wScrollLeft, 0);
- return this;
- },
- /**
- * Updates position of the right cover area.
- *
- * @returns {Sticky} Chainable.
- */
- updateRightCap: function () {
- var left = this._toolbarWidth - this._wScrollLeft;
- locate(this.$rightCap, left, 0);
- return this;
- },
- /**
- * Updates position of the sticky table.
- *
- * @returns {Sticky} Chainable.
- */
- updateTableScroll: function () {
- var container = this.$tableContainer,
- left = container.scrollLeft + this._wScrollLeft;
- locate(this.$stickyTable, -left, 0);
- return this;
- },
- /**
- * Updates width of the toolbar element.
- *
- * @returns {Sticky} Chainable.
- */
- updateToolbarWidth: function () {
- this.$stickyToolbar.style.width = this._toolbarWidth + 'px';
- return this;
- },
- /**
- * Handles changes of the toolbar element's width.
- */
- onToolbarWidthChange: function () {
- this.updateToolbarWidth()
- .updateRightCap();
- },
- /**
- * Handles changes of the table top position.
- */
- onTableTopChange: function () {
- this.updateStickyTableOffset();
- },
- /**
- * Handles change of the table width.
- */
- onTableWidthChange: function () {
- this.updateTableWidth();
- },
- /**
- * Handles change of the table columns width.
- */
- onColumnsWidthChange: function () {
- this.updateColumnsWidth();
- },
- /**
- * Handles changes of the window's size.
- */
- onWindowResize: function () {
- this.checkToolbarSize();
- this._resized = false;
- },
- /**
- * Handles changes of the original table scroll position.
- */
- onTableScroll: function () {
- this.updateTableScroll();
- this._tableScrolled = false;
- },
- /**
- * Handles changes of window's scroll position.
- */
- onWindowScroll: function () {
- var scrollTop = window.pageYOffset,
- scrollLeft = window.pageXOffset;
- if (this._wScrollTop !== scrollTop) {
- this._wScrollTop = scrollTop;
- this.onWindowScrollTop(scrollTop);
- }
- if (this._wScrollLeft !== scrollLeft) {
- this._wScrollLeft = scrollLeft;
- this.onWindowScrollLeft(scrollLeft);
- }
- this._scrolled = false;
- },
- /**
- * Handles changes of windows' top scroll position.
- */
- onWindowScrollTop: function () {
- this.updateTableOffset()
- .updateVisibility();
- },
- /**
- * Handles changes of windows' left scroll position.
- */
- onWindowScrollLeft: function () {
- this.updateRightCap()
- .updateLeftCap()
- .updateTableScroll();
- },
- /**
- * Original window 'scroll' event handler.
- * Sets 'scrolled' flag to 'true'.
- *
- * @private
- */
- _onWindowScroll: function () {
- this._scrolled = true;
- },
- /**
- * Original window 'resize' event handler.
- * Sets 'resized' flag to 'true'.
- *
- * @private
- */
- _onWindowResize: function () {
- this._resized = true;
- },
- /**
- * Original table 'scroll' event handler.
- * Sets '_tableScrolled' flag to 'true'.
- *
- * @private
- */
- _onTableScroll: function () {
- this._tableScrolled = true;
- }
- });
- });
|