UNPKG

@progress/telerik-jquery-report-viewer

Version:

Progress® Telerik® Report Viewer for jQuery

279 lines (276 loc) 14.1 kB
import { rectangle, getColorAlphaValue } from './utils.js'; var UIFreezeCoordinator = { $placeholder: null, $scrollableContainer: null, // Holds all items initial position per container itemsInitialState: {}, // Holds the bounds of the frozen areas by X per container xFrozenAreasBounds: {}, // Holds the bounds of the frozen areas by Y per container yFrozenAreasBounds: {}, freezeMaxZIndex: {}, zIndex: 1, // Holds default background-color value per container freezeBGColor: {}, // Holds whether freezing has been applied per container. currentlyFrozenContainer: { vertical: {}, horizontal: {} }, isInitialize: false, scaleFactor: null, /** * Initialize the uiFreezeCoordinator object * Takes one parameter * - $placeholder - PageArea jQuery DOM element */ init: function($placeholder) { this.$placeholder = $placeholder; this.$scrollableContainer = $placeholder.find(".trv-page-container"); if (this.isInitialize) { this.reset($placeholder); } this._attachToScrollEvent(); this.isInitialize = true; }, reset: function($placeholder) { this.$placeholder = $placeholder; this.$scrollableContainer = $placeholder.find(".trv-page-container"); this.itemsInitialState = {}; this.xFrozenAreasBounds = {}; this.yFrozenAreasBounds = {}; this.currentlyfreezedContainer = { vertical: {}, horizontal: {} }; }, setScaleFactor: function(scale) { this.scaleFactor = scale; }, /** * Initializing scroll listener */ _attachToScrollEvent: function() { var thisInstance = this; this.$scrollableContainer.scroll(function updateFreezeUIOnScroll() { var $freezeItems = thisInstance.$scrollableContainer.find("div[data-sticky-id]"); if ($freezeItems.length) { var tableIDs = $freezeItems.map(function(index2, $element) { return $($element).attr("data-sticky-id"); }).get(); var uniqueIDs = tableIDs.filter(function(item, index2) { return index2 === tableIDs.indexOf(item); }); var scrollableContainerScrollTop = thisInstance.$scrollableContainer.scrollTop(); var scrollableContainerScrollLeft = thisInstance.$scrollableContainer.scrollLeft(); for (var index = 0; index < uniqueIDs.length; index++) { var freezeItemsContainerID = uniqueIDs[index]; if (!thisInstance.itemsInitialState[freezeItemsContainerID]) { thisInstance._saveFreezeItemsInitialState(freezeItemsContainerID); } thisInstance._updateFreezeItemsOnScroll( freezeItemsContainerID, scrollableContainerScrollTop, scrollableContainerScrollLeft ); } } }); }, _saveFreezeItemsInitialState: function(freezeItemsContainerID) { var $allFreezeItems = $("[data-sticky-direction][data-sticky-id='" + freezeItemsContainerID + "']"); var $freezeActions = $("[data-reporting-action][data-sticky-id='" + freezeItemsContainerID + "']"); var yAreaBounds; var xAreaBounds; this.itemsInitialState[freezeItemsContainerID] = {}; this.freezeBGColor[freezeItemsContainerID] = $("[data-id='" + freezeItemsContainerID + "']").attr("data-sticky-bg-color"); for (var index = 0; index < $allFreezeItems.length; index++) { var $item = $($allFreezeItems[index]); var scrollDirection = $item.attr("data-sticky-direction"); var itemID = $item.attr("data-id"); var itemPosition = $item.position(); var scaledItemPosition = { top: itemPosition.top / this.scaleFactor, left: itemPosition.left / this.scaleFactor }; var itemBounds = rectangle(scaledItemPosition.left, scaledItemPosition.top, $item.outerWidth(true) * this.scaleFactor, $item.outerHeight(true) * this.scaleFactor); switch (scrollDirection) { case "Vertical": yAreaBounds = yAreaBounds ? yAreaBounds.union(itemBounds) : itemBounds; break; case "Horizontal": xAreaBounds = xAreaBounds ? xAreaBounds.union(itemBounds) : itemBounds; break; } this._saveFreezeItemInitialState(freezeItemsContainerID, $item, itemID, scaledItemPosition); } this.freezeMaxZIndex[freezeItemsContainerID] = $freezeActions.length ? $freezeActions.css("zIndex") : this.zIndex; this.yFrozenAreasBounds[freezeItemsContainerID] = yAreaBounds; this.xFrozenAreasBounds[freezeItemsContainerID] = xAreaBounds; }, /** * Save the freeze UI item initial position based on the wrapper element and current page * - freezeItemsContainerID - string. A parent/wrapper element identifier * - $item - JQuery DOM element of the freezed item * - itemID - string. A ID of the freeze UI item * - position - object. Contains the top and left values */ _saveFreezeItemInitialState: function(freezeItemsContainerID, $item, itemID, position) { var itemBgColor = $item.css("background-color"); var hasInitialBgColor = this._hasSetBgColor(itemBgColor); var itemState = { top: position.top, left: position.left, zIndex: $item.css("zIndex"), hasBgColor: hasInitialBgColor }; this.itemsInitialState[freezeItemsContainerID][itemID] = itemState; }, _updateFreezeItemsOnScroll: function(freezeItemsContainerID, scrollableContainerScrollTop, scrollableContainerScrollLeft) { var $elementWrapper = $("div[data-id='" + freezeItemsContainerID + "']"); if (this._isInScrollVisibleArea($elementWrapper)) { var $pageContainer = $elementWrapper.closest(".trv-report-page"); var pageContainerPosition = $pageContainer.position(); var pageContainerMargin = parseFloat($pageContainer.css("margin-top")); var pageContainerTopOffset = parseFloat($pageContainer.css("padding-top")); var pageContainerLeftOffset = parseFloat($pageContainer.css("padding-left")); var pageContainerBorderTopWidth = parseFloat($pageContainer.css("border-top-width")); var pageContainerBorderLeftWidth = parseFloat($pageContainer.css("border-left-width")); var $rowHeaders = $("[data-sticky-direction*='Horizontal'][data-sticky-id='" + freezeItemsContainerID + "']"); var $colHeaders = $("[data-sticky-direction*='Vertical'][data-sticky-id='" + freezeItemsContainerID + "']"); var hasFixRow = $rowHeaders.length > 0; var hasFixColumn = $colHeaders.length > 0; var elementWrapperPosition = $elementWrapper.position(); var elementWrapperTopPosition = elementWrapperPosition.top + pageContainerPosition.top + pageContainerMargin + pageContainerTopOffset + pageContainerBorderTopWidth; var elementWrapperLeftPosition = elementWrapperPosition.left + pageContainerLeftOffset + pageContainerBorderLeftWidth; var verticalMoveOffset = scrollableContainerScrollTop - elementWrapperTopPosition; var horizontalMoveOffset = scrollableContainerScrollLeft - elementWrapperLeftPosition; if (hasFixColumn && verticalMoveOffset > 0) { if (scrollableContainerScrollTop <= $elementWrapper.outerHeight() * this.scaleFactor + elementWrapperTopPosition - this.yFrozenAreasBounds[freezeItemsContainerID].height) { this.currentlyFrozenContainer.vertical[freezeItemsContainerID] = true; this._updateUIElementsPosition($colHeaders, "top", verticalMoveOffset / this.scaleFactor, freezeItemsContainerID); } } else { if (this.currentlyFrozenContainer.vertical[freezeItemsContainerID]) { delete this.currentlyFrozenContainer.vertical[freezeItemsContainerID]; this._updateUIElementsPosition($colHeaders, "top", -1, freezeItemsContainerID); } } if (hasFixRow && horizontalMoveOffset > 0) { if (scrollableContainerScrollLeft <= $elementWrapper.outerWidth() * this.scaleFactor + elementWrapperLeftPosition - this.xFrozenAreasBounds[freezeItemsContainerID].width) { this.currentlyFrozenContainer.horizontal[freezeItemsContainerID] = true; this._updateUIElementsPosition($rowHeaders, "left", horizontalMoveOffset / this.scaleFactor, freezeItemsContainerID); } } else { if (this.currentlyFrozenContainer.horizontal[freezeItemsContainerID]) { delete this.currentlyFrozenContainer.horizontal[freezeItemsContainerID]; this._updateUIElementsPosition($rowHeaders, "left", -1, freezeItemsContainerID); } } } else { if (this.currentlyFrozenContainer.horizontal[freezeItemsContainerID] || this.currentlyFrozenContainer.vertical[freezeItemsContainerID]) { this._resetToDefaultPosition(freezeItemsContainerID); } } }, /** * Move all freeze items to their initial position * Takes one parameters * - freezeItemsContainerID - string. A parent/wrapper element identifier */ _resetToDefaultPosition: function(freezeItemsContainerID) { var $rowHeaders = $("[data-sticky-direction*='Horizontal'][data-sticky-id='" + freezeItemsContainerID + "']"); var $colHeaders = $("[data-sticky-direction*='Vertical'][data-sticky-id='" + freezeItemsContainerID + "']"); this._updateUIElementsPosition($colHeaders, "top", -1, freezeItemsContainerID); this._updateUIElementsPosition($rowHeaders, "left", -1, freezeItemsContainerID); delete this.currentlyFrozenContainer.horizontal[freezeItemsContainerID]; delete this.currentlyFrozenContainer.vertical[freezeItemsContainerID]; }, /** * Update the freeze elements position * Takes four parameters * - targetElements -Array. Collection of DOM element, that has a freeze attribute * - position - string. Indicates which position property to be updated - top or left * - offset - integer. The value of the increase that should be applied. * If it is negative number, should not move the items and it should set their initial position * - freezeItemsContainerID - string. A parent/wrapper element identifier */ _updateUIElementsPosition: function(targetElements, position, offset, freezeItemsContainerID) { for (var index = 0; index < targetElements.length; index++) { var $item = $(targetElements[index]); var itemFreezeDirection = $item.attr("data-sticky-direction"); var isFrozenBothDirection = itemFreezeDirection.indexOf(",") > 0; var itemID = $item.attr("data-id"); var itemInitialState = this.itemsInitialState[freezeItemsContainerID][itemID]; var itemNewPostion = itemInitialState[position]; var initialZIndex = itemInitialState["zIndex"]; var hasInitialBgColor = itemInitialState["hasBgColor"]; var zIndexValue = 1; var maxZIndex = this.freezeMaxZIndex[freezeItemsContainerID] ? this.freezeMaxZIndex[freezeItemsContainerID] : zIndexValue; if (isFrozenBothDirection) { zIndexValue = initialZIndex !== "auto" ? initialZIndex : maxZIndex + 2; } else { zIndexValue = initialZIndex !== "auto" ? initialZIndex + 1 : maxZIndex; } var newStyleRules = { "z-index": zIndexValue }; if (offset >= 0) { itemNewPostion = itemNewPostion + offset; } else { newStyleRules["z-index"] = initialZIndex; } if (!hasInitialBgColor) { this._applyBgColorOnScroll($item, isFrozenBothDirection, hasInitialBgColor, offset >= 0, freezeItemsContainerID); } newStyleRules[position] = itemNewPostion + "px"; $item.css(newStyleRules); } }, // eslint-disable-next-line max-params _applyBgColorOnScroll: function($item, isItemFrozenBothDirection, hasInitialBgColor, shouldApplyBGColor, freezeItemsContainerID) { if ($item.is("img")) { return true; } if (isItemFrozenBothDirection && this._isFrozen(freezeItemsContainerID) && !hasInitialBgColor) { $item.css("background-color", this.freezeBGColor[freezeItemsContainerID]); return true; } if (shouldApplyBGColor) { $item.css("background-color", this.freezeBGColor[freezeItemsContainerID]); } else { $item.css("background-color", "initial"); } }, _hasSetBgColor: function(bgColorValue) { return getColorAlphaValue(bgColorValue) > 0; }, _isFrozen: function(freezeItemsContainerID) { return this.currentlyFrozenContainer.horizontal[freezeItemsContainerID] || this.currentlyFrozenContainer.vertical[freezeItemsContainerID]; }, /** * Checks if an UI element is in the visible part of the scrollable container * Takes one parameters * - $element - JQuery DOM element */ _isInScrollVisibleArea: function($element) { var $page = $element.closest(".trv-report-page"); var elementPosition = $element.position(); return this._isVisibleVertically($element, $page, elementPosition) && this._isVisibleHorizontally($element, $page, elementPosition); }, _isVisibleHorizontally: function($element, $page, elementPosition) { var pageLeftOffset = parseFloat($page.css("padding-left")); var scrollableContainerLeftScrollPosition = this.$scrollableContainer.scrollLeft(); var scrollableContainerWidth = this.$scrollableContainer.width(); var elementWidth = $element.outerWidth(true) * this.scaleFactor; var elementLeftOffset = elementPosition.left + pageLeftOffset; return elementLeftOffset > scrollableContainerLeftScrollPosition - elementWidth && elementLeftOffset < scrollableContainerLeftScrollPosition + elementWidth + scrollableContainerWidth; }, _isVisibleVertically: function($element, $page, elementPosition) { var pageTopOffset = parseFloat($page.css("padding-top")); var pagePosition = $page.position(); var scrollableContainerTopScrollPosition = this.$scrollableContainer.scrollTop(); var scrollableContainerHeight = this.$scrollableContainer.height(); var elementHeight = $element.outerHeight(true) * this.scaleFactor; var elementTopOffset = elementPosition.top + pageTopOffset + pagePosition.top; return elementTopOffset > scrollableContainerTopScrollPosition - elementHeight && elementTopOffset < scrollableContainerTopScrollPosition + elementHeight + scrollableContainerHeight; } }; export { UIFreezeCoordinator };