@syncfusion/ej2-spreadsheet
Version: 
Feature-rich JavaScript Spreadsheet (Excel) control with built-in support for selection, editing, formatting, importing and exporting to Excel
398 lines (397 loc) • 19.1 kB
JavaScript
import { Browser, EventHandler, getComponent, isNullOrUndefined } from '@syncfusion/ej2-base';
import { isFormulaBarEdit, colWidthChanged, mouseDown, getUpdateUsingRaf } from '../index';
import { contentLoaded, spreadsheetDestroyed, onVerticalScroll, onHorizontalScroll, getScrollBarWidth, updateNoteContainer, focusRenameInput } from '../common/index';
import { onContentScroll, deInitProperties, updateScroll, selectionStatus } from '../common/index';
import { virtualContentLoaded, updateScrollValue } from '../common/index';
import { getRowHeight, getColumnWidth, getCellAddress, skipHiddenIdx } from '../../workbook/index';
/**
 * The `Scroll` module is used to handle scrolling behavior.
 *
 * @hidden
 */
var Scroll = /** @class */ (function () {
    /**
     * Constructor for the Spreadsheet scroll module.
     *
     * @param {Spreadsheet} parent - Constructor for the Spreadsheet scroll module.
     * @private
     */
    function Scroll(parent) {
        this.clientX = 0;
        /** @hidden */
        this.isKeyScroll = true;
        this.parent = parent;
        this.addEventListener();
        this.initProps();
    }
    Scroll.prototype.onContentScroll = function (e) {
        if (!this.parent) {
            return;
        }
        var target = this.parent.getMainContent().parentElement;
        var scrollLeft = e.scrollLeft;
        var top = e.scrollTop || target.scrollTop;
        var left = scrollLeft && this.parent.enableRtl ? this.initScrollValue - scrollLeft : scrollLeft;
        var scrollArgs;
        var prevSize;
        if (this.parent.allowAutoFill) {
            var elem = document.querySelector('#' + this.parent.element.id + '_autofilloptionbtn-popup');
            var DDBElem = document.querySelector('#' + this.parent.element.id + '_autofilloptionbtn');
            if (elem) {
                var DDBObj = getComponent(DDBElem, 'dropdown-btn');
                DDBObj.toggle();
            }
        }
        if (!isNullOrUndefined(scrollLeft) && this.prevScroll.scrollLeft !== left) {
            var scrollRight = left > this.prevScroll.scrollLeft;
            prevSize = this.offset.left.size;
            this.offset.left = this.getColOffset(left, scrollRight, e.skipHidden);
            if (!e.preventScroll) {
                this.parent.getColumnHeaderContent().scrollLeft = scrollLeft;
                this.parent.getMainContent().scrollLeft = scrollLeft;
                e.scrollLeft = scrollLeft;
            }
            scrollArgs = {
                cur: this.offset.left, prev: { idx: this.leftIndex, size: prevSize }, increase: scrollRight, preventScroll: e.preventScroll
            };
            this.updateTopLeftCell(scrollRight, true);
            this.parent.notify(focusRenameInput, null);
            this.parent.notify(onHorizontalScroll, scrollArgs);
            this.updateNoteContainer();
            if (!this.parent.scrollSettings.enableVirtualization && scrollRight && !this.parent.scrollSettings.isFinite) {
                this.updateNonVirtualCols();
            }
            this.leftIndex = scrollArgs.prev.idx;
            this.prevScroll.scrollLeft = left;
        }
        if (Math.round(this.prevScroll.scrollTop) !== Math.round(top)) {
            if (e.skipRowVirualScroll) {
                this.prevScroll.scrollTop = 0;
                this.offset.top = { idx: 0, size: 0 };
            }
            var scrollDown = top > this.prevScroll.scrollTop;
            prevSize = this.offset.top.size;
            this.offset.top = this.getRowOffset(top, scrollDown);
            scrollArgs = {
                cur: this.offset.top, prev: { idx: this.topIndex, size: prevSize }, increase: scrollDown, preventScroll: e.preventScroll
            };
            this.updateTopLeftCell(scrollDown);
            if (e.preventScroll && this.offset.top.idx <= this.parent.getThreshold('row')) {
                this.offset.top = { idx: 0, size: 0 };
            }
            else if (!e.skipRowVirualScroll) {
                this.parent.notify(focusRenameInput, null);
                this.parent.notify(onVerticalScroll, scrollArgs);
                this.updateNoteContainer();
            }
            else {
                scrollArgs.prev.idx = scrollArgs.cur.idx;
            }
            if (!this.parent.scrollSettings.enableVirtualization && scrollDown && !this.parent.scrollSettings.isFinite) {
                this.updateNonVirtualRows();
            }
            this.topIndex = scrollArgs.prev.idx;
            this.prevScroll.scrollTop = top;
        }
        var isEdit = false;
        var args = { isEdit: isEdit };
        this.parent.notify(isFormulaBarEdit, args);
        if (args.isEdit) {
            var textArea = this.parent.element.querySelector('.e-formula-bar');
            textArea.focus();
        }
        this.isKeyScroll = true;
    };
    Scroll.prototype.updateNoteContainer = function () {
        if (document.getElementsByClassName('e-addNoteContainer') && document.getElementsByClassName('e-addNoteContainer').length > 0) {
            this.parent.notify(updateNoteContainer, null);
        }
    };
    Scroll.prototype.updateScrollValue = function (args) {
        if (args.scrollLeft !== undefined) {
            this.prevScroll.scrollLeft = args.scrollLeft + (this.prevScroll.scrollLeft - this.offset.left.size);
            this.offset.left.size = args.scrollLeft;
        }
        if (args.scrollTop !== undefined) {
            this.prevScroll.scrollTop = args.scrollTop + (this.prevScroll.scrollTop - this.offset.top.size);
            this.offset.top.size = args.scrollTop;
        }
    };
    Scroll.prototype.updateNonVirtualRows = function () {
        var sheet = this.parent.getActiveSheet();
        var threshold = this.parent.getThreshold('row');
        if (this.offset.top.idx > sheet.rowCount - (this.parent.viewport.rowCount + threshold)) {
            this.parent.renderModule.refreshUI({ rowIndex: sheet.rowCount, colIndex: 0, direction: 'first', refresh: 'RowPart' }, getCellAddress(sheet.rowCount, 0) + ":" + getCellAddress(sheet.rowCount + threshold - 1, sheet.colCount - 1));
            this.parent.setSheetPropertyOnMute(sheet, 'rowCount', sheet.rowCount + threshold);
            this.parent.viewport.bottomIndex = sheet.rowCount - 1;
        }
    };
    Scroll.prototype.updateNonVirtualCols = function () {
        var sheet = this.parent.getActiveSheet();
        var threshold = this.parent.getThreshold('col');
        if (this.offset.left.idx > sheet.colCount - (this.parent.viewport.colCount + threshold)) {
            this.parent.renderModule.refreshUI({ rowIndex: 0, colIndex: sheet.colCount, direction: 'first', refresh: 'ColumnPart' }, getCellAddress(0, sheet.colCount) + ":" + getCellAddress(sheet.rowCount - 1, sheet.colCount + threshold - 1));
            this.parent.setSheetPropertyOnMute(sheet, 'colCount', sheet.colCount + threshold);
            this.parent.viewport.rightIndex = sheet.colCount - 1;
        }
    };
    Scroll.prototype.updateTopLeftCell = function (increase, isLeft) {
        var sheet = this.parent.getActiveSheet();
        var top = this.offset.top.idx;
        var left = this.offset.left.idx;
        if (!increase) {
            var frozenRow = this.parent.frozenRowCount(sheet);
            top = skipHiddenIdx(sheet, top + frozenRow, true) - frozenRow;
            var frozenCol = this.parent.frozenColCount(sheet);
            left = skipHiddenIdx(sheet, left + frozenCol, true, 'columns') - frozenCol;
        }
        if (isLeft) {
            this.parent.updateTopLeftCell(null, left, 'row');
        }
        else {
            this.parent.updateTopLeftCell(top, null, 'col');
        }
    };
    Scroll.prototype.getRowOffset = function (scrollTop, scrollDown) {
        var temp = this.offset.top.size;
        var sheet = this.parent.getActiveSheet();
        var i = scrollDown ? this.offset.top.idx + 1 : (this.offset.top.idx ? this.offset.top.idx - 1 : 0);
        var frozenRow = this.parent.frozenRowCount(sheet);
        var count = this.parent.scrollSettings.isFinite ? sheet.rowCount : Infinity;
        scrollTop = Math.round(scrollTop);
        while (i < count) {
            if (scrollDown) {
                var rowHeight = getRowHeight(sheet, i - 1 + frozenRow, true);
                temp += rowHeight;
                if (Math.abs(Math.round(temp) - scrollTop) <= 1) { // <=1 -> For other resolution scrollTop value slightly various with row height
                    return { idx: skipHiddenIdx(sheet, i + frozenRow, true) - frozenRow, size: temp };
                }
                if (Math.round(temp) > scrollTop) {
                    return { idx: i - 1, size: temp - rowHeight };
                }
                i++;
            }
            else {
                var rowHeight = getRowHeight(sheet, i + frozenRow, true);
                temp -= rowHeight;
                if (temp <= 0) {
                    return { idx: 0, size: 0 };
                }
                if (Math.abs(Math.round(temp) - scrollTop) <= 1) {
                    return { idx: i, size: temp };
                }
                if (Math.round(temp) < scrollTop) {
                    temp += rowHeight;
                    if (Math.round(temp) > scrollTop) {
                        return { idx: i, size: temp - rowHeight < 0 ? 0 : temp - rowHeight };
                    }
                    else {
                        return { idx: skipHiddenIdx(sheet, i + 1 + frozenRow, true) - frozenRow, size: temp };
                    }
                }
                i--;
            }
        }
        return { idx: this.offset.top.idx, size: this.offset.top.size };
    };
    Scroll.prototype.getColOffset = function (scrollLeft, increase, skipHidden) {
        var temp = this.offset.left.size;
        var sheet = this.parent.getActiveSheet();
        var i = increase ? this.offset.left.idx + 1 : (this.offset.left.idx ? this.offset.left.idx - 1 : 0);
        var frozenCol = this.parent.frozenColCount(sheet);
        var count = this.parent.scrollSettings.isFinite ? sheet.colCount : Infinity;
        while (i < count) {
            if (increase) {
                var colWidth = getColumnWidth(sheet, i - 1 + frozenCol, skipHidden, true);
                temp += colWidth;
                if (Math.abs(Math.round(temp) - scrollLeft) <= 1) {
                    return { idx: skipHiddenIdx(sheet, i + frozenCol, true, 'columns') - frozenCol, size: temp };
                }
                if (Math.round(temp) > scrollLeft) {
                    return { idx: i - 1, size: temp - colWidth };
                }
                i++;
            }
            else {
                var colWidth = getColumnWidth(sheet, i + frozenCol, skipHidden, true);
                temp -= colWidth;
                if (temp <= 0) {
                    return { idx: 0, size: 0 };
                }
                if (Math.abs(Math.round(temp) - scrollLeft) <= 1) {
                    return { idx: i, size: temp };
                }
                if (Math.round(temp) < scrollLeft) {
                    temp += colWidth;
                    if (Math.round(temp) > scrollLeft) {
                        temp = temp - colWidth;
                        return { idx: i, size: temp < 0 ? 0 : temp };
                    }
                    else {
                        return { idx: skipHiddenIdx(sheet, i + 1 + frozenCol, true, 'columns') - frozenCol, size: temp };
                    }
                }
                i--;
            }
        }
        return { idx: this.offset.left.idx, size: this.offset.left.size };
    };
    Scroll.prototype.contentLoaded = function (args) {
        if (!this.parent.scrollSettings.enableVirtualization) {
            var scrollTrack = this.parent.createElement('div', { className: 'e-virtualtrack' });
            this.updateNonVirualScrollWidth({ scrollTrack: scrollTrack });
            this.parent.getScrollElement().appendChild(scrollTrack);
        }
        if (args.left) {
            this.parent.getScrollElement().scrollLeft = args.left;
        }
        this.setScrollEvent();
        if (this.parent.enableRtl) {
            this.initScrollValue = this.parent.getScrollElement().scrollLeft;
        }
    };
    Scroll.prototype.updateNonVirualScrollWidth = function (args) {
        if (!args.scrollTrack) {
            args.scrollTrack = this.parent.getScrollElement().getElementsByClassName('e-virtualtrack')[0];
        }
        args.scrollTrack.style.width = Math.abs(this.parent.getContentTable().getBoundingClientRect().width +
            (this.parent.scrollSettings.isFinite ? this.parent.sheetModule.getScrollSize() : 0)) + "px";
    };
    Scroll.prototype.onHeaderWheel = function (e) {
        e.preventDefault();
        this.parent.getMainContent().parentElement.scrollTop += e.deltaY;
        this.parent.getScrollElement().scrollLeft += e.deltaX;
    };
    Scroll.prototype.onContentWheel = function (e) {
        if (e.deltaX !== 0) {
            e.preventDefault();
            this.parent.getScrollElement().scrollLeft += e.deltaX;
        }
    };
    Scroll.prototype.scrollHandler = function (e) {
        this.onContentScroll({ scrollLeft: e.target.scrollLeft });
    };
    Scroll.prototype.updateScroll = function (args) {
        if (isNullOrUndefined(args.left)) {
            this.parent.sheetModule.contentPanel.scrollTop = args.top;
        }
        else {
            this.parent.getScrollElement().scrollLeft = args.left;
        }
    };
    Scroll.prototype.setScrollEvent = function () {
        EventHandler.add(this.parent.sheetModule.contentPanel, 'scroll', this.onContentScroll, this);
        EventHandler.add(this.parent.getColumnHeaderContent(), 'wheel', this.onHeaderWheel, this);
        EventHandler.add(this.parent.getSelectAllContent(), 'wheel', this.onHeaderWheel, this);
        EventHandler.add(this.parent.getMainContent(), 'wheel', this.onContentWheel, this);
        EventHandler.add(this.parent.getRowHeaderContent(), 'wheel', this.onContentWheel, this);
        EventHandler.add(this.parent.getScrollElement(), 'scroll', this.scrollHandler, this);
    };
    Scroll.prototype.initProps = function () {
        this.topIndex = 0;
        this.leftIndex = 0;
        this.prevScroll = { scrollLeft: 0, scrollTop: 0 };
        this.offset = { left: { idx: 0, size: 0 }, top: { idx: 0, size: 0 } };
    };
    /**
     * @hidden
     *
     * @param {boolean} isRtlChange - Specifies RtlChange or not.
     * @returns {void} - To Set padding
     */
    Scroll.prototype.setPadding = function (isRtlChange) {
        this.parent.sheetModule.contentPanel.style.overflowY = 'scroll';
        var scrollWidth = getScrollBarWidth();
        if (scrollWidth > 0) {
            var colHeader = this.parent.getColumnHeaderContent();
            var cssProps = this.parent.enableRtl ? { margin: 'marginLeft', border: 'borderLeftWidth' }
                : { margin: 'marginRight', border: 'borderRightWidth' };
            colHeader.parentElement.style[cssProps.margin] = scrollWidth + 'px';
            colHeader.style[cssProps.border] = '1px';
        }
        if (isRtlChange) {
            this.initScrollValue = 0;
        }
    };
    Scroll.prototype.setClientX = function (e) {
        if (e.type === 'mousedown' || e.pointerType === 'mouse') {
            return;
        }
        var args = { touchSelectionStarted: false };
        this.parent.notify(selectionStatus, args);
        if (args.touchSelectionStarted || args.isOverlayClicked) {
            return;
        }
        this.clientX = this.getPointX(e);
        var sheetContent = document.getElementById(this.parent.element.id + '_sheet');
        EventHandler.add(sheetContent, Browser.isPointer ? 'pointermove' : 'touchmove', this.onTouchScroll, this);
        EventHandler.add(sheetContent, Browser.isPointer ? 'pointerup' : 'touchend', this.pointerUpHandler, this);
    };
    Scroll.prototype.getPointX = function (e) {
        var clientX = 0;
        if (e.touches && e.touches.length) {
            clientX = e.touches[0].clientX;
        }
        else {
            clientX = e.clientX;
        }
        return clientX;
    };
    Scroll.prototype.onTouchScroll = function (e) {
        if (e.pointerType === 'mouse') {
            return;
        }
        var clientX = this.getPointX(e);
        var diff = this.clientX - clientX;
        var scroller = this.parent.element.getElementsByClassName('e-scroller')[0];
        if ((diff > 10 || diff < -10) && scroller.scrollLeft + diff >= 0) {
            e.preventDefault();
            this.clientX = clientX;
            getUpdateUsingRaf(function () { scroller.scrollLeft += diff; });
        }
    };
    Scroll.prototype.pointerUpHandler = function () {
        var sheetContent = document.getElementById(this.parent.element.id + '_sheet');
        EventHandler.remove(sheetContent, Browser.isPointer ? 'pointermove' : 'touchmove', this.onTouchScroll);
        EventHandler.remove(sheetContent, Browser.isPointer ? 'pointerup' : 'touchend', this.pointerUpHandler);
    };
    Scroll.prototype.addEventListener = function () {
        this.parent.on(contentLoaded, this.contentLoaded, this);
        this.parent.on(onContentScroll, this.onContentScroll, this);
        this.parent.on(updateScroll, this.updateScroll, this);
        this.parent.on(deInitProperties, this.initProps, this);
        this.parent.on(spreadsheetDestroyed, this.destroy, this);
        this.parent.on(mouseDown, this.setClientX, this);
        this.parent.on(updateScrollValue, this.updateScrollValue, this);
        if (!this.parent.scrollSettings.enableVirtualization) {
            this.parent.on(virtualContentLoaded, this.updateNonVirualScrollWidth, this);
            this.parent.on(colWidthChanged, this.updateNonVirualScrollWidth, this);
        }
    };
    Scroll.prototype.destroy = function () {
        this.removeEventListener();
        var ddbEle = document.querySelector('#' + this.parent.element.id + '_autofilloptionbtn');
        if (ddbEle) {
            var ddbObj = getComponent(ddbEle, 'dropdown-btn');
            if (ddbObj) {
                ddbObj.destroy();
            }
        }
        this.parent = null;
    };
    Scroll.prototype.removeEventListener = function () {
        this.parent.off(contentLoaded, this.contentLoaded);
        this.parent.off(onContentScroll, this.onContentScroll);
        this.parent.off(updateScroll, this.updateScroll);
        this.parent.off(deInitProperties, this.initProps);
        this.parent.off(spreadsheetDestroyed, this.destroy);
        this.parent.off(mouseDown, this.setClientX);
        this.parent.off(updateScrollValue, this.updateScrollValue);
        if (!this.parent.scrollSettings.enableVirtualization) {
            this.parent.off(virtualContentLoaded, this.updateNonVirualScrollWidth);
            this.parent.off(colWidthChanged, this.updateNonVirualScrollWidth);
        }
    };
    return Scroll;
}());
export { Scroll };