/* * (c) Copyright Ascensio System SIA 2010-2024 * * This program is a free software product. You can redistribute it and/or * modify it under the terms of the GNU Affero General Public License (AGPL) * version 3 as published by the Free Software Foundation. In accordance with * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect * that Ascensio System SIA expressly excludes the warranty of non-infringement * of any third-party rights. * * This program is distributed WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html * * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish * street, Riga, Latvia, EU, LV-1050. * * The interactive user interfaces in modified source and object code versions * of the Program must display Appropriate Legal Notices, as required under * Section 5 of the GNU AGPL version 3. * * Pursuant to Section 7(b) of the License you must retain the original Product * logo when distributing the program. Pursuant to Section 7(e) we decline to * grant you any rights under trademark law for use of our trademarks. * * All the Product's GUI elements, including illustrations and icon sets, as * well as technical writing content are licensed under the terms of the * Creative Commons Attribution-ShareAlike 4.0 International. See the License * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode * */ "use strict"; (/** * @param {Window} window * @param {undefined} undefined */ function (window, undefined) { /* * Import * ----------------------------------------------------------------------------- */ var CellValueType = AscCommon.CellValueType; var c_oAscBorderStyles = Asc.c_oAscBorderStyles; var c_oAscBorderType = AscCommon.c_oAscBorderType; var c_oAscLockTypes = AscCommon.c_oAscLockTypes; var c_oAscFormatPainterState = AscCommon.c_oAscFormatPainterState; var c_oAscPrintDefaultSettings = AscCommon.c_oAscPrintDefaultSettings; var AscBrowser = AscCommon.AscBrowser; var CColor = AscCommon.CColor; var fSortAscending = AscCommon.fSortAscending; var parserHelp = AscCommon.parserHelp; var gc_nMaxDigCountView = AscCommon.gc_nMaxDigCountView; var gc_nMaxRow0 = AscCommon.gc_nMaxRow0; var gc_nMaxCol0 = AscCommon.gc_nMaxCol0; var gc_nMaxRow = AscCommon.gc_nMaxRow; var gc_nMaxCol = AscCommon.gc_nMaxCol; var History = AscCommon.History; var c_oAscFillType = Asc.c_oAscFillType; var asc = window["Asc"]; var asc_applyFunction = AscCommonExcel.applyFunction; var asc_getcvt = asc.getCvtRatio; var asc_floor = asc.floor; var asc_ceil = asc.ceil; var asc_typeof = asc.typeOf; var asc_incDecFonSize = asc.incDecFonSize; var asc_debug = asc.outputDebugStr; var asc_Range = asc.Range; var asc_CMM = AscCommonExcel.asc_CMouseMoveData; var asc_VR = AscCommonExcel.VisibleRange; var asc_CCellInfo = AscCommonExcel.asc_CCellInfo; var asc_CHyperlink = asc.asc_CHyperlink; var asc_CPageSetup = asc.asc_CPageSetup; var asc_CPagePrint = AscCommonExcel.CPagePrint; var asc_CAutoFilterInfo = AscCommonExcel.asc_CAutoFilterInfo; var c_oTargetType = AscCommonExcel.c_oTargetType; var c_oAscCanChangeColWidth = AscCommonExcel.c_oAscCanChangeColWidth; var c_oAscMergeType = AscCommonExcel.c_oAscMergeType; var c_oAscLockTypeElemSubType = AscCommonExcel.c_oAscLockTypeElemSubType; var c_oAscLockTypeElem = AscCommonExcel.c_oAscLockTypeElem; var c_oAscError = asc.c_oAscError; var c_oAscMergeOptions = asc.c_oAscMergeOptions; var c_oAscInsertOptions = asc.c_oAscInsertOptions; var c_oAscDeleteOptions = asc.c_oAscDeleteOptions; var c_oAscBorderOptions = asc.c_oAscBorderOptions; var c_oAscCleanOptions = asc.c_oAscCleanOptions; var c_oAscSelectionType = asc.c_oAscSelectionType; var c_oAscAutoFilterTypes = asc.c_oAscAutoFilterTypes; var c_oAscChangeTableStyleInfo = asc.c_oAscChangeTableStyleInfo; var c_oAscChangeSelectionFormatTable = asc.c_oAscChangeSelectionFormatTable; var asc_CSelectionMathInfo = AscCommonExcel.asc_CSelectionMathInfo; var c_maxColFillDataCount = 10000; /* * Constants * ----------------------------------------------------------------------------- */ /** * header styles * @const */ var kHeaderDefault = 0; var kHeaderActive = 1; var kHeaderHighlighted = 2; /** * cursor styles * @const */ var kCurDefault = "default"; var kCurCorner = "pointer"; // Курсор для автозаполнения var kCurFillHandle = "crosshair"; // Курсор для гиперссылки var kCurHyperlink = "pointer"; // Курсор для перемещения области выделения var kCurMove = "move"; var kCurSEResize = /*window.rightToleft ? "sw-resize" :*/ "se-resize"; var kCurNEResize = "ne-resize"; var kCurAutoFilter = "pointer"; var kCurEWResize = "ew-resize"; var kCurNSResize = "ns-resize"; AscCommon.g_oHtmlCursor.register(AscCommon.Cursors.CellCur, "6 6", "cell"); AscCommon.g_oHtmlCursor.register(AscCommon.Cursors.CellFormatPainter, "1 1", "pointer"); AscCommon.g_oHtmlCursor.register(AscCommon.Cursors.MoveBorderVer, "9 9", "default"); AscCommon.g_oHtmlCursor.register(AscCommon.Cursors.MoveBorderHor, "9 9", "default"); var kNewLine = "\n"; var kMaxAutoCompleteCellEdit = 20000; var kRowsCacheSize = 64; var gridlineSize = 1; var filterSizeButton = 17; var collapsePivotSizeButton = 10; //limit rows for prepare metrics. if more then limit -> metrics will prepare dynamic var nMaxPrintRows = 150000; function isAllowPasteLink(pastedWb) { var api = window["Asc"]["editor"]; let _core = pastedWb && pastedWb.Core; if (!api || !_core) { return false; } //for portals: //wb.Core.contentStatus -> DocInfo.ReferenceData.fileKey //wb.Core.category -> DocInfo.ReferenceData.instanceId //for desktops: //contentStatus -> filePath if (window["AscDesktopEditor"] && window["AscDesktopEditor"]["IsLocalFile"]()) { let pasteProcessor = AscCommonExcel.g_clipboardExcel && AscCommonExcel.g_clipboardExcel.pasteProcessor; let sameDoc = pasteProcessor && pasteProcessor._checkPastedInOriginalDoc(pastedWb, true); return sameDoc || (_core.contentStatus && !_core.category && window["AscDesktopEditor"]["LocalFileGetSaved"]()); } if (_core.contentStatus && _core.category) { //работаем внутри одного портала //если разные документу, то вставляем ссылку на другой документ, если один и тот же, то вставляем обычную ссылку return api.DocInfo && api.DocInfo.ReferenceData && _core.category === api.DocInfo.ReferenceData["instanceId"]; } return false; } function getMergeType(merged) { var res = c_oAscMergeType.none; if (null !== merged) { if (merged.c1 !== merged.c2) { res |= c_oAscMergeType.cols; } if (merged.r1 !== merged.r2) { res |= c_oAscMergeType.rows; } } return res; } function getFontMetrics(format, stringRender) { var res = AscCommonExcel.g_oCacheMeasureEmpty2.get(format); if (!res) { if (!format.isEqual2(stringRender.drawingCtx.font)) { stringRender.drawingCtx.setFont(format); } res = stringRender.drawingCtx.getFontMetrics(); AscCommonExcel.g_oCacheMeasureEmpty2.add(format, res); } return res; } function getCFIconSize(fontSize) { return AscCommonExcel.cDefIconSize * fontSize / AscCommonExcel.cDefIconFont; } var pivotCollapseButtonClose = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOSIgaGVpZ2h0PSI5IiB2aWV3Qm94PSIwIDAgOSA5IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cmVjdCB4PSIwLjUiIHk9IjAuNSIgd2lkdGg9IjgiIGhlaWdodD0iOCIgZmlsbD0id2hpdGUiIHN0cm9rZT0iI0NBQ0FDQSIvPgo8cGF0aCBkPSJNNSA0VjJINFY0SDJWNUg0VjdINVY1SDdWNEg1WiIgZmlsbD0iIzc4Nzg3OCIvPgo8L3N2Zz4K"; var pivotCollapseButtonOpen = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOSIgaGVpZ2h0PSI5IiB2aWV3Qm94PSIwIDAgOSA5IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cmVjdCB4PSIwLjUiIHk9IjAuNSIgd2lkdGg9IjgiIGhlaWdodD0iOCIgZmlsbD0id2hpdGUiIHN0cm9rZT0iI0NBQ0FDQSIvPgo8cmVjdCB4PSIyIiB5PSI0IiB3aWR0aD0iNSIgaGVpZ2h0PSIxIiBmaWxsPSIjNzg3ODc4Ii8+Cjwvc3ZnPgo="; var asyncOperationsTypes = { mathInfo: 0 }; function getPivotButtonsForLoad() { return [pivotCollapseButtonClose, pivotCollapseButtonOpen]; } function buildRelativePath(fromPath, thisPath) { if (!fromPath || !thisPath) { return null; } let fromTree = fromPath.split("/"); let thisTree = thisPath.split("/"); if (fromTree[0] === thisTree[0]) { if (fromTree.length < thisTree.length) { // "/" + from // from root: "/root/from1.xlsx" return fromPath.substring(thisTree[0].length); } else { //if this is part of from let fromIsPartOfTo = true; for (let i = 0; i < thisTree.length - 1; i++) { if (fromTree[i] !== thisTree[i]) { fromIsPartOfTo = false; break; } } if (fromIsPartOfTo) { // "inside/inside2/inseide3/inside4/from2.xlsx" // "from2.xlsx" let path = ""; for (let i = thisTree.length - 1; i < fromTree.length; i++) { path += (path === "" ? "" : "/") + fromTree[i]; } return path; } else { // from root: "/root/from1.xlsx" return fromPath.substring(thisTree[0].length); } } } //return absolute path // "file:///C:\root\from1.xlsx" return "file:///" + fromPath.replaceAll("/", "\\"); } function CacheColumn() { this.left = 0; this.width = 0; this._widthForPrint = null; } function CacheRow() { this.top = 0; this.height = 0; // Высота с точностью до 1 px this.descender = 0; this._heightForPrint = null; } function CacheElement() { this.columnsWithText = {}; // Колонки, в которых есть текст this.columns = {}; this.erased = {}; return this; } function CacheElementText() { this.state = null; this.flags = null; this.metrics = null; this.cellW = null; this.cellHA = null; this.cellVA = null; this.sideL = null; this.sideR = null; this.cellType = null; this.isFormula = false; this.angle = null; this.textBound = null; this.indent = null; } function Cache() { this.rows = {}; this.sectors = []; this.reset = function () { this.rows = {}; this.sectors = []; }; // Structure of cache // // cache : { // // rows : { // 0 : { // columns : { // 0 : { // text : { // cellHA : String, // cellVA : String, // cellW : Number, // color : String, // metrics : TextMetrics, // sideL : Number, // sideR : Number, // state : StringRenderInternalState // } // } // }, // erased : { // 1 : true, 2 : true // } // } // }, // // sectors: [ // 0 : true // 9 : true // ] // // } } function CellFlags() { this.wrapText = false; this.verticalText = false; this.shrinkToFit = false; this.merged = null; this.textAlign = null; this.ctrlKey = null; this.shiftKey = null; this.readingOrder = null; } CellFlags.prototype.clone = function () { var oRes = new CellFlags(); oRes.wrapText = this.wrapText; oRes.shrinkToFit = this.shrinkToFit; oRes.merged = this.merged ? this.merged.clone() : null; oRes.textAlign = this.textAlign; oRes.verticalText = this.verticalText; oRes.readingOrder = this.readingOrder; return oRes; }; CellFlags.prototype.isMerged = function () { return null !== this.merged; }; CellFlags.prototype.getMergeType = function () { return getMergeType(this.merged); }; CellFlags.prototype.getReadingOrder = function () { return this.readingOrder; }; function CellBorderObject(borders, mergeInfo, col, row) { this.borders = borders; this.mergeInfo = mergeInfo; this.col = col; this.row = row; } CellBorderObject.prototype.isMerge = function () { return null != this.mergeInfo; }; CellBorderObject.prototype.getLeftBorder = function () { if (!this.borders || (this.isMerge() && (this.col !== this.mergeInfo.c1 || this.col - 1 !== this.mergeInfo.c2))) { return null; } return this.borders.getL(); }; CellBorderObject.prototype.getRightBorder = function () { if (!this.borders || (this.isMerge() && (this.col - 1 !== this.mergeInfo.c1 || this.col !== this.mergeInfo.c2))) { return null; } return this.borders.getR(); }; CellBorderObject.prototype.getTopBorder = function () { if (!this.borders || (this.isMerge() && (this.row !== this.mergeInfo.r1 || this.row - 1 !== this.mergeInfo.r2))) { return null; } return this.borders.getT(); }; CellBorderObject.prototype.getBottomBorder = function () { if (!this.borders || (this.isMerge() && (this.row - 1 !== this.mergeInfo.r1 || this.row !== this.mergeInfo.r2))) { return null; } return this.borders.getB(); }; /** * Widget for displaying and editing Worksheet object * ----------------------------------------------------------------------------- * @param {WorkbookView} workbook WorkbookView * @param {Worksheet} model Worksheet * @param {AscCommonExcel.asc_CHandlersList} handlers Event handlers * @param {Object} buffers DrawingContext + Overlay * @param {AscCommonExcel.StringRender} stringRender StringRender * @param {Number} maxDigitWidth Максимальный размер цифры * @param {CCollaborativeEditing} collaborativeEditing * @param {Object} settings Settings * * @constructor * @memberOf Asc */ function WorksheetView(workbook, model, handlers, buffers, stringRender, maxDigitWidth, collaborativeEditing, settings) { this.settings = settings; this.workbook = workbook; this.handlers = handlers; this.model = model; this.buffers = buffers; this.drawingCtx = this.buffers.main; this.overlayCtx = this.buffers.overlay; this.drawingGraphicCtx = this.buffers.mainGraphic; this.overlayGraphicCtx = this.buffers.overlayGraphic; this.stringRender = stringRender; // Флаг, сигнализирует о том, что мы сделали resize, но это не активный лист (поэтому как только будем показывать, нужно перерисовать и пересчитать кеш) this.updateResize = false; // Флаг, сигнализирует о том, что мы сменили zoom, но это не активный лист (поэтому как только будем показывать, нужно перерисовать и пересчитать кеш) this.updateZoom = false; this.isZooming = false; // ToDo Флаг-заглушка, для того, чтобы на mobile не было изменения высоты строк при zoom (по правильному высота просто не должна меняться) this.notUpdateRowHeight = false; this.cache = new Cache(); //---member declaration--- // Максимальная ширина числа из 0,1,2...,9, померенная в нормальном шрифте(дефалтовый для книги) в px(целое) // Ecma-376 Office Open XML Part 1, пункт 18.3.1.13 this.maxDigitWidth = maxDigitWidth; this.defaultColWidthChars = 0; this.defaultColWidthPx = 0; this.defaultRowHeightPx = 0; this.defaultRowDescender = 0; this.defaultSpaceWidth = 0; this.headersLeft = 0; this.headersTop = 0; this.headersWidth = 0; this.headersHeight = 0; this.headersHeightByFont = 0; // Размер по шрифту (размер без скрытия заголовков) this.groupWidth = 0; this.groupHeight = 0; this.cellsLeft = 0; this.cellsTop = 0; this.cols = []; this.rows = []; this.highlightedCol = -1; this.highlightedRow = -1; this.topLeftFrozenCell = null; // Верхняя ячейка для закрепления диапазона this.visibleRange = new asc_Range(0, 0, 0, 0); this.isChanged = false; this.isChartAreaEditMode = false; this.lockDraw = false; this.isSelectOnShape = false; // Выделен shape this.startCellMoveResizeRange = null; this.startCellMoveResizeRange2 = null; this.moveRangeDrawingObjectTo = null; // Координаты ячейки начала перемещения диапазона this.startCellMoveRange = null; // Дипазон перемещения this.activeMoveRange = null; // Range for drag and drop this.dragAndDropRange = null; // Range fillHandle this.activeFillHandle = null; this.resizeTableIndex = null; // Горизонтальное (0) или вертикальное (1) направление автозаполнения this.fillHandleDirection = -1; // Зона автозаполнения this.fillHandleArea = -1; this.nRowsCount = 0; this.nColsCount = 0; // Other ranges for draw (sparklines info, chart ranges or formula ranges) this.oOtherRanges = null; //------------------------ this.collaborativeEditing = collaborativeEditing; this.drawingArea = new AscFormat.DrawingArea(this); this.cellCommentator = new AscCommonExcel.CCellCommentator(this); this.objectRender = null; this.arrRecalcRanges = []; this.arrRecalcRangesWithHeight = []; this.arrRecalcRangesCanChangeColWidth = []; this.skipUpdateRowHeight = false; this.canChangeColWidth = c_oAscCanChangeColWidth.none; this.scrollType = 0; this.updateRowHeightValuePx = null; this.updateColumnsStart = Number.MAX_VALUE; this.viewPrintLines = false; this.copyCutRange = null; this.usePrintScale = false;//флаг нужен для того, чтобы возвращался scale только в случае печати, а при отрисовке, допустим сектки, он был равен 1 this.arrRowGroups = null; this.arrColGroups = null; this.clickedGroupButton = null; this.ignoreGroupSize = null;//для печати не нужно учитывать отступы групп //ифомарция о залоченности нового добавленного правила //TODO пока сюда добавляю, пересмотреть! this._lockAddNewRule = null; this._lockAddProtectedRange = null; //добавляю константы для расчётов без зума this.maxDigitWidthForPrint = null; this.defaultColWidthPxForPrint = null; this.pagesModeData = null; this.pageBreakPreviewSelectionRange = null; this.asyncOperations = null; this.traceDependentsManager = new AscCommonExcel.TraceDependentsManager(this); //settings for split draw/ this.renderingSettings = null; this.cellPasteHelper = new CCellPasteHelper(this); this.vScrollPxStep = null; this.hScrollPxStep = null; this._replaceCellTextManager = null; this._init(); return this; } WorksheetView.prototype._init = function () { this._initTopLeftCell(); this._initWorksheetDefaultWidth(); this._initWorksheetDefaultWidthForPrint(); this._initPane(); this._updateGroups(); this._updateGroups(true); this._initCellsArea(AscCommonExcel.recalcType.full); this.model.setTableStyleAfterOpen(); this.model.setDirtyConditionalFormatting(null); this.model.updatePivotTablesStyle(null); this._cleanCellsTextMetricsCache(); this._prepareCellTextMetricsCache(); // initializing is completed this.handlers.trigger("initialized"); }; WorksheetView.prototype.getOleSize = function () { return this.workbook && this.workbook.model.getOleSize(); }; WorksheetView.prototype.setOleSize = function (oPr) { return this.workbook && this.workbook.model.setOleSize(oPr); }; WorksheetView.prototype._initWorksheetDefaultWidth = function () { // Теперь рассчитываем число px this.defaultColWidthChars = this.model.charCountToModelColWidth(this.model.getBaseColWidth()); this.defaultColWidthPx = this.model.modelColWidthToColWidth(this.defaultColWidthChars); // Делаем кратным 8 (http://support.microsoft.com/kb/214123) this.defaultColWidthPx = asc_ceil(this.defaultColWidthPx / 8) * 8; this.defaultColWidthChars = this.model.colWidthToCharCount(this.defaultColWidthPx); AscCommonExcel.oDefaultMetrics.ColWidthChars = this.model.charCountToModelColWidth(this.defaultColWidthChars); var defaultColWidth = this.model.getDefaultWidth(); if (null !== defaultColWidth) { this.defaultColWidthPx = this.model.modelColWidthToColWidth(defaultColWidth); } // ToDo разобраться со значениями this._setDefaultFont(undefined); var tm = this._roundTextMetrics(this.stringRender.measureString("A")); this.headersHeightByFont = tm.height; this.maxRowHeightPx = AscCommonExcel.convertPtToPx(Asc.c_oAscMaxRowHeight); this.defaultRowDescender = this.stringRender.lines[0].d; AscCommonExcel.oDefaultMetrics.RowHeight = Math.min(Asc.c_oAscMaxRowHeight, this.model.getDefaultHeight() || AscCommonExcel.convertPxToPt(this.headersHeightByFont)); this.defaultRowHeightPx = AscCommonExcel.convertPtToPx(AscCommonExcel.oDefaultMetrics.RowHeight); var tmSpace = this._roundTextMetrics(this.stringRender.measureString(" ")); if (tmSpace) { this.defaultSpaceWidth = tmSpace.width; } // ToDo refactoring this.model.setDefaultHeight(AscCommonExcel.oDefaultMetrics.RowHeight); // Инициализируем число колонок и строк (при открытии). Причем нужно поставить на 1 больше, // чтобы могли показать последнюю строку/столбец (http://bugzilla.onlyoffice.com/show_bug.cgi?id=23513) this._initRowsCount(); this._initColsCount(); this.model.initColumns(); this._initScrollStep(); }; WorksheetView.prototype.createImageFromMaxRange = function () { var range = this.getOleSize().getLast(); var drawingContext = this.printForOleObject(range); return drawingContext.canvas.toDataURL(); }; WorksheetView.prototype.createImageForChart = function (idx) { var charts = this.getCharts(); if (idx) { charts = charts.filter(function (drawing) { return drawing.graphicObject.Id === idx; }); } var oChart = charts[0]; var image = oChart.getBase64Img(); return image; }; WorksheetView.prototype.getCharts = function () { var charts = []; function appendChart(obj) { if (obj.getObjectType() === AscDFH.historyitem_type_ChartSpace) { charts.push(obj); } } this.model.handleDrawings(appendChart); return charts; }; WorksheetView.prototype.getCurrentChart = function() { if(this.isSelectOnShape) { let aSelectedDrawings = this.objectRender.controller.getSelectedArray(); if(aSelectedDrawings.length === 1 && aSelectedDrawings[0].isChart()) { return aSelectedDrawings[0]; } } return null; }; WorksheetView.prototype.getRangesForCharts = function () { let aRanges; let oCurChart = this.getCurrentChart(); if(oCurChart) { let sChartRange = oCurChart.getCommonRange(); if(!sChartRange) { return null; } aRanges = AscFormat.fParseChartFormulaExternal(sChartRange); } if(!aRanges) { aRanges = this.getSelectedRanges(); } if(!aRanges) { return null; } return aRanges; }; WorksheetView.prototype.getRecommendedChartData = function() { return AscFormat.ExecuteNoHistory(function() { let aRanges = this.getRangesForCharts(); if(!aRanges) return null; let aResultCheckRange = aRanges; if(aRanges.length === 1 && aRanges[0].isOneCell()) { let oBBox = this.model.autoFilters.expandRange(aRanges[0].bbox, true); let oRange = AscCommonExcel.Range.prototype.createFromBBox(this.model, oBBox); aResultCheckRange = [oRange]; } if(aResultCheckRange.length > 2) { let oFirstRange = aResultCheckRange[0]; let oSecondRange = aResultCheckRange[1]; if(!oFirstRange.isEqualCols(oSecondRange) && !oFirstRange.isEqualRows(oSecondRange)) { return null; } let bRows = oFirstRange.isEqualRows(oSecondRange); for(let nRange = 2; nRange < aResultCheckRange.length; ++nRange) { let oCurRange = aResultCheckRange[nRange]; if(bRows) { if(!oFirstRange.isEqualRows(oCurRange)) { return null; } } else { if(!oFirstRange.isEqualCols(oCurRange)) { return null; } } } } let bEmpty = true; for(let nRange = 0; nRange < aResultCheckRange.length; ++nRange) { let oRange = aResultCheckRange[nRange]; oRange._foreachNoEmpty(function (oCell) { if(AscFormat.isRealNumber(oCell.getNumberValue())) { bEmpty = false; return true; } return null; }, undefined, true); if(!bEmpty) { break; } } if(bEmpty) { return null; } const oDataRefs = new AscFormat.CChartDataRefs(null); const nHorCheckError = oDataRefs.checkDataRangeRefs(aResultCheckRange, true, Asc.c_oAscChartTypeSettings.unknown); const nVertCheckError = oDataRefs.checkDataRangeRefs(aResultCheckRange, false, Asc.c_oAscChartTypeSettings.unknown); if(Asc.c_oAscError.ID.No !== nHorCheckError && Asc.c_oAscError.ID.No !== nVertCheckError) { return null; } let oResultMap = {}; let aCharts = []; let aSeriesRefsHor = oDataRefs.getSeriesRefsFromUnionRefs(aResultCheckRange, true, false); let aSeriesRefsVer = oDataRefs.getSeriesRefsFromUnionRefs(aResultCheckRange, false, false); if(aSeriesRefsHor.length === 1 || aSeriesRefsVer.length === 1) { //bar, hbar, linear, pie let aSeriesRef = aSeriesRefsHor.length === 1 ? aSeriesRefsHor : aSeriesRefsVer; let oBarCS = this.getChartByType(Asc.c_oAscChartTypeSettings.barNormal, aSeriesRef); aCharts.push(oBarCS); let oHBarCS = this.getChartByType(Asc.c_oAscChartTypeSettings.hBarNormal, aSeriesRef); aCharts.push(oHBarCS); let oPieChart = this.getChartByType(Asc.c_oAscChartTypeSettings.pie, aSeriesRef); aCharts.push(oPieChart); if(aSeriesRefsHor.length > 1 || aSeriesRefsVer.length > 1) { let oLineCS = this.getChartByType(Asc.c_oAscChartTypeSettings.lineNormal, aSeriesRef); aCharts.push(oLineCS); } for(let nChart = 0; nChart < aCharts.length; ++nChart) { let oCS = aCharts[nChart]; oCS.setBDeleted(false); oCS.setWorksheet(this.model); AscFormat.CheckSpPrXfrm(oCS); oCS.allPreviewCharts = aCharts; let nType = oCS.getChartType(); if(!Array.isArray(oResultMap[nType])) { oResultMap[nType] = []; } oResultMap[nType].push(oCS); } return oResultMap; } let aSeriesRefsArr = []; if(aSeriesRefsHor.length >= aSeriesRefsVer.length) { aSeriesRefsArr.push(aSeriesRefsVer); } if(aSeriesRefsHor.length <= aSeriesRefsVer.length) { aSeriesRefsArr.push(aSeriesRefsHor); } for(let nSerArr = 0; nSerArr < aSeriesRefsArr.length; ++nSerArr) { let aSeriesRef = aSeriesRefsArr[nSerArr]; //bar, hbar, linear, hbarstacked, barstacked, barstackedper, hbarstackedper; let oBarCS = this.getChartByType(Asc.c_oAscChartTypeSettings.barNormal, aSeriesRef); aCharts.push(oBarCS); let oHBarCS = this.getChartByType(Asc.c_oAscChartTypeSettings.hBarNormal, aSeriesRef); aCharts.push(oHBarCS); let oLineCS = this.getChartByType(Asc.c_oAscChartTypeSettings.lineNormal, aSeriesRef); aCharts.push(oLineCS); let oHBarStackedCS = this.getChartByType(Asc.c_oAscChartTypeSettings.hBarStacked, aSeriesRef); aCharts.push(oHBarStackedCS); let oBarStackedCS = this.getChartByType(Asc.c_oAscChartTypeSettings.barStacked, aSeriesRef); aCharts.push(oBarStackedCS); let oBarStackedPerCS = this.getChartByType(Asc.c_oAscChartTypeSettings.barStackedPer, aSeriesRef); aCharts.push(oBarStackedPerCS); let oHBarStackedPerCS = this.getChartByType(Asc.c_oAscChartTypeSettings.hBarStackedPer, aSeriesRef); aCharts.push(oHBarStackedPerCS); } let aScatterSeriesRefsHor = oDataRefs.getSeriesRefsFromUnionRefs(aResultCheckRange, true, true); let aScatterSeriesRefsVer = oDataRefs.getSeriesRefsFromUnionRefs(aResultCheckRange, false, true); aSeriesRefsArr = []; if(aScatterSeriesRefsHor.length >= aScatterSeriesRefsVer.length) { aSeriesRefsArr.push(aScatterSeriesRefsVer); } if(aScatterSeriesRefsHor.length <= aScatterSeriesRefsVer.length) { aSeriesRefsArr.push(aScatterSeriesRefsHor); } for(let nSerArr = 0; nSerArr < aSeriesRefsArr.length; ++nSerArr) { let aSeriesRef = aSeriesRefsArr[nSerArr]; let oScatterCS = this.getChartByType(Asc.c_oAscChartTypeSettings.scatterMarker, aSeriesRef); aCharts.push(oScatterCS); } for(let nChart = 0; nChart < aCharts.length; ++nChart) { let oCS = aCharts[nChart]; oCS.setBDeleted(false); oCS.setWorksheet(this.model); AscFormat.CheckSpPrXfrm(oCS); oCS.allPreviewCharts = aCharts; let nType = oCS.getChartType(); if(!Array.isArray(oResultMap[nType])) { oResultMap[nType] = []; } oResultMap[nType].push(oCS); } return oResultMap; }, this, []); }; WorksheetView.prototype.getChartByType = function(nType, aSeriesRef) { let oCurChart = this.getCurrentChart(); let oChartSpace; if(oCurChart) { oChartSpace = oCurChart.copy(); oChartSpace.buildSeries(aSeriesRef); oChartSpace.changeChartType(nType); } else { let oDrawingsController = this.objectRender.controller; oChartSpace = oDrawingsController._getChartSpace([], {type: nType}, false); oChartSpace.buildSeries(aSeriesRef); let oProps = Asc.editor.asc_getChartSettings(true); oProps.chartSpace = null; oProps.removeAllAxesProps(); oProps.putType(nType); oDrawingsController.applyPropsToChartSpace(oProps, oChartSpace); } return oChartSpace; } WorksheetView.prototype.getChartData = function(nType) { return AscFormat.ExecuteNoHistory(function() { let aRanges = this.getRangesForCharts(); let aResult = []; if(!aRanges) { let oCurChart = this.getCurrentChart(); if(oCurChart) { let oChartSpace = oCurChart.copy(); if(oChartSpace.changeChartType(nType)) { oChartSpace.setWorksheet(this.model); oChartSpace.allPreviewCharts = aResult; AscFormat.CheckSpPrXfrm(oChartSpace); aResult.push(oChartSpace); return aResult; } } return null; } const oDataRefs = new AscFormat.CChartDataRefs(null); const bIsScatter = AscFormat.isScatterChartType(nType); let aSeriesRefsHor = oDataRefs.getSeriesRefsFromUnionRefs(aRanges, true, bIsScatter); let aSeriesRefsVer = oDataRefs.getSeriesRefsFromUnionRefs(aRanges, false, bIsScatter); let oChartSpace; let aParams = []; function getSeriesMaxValCount(aSeries) { let nMaxCount = 0; for(let nS = 0; nS < aSeries.length; ++nS) { let nValCount = aSeries[nS].getValCellsCount(); if(nValCount > nMaxCount) { nMaxCount = nValCount; } } return nMaxCount; } if(AscFormat.isComboChartType(nType)) { if(aSeriesRefsHor.length <= aSeriesRefsVer.length) { if(oDataRefs.checkValidDataRangeRefs(aRanges, true, nType)) { aParams.push({ bHorValue: true, aSeries: aSeriesRefsHor }); } else { if(oDataRefs.checkValidDataRangeRefs(aRanges, false, nType)) { aParams.push({ bHorValue: false, aSeries: aSeriesRefsVer }); } } } else { if(oDataRefs.checkValidDataRangeRefs(aRanges, false, nType)) { aParams.push({ bHorValue: false, aSeries: aSeriesRefsVer, }); } else { if(oDataRefs.checkValidDataRangeRefs(aRanges, true, nType)) { aParams.push({ bHorValue: true, aSeries: aSeriesRefsHor }); } } } } else if(AscFormat.isAreaChartType(nType) || AscFormat.isRadarChartType(nType) || AscFormat.isLineChartType(nType) || AscFormat.isScatterChartType(nType) || AscFormat.isDoughnutChartType(nType)) { let nMinPtCount; if(AscFormat.isRadarChartType(nType)) { nMinPtCount = 3; } else { nMinPtCount = 2; } if(getSeriesMaxValCount(aSeriesRefsHor) >= nMinPtCount) { aParams.push({ bHorValue: true, aSeries: aSeriesRefsHor }); } if(getSeriesMaxValCount(aSeriesRefsVer) >= nMinPtCount) { aParams.push({ bHorValue: false, aSeries: aSeriesRefsVer }); } if(aParams.length === 0) { aParams.push({ bHorValue: true, aSeries: aSeriesRefsHor }); } } else if(AscFormat.isPieChartType(nType)) { if(aSeriesRefsHor.length <= aSeriesRefsVer.length) { aParams.push({ bHorValue: true, aSeries: aSeriesRefsHor }); if(aSeriesRefsHor.length === 2) { aParams.push({ bHorValue: true, aSeries: oDataRefs.getSeriesRefsFromUnionRefs(aRanges, true, true) }); } } else { aParams.push({ bHorValue: false, aSeries: aSeriesRefsVer }); if(aSeriesRefsVer.length === 2) { aParams.push({ bHorValue: false, aSeries: oDataRefs.getSeriesRefsFromUnionRefs(aRanges, false, true) }); } } } else { aParams.push({ bHorValue: true, aSeries: aSeriesRefsHor }); aParams.push({ bHorValue: false, aSeries: aSeriesRefsVer }); } let nError = Asc.c_oAscError.ID.No; for(let nParam = 0; nParam < aParams.length; ++nParam) { let oParam = aParams[nParam]; nError = oDataRefs.checkDataRangeRefs(aRanges, oParam.bHorValue, nType) if(nError === Asc.c_oAscError.ID.No) { oChartSpace = this.getChartByType(nType, oParam.aSeries); if(oChartSpace) { aResult.push(oChartSpace); oChartSpace.setBDeleted(false); oChartSpace.setWorksheet(this.model); oChartSpace.allPreviewCharts = aResult; AscFormat.CheckSpPrXfrm(oChartSpace); } } } if(aResult.length === 0 && nError !== Asc.c_oAscError.ID.No) { return nError; } return aResult; }, this, []); }; WorksheetView.prototype._initWorksheetDefaultWidthForPrint = function () { var defaultPpi = 96; var truePPIX = this.drawingCtx.ppiX; var truePPIY = this.drawingCtx.ppiY; var retinaPixelRatio = this.getRetinaPixelRatio(); var needReplacePpi = truePPIX !== defaultPpi || truePPIY !== defaultPpi; if (needReplacePpi) { this.drawingCtx.ppiY = 96; this.drawingCtx.ppiX = 96; AscBrowser.retinaPixelRatio = 1; //this.workbook._calcMaxDigitWidth(); } var defaultColWidthChars = this.model.charCountToModelColWidth(this.model.getBaseColWidth()); var defaultColWidthPx = this.model.modelColWidthToColWidth(defaultColWidthChars); this.maxDigitWidthForPrint = this.model.workbook.maxDigitWidth; this.defaultColWidthPxForPrint = asc_ceil(defaultColWidthPx / 8) * 8; var defaultColWidth = this.model.getDefaultWidth(); if (null !== defaultColWidth) { this.defaultColWidthPxForPrint = this.model.modelColWidthToColWidth(defaultColWidth); } var tm = this._roundTextMetrics(this.stringRender.measureString("A")); var headersHeightByFont = tm.height; this.defaultRowHeightForPrintPt = Math.min(Asc.c_oAscMaxRowHeight, this.model.getDefaultHeight() || AscCommonExcel.convertPxToPt(headersHeightByFont)); if (needReplacePpi) { this.drawingCtx.ppiY = truePPIY; this.drawingCtx.ppiX = truePPIX; AscBrowser.retinaPixelRatio = retinaPixelRatio; //this.workbook._calcMaxDigitWidth(); } }; WorksheetView.prototype._initRowsCount = function () { var old = this.nRowsCount; this.nRowsCount = Math.min(Math.max(this.model.getRowsCount(), this.visibleRange.r2) + 1, gc_nMaxRow); return old !== this.nRowsCount; }; WorksheetView.prototype._initColsCount = function () { var old = this.nColsCount; this.setColsCount(Math.min(Math.max(this.model.getColsCount(), this.visibleRange.c2) + 1, gc_nMaxCol)); return old !== this.nColsCount; }; WorksheetView.prototype._initScrollStep = function () { let isMobileVersion = this.workbook && this.workbook.Api && this.workbook.Api.isMobileVersion; if (isMobileVersion) { let oView = this.workbook && this.workbook.controller && this.workbook.controller.settings; let defaultStep = 10; this.vScrollPxStep = oView ? oView.vscrollStep : defaultStep; this.hScrollPxStep = oView ? oView.hscrollStep : defaultStep; } else { let defaultColWidthPx = this.defaultColWidthPx; if (!defaultColWidthPx) { let defaultColWidthChars = this.model.charCountToModelColWidth(this.model.getBaseColWidth()); defaultColWidthPx = this.model.modelColWidthToColWidth(defaultColWidthChars); } this.vScrollPxStep = this.defaultRowHeightPx; this.hScrollPxStep = defaultColWidthPx; } }; WorksheetView.prototype.getCellEditMode = function () { return this.workbook.isCellEditMode; }; WorksheetView.prototype.getFormulaEditMode = function () { return this.workbook.isFormulaEditMode; }; WorksheetView.prototype.getSelectionDialogMode = function () { return this.workbook.selectionDialogMode; }; WorksheetView.prototype.getDialogOtherRanges = function () { return !this.workbook.isWizardMode; }; WorksheetView.prototype.getCellVisibleRange = function (col, row, opt_ignore_contains) { var vr, offsetX = 0, offsetY = 0, cFrozen, rFrozen; if (this.topLeftFrozenCell) { cFrozen = this.topLeftFrozenCell.getCol0() - 1; rFrozen = this.topLeftFrozenCell.getRow0() - 1; if (col <= cFrozen && row <= rFrozen) { vr = new asc_Range(0, 0, cFrozen, rFrozen); } else if (col <= cFrozen) { vr = new asc_Range(0, this.visibleRange.r1, cFrozen, this.visibleRange.r2); offsetY -= this._getRowTop(rFrozen + 1) - this.cellsTop; } else if (row <= rFrozen) { vr = new asc_Range(this.visibleRange.c1, 0, this.visibleRange.c2, rFrozen); offsetX -= this._getColLeft(cFrozen + 1) - this.cellsLeft; } else { vr = this.visibleRange; offsetX -= this._getColLeft(cFrozen + 1) - this.cellsLeft; offsetY -= this._getRowTop(rFrozen + 1) - this.cellsTop; } } else { vr = this.visibleRange; } offsetX += this._getOffsetX(vr.c1, true); offsetY += this._getOffsetY(vr.r1, true); return (opt_ignore_contains || !opt_ignore_contains && vr.contains(col, row)) ? new asc_VR(vr, offsetX, offsetY) : null; }; WorksheetView.prototype.getCellMetrics = function (col, row, opt_check_merge, opt_ignore_contains) { let vr; if (vr = this.getCellVisibleRange(col, row, opt_ignore_contains)) { let _width, _height, mc; if (opt_check_merge && (mc = this.model.getMergedByCell(row, col))) { col = mc.c1; row = mc.r1; _width = (this._getColLeft(mc.c2 + 1) - this._getColLeft(mc.c1)); _height = (this._getRowTop(mc.r2 + 1) - this._getRowTop(mc.r1)); } else { _width = this._getColumnWidth(col); _height = this._getRowHeight(row); } return { left: this._getColLeft(col) - vr.offsetX, top: this._getRowTop(row) - vr.offsetY, width: _width, height: _height }; } return null; }; WorksheetView.prototype.getFrozenCell = function () { return this.topLeftFrozenCell; }; WorksheetView.prototype.getVisibleRange = function () { return this.visibleRange; }; WorksheetView.prototype.getFirstVisibleCol = function (allowPane) { var tmp = 0; if (allowPane && this.topLeftFrozenCell) { tmp = this.topLeftFrozenCell.getCol0(); } return this.visibleRange.c1 - tmp; }; WorksheetView.prototype.getLastVisibleCol = function () { return this.visibleRange.c2; }; WorksheetView.prototype.getFirstVisibleRow = function (allowPane) { var tmp = 0; if (allowPane && this.topLeftFrozenCell) { tmp = this.topLeftFrozenCell.getRow0(); } return this.visibleRange.r1 - tmp; }; WorksheetView.prototype.getFirstVisibleRowSmoothScroll = function (allowPane) { var frozenVisibleRangeHeight = 0; if (allowPane && this.topLeftFrozenCell) { let tmp = this.topLeftFrozenCell.getRow0(); frozenVisibleRangeHeight = this._getRowTop(tmp) - this.cellsTop; } //new scroll - calculate height before vr let beforeVisibleRangeHeight = this._getRowTop(this.visibleRange.r1) - this.cellsTop; beforeVisibleRangeHeight += this.getScrollCorrect(); let defaultScrollPxStep = Asc.round(this.getVScrollStep()); return defaultScrollPxStep === 0 ? 0 : ((beforeVisibleRangeHeight - frozenVisibleRangeHeight)/defaultScrollPxStep); }; WorksheetView.prototype.getVerticalSmoothScrollRange = function (bCheckEqual) { var offsetFrozen = this.getFrozenPaneOffset(true, false); var ctxH = this.drawingCtx.getHeight() - offsetFrozen.offsetY - this.cellsTop; for (var h = 0, i = this.nRowsCount - 1; i >= 0; --i) { h += this._getRowHeight(i); if (h >= ctxH) { if (bCheckEqual && h > ctxH) { i++; } break; } } var frozenVisibleRangeHeight = 0; if (this.topLeftFrozenCell) { let tmp = this.topLeftFrozenCell.getRow0(); frozenVisibleRangeHeight = this._getRowTop(tmp) - this.cellsTop; } //TODO /*if (gc_nMaxRow === this.nRowsCount || this.model.isDefaultHeightHidden()) { tmp -= 1; }*/ let isMobileVersion = this.workbook && this.workbook.Api && this.workbook.Api.isMobileVersion; let row = Math.max(0, i); // Диапазон скрола должен быть меньше количества строк, чтобы не было прибавления строк при перетаскивании бегунка let defaultScrollPxStep = Asc.round(this.getVScrollStep()); let beforeVisibleRangeHeight = this._getRowTop(row) - this.cellsTop; if (isMobileVersion || AscCommonExcel.c_oAscScrollType.ScrollInitRowsColsCount & this.scrollType) { beforeVisibleRangeHeight += this.getScrollCorrect(); } return defaultScrollPxStep === 0 ? 0 : ((beforeVisibleRangeHeight - frozenVisibleRangeHeight)/defaultScrollPxStep); }; WorksheetView.prototype.getFirstVisibleColSmoothScroll = function (allowPane) { var frozenVisibleRangeWidth = 0; if (allowPane && this.topLeftFrozenCell) { let tmp = this.topLeftFrozenCell.getCol0(); frozenVisibleRangeWidth = this._getColLeft(tmp) - this.cellsLeft; } //new scroll - calculate height before vr let beforeVisibleRangeWidth = this._getColLeft(this.visibleRange.c1) - this.cellsLeft; beforeVisibleRangeWidth += this.getHorizontalScrollCorrect(); let defaultScrollPxStep = Asc.round(this.getHScrollStep()); return defaultScrollPxStep === 0 ? 0 : ((beforeVisibleRangeWidth - frozenVisibleRangeWidth)/defaultScrollPxStep); }; WorksheetView.prototype.getHorizontalSmoothScrollRange = function (/*bCheckEqual*/) { var offsetFrozen = this.getFrozenPaneOffset(false, true); var ctxW = this.drawingCtx.getWidth() - offsetFrozen.offsetX - this.cellsLeft; for (var h = 0, i = this.nColsCount - 1; i >= 0; --i) { h += this._getColumnWidth(i); if (h >= ctxW) { /*if (bCheckEqual && h > ctxH) { i++; }*/ break; } } var frozenVisibleRangeWidth = 0; if (this.topLeftFrozenCell) { let tmp = this.topLeftFrozenCell.getCol0(); frozenVisibleRangeWidth = this._getColLeft(tmp) - this.cellsLeft; } //TODO /*if (gc_nMaxRow === this.nRowsCount || this.model.isDefaultHeightHidden()) { tmp -= 1; }*/ let isMobileVersion = this.workbook && this.workbook.Api && this.workbook.Api.isMobileVersion; let col = Math.max(0, i); // Диапазон скрола должен быть меньше количества строк, чтобы не было прибавления строк при перетаскивании бегунка let defaultScrollPxStep = Asc.round(this.getHScrollStep()); let beforeVisibleRangeWidth = this._getColLeft(col) - this.cellsLeft; if (isMobileVersion || AscCommonExcel.c_oAscScrollType.ScrollInitRowsColsCount & this.scrollType) { beforeVisibleRangeWidth += this.getHorizontalScrollCorrect(); } return defaultScrollPxStep === 0 ? 0 : ((beforeVisibleRangeWidth - frozenVisibleRangeWidth)/defaultScrollPxStep); }; WorksheetView.prototype.getLastVisibleRow = function () { return this.visibleRange.r2; }; WorksheetView.prototype.getHorizontalScrollRange = function () { if (this.workbook.getSmoothScrolling()) { return this.getHorizontalSmoothScrollRange(); } var offsetFrozen = this.getFrozenPaneOffset(false, true); var ctxW = this.drawingCtx.getWidth() - offsetFrozen.offsetX - this.cellsLeft; for (var w = 0, i = this.nColsCount - 1; i >= 0; --i) { w += this._getColumnWidth(i); if (w >= ctxW) { break; } } var tmp = 0; if (this.topLeftFrozenCell) { tmp = this.topLeftFrozenCell.getCol0(); } if (gc_nMaxCol === this.nColsCount || this.model.isDefaultWidthHidden()) { tmp -= 1; } return Math.max(0, i - tmp); // Диапазон скрола должен быть меньше количества столбцов, чтобы не было прибавления столбцов при перетаскивании бегунка }; WorksheetView.prototype.getVerticalScrollRange = function (bCheckEqual) { if (this.workbook.getSmoothScrolling()) { return this.getVerticalSmoothScrollRange(bCheckEqual); } var offsetFrozen = this.getFrozenPaneOffset(true, false); var ctxH = this.drawingCtx.getHeight() - offsetFrozen.offsetY - this.cellsTop; for (var h = 0, i = this.nRowsCount - 1; i >= 0; --i) { h += this._getRowHeight(i); if (h >= ctxH) { if (bCheckEqual && h > ctxH) { i++; } break; } } var tmp = 0; if (this.topLeftFrozenCell) { tmp = this.topLeftFrozenCell.getRow0(); } if (gc_nMaxRow === this.nRowsCount || this.model.isDefaultHeightHidden()) { tmp -= 1; } return Math.max(0, i - tmp); // Диапазон скрола должен быть меньше количества строк, чтобы не было прибавления строк при перетаскивании бегунка }; WorksheetView.prototype.getHorizontalScrollMax = function () { var tmp = 0; if (this.topLeftFrozenCell) { tmp = this.topLeftFrozenCell.getCol0(); } return (this.model.isDefaultWidthHidden() ? this.nColsCount : gc_nMaxCol) - tmp - 1; }; WorksheetView.prototype.getVerticalScrollMax = function () { var tmp = 0; if (this.topLeftFrozenCell) { tmp = this.topLeftFrozenCell.getRow0(); } return (this.model.isDefaultHeightHidden() ? this.nRowsCount : gc_nMaxRow) - tmp - 1; }; WorksheetView.prototype.getCellsOffset = function (units) { var u = units >= 0 && units <= 3 ? units : 0; return { left: this.cellsLeft * asc_getcvt(0/*px*/, u, this._getPPIX()), top: this.cellsTop * asc_getcvt(0/*px*/, u, this._getPPIY()) }; }; WorksheetView.prototype._getColLeft = function (i, saveRealRightToLeft, ctx) { ctx = ctx || this.drawingCtx; this._updateColumnPositions(); let realRightToleft = this.getRightToLeft(); if (!saveRealRightToLeft) { this.setRightToLeft(false); } var l = this.cols.length; let defaultWidth = Asc.round(this.defaultColWidthPx * this.getZoom(true) * this.getRetinaPixelRatio()); let posReal = this.cellsLeft + ((i < l) ? this.cols[i].left : (((0 === l) ? 0 : this.cols[l - 1].left + this.cols[l - 1].width) + (!this.model.isDefaultWidthHidden()) * defaultWidth * (i - l))); if (this.getRightToLeft()) { posReal = (this.getCtxWidth(ctx)) - posReal - (i < l ? this.cols[i].width : defaultWidth); } this.setRightToLeft(realRightToleft); return posReal; }; WorksheetView.prototype.getCellLeft = function (column, units, saveRealRtl) { var u = units >= 0 && units <= 3 ? units : 0; return this._getColLeft(column, saveRealRtl) * asc_getcvt(0/*px*/, u, this._getPPIX()); }; WorksheetView.prototype._getRowHeightReal = function (i) { // Реальная высота из файла (может быть не кратна 1 px, в Excel можно выставить через меню строки) var h = -1; this.model._getRowNoEmptyWithAll(i, function (row) { if (row) { if (row.getHidden()) { h = 0; } else if (row.h > 0 && (row.getCustomHeight() || row.getCalcHeight())) { h = row.h; } } }); return (h < 0) ? AscCommonExcel.oDefaultMetrics.RowHeight : h; }; WorksheetView.prototype._getRowDescender = function (i) { return (i < this.rows.length) ? this.rows[i].descender : this.defaultRowDescender; }; WorksheetView.prototype._getRowTop = function (i) { var l = this.rows.length; return (i < l) ? this.rows[i].top : (((0 === l) ? this.cellsTop : this.rows[l - 1].top + this.rows[l - 1].height) + (!this.model.isDefaultHeightHidden()) * Asc.round(this.defaultRowHeightPx * this.getZoom()) * (i - l)); }; WorksheetView.prototype.getCellTop = function (row, units) { var u = units >= 0 && units <= 3 ? units : 0; return this._getRowTop(row) * asc_getcvt(0/*px*/, u, this._getPPIY()); }; WorksheetView.prototype.getCellLeftRelative = function (col, units, checkFrozenOffset) { if (col < 0 || col >= this.nColsCount) { return null; } // С учетом видимой области var offsetX = 0; let frozenOffset = null; if (this.topLeftFrozenCell) { var cFrozen = this.topLeftFrozenCell.getCol0(); if (col < cFrozen) { offsetX = 0; } else { frozenOffset = this._getColLeft(cFrozen); offsetX = this._getColLeft(this.visibleRange.c1) - frozenOffset + this.getHorizontalScrollCorrect(); } } else { offsetX = this._getOffsetX(); } var u = units >= 0 && units <= 3 ? units : 0; let _left = this._getColLeft(col) - offsetX; if (_left < this.cellsLeft) { _left = this.cellsLeft; } if (checkFrozenOffset && frozenOffset && _left < frozenOffset) { _left = frozenOffset; } return _left * asc_getcvt(0/*px*/, u, this._getPPIX()); }; WorksheetView.prototype.getCellTopRelative = function (row, units, checkFrozenOffset) { if (row < 0 || row >= this.nRowsCount) { return null; } // С учетом видимой области var offsetY = 0; let frozenOffset = null; if (this.topLeftFrozenCell) { var rFrozen = this.topLeftFrozenCell.getRow0(); if (row < rFrozen) { offsetY = 0; } else { frozenOffset = this._getRowTop(rFrozen); offsetY = this._getRowTop(this.visibleRange.r1) - frozenOffset + this.getScrollCorrect(); } } else { offsetY = this._getOffsetY(); } var u = units >= 0 && units <= 3 ? units : 0; let _top = this._getRowTop(row) - offsetY; if (_top < this.cellsTop) { _top = this.cellsTop; } if (checkFrozenOffset && frozenOffset && _top < frozenOffset) { _top = frozenOffset; } return _top * asc_getcvt(0/*px*/, u, this._getPPIY()); }; WorksheetView.prototype._getColumnWidthInner = function (i) { return Math.max(this._getColumnWidth(i) - this.settings.cells.padding * 2 - gridlineSize, 0); }; WorksheetView.prototype._getColumnWidth = function (i) { return (i < this.cols.length) ? this.cols[i].width : (!this.model.isDefaultWidthHidden()) * Asc.round(this.defaultColWidthPx * this.getZoom(true) * this.getRetinaPixelRatio()); }; WorksheetView.prototype._getWidthForPrint = function (i) { if (i >= this.cols.length && !this.model.isDefaultWidthHidden() && this.defaultColWidthPxForPrint) { return this.defaultColWidthPxForPrint * this.getZoom(true); } else if (i < this.cols.length && this.maxDigitWidthForPrint && this.cols[i]._widthForPrint) { return this.cols[i]._widthForPrint * this.getZoom(true); } return null; }; WorksheetView.prototype._getHeightForPrint = function (i) { //_heightForPrint и defaultRowHeightForPrintPt всегда в пунктах, здесь перевожу в px var height; if (i < this.rows.length) { height = this.rows[i]._heightForPrint !== null ? this.rows[i]._heightForPrint : this.defaultRowHeightForPrintPt; } else { height = (!this.model.isDefaultHeightHidden()) * this.defaultRowHeightForPrintPt; } let realretinaPixelRatio = this.getRetinaPixelRatio(); AscBrowser.retinaPixelRatio = 1; height = AscCommonExcel.convertPtToPx(height); AscBrowser.retinaPixelRatio = realretinaPixelRatio; return height * this.getZoom(); }; WorksheetView.prototype.getColumnWidth = function (index, units) { var u = units >= 0 && units <= 3 ? units : 0; return this._getColumnWidth(index) * asc_getcvt(0/*px*/, u, this._getPPIX()); }; WorksheetView.prototype.getColumnWidthInSymbols = function (index) { var c = this.model._getColNoEmptyWithAll(index); return (c && c.charCount) || this.defaultColWidthChars; }; WorksheetView.prototype.getSelectedColumnWidthInSymbols = function () { var i, charCount, res = null; var range = this.model.selectionRange.getLast(); for (i = range.c1; i <= range.c2; ++i) { charCount = this.getColumnWidthInSymbols(i); if (null !== res && res !== charCount) { return null; } res = charCount; if (i >= this.cols.length) { break; } } return res; }; WorksheetView.prototype.getSelectedRowHeight = function () { var i, hR, res = null; var range = this.model.selectionRange.getLast(); for (i = range.r1; i <= range.r2; ++i) { hR = this._getRowHeightReal(i); if (null !== res && res !== hR) { return null; } res = hR; if (i >= this.rows.length) { break; } } return res; }; WorksheetView.prototype._getRowHeight = function (i) { return (i < this.rows.length) ? this.rows[i].height : (!this.model.isDefaultHeightHidden()) * Asc.round(this.defaultRowHeightPx * this.getZoom()); }; WorksheetView.prototype.getRowHeight = function (index, units) { var u = units >= 0 && units <= 3 ? units : 0; return this._getRowHeight(index) * asc_getcvt(0/*px*/, u, this._getPPIY()); }; WorksheetView.prototype.getSelectedRange = function () { // ToDo multiselect ? var lastRange = this.model.getSelection().getLast(); return this._getRange(lastRange.c1, lastRange.r1, lastRange.c2, lastRange.r2); }; WorksheetView.prototype.getSelectedRanges = function () { var selection = this.model.getSelection(); var aRanges = selection && selection.ranges; if (!aRanges) { return null; } var ret = []; var oRange; for (var i = 0; i < aRanges.length; ++i) { oRange = aRanges[i]; ret.push(this._getRange(oRange.c1, oRange.r1, oRange.c2, oRange.r2)) } return ret; }; WorksheetView.prototype.resize = function (isUpdate, editor) { if (isUpdate) { this._initCellsArea(AscCommonExcel.recalcType.newLines); this._normalizeViewRange(); this._prepareCellTextMetricsCache(); this.updateResize = false; this.objectRender.resizeCanvas(); if (this.getRightToLeft()) { AscFormat.ExecuteNoHistory(function () { let drawings = this.objectRender.controller.getDrawingObjects(); for (var i = 0; i < drawings.length; ++i) { if (!drawings[i].group) { AscFormat.CheckSpPrXfrm3(drawings[i], true); } else { AscFormat.CheckSpPrXfrm(drawings[i], true); } } this.objectRender.controller.recalculate(true); }, this, []); } if (editor) { editor.move(); } } else { this.updateResize = true; } return this; }; WorksheetView.prototype.getZoom = function (checkShowFormulasZoom) { let showFormulasKf = 1; if (checkShowFormulasZoom) { let viewSettings = this.model.getSheetView(); if (viewSettings && viewSettings.showFormulas) { showFormulasKf = 2; } } return this.drawingCtx.getZoom()* showFormulasKf; }; WorksheetView.prototype.getPrintScale = function () { var res = 1; if(this.usePrintScale) { var printOptions = this.model.PagePrintOptions; res = printOptions && printOptions.pageSetup ? printOptions.pageSetup.scale : 100; res = res / 100; } return res; }; WorksheetView.prototype.changeZoom = function (isUpdate, changeZoomOnPrint) { this.setScrollCorrect(0); this.setHorizontalScrollCorrect(0); if (isUpdate || changeZoomOnPrint) { this.isZooming = true; this.notUpdateRowHeight = true; this.cleanSelection(); this._updateGroupsWidth(); this._initCellsArea(AscCommonExcel.recalcType.recalc); this._normalizeViewRange(); this._cleanCellsTextMetricsCache(); // ToDo check this if (!changeZoomOnPrint) { this._scrollToRange(); } this._prepareCellTextMetricsCache(); this.cellCommentator.updateActiveComment(); window['AscCommon'].g_specialPasteHelper.SpecialPasteButton_Update_Position(); Asc.editor.toggleChartElementsCallback(); this.handlers.trigger("toggleAutoCorrectOptions", null, true); this.handlers.trigger("onDocumentPlaceChanged"); this._updateDrawingArea(); this.updateZoom = false; this.isZooming = false; this.notUpdateRowHeight = false; } else { this.updateZoom = true; } return this; }; WorksheetView.prototype.changeZoomResize = function () { this.cleanSelection(); this._initCellsArea(AscCommonExcel.recalcType.full); this._normalizeViewRange(); this._cleanCellsTextMetricsCache(); // ToDo check this this._scrollToRange(); this._prepareCellTextMetricsCache(); this.cellCommentator.updateActiveComment(); window['AscCommon'].g_specialPasteHelper.SpecialPasteButton_Update_Position(); Asc.editor.toggleChartElementsCallback(); this.handlers.trigger("onDocumentPlaceChanged"); this._updateDrawingArea(); this.updateResize = false; this.updateZoom = false; }; WorksheetView.prototype.getSheetViewSettings = function (bNotClone) { return this.model.getSheetViewSettings(bNotClone); }; WorksheetView.prototype.getFrozenPaneOffset = function (noX, noY) { var offsetX = 0, offsetY = 0; if (this.topLeftFrozenCell) { if (!noX) { var cFrozen = this.topLeftFrozenCell.getCol0(); offsetX = this._getColLeft(cFrozen) - this._getColLeft(0); } if (!noY) { var rFrozen = this.topLeftFrozenCell.getRow0(); offsetY = this._getRowTop(rFrozen) - this._getRowTop(0); } } return {offsetX: offsetX, offsetY: offsetY}; }; // mouseX - это разница стартовых координат от мыши при нажатии и границы WorksheetView.prototype.changeColumnWidth = function (col, x2, mouseX) { if (this.model.isUserProtectedRangesIntersection(new Asc.Range(col, 0, col, gc_nMaxRow0))) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ProtectedRangeByOtherUser, c_oAscError.Level.NoCritical); return; } if (this.model.getSheetProtection(Asc.c_oAscSheetProtectType.formatColumns)) { return; } if (this.getRightToLeft()) { x2 = this.getCtxWidth() - x2; } var viewMode = this.handlers.trigger('getViewMode'); var t = this; // Учитываем координаты точки, где мы начали изменение размера x2 += mouseX; var offsetFrozenX = 0; var c1 = t.visibleRange.c1; if (this.topLeftFrozenCell) { var cFrozen = this.topLeftFrozenCell.getCol0() - 1; if (0 <= cFrozen) { if (col < c1) { c1 = 0; } else { offsetFrozenX = t._getColLeft(cFrozen + 1) - t._getColLeft(0); } } } var offsetX = t._getOffsetX(c1); offsetX -= offsetFrozenX; var x1 = t._getColLeft(col) - offsetX - gridlineSize; var w = Math.max(x2 - x1, 0); if (w === this._getColumnWidth(col)) { return; } w = Asc.round(w / ((this.getZoom(true) * this.getRetinaPixelRatio()))); var cc = Math.min(this.model.colWidthToCharCount(w), Asc.c_oAscMaxColumnWidth); var onChangeWidthCallback = function (isSuccess) { if (false === isSuccess) { return; } if (viewMode) { History.TurnOff(); } var getHiddenMap = function (start, end, opt_compare) { var res = null; for (var j = start; j < end; j++) { if (opt_compare) { if (t.model.getColHidden(j) !== opt_compare[j]) { if (!res) { res = {}; } res[j] = t.model.getColHidden(j); } } else { if (!res) { res = {}; } res[j] = t.model.getColHidden(j); } } return res; }; var getRangesFromMap = function (_tempArrAfter, container) { if (!_tempArrAfter) { return; } for (var j in _tempArrAfter) { var _oRange = new AscCommonExcel.Range(t.model, 0, parseInt(j), gc_nMaxRow0, parseInt(j)); container.push(_oRange); } }; var bIsHidden = t.model.getColHidden(col); History.Create_NewPoint(); History.StartTransaction(); var bIsHiddenArr; var startUpdateCol = col; var _selectionRange = t.model.selectionRange; if (_selectionRange && _selectionRange.ranges && _selectionRange.isContainsOnlyFullRowOrCol(true) && _selectionRange.containsCol(col)) { bIsHiddenArr = []; for (var i = 0; i < _selectionRange.ranges.length; i++) { var _range = _selectionRange.ranges[i]; var _tempArr = getHiddenMap(_range.c1, _range.c2); t.model.setColWidth(cc, _range.c1, _range.c2); if (_range.c1 < startUpdateCol) { startUpdateCol = _range.c1; } getRangesFromMap(getHiddenMap(_range.c1, _range.c2, _tempArr), bIsHiddenArr); } } else { t.model.setColWidth(cc, col, col); } History.EndTransaction(); t._cleanCache(new asc_Range(0, 0, t.cols.length - 1, t.rows.length - 1)); if(t.objectRender) { t.objectRender.bUpdateMetrics = false; } t.changeWorksheet("update", {reinitRanges: true, viewModeUpdate: viewMode}); t._updateGroups(true, undefined, undefined, true); t._updateVisibleColsCount(); t.cellCommentator.updateActiveComment(); t.cellCommentator.updateAreaComments(); if(t.objectRender) { t.objectRender.bUpdateMetrics = true; } if (bIsHiddenArr) { if (bIsHiddenArr.length) { Asc.editor.wb.handleDrawingsOnWorkbookChange(bIsHiddenArr); } } else if (bIsHidden !== t.model.getColHidden(col)) { var oRange = new AscCommonExcel.Range(t.model, 0, col, gc_nMaxRow0, col); Asc.editor.wb.handleDrawingsOnWorkbookChange([oRange]); } if (t.objectRender) { var oTarget = { target: AscCommonExcel.c_oTargetType.ColumnResize, col: startUpdateCol }; t.objectRender.updateSizeDrawingObjects(oTarget); t.objectRender.updateDrawingsTransform(oTarget); } if (viewMode) { History.TurnOn(); } }; if (viewMode) { onChangeWidthCallback(true); } else { this._isLockedAll(onChangeWidthCallback); } }; // mouseY - это разница стартовых координат от мыши при нажатии и границы WorksheetView.prototype.changeRowHeight = function (row, y2, mouseY) { if (this.model.isUserProtectedRangesIntersection(new Asc.Range(0, row, gc_nMaxCol0, row))) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ProtectedRangeByOtherUser, c_oAscError.Level.NoCritical); return; } if (this.model.getSheetProtection(Asc.c_oAscSheetProtectType.formatRows)) { return; } var viewMode = this.handlers.trigger('getViewMode'); var t = this; // Учитываем координаты точки, где мы начали изменение размера y2 += mouseY; var offsetFrozenY = 0; var r1 = this.visibleRange.r1; if (this.topLeftFrozenCell) { var rFrozen = this.topLeftFrozenCell.getRow0() - 1; if (0 <= rFrozen) { if (row < r1) { r1 = 0; } else { offsetFrozenY = this._getRowTop(rFrozen + 1) - this._getRowTop(0); } } } var offsetY = this._getOffsetY(r1); offsetY -= offsetFrozenY; var y1 = this._getRowTop(row) - offsetY - gridlineSize; var newHeight = Math.max(y2 - y1, 0); if (newHeight === this._getRowHeight(row)) { return; } newHeight = Math.min(this.maxRowHeightPx, Asc.round(newHeight / this.getZoom())); var onChangeHeightCallback = function (isSuccess) { if (false === isSuccess) { return; } var bIsHidden = t.model.getRowHidden(row); if (viewMode) { History.TurnOff(); } var getHiddenMap = function (start, end, opt_compare) { var res = null; for (var j = start; j < end; j++) { if (opt_compare) { if (t.model.getRowHidden(j) !== opt_compare[j]) { if (!res) { res = {}; } res[j] = t.model.getRowHidden(j); } } else { if (!res) { res = {}; } res[j] = t.model.getRowHidden(j); } } return res; }; var getRangesFromMap = function (_tempArrAfter, container) { if (!_tempArrAfter) { return; } for (var j in _tempArrAfter) { var _oRange = new AscCommonExcel.Range(t.model, parseInt(j), gc_nMaxCol0, parseInt(j), gc_nMaxCol0); container.push(_oRange); } }; History.Create_NewPoint(); History.StartTransaction(); var bIsHiddenArr; var startUpdateRow = row; var endUpdateRow = row; var _selectionRange = t.model.selectionRange; if (_selectionRange && _selectionRange.ranges && _selectionRange.isContainsOnlyFullRowOrCol() && _selectionRange.containsRow(row)) { bIsHiddenArr = []; for (var i = 0; i < _selectionRange.ranges.length; i++) { var _range = _selectionRange.ranges[i]; var _tempArr = getHiddenMap(_range.r1, _range.r2); t.model.setRowHeight(AscCommonExcel.convertPxToPt(newHeight), _range.r1, _range.r2, true); if (_range.r1 < startUpdateRow) { startUpdateRow = _range.r1; } if (_range.r2 > endUpdateRow) { endUpdateRow = _range.r2; } getRangesFromMap(getHiddenMap(_range.r1, _range.r2, _tempArr), bIsHiddenArr); } } else { t.model.setRowHeight(AscCommonExcel.convertPxToPt(newHeight), row, row, true); } History.EndTransaction(); var updateRange = new asc_Range(0, startUpdateRow, t.cols.length - 1, endUpdateRow); t.model.autoFilters.reDrawFilter(updateRange); t._cleanCache(updateRange); if(t.objectRender) { t.objectRender.bUpdateMetrics = false; } t.changeWorksheet("update", {reinitRanges: true, viewModeUpdate: viewMode}); t._updateGroups(false, undefined, undefined, true); t._updateVisibleRowsCount(); t.cellCommentator.updateActiveComment(); t.cellCommentator.updateAreaComments(); if(t.objectRender) { t.objectRender.bUpdateMetrics = true; } if (bIsHiddenArr) { if (bIsHiddenArr.length) { Asc.editor.wb.handleDrawingsOnWorkbookChange(bIsHiddenArr); } } else if (bIsHidden !== t.model.getRowHidden(row)) { var oRange = new AscCommonExcel.Range(t.model, row, gc_nMaxCol0, row, gc_nMaxCol0); Asc.editor.wb.handleDrawingsOnWorkbookChange([oRange]); } if (t.objectRender) { var oTarget = { target: AscCommonExcel.c_oTargetType.RowResize, row: startUpdateRow }; t.objectRender.updateSizeDrawingObjects(oTarget); t.objectRender.updateDrawingsTransform(oTarget); } if (viewMode) { History.TurnOn(); } }; if (viewMode) { onChangeHeightCallback(true); } else { this._isLockedAll(onChangeHeightCallback); } }; // Checks if there are non-empty values ​​in a range WorksheetView.prototype._getValuesPositionsInRange = function (onlyNumbers) { /* The onlyNumbers flag checks all values ​​except string values */ let cell, cellType, exist = false, setCols = {}, setRows = {}; let selection = this.model.getSelection(); let selectionRange = selection.getLast(); let mergedRange = this.model.getMergedByCell(selectionRange.r1, selectionRange.c1); if (mergedRange && mergedRange.isEqual(selectionRange)) { // There is no need to do anything for one cell return null; } if (c_oAscSelectionType.RangeMax === selectionRange.getType()) { return null; } let c2 = Math.min(selectionRange.c2, this.nColsCount - 1); let r2 = Math.min(selectionRange.r2, this.nRowsCount - 1); for (let c = selectionRange.c1; c <= c2; ++c) { for (let r = selectionRange.r1; r <= r2; ++r) { cell = this._getCellTextCache(c, r, true); if (cell) { // We found a non-empty cell, let's check the format cellType = cell.cellType; // When performing autocomplete formula, all data types except string are treated as numeric if ((null == cellType || CellValueType.Number === cellType || CellValueType.Bool === cellType || CellValueType.Error === cellType || CellValueType.String === cellType)) { if (!(onlyNumbers && CellValueType.String === cellType)) { exist = setRows[r] = setCols[c] = true; } } } } } if (exist) { // Making arrays unique and sorting let i, arrCols = [], arrRows = []; for(i in setCols) { arrCols.push(+i); } for(i in setRows) { arrRows.push(+i); } return {arrCols: arrCols.sort(fSortAscending), arrRows: arrRows.sort(fSortAscending)}; } else { return null; } }; WorksheetView.prototype._getAutocompleteValues = function () { const t = this; let canExecuteFormula; /* setRows|setCols - arrays with positions of all real elements */ /* setNumberRows|setNumberCols - arrays with positions of all "numeric" elements */ let setCols = [], setRows = [], setNumberCols = [], setNumberRows = []; let selection = this.model.getSelection(); let selectionRange = selection.getLast(); let mergedRange = this.model.getMergedByCell(selectionRange.r1, selectionRange.c1); if (mergedRange && mergedRange.isEqual(selectionRange)) { // There is no need to do anything for one cell return null; } if (c_oAscSelectionType.RangeMax === selectionRange.getType()) { return null; } let c2 = Math.min(selectionRange.c2, this.nColsCount - 1); let r2 = Math.min(selectionRange.r2, this.nRowsCount - 1); if (selectionRange.c1 === c2 && selectionRange.r1 === r2 && selectionRange.isOneCell()) { return null; } for (let c = selectionRange.c1; c <= c2; ++c) { for (let r = selectionRange.r1; r <= r2; ++r) { let cellCache = this._getCellTextCache(c, r, true); if (cellCache) { if (!canExecuteFormula) { this.model._getCellNoEmpty(r, c, function (cell) { if (cell && !cell.isNullText() && cell.type !== CellValueType.String) { let xfs = cell.getCompiledStyle(); let numFormatStr, info; if (xfs && xfs.num) { // numFormatStr = xfs.num.getNumFormat(); info = xfs.asc_getNumFormatInfo(); } if (!info) { canExecuteFormula = true } else if (info && info.type !== Asc.c_oAscNumFormatType.Date && info.type !== Asc.c_oAscNumFormatType.LongDate && info.type !== Asc.c_oAscNumFormatType.None && info.type !== Asc.c_oAscNumFormatType.Text) { canExecuteFormula = true } } }); } if (cellCache.cellType !== CellValueType.String) { if (setNumberRows.indexOf(r) === -1) { setNumberRows.push(r); } if (setNumberCols.indexOf(c) === -1) { setNumberCols.push(c); } } if (setRows.indexOf(r) === -1) { setRows.push(r); } if (setCols.indexOf(c) === -1) { setCols.push(c); } } } } if (canExecuteFormula && (setRows.length > 0 || setCols.length > 0) && (setNumberRows.length > 0 || setNumberCols.length > 0)) { // return an object with information about the positions of real and only numeric values return { allExistedValPos: {arrCols: setCols.sort(fSortAscending), arrRows: setRows.sort(fSortAscending)}, allNumberPos: {arrCols: setNumberCols.sort(fSortAscending), arrRows: setNumberRows.sort(fSortAscending)} }; } else { return null; } }; // Autocomplete formula with range if possible WorksheetView.prototype.autoCompleteFormula = function (functionName, callFromWizard) { const t = this; // ToDo autoComplete with multiselect let selection = this.model.getSelection(); let activeCell = selection.activeCell; let ar = selection.getLast(); let arCopy = null; let arHistorySelect = ar.clone(true); let vr = this.visibleRange; // First top cell with data let topCell = null; // First left cell with data let leftCell = null; let r = activeCell.row - 1; let c = activeCell.col - 1; let cell, cellType, isNumberFormat; let result = {}; let hasNumber = !callFromWizard && this._getAutocompleteValues(); // Get all valid values ​​for autocomplete according to the cell format and type let functionAction = null; let changedRange = null; const onAutoCompleteFormula = function (isSuccess) { if (false === isSuccess) { return; } History.Create_NewPoint(); History.SetSelection(arHistorySelect.clone()); History.SetSelectionRedo(arCopy.clone()); History.StartTransaction(); asc_applyFunction(functionAction); History.EndTransaction(); t.getSelectionMathInfo(function (info) { t.handlers.trigger("selectionMathInfoChanged", info); }); let selectionType = ar.getType && ar.getType(); if (selectionType === c_oAscSelectionType.RangeCol) { t.scrollType |= AscCommonExcel.c_oAscScrollType.ScrollVertical; } else if (selectionType === c_oAscSelectionType.RangeRow) { t.scrollType |= AscCommonExcel.c_oAscScrollType.ScrollHorizontal; } else if (selectionType === c_oAscSelectionType.RangeMax) { t.scrollType |= AscCommonExcel.c_oAscScrollType.ScrollVertical | AscCommonExcel.c_oAscScrollType.ScrollHorizontal; } t.draw(); }; /* If the first value in the select is a string, then: if there are numeric values ​​and there are more than 1, then cut the select to the first value in the column/row if there is one numeric value, then we do not change the select and perform the same actions as when selecting one numeric cell (empty SUM) If the last value in the select exists (non empty), then move the select +1 from the current one (column or row), We write the autosum only in empty cells of the select (right or left) If there are none, then expand the select down or to the right By default, the select expands downwards, except in cases where one line is selected (r2 - r1 === 0) or the number of numeric values ​​in the column is 1 */ let val, text, merged; let firstCell = this._getCellTextCache(ar.c1, ar.r1, true); let lastCell = this._getCellTextCache(ar.c2, ar.r2, true); let isSingleCellSelection = (ar.r1 === ar.r2) && (ar.c1 === ar.c2); let isSingleRowColSelection = (ar.r1 === ar.r2) || (ar.c1 === ar.c2); if (hasNumber) { let i; let realValues = hasNumber.allExistedValPos; hasNumber = hasNumber.allNumberPos; // Are there numeric values ​​in the last row and column let hasNumberInLastColumn = (ar.c2 === hasNumber.arrCols[hasNumber.arrCols.length - 1]); let hasNumberInLastRow = (ar.r2 === hasNumber.arrRows[hasNumber.arrRows.length - 1]); let numberElementsInCol = hasNumber.arrRows.length; let numberElementsInRow = hasNumber.arrCols.length; // Are there any non-empty values ​​in the last row and column let hasRealElementInLastCol = (ar.c2 === realValues.arrCols[realValues.arrCols.length - 1]); let hasRealElementInLastRow = (ar.r2 === realValues.arrRows[realValues.arrRows.length - 1]); let realElementsInCol = realValues.arrRows.length; let realElementsInRow = realValues.arrCols.length; // Should execution be stopped let breakExec; // Is necessary to reduce the selection area (if it has actually decreased) let startRow = (ar.c2 - ar.c1) > 0 ? hasNumber.arrRows[0] : ar.r1; let startCol = hasNumber.arrRows.length === 1 ? ar.c1 : hasNumber.arrCols[0]; // Old range borders let startColOld = ar.c1; let startRowOld = ar.r1; // Need to update and redraw Selection let bIsUpdate = false; if (startColOld !== startCol || startRowOld !== startRow) { bIsUpdate = true; } if (true === hasNumberInLastRow && true === hasNumberInLastColumn) { bIsUpdate = true; } if (firstCell && firstCell.cellType === CellValueType.String) { // If the first cell is a string, cut the select to the first non-empty value if (hasNumberInLastColumn && hasNumberInLastRow && (numberElementsInCol === 1 && numberElementsInRow === 1)) { // Last value is number bIsUpdate = false; // set active cell to the end of the select activeCell.row = ar.r2; activeCell.col = ar.c2; breakExec = true; } else { // set selection by last number value startRow = hasNumber.arrRows[0]; startCol = hasNumber.arrCols[0]; bIsUpdate = true; } } else if ((realElementsInRow === 1 && realElementsInCol === 1) && (hasNumberInLastColumn && hasNumberInLastRow)) { // The last cell is a number - need to expand the select startRow = ar.r1; startCol = ar.c1; bIsUpdate = true; } else if (hasRealElementInLastRow && hasRealElementInLastCol) { bIsUpdate = true; } if (bIsUpdate) { this.cleanSelection(); ar.c1 = startCol; ar.r1 = startRow; if (false === ar.contains(activeCell.col, activeCell.row)) { // Move the active cell in the selection activeCell.col = startCol; activeCell.row = startRow; } let newRealValues = this._getValuesPositionsInRange(); hasRealElementInLastCol = (ar.c2 === newRealValues.arrCols[newRealValues.arrCols.length - 1]); hasRealElementInLastRow = (ar.r2 === newRealValues.arrRows[newRealValues.arrRows.length - 1]); if ((true === hasRealElementInLastCol || true === hasRealElementInLastRow)) { // Expanding the range if (1 === hasNumber.arrRows.length && (ar.c2 - ar.c1 /*startColOld*/) > 0) { // We increase to the right, only if the selected range in columns is more than 1 cell and only one row contains values if ((newRealValues.arrCols[newRealValues.arrCols.length - 1] === ar.c2)) { ar.c2 += 1; } } // else if (hasRealElementInLastRow && (ar.r2 - ar.r1 /*startRowOld*/) > 0) { // If selecting by rows is more than 1 cell and there is no free space for the formula in the last row, increase down if ((newRealValues.arrRows[newRealValues.arrRows.length - 1] === ar.r2)) { ar.r2 += 1; } } } this._drawSelection(); } if (!breakExec){ arCopy = ar.clone(true); if (false === hasNumberInLastColumn && false === hasNumberInLastRow) { // Значений нет ни в последней строке ни в последнем столбце (значит нужно сделать формулы в каждой последней ячейке) changedRange = [new asc_Range(hasNumber.arrCols[0], arCopy.r2, hasNumber.arrCols[hasNumber.arrCols.length - 1], arCopy.r2), new asc_Range(arCopy.c2, hasNumber.arrRows[0], arCopy.c2, hasNumber.arrRows[hasNumber.arrRows.length - 1])]; functionAction = function () { // Пройдемся по последней строке for (i = 0; i < hasNumber.arrCols.length; ++i) { c = hasNumber.arrCols[i]; cell = t._getVisibleCell(c, arCopy.r2); if (cell.hasMerged()) { continue; } text = (new asc_Range(c, arCopy.r1, c, arCopy.r2 - 1)).getName(); val = t.generateAutoCompleteFormula(functionName, text); // ToDo - при вводе формулы в заголовок автофильтра надо писать "0" cell.setValue(val); } // Пройдемся по последнему столбцу for (i = 0; i < hasNumber.arrRows.length; ++i) { r = hasNumber.arrRows[i]; cell = t._getVisibleCell(arCopy.c2, r); if (cell.hasMerged()) { continue; } text = (new asc_Range(arCopy.c1, r, arCopy.c2 - 1, r)).getName(); val = t.generateAutoCompleteFormula(functionName, text); cell.setValue(val); } // Значение в правой нижней ячейке cell = t._getVisibleCell(arCopy.c2, arCopy.r2); if (!cell.hasMerged()) { text = (new asc_Range(arCopy.c1, arCopy.r2, arCopy.c2 - 1, arCopy.r2)).getName(); val = t.generateAutoCompleteFormula(functionName, text); cell.setValue(val); } }; } else if (true === hasNumberInLastRow && false === hasNumberInLastColumn) { // Есть значения только в последней строке (значит нужно заполнить только последнюю колонку) changedRange = new asc_Range(arCopy.c2, hasNumber.arrRows[0], arCopy.c2, hasNumber.arrRows[hasNumber.arrRows.length - 1]); functionAction = function () { // Пройдемся по последнему столбцу for (i = 0; i < hasNumber.arrRows.length; ++i) { r = hasNumber.arrRows[i]; cell = t._getVisibleCell(arCopy.c2, r); if (cell.hasMerged()) { continue; } text = (new asc_Range(arCopy.c1, r, arCopy.c2 - 1, r)).getName(); val = t.generateAutoCompleteFormula(functionName, text); cell.setValue(val); } }; } else if (false === hasNumberInLastRow && true === hasNumberInLastColumn) { // Есть значения только в последнем столбце (значит нужно заполнить только последнюю строчку) changedRange = new asc_Range(hasNumber.arrCols[0], arCopy.r2, hasNumber.arrCols[hasNumber.arrCols.length - 1], arCopy.r2); functionAction = function () { // Пройдемся по последней строке for (i = 0; i < hasNumber.arrCols.length; ++i) { c = hasNumber.arrCols[i]; cell = t._getVisibleCell(c, arCopy.r2); if (cell.hasMerged()) { continue; } text = (new asc_Range(c, arCopy.r1, c, arCopy.r2 - 1)).getName(); val = t.generateAutoCompleteFormula(functionName, text); cell.setValue(val); } }; } else { // Есть значения и в последнем столбце, и в последней строке, выделенный диапазон по столбцам больше одной ячейки и только в одной строке есть значения if (1 === hasNumber.arrRows.length && (ar.c2 - ar.c1) > 0) { changedRange = new asc_Range(arCopy.c2, arCopy.r2, arCopy.c2, arCopy.r2); functionAction = function () { // Одна строка или только в последней строке есть значения... cell = t._getVisibleCell(arCopy.c2, arCopy.r2); // ToDo вводить в первое свободное место, а не сразу за диапазоном text = (new asc_Range(arCopy.c1, arCopy.r2, arCopy.c2 - 1, arCopy.r2)).getName(); val = t.generateAutoCompleteFormula(functionName, text); cell.setValue(val); }; } else { changedRange = new asc_Range(hasNumber.arrCols[0], arCopy.r2, hasNumber.arrCols[hasNumber.arrCols.length - 1], arCopy.r2); functionAction = function () { // Иначе вводим в строку вниз for (i = 0; i < hasNumber.arrCols.length; ++i) { c = hasNumber.arrCols[i]; cell = t._getVisibleCell(c, arCopy.r2); // ToDo вводить в первое свободное место, а не сразу за диапазоном text = (new asc_Range(c, arCopy.r1, c, arCopy.r2 - 1)).getName(); val = t.generateAutoCompleteFormula(functionName, text); cell.setValue(val); } }; } } // Можно ли применять автоформулу this._isLockedCells(changedRange, /*subType*/null, onAutoCompleteFormula); result.notEditCell = true; return result; } } else { if (!result.text && !result.notEditCell) { let supposedCell = this.model.getCell3(activeCell.row, activeCell.col); merged = supposedCell && supposedCell.hasMerged(); if (merged) { selection.setActiveCell(merged.r1, merged.c1); } else if (firstCell && (firstCell.cellType === CellValueType.String) && lastCell && (lastCell.cellType === CellValueType.String)) { // change selection to the last cell if the values ​​in the range are not valid in the autocomplete formula selection.setActiveCell(ar.r2, ar.c2); } } } // Ищем первую ячейку с числом for (; r >= vr.r1; --r) { cell = this._getCellTextCache(activeCell.col, r); if (cell) { // Нашли не пустую ячейку, проверим формат cellType = cell.cellType; isNumberFormat = (null === cellType || CellValueType.Number === cellType); let cellRange = this.model.getCell3(r, activeCell.col); let isDateFormat = cellRange.getNumFormat().isDateTimeFormat(); if (isNumberFormat && !isDateFormat) { // Это число, мы нашли то, что искали topCell = { c: activeCell.col, r: r, isFormula: cell.isFormula }; // смотрим вторую ячейку if (topCell.isFormula && r - 1 >= vr.r1) { cell = this._getCellTextCache(activeCell.col, r - 1); if (cell && cell.isFormula) { topCell.isFormulaSeq = true; } } break; } } } // Проверим, первой все равно должна быть колонка if (null === topCell || topCell.r !== activeCell.row - 1 || topCell.isFormula && !topCell.isFormulaSeq) { for (; c >= vr.c1; --c) { cell = this._getCellTextCache(c, activeCell.row); if (cell) { // Нашли не пустую ячейку, проверим формат cellType = cell.cellType; isNumberFormat = (null === cellType || CellValueType.Number === cellType); let cellRange = this.model.getCell3(activeCell.row, c); let isDateFormat = cellRange.getNumFormat().isDateTimeFormat(); if (isNumberFormat && !isDateFormat) { // Это число, мы нашли то, что искали leftCell = { r: activeCell.row, c: c }; break; } } if (null !== topCell) { // Если это не первая ячейка слева от текущей и мы нашли верхнюю, то дальше не стоит искать break; } } } if (leftCell) { // Move to the left until the first non-numeric cell --c; for (; c >= 0; --c) { cell = this._getCellTextCache(c, activeCell.row); if (!cell) { // There may still be uncached data this._addCellTextToCache(c, activeCell.row); cell = this._getCellTextCache(c, activeCell.row); if (!cell) { break; } } cellType = cell.cellType; isNumberFormat = (null === cellType || CellValueType.Number === cellType); if (!isNumberFormat) { break; } } // We have gone a little further ++c; // If we have one line or column in the selection and we found not empty cells to the left or on top, // then we need to add the formula with the result for the entire selection with a shift for each cell // if we select only one cell, we must only get the formula for editing without writing in the cell if (!isSingleCellSelection && !merged && isSingleRowColSelection) { changedRange = new asc_Range(c, ar.r1, activeCell.col - 1, leftCell.r); arCopy = !arCopy ? ar.clone(true) : arCopy; functionAction = function () { let byCol = arHistorySelect.c1 === arHistorySelect.c2 ? true : false; if (byCol) { for (let row = arHistorySelect.r1; row <= arHistorySelect.r2; ++row) { cell = t._getVisibleCell(arHistorySelect.c2, row); text = (new asc_Range(c, row, arHistorySelect.c2 - 1, row)).getName(); val = t.generateAutoCompleteFormula(functionName, text); cell.setValue(val); } } else { for (let col = arHistorySelect.c1, colShift = 0; col <= arHistorySelect.c2; ++col, ++colShift) { cell = t._getVisibleCell(col, arHistorySelect.r2); text = (new asc_Range(c + (colShift), ar.r1, col - 1, ar.r1)).getName(); val = t.generateAutoCompleteFormula(functionName, text); cell.setValue(val); } } }; this._isLockedCells(changedRange, /*subType*/null, onAutoCompleteFormula); result.notEditCell = true; return result; } if (activeCell.col - 1 !== c) { // Range result = new asc_Range(c, leftCell.r, activeCell.col - 1, leftCell.r); } else { // Single cell result = new asc_Range(c, leftCell.r, c, leftCell.r); } this._fixSelectionOfMergedCells(result); result.text = result.getName(); } if (topCell) { // Move up until the first non-numeric cell --r; for (; r >= 0; --r) { cell = this._getCellTextCache(activeCell.col, r); if (!cell) { // There may still be uncached data this._addCellTextToCache(activeCell.col, r); cell = this._getCellTextCache(activeCell.col, r); if (!cell) { break; } } cellType = cell.cellType; isNumberFormat = (null === cellType || CellValueType.Number === cellType); if (!isNumberFormat) { break; } } // We have gone a little further ++r; if (!isSingleCellSelection && !merged && isSingleRowColSelection) { changedRange = new asc_Range(ar.c1, r, topCell.c, activeCell.row - 1); arCopy = !arCopy ? ar.clone(true) : arCopy; functionAction = function () { let byCol = arHistorySelect.c1 === arHistorySelect.c2 ? true : false; if (byCol) { // go down the lines and together with the rowShift, add the formula to the cells inside the select for (let row = arHistorySelect.r1, rowShift = 0; row <= arHistorySelect.r2; ++row, ++rowShift) { cell = t._getVisibleCell(arHistorySelect.c1, row); text = (new asc_Range(arHistorySelect.c2, r + rowShift, arHistorySelect.c2, row - 1)).getName(); val = t.generateAutoCompleteFormula(functionName, text); cell.setValue(val); } } else { // go along the line to the right and add the formula to the cells inside the select without shift for (let col = arHistorySelect.c1; col <= arHistorySelect.c2; ++col) { cell = t._getVisibleCell(col, arHistorySelect.r2); text = (new asc_Range(col, r, col, arHistorySelect.r2 - 1)).getName(); val = t.generateAutoCompleteFormula(functionName, text); cell.setValue(val); } } }; this._isLockedCells(changedRange, /*subType*/null, onAutoCompleteFormula); result.notEditCell = true; return result; } if (activeCell.row - 1 !== r) { // Range result = new asc_Range(topCell.c, r, topCell.c, activeCell.row - 1); } else { // Single cell result = new asc_Range(topCell.c, r, topCell.c, r); } this._fixSelectionOfMergedCells(result); result.text = result.getName(); } return result; }; WorksheetView.prototype.generateAutoCompleteFormula = function (name, text) { var _res = null; var selection = this.model.getSelection(); var activeCell = selection.activeCell; var bLocale = AscCommonExcel.oFormulaLocaleInfo.Parse; var cFormulaList = (bLocale && AscCommonExcel.cFormulaFunctionLocalized) ? AscCommonExcel.cFormulaFunctionLocalized : AscCommonExcel.cFormulaFunction; name = name.toUpperCase(); var isSumFunc; if (cFormulaList && name in cFormulaList) { var tempFunc = cFormulaList[name]; if (tempFunc && tempFunc.prototype && tempFunc.prototype.name === "SUM") { isSumFunc = true; } } if (isSumFunc && ((this.model.AutoFilter && this.model.AutoFilter.isApplyAutoFilter()) || this.model.autoFilters._getTableIntersectionWithActiveCell(activeCell, true, true))) { var _name = "SUBTOTAL"; var _f = bLocale && AscCommonExcel.cFormulaFunctionToLocale ? AscCommonExcel.cFormulaFunctionToLocale[_name] : _name; var _separator = AscCommon.FormulaSeparators.functionArgumentSeparator; var funcType = 9; _res = "=" + _f + "(" + funcType + _separator + text + ")"; } return _res ? _res : ("=" + name + "(" + text + ")"); }; WorksheetView.prototype._prepareComments = function () { // ToDo возможно не нужно это делать именно тут.. if (0 < this.model.aComments.length) { this.model.workbook.handlers.trigger("asc_onAddComments", this.model.aComments); } }; WorksheetView.prototype._prepareDrawingObjects = function () { this.objectRender = new AscFormat.DrawingObjects(); if (!AscCommon.isFileBuild()) { this.objectRender.init(this); } }; WorksheetView.prototype._initCellsArea = function (type) { // calculate rows heights and visible rows this._calcHeaderRowHeight(); this._calcHeightRows(type); this._updateVisibleRowsCount(/*skipScrolReinit*/true); // calculate columns widths and visible columns this._calcWidthColumns(type); this._updateVisibleColsCount(/*skipScrolReinit*/true); }; WorksheetView.prototype._initPane = function () { var pane = this.model.getSheetView().pane; if ( null !== pane && pane.isInit() && !window['IS_NATIVE_EDITOR']) { this.topLeftFrozenCell = pane.topLeftFrozenCell; this.visibleRange.r1 = this.topLeftFrozenCell.getRow0(); this.visibleRange.c1 = this.topLeftFrozenCell.getCol0(); } }; WorksheetView.prototype._getSelection = function () { return this.model.selectionRange; }; WorksheetView.prototype.getSelectionState = function () { return this.model.getSelection().clone(); }; WorksheetView.prototype.getSpeechDescription = function (prevState, curState, action) { let res = null; if (action) { res = this._getSpeechDescriptionAction(prevState, curState, action); } else { res = this._getSpeechDescriptionSelection(prevState, curState); } return res; }; WorksheetView.prototype._getSpeechDescriptionAction = function (prevState, curState, action) { let obj = null, type = null; if (action) { switch (action.type) { case AscCommon.SpeakerActionType.sheetChange: { obj = {}; obj.name = this.model.sName; let endCol = Math.max(this.model.getColsCount() - 1, 0); let endRow = Math.max(this.model.getRowsCount() - 1, 0); obj.cellEnd = new asc_Range(endCol, endRow, endCol, endRow).getName(); obj.cellsCount = this.model.getCountNoEmptyCells(); obj.objectsCount = this.model.Drawings ? this.model.Drawings.length : 0; //read on change selection /*let curRange = curState && curState.ranges && curState.ranges[0]; if (curRange) { let oCell, text; if (curRange.isOneCell()) { oCell = this._getVisibleCell(curRange.c1, curRange.r1); obj.text = oCell && oCell.getValueForEdit(); obj.cell = oCell.getName(); } else { oCell = this._getVisibleCell(curRange.c1, curRange.r1); text = oCell && oCell.getValueForEdit(); let startObj = {text: text === "" ? null : text, cell: oCell.getName()}; oCell = this._getVisibleCell(curRange.c2, curRange.r2); text = oCell && oCell.getValueForEdit(); let endOnj = {text: text === "" ? null : text, cell: oCell.getName()}; obj.start = startObj; obj.end = endOnj; } }*/ type = AscCommon.SpeechWorkerCommands.SheetSelected; break; } case AscCommon.SpeakerActionType.keyDown: { if ((action.event.KeyCode >= 35 && action.event.KeyCode <= 40) || (action.event.KeyCode === 9 || action.event.KeyCode === 13)) { return this._getSpeechDescriptionSelection(prevState, curState); } break; } case AscCommon.SpeakerActionType.undoRedo: { return this._getSpeechDescriptionSelection(prevState, curState, true); } } } return obj ? {type: type, obj: obj} : null; }; WorksheetView.prototype._getSpeechDescriptionSelection = function (prevState, curState, notTrySearchDifference) { let type = null, text = null, obj = null; let oCell, oCellRange, curRange; if (prevState && curState && prevState.ranges && curState.ranges && prevState.isEqual(curState)) { return null; } if (!notTrySearchDifference && prevState && curState && prevState.ranges && curState.ranges && prevState.ranges.length === 1 && prevState.ranges.length === curState.ranges.length) { //1 row/1 col and change 1 cell let prevRange = prevState.ranges[0]; curRange = curState.ranges[0]; if (curRange.isOneCell()) { type = AscCommon.SpeechWorkerCommands.CellSelected; oCellRange = this._getVisibleCell(curRange.c1, curRange.r1); text = oCellRange && oCellRange.getValueForEdit(); obj = {text: text === "" ? null : text, cell: curRange.getName()}; } else { let oStart, oEnd; let diff1 = prevRange.difference(curRange); let diff2 = curRange.difference(prevRange); if (diff1.length === 0 && diff2.length === 1) { if (diff2[0].isOneCell()) { oStart = diff2[0]; type = AscCommon.SpeechWorkerCommands.CellRangeUnselectedChangeOne; } else { //todo ms - only current selection oStart = new Asc.Range(diff2[0].c1, diff2[0].r1, diff2[0].c1, diff2[0].r1); oEnd = new Asc.Range(diff2[0].c2, diff2[0].r2, diff2[0].c2, diff2[0].r2); type = AscCommon.SpeechWorkerCommands.CellRangeUnselected; } } else if (diff2.length === 0 && diff1.length === 1) { if (diff1[0].isOneCell()) { oStart = diff1[0]; type = AscCommon.SpeechWorkerCommands.CellRangeSelectedChangeOne; } else { //todo ms - only current selection oStart = new Asc.Range(diff1[0].c1, diff1[0].r1, diff1[0].c1, diff1[0].r1); oEnd = new Asc.Range(diff1[0].c2, diff1[0].r2, diff1[0].c2, diff1[0].r2); type = AscCommon.SpeechWorkerCommands.CellRangeSelected; } } if (oStart) { let startObj, endOnj, oCell; oCell = this._getVisibleCell(oStart.c1, oStart.r1); text = oCell && oCell.getValueForEdit(); startObj = {text: text === "" ? null : text, cell: oStart.getName()}; if (oEnd) { oCell = this._getVisibleCell(oEnd.c1, oEnd.r1); text = oCell && oCell.getValueForEdit(); endOnj = {text: text === "" ? null : text, cell: oEnd.getName()}; obj = {start: startObj, end: endOnj}; } if (!obj) { obj = startObj; } } } } else { if (curState && curState.ranges && curState.ranges.length > 1) { //multiple selection obj = {}; obj.ranges = []; oCell = this._getVisibleCell(curState.activeCell.col, curState.activeCell.row); text = oCell && oCell.getValueForEdit(); obj.text = text === "" ? null : text; for (let i = 0; i < curState.ranges.length; i++) { let _range = curState.ranges[i]; let elem = {startCell: new Asc.Range(_range.c1, _range.r1, _range.c1, _range.r1).getName(), endCell: new Asc.Range(_range.c2, _range.r2, _range.c2, _range.r2).getName()}; obj.ranges.push(elem); } type = AscCommon.SpeechWorkerCommands.MultipleRangesSelected; } else { curRange = curState && curState.ranges && curState.ranges[0]; } } if (!obj && curRange) { oCell = this._getVisibleCell(curRange.c1, curRange.r1); text = oCell && oCell.getValueForEdit(); let startObj = {text: text === "" ? null : text, cell: oCell.getName()}; oCell = this._getVisibleCell(curRange.c2, curRange.r2); text = oCell && oCell.getValueForEdit(); let endOnj = {text: text === "" ? null : text, cell: oCell.getName()}; obj = {start: startObj, end: endOnj}; type = AscCommon.SpeechWorkerCommands.CellRangeSelected; } return obj ? {type: type, obj: obj} : null; }; WorksheetView.prototype._fixVisibleRange = function ( range ) { var tmp; if ( null !== this.topLeftFrozenCell ) { tmp = this.topLeftFrozenCell.getRow0(); if ( range.r1 < tmp ) { range.r1 = tmp; tmp = this._findVisibleRow( range.r1, +1 ); if ( 0 < tmp ) { range.r1 = tmp; } } tmp = this.topLeftFrozenCell.getCol0(); if ( range.c1 < tmp ) { range.c1 = tmp; tmp = this._findVisibleCol( range.c1, +1 ); if ( 0 < tmp ) { range.c1 = tmp; } } } }; WorksheetView.prototype._calcColWidth = function (i) { if (i !== this.cols.length) { // Only this.model.getColsCount() can >= i this._calcWidthColumns(AscCommonExcel.recalcType.newLines); } var w; // Получаем свойства колонки var isDefaultWidth; var column = this.model._getColNoEmptyWithAll(i); if (!column) { isDefaultWidth = true; w = this.defaultColWidthPx; // Используем дефолтное значение } else if (column.getHidden()) { w = 0; // Если столбец скрытый, ширину выставляем 0 } else { if (null === column.widthPx) { isDefaultWidth = true; } w = null === column.widthPx ? this.defaultColWidthPx : column.widthPx; } this.cols[i] = new CacheColumn(w); this.cols[i].width = this.workbook.printPreviewState.isStart() ? w * this.getZoom(true) * this.getRetinaPixelRatio() : Asc.round(w * this.getZoom(true) * this.getRetinaPixelRatio()); if (!w) { this.cols[i]._widthForPrint = 0; } else { this.cols[i]._widthForPrint = isDefaultWidth ? this.defaultColWidthPxForPrint : column && Asc.floor( ((256 * column.width + Asc.floor(128 / this.maxDigitWidthForPrint)) / 256) * this.maxDigitWidthForPrint); } this.updateColumnsStart = Math.min(i, this.updateColumnsStart); }; WorksheetView.prototype._getColumnWidthIgnoreHidden = function (i) { var w; var column = this.model._getColNoEmptyWithAll(i); if (!column) { w = this.defaultColWidthPx; // Используем дефолтное значение } else { w = null === column.widthPx ? this.defaultColWidthPx : column.widthPx; } w = this.workbook.printPreviewState.isStart() ? w * this.getZoom(true) * this.getRetinaPixelRatio() : Asc.round(w * this.getZoom(true) * this.getRetinaPixelRatio()) return w; }; WorksheetView.prototype._calcHeightRow = function (y, i) { var r, hR; this.model._getRowNoEmptyWithAll(i, function (row) { if (!row) { hR = -1; // Будет использоваться дефолтная высота строки } else if (row.getHidden()) { hR = 0; // Скрытая строка, высоту выставляем 0 } else { // Берем высоту из модели, если она custom(баг 15618), либо дефолтную if (row.h > 0 && (row.getCustomHeight() || row.getCalcHeight())) { hR = row.h; } else { hR = -1; } } }); var isDefaultHeight; if (hR < 0) { hR = AscCommonExcel.oDefaultMetrics.RowHeight; isDefaultHeight = true; } r = this.rows[i] = new CacheRow(); r.top = y; r.height = this.workbook.printPreviewState.isStart() ? AscCommonExcel.convertPtToPx(hR) * this.getZoom() : Asc.round(AscCommonExcel.convertPtToPx(hR) * this.getZoom()); if (!hR) { r._heightForPrint = 0; } else { r._heightForPrint = isDefaultHeight ? null : hR; } r.descender = this.defaultRowDescender; }; /** Вычисляет ширину колонки заголовков */ WorksheetView.prototype._calcHeaderColumnWidth = function () { var old = this.cellsLeft; if (false === this.model.getSheetView().asc_getShowRowColHeaders()) { this.headersWidth = 0; } else { // Ширина колонки заголовков считается - max число знаков в строке - перевести в символы - перевести в пикселы var numDigit = Math.max(AscCommonExcel.calcDecades(this.visibleRange.r2 + 1), 3); var nCharCount = this.model.charCountToModelColWidth(numDigit); this.headersWidth = Asc.round(this.model.modelColWidthToColWidth(nCharCount) * this.getZoom() * this.getRetinaPixelRatio()); } //todo приравниваю headersLeft и groupWidth. Необходимо пересмотреть! this.headersLeft = this.ignoreGroupSize ? 0 : this.groupWidth; this.cellsLeft = this.headersLeft + this.headersWidth; return old !== this.cellsLeft; }; /** Вычисляет высоту строки заголовков */ WorksheetView.prototype._calcHeaderRowHeight = function () { this.headersHeight = (false === this.model.getSheetView().asc_getShowRowColHeaders()) ? 0 : Asc.round(this.headersHeightByFont * this.getZoom()); //todo приравниваю headersTop и groupHeight. Необходимо пересмотреть! this.headersTop = this.ignoreGroupSize ? 0 : this.groupHeight; this.cellsTop = this.headersTop + this.headersHeight; }; /** * Вычисляет ширину и позицию колонок * @param {AscCommonExcel.recalcType} type */ WorksheetView.prototype._calcWidthColumns = function (type) { var l = this.model.getColsCount(); var i = 0; if (AscCommonExcel.recalcType.full === type) { this.cols = []; } else if (AscCommonExcel.recalcType.newLines === type) { i = this.cols.length; } for (; i < l; ++i) { this._calcColWidth(i); } this.setColsCount(Math.min(Math.max(this.nColsCount, i), gc_nMaxCol)); }; /** * Вычисляет высоту и позицию строк * @param {AscCommonExcel.recalcType} type */ WorksheetView.prototype._calcHeightRows = function (type) { var y = this.cellsTop; var l = this.model.getRowsCount(); var i = 0; if (AscCommonExcel.recalcType.full === type) { this.rows = []; } else if (AscCommonExcel.recalcType.newLines === type) { i = this.rows.length; y = this._getRowTop(i); } for (; i < l; ++i) { this._calcHeightRow(y, i); y += this._getRowHeight(i); } this.nRowsCount = Math.min(Math.max(this.nRowsCount, i), gc_nMaxRow); }; /** Вычисляет диапазон индексов видимых колонок */ WorksheetView.prototype._calcVisibleColumns = function () { var w = this.drawingCtx.getWidth(); var sumW = this.topLeftFrozenCell ? this._getColLeft(this.topLeftFrozenCell.getCol0()) : this.cellsLeft; sumW -= this.getHorizontalScrollCorrect(); for (var i = this.visibleRange.c1, f = false; i < this.nColsCount && sumW < w; ++i) { sumW += this._getColumnWidth(i); f = true; } this.visibleRange.c2 = i - (f ? 1 : 0); }; /** Вычисляет диапазон индексов видимых строк */ WorksheetView.prototype._calcVisibleRows = function () { var h = this.drawingCtx.getHeight(); var sumH = this.topLeftFrozenCell ? this._getRowTop(this.topLeftFrozenCell.getRow0()) : this.cellsTop; sumH -= this.getScrollCorrect(); for (var i = this.visibleRange.r1, f = false; i < this.nRowsCount && sumH < h; ++i) { sumH += this._getRowHeight(i); f = true; } this.visibleRange.r2 = i - (f ? 1 : 0); if (this._calcHeaderColumnWidth()) { this._updateVisibleColsCount(true); } }; /** Обновляет позицию колонок */ WorksheetView.prototype._updateColumnPositions = function () { if (Number.MAX_VALUE === this.updateColumnsStart) { return; } var i = this.updateColumnsStart; var l = this.cols.length; if (i < l) { var x = (0 === i) ? 0 : this.cols[--i].left; for (; i < l; ++i) { this.cols[i].left = x; x += this.cols[i].width; } } var updateColumnsStart = this.updateColumnsStart; this.updateColumnsStart = Number.MAX_VALUE; this._updateVisibleColsCount(true); // ToDo check need calculate this._updateDrawingArea(); // ToDo может отказаться от своих area в DO? if (this.objectRender) { this.objectRender.updateDrawingsTransform({target: c_oTargetType.ColumnResize, col: updateColumnsStart}); } }; /** Обновляет позицию строк */ WorksheetView.prototype._updateRowPositions = function () { // ToDo add updateStart. See _updateColumnPositions var y = this.cellsTop; for (var l = this.rows.length, i = 0; i < l; ++i) { this.rows[i].top = y; y += this.rows[i].height; } }; /** Устанаваливает видимый диапазон ячеек максимально возможным */ WorksheetView.prototype._normalizeViewRange = function () { var t = this; var vr = t.visibleRange; var w = t.drawingCtx.getWidth() - t.cellsLeft; var h = t.drawingCtx.getHeight() - t.cellsTop; var vw = this._getColLeft(vr.c2 + 1) - this._getColLeft(vr.c1); var vh = this._getRowTop(vr.r2 + 1) - this._getRowTop(vr.r1); var i; var offsetFrozen = t.getFrozenPaneOffset(); vw += offsetFrozen.offsetX; vh += offsetFrozen.offsetY; if ( vw < w ) { for ( i = vr.c1 - 1; i >= 0; --i ) { vw += this._getColumnWidth(i); if ( vw > w ) { break; } } vr.c1 = i + 1; if ( vr.c1 >= vr.c2 ) { vr.c1 = vr.c2 - 1; } if ( vr.c1 < 0 ) { vr.c1 = 0; } } if ( vh < h ) { for ( i = vr.r1 - 1; i >= 0; --i ) { vh += this._getRowHeight(i); if ( vh > h ) { break; } } vr.r1 = i + 1; if ( vr.r1 >= vr.r2 ) { vr.r1 = vr.r2 - 1; } if ( vr.r1 < 0 ) { vr.r1 = 0; } } }; // ----- Drawing for print ----- WorksheetView.prototype._calcPagesPrint = function(range, pageOptions, indexWorksheet, arrPages, printScale, adjustPrint, bPrintArea, opt_prepareTextMetrics) { if (0 > range.r2 || 0 > range.c2) { // Ничего нет return; } if (window["NATIVE_EDITOR_ENJINE"]) { if (!this.rows.length) { this._calcHeightRows(AscCommonExcel.recalcType.newLines); } if (!this.cols.length) { this._calcWidthColumns(AscCommonExcel.recalcType.newLines); } } var vector_koef = AscCommonExcel.vector_koef / this.getZoom(); if (AscCommon.AscBrowser.isCustomScaling()) { //vector_koef /= AscCommon.AscBrowser.retinaPixelRatio; } let isOnlyFirstPage = adjustPrint && adjustPrint.isOnlyFirstPage; if (!isOnlyFirstPage) { let printOptionsJson = this.workbook && this.workbook.getPrintOptionsJson(); let curPrintOptionsJson = (printOptionsJson && printOptionsJson["spreadsheetLayout"]) ? printOptionsJson["spreadsheetLayout"] : printOptionsJson; let thumbnailFirst = curPrintOptionsJson && curPrintOptionsJson["thumbnail"] && curPrintOptionsJson["thumbnail"]["first"]; if (thumbnailFirst === true || (typeof thumbnailFirst === "string" && thumbnailFirst.toLowerCase() === "true")) { isOnlyFirstPage = true; } } let pageMargins, pageSetup, pageGridLines, pageHeadings; if (pageOptions) { pageMargins = pageOptions.asc_getPageMargins(); pageSetup = pageOptions.asc_getPageSetup(); pageGridLines = pageOptions.asc_getGridLines(); pageHeadings = pageOptions.asc_getHeadings(); } let bFitToWidth = false; let bFitToHeight = false; let pageWidth, pageHeight, pageOrientation, scale; if (pageSetup instanceof asc_CPageSetup) { pageWidth = pageSetup.asc_getWidth(); pageHeight = pageSetup.asc_getHeight(); pageOrientation = pageSetup.asc_getOrientation(); bFitToWidth = pageSetup.asc_getFitToWidth(); bFitToHeight = pageSetup.asc_getFitToHeight(); } if(printScale) { scale = printScale / 100; } else { //scale пока всегда берём из модели let pageSetupModel = this.model.PagePrintOptions ? this.model.PagePrintOptions.pageSetup : null; scale = pageSetupModel ? pageSetupModel.asc_getScale() / 100 : 1; } let pageLeftField, pageRightField, pageTopField, pageBottomField; if (pageMargins) { pageLeftField = Math.max(pageMargins.asc_getLeft(), c_oAscPrintDefaultSettings.MinPageLeftField); pageRightField = Math.max(pageMargins.asc_getRight(), c_oAscPrintDefaultSettings.MinPageRightField); pageTopField = Math.max(pageMargins.asc_getTop(), c_oAscPrintDefaultSettings.MinPageTopField); pageBottomField = Math.max(pageMargins.asc_getBottom(), c_oAscPrintDefaultSettings.MinPageBottomField); } let t = this; let _getColumnWidth = function (index) { let defaultWidth = t._getWidthForPrint(index); if (defaultWidth) { return defaultWidth; } return t._getColumnWidth(index); }; let _getRowHeight = function (index) { let defaultHeight = t._getHeightForPrint(index); if (defaultHeight) { return defaultHeight; } return t._getRowHeight(index); }; if (null == pageGridLines) { pageGridLines = c_oAscPrintDefaultSettings.PageGridLines; } if (null == pageHeadings) { pageHeadings = c_oAscPrintDefaultSettings.PageHeadings; } if (null == pageWidth) { pageWidth = c_oAscPrintDefaultSettings.PageWidth; } if (null == pageHeight) { pageHeight = c_oAscPrintDefaultSettings.PageHeight; } if (null == pageOrientation) { pageOrientation = c_oAscPrintDefaultSettings.PageOrientation; } if (null == pageLeftField) { pageLeftField = c_oAscPrintDefaultSettings.PageLeftField; } if (null == pageRightField) { pageRightField = c_oAscPrintDefaultSettings.PageRightField; } if (null == pageTopField) { pageTopField = c_oAscPrintDefaultSettings.PageTopField; } if (null == pageBottomField) { pageBottomField = c_oAscPrintDefaultSettings.PageBottomField; } if (Asc.c_oAscPageOrientation.PageLandscape === pageOrientation) { let tmp = pageWidth; pageWidth = pageHeight; pageHeight = tmp; } let pageWidthWithFields = pageWidth - pageLeftField - pageRightField; let pageHeightWithFields = pageHeight - pageTopField - pageBottomField; let leftFieldInPx = pageLeftField / vector_koef + 1; let topFieldInPx = pageTopField / vector_koef + 1; let startPrintPreview = this.workbook.printPreviewState && this.workbook.printPreviewState.isStart(); let pageWidthWithoutFieldsHeadings = ((pageWidth - pageRightField - pageLeftField) / vector_koef); let pageHeightWithoutFieldsHeadings = ((pageHeight - pageBottomField - pageTopField) / vector_koef); let _retinaPixelRatio = this.getRetinaPixelRatio(); if (pageHeadings) { // Рисуем заголовки, нужно чуть сдвинуться leftFieldInPx += startPrintPreview ? (this.cellsLeft * scale) / _retinaPixelRatio : this.cellsLeft / _retinaPixelRatio; topFieldInPx += startPrintPreview ? (this.cellsTop * scale) / _retinaPixelRatio : this.cellsTop / _retinaPixelRatio; } //TODO при сравнении резальтатов рассчета страниц в зависимости от scale - LO выдаёт похожие результаты, MS - другие. Необходимо пересмотреть! let pageWidthWithFieldsHeadings = ((pageWidth - pageRightField) / vector_koef - leftFieldInPx); let pageHeightWithFieldsHeadings = ((pageHeight - pageBottomField) / vector_koef - topFieldInPx); //PRINT TITLES let tCol1, tCol2, tRow1, tRow2; //первостепенно ориентируемся что в этих настройках let printTitlesHeight = pageOptions.printTitlesHeight; let printTitlesWidth = pageOptions.printTitlesWidth; let _titleRange; if (null !== printTitlesHeight) { AscCommonExcel.executeInR1C1Mode(AscCommonExcel.g_R1C1Mode, function () { _titleRange = AscCommonExcel.g_oRangeCache.getAscRange(printTitlesHeight); }); if (_titleRange) { tRow1 = _titleRange.r1; tRow2 = _titleRange.r2; } else { tRow1 = undefined; tRow2 = undefined; } } if (null !== printTitlesWidth) { AscCommonExcel.executeInR1C1Mode(AscCommonExcel.g_R1C1Mode, function () { _titleRange = AscCommonExcel.g_oRangeCache.getAscRange(printTitlesWidth); }); if (_titleRange) { tCol1 = _titleRange.c1; tCol2 = _titleRange.c2; } else { tCol1 = undefined; tCol2 = undefined; } } //let titleWidth = 0, titleHeight = 0; if (!printTitlesHeight || !printTitlesWidth) { let printTitles = this.model.workbook.getDefinesNames("Print_Titles", this.model.getId()); if(printTitles) { let printTitleRefs; AscCommonExcel.executeInR1C1Mode(false, function () { printTitleRefs = AscCommonExcel.getRangeByRef(printTitles.ref, t.model, true, true) }); if(printTitleRefs && printTitleRefs.length) { for(let i = 0; i < printTitleRefs.length; i++) { let bbox = printTitleRefs[i].bbox; if(bbox) { if(c_oAscSelectionType.RangeCol === bbox.getType() && null == printTitlesWidth) { tCol1 = bbox.c1; tCol2 = bbox.c2; } else if(c_oAscSelectionType.RangeRow === bbox.getType() && null == printTitlesHeight) { tRow1 = bbox.r1; tRow2 = bbox.r2; } } } } } } let recalculatePageMargins = function (_page) { let horizontalCentered = pageOptions && pageOptions.asc_getHorizontalCentered(); let verticalCentered = pageOptions && pageOptions.asc_getVerticalCentered(); if (horizontalCentered) { let _offset = (pageWidthWithoutFieldsHeadings - realPageWidth) / 2; _page.pageClipRectLeft += _offset; _page.leftFieldInPx += _offset; } if (verticalCentered) { let _offset = (pageHeightWithoutFieldsHeadings - realPageHeight) / 2; _page.pageClipRectTop += _offset; _page.topFieldInPx += _offset; } }; let realPageWidth, realPageHeight; let currentColIndex = range.c1; let currentWidth = 0; let currentRowIndex = range.r1; let currentHeight = 0; let isCalcColumnsWidth = true; let currentHeightReal = 0; let currentWidthReal = 0; let bIsAddOffset = false; let nCountOffset = 0; let nCountPages = 0; let curTitleWidth = 0, curTitleHeight = 0; let addedTitleHeight = 0, addedTitleWidth = 0; let startTitleArrRow = []; let j; let baseTitleHeight = 0; if (tRow1 < currentRowIndex) { for (j = tRow1; j < Math.min(currentRowIndex, tRow2 + 1); j++) { baseTitleHeight += _getRowHeight(j) * scale; } } let baseTitleWidth = 0; if (tCol1 < currentColIndex) { for (j = tCol1; j < Math.min(currentColIndex, tCol2 + 1); j++) { baseTitleWidth += _getColumnWidth(j) * scale; } } let prepareTextMetricsRowMax = 0; let _range, step = 1000; if (opt_prepareTextMetrics) { _range = new Asc.Range(range.c1, range.r1, range.c2, range.r1 + step); this._prepareCellTextMetricsCache(_range); prepareTextMetricsRowMax = range.r1 + step; } while (AscCommonExcel.c_kMaxPrintPages > arrPages.length) { if(isOnlyFirstPage && nCountPages > 0) { break; } let newPagePrint = new asc_CPagePrint(); let colIndex = currentColIndex, rowIndex = currentRowIndex, pageRange; let rowBreak = false, colBreak = false; newPagePrint.indexWorksheet = indexWorksheet; newPagePrint.pageWidth = pageWidth; newPagePrint.pageHeight = pageHeight; newPagePrint.pageClipRectLeft = pageLeftField / vector_koef; newPagePrint.pageClipRectTop = pageTopField / vector_koef; newPagePrint.pageClipRectWidth = pageWidthWithFields / vector_koef; newPagePrint.pageClipRectHeight = pageHeightWithFields / vector_koef; newPagePrint.leftFieldInPx = leftFieldInPx; newPagePrint.topFieldInPx = topFieldInPx; //каждая новая страница должна начинаться с заголовков печати if(range.r1 === rowIndex) { curTitleHeight = 0; addedTitleHeight = 0; } else if(undefined !== startTitleArrRow[rowIndex - 1]) { //TODO в дальнейшем для функционала печати страниц по вертикали необходимо сделать аналогично для столбцов curTitleHeight = startTitleArrRow[rowIndex - 1]; addedTitleHeight = startTitleArrRow[rowIndex - 1]; } if (baseTitleHeight) { curTitleHeight += baseTitleHeight; //addedTitleHeight += baseTitleHeight; } newPagePrint.titleHeight = curTitleHeight; let rightBorderWidth = null; for (rowIndex = currentRowIndex; rowIndex <= range.r2; ++rowIndex) { if (opt_prepareTextMetrics && rowIndex === prepareTextMetricsRowMax + 1) { _range = new Asc.Range(range.c1, prepareTextMetricsRowMax + 1, range.c2, prepareTextMetricsRowMax + 1 + step); prepareTextMetricsRowMax += step + 1; this._prepareCellTextMetricsCache(_range); } let currentRowHeight = _getRowHeight(rowIndex) * scale; let currentRowHeightReal = (t._getRowHeight(rowIndex)/this.getRetinaPixelRatio()) *scale; rowBreak = !bFitToHeight && rowIndex !== currentRowIndex && t.model.rowBreaks && t.model.rowBreaks.isBreak(rowIndex, bPrintArea && range.c1, bPrintArea && range.c2); if ((currentHeight + currentRowHeight + curTitleHeight > pageHeightWithFieldsHeadings && rowIndex !== currentRowIndex) || rowBreak) { // Закончили рисовать страницу curTitleHeight = addedTitleHeight; break; } if (isCalcColumnsWidth) { if(range.c1 === colIndex) { curTitleWidth = 0; addedTitleWidth = 0; } if (baseTitleWidth) { curTitleWidth += baseTitleWidth; //addedTitleWidth += baseTitleWidth; } newPagePrint.titleWidth = curTitleWidth; for (colIndex = currentColIndex; colIndex <= range.c2; ++colIndex) { let currentColWidth = _getColumnWidth(colIndex) * scale; let currentRowWidthReal = (t._getColumnWidth(colIndex)/this.getRetinaPixelRatio()) *scale; if (bIsAddOffset) { newPagePrint.startOffset = ++nCountOffset; newPagePrint.startOffsetPx = (pageWidthWithFieldsHeadings * newPagePrint.startOffset); currentColWidth -= newPagePrint.startOffsetPx; } colBreak = !bFitToWidth && colIndex !== currentColIndex && t.model.colBreaks && t.model.colBreaks.isBreak(colIndex, bPrintArea && range.r1, bPrintArea && range.r2); if ((currentWidth + currentColWidth + curTitleWidth > pageWidthWithFieldsHeadings && colIndex !== currentColIndex) || colBreak) { curTitleWidth = addedTitleWidth; break; } currentWidth += currentColWidth; currentWidthReal += currentRowWidthReal; if(tCol1 !== undefined && colIndex >= tCol1 && colIndex <= tCol2) { addedTitleWidth += currentColWidth; } if (currentWidth > pageWidthWithFieldsHeadings && colIndex === currentColIndex) { // Смещаем в селедующий раз ячейку bIsAddOffset = true; ++colIndex; break; } else { bIsAddOffset = false; } } isCalcColumnsWidth = false; if (pageHeadings) { currentWidth += this.cellsLeft; currentWidthReal += this.cellsLeft; } if (startPrintPreview && (bFitToWidth || bFitToHeight)) { newPagePrint.pageClipRectWidth = Math.max(currentWidth, newPagePrint.pageClipRectWidth, currentWidthReal); //newPagePrint.pageWidth = newPagePrint.pageClipRectWidth * vector_koef + (pageLeftField + pageRightField); } else { newPagePrint.pageClipRectWidth = Math.min(currentWidth, newPagePrint.pageClipRectWidth); } realPageWidth = currentWidth; } let endCell = t.model.getCell3(rowIndex, colIndex - 1); let fullBordersEndCell = endCell.getBorderFull(); if (fullBordersEndCell && fullBordersEndCell.r) { rightBorderWidth = Math.max(fullBordersEndCell.r.w, rightBorderWidth); } currentHeight += currentRowHeight; currentHeightReal += currentRowHeightReal; if(tRow1 !== undefined && rowIndex >= tRow1 && rowIndex <= tRow2) { addedTitleHeight += currentRowHeight; } currentWidth = 0; currentWidthReal = 0; } if (pageHeadings) { currentHeight += this.cellsTop; currentHeightReal += this.cellsTop; } if (rightBorderWidth) { rightBorderWidth = Math.floor(rightBorderWidth / 2); newPagePrint.pageClipRectWidth += rightBorderWidth; } if (startPrintPreview && (bFitToHeight || bFitToWidth)) { newPagePrint.pageClipRectHeight = Math.max(currentHeight, newPagePrint.pageClipRectHeight, currentHeightReal); //newPagePrint.pageHeight = newPagePrint.pageClipRectHeight * vector_koef + (pageTopField + pageBottomField); } else { newPagePrint.pageClipRectHeight = Math.min(currentHeight, newPagePrint.pageClipRectHeight); } realPageHeight = currentHeight; // Нужно будет пересчитывать колонки isCalcColumnsWidth = true; // Рисуем сетку if (pageGridLines) { newPagePrint.pageGridLines = true; } if (pageHeadings) { // Нужно отрисовать заголовки newPagePrint.pageHeadings = true; } startTitleArrRow[rowIndex - 1] = curTitleHeight; pageRange = new asc_Range(currentColIndex, currentRowIndex, colIndex - 1, rowIndex - 1); newPagePrint.pageRange = pageRange; if(tRow1 !== undefined && currentRowIndex > tRow1) { newPagePrint.titleRowRange = new asc_Range(pageRange.c1, tRow1, colIndex - 1, Math.min(tRow2, currentRowIndex - 1)); //newPagePrint.titleHeight = addedTitleHeight; } if(tCol1 !== undefined && currentColIndex > tCol1) { newPagePrint.titleColRange = new asc_Range(tCol1, pageRange.r1, Math.min(tCol2, currentColIndex - 1), rowIndex - 1); //newPagePrint.titleWidth = addedTitleWidth; } //чтобы передать временный scale(допустим при печати выделенного) добавляем его в pagePrint if(printScale) { newPagePrint.scale = printScale / 100; } else if(scale) { newPagePrint.scale = scale; } recalculatePageMargins(newPagePrint); arrPages.push(newPagePrint); nCountPages++; if (bIsAddOffset) { // Мы еще не дорисовали колонку colIndex -= 1; } else { nCountOffset = 0; } if (colIndex <= range.c2) { // Мы еще не все колонки отрисовали currentColIndex = colIndex; currentHeight = 0; currentHeightReal = 0; } else { // Мы дорисовали все колонки, нужна новая строка и стартовая колонка currentColIndex = range.c1; currentRowIndex = rowIndex; currentHeight = 0; currentHeightReal = 0; } if (rowIndex > range.r2) { // Мы вышли, т.к. дошли до конца отрисовки по строкам if (colIndex <= range.c2) { currentColIndex = colIndex; currentHeight = 0; currentHeightReal = 0; } else { // Мы дошли до конца отрисовки currentColIndex = colIndex; currentRowIndex = rowIndex; break; } } } }; WorksheetView.prototype._checkPrintRange = function (range, doNotRecalc/*, _checkLargeRange*/) { let t = this; let isLargeRange = false; var maxCol = -1; var maxRow = -1; var rowCache, rightSide, curRow = -1, hiddenRow = false; //TODO while commented large range. need research all limits. let checkMaxRowCol = function (_range, stopOnMax) { /*let maxDefinedCells = 99998; let counterCells = 0;*/ t.model.getRange3(_range.r1, _range.c1, _range.r2, _range.c2)._foreachNoEmpty(function(cell) { var c = cell.nCol; var r = cell.nRow; if (curRow !== r) { curRow = r; hiddenRow = 0 === t._getRowHeight(r); rowCache = t._getRowCache(r); } if(!hiddenRow && 0 < t._getColumnWidth(c)){ var style = cell.getStyle(); if (style && ((style.fill && style.fill.notEmpty()) || (style.border && style.border.notEmpty()))) { maxCol = Math.max(maxCol, c); maxRow = Math.max(maxRow, r); } var ct = t._getCellTextCache(c, r); if (ct !== undefined) { rightSide = 0; if (!ct.flags.isMerged() && !ct.flags.wrapText) { rightSide = ct.sideR; } maxCol = Math.max(maxCol, c + rightSide); maxRow = Math.max(maxRow, r); } } /*counterCells++; if (stopOnMax && counterCells === maxDefinedCells) { isLargeRange = true; return true; }*/ }); }; /*if (_checkLargeRange) { checkMaxRowCol(range, true); if (isLargeRange) { return null; } }*/ if(!doNotRecalc) { this._prepareCellTextMetricsCache(range); } checkMaxRowCol(range); return new AscCommon.CellBase(maxRow, maxCol); }; WorksheetView.prototype._calculateMaxPrintRange = function(range) { let self = this; let maxCol = -1; let maxRow = -1; let curRow = -1; let rowCache; let checkRightSideCell = function (_ct, _col, _row) { let rightSide = 0; if (_ct && _ct.flags && !_ct.flags.isMerged() && !_ct.flags.wrapText) { rightSide = _ct.sideR; } maxCol = Math.max(maxCol, _col + rightSide); maxRow = Math.max(maxRow, _row); }; // Helper function to check if cell content requires printing let lastNoEmptyCell = null; function checkCellForPrinting(c) { let col = c.nCol; let row = c.nRow; if (lastNoEmptyCell && lastNoEmptyCell.row !== row) { //we must check last cell(string type) in row. inside string can be more then column width. expand if text do not fits in cell if (lastNoEmptyCell) { let ct = self._addCellTextToCache(lastNoEmptyCell.col, lastNoEmptyCell.row, true); checkRightSideCell(ct, lastNoEmptyCell.col, lastNoEmptyCell.row); lastNoEmptyCell = null; } } // Skip hidden rows and columns let hiddenRow = false; if (curRow !== row) { curRow = row; hiddenRow = 0 === self._getRowHeight(row); rowCache = self._getRowCache(row); } if (hiddenRow || 0 === self._getColumnWidth(col)) { return; } if (!c.isEmptyTextString()) { maxCol = Math.max(maxCol, col); maxRow = Math.max(maxRow, row); let ct = self._getCellTextCache(col, row); if (ct !== undefined) { checkRightSideCell(ct, col, row); lastNoEmptyCell = null; } else { let align = c.getAlign(); let angle = align.getAngle(); let cellType = c.getType(); let isNumberFormat = (null === cellType || CellValueType.String !== cellType); let verticalText = angle === AscCommonExcel.g_nVerticalTextAngle; let isWrapped = align.getWrap() || align.hor === AscCommon.align_Distributed; if (isNumberFormat || verticalText || isWrapped) { lastNoEmptyCell = null; } else { if (!lastNoEmptyCell) { lastNoEmptyCell = {}; } lastNoEmptyCell.col = col; lastNoEmptyCell.row = row; } } return; } // Check cell style (fills and borders) let style = c.getStyle(); if (style && ((style.fill && style.fill.notEmpty()) || (style.border && style.border.notEmpty()))) { maxCol = Math.max(maxCol, col); maxRow = Math.max(maxRow, row); } // Check formulas if (c.isFormula()) { maxCol = Math.max(maxCol, col); maxRow = Math.max(maxRow, row); } } // Prepare cell metrics cache //this._prepareCellTextMetricsCache(range); // Iterate through all non-empty cells this.model.getRange3(range.r1, range.c1, range.r2, range.c2)._foreachNoEmpty(function(cell) { checkCellForPrinting(cell); }); let mergedRanges = this.model.mergeManager.getAll(); if (mergedRanges) { for (let i = 0; i < mergedRanges.length; i++) { if (mergedRanges[i].bbox) { let type = mergedRanges[i].bbox.getType(); if (c_oAscSelectionType.RangeCells === type) { maxCol = Math.max(maxCol, mergedRanges[i].bbox.c2); maxRow = Math.max(maxRow, mergedRanges[i].bbox.r2); } /*else if (c_oAscSelectionType.RangeCol === type) { maxCol = Math.max(maxCol, mergedRanges[i].bbox.c2); } else if (c_oAscSelectionType.RangeRow === type) { maxRow = Math.max(maxRow, mergedRanges[i].bbox.r2); }*/ } } } return new AscCommon.CellBase(maxRow, maxCol); }; WorksheetView.prototype.calcPagesPrint = function (pageOptions, printOnlySelection, indexWorksheet, arrPages, arrRanges, adjustPrint, doNotRecalc) { var range, maxCell, t = this; //в опциях может прийти другая область печати. сделано на случай, когда при совместке меняется область в модели var _printArea; if (pageOptions && pageOptions.pageSetup && (pageOptions.pageSetup.printArea || pageOptions.pageSetup.printArea === false) ) { _printArea = pageOptions.pageSetup.printArea; } else { _printArea = this.model.workbook.getDefinesNames("Print_Area", this.model.getId()); } var ignorePrintArea = adjustPrint ? adjustPrint.asc_getIgnorePrintArea() : null; var printArea = !ignorePrintArea && _printArea; this.recalcPrintScale(); var oldPagePrintOptions; if(this.model.PagePrintOptions) { oldPagePrintOptions = this.model.PagePrintOptions; this.model.PagePrintOptions = pageOptions; } //this.model.PagePrintOptions.pageSetup.scale = 145; var getPrintAreaRanges = function() { var res = false; AscCommonExcel.executeInR1C1Mode(false, function () { res = AscCommonExcel.getRangeByRef(printArea.ref, t.model, true, true, true) }); return res && res.length ? res : null; }; //TODO для печати не нужно учитывать размер группы if(this.groupWidth || this.groupHeight) { this.ignoreGroupSize = true; this._calcHeaderColumnWidth(); this._calcHeaderRowHeight(); } var printAreaRanges = !printOnlySelection && printArea ? getPrintAreaRanges() : null; var pageSetup = pageOptions.asc_getPageSetup(); var fitToWidth = pageSetup.asc_getFitToWidth(); var fitToHeight = pageSetup.asc_getFitToHeight(); var _scale = pageSetup.asc_getScale(); //проверяем, не пришли ли настройки масштабирование, отличные от тех, которые лежат в модели var checkCustomScaleProps = function() { var _res; var _pageOptions = t.model.PagePrintOptions; var _pageSetup = _pageOptions.asc_getPageSetup(); var modelScale = _pageSetup.asc_getScale(); if(fitToWidth || fitToHeight) { _res = t.calcPrintScale(fitToWidth, fitToHeight); } if(_res !== null && _res !== modelScale) { return _res; } return null; }; if (printOnlySelection) { let selection; if (pageOptions && pageOptions.pageSetup && pageOptions.pageSetup.selection) { selection = pageOptions.pageSetup.selection; let _arrRanges = []; for (let i = 0; i < selection.length; i++) { let _selectionRange = new asc_Range(selection[i].c1, selection[i].r1, selection[i].c2, selection[i].r2); _arrRanges.push(_selectionRange); } selection = _arrRanges; } var tempPrintScale; //подменяем scale на временный для печати выделенной области if(fitToWidth || fitToHeight) { tempPrintScale = this.calcPrintScale(fitToWidth, fitToHeight, selection ? selection : true); } if (!selection) { selection = this.model.selectionRange.ranges; } for (var i = 0; i < selection.length; ++i) { range = selection[i]; if (c_oAscSelectionType.RangeCells === range.getType()) { if(!doNotRecalc) { this._prepareCellTextMetricsCache(range); } } else { maxCell = this._calculateMaxPrintRange(range, doNotRecalc); range = new asc_Range(range.c1, range.r1, maxCell.col, maxCell.row); } this._calcPagesPrint(range, pageOptions, indexWorksheet, arrPages, tempPrintScale, adjustPrint); } } else if(printArea && printAreaRanges) { //когда printArea мультиселект - при отрисовке областей печати в специальном режиме // необходимо возвращать массив из фрагментов //для этого добавил arrRanges tempPrintScale = checkCustomScaleProps(); for(var j = 0; j < printAreaRanges.length; j++) { range = printAreaRanges[j]; if(range && range.bbox) { range = range.bbox; } else { continue; } if (c_oAscSelectionType.RangeCells === range.getType()) { if(!doNotRecalc) { this._prepareCellTextMetricsCache(range); } } else { maxCell = this._calculateMaxPrintRange(range, doNotRecalc); range = new asc_Range(range.c1, range.r1, maxCell.col, maxCell.row); } let _startPages = arrPages.length; this._calcPagesPrint(range, pageOptions, indexWorksheet, arrPages, tempPrintScale, adjustPrint, true); if(arrRanges) { arrRanges.push({range: range, start: _startPages, end: arrPages.length}); } } } else { var _maxRowCol = this.getMaxRowColWithData(doNotRecalc); if (!_maxRowCol) { range = new asc_Range(0, 0, this.model.getColsCount() - 1, this.model.getRowsCount() - 1); //подменяем scale на временный для печати выделенной области if(_printArea && ignorePrintArea && (fitToWidth || fitToHeight)) { tempPrintScale = this.calcPrintScale(fitToWidth, fitToHeight, null, ignorePrintArea); } else { tempPrintScale = checkCustomScaleProps(); } this._calcPagesPrint(range, pageOptions, indexWorksheet, arrPages, tempPrintScale, adjustPrint, null, true); } else { range = new asc_Range(0, 0, _maxRowCol.col, _maxRowCol.row); //подменяем scale на временный для печати выделенной области if(_printArea && ignorePrintArea && (fitToWidth || fitToHeight)) { tempPrintScale = this.calcPrintScale(fitToWidth, fitToHeight, null, ignorePrintArea); } else { tempPrintScale = checkCustomScaleProps(); } this._calcPagesPrint(range, pageOptions, indexWorksheet, arrPages, tempPrintScale, adjustPrint); } } if(oldPagePrintOptions) { this.model.PagePrintOptions = oldPagePrintOptions; } if(this.groupWidth || this.groupHeight) { this.ignoreGroupSize = false; this._calcHeaderColumnWidth(); this._calcHeaderRowHeight(); } }; WorksheetView.prototype.printForOleObject = function (oRange) { return this.workbook.printForOleObject(this, oRange); }; WorksheetView.prototype.getRangePosition = function (oRange) { var result = {}; result.left = this._getColLeft(oRange.c1); result.top = this._getRowTop(oRange.r1); result.width = this._getColLeft(oRange.c2) + this.getColumnWidth(oRange.c2) - result.left; result.height = this._getRowTop(oRange.r2) + this.getRowHeight(oRange.r2) - result.top; return result; }; WorksheetView.prototype.getPrintOleRangePosition = function (oRange) { const oRangeSizes = this.getRangePosition(oRange); oRangeSizes.width += 3; oRangeSizes.height += 3; return oRangeSizes; }; WorksheetView.prototype.drawForPrint = function (drawingCtx, printPagesData, indexPrintPage, pages) { let t = this; let countPrintPages = pages && pages.length; let recalcIndexPrintPage = function (_indexPrintPage) { //real header/footer index starts with new sheet let newIndex = null; if (pages && pages[indexPrintPage]) { newIndex = 0; let activeSheetIndex = pages[_indexPrintPage].indexWorksheet; for (let i = _indexPrintPage - 1; i >= 0; i--) { if (pages[i].indexWorksheet === activeSheetIndex) { newIndex++; } } } return newIndex !== null ? newIndex : _indexPrintPage; }; indexPrintPage = recalcIndexPrintPage(indexPrintPage); let vector_koef = AscCommonExcel.vector_koef / t.getZoom(); if (AscCommon.AscBrowser.isCustomScaling()) { vector_koef /= t.getRetinaPixelRatio(); } this.stringRender.fontNeedUpdate = true; if (null === printPagesData) { // Напечатаем пустую страницу drawingCtx.BeginPage && drawingCtx.BeginPage(c_oAscPrintDefaultSettings.PageWidth, c_oAscPrintDefaultSettings.PageHeight); //draw header/footer this.drawHeaderFooter(drawingCtx, printPagesData, indexPrintPage, countPrintPages); if(window['Asc']['editor'].watermarkDraw) { window['Asc']['editor'].watermarkDraw.zoom = 1;//this.worksheet.objectRender.zoom.current; window['Asc']['editor'].watermarkDraw.Generate(); window['Asc']['editor'].watermarkDraw.StartRenderer(); window['Asc']['editor'].watermarkDraw.DrawOnRenderer(drawingCtx.DocumentRenderer, c_oAscPrintDefaultSettings.PageWidth, c_oAscPrintDefaultSettings.PageHeight); window['Asc']['editor'].watermarkDraw.EndRenderer(); } drawingCtx.EndPage && drawingCtx.EndPage(); } else { let printScale = (printPagesData && printPagesData.scale) ? printPagesData.scale : this.getPrintScale(); if (this.getRightToLeft()) { let renderingSettings = this.getRenderingSettings(); if (!renderingSettings) { renderingSettings = this.initRenderingSettings(); } renderingSettings && !renderingSettings.getCtxWidth() && renderingSettings.setCtxWidth(printPagesData.pageWidth / vector_koef); renderingSettings && renderingSettings.setPageLeftOffset(printPagesData.leftFieldInPx); let pageRightField = c_oAscPrintDefaultSettings.PageRightField; renderingSettings && renderingSettings.setPageRightOffset(pageRightField / vector_koef); renderingSettings.printScale = printScale; this.objectRender.updateDrawingsTransform({target: c_oTargetType.ColumnResize, col: 0}); } drawingCtx.BeginPage && drawingCtx.BeginPage(printPagesData.pageWidth, printPagesData.pageHeight); //special thumbnail split let printOptionsJson = this.workbook && this.workbook.getPrintOptionsJson(); let curPrintOptionsJson = (printOptionsJson && printOptionsJson["spreadsheetLayout"]) ? printOptionsJson["spreadsheetLayout"] : printOptionsJson; let thumbnailFirst = curPrintOptionsJson && curPrintOptionsJson["thumbnail"] && curPrintOptionsJson["thumbnail"]["first"]; let renderingSettings; if (thumbnailFirst === true || (typeof thumbnailFirst === "string" && thumbnailFirst.toLowerCase() === "true")) { let thumbnailMaxRowCount = 100; let currentRowCount = (printPagesData.pageRange.r2 - printPagesData.pageRange.r1) + (printPagesData.titleRowRange ? (printPagesData.titleRowRange.r2 - printPagesData.titleRowRange.r1) : 0); if (currentRowCount > thumbnailMaxRowCount) { renderingSettings = this.getRenderingSettings(); if (!renderingSettings) { renderingSettings = this.initRenderingSettings(); } let splitNumber = 2; renderingSettings && renderingSettings.setSplitRowBG(splitNumber); } } //TODO для печати не нужно учитывать размер группы if(this.groupWidth || this.groupHeight) { this.ignoreGroupSize = true; this._calcHeaderColumnWidth(); this._calcHeaderRowHeight(); } this._setDefaultFont(drawingCtx); this.usePrintScale = true; //draw header/footer this.drawHeaderFooter(drawingCtx, printPagesData, indexPrintPage, countPrintPages); //отступы с учётом заголовков let clipLeft, clipTop, clipWidth, clipHeight; //отступы без учёта загаловков let clipLeftShape, clipTopShape, clipWidthShape, clipHeightShape; let doDraw = function(range, titleWidth, titleHeight) { let renderingSettings = t.getRenderingSettings(); let _printScale; if (renderingSettings && printScale !== 1 && drawingCtx.Transform) { _printScale = renderingSettings.printScale; renderingSettings.printScale = 1; } drawingCtx.AddClipRect && t._AddClipRect(drawingCtx, clipLeft, clipTop, clipWidth, clipHeight); if (_printScale) { renderingSettings.printScale = _printScale; } let transformMatrix; let _transform = drawingCtx.Transform; if (printScale !== 1 && _transform) { let mmToPx = asc_getcvt(3/*mm*/, 0/*px*/, t._getPPIX()); let leftDiff = printPagesData.pageClipRectLeft * (1 - printScale); let topDiff = printPagesData.pageClipRectTop * (1 - printScale); transformMatrix = _transform.CreateDublicate ? _transform.CreateDublicate() : _transform.clone(); drawingCtx.setTransform(printScale, _transform.shy, _transform.shx, printScale, (t.getRightToLeft() ? -leftDiff : leftDiff) / mmToPx, topDiff / mmToPx); } if (t.getRightToLeft()) { /*if (!_transform) { _transform = new AscCommon.CMatrix(); } transformMatrix = new AscCommon.CMatrix(); transformMatrix.sx = -1; transformMatrix.tx = t.getCtxWidth() * (drawingCtx instanceof AscCommonExcel.CPdfPrinter ? vector_koef : 1); let newTransformMatrix = _transform.Multiply(transformMatrix); drawingCtx.setTransform(newTransformMatrix.sx, newTransformMatrix.shy, newTransformMatrix.shx, newTransformMatrix.sy, newTransformMatrix.tx, newTransformMatrix.ty); drawingCtx.updateTransforms && drawingCtx.updateTransforms();*/ } let offsetCols = printPagesData.startOffsetPx; //range = printPagesData.pageRange; let offsetX = t._getColLeft(range.c1) - printPagesData.leftFieldInPx + offsetCols - titleWidth; let offsetY = t._getRowTop(range.r1) - printPagesData.topFieldInPx - titleHeight; //TODO необходимо ли подменять visibleRange - в методе _prepareCellTextMetricsCache он может измениться let tmpVisibleRange = t.visibleRange; // Сменим visibleRange для прохождения проверок отрисовки t.visibleRange = range.clone(); // Нужно отрисовать заголовки if (printPagesData.pageHeadings) { t._drawColumnHeaders(drawingCtx, range.c1, range.c2, /*style*/ undefined, offsetX, printPagesData.topFieldInPx - t.cellsTop); t._drawRowHeaders(drawingCtx, range.r1, range.r2, /*style*/ undefined, printPagesData.leftFieldInPx - t.cellsLeft, offsetY); } // Рисуем сетку if (printPagesData.pageGridLines) { let vector_koef = AscCommonExcel.vector_koef / t.getZoom(); if (AscCommon.AscBrowser.isCustomScaling()) { vector_koef /= t.getRetinaPixelRatio(); } t._drawGrid(drawingCtx, range, offsetX, offsetY, printPagesData.pageWidth / vector_koef, printPagesData.pageHeight / vector_koef, printPagesData.scale, !titleHeight, !titleWidth); } //TODO временно подменяю scale. пересмотреть! подменять либо всегда, либо флаг добавить. let _modelScale, _modelPagesOptions; if(t.model.PagePrintOptions && t.model.PagePrintOptions.pageSetup) { _modelScale = t.model.PagePrintOptions.pageSetup.scale; t.model.PagePrintOptions.pageSetup.scale = printPagesData.scale; } else { _modelPagesOptions = t.model.PagePrintOptions; t.model.PagePrintOptions = new Asc.asc_CPageOptions(t.model); t.model.PagePrintOptions.pageSetup.scale = printPagesData.scale; } // Отрисовываем ячейки и бордеры t._drawCellsAndBorders(drawingCtx, range, offsetX, offsetY); if (_modelPagesOptions) { t.model.PagePrintOptions = _modelPagesOptions; } else { t.model.PagePrintOptions.pageSetup.scale = _modelScale; } t._RemoveClipRect(drawingCtx); if (transformMatrix) { drawingCtx.setTransform(transformMatrix.sx, transformMatrix.shy, transformMatrix.shx, transformMatrix.sy, transformMatrix.tx, transformMatrix.ty); } //Отрисовываем панель группировки по строкам //t._drawGroupData(drawingCtx, null, offsetX, offsetY); let drawingPrintOptions = { ctx: drawingCtx, printPagesData: printPagesData, titleWidth: titleWidth, titleHeight: titleHeight }; let oDocRenderer = drawingCtx.DocumentRenderer; let oOldBaseTransform = oDocRenderer.m_oBaseTransform; let oBaseTransform = new AscCommon.CMatrix(); oBaseTransform.sx = printScale; oBaseTransform.sy = printScale; oBaseTransform.tx = asc_getcvt(0/*mm*/, 3/*px*/, t._getPPIX()) * ( -offsetCols * printScale + printPagesData.pageClipRectLeft + (printPagesData.leftFieldInPx - printPagesData.pageClipRectLeft + titleWidth) * printScale) - (t.getRightToLeft() ? -1 : 1) * (t.getCellLeft(range.c1, 3) - t.getCellLeft(0, 3)) * printScale; const pxToMm = asc_getcvt(0/*mm*/, 3/*px*/, t._getPPIX()); const pageClipRectLeft = printPagesData.pageClipRectLeft; const leftFieldInPx = printPagesData.leftFieldInPx; const rightToLeft = t.getRightToLeft() ? -1 : 1; const rangeLeft = t.getCellLeft(range.c1); const col0Left = t.getCellLeft(0); const rangeWidth = rangeLeft - col0Left; const _txPx = printScale * (-offsetCols + leftFieldInPx - rightToLeft*pageClipRectLeft + titleWidth - rightToLeft * rangeWidth) + rightToLeft*pageClipRectLeft; oBaseTransform.tx = _txPx * pxToMm; oBaseTransform.ty = pxToMm * (printPagesData.pageClipRectTop + (printPagesData.topFieldInPx - printPagesData.pageClipRectTop + titleHeight) * printScale) - (t.getCellTop(range.r1, 3) - t.getCellTop(0, 3)) * printScale; let bGraphics = !!(oDocRenderer instanceof AscCommon.CGraphics); let clipL, clipT, clipR, clipB; if (bGraphics) { let oldTx, oldTy; if (oDocRenderer.m_oCoordTransform) { oldTx = oDocRenderer.m_oCoordTransform.tx; oldTy = oDocRenderer.m_oCoordTransform.ty; oDocRenderer.m_oCoordTransform.tx = !t.getRightToLeft() ? (t.getCellLeft(0) - offsetX) : (-t.getCellLeft(0) + t.getCellLeft(Math.max(0, range.c1)) + printPagesData.leftFieldInPx + offsetCols - titleWidth); oDocRenderer.m_oCoordTransform.ty = (t.getCellTop(0) - offsetY); } oDocRenderer.SaveGrState(); oDocRenderer.RestoreGrState(); oDocRenderer.IsPrintPreview = true; let oInvertBaseTransform = AscCommon.global_MatrixTransformer.Invert(oDocRenderer.m_oCoordTransform); clipLeftShape = (t.getCellLeft(range.c1) - offsetX) >> 0; clipTopShape = (t.getCellTop(range.r1) - offsetY) >> 0; let clipRightShape = (t.getCellLeft(range.c2 + 1) + 0.5 - offsetX) >> 0; let clipBottomShape = (t.getCellTop(range.r2 + 1) + 0.5 - offsetY) >> 0; if (t.getRightToLeft()) { clipRightShape = t.checkRtl(clipRightShape); clipLeftShape = t.checkRtl(clipLeftShape); } clipL = oInvertBaseTransform.TransformPointX(clipLeftShape, clipTopShape); clipT = oInvertBaseTransform.TransformPointY(clipLeftShape, clipTopShape); clipR = oInvertBaseTransform.TransformPointX(clipRightShape, clipBottomShape); clipB = oInvertBaseTransform.TransformPointY(clipRightShape, clipBottomShape); oDocRenderer.SaveGrState(); t._AddClipRect(oDocRenderer, clipL, clipT, clipR - clipL, clipB - clipT, true); t.objectRender.print(drawingPrintOptions); delete oDocRenderer.IsPrintPreview; oDocRenderer.RestoreGrState(); if (oDocRenderer.m_oCoordTransform) { if (oOldBaseTransform) { oDocRenderer.m_oCoordTransform.tx = oOldBaseTransform.tx * oDocRenderer.m_oCoordTransform.sx; oDocRenderer.m_oCoordTransform.ty = oOldBaseTransform.ty * oDocRenderer.m_oCoordTransform.sy; } else if (oldTx != null && oldTy != null) { oDocRenderer.m_oCoordTransform.tx = oldTx; oDocRenderer.m_oCoordTransform.ty = oldTy; } } } else { clipL = clipLeftShape >> 0; clipT = clipTopShape >> 0; clipR = (clipLeftShape + clipWidthShape + 0.5) >> 0; clipB = (clipTopShape + clipHeightShape + 0.5) >> 0; let _printScale; if (t.getRightToLeft()) { let renderingSettings = t.getRenderingSettings(); if (renderingSettings) { _printScale = renderingSettings.printScale; renderingSettings.printScale = null; } } drawingCtx.AddClipRect && t._AddClipRect(drawingCtx, clipL, clipT, clipR - clipL, clipB - clipT); if (_printScale) { renderingSettings.printScale = printScale; } if (oDocRenderer.SetBaseTransform) { oDocRenderer.SetBaseTransform(oBaseTransform); } t.objectRender.print(drawingPrintOptions); if (oDocRenderer.SetBaseTransform) { oDocRenderer.SetBaseTransform(oOldBaseTransform); } t._RemoveClipRect(drawingCtx); } t.visibleRange = tmpVisibleRange; }; let cellsLeft = printPagesData.pageHeadings ? this.cellsLeft : 0; let cellsTop = printPagesData.pageHeadings ? this.cellsTop : 0; let changedCellLeft = cellsLeft - cellsLeft*printScale; let changedCellTop = cellsTop - cellsTop*printScale; let pageWidth, pageHeight; //увеличиваем область клипирования на половину максимального размера бордера - максимально выступающую часть за пределы листа let borderDiff = 2;//Math.ceil(1.5) if(printPagesData.titleRowRange || printPagesData.titleColRange) { if(printPagesData.titleRowRange && printPagesData.titleColRange){ clipLeft = printPagesData.pageClipRectLeft - borderDiff; clipTop = printPagesData.pageClipRectTop - borderDiff; clipWidth = printPagesData.titleWidth + cellsLeft*printScale + borderDiff; clipHeight = printPagesData.titleHeight + cellsTop*printScale + borderDiff; clipLeftShape = printPagesData.pageClipRectLeft + cellsLeft*printScale; clipTopShape = printPagesData.pageClipRectTop + cellsTop*printScale; clipWidthShape = printPagesData.titleWidth; clipHeightShape = printPagesData.titleHeight; doDraw(new asc_Range(printPagesData.titleColRange.c1, printPagesData.titleRowRange.r1, printPagesData.titleColRange.c2, printPagesData.titleRowRange.r2), 0, 0); } if(printPagesData.titleRowRange){ clipLeft = printPagesData.pageClipRectLeft + printPagesData.titleWidth + (printPagesData.titleWidth ? (cellsLeft*printScale) : 0) - borderDiff; clipTop = printPagesData.pageClipRectTop - borderDiff; clipWidth = printPagesData.pageClipRectWidth + cellsLeft*printScale + borderDiff; clipHeight = printPagesData.titleHeight + cellsTop*printScale + borderDiff; pageWidth = (t.getCellLeft(printPagesData.titleRowRange.c2 + 1, 0) - t.getCellLeft(printPagesData.titleRowRange.c1, 0)) * printScale; clipLeftShape = printPagesData.pageClipRectLeft + printPagesData.titleWidth + cellsLeft*printScale; clipTopShape = printPagesData.pageClipRectTop + cellsTop*printScale; clipWidthShape = pageWidth; clipHeightShape = printPagesData.titleHeight; doDraw(printPagesData.titleRowRange, printPagesData.titleWidth/printScale, 0); } if(printPagesData.titleColRange){ clipLeft = printPagesData.pageClipRectLeft - borderDiff; clipTop = printPagesData.pageClipRectTop + printPagesData.titleHeight + (printPagesData.titleHeight ? (cellsTop*printScale) : 0) - borderDiff; clipWidth = printPagesData.titleWidth + cellsLeft*printScale + borderDiff; clipHeight = printPagesData.pageClipRectHeight + (printPagesData.titleHeight ? cellsTop : 0) - changedCellTop + borderDiff; pageHeight = (t.getCellTop(printPagesData.titleColRange.r2 + 1, 0) - t.getCellTop(printPagesData.titleColRange.r1, 0)) * printScale; clipLeftShape = printPagesData.pageClipRectLeft + cellsLeft*printScale; clipTopShape = printPagesData.pageClipRectTop + printPagesData.titleHeight + cellsTop*printScale; clipWidthShape = printPagesData.titleWidth; clipHeightShape = pageHeight; doDraw(printPagesData.titleColRange, 0, printPagesData.titleHeight/printScale); } pageWidth = (t.getCellLeft(printPagesData.pageRange.c2 + 1, 0) - t.getCellLeft(printPagesData.pageRange.c1, 0)) * printScale; pageHeight = (t.getCellTop(printPagesData.pageRange.r2 + 1, 0) - t.getCellTop(printPagesData.pageRange.r1, 0)) * printScale; clipLeft = printPagesData.pageClipRectLeft + printPagesData.titleWidth + (printPagesData.titleWidth ? (cellsLeft*printScale) : 0) - borderDiff; clipTop = printPagesData.pageClipRectTop + printPagesData.titleHeight + (printPagesData.titleHeight ? (cellsTop*printScale) : 0) - borderDiff; clipWidth = printPagesData.pageClipRectWidth + cellsLeft*printScale + borderDiff; clipHeight = printPagesData.pageClipRectHeight + (printPagesData.titleHeight ? cellsTop : 0) - changedCellTop + borderDiff; clipLeftShape = printPagesData.pageClipRectLeft + printPagesData.titleWidth + cellsLeft*printScale; clipTopShape = printPagesData.pageClipRectTop + printPagesData.titleHeight + cellsTop*printScale; clipWidthShape = pageWidth; clipHeightShape = pageHeight; doDraw(printPagesData.pageRange, printPagesData.titleWidth/printScale, printPagesData.titleHeight/printScale); } else { //pageClipRectWidth - ширина страницы без учёта измененного(*scale) хеадера - как при 100% //поэтому при расчтетах из него вычетаем размер заголовка как при 100% //смещение слева/сверху рассчитывается с учётом измененной ширины заголовков - поэтому домножаем её на printScale clipLeft = printPagesData.pageClipRectLeft - borderDiff; clipTop = printPagesData.pageClipRectTop - borderDiff; clipWidth = printPagesData.pageClipRectWidth - changedCellLeft + borderDiff; clipHeight = printPagesData.pageClipRectHeight - changedCellTop + borderDiff; clipLeftShape = printPagesData.pageClipRectLeft + cellsLeft*printScale; clipTopShape = printPagesData.pageClipRectTop + cellsTop*printScale; clipWidthShape = printPagesData.pageClipRectWidth - cellsLeft; clipHeightShape = printPagesData.pageClipRectHeight - cellsTop; doDraw(printPagesData.pageRange, 0, 0); } this.usePrintScale = false; if(this.groupWidth || this.groupHeight) { this.ignoreGroupSize = false; this._calcHeaderColumnWidth(); this._calcHeaderRowHeight(); } let oWatermark = window['Asc']['editor'].watermarkDraw; if(oWatermark) { let oDocRenderer = drawingCtx.DocumentRenderer; oWatermark.zoom = 1;//this.worksheet.objectRender.zoom.current; oWatermark.Generate(); if(oDocRenderer instanceof AscCommon.CGraphics) { let oCtx = oDocRenderer.m_oContext; oWatermark.Draw(oCtx, oCtx.canvas.width, oCtx.canvas.height); } else { oWatermark.StartRenderer(); oWatermark.DrawOnRenderer(oDocRenderer, printPagesData.pageWidth, printPagesData.pageHeight); oWatermark.EndRenderer(); } } this.stringRender.resetTransform(drawingCtx); this.setRenderingSettings(null); this.pageWidth = null; drawingCtx.EndPage && drawingCtx.EndPage(); this.getRightToLeft() && this.objectRender.updateDrawingsTransform({target: c_oTargetType.ColumnResize, col: 0}); } }; WorksheetView.prototype.fitOnOnePage = function(val) { //TODO add constant! var width = undefined, height = undefined; if(val === 0) { //sheet width = 1; height = 1; //todo fitToPage } else if(val === 1) { //columns width = 1; //pageSetup.asc_setFitToWidth(); } else { //rows height = 1; //pageSetup.asc_setFitToHeight(); } this.fitToPages(width, height); }; WorksheetView.prototype.setPrintScale = function (width, height, scale) { var t = this; this._isLockedLayoutOptions(function(success) { if(!success) { return; } t.fitToWidthHeight(width, height, ((width === null && height === null) || (width === 0 && height === 0)) ? scale : undefined); }); }; //пересчитывать необходимо когда после открытия зашли в настройки печати WorksheetView.prototype.recalcPrintScale = function () { var pageOptions = this.model.PagePrintOptions; var pageSetup = pageOptions.asc_getPageSetup(); var width = pageSetup.asc_getFitToWidth(); var height = pageSetup.asc_getFitToHeight(); if(!height && !width) { return; } var calcScale = this.calcPrintScale(width, height); if(!isNaN(calcScale)) { let viewMode = this.handlers.trigger('getViewMode'); let realLockDraw = this.lockDraw; //TODO add lock draw here. need review all draw calls(try to replace on recalculate) this.lockDraw = true; this._setPrintScale(calcScale, viewMode); this.lockDraw = realLockDraw; } //TODO нужно ли в данном случае лочить? //this._isLockedLayoutOptions(callback); }; WorksheetView.prototype.fitToPages = function (width, height) { //width/height - count of pages //automatic -> width/height = undefined //define print scale this._setPrintScale(this.calcPrintScale(width, height)); //TODO нужно ли в данном случае лочить? //this._isLockedLayoutOptions(callback); }; //вызывается из меню при изменении только scale to fit -> width WorksheetView.prototype.fitToWidth = function (val) { //width/height - count of pages //automatic -> width/height = undefined //define print scale var t = this; var pageOptions = t.model.PagePrintOptions; if(val !== pageOptions.asc_getFitToWidth()) { History.Create_NewPoint(); History.StartTransaction(); pageOptions.asc_setFitToWidth(val); this._setPrintScale(this.calcPrintScale(pageOptions.asc_getFitToWidth(), pageOptions.asc_getFitToHeight())); History.EndTransaction(); } //TODO нужно ли в данном случае лочить? //this._isLockedLayoutOptions(callback); }; //вызывается из меню при изменении только scale to fit -> height WorksheetView.prototype.fitToHeight = function (val) { //width/height - count of pages //automatic -> width/height = undefined //define print scale var t = this; var pageOptions = t.model.PagePrintOptions; if(val !== pageOptions.asc_getFitToHeight()) { History.Create_NewPoint(); History.StartTransaction(); pageOptions.asc_setFitToHeight(val); this._setPrintScale(this.calcPrintScale(pageOptions.asc_getFitToWidth(), pageOptions.asc_getFitToHeight())); History.EndTransaction(); } //TODO нужно ли в данном случае лочить? //this._isLockedLayoutOptions(callback); }; WorksheetView.prototype.fitToWidthHeight = function (width, height, scale) { //width/height - count of pages //automatic -> width/height = undefined //define print scale var t = this; var pageOptions = t.model.PagePrintOptions; var pageSetup = pageOptions.asc_getPageSetup(); if(width === null) { width = 0; } if(height === null) { height = 0; } var fitToPageModel = this.model.sheetPr ? this.model.sheetPr.FitToPage : null; var fitToHeightAuto = height === 0 || height === undefined; var fitToWidthAuto = width === 0 || width === undefined; var changedFitToPage = (!fitToHeightAuto || !fitToWidthAuto) !== fitToPageModel; var fitToWidthModel = pageSetup.fitToWidth; var changedWidth = width !== fitToWidthModel; var fitToHeightModel = pageSetup.fitToHeight; var changedHeight = height !== fitToHeightModel; var changedScale = scale && scale !== pageSetup.asc_getScale(); if(changedWidth || changedHeight || changedScale || changedFitToPage) { History.Create_NewPoint(); History.StartTransaction(); t._changeFitToPage(width, height); if(changedWidth) { pageSetup.asc_setFitToWidth(width); } if(changedHeight) { pageSetup.asc_setFitToHeight(height); } if(undefined === scale && (width !== 0 || height !== 0)) { scale = t.calcPrintScale(pageSetup.asc_getFitToWidth(), pageSetup.asc_getFitToHeight()); } if(scale) { t._setPrintScale(scale); } t.changeViewPrintLines(true); if(t.viewPrintLines) { t.updateSelection(); } History.EndTransaction(); } }; WorksheetView.prototype._setPrintScale = function (val, isNotHistory) { var pageOptions = this.model.PagePrintOptions; var pageSetup = pageOptions.asc_getPageSetup(); var oldScale = pageSetup.asc_getScale(); if(val !== oldScale) { History.Create_NewPoint(); History.StartTransaction(); pageSetup.asc_setScale(val, isNotHistory); History.EndTransaction(); } //TODO нужно ли в данном случае лочить? //this._isLockedLayoutOptions(callback); }; WorksheetView.prototype._changeFitToPage = function(width, height) { var fitToHeightAuto = height === 0 || height === undefined; var fitToWidthAuto = width === 0 || width === undefined; this.model.setFitToPage(!fitToHeightAuto || !fitToWidthAuto); }; WorksheetView.prototype.calcPrintScale = function(width, height, _selection, ignorePrintArea) { //TODO для печати не нужно учитывать размер группы if(this.groupWidth || this.groupHeight) { this.ignoreGroupSize = true; this._calcHeaderColumnWidth(); this._calcHeaderRowHeight(); } var pageOptions = this.model.PagePrintOptions; var pageMargins, pageSetup, pageGridLines, pageHeadings; if (pageOptions) { pageMargins = pageOptions.asc_getPageMargins(); pageSetup = pageOptions.asc_getPageSetup(); pageGridLines = pageOptions.asc_getGridLines(); pageHeadings = pageOptions.asc_getHeadings(); } var pageWidth, pageHeight, pageOrientation; if (pageSetup instanceof asc_CPageSetup) { pageWidth = pageSetup.asc_getWidth(); pageHeight = pageSetup.asc_getHeight(); pageOrientation = pageSetup.asc_getOrientation(); } var pageLeftField, pageRightField, pageTopField, pageBottomField; if (pageMargins) { pageLeftField = Math.max(pageMargins.asc_getLeft(), c_oAscPrintDefaultSettings.MinPageLeftField); pageRightField = Math.max(pageMargins.asc_getRight(), c_oAscPrintDefaultSettings.MinPageRightField); pageTopField = Math.max(pageMargins.asc_getTop(), c_oAscPrintDefaultSettings.MinPageTopField); pageBottomField = Math.max(pageMargins.asc_getBottom(), c_oAscPrintDefaultSettings.MinPageBottomField); } var _retinaPixelRatio = 1; var vector_koef = AscCommonExcel.vector_koef / this.getZoom(); if (AscCommon.AscBrowser.isCustomScaling()) { _retinaPixelRatio = this.getRetinaPixelRatio(); vector_koef /= this.getRetinaPixelRatio(); } if (null == pageGridLines) { pageGridLines = c_oAscPrintDefaultSettings.PageGridLines; } if (null == pageHeadings) { pageHeadings = c_oAscPrintDefaultSettings.PageHeadings; } if (null == pageWidth) { pageWidth = c_oAscPrintDefaultSettings.PageWidth; } if (null == pageHeight) { pageHeight = c_oAscPrintDefaultSettings.PageHeight; } if (null == pageOrientation) { pageOrientation = c_oAscPrintDefaultSettings.PageOrientation; } if (null == pageLeftField) { pageLeftField = c_oAscPrintDefaultSettings.PageLeftField; } if (null == pageRightField) { pageRightField = c_oAscPrintDefaultSettings.PageRightField; } if (null == pageTopField) { pageTopField = c_oAscPrintDefaultSettings.PageTopField; } if (null == pageBottomField) { pageBottomField = c_oAscPrintDefaultSettings.PageBottomField; } if (Asc.c_oAscPageOrientation.PageLandscape === pageOrientation) { var tmp = pageWidth; pageWidth = pageHeight; pageHeight = tmp; } var pageWidthWithFields = pageWidth - pageLeftField - pageRightField; var pageHeightWithFields = pageHeight - pageTopField - pageBottomField; var leftFieldInPx = pageLeftField / vector_koef + 1; var topFieldInPx = pageTopField / vector_koef + 1; let _cellsLeft = this.cellsLeft; let _cellsTop = this.cellsTop; //TODO ms считает именно так - каждый раз прибаляются размеры заголовков к полям. необходимо перепроверить! //if (pageHeadings) { // Рисуем заголовки, нужно чуть сдвинуться leftFieldInPx += _cellsLeft; topFieldInPx += _cellsTop; //} //TODO при сравнении резальтатов рассчета страниц в зависимости от scale - LO выдаёт похожие результаты, MS - другие. Необходимо пересмотреть! var pageWidthWithFieldsHeadings = ((pageWidth - pageRightField) / vector_koef - leftFieldInPx) /*/ scale*/; var pageHeightWithFieldsHeadings = ((pageHeight - pageBottomField) / vector_koef - topFieldInPx) /*/ scale*/; var t = this; var doCalcScaleWidth = function(start, end) { var res; if(width) { var widthAllCols = pageHeadings ? _cellsLeft * width : 0; for(var i = start; i <= end; i++) { //widthAllCols += t._getColumnWidth(i); widthAllCols += t._getWidthForPrint(i) * _retinaPixelRatio; } res = ((pageWidthWithFieldsHeadings * width) / widthAllCols) * 100; } return res; }; var doCalcScaleHeight = function(start, end) { var res; if(height) { var heightAllRows = pageHeadings ? _cellsTop * height : 0; for(var i = start; i <= end; i++) { //heightAllRows += t._getRowHeight(i); heightAllRows += t._getHeightForPrint(i) * _retinaPixelRatio; } res = ((pageHeightWithFieldsHeadings * height) / heightAllRows) * 100; } return res; }; var wScale; var hScale; var calcScaleByRanges = function(ranges) { var tempWScale = null, tempHScale = null; for(var i = 0; i < ranges.length; i++) { var range = ranges[i].bbox ? ranges[i].bbox : ranges[i]; tempWScale = doCalcScaleWidth(range.c1, range.c2); tempHScale = doCalcScaleHeight(range.r1, range.r2); if(!wScale || (tempWScale && wScale > tempWScale)) { wScale = tempWScale; } if(!hScale || (tempHScale && hScale > tempHScale)) { hScale = tempHScale; } } }; if(_selection) { calcScaleByRanges(asc_typeof(_selection) === "object" ? _selection : this._getSelection().ranges); } else { //TODO ignorePrintArea - необходимо протащить флаг! var printArea = !ignorePrintArea && this.model.workbook.getDefinesNames("Print_Area", this.model.getId()); var getPrintAreaRanges = function() { var res = false; AscCommonExcel.executeInR1C1Mode(false, function () { res = AscCommonExcel.getRangeByRef(printArea.ref, t.model, true, true) }); return res && res.length ? res : null; }; var printAreaRanges = printArea ? getPrintAreaRanges() : null; if(printAreaRanges) { calcScaleByRanges(printAreaRanges); } else { //calculate width/height all columns/rows let rowsCount = this.model.getRowsCount(); let colsCount = this.model.getColsCount(); /*if (rowsCount > nMaxPrintRows) { maxCol = colsCount - 1; maxRow = rowsCount - 1; } else {*/ var range = new asc_Range(0, 0, colsCount - 1, rowsCount - 1); var maxCell = this._calculateMaxPrintRange(range); var maxCol = maxCell.col; var maxRow = maxCell.row; maxCell = this.model.getSparkLinesMaxColRow(); maxCol = Math.max(maxCol, maxCell.col); maxRow = Math.max(maxRow, maxCell.row); maxCell = this.model.autoFilters.getMaxColRow(); maxCol = Math.max(maxCol, maxCell.col); maxRow = Math.max(maxRow, maxCell.row); maxCell = this.objectRender && this.objectRender.getMaxColRow(); if (maxCell) { maxCol = Math.max(maxCol, maxCell.col); maxRow = Math.max(maxRow, maxCell.row); } //} //TODO print area wScale = doCalcScaleWidth(0, maxCol); hScale = doCalcScaleHeight(0, maxRow); } } //scale only int /*wScale = wScale >> 0; hScale = hScale >> 0; var minScale; if(width && height) { minScale = Math.min(wScale, hScale); } else if(width) { minScale = wScale; } else { minScale = hScale; }*/ //TODO revert old version for standardtester on hotfix //up commented code is true, after release need change var minScale; if(width && height) { minScale = Math.min(Math.round(wScale), Math.round(hScale)); } else if(width) { minScale = Math.round(wScale); } else { minScale = Math.round(hScale); } if(minScale < 10) { minScale = 10; } if(minScale > 100) { minScale = 100; } if(this.groupWidth || this.groupHeight) { this.ignoreGroupSize = false; this._calcHeaderColumnWidth(); this._calcHeaderRowHeight(); } return minScale; }; // ----- Drawing ----- WorksheetView.prototype.draw = function (lockDraw) { if (lockDraw || this.model.workbook.bCollaborativeChanges || window['IS_NATIVE_EDITOR']) { return this; } if (this.workbook.printPreviewState && this.workbook.printPreviewState.isStart()) { //только перерисовываю, каждый раз пересчёт - может потребовать много ресурсов //если изменилось количество строк/столбцов со значениями - пересчитываю //пересчёт выполянется когда пришли данные от других пользователей return; } if (this.workbook.Api.isEyedropperStarted()) { this.workbook.Api.clearEyedropperImgData(); } this._recalculate(); this.handlers.trigger("checkLastWork"); this._clean(); this._drawCorner(); this._drawColumnHeaders(null); this._drawRowHeaders(null); this._drawGrid(null); this._drawCellsAndBorders(null); this._drawGroupData(null); this._drawGroupData(null, null, undefined, undefined, true); this._drawFrozenPane(); this._drawFrozenPaneLines(); this._fixSelectionOfMergedCells(); this._drawElements(this.af_drawButtons); this.cellCommentator.drawCommentCells(); this.objectRender.showDrawingObjects(); if (this.overlayCtx) { this._drawSelection(); } //this._cleanPagesModeData(); return this; }; WorksheetView.prototype._clean = function () { this.drawingCtx.setFillStyle( this.settings.cells.defaultState.background ); this._fillRect( this.drawingCtx, 0, 0, this.drawingCtx.getWidth(), this.drawingCtx.getHeight() ); if ( this.overlayCtx ) { this.overlayCtx.clear(); } }; WorksheetView.prototype.drawHighlightedHeaders = function (col, row) { this._activateOverlayCtx(); if (col >= 0 && col !== this.highlightedCol) { this._doCleanHighlightedHeaders(); this.highlightedCol = col; this._drawColumnHeaders(null, col, col, kHeaderHighlighted); } else if (row >= 0 && row !== this.highlightedRow) { this._doCleanHighlightedHeaders(); this.highlightedRow = row; this._drawRowHeaders(null, row, row, kHeaderHighlighted); } this._deactivateOverlayCtx(); return this; }; WorksheetView.prototype.cleanHighlightedHeaders = function () { this._activateOverlayCtx(); this._doCleanHighlightedHeaders(); this._deactivateOverlayCtx(); return this; }; WorksheetView.prototype._activateOverlayCtx = function () { this.drawingCtx = this.buffers.overlay; }; WorksheetView.prototype._deactivateOverlayCtx = function () { this.drawingCtx = this.buffers.main; }; WorksheetView.prototype._doCleanHighlightedHeaders = function () { var selectionRange = this.model.getSelection(); var hlc = this.highlightedCol, hlr = this.highlightedRow; var bSelectionObject = this.objectRender.selectedGraphicObjectsExists(); if (hlc >= 0) { if (bSelectionObject || !selectionRange.containsCol(hlc)) { this._cleanColumnHeaders(hlc); if (!bSelectionObject) { if (selectionRange.containsCol(hlc + 1)) { this._drawColumnHeaders(null, hlc + 1, hlc + 1, kHeaderActive); } if (selectionRange.containsCol(hlc - 1)) { this._drawColumnHeaders(null, hlc - 1, hlc - 1, kHeaderActive); } } } else { this._drawColumnHeaders(null, hlc, hlc, kHeaderActive); } this.highlightedCol = -1; } if (hlr >= 0) { if (bSelectionObject || !selectionRange.containsRow(hlr)) { this._cleanRowHeaders(hlr); if (!bSelectionObject) { if (selectionRange.containsRow(hlr + 1)) { this._drawRowHeaders(null, hlr + 1, hlr + 1, kHeaderActive); } if (selectionRange.containsRow(hlr - 1)) { this._drawRowHeaders(null, hlr - 1, hlr - 1, kHeaderActive); } } } else { this._drawRowHeaders(null, hlr, hlr, kHeaderActive); } this.highlightedRow = -1; } }; WorksheetView.prototype._drawActiveHeaders = function () { var vr = this.visibleRange; var selectionRange = this.model.getSelection(); var range, c1, c2, r1, r2; this._activateOverlayCtx(); for (var i = 0; i < selectionRange.ranges.length; ++i) { range = selectionRange.ranges[i]; c1 = Math.max(vr.c1, range.c1); c2 = Math.min(vr.c2, range.c2); r1 = Math.max(vr.r1, range.r1); r2 = Math.min(vr.r2, range.r2); this._drawColumnHeaders(null, c1, c2, kHeaderActive); this._drawRowHeaders(null, r1, r2, kHeaderActive); if (this.topLeftFrozenCell) { var cFrozen = this.topLeftFrozenCell.getCol0() - 1; var rFrozen = this.topLeftFrozenCell.getRow0() - 1; if (0 <= cFrozen) { c1 = Math.max(0, range.c1); c2 = Math.min(cFrozen, range.c2); this._drawColumnHeaders(null, c1, c2, kHeaderActive); } if (0 <= rFrozen) { r1 = Math.max(0, range.r1); r2 = Math.min(rFrozen, range.r2); this._drawRowHeaders(null, r1, r2, kHeaderActive); } } } this._deactivateOverlayCtx(); }; WorksheetView.prototype._drawCorner = function () { if (false === this.model.getSheetView().asc_getShowRowColHeaders()) { return; } var x2 = this.headersLeft + this.headersWidth; var x1 = x2 - this.headersHeight; var y2 = this.headersTop + this.headersHeight; var y1 = this.headersTop; var dx = 4; var dy = 4; var isPrint = this.usePrintScale; var activeNamedSheetView = !isPrint && this.model.getActiveNamedSheetViewId() !== null; this._drawHeader(null, this.headersLeft, this.headersTop, this.headersWidth, this.headersHeight, kHeaderDefault, true, -1); this.drawingCtx.beginPath(); this._moveTo(this.drawingCtx, x2 - dx, y1 + dy); this._lineTo(this.drawingCtx, x2 - dx, y2 - dy); this._lineTo(this.drawingCtx, x1 + dx, y2 - dy); this._lineTo(this.drawingCtx, x2 - dx, y1 + dy); this.drawingCtx.setFillStyle(activeNamedSheetView ? this.settings.header.cornerColorSheetView : this.settings.header.cornerColor) .fill(); }; /** Рисует заголовки видимых колонок */ WorksheetView.prototype._drawColumnHeaders = function (drawingCtx, start, end, style, offsetXForDraw, offsetYForDraw) { if (!drawingCtx && false === this.model.getSheetView().asc_getShowRowColHeaders()) { return; } if (window["IS_NATIVE_EDITOR"]) { // for ios (TODO check the need) this._prepareCellTextMetricsCache(new asc_Range(start, 0, end, 1)); } var vr = this.visibleRange; var offsetX = (undefined !== offsetXForDraw) ? offsetXForDraw : this._getOffsetX(); var offsetY = (undefined !== offsetYForDraw) ? offsetYForDraw : this.headersTop; let clipRectX = this.cellsLeft; if (!drawingCtx && this.topLeftFrozenCell && undefined === offsetXForDraw) { var cFrozen = this.topLeftFrozenCell.getCol0(); if (start < vr.c1) { offsetX = this._getOffsetY(0, true); } else { offsetX -= this._getColLeft(cFrozen) - this._getColLeft(0); clipRectX = this._getColLeft(cFrozen); } } if (asc_typeof(start) !== "number") { start = vr.c1; } if (asc_typeof(end) !== "number") { end = vr.c2; } if (style === undefined) { style = kHeaderDefault; } this._setDefaultFont(drawingCtx); var ctx = this.drawingCtx; var ctxW = ctx.getWidth(); var ctxH = ctx.getHeight(); let isUseMainClip = (window["IS_NATIVE_EDITOR"] !== true); if (isUseMainClip) this._AddClipRect(ctx, clipRectX, this.headersTop - this.groupHeight, ctxW, ctxH); // draw column headers var l = this._getColLeft(start) - offsetX, w; for (var i = start; i <= end; ++i) { w = this._getColumnWidth(i); this._drawHeader(drawingCtx, l, offsetY, w, this.headersHeight, style, true, i); l += w; } if (isUseMainClip) this._RemoveClipRect(ctx); }; /** Рисует заголовки видимых строк */ WorksheetView.prototype._drawRowHeaders = function (drawingCtx, start, end, style, offsetXForDraw, offsetYForDraw) { if (!drawingCtx && false === this.model.getSheetView().asc_getShowRowColHeaders()) { return; } var vr = this.visibleRange; var offsetX = (undefined !== offsetXForDraw) ? offsetXForDraw : this.headersLeft; var offsetY = (undefined !== offsetYForDraw) ? offsetYForDraw : this._getOffsetY(); let clipRectY = this.cellsTop; if (!drawingCtx && this.topLeftFrozenCell && undefined === offsetYForDraw) { var rFrozen = this.topLeftFrozenCell.getRow0(); if (start < vr.r1) { offsetY = this._getOffsetY(0, true); } else { offsetY -= this._getRowTop(rFrozen) - this._getRowTop(0); clipRectY = this._getRowTop(rFrozen); } } if (asc_typeof(start) !== "number") { start = vr.r1; } if (asc_typeof(end) !== "number") { end = vr.r2; } if (style === undefined) { style = kHeaderDefault; } this._setDefaultFont(drawingCtx); var ctx = this.drawingCtx; var ctxW = ctx.getWidth(); var ctxH = ctx.getHeight(); let isUseMainClip = (window["IS_NATIVE_EDITOR"] !== true); if (isUseMainClip) this._AddClipRect(ctx, this.headersLeft - this.groupWidth, clipRectY, ctxW, ctxH); // draw row headers var t = this._getRowTop(start) - offsetY, h; for (var i = start; i <= end; ++i) { h = this._getRowHeight(i); this._drawHeader(drawingCtx, offsetX, t, this.headersWidth, h, style, false, i); t += h; } if (isUseMainClip) this._RemoveClipRect(ctx); }; /** * Рисует заголовок, принимает координаты и размеры в px * @param {DrawingContext} drawingCtx * @param {Number} x Координата левого угла в px * @param {Number} y Координата левого угла в px * @param {Number} w Ширина в px * @param {Number} h Высота в px * @param {Number} style Стиль заголовка (kHeaderDefault, kHeaderActive, kHeaderHighlighted) * @param {Boolean} isColHeader Тип заголовка: true - колонка, false - строка * @param {Number} index Индекс столбца/строки или -1 */ WorksheetView.prototype._drawHeader = function (drawingCtx, x, y, w, h, style, isColHeader, index) { // Для отрисовки невидимого столбца/строки var isZeroHeader = false; if (-1 !== index) { if (isColHeader) { if (0 === w) { if (style !== kHeaderDefault) { return; } // Это невидимый столбец isZeroHeader = true; // Отрисуем только границу w = 1; // Возможно мы уже рисовали границу невидимого столбца (для последовательности невидимых) if (0 < index && 0 === this._getColumnWidth(index - 1)) { // Мы уже нарисовали border для невидимой границы return; } } else if (0 < index && 0 === this._getColumnWidth(index - 1)) { // Мы уже нарисовали border для невидимой границы (поэтому нужно чуть меньше рисовать для соседнего столбца) w -= 1; x += 1; } } else { if (0 === h) { if (style !== kHeaderDefault) { return; } // Это невидимая строка isZeroHeader = true; // Отрисуем только границу h = 1; // Возможно мы уже рисовали границу невидимой строки (для последовательности невидимых) if (0 < index && 0 === this._getRowHeight(index - 1)) { // Мы уже нарисовали border для невидимой границы return; } } else if (0 < index && 0 === this._getRowHeight(index - 1)) { // Мы уже нарисовали border для невидимой границы (поэтому нужно чуть меньше рисовать для соседней строки) h -= 1; y += 1; } } } //TODO во время печати едиственный флаг usePrintScale выставляется в true, использую здесь именно его //в дальнейшем необходимо его изменить/переименовать var isPrint = this.usePrintScale; var isFiltering = false; if (!isPrint && !isColHeader) { isFiltering = this.model.autoFilters.containInFilter(index, true, true, true) } var activeNamedSheetView = !isPrint && this.model.getActiveNamedSheetViewId() !== null; var ctx = drawingCtx || this.drawingCtx; var st = this.settings.header.style[style]; var backgroundColor = isPrint ? this.settings.header.printBackground : (activeNamedSheetView ? st.backgroundDark : st.background); var borderColor = isPrint ? this.settings.header.printBorder : st.border; var color = isPrint ? this.settings.header.printColor : (isFiltering ? (activeNamedSheetView ? st.colorDarkFiltering : st.colorFiltering) : (activeNamedSheetView ? st.sheetViewCellTitleLabel : st.color)); var x2 = x + w; var y2 = y + h; var x2WithoutBorder = x2 - gridlineSize; // background только для видимых if (!isZeroHeader) { // draw background ctx.setFillStyle(backgroundColor); this._fillRect(ctx, x, y, w, h); } let t = this; let _toRetina = function (val) { return t.getRetinaPixelRatio() >= 2 ? AscCommon.AscBrowser.convertToRetinaValue(val, true) : val; }; let drawTopBorder = function (_selected) { if (style !== kHeaderDefault && !isColHeader && !window["IS_NATIVE_EDITOR"]) { // Select row (top border) t._lineHorPrevPx(ctx, x, y, x2); } }; let drawLeftBorder = function (_selected) { if ((style !== kHeaderDefault || t.getRightToLeft()) && isColHeader) { // Select col (left border) t._lineVerPrevPx(ctx, x, y, y2); } }; let checkSelectionFirstRowCol = function () { let ranges = t.model.selectionRange && t.model.selectionRange.ranges; if (!ranges) { return false; } let headerCell; if (isColHeader) { let firstRow = t.visibleRange.r1; headerCell = new Asc.Range(index, firstRow, index, firstRow); } else { let firstCol = t.visibleRange.c1; headerCell = new Asc.Range(firstCol, index, firstCol, index); } for (let i = 0, l = ranges.length; i < l; ++i) { if (ranges[i].containsRange(headerCell)) { return true; } } return false; }; let isFirstRowSelection = isColHeader && checkSelectionFirstRowCol(); let isFirstColSelection = !isColHeader && checkSelectionFirstRowCol(); let drawRightBorder = function (_selected) { if (isColHeader || !window["IS_NATIVE_EDITOR"]) { let y1Diff = 0; let y2Diff = 0; if (_selected) { y1Diff = (isFirstColSelection ? (_toRetina(1) + 1) : 1); y2Diff = (isFirstColSelection ? _toRetina(1) : 0); } t._lineVerPrevPx(ctx, x2, y - y1Diff, y2 + y2Diff); } }; let drawBottomBorder = function (_selected) { if (!isColHeader || !window["IS_NATIVE_EDITOR"]) { let x1Diff = 0; let x2Diff = 0; if (_selected) { x1Diff = (isFirstRowSelection ? (_toRetina(1) + 1) : (1 - t.getRightToLeftOffset())); x2Diff = (isFirstRowSelection ? _toRetina(1) : 0); } t._lineHorPrevPx(ctx, x - x1Diff, y2, x2 + x2Diff); } }; let needSelectTopBorder = false; let needSelectRightBorder = style !== kHeaderDefault && !isColHeader; let needSelectBottomBorder = style !== kHeaderDefault && isColHeader; let needSelectLeftBorder = false; let drawBorders = function (_selected) { needSelectTopBorder === _selected && drawTopBorder(_selected); needSelectRightBorder === _selected && drawRightBorder(_selected); needSelectBottomBorder === _selected && drawBottomBorder(_selected); needSelectLeftBorder === _selected && drawLeftBorder(_selected); }; // draw borders ctx.setStrokeStyle(borderColor) .setLineWidth(1) .beginPath(); drawBorders(false); ctx.stroke(); // draw borders (selected bottom/right) ctx.setStrokeStyle(this.settings.activeCellBorderColor) .setLineWidth(_toRetina(2)) .beginPath(); drawBorders(true); ctx.stroke(); // Для невидимых кроме border-а ничего не рисуем if (isZeroHeader || -1 === index) { return; } // draw text var text = isColHeader ? this._getColumnTitle(index) : this._getRowTitle(index); var sr = this.stringRender; var tm = this._roundTextMetrics(sr.measureString(text)); var bl = y2 - Asc.round((isColHeader ? this.defaultRowDescender : this._getRowDescender(index)) * this.getZoom()); var textX = this._calcTextHorizPos(x, x2WithoutBorder, tm, tm.width < w ? AscCommon.align_Center : AscCommon.align_Left); var textY = this._calcTextVertPos(y, h, bl, tm, Asc.c_oAscVAlign.Bottom); this._AddClipRect(ctx, x, y, w, h); ctx.setFillStyle(color); let charsWidth = 0; if (this.getRightToLeft()) { for (let i in sr.charWidths) { charsWidth += sr.charWidths[i]; } textX = textX + charsWidth; } this._fillText(ctx, text, textX, textY + Asc.round(tm.baseline * this.getZoom()), undefined, sr.charWidths); this._RemoveClipRect(ctx); }; WorksheetView.prototype.drawHeaderFooter = function (drawingCtx, printPagesData, indexPrintPage, countPrintPages) { //odd - нечетные страницы, even - четные. в случае если флаг differentOddEven не выставлен, используем odd if(!printPagesData) { return; } let trueRtl = this.getRightToLeft(); if (trueRtl) { this.setRightToLeft(false); } //new CHeaderFooter(); //при печати берём колонтитул либо из настроек печати(если есть), либо из модели var printPreview = this.workbook.printPreviewState; var pageOptionsMap = printPreview && printPreview.advancedOptions && printPreview.advancedOptions.pageOptionsMap; var opt_headerFooter = pageOptionsMap && pageOptionsMap[this.model.index] && pageOptionsMap[this.model.index].pageSetup && pageOptionsMap[this.model.index].pageSetup.getPreviewHeaderFooter(); if (!opt_headerFooter) { opt_headerFooter = this.workbook.getPrintHeaderFooterFromJson(this.model.index); } var headerFooterModel = opt_headerFooter ? opt_headerFooter : this.model.headerFooter; //HEADER var curHeader; if(indexPrintPage === 0 && headerFooterModel.differentFirst) { curHeader = headerFooterModel.getFirstHeader(); } else if(headerFooterModel.differentOddEven) { curHeader = 0 === (indexPrintPage + 1) % 2 ? headerFooterModel.getEvenHeader() : headerFooterModel.getOddHeader(); } else { curHeader = headerFooterModel.getOddHeader(); } if(curHeader) { if(!curHeader.parser) { curHeader.parser = new AscCommonExcel.HeaderFooterParser(); curHeader.parser.parse(curHeader.str); } curHeader.parser.calculateTokens(this, indexPrintPage, countPrintPages, true); //get current tokens -> curHeader.parser -> getTokensByPosition(AscCommomExcel.c_oPortionPosition) this._drawHeaderFooter(drawingCtx, printPagesData, curHeader, indexPrintPage, countPrintPages, false, opt_headerFooter); } //FOOTER var curFooter; if(indexPrintPage === 0 && headerFooterModel.differentFirst) { curFooter = headerFooterModel.getFirstFooter(); } else if(headerFooterModel.differentOddEven) { curFooter = 0 === (indexPrintPage + 1) % 2 ? headerFooterModel.getEvenFooter() : headerFooterModel.getOddFooter(); } else { curFooter = headerFooterModel.getOddFooter(); } if(curFooter) { if(!curFooter.parser) { curFooter.parser = new AscCommonExcel.HeaderFooterParser(); curFooter.parser.parse(curFooter.str); } curFooter.parser.calculateTokens(this, indexPrintPage, countPrintPages, true); //get current tokens -> curHeader.parser -> getTokensByPosition(AscCommomExcel.c_oPortionPosition) this._drawHeaderFooter(drawingCtx, printPagesData, curFooter, indexPrintPage, countPrintPages, true, opt_headerFooter); } if (trueRtl) { this.setRightToLeft(trueRtl); } }; /** Рисует текст ячейки */ WorksheetView.prototype._drawHeaderFooter = function (drawingCtx, printPagesData, headerFooterData, indexPrintPage, countPrintPages, bFooter, opt_headerFooter) { const t = this; const _printScale = printPagesData ? printPagesData.scale : this.getPrintScale(); const hF = opt_headerFooter ? opt_headerFooter : this.model.headerFooter; let scaleWithDoc = hF.getScaleWithDoc(); scaleWithDoc = scaleWithDoc === null || scaleWithDoc === true; let printScale = scaleWithDoc ? _printScale : 1; const headerFooterParser = headerFooterData && headerFooterData.parser; const margins = this.model.PagePrintOptions.asc_getPageMargins(); const width = printPagesData.pageWidth; const height = printPagesData.pageHeight; //это стандартный маргин для случая, если alignWithMargins = true //TODO необходимо перепроверить размер маргина const defaultMargin = 17.8; const alignWithMargins = hF.getAlignWithMargins(); const left = alignWithMargins ? margins.left : defaultMargin; const right = alignWithMargins ? margins.right : defaultMargin; const top = margins.header; const bottom = margins.footer; const footerStartPos = height - bottom; let drawPortion = function(index) { let portion = headerFooterParser.tokens[index]; if(!portion) { return; } const nAlign = window["AscCommonExcel"].CHeaderFooterEditorSection.prototype.getAlign.call(null, index); const aFragments = portion; const maxWidth = (width - left - right) / printScale; let dLIns = 0, dRIns = 0; const oShape = AscFormat.ExecuteNoHistory(function() { const oMockLogicDoc = { Get_PageLimits : function(PageAbs) { return {X: 0, Y: 0, XLimit: Page_Width, YLimit: Page_Height}; }, Get_PageFields : function (PageAbs, isInHdrFtr) { return {X: 0, Y: 0, XLimit: 2000, YLimit: 2000}; }, IsTrackRevisions: function() { return false; }, IsDocumentEditor: function() { return false; }, Spelling: { AddParagraphToCheck: function(Para) {} }, IsSplitPageBreakAndParaMark: function () { return false; }, IsDoNotExpandShiftReturn: function () { return false; }, GetApi: function() { return Asc.editor; }, GetDrawingDocument: function() { return Asc.editor.getDrawingDocument(); }, IsVisioEditor: function() { return false; }, SearchEngine: { Selection: [] } }; const oShape = new AscFormat.CShape(); oShape.setWorksheet(t.model); oShape.createTextBody(); let oBodyPr = oShape.txBody.bodyPr; oBodyPr.resetInsets(); oBodyPr.anchor = 4;//top let oContent = oShape.txBody.content; const oParagraph = oContent.GetAllParagraphs()[0]; oParagraph.LogicDocument = oMockLogicDoc; oParagraph.MoveCursorToStartPos(); oParagraph.Set_Align(nAlign); let isPrintPreview = t.workbook.printPreviewState.isStart(); let legacyDrawingId = AscCommonExcel.CHeaderFooterEditorSection.prototype.getStringName(index, headerFooterData.type); let legacyDrawingHF = t.model.legacyDrawingHF; let oDrawingTemp = isPrintPreview && opt_headerFooter && opt_headerFooter.legacyDrawingHF && opt_headerFooter.legacyDrawingHF.getDrawingById(legacyDrawingId); let oDrawing = oDrawingTemp ? oDrawingTemp : legacyDrawingHF && legacyDrawingHF.getDrawingById(legacyDrawingId); let oImage = oDrawing && oDrawing.obj && oDrawing.obj.graphicObject; for(let nFragment = 0; nFragment < aFragments.length; ++nFragment) { let oFragment = aFragments[nFragment]; let sText = oFragment._calculatedText; let oFormat = oFragment.format.clone(); oFormat.merge(AscCommonExcel.g_oDefaultFormat.Font); let oParaRun = new AscCommonWord.ParaRun(oParagraph); let oTextPr = new CTextPr(); oTextPr.FillFromExcelFont(oFormat); oParaRun.Set_Pr(oTextPr); if(oFragment.field === asc.c_oAscHeaderFooterField.picture) { if(oImage) { let dW = oImage.getXfrmExtX(); let dH = oImage.getXfrmExtY(); oImage.recalculate(); let oDrawing = new ParaDrawing(dW, dH, oImage, oShape.getDrawingDocument(), oContent, oParaRun); oDrawing.bCellHF = true; oImage.setParent(oDrawing); oParaRun.AddToContent(0, oDrawing, true); } } else if(sText) { oParaRun.AddText(sText); } oParagraph.AddToContent(nFragment, oParaRun); } let dIns = 1.6; let res = AscCommon.align_Left; if (nAlign === AscCommon.align_Left) { dLIns = 0; dRIns = 2*dIns; } else if (nAlign === AscCommon.align_Right) { dLIns = -2*dIns; } else if(nAlign === AscCommon.align_Center) { dLIns = -dIns; dRIns = dIns; } oShape.setTransformParams(-dLIns, 0, maxWidth + dLIns + dRIns, 2000, 0, false, false); oShape.setBDeleted(false); oShape.recalculate(); let x, y; x = left / printScale; y = (!bFooter ? top : footerStartPos - oShape.contentHeight) / printScale; oShape.posX += x ; oShape.posY += y; oShape.updateTransformMatrix(); if(oImage) { oImage.updateTransformMatrix(); } oShape.clipRect = null; return oShape; }, this, []); let oGraphics; if(drawingCtx instanceof AscCommonExcel.CPdfPrinter) { oGraphics = drawingCtx.DocumentRenderer; oGraphics.SaveGrState(); let oBaseTransform = new AscCommon.CMatrix(); oBaseTransform.Scale(printScale, printScale, AscCommon.MATRIX_ORDER_APPEND); oGraphics.SetBaseTransform(oBaseTransform); } else { oGraphics = new AscCommon.CGraphics(); oGraphics.init(drawingCtx.ctx, drawingCtx.getWidth(0), drawingCtx.getHeight(0), width / printScale, height / printScale); oGraphics.m_oFontManager = AscCommon.g_fontManager; } oGraphics.SaveGrState(); oGraphics.transform3(new AscCommon.CMatrix()); t._AddClipRect(oGraphics, left / printScale - dLIns / printScale, top / printScale, (width - (left + right)) / printScale + (dLIns + dRIns) / printScale, (height - (top + bottom)) / printScale); oShape.draw(oGraphics); oGraphics.RestoreGrState(); if (drawingCtx instanceof AscCommonExcel.CPdfPrinter) { oGraphics.SetBaseTransform(null); oGraphics.RestoreGrState(); } }; for(let nTokeIdx = 0; nTokeIdx < headerFooterParser.tokens.length; nTokeIdx++) { drawPortion(nTokeIdx); } }; WorksheetView.prototype._cleanColumnHeaders = function (colStart, colEnd) { var offsetX = this._getOffsetX(); var l, w, i, cFrozen = 0; if (this.topLeftFrozenCell) { cFrozen = this.topLeftFrozenCell.getCol0(); offsetX -= this._getColLeft(cFrozen) - this._getColLeft(0); } if (colEnd === undefined) { colEnd = colStart; } let t = this; let _toRetina = function (val) { return t.getRetinaPixelRatio() >= 2 ? AscCommon.AscBrowser.convertToRetinaValue(val, true) : val; }; //by clean down thin border let correctX = -1*(_toRetina(1) + 1); let correctY = 0; let correctW = _toRetina(2) + 1; let correctH = (t.getRetinaPixelRatio() >= 2 ? _toRetina(1) : 0); var colStartTmp = Math.max(this.visibleRange.c1, colStart); var colEndTmp = Math.min(this.visibleRange.c2, colEnd); l = this._getColLeft(colStartTmp) - offsetX; for (i = colStartTmp; i <= colEndTmp; ++i) { w = this._getColumnWidth(i); if (0 !== w) { this._clearRectByX(this.drawingCtx, l + correctX, this.headersTop + correctY, w + correctW, this.headersHeight + correctH); l += w; } } if (0 !== cFrozen) { offsetX = this._getOffsetX(0, true); // Почистим для pane colStart = Math.max(0, colStart); colEnd = Math.min(cFrozen, colEnd); l = this._getColLeft(colStart) - offsetX; for (i = colStart; i <= colEnd; ++i) { w = this._getColumnWidth(i); if (0 !== w) { this._clearRectByX(this.drawingCtx, l + correctX, this.headersTop + correctY, w + correctW, this.headersHeight + correctH); l += w; } } } }; WorksheetView.prototype._cleanRowHeaders = function (rowStart, rowEnd) { var offsetY = this._getOffsetY(); var t, h, i, rFrozen = 0; if (this.topLeftFrozenCell) { rFrozen = this.topLeftFrozenCell.getRow0(); offsetY -= this._getRowTop(rFrozen) - this._getRowTop(0); } if (rowEnd === undefined) { rowEnd = rowStart; } let oThis = this; let _toRetina = function (val) { return oThis.getRetinaPixelRatio() >= 2 ? AscCommon.AscBrowser.convertToRetinaValue(val, true) : val; }; //by clean down thin border let correctX = 0; let correctY = -1*(_toRetina(1) + 1); let correctW = (this.getRetinaPixelRatio() >= 2 ? _toRetina(1) : 0) + 2 * this.getRightToLeftOffset(); let correctH = _toRetina(2) + 1; var rowStartTmp = Math.max(this.visibleRange.r1, rowStart); var rowEndTmp = Math.min(this.visibleRange.r2, rowEnd); t = this._getRowTop(rowStartTmp) - offsetY; for (i = rowStartTmp; i <= rowEndTmp; ++i) { h = this._getRowHeight(i); if (0 !== h) { this._clearRectByY(this.drawingCtx, this.headersLeft + correctX, t + correctY, this.headersWidth + correctW, h + correctH); t += h; } } if (0 !== rFrozen) { offsetY = this._getOffsetY(0, true); // Почистим для pane rowStart = Math.max(0, rowStart); rowEnd = Math.min(rFrozen, rowEnd); t = this._getRowTop(rowStart) - offsetY; for (i = rowStart; i <= rowEnd; ++i) { h = this._getRowHeight(i); if (0 !== h) { this._clearRectByY(this.drawingCtx, this.headersLeft + correctX, t + correctY, this.headersWidth + correctW, h + correctH); t += h; } } } }; WorksheetView.prototype._cleanColumnHeadersRect = function () { this._clearRect(this.drawingCtx, this.cellsLeft, this.headersTop, this.drawingCtx.getWidth() - this.cellsLeft, this.headersHeight); }; /** Рисует сетку таблицы */ WorksheetView.prototype._drawGrid = function (drawingCtx, range, leftFieldInPx, topFieldInPx, width, height, printScale, needDrawFirstHLine, needDrawFirstVLine) { //отрисовку для режима предварительного просмотра страниц //добавлено сюда потому что отрисовка проиходит одновеременно с отрисовкой сетки //и отрисовка происходит в два этапа - сначала текст - до линий сетки, потом линии печати - после линий сетки //поэтому рассчет делаю 1 раз if (this.isPageBreakPreview() && !this.pagesModeData) { this.pagesModeData = this._getPagesModeData(range); } // Возможно сетку не нужно рисовать (при печати свои проверки) if (!drawingCtx && false === this.model.getSheetView().asc_getShowGridLines()) { return; } //needDrawFirstVLine, needDrawFirstHLine - добавляю два аргумета, в дальнейшем их убрать и при отрисовке на печать всегда рисовать первый бордер(за исключением когда заголовки применены) if (range === undefined) { range = this.visibleRange; } if (!printScale) { printScale = this.getPrintScale(); } let ctx = drawingCtx || this.drawingCtx; let widthCtx = (width) ? width / printScale : ctx.getWidth() / printScale; let heightCtx = (height) ? height / printScale : ctx.getHeight() / printScale; let offsetX = (undefined !== leftFieldInPx) ? leftFieldInPx : this._getOffsetX(); let offsetY = (undefined !== topFieldInPx) ? topFieldInPx : this._getOffsetY(); if (!drawingCtx && this.topLeftFrozenCell) { if (undefined === leftFieldInPx) { let cFrozen = this.topLeftFrozenCell.getCol0(); offsetX -= this._getColLeft(cFrozen) - this._getColLeft(0); } if (undefined === topFieldInPx) { let rFrozen = this.topLeftFrozenCell.getRow0(); offsetY -= this._getRowTop(rFrozen) - this._getRowTop(0); } } let isClip; if (!drawingCtx && !window['IS_NATIVE_EDITOR']) { if (this._clipDrawingRect(ctx, range, clipType.range)) { isClip = true; } } let x1 = this._getColLeft(range.c1) - offsetX; let y1 = this._getRowTop(range.r1) - offsetY; let x2 = Math.min(this._getColLeft(range.c2 + 1) - offsetX, widthCtx); let y2 = Math.min(this._getRowTop(range.r2 + 1) - offsetY, heightCtx); let isPrint = this.usePrintScale; if (!ctx.isNotDrawBackground && !isPrint) { ctx.setFillStyle(this.settings.cells.defaultState.background); this._fillRect(ctx, x1, y1, x2 - x1, y2 - y1); } //рисуем текст для преварительного просмотра //this._drawPageBreakPreviewText(drawingCtx, range, leftFieldInPx, topFieldInPx, width, height); ctx.setStrokeStyle(this.settings.cells.defaultState.border) .setLineWidth(1).beginPath(); let i, d, l; if (needDrawFirstVLine) { this._lineVerPrevPx(ctx, x1, y1, y2); } for (i = range.c1, d = x1; i <= range.c2 && d <= x2; ++i) { l = this._getColumnWidth(i); d += l; if (0 < l) { this._lineVerPrevPx(ctx, d, y1, y2); } } if (needDrawFirstHLine) { this._lineHorPrevPx(ctx, x1, y1, x2); } for (i = range.r1, d = y1; i <= range.r2 && d <= y2; ++i) { l = this._getRowHeight(i); d += l; if (0 < l) { this._lineHorPrevPx(ctx, x1, d, x2); } } ctx.stroke(); // Clear grid for pivot tables with classic and outline layout let clearRange, pivotRange, clearRanges = this.model.getPivotTablesClearRanges(range); ctx.setFillStyle(this.settings.cells.defaultState.background); for (i = 0; i < clearRanges.length; i += 2) { clearRange = clearRanges[i]; pivotRange = clearRanges[i + 1]; x1 = this._getColLeft(clearRange.c1) - offsetX + (clearRange.c1 === pivotRange.c1 ? 1 : 0); y1 = this._getRowTop(clearRange.r1) - offsetY + (clearRange.r1 === pivotRange.r1 ? 1 : 0); x2 = Math.min(this._getColLeft(clearRange.c2 + 1) - offsetX - (clearRange.c2 === pivotRange.c2 ? 1 : 0), widthCtx); y2 = Math.min(this._getRowTop(clearRange.r2 + 1) - offsetY - (clearRange.r2 === pivotRange.r2 ? 1 : 0), heightCtx); this._fillRect(ctx, x1, y1, x2 - x1, y2 - y1); } if (!drawingCtx && !window['IS_NATIVE_EDITOR'] && isClip) { this._RemoveClipRect(ctx); } //this._drawPageBreakPreviewLines(drawingCtx, range, leftFieldInPx, topFieldInPx, width, height); }; let clipType = { groupRows: 0, groupCols: 1, groupAll: 2, headersRows: 3, headersCols: 4, headersAll: 5, range: 6 }; WorksheetView.prototype._clipDrawingRect = function (drawingCtx, range, type) { let ctxW = drawingCtx.getWidth(); let ctxH = drawingCtx.getHeight(); if (range === undefined) { range = this.visibleRange; } if (type === undefined) { type = clipType.range; } let frozenOffsetX = 0; let frozenOffsetY = 0; let isFrozenRows = null; let isFrozenCols = null; if (this.topLeftFrozenCell) { //if (undefined === offsetXForDraw) { let cFrozen = this.topLeftFrozenCell.getCol0(); if (range.c1 < cFrozen) { isFrozenCols = true; } frozenOffsetX = this._getColLeft(cFrozen) - this.cellsLeft; //} //if (undefined === offsetYForDraw) { let rFrozen = this.topLeftFrozenCell.getRow0(); frozenOffsetY = this._getRowTop(rFrozen) - this.cellsTop; if (range.r1 < rFrozen) { isFrozenRows = true; } //} } let _case = 0; let clipX, clipY, clipWidth, clipHeight; switch (type) { case clipType.groupRows: if (!this.groupWidth) { return false; } //clip rows group bar clipX = this.headersLeft - this.groupWidth; clipY = (!isFrozenRows && frozenOffsetY) ? (this.cellsTop + frozenOffsetY) : this.cellsTop; clipWidth = this.groupWidth; clipHeight = ctxH; _case = -1; break; case clipType.groupCols: if (!this.groupHeight) { return false; } //clip cols group bar clipX = (!isFrozenCols && frozenOffsetX) ? (this.cellsLeft + frozenOffsetX) : this.cellsLeft; clipY = this.headersTop - this.groupHeight; clipWidth = ctxW; clipHeight = this.groupHeight; _case = -2; break; case clipType.groupAll: if (!this.groupHeight) { return false; } //clip all include groups bar clipX = this.headersLeft - this.groupWidth; clipY = this.headersTop - this.groupHeight; clipWidth = ctxW; clipHeight = ctxH; _case = -3; break; case clipType.headersRows: if (!this.model.getSheetView().asc_getShowRowColHeaders()) { return false; } clipX = this.headersLeft; clipY = isFrozenRows ? (this.cellsTop + frozenOffsetY) : this.cellsTop; clipWidth = this.headersWidth; clipHeight = ctxH; _case = -4; break; case clipType.headersCols: if (!this.model.getSheetView().asc_getShowRowColHeaders()) { return false; } clipX = isFrozenCols ? (this.cellsLeft + frozenOffsetX) : this.cellsLeft; clipY = this.headersTop; clipWidth = ctxW; clipHeight = this.headersHeight; _case = -5; break; case clipType.headersAll: if (!this.model.getSheetView().asc_getShowRowColHeaders()) { return false; } clipX = this.headersLeft; clipY = this.headersTop; clipWidth = ctxW; clipHeight = ctxH; _case = -6; break; case clipType.range: let x1 = this._getColLeft(range.c1); let x2 = this._getColLeft(range.c2 + 1); let y1 = this._getRowTop(range.r1); let y2 = this._getRowTop(range.r2 + 1); let width = x2 - x1; let height = y2 - y1; let offsetX = this._getOffsetX(); let offsetY = this._getOffsetY(); let t = this; let doSimpleClip = function () { let heightOffset = 0; if (y1 - offsetY < t.cellsTop) { heightOffset = t.cellsTop - (y1 - offsetY); } let widthOffset = 0; if (x1 - offsetX < t.cellsLeft) { widthOffset = t.cellsLeft - (x1 - offsetX); } clipX = x1 - offsetX + widthOffset + t.getRightToLeftOffset(); clipY = y1 - offsetY + heightOffset; clipWidth = width - widthOffset; clipHeight = height - heightOffset; }; if (!frozenOffsetX && !frozenOffsetY) { //not frozen panes doSimpleClip(); _case = 1; } else if (frozenOffsetX && !frozenOffsetY) { //only cols frozen let heightOffset = 0; if (y1 - offsetY < this.cellsTop) { heightOffset = this.cellsTop - (y1 - offsetY); } if (!isFrozenCols) { //outside frozen area let screenX = x1 - offsetX + frozenOffsetX; let widthOffset = 0; if (screenX < frozenOffsetX + this.cellsLeft) { widthOffset = (frozenOffsetX + this.cellsLeft) - screenX; } clipX = screenX + widthOffset; clipY = y1 - offsetY + heightOffset; clipWidth = width - widthOffset; clipHeight = height - heightOffset; _case = 2; } else { //inside frozen area clipX = x1; clipY = y1 - offsetY + heightOffset; clipWidth = width; clipHeight = height - heightOffset; _case = 3; } } else if (!frozenOffsetX && frozenOffsetY) { //only rows frozen let widthOffset = 0; if (x1 - offsetX < this.cellsLeft) { widthOffset = this.cellsLeft - (x1 - offsetX); } if (!isFrozenRows) { //outside frozen area let screenY = y1 - offsetY + frozenOffsetY; let heightOffset = 0; if (screenY < frozenOffsetY + this.cellsTop) { heightOffset = (frozenOffsetY + this.cellsTop) - screenY; } clipX = x1 - offsetX + widthOffset; clipY = screenY + heightOffset; clipWidth = width - widthOffset; clipHeight = height - heightOffset; _case = 4 } else { //inside frozen area clipX = x1 - offsetX + widthOffset; clipY = y1; clipWidth = width - widthOffset; clipHeight = height; _case = 5; } } else if (frozenOffsetX && frozenOffsetY) { if (!isFrozenRows && !isFrozenCols) { let screenX = x1 - offsetX + frozenOffsetX; let widthOffset = 0; if (screenX < frozenOffsetX + this.cellsLeft) { widthOffset = (frozenOffsetX + this.cellsLeft) - screenX; } let screenY = y1 - offsetY + frozenOffsetY; let heightOffset = 0; if (screenY < frozenOffsetY + this.cellsTop) { heightOffset = (frozenOffsetY + this.cellsTop) - screenY; } clipX = screenX + widthOffset; clipY = screenY + heightOffset; clipWidth = width - widthOffset; clipHeight = height - heightOffset; _case = 6 } else if (isFrozenRows && !isFrozenCols) { let screenX = x1 - offsetX + frozenOffsetX; let widthOffset = 0; if (screenX < frozenOffsetX + this.cellsLeft) { widthOffset = (frozenOffsetX + this.cellsLeft) - screenX; } let screenY = y1 - offsetY + frozenOffsetY; let heightOffset = 0; if (screenY < frozenOffsetY + this.cellsTop) { heightOffset = (frozenOffsetY + this.cellsTop) - screenY; } clipX = screenX + widthOffset; clipY = y1; clipWidth = width - widthOffset; clipHeight = height; _case = 7; } else if (!isFrozenRows && isFrozenCols) { let screenX = x1 - offsetX + frozenOffsetX; let widthOffset = 0; if (screenX < frozenOffsetX + this.cellsLeft) { widthOffset = (frozenOffsetX + this.cellsLeft) - screenX; } let screenY = y1 - offsetY + frozenOffsetY; let heightOffset = 0; if (screenY < frozenOffsetY + this.cellsTop) { heightOffset = (frozenOffsetY + this.cellsTop) - screenY; } clipX = x1; clipY = screenY + heightOffset; clipWidth = width; clipHeight = height - heightOffset; _case = 8; } else if (isFrozenRows && isFrozenCols) { clipX = x1; clipY = y1; clipWidth = width; clipHeight = height; _case = 9; } } break; } this._AddClipRect(drawingCtx, clipX, clipY, clipWidth, clipHeight); //for test //console.log(" range: " + range.getName() + " clipX: " + clipX + " clipY: " + clipY + " clipWidth: " + clipWidth + " clipHeight: " + clipHeight + " caset: " + caset) //drawingCtx.setLineWidth(3).setStrokeStyle(AscCommonExcel.c_oAscCoAuthoringOtherBorderColor).strokeRect(clipX + 1, clipY + 1, clipWidth - 1, clipHeight - 1); return true; }; WorksheetView.prototype._drawCellsAndBorders = function (drawingCtx, range, offsetXForDraw, offsetYForDraw) { if (range === undefined) { range = this.visibleRange; } let left, top, cFrozen, rFrozen; let offsetX = (undefined === offsetXForDraw) ? this._getOffsetX() : offsetXForDraw; let offsetY = (undefined === offsetYForDraw) ? this._getOffsetY() : offsetYForDraw; if (!drawingCtx && this.topLeftFrozenCell) { if (undefined === offsetXForDraw) { cFrozen = this.topLeftFrozenCell.getCol0(); offsetX -= this._getColLeft(cFrozen) - this.cellsLeft; } if (undefined === offsetYForDraw) { rFrozen = this.topLeftFrozenCell.getRow0(); offsetY -= this._getRowTop(rFrozen) - this.cellsTop; } } let isClip = null; if (!drawingCtx && !window['IS_NATIVE_EDITOR']) { if (this._clipDrawingRect(this.drawingCtx, range, clipType.range)) { isClip = true; } } this._prepareCellTextMetricsCache(range); let cfIterator = this.model.getConditionalFormattingRangeIterator(); let renderingSettings = this.getRenderingSettings(); let mergedCells = {}, mc; for (let row = range.r1; row <= range.r2; ++row) { if (renderingSettings && renderingSettings.isSkipRowBG(range.r1, row)) { continue; } this._drawRowBG(drawingCtx, row, range.c1, range.c2, offsetX, offsetY, mergedCells, null, cfIterator); } // draw merged cells at last stage to fix cells background issue for (let i in mergedCells) { mc = mergedCells[i]; this._drawRowBG(drawingCtx, mc.r1, mc.c1, mc.c1, offsetX, offsetY, null, mc, cfIterator); } this._drawSparklines(drawingCtx, range, offsetX, offsetY); //this text draw in excel: after cell bg, sparklines // but before cells borders, cells text, grid //TODO need change all rendering sequence this._drawPageBreakPreviewText(drawingCtx, range, offsetXForDraw, offsetYForDraw); this._drawCellsBorders(drawingCtx, range, offsetX, offsetY, mergedCells); //draw after other //this._drawPageBreakPreviewLines(drawingCtx, range, offsetXForDraw, offsetYForDraw); let isPrint = this.usePrintScale; if (isPrint) { this.drawTraceArrows(range, offsetX, offsetY, [drawingCtx]); } if (isClip) { // restore canvas' original clipping range this.drawingCtx.restore(); } }; /** Рисует спарклайны */ WorksheetView.prototype._drawSparklines = function(drawingCtx, range, offsetX, offsetY) { this.objectRender.drawSparkLineGroups(drawingCtx || this.drawingCtx, this.model.aSparklineGroups, range, offsetX * asc_getcvt(0, 3, this._getPPIX()), offsetY * asc_getcvt(0, 3, this._getPPIX())); }; /** Рисует фон ячеек в строке */ WorksheetView.prototype._drawRowBG = function (drawingCtx, row, colStart, colEnd, offsetX, offsetY, mergedCells, mc, cfIterator) { var height = this._getRowHeight(row); if (0 === height && mergedCells) { return; } var drawCells = {}, i; var top = this._getRowTop(row); var ctx = drawingCtx || this.drawingCtx; var graphics = drawingCtx ? ctx.DocumentRenderer : this.handlers.trigger('getMainGraphics'); for (var col = colStart; col <= colEnd; ++col) { var width = this._getColumnWidth(col); if (0 === width && mergedCells) { continue; } // ToDo подумать, может стоит не брать ячейку из модели (а брать из кеш-а) var c = this._getVisibleCell(col, row); //***searchEngine var findFillColor = this.handlers.trigger('selectSearchingResults') && undefined !== this.workbook.inFindResults(this, row, col)/*this.model.inFindResults(row, col)*/ ? this.settings.findFillColor : null; var fill = c.getFill(); var hasFill = fill.hasFill(); var mwidth = 0, mheight = 0; if (mergedCells) { mc = this.model.getMergedByCell(row, col); if (mc) { mergedCells[AscCommonExcel.getCellIndex(mc.r1, mc.c1)] = mc; col = mc.c2; continue; } } if (mc) { if (col !== mc.c1 || row !== mc.r1) { continue; } mwidth = this._getColLeft(mc.c2 + 1) - this._getColLeft(mc.c1 + 1); mheight = this._getRowTop(mc.r2 + 1) - this._getRowTop(mc.r1 + 1); } //without merged -> merged after, because part of merged can if (this.isPageBreakPreview(true) && !mc && this.pagesModeDataContains(col, row) === false) { findFillColor = this.settings.cells.defaultState.border; } if (findFillColor || hasFill || mc) { // ToDo не отрисовываем заливку границ от ячеек c заливкой, которые находятся правее и ниже // отрисовываемого диапазона. Но по факту проблем быть не должно. var fillGrid = findFillColor || hasFill; findFillColor = findFillColor || (!hasFill && mc && this.settings.cells.defaultState.background); var x = this._getColLeft(col) - (fillGrid ? 1 : 0) + this.getRightToLeftOffset(); var y = top - (fillGrid ? 1 : 0); var w = width + (fillGrid ? +1 : -1) + mwidth; var h = height + (fillGrid ? +1 : -1) + mheight; if (findFillColor) { fill = new AscCommonExcel.Fill(); fill.fromColor(findFillColor); } AscCommonExcel.drawFillCell(ctx, graphics, fill, new AscCommon.asc_CRect((this.getRightToLeft() ? (this.getCtxWidth(ctx) - x - w + offsetX) : x - offsetX), y - offsetY, w, h)); } if (this.isPageBreakPreview(true) && mc) { for (let r = mc.r1; r <= mc.r2; r++) { for (let n = mc.c1; n <= mc.c2; n++) { if (this.pagesModeDataContains(n, r) === false) { var _height = this._getRowHeight(r); var _top = this._getRowTop(r); var _width = this._getColumnWidth(n); var _x = this._getColLeft(n) - 1; var _y = _top - 1; var _w = _width + 1; var _h = _height + 1; let _fill = new AscCommonExcel.Fill(); _fill.fromColor(this.settings.cells.defaultState.border); AscCommonExcel.drawFillCell(ctx, graphics, _fill, new AscCommon.asc_CRect((this.getRightToLeft() ? (this.getCtxWidth(ctx) - _x - w + offsetX) : _x - offsetX), _y - offsetY, _w, _h)); } } } } var showValue = this._drawCellCF(ctx, cfIterator, c, row, col, top, width + mwidth, height + mheight, offsetX, offsetY); if (showValue) { drawCells[col] = 1; } } // Check overlap start i = this._findOverlapCell(colStart, row); if (-1 !== i) { drawCells[i] = 1; } // Check overlap end if (colStart !== colEnd) { i = this._findOverlapCell(colEnd, row); if (-1 !== i) { drawCells[i] = 1; } } // draw text for (i in drawCells) { this._drawCellText(drawingCtx, cfIterator, i >> 0, row, colStart, colEnd, offsetX, offsetY); } }; WorksheetView.prototype._getCellCF = function (cfIterator, c, row, col, type) { var ct = this._getCellTextCache(col, row); if (!ct || !ct.flags.isNumberFormat || 0 === cfIterator.getSize()) { return null; } var cellValue = c.getNumberValue(); if (null === cellValue) { return null; } var oRule, oRuleElement, ranges, values; var aRules = cfIterator.get(row, col); //todo sort inside RangeTopBottomIterator ? aRules.sort(function(v1, v2) { return v2.priority - v1.priority; }); for (var i = aRules.length - 1; i >= 0; --i) { oRule = aRules[i]; ranges = oRule.ranges; oRuleElement = oRule.asc_getColorScaleOrDataBarOrIconSetRule(); if (!oRuleElement || Asc.ECfType.colorScale === oRuleElement.type) { continue; } if (type !== oRule.type) { continue; } if (Asc.ECfType.iconSet === oRule.type) { if (ct.angle && oRuleElement.ShowValue) { continue; } values = this.model._getValuesForConditionalFormatting(ranges, true); var img = AscCommonExcel.getCFIcon(oRuleElement, oRule.getIndexRule(values, this.model, cellValue)); if (!img) { continue; } } return oRule; } return null; }; WorksheetView.prototype._drawCellCFDataBar = function (ctx, graphics, oRule, cellValue, x, top, width, height) { var tmp; var oRuleElement = oRule.asc_getColorScaleOrDataBarOrIconSetRule(); var values = this.model._getValuesForConditionalFormatting(oRule.ranges, true); var min = oRule.getMin(values, this.model); var max = oRule.getMax(values, this.model); var isPositive = 0 <= cellValue; var isReverse = AscCommonExcel.EDataBarDirection.rightToLeft === oRuleElement.Direction; var isMiddle = (AscCommonExcel.EDataBarAxisPosition.middle === oRuleElement.AxisPosition) || (AscCommonExcel.EDataBarAxisPosition.automatic === oRuleElement.AxisPosition && 0 > min && 0 < max); var automaticAxisPos = AscCommonExcel.EDataBarAxisPosition.automatic === oRuleElement.AxisPosition && 0 > min && 0 < max; var trueMin = min; var trueMax = max; if (isMiddle) { if (isPositive) { min = Math.max(0, min); } else { max = Math.min(0, max); } } if (0 >= max) { tmp = -max; max = -min; min = tmp; cellValue = -cellValue; isReverse = !isReverse; } if (cellValue < min) { cellValue = min; } else if (cellValue > max) { cellValue = max; } var axisLineWidth = oRuleElement.AxisColor ? 1 : 0; var minLength = Math.floor(width * oRuleElement.MinLength / 100); var maxLength = Math.floor(width * oRuleElement.MaxLength / 100); var k = automaticAxisPos ? (trueMax - trueMin) : (max - min); var middleX = ((maxLength - minLength) / k) * (AscCommonExcel.EDataBarDirection.rightToLeft === oRuleElement.Direction ? Math.abs(trueMax) : Math.abs(trueMin)); k = k ? ((maxLength - minLength) / k) : 0; var dataBarLength = automaticAxisPos ? (minLength + (Math.abs(cellValue) * k)) : (minLength + (cellValue - min) * k); color = (isPositive || oRuleElement.NegativeBarColorSameAsPositive) ? oRuleElement.Color : oRuleElement.NegativeColor; if (0 !== dataBarLength && color) { if (isMiddle) { if (oRuleElement.AxisColor) { ctx.setLineWidth(1).setLineDash([3, 1]).setStrokeStyle(oRuleElement.AxisColor); if (automaticAxisPos) { ctx.beginPath(); this._lineVer(ctx, x + middleX, top - 1, top - 1 + height - 1).stroke(); } else { ctx.beginPath(); this._lineVer(ctx, x + Asc.floor(width / 2), top - 1, top - 1 + height - 1).stroke(); } } if (!automaticAxisPos) { dataBarLength = Asc.floor(dataBarLength / 2); x += (Asc.floor(width / 2) + axisLineWidth) * (isReverse ? -1 : 1); } else { if (AscCommonExcel.EDataBarDirection.rightToLeft === oRuleElement.Direction) { if (isPositive) { x -= width - middleX; } else { x += middleX + axisLineWidth; } } else { if (isPositive) { x += middleX + axisLineWidth; } else { x -= width - middleX; } } } } if (isReverse) { x += width - dataBarLength; } var fill = new AscCommonExcel.Fill(); if (oRuleElement.Gradient) { var endColor = AscCommonExcel.getDataBarGradientColor(color); if (isReverse) { tmp = color; color = endColor; endColor = tmp; } fill.gradientFill = new AscCommonExcel.GradientFill(); var stop0 = new AscCommonExcel.GradientStop(); stop0.position = 0; stop0.color = color; var stop1 = new AscCommonExcel.GradientStop(); stop1.position = 1; stop1.color = endColor; fill.gradientFill.asc_putGradientStops([stop0, stop1]); } else { fill.fromColor(color); } AscCommonExcel.drawFillCell(ctx, graphics, fill, new AscCommon.asc_CRect((this.getRightToLeft() ? (this.getCtxWidth(ctx) - x - dataBarLength) : x), top, dataBarLength, height - 3)); var color = (isPositive || oRuleElement.NegativeBarBorderColorSameAsPositive) ? oRuleElement.BorderColor : oRuleElement.NegativeBorderColor; if (color) { ctx.setLineWidth(1).setLineDash([]).setStrokeStyle(color); this._strokeRect(ctx, x, top, dataBarLength - 1, height - 4); } } }; WorksheetView.prototype._drawCellCFIconSet = function (ctx, graphics, oRule, cellValue, fontSize, align, row, x, top, width, height) { var oRuleElement = oRule.asc_getColorScaleOrDataBarOrIconSetRule(); var values = this.model._getValuesForConditionalFormatting(oRule.ranges, true); var img = AscCommonExcel.getCFIcon(oRuleElement, oRule.getIndexRule(values, this.model, cellValue)); if (!img) { return; } var iconSize = AscCommon.AscBrowser.convertToRetinaValue(getCFIconSize(fontSize), true); var rect = new AscCommon.asc_CRect(x, top, width, height); var bl = rect._y + rect._height - Asc.round(this._getRowDescender(row) * this.getZoom()); var tm = new Asc.TextMetrics(iconSize, iconSize, 0, iconSize - 2 * fontSize / AscCommonExcel.cDefIconFont, 0, 0, 0); var cellHA = align.getAlignHorizontal(); if (oRuleElement.ShowValue || (AscCommon.align_Left !== cellHA && AscCommon.align_Right !== cellHA && AscCommon.align_Center !== cellHA)) { cellHA = AscCommon.align_Left; } if (this.getRightToLeft()) { rect._x = this.getCtxWidth(ctx) - rect._x - rect._width; } rect._x = this._calcTextHorizPos(rect._x, rect._x + rect._width, tm, cellHA, true); rect._y = this._calcTextVertPos(rect._y, rect._height, bl, tm, align.getAlignVertical()); var dScale = asc_getcvt(0, 3, this._getPPIX()); rect._x *= dScale; rect._y *= dScale; rect._width *= dScale; rect._height *= dScale; AscFormat.ExecuteNoHistory( function (img, rect, imgSize) { var geometry = new AscFormat.CreateGeometry("rect"); geometry.Recalculate(imgSize, imgSize, true); if (ctx instanceof AscCommonExcel.CPdfPrinter) { graphics.SaveGrState(); var _baseTransform; if (!ctx.Transform) { _baseTransform = new AscCommon.CMatrix(); } else { _baseTransform = ctx.Transform; } graphics.SetBaseTransform(_baseTransform); } var oUniFill = new AscFormat.builder_CreateBlipFill(img, "stretch"); graphics.SaveGrState(); var oMatrix = new AscCommon.CMatrix(); oMatrix.tx = rect._x; oMatrix.ty = rect._y; graphics.transform3(oMatrix); var shapeDrawer = new AscCommon.CShapeDrawer(); shapeDrawer.Graphics = graphics; shapeDrawer.fromShape2(new AscFormat.CColorObj(null, oUniFill, geometry), graphics, geometry); shapeDrawer.draw(geometry); graphics.RestoreGrState(); if (ctx instanceof AscCommonExcel.CPdfPrinter) { graphics.SetBaseTransform(null); graphics.RestoreGrState(); } }, this, [img, rect, iconSize * dScale * this.getZoom()] ); }; WorksheetView.prototype._drawCellCF = function (ctx, cfIterator, c, row, col, top, width, height, offsetX, offsetY) { var oDataBarRule = this._getCellCF(cfIterator, c, row, col, Asc.ECfType.dataBar); var oIconSetRule = this._getCellCF(cfIterator, c, row, col, Asc.ECfType.iconSet); if (!oDataBarRule && !oIconSetRule) { return true; } var x = this._getColLeft(col) - offsetX + 1 + 2*this.getRightToLeftOffset(); width -= 3; // indent top += 1 - offsetY; var graphics = (ctx && ctx.DocumentRenderer) || this.handlers.trigger('getMainGraphics'); var cellValue = c.getNumberValue(); if (oDataBarRule) { this._drawCellCFDataBar(ctx, graphics, oDataBarRule, cellValue, x, top, width, height); } if (oIconSetRule) { this._drawCellCFIconSet(ctx, graphics, oIconSetRule, cellValue, c.getFont().getSize(), c.getAlign(), row, x, top, width, height); } var res; if (oDataBarRule && oIconSetRule) { res = oDataBarRule.priority < oIconSetRule.priority ? oDataBarRule : oIconSetRule; } else { res = oDataBarRule || oIconSetRule; } var oRuleElement = res.asc_getColorScaleOrDataBarOrIconSetRule(); return oRuleElement.ShowValue; }; /** Рисует текст ячейки */ WorksheetView.prototype._drawCellText = function (drawingCtx, cfIterator, col, row, colStart, colEnd, offsetX, offsetY) { var ct = this._getCellTextCache(col, row); if (!ct) { return null; } /*if (this.getRightToLeft()) { offsetX = -offsetX; }*/ var c = this._getVisibleCell(col, row); if (false === this.model.getSheetView().asc_getShowZeros() && c.getValue() === "0") { return; } var font = c.getFont(); var color = font.getColor(); var isMerged = ct.flags.isMerged(), range, isWrapped = ct.flags.wrapText; var ctx = drawingCtx || this.drawingCtx; if (isMerged) { range = ct.flags.merged; if (col !== range.c1 || row !== range.r1) { return null; } } var colL = isMerged ? range.c1 : Math.max(colStart, col - ct.sideL); var colR = isMerged ? Math.min(range.c2, this.nColsCount - 1) : Math.min(colEnd, col + ct.sideR); var rowT = isMerged ? range.r1 : row; var rowB = isMerged ? Math.min(range.r2, this.nRowsCount - 1) : row; var isTrimmedR = !isMerged && colR !== col + ct.sideR; if (!ct.angle) { if (!isMerged && !isWrapped) { this._eraseCellRightBorder(drawingCtx, colL, colR + (isTrimmedR ? 1 : 0), row, offsetX, offsetY); } } var x1 = this._getColLeft(colL) - offsetX; var y1 = this._getRowTop(rowT) - offsetY; var w = this._getColLeft(colR + 1) - offsetX - x1; var h = this._getRowTop(rowB + 1) - offsetY - y1; var x2 = x1 + w - (isTrimmedR ? 0 : gridlineSize); var y2 = y1 + h; var bl = y2 - Asc.round( (isMerged ? (ct.metrics.height - ct.metrics.baseline) : this._getRowDescender(rowB)) * this.getZoom()); /*if (this.getRightToLeft()) { let temp = x1; x1 = x2; x2 = temp; w = -w; }*/ var x1ct = isMerged ? x1 : this._getColLeft(col, false, ctx) - offsetX; var x2ct = isMerged ? x2 : x1ct + this._getColumnWidth(col) - gridlineSize; var textX = this._calcTextHorizPos(x1ct, x2ct, ct.metrics, ct.cellHA); var textY = this._calcTextVertPos(y1, h, bl, ct.metrics, ct.cellVA); var textW = this._calcTextWidth(x1ct, x2ct, ct.metrics, ct.cellHA); var xb1, yb1, wb, hb, colLeft, colRight; var txtRotX, txtRotW, clipUse = false; var _printScale = this.getPrintScale(); var isPrintPreview = this.workbook.printPreviewState.isStart(); if (ct.angle) { xb1 = this._getColLeft(col, false, ctx) - offsetX; yb1 = this._getRowTop(row) - offsetY; wb = this._getColumnWidth(col); hb = this._getRowHeight(row); xb1 = this.checkRtl(xb1); if (!isMerged && this.getRightToLeft()) { xb1 -= wb; } txtRotX = xb1 - ct.textBound.offsetX; txtRotW = ct.textBound.width + xb1 - ct.textBound.offsetX; if (isMerged) { wb = this._getColLeft(colR + 1, false, ctx) - this._getColLeft(colL, false, ctx); if (this.getRightToLeft()) { xb1 -= wb; } hb = this._getRowTop(rowB + 1) - this._getRowTop(rowT); this._AddClipRect(ctx, xb1, yb1, wb, hb, true); clipUse = true; } this.stringRender.angle = ct.angle; this.stringRender.fontNeedUpdate = true; if (90 === ct.angle || -90 === ct.angle) { // клип по ячейке if (!isMerged) { this._AddClipRect(ctx, xb1, yb1, wb, hb, true); clipUse = true; } } else { // клип по строке if (!isMerged) { this._AddClipRect(ctx, 0, y1, this.drawingCtx.getWidth(), h); clipUse = true; } if (!isMerged && !isWrapped) { colLeft = col; if (0 !== txtRotX) { while (true) { if (0 == colLeft) { break; } if (txtRotX >= this._getColLeft(colLeft, true, ctx)) { break; } --colLeft; } } colRight = Math.min(col, this.nColsCount - 1); if (0 !== txtRotW) { while (true) { ++colRight; if (colRight >= this.nColsCount) { --colRight; break; } if (txtRotW <= this._getColLeft(colRight, true, ctx)) { --colRight; break; } } } colLeft = isMerged ? range.c1 : colLeft; colRight = isMerged ? Math.min(range.c2, this.nColsCount - 1) : colRight; this._eraseCellRightBorder(drawingCtx, colLeft, colRight + (isTrimmedR ? 1 : 0), row, offsetX, offsetY); } } //если ранее выставлена матрица трансформации, например, в случае когда задан масштаб печати //необходимо перемножить на новую матрицу, а в конце вернуть начальную var transformMatrix; if (_printScale !== 1 && drawingCtx && drawingCtx.Transform) { transformMatrix = drawingCtx.Transform.CreateDublicate(); } var realCtx; if (isPrintPreview) { realCtx = this.stringRender.drawingCtx; this.stringRender.drawingCtx = drawingCtx; } this.stringRender.rotateAtPoint(isPrintPreview ? null : drawingCtx, ct.angle, xb1, yb1, ct.textBound.dx, ct.textBound.dy); if (transformMatrix) { var tempMatrix = drawingCtx.Transform.CreateDublicate(); var resMatrix = tempMatrix.Multiply(transformMatrix); drawingCtx.setTransform(resMatrix.sx, resMatrix.shy, resMatrix.shx, resMatrix.sy, resMatrix.tx, resMatrix.ty); } this.stringRender.restoreInternalState(ct.state); if (isWrapped) { if (ct.angle < 0) { if (Asc.c_oAscVAlign.Top === ct.cellVA) { this.stringRender.flags.textAlign = AscCommon.align_Left; } else if (Asc.c_oAscVAlign.Center === ct.cellVA || Asc.c_oAscVAlign.Dist === ct.cellVA || Asc.c_oAscVAlign.Just === ct.cellVA) { this.stringRender.flags.textAlign = AscCommon.align_Center; } else if (Asc.c_oAscVAlign.Bottom === ct.cellVA) { this.stringRender.flags.textAlign = AscCommon.align_Right; } } else { if (Asc.c_oAscVAlign.Top === ct.cellVA) { this.stringRender.flags.textAlign = AscCommon.align_Right; } else if (Asc.c_oAscVAlign.Center === ct.cellVA || Asc.c_oAscVAlign.Dist === ct.cellVA || Asc.c_oAscVAlign.Just === ct.cellVA) { this.stringRender.flags.textAlign = AscCommon.align_Center; } else if (Asc.c_oAscVAlign.Bottom === ct.cellVA) { this.stringRender.flags.textAlign = AscCommon.align_Left; } } } this._drawText(this.stringRender, drawingCtx, 0, 0, textW, color, true); this.stringRender.resetTransform(isPrintPreview ? null : drawingCtx); if (transformMatrix) { drawingCtx.setTransform(transformMatrix.sx, transformMatrix.shy, transformMatrix.shx, transformMatrix.sy, transformMatrix.tx, transformMatrix.ty); } if (isPrintPreview) { this.stringRender.drawingCtx = realCtx; } if (clipUse) { this._RemoveClipRect(ctx); } } else { this._AddClipRect(ctx, x1, y1, w, h); if (this._getCellCF(cfIterator, c, row, col, Asc.ECfType.iconSet) /*&& AscCommon.align_Left === ct.cellHA*/) { var iconSize = AscCommon.AscBrowser.convertToRetinaValue(getCFIconSize(font.getSize()) * this.getZoom(), true); //TODO оставляю отступ 0, пересмотреть! var indentIcon = 0; if (AscCommon.align_Left === ct.cellHA) { textX += iconSize; } else if ((iconSize + textW + indentIcon) > w) { textX += iconSize; } } var pivotButtons = this.model.getPivotTableButtons(new Asc.Range(col, row, col, row)); if (pivotButtons && pivotButtons[0] && pivotButtons[0].idPivotCollapse && AscCommon.align_Left === ct.cellHA) { //TODO 4? var _diff = 4; textX += (this._getFilterButtonSize(true) + _diff) * this.getZoom(); } if (ct.indent) { let rtlKf = this.getRightToLeft() ? -1 : 1; var verticalText = ct.angle === AscCommonExcel.g_nVerticalTextAngle || (ct.flags && ct.flags.verticalText); var _defaultSpaceWidth = this.workbook.printPreviewState && this.workbook.printPreviewState.isStart() ? this.defaultSpaceWidth * this.getZoom(true) : this.defaultSpaceWidth; if (verticalText) { if (Asc.c_oAscVAlign.Bottom === ct.cellVA) { //textY -= ct.indent * 3 * this.defaultSpaceWidth; } else if (Asc.c_oAscVAlign.Top === ct.cellVA) { textY += rtlKf*ct.indent * 3 * _defaultSpaceWidth; } } else { if (AscCommon.align_Right === ct.cellHA) { textX -= rtlKf*ct.indent * 3 * _defaultSpaceWidth; } else if (AscCommon.align_Left === ct.cellHA) { textX += rtlKf*ct.indent * 3 * _defaultSpaceWidth; } } } this._drawText(this.stringRender.restoreInternalState(ct.state), ctx, textX, textY, textW, color); this._RemoveClipRect(ctx); } //внутреннии ссылки не добавляю, мс аналогично работает if (drawingCtx && drawingCtx.DocumentRenderer && drawingCtx.DocumentRenderer.AddHyperlink /*&& drawingCtx.DocumentRenderer.AddLink*/) { var oHyperlink = this.model.getHyperlinkByCell(row, col); if (oHyperlink && oHyperlink.Hyperlink) { var hyperlink = oHyperlink.Hyperlink; var tooltip = oHyperlink.Tooltip; var kF = AscCommon.g_dKoef_pix_to_mm * _printScale * 100; drawingCtx.DocumentRenderer.AddHyperlink(textX * kF, textY * kF, Math.min(w, textW) * kF, h * kF, hyperlink, tooltip ? tooltip : hyperlink); } } return null; }; WorksheetView.prototype._drawPageBreakPreviewLines = function () { if(!this.isPageBreakPreview(true)) { return; } const t = this; const printArea = this.model.workbook.getDefinesNames("Print_Area", this.model.getId()); const oPrintPages = this.pagesModeData; const printPages = oPrintPages && oPrintPages.printPages; const color = new CColor(0, 0, 208); const printRanges = this._getPageBreakPreviewRanges(oPrintPages); const lineType = AscCommonExcel.selectionLineType.ResizeRange; const dashLineType = AscCommonExcel.selectionLineType.Dash | lineType; const widthLine = 3; let allPagesRange; //рисуем страницы if(printPages && printPages.length) { for (let i = 0; i < printRanges.length; i++) { let oPrintRange = printRanges[i]; allPagesRange = oPrintRange.range; for (let j = oPrintRange.start; j < oPrintRange.end; j++) { if (printPages[j] && printPages[j].page) { this._drawElements(this._drawSelectionElement, printPages[j].page.pageRange, dashLineType, color, null, null, true); } } this._drawElements(this._drawSelectionElement, allPagesRange, lineType, color, true); } //draw pages break let pageOptions = this.model.PagePrintOptions; let pageSetup = pageOptions && pageOptions.asc_getPageSetup(); let bFitToWidth = pageSetup && pageSetup.asc_getFitToWidth(); let bFitToHeight = pageSetup && pageSetup.asc_getFitToHeight(); let doDrawBreaks = function (_break, _byCol) { if (!printArea) { t._drawElements(t._drawLineBetweenRowCol, _byCol && _break.id, !_byCol && _break.id, color, allPagesRange, widthLine); return; } if (_break.min === null && _break.max === null) { return; } for (let i = 0; i < printRanges.length; i++) { //if intersection with range between min/max -> draw line let printRange = printRanges[i].range; if (_break.isBreak(_break.id, _byCol ? printRange.r1 : printRange.c1, _byCol ? printRange.r2 : printRange.c2)) { t._drawElements(t._drawLineBetweenRowCol, _byCol && _break.id, !_byCol && _break.id, color, printRange, widthLine); } } }; if (this.model.colBreaks && !bFitToWidth) { this.model.colBreaks.forEach(function (colBreak) { doDrawBreaks(colBreak, true); }); } if (this.model.rowBreaks && !bFitToHeight) { this.model.rowBreaks.forEach(function (rowBreak) { doDrawBreaks(rowBreak); }); } } }; WorksheetView.prototype._drawPrintArea = function () { let printOptions = this.model.PagePrintOptions; let printPages = this.pagesModeData && this.pagesModeData.printPages; if (!printPages) { let printArea = this.model.workbook.getDefinesNames("Print_Area", this.model.getId()); printPages = []; if(printArea) { this.calcPagesPrint(printOptions, null, null, printPages, null, null, true); } else { let range = new asc_Range(0, 0, this.visibleRange.c2, this.visibleRange.r2); this._calcPagesPrint(range, printOptions, null, printPages, null, null, true); } } let pageSetupModel = printOptions.asc_getPageSetup(); let fitToWidth = pageSetupModel.asc_getFitToWidth(); let fitToHeight = pageSetupModel.asc_getFitToHeight(); let drawProp; if(fitToWidth >= 1 && fitToHeight >= 1) { return; } else if(fitToWidth >= 1) { drawProp = 1; } else if(fitToHeight >= 1) { drawProp = 2; } for (let i = 0, l = printPages.length; i < l; ++i) { this._drawElements(this._drawSelectionElement, printPages[i].pageRange, AscCommonExcel.selectionLineType.Dash, new CColor(0, 0, 0), undefined, drawProp); } }; WorksheetView.prototype._drawCutRange = function () { let cutRange = this.getCutRange(); if(cutRange) { for (var i in cutRange) { this._drawElements(this._drawSelectionElement, cutRange[i], AscCommonExcel.selectionLineType.DashThick, this.settings.activeCellBorderColor); } } }; WorksheetView.prototype.setCutRange = function (val) { this.copyCutRange = val; }; WorksheetView.prototype.getCutRange = function () { return this.copyCutRange; }; WorksheetView.prototype.drawTraceDependents = function () { let traceManager = this.traceDependentsManager; if(traceManager && (traceManager.isHaveDependents() || traceManager.isHavePrecedents() || traceManager.isHaveExternalPrecedents())) { this._drawElements(this.drawTraceArrows); } }; WorksheetView.prototype.drawTraceArrows = function (visibleRange, offsetX, offsetY, args) { let traceManager = this.traceDependentsManager; let ctx = args[0] ? args[0] : this.overlayCtx; let widthLine = 2, customScale = AscBrowser.retinaPixelRatio, zoom = this.getZoom(); widthLine = customScale * widthLine * zoom; ctx.setLineWidth(widthLine); const lineColor = new CColor(78, 128, 245); const externalLineColor = new CColor(68, 68, 68); const whiteColor = new CColor(255, 255, 255); let t = this; // clip by visible area this._AddClipRect(ctx, t._getColLeft(visibleRange.c1) - offsetX, t._getRowTop(visibleRange.r1) - offsetY, Math.abs(t._getColLeft(visibleRange.c2 + 1) - t._getColLeft(visibleRange.c1)), Math.abs(t._getRowTop(visibleRange.r2 + 1) - t._getRowTop(visibleRange.r1))); const doDrawArrow = function (_from, _to, external, isPrecedent) { // drawing line, arrow, dot, minitable as part of a whole dependency line ctx.beginPath(); ctx.setStrokeStyle(!external ? lineColor : externalLineColor); ctx.setLineDash([]); if (isPrecedent && external) { drawExternalPrecedentLine(_from); } else { drawDependentLine(_from, _to, external); } }; const drawDependentLine = function (from, to, external) { let fromCellIndex = from ? AscCommonExcel.getCellIndex(from.row, from.col) : null, toCellIndex = to ? AscCommonExcel.getCellIndex(to.row, to.col) : null; let x1 = t._getColLeft(from.col) - offsetX + t._getColumnWidth(from.col) / 4; let y1 = t._getRowTop(from.row) - offsetY + t._getRowHeight(from.row) / 2; let arrowSize = 7 * zoom * customScale; let x2, y2, miniTableCol, miniTableRow, isTableLeft, isTableTop = true; if (external) { if (from.col < 2 && from.row < 3) { // 1) Right down (+1r, +1c) x2 = t._getColLeft(from.col + 1) - offsetX + t._getColumnWidth(from.col + 1); y2 = t._getRowTop(from.row + 1) - offsetY + t._getRowHeight(from.row + 1); miniTableCol = from.col + 2; miniTableRow = from.row + 1; } else if (from.col < 2 && from.row >= 3) { // 2) Right up(-1r,+1c) x2 = t._getColLeft(from.col + 1) - offsetX + t._getColumnWidth(from.col + 1); y2 = t._getRowTop(from.row - 1) - offsetY; miniTableCol = from.col + 2; miniTableRow = from.row - 2; } else if (from.col >= 2 && from.row < 3) { // 3) Left down(+1r,-1c) x2 = t._getColLeft(from.col - 1) - offsetX; y2 = t._getRowTop(from.row + 1) - offsetY + t._getRowHeight(from.row + 1); miniTableCol = from.col - 2; miniTableRow = from.row + 1; isTableLeft = true; } else { // 4) Left up(-1r,-1c) x2 = t._getColLeft(from.col - 1) - offsetX; y2 = t._getRowTop(from.row - 1) - offsetY; miniTableCol = from.col - 2; miniTableRow = from.row - 2; isTableLeft = true; } } else { x2 = t._getColLeft(to.col) - offsetX + t._getColumnWidth(to.col) / 4; y2 = t._getRowTop(to.row) - offsetY + t._getRowHeight(to.row) / 2; } // Angle and size for arrowhead let angle = Math.atan2(y2 - y1, x2 - x1); // Draw the line and subtract the padding to draw the arrowhead correctly let extLength = Math.sqrt(Math.pow((x2 - x1), 2) + Math.pow((y2 - y1), 2)); if (extLength === 0 && angle === 0) { // temporary exception t._lineDiag(ctx, x1, y1, x2, y2); ctx.stroke(); !external ? drawDot(x1, y1, lineColor) : drawDot(x1, y1, externalLineColor); } else { let dx = (x2 - x1) / extLength; let dy = (y2 - y1) / extLength; let newX2 = x2 - dx * arrowSize; let newY2 = y2 - dy * arrowSize; arrowSize = zoom <= 0.5 ? arrowSize * 1.25 : arrowSize; if (external) { drawDottedLine(x1, y1, newX2, newY2); drawArrowHead(x2, y2, arrowSize, angle, externalLineColor); drawDot(x1, y1, externalLineColor); drawMiniTable(x2, y2, miniTableCol, miniTableRow, isTableLeft, isTableTop); traceManager.addExternalLineCoordinates(fromCellIndex, x1, y1, newX2, newY2); } else { ctx.beginPath(); ctx.setStrokeStyle(!external ? lineColor : externalLineColor); t._moveTo(ctx, x1, y1); t._lineTo(ctx, newX2, newY2); ctx.stroke(); drawArrowHead(newX2, newY2, arrowSize, angle, lineColor); drawDot(x1, y1, lineColor); // write the coordinates of line to traceManager traceManager.addLineCoordinates(fromCellIndex, toCellIndex, /*{x: x1, y: y1}, {x: newX2, y: newY2}*/x1, y1, newX2, newY2); } } }; const drawExternalPrecedentLine = function (from) { // make x1 the end of line and x2 is start let x1 = t._getColLeft(from.col) - offsetX + t._getColumnWidth(from.col) / 4; let y1 = t._getRowTop(from.row) - offsetY + t._getRowHeight(from.row) / 2; let arrowSize = 7 * zoom * customScale; let fromCellIndex = AscCommonExcel.getCellIndex(from.row, from.col); let x2, y2, miniTableCol, miniTableRow, isTableLeft, isTableTop = true; // reverse the line and set tableTop flag to true(mini-table is always drawn above the dot) x2 = x1; y2 = y1; if (from.col < 2 && from.row < 3) { // 1) Right down (+1r, +1c) x1 = t._getColLeft(from.col + 1) - offsetX + t._getColumnWidth(from.col + 1); y1 = t._getRowTop(from.row + 1) - offsetY + t._getRowHeight(from.row + 1); miniTableCol = from.col + 2; miniTableRow = from.row + 1; } else if (from.col < 2 && from.row >= 3) { // 2) Right up(-1r,+1c) x1 = t._getColLeft(from.col + 1) - offsetX + t._getColumnWidth(from.col + 1); y1 = t._getRowTop(from.row - 1) - offsetY; miniTableCol = from.col + 2; miniTableRow = from.row - 2; } else if (from.col >= 2 && from.row < 3) { // 3) Left down(+1r,-1c) x1 = t._getColLeft(from.col - 1) - offsetX; y1 = t._getRowTop(from.row + 1) - offsetY + t._getRowHeight(from.row + 1); miniTableCol = from.col - 2; miniTableRow = from.row + 1; isTableLeft = true; } else { // 4) Left up(-1r,-1c) x1 = t._getColLeft(from.col - 1) - offsetX; y1 = t._getRowTop(from.row - 1) - offsetY; miniTableCol = from.col - 2; miniTableRow = from.row - 2; isTableLeft = true; } // Angle and size for arrowhead let angle = Math.atan2(y2 - y1, x2 - x1); // Draw the line and subtract the padding to draw the arrowhead correctly let extLength = Math.sqrt(Math.pow((x2 - x1), 2) + Math.pow((y2 - y1), 2)); let dx = (x2 - x1) / extLength; let dy = (y2 - y1) / extLength; let newX2 = x2 - dx * arrowSize; let newY2 = y2 - dy * arrowSize; arrowSize = zoom <= 0.5 ? arrowSize * 1.25 : arrowSize; drawDottedLine(x1, y1, newX2, newY2); drawArrowHead(newX2, newY2, arrowSize, angle, externalLineColor); drawDot(x1, y1, externalLineColor); drawMiniTable(x1, y1, miniTableCol, miniTableRow, isTableLeft, isTableTop); traceManager.addExternalLineCoordinates(fromCellIndex, x1, y1, newX2, newY2); }; const drawDottedLine = function (x1, y1, x2, y2) { const dashLength = 8 * zoom; const dashSpace = 2 * zoom; const dx = x2 - x1; const dy = y2 - y1; const distance = Math.sqrt(dx * dx + dy * dy); const dashCount = Math.floor(distance / (dashLength + dashSpace)); const xStep = dx / (dashCount); const yStep = dy / (dashCount); ctx.setLineWidth(widthLine); ctx.beginPath(); ctx.setStrokeStyle(externalLineColor); t._lineDiag(ctx, x1, y1, x2, y2); ctx.stroke(); ctx.setStrokeStyle(whiteColor); for (let i = 0; i < dashCount; i++) { ctx.beginPath(); t._lineDiag(ctx, x1, y1, x1 - xStep * 0.2, y1 - yStep * 0.2); ctx.stroke(); x1 += xStep; y1 += yStep; } }; const drawArrowHead = function (x2, y2, arrowSize, angle, color) { function checkArrowSize (size) { if (Number.isInteger(size)) { return size % 2 !== 0 ? ++size : size; } else { let intPart = parseInt(size, 10), decimalPart = +(size+"").split(".")[1] ? +(size+"").split(".")[1][0] : null; if (decimalPart && intPart % 2 === 0) { return intPart; } else { return Math.ceil(size); } } } arrowSize = checkArrowSize(arrowSize); ctx.setFillStyle(color); let lineDeg = angle * 180 / Math.PI, lineDeg1 = 90 + angle * 180 / Math.PI, lineDeg2 = -90 + angle * 180 / Math.PI; ctx.beginPath(); t._moveTo(ctx, x2, y2); t._lineTo(ctx, x2 + Math.cos(lineDeg1 * Math.PI / 180) * arrowSize / 2, y2 + Math.sin(lineDeg1 * Math.PI / 180) * arrowSize / 2); t._lineTo(ctx, x2 + Math.cos(lineDeg * Math.PI / 180) * arrowSize, y2 + Math.sin(lineDeg * Math.PI / 180) * arrowSize); t._lineTo(ctx, x2 + Math.cos(lineDeg2 * Math.PI / 180) * arrowSize / 2, y2 + Math.sin(lineDeg2 * Math.PI / 180) * arrowSize / 2); ctx.closePath().fill(); }; const drawDot = function (x, y, color) { const dotRadius = 2.75 * zoom * customScale; ctx.beginPath(); let dx = Math.round(x); let dy = Math.round(y); window['AscFormat'].EllipseOnCanvas(ctx, dx, dy, dotRadius, dotRadius); ctx.setFillStyle(color); ctx.fill(); }; const drawMiniTable = function (x, y, destCol, destRow, isTableLeft, isTableTop) { const paddingX = 8 * zoom * customScale; const paddingY = 4 * zoom * customScale; const tableWidth = 15 * zoom * customScale; const tableHeight = 9 * zoom * customScale; const cellWidth = tableWidth / 3; const cellHeight = tableHeight / 3; const lineWidth = 1 * zoom * customScale; const cellStrokesColor = new CColor(0, 0, 0); // Padding for a table inside the cell const x1 = isTableLeft ? x - tableWidth - paddingX : x + paddingX; const y1 = isTableTop ? y - tableHeight - (paddingY * 2) : y + paddingY; // draw white canvas behind the table ctx.setFillStyle(whiteColor); ctx.beginPath(); t._fillRect(ctx, x1, y1 - lineWidth, tableWidth, tableHeight + (lineWidth * 2)); ctx.setLineWidth(lineWidth); ctx.setFillStyle(cellStrokesColor); ctx.setStrokeStyle(cellStrokesColor); // draw main rectangle ctx.beginPath(); t._strokeRect(ctx, x1, y1, tableWidth, tableHeight); let isEven = lineWidth % 2 !== 0 ? 0.5 : 0; ctx.beginPath(); t._fillRect(ctx, x1, y1 - lineWidth, tableWidth + isEven, lineWidth + isEven); t._strokeRect(ctx, x1, y1 - lineWidth, tableWidth, tableHeight + lineWidth); // Vertical lines for (let i = 1; i < 3; i++) { let x2 = i * cellWidth; ctx.beginPath(); t._lineVer(ctx, x2 + x1, y1, y1 + tableHeight); ctx.stroke(); } // Horizontal lines for (let j = 1; j < 3; j++) { let y2 = j * cellHeight; ctx.beginPath(); t._lineHor(ctx, x1, y1 + y2, x1 + tableWidth); ctx.stroke(); } }; // draw stroke for precedent cArea const drawAreaStroke = function (areas) { for (let area in areas) { const range = areas[area].range, // write top left and bottom right cell coords to draw a rectangle around the range topLeftCoords = {row: range.r1, col: range.c1}, bottomRightCoords = {row: range.r2, col: range.c2}; let x1 = t._getColLeft(topLeftCoords.col) - offsetX, y1 = t._getRowTop(topLeftCoords.row) - offsetY, x2 = t._getColLeft(bottomRightCoords.col) + t._getColumnWidth(bottomRightCoords.col) - offsetX, y2 = t._getRowTop(bottomRightCoords.row) + t._getRowHeight(bottomRightCoords.row) - offsetY; // draw rectangle ctx.beginPath(); ctx.setStrokeStyle(lineColor); ctx.setLineWidth(1); t._strokeRect(ctx, x1, y1, Math.abs(x2 - x1), Math.abs(y2 - y1)); // then go to the next area } }; let otherSheetMap = {}; traceManager.forEachDependents(function (from, to, isPrecedent) { if (from && to) { for (let i in to) { let cellFrom = AscCommonExcel.getFromCellIndex(from, true); if (-1 !== i.indexOf(";")) { if (!otherSheetMap[from]) { doDrawArrow(cellFrom, null, true, false); } } else { let cellTo = AscCommonExcel.getFromCellIndex(i, true); if (visibleRange.contains2(cellFrom) || visibleRange.contains2(cellTo)) { doDrawArrow(cellFrom, cellTo, false, isPrecedent); } else { let range = new Asc.Range(cellFrom.col, cellFrom.row, cellTo.col, cellTo.row); range.normalize(); if (visibleRange.isIntersect(range)) { doDrawArrow(cellFrom, cellTo, false, isPrecedent); } } } } } }); // draw external line for precedents traceManager.forEachExternalPrecedent(function (from) { if (from) { let cellFrom = AscCommonExcel.getFromCellIndex(from, true); if (traceManager.checkPrecedentExternal(+from)) { doDrawArrow(cellFrom, null, true, true); } } }); // draw area drawAreaStroke(traceManager._getPrecedentsAreas()); // remove clip range this._RemoveClipRect(ctx); return true; }; WorksheetView.prototype._drawPageBreakPreviewText = function (drawingCtx, range, leftFieldInPx, topFieldInPx) { if(!this.isPageBreakPreview(true)) { return; } if (!this.pagesModeData || !this.pagesModeData.printPages) { return; } let printPages = this.pagesModeData.printPages; if (range === undefined) { range = this.visibleRange; } var t = this; var ctx = drawingCtx || this.drawingCtx; var offsetX = (undefined !== leftFieldInPx) ? leftFieldInPx : this._getOffsetX(); var offsetY = (undefined !== topFieldInPx) ? topFieldInPx : this._getOffsetY(); var frozenX = 0, frozenY = 0, cFrozen, rFrozen; if (!drawingCtx && this.topLeftFrozenCell) { if (undefined === leftFieldInPx) { cFrozen = this.topLeftFrozenCell.getCol0(); offsetX -= frozenX = this._getColLeft(cFrozen) - this._getColLeft(0); } if (undefined === topFieldInPx) { rFrozen = this.topLeftFrozenCell.getRow0(); offsetY -= frozenY = this._getRowTop(rFrozen) - this._getRowTop(0); } } var basePageString = AscCommon.translateManager.getValue("Page") + " "; var getOptimalFontSize = function(width, height) { var kf = 3.04; var needWidth = width / kf; var needHeight = height / kf; //TODO максмальный размер выбрал произвольно. изменить! + оптимизировать алгоритм по равенству var font = new AscCommonExcel.Font(); font.fn = "Arial"; var str; var i = 0, j = 100, k, textMetrics; while (i <= j) { k = Math.floor((i + j) / 2); font.fs = k; str = new AscCommonExcel.Fragment(); str.setFragmentText(basePageString + (index + 1)); str.format = font; t.stringRender.setString([str]); textMetrics = t.stringRender._measureChars(); if (textMetrics.width === needWidth && textMetrics.height === needHeight) { break; } else if (textMetrics.width > needWidth || textMetrics.height > needHeight) { j = k - 1; } else { i = k + 1; } } return k; }; var x1, x2, y1, y2; var startRange = printPages[0] ? printPages[0].page.pageRange : null; var endRange = printPages[0] ? printPages[printPages.length - 1].page.pageRange : null; var unionRange = startRange ? new Asc.Range(startRange.c1, startRange.r1, endRange.c2, endRange.r2) : null; var intersection = unionRange ? range.intersection(unionRange) : null; if(printPages[0] && intersection) { x1 = this._getColLeft(range.c1) - offsetX; y1 = this._getRowTop(range.r1) - offsetY; x2 = this._getColLeft(range.c2 + 1) - offsetX; y2 = this._getRowTop(range.r2 + 1) - offsetY; var pageRange; var tX1, tX2, tY1, tY2, pageIntersection, index; for (var i = 0; i < printPages.length; ++i) { pageRange = printPages[i].page.pageRange; index = printPages[i].index; pageIntersection = pageRange.intersection(range); if(!pageIntersection) { if(pageRange.r1 > range.r2 && pageRange.c1 > range.c2) { break; } else { continue; } } var widthPage = this._getColLeft(pageRange.c2 + 1) - this._getColLeft(pageRange.c1); var heightPage = this._getRowTop(pageRange.r2 + 1) - this._getRowTop(pageRange.r1); var centerX = this._getColLeft(pageRange.c1) + (widthPage) / 2 - offsetX; var centerY = this._getRowTop(pageRange.r1) + (heightPage) / 2 - offsetY; //TODO подобрать такой размер шрифта, чтобы у текста была нужная нам ширина(1/3 от ширины страницы) var font = new AscCommonExcel.Font(); font.fn = "Arial"; font.fs = getOptimalFontSize(widthPage, heightPage); font.c = new CColor(150, 150, 150); var str = new AscCommonExcel.Fragment(); str.setFragmentText(basePageString + (index + 1)); str.format = font; this.stringRender.setString([str]); var textMetrics = this.stringRender._measureChars(); let textWidth = textMetrics.width; let textHeight = textMetrics.height; tX1 = centerX - textWidth / 2; tX2 = centerX + textWidth / 2; tY1 = centerY - textHeight / 2; tY2 = centerY + textHeight / 2; let _zoom = this.getZoom(); let _x1 = Math.max(tX1, x1); let _x2 = Math.min(tX1 + textWidth * _zoom, x2); let _y1 = Math.max(tY1, y1); let _y2 = Math.min(tY1 + textHeight * _zoom, y2); if (_x1 < _x2 && _y1 < _y2) { this._AddClipRect(ctx, x1, y1, x2 - x1, y2 - y1); this._drawText(this.stringRender, undefined, tX1, tY1, 100, this.settings.activeCellBorderColor); this._RemoveClipRect(ctx); } } } }; WorksheetView.prototype._getPagesModeData = function (range) { var printOptions = this.model.PagePrintOptions; var printPages = []; var printRanges = []; this.calcPagesPrint(printOptions, null, null, printPages, printRanges); var res = []; if (range === undefined) { range = this.visibleRange; } for (var i = 0; i < printPages.length; ++i) { //if(printPages[i].pageRange.intersection(range)) { res.push({index: i, page: printPages[i]}); //} } /*var visiblePrintRanges = []; for (var i = 0; i < printRanges.length; ++i) { if(printRanges[i].intersection(range)) { visiblePrintRanges.push(printRanges[i]); } }*/ return {printPages: res, printRanges: printRanges && printRanges.length ? printRanges : null}; }; /** Удаляет вертикальные границы ячейки, если текст выходит за границы и соседние ячейки пусты */ WorksheetView.prototype._eraseCellRightBorder = function ( drawingCtx, colBeg, colEnd, row, offsetX, offsetY ) { if ( colBeg >= colEnd ) { return; } let rtlKf = this.getRightToLeft() ? -1 : 1; var nextCell = -1; var ctx = drawingCtx || this.drawingCtx; ctx.setFillStyle( this.settings.cells.defaultState.background ); for ( var col = colBeg; col < colEnd; ++col ) { var c = -1 !== nextCell ? nextCell : this._getCell( col, row ); var bg = null !== c ? c.getFillColor() : null; if ( bg !== null ) { continue; } nextCell = this._getCell( col + 1, row ); bg = null !== nextCell ? nextCell.getFillColor() : null; if ( bg !== null ) { continue; } this._fillRect( ctx, this._getColLeft(col + 1) - offsetX - rtlKf*gridlineSize, this._getRowTop(row) - offsetY, rtlKf*gridlineSize, this._getRowHeight(row) - gridlineSize ); } }; /** Рисует рамки для ячеек */ WorksheetView.prototype._drawCellsBorders = function (drawingCtx, range, offsetX, offsetY, mergedCells) { //TODO: использовать стили линий при рисовании границ var t = this; var ctx = drawingCtx || this.drawingCtx; var objectMergedCells = {}; // Двумерный map вида строка-колонка {1: {1: range, 4: range}} var h, w, i, mergeCellInfo, startCol, endRow, endCol, col, row; for (i in mergedCells) { mergeCellInfo = mergedCells[i]; startCol = Math.max(range.c1, mergeCellInfo.c1); endRow = Math.min(mergeCellInfo.r2, range.r2, this.nRowsCount); endCol = Math.min(mergeCellInfo.c2, range.c2, this.nColsCount); for (row = Math.max(range.r1, mergeCellInfo.r1); row <= endRow; ++row) { if (!objectMergedCells.hasOwnProperty(row)) { objectMergedCells[row] = {}; } for (col = startCol; col <= endCol; ++col) { objectMergedCells[row][col] = mergeCellInfo; } } } var zoomPrintPreviewCorrect = function (val) { var zoom = t.getZoom(); if (val < 1) { return val; } //учитываю здесь только зум масштабирования return t.workbook.printPreviewState && t.workbook.printPreviewState.isStart() ? Math.max(Asc.round(val * zoom), 1) : val; }; var bc = null, bs = c_oAscBorderStyles.None, isNotFirst = false; // cached border color function drawBorder(type, border, x1, y1, x2, y2) { var isStroke = false, isNewColor = !AscCommonExcel.g_oColorManager.isEqual(bc, border.getColorOrDefault()), isNewStyle = bs !== border.s; if (isNotFirst && (isNewColor || isNewStyle)) { ctx.stroke(); isStroke = true; } if (isNewColor) { bc = border.getColorOrDefault(); ctx.setStrokeStyle(bc); } if (isNewStyle) { bs = border.s; ctx.setLineWidth(zoomPrintPreviewCorrect(border.w)); ctx.setLineDash(border.getDashSegments()); } if (isStroke || false === isNotFirst) { isNotFirst = true; ctx.beginPath(); } switch (type) { case c_oAscBorderType.Hor: t._lineHor(ctx, x1 + t.getRightToLeftOffset(), y1, x2 + t.getRightToLeftOffset()); break; case c_oAscBorderType.Ver: t._lineVer(ctx, x1 + 2*t.getRightToLeftOffset(), y1, y2); break; case c_oAscBorderType.Diag: t._lineDiag(ctx, x1, y1, x2, y2); break; } } function drawVerticalBorder(borderLeftObject, borderRightObject, x, y1, y2) { var borderLeft = borderLeftObject ? borderLeftObject.borders : null, borderRight = borderRightObject ? borderRightObject.borders : null; var border = AscCommonExcel.getMatchingBorder(borderLeft && borderLeft.getR(), borderRight && borderRight.getL()); if (!border || border.w < 1) { return; } var bw = zoomPrintPreviewCorrect(border.w); // ToDo переделать рассчет var tbw = zoomPrintPreviewCorrect(t._calcMaxBorderWidth(borderLeftObject && borderLeftObject.getTopBorder(), borderRightObject && borderRightObject.getTopBorder())); // top border width var bbw = zoomPrintPreviewCorrect(t._calcMaxBorderWidth(borderLeftObject && borderLeftObject.getBottomBorder(), borderRightObject && borderRightObject.getBottomBorder())); // bottom border width var dy1 = tbw > bw ? tbw - 1 : (tbw > 1 ? -1 : 0); var dy2 = bbw > bw ? -2 : (bbw > 2 ? 1 : 0); drawBorder(c_oAscBorderType.Ver, border, x, y1 + (-1 + dy1), x, y2 + (1 + dy2)); } function drawHorizontalBorder(borderTopObject, borderBottomObject, x1, y, x2) { var borderTop = borderTopObject ? borderTopObject.borders : null, borderBottom = borderBottomObject ? borderBottomObject.borders : null; var border = AscCommonExcel.getMatchingBorder(borderTop && borderTop.getB(), borderBottom && borderBottom.getT()); if (border && border.w > 0) { var bw = zoomPrintPreviewCorrect(border.w); // ToDo переделать рассчет var lbw = zoomPrintPreviewCorrect(t._calcMaxBorderWidth(borderTopObject && borderTopObject.getLeftBorder(), borderBottomObject && borderBottomObject.getLeftBorder())); var rbw = zoomPrintPreviewCorrect(t._calcMaxBorderWidth(borderTopObject && borderTopObject.getRightBorder(), borderTopObject && borderTopObject.getRightBorder())); var dx1 = bw > lbw ? (lbw > 1 ? -1 : 0) : (lbw > 2 ? 2 : 1); var dx2 = bw > rbw ? (rbw > 2 ? 1 : 0) : (rbw > 1 ? -2 : -1); drawBorder(c_oAscBorderType.Hor, border, x1 + (-1 + dx1), y, x2 + (1 + dx2), y); } } let _checkLastMergedRow = function (_mc, _row) { let _res = _mc && _row === _mc.r2; if (!_res) { for (let i = _row + 1; i <= _mc.r2; i++) { if (t._getRowHeight(i) !== 0) { _res = false; break; } else { _res = true; } } } return _res; }; var arrPrevRow = [], arrCurrRow = [], arrNextRow = []; var objMCPrevRow = null, objMCRow = null, objMCNextRow = null; var bCur, bPrev, bNext, bTopCur, bTopPrev, bTopNext, bBotCur, bBotPrev, bBotNext; bCur = bPrev = bNext = bTopCur = bTopNext = bBotCur = bBotNext = null; row = range.r1 - 1; var prevCol = range.c1 - 1; // Определим первую колонку (т.к. могут быть скрытые колонки) while (0 <= prevCol && 0 === this._getColumnWidth(prevCol)) --prevCol; // Сначала пройдемся по верхней строке (над отрисовываемым диапазоном) while (0 <= row) { if (this._getRowHeight(row) > 0) { objMCPrevRow = objectMergedCells[row]; for (col = prevCol; col <= range.c2 && col < t.nColsCount; ++col) { if (0 > col || this._getColumnWidth(col) <= 0) { continue; } arrPrevRow[col] = new CellBorderObject(t._getVisibleCell(col, row).getBorder(), objMCPrevRow ? objMCPrevRow[col] : null, col, row); } break; } --row; } var mc = null, nextRow, isFirstRow = true; var isPrevColExist = (0 <= prevCol); for (row = range.r1; row <= range.r2; row = nextRow) { nextRow = row + 1; h = this._getRowHeight(row); if (0 === h) { continue; } // Нужно отсеять пустые снизу for (; nextRow <= range.r2 && nextRow < t.nRowsCount; ++nextRow) { if (0 < this._getRowHeight(nextRow)) { break; } } var isFirstRowTmp = isFirstRow, isLastRow = nextRow > range.r2 || nextRow >= t.nRowsCount; isFirstRow = false; // Это уже не первая строка (определяем не по совпадению с range.r1, а по видимости) objMCRow = isFirstRowTmp ? objectMergedCells[row] : objMCNextRow; objMCNextRow = objectMergedCells[nextRow]; var rowCache = t._getRowCache(row); var y1 = this._getRowTop(row) - offsetY; var y2 = y1 + h - gridlineSize; var nextCol, isFirstCol = true; for (col = range.c1; col <= range.c2 && col < t.nColsCount; col = nextCol) { nextCol = col + 1; w = this._getColumnWidth(col); if (0 === w) { continue; } // Нужно отсеять пустые справа for (; nextCol <= range.c2 && nextCol < t.nColsCount; ++nextCol) { if (0 < this._getColumnWidth(nextCol)) { break; } } var isFirstColTmp = isFirstCol, isLastCol = nextCol > range.c2 || nextCol >= t.nColsCount; isFirstCol = false; // Это уже не первая колонка (определяем не по совпадению с range.c1, а по видимости) mc = objMCRow ? objMCRow[col] : null; var x1 = this._getColLeft(col) - offsetX; var x2 = x1 + w - gridlineSize; if (isFirstColTmp) { bPrev = arrCurrRow[prevCol] = new CellBorderObject(isPrevColExist ? t._getVisibleCell(prevCol, row).getBorder() : null, objMCRow ? objMCRow[prevCol] : null, prevCol, row); bCur = arrCurrRow[col] = new CellBorderObject(t._getVisibleCell(col, row).getBorder(), mc, col, row); bTopPrev = arrPrevRow[prevCol]; bTopCur = arrPrevRow[col]; } else { bPrev = bCur; bCur = bNext; bTopPrev = bTopCur; bTopCur = bTopNext; } if (col === t.nColsCount) { bNext = null; bTopNext = null; } else { bNext = arrCurrRow[nextCol] = new CellBorderObject(t._getVisibleCell(nextCol, row).getBorder(), objMCRow ? objMCRow[nextCol] : null, nextCol, row); bTopNext = arrPrevRow[nextCol]; } if (mc && row !== mc.r1 && row !== mc.r2 && col !== mc.c1 && col !== mc.c2) { continue; } // draw diagonal borders if ((bCur.borders.dd || bCur.borders.du) && (!mc || (row === mc.r1 && col === mc.c1))) { var x2Diagonal = x2; var y2Diagonal = y2; if (mc) { // Merge cells x2Diagonal = this._getColLeft(mc.c2 + 1) - offsetX - 1; y2Diagonal = this._getRowTop(mc.r2 + 1) - offsetY - 1; } // ToDo Clip diagonal borders /*ctx.save() .beginPath() .rect(x1 + (lb.w < 1 ? -1 : (lb.w < 3 ? 0 : +1)), y1 + (tb.w < 1 ? -1 : (tb.w < 3 ? 0 : +1)), c[col].width + ( -1 + (lb.w < 1 ? +1 : (lb.w < 3 ? 0 : -1)) + (rb.w < 1 ? +1 : (rb.w < 2 ? 0 : -1)) ), r[row].height + ( -1 + (tb.w < 1 ? +1 : (tb.w < 3 ? 0 : -1)) + (bb.w < 1 ? +1 : (bb.w < 2 ? 0 : -1)) )) .clip(); */ if (bCur.borders.dd) { // draw diagonal line l,t - r,b if (bCur.borders.d && bCur.borders.d.w > 0) { drawBorder(c_oAscBorderType.Diag, bCur.borders.d, x1 - 1, y1 - 1, x2Diagonal, y2Diagonal); } } if (bCur.borders.du) { // draw diagonal line l,b - r,t if (bCur.borders.d && bCur.borders.d.w > 0) { drawBorder(c_oAscBorderType.Diag, bCur.borders.d, x1 - 1, y2Diagonal, x2Diagonal, y1 - 1); } } // ToDo Clip diagonal borders //ctx.restore(); // canvas context has just been restored, so destroy border color cache //bc = undefined; } // draw left border if (isFirstColTmp && !t._isLeftBorderErased(col, rowCache)) { drawVerticalBorder(bPrev, bCur, x1 - gridlineSize, y1, y2); // Если мы в печати и печатаем первый столбец, то нужно напечатать бордеры // if (lb.w >= 1 && drawingCtx && 0 === col) { // Иначе они будут не такой ширины // ToDo посмотреть что с этим ? в печати будет обрезка // drawVerticalBorder(lb, tb, tbPrev, bb, bbPrev, x1, y1, y2); // } } // draw right border //если пустая является частью мерженной ячейки, то её бордер может потеряться, nextCol === mc.c2 + 1 - условие для этого if ((!mc || col === mc.c2 || nextCol === mc.c2 + 1) && !t._isRightBorderErased(col, rowCache)) { drawVerticalBorder(bCur, bNext, x2, y1, y2); } // draw top border if (isFirstRowTmp) { drawHorizontalBorder(bTopCur, bCur, x1, y1 - gridlineSize, x2); // Если мы в печати и печатаем первую строку, то нужно напечатать бордеры // if (tb.w > 0 && drawingCtx && 0 === row) { // ToDo посмотреть что с этим ? в печати будет обрезка // drawHorizontalBorder.call(this, tb, lb, lbPrev, rb, rbPrev, x1, y1, x2); // } } } isFirstCol = true; for (col = range.c1; col <= range.c2 && col < t.nColsCount; col = nextCol) { nextCol = col + 1; w = this._getColumnWidth(col); if (0 === w) { continue; } // Нужно отсеять пустые справа for (; nextCol <= range.c2 && nextCol < t.nColsCount; ++nextCol) { if (0 < this._getColumnWidth(nextCol)) { break; } } var isFirstColTmp = isFirstCol, isLastCol = nextCol > range.c2 || nextCol >= t.nColsCount; isFirstCol = false; // Это уже не первая колонка (определяем не по совпадению с range.c1, а по видимости) mc = objMCRow ? objMCRow[col] : null; var x1 = this._getColLeft(col) - offsetX; var x2 = x1 + w - gridlineSize; bCur = arrCurrRow[col]; if (row === t.nRowsCount) { bBotPrev = bBotCur = bBotNext = null; } else { if (isFirstColTmp) { bBotPrev = arrNextRow[prevCol] = new CellBorderObject(isPrevColExist ? t._getVisibleCell(prevCol, nextRow).getBorder() : null, objMCNextRow ? objMCNextRow[prevCol] : null, prevCol, nextRow); bBotCur = arrNextRow[col] = new CellBorderObject(t._getVisibleCell(col, nextRow).getBorder(), objMCNextRow ? objMCNextRow[col] : null, col, nextRow); } else { bBotPrev = bBotCur; bBotCur = bBotNext; } } if (col === t.nColsCount) { } else { if (row === t.nRowsCount) { bBotNext = null; } else { bBotNext = arrNextRow[nextCol] = new CellBorderObject(t._getVisibleCell(nextCol, nextRow).getBorder(), objMCNextRow ? objMCNextRow[nextCol] : null, nextCol, nextRow); } } if (mc && row !== mc.r1 && row !== mc.r2 && col !== mc.c1 && col !== mc.c2) { continue; } if (!mc || (_checkLastMergedRow(mc, row))) { // draw bottom border drawHorizontalBorder(bCur, bBotCur, x1, y2, x2); } } arrPrevRow = arrCurrRow; arrCurrRow = arrNextRow; arrNextRow = []; } if (isNotFirst) { ctx.stroke(); } }; /** Рисует закрепленные области областей */ WorksheetView.prototype._drawFrozenPane = function ( noCells ) { if ( this.topLeftFrozenCell ) { var row = this.topLeftFrozenCell.getRow0(); var col = this.topLeftFrozenCell.getCol0(); var tmpRange, offsetX, offsetY; if ( 0 < row && 0 < col ) { offsetX = this._getOffsetX(0, true); offsetY = this._getOffsetY(0, true) tmpRange = new asc_Range( 0, 0, col - 1, row - 1 ); if ( !noCells ) { this._drawGrid( null, tmpRange, offsetX, offsetY ); this._drawGroupData(null, tmpRange, offsetX, offsetY); this._drawGroupData(null, tmpRange, offsetX, undefined, true); this._drawCellsAndBorders(null, tmpRange, offsetX, offsetY ); } } if ( 0 < row ) { row -= 1; offsetX = undefined; offsetY = this._getOffsetY(0, true); tmpRange = new asc_Range( this.visibleRange.c1, 0, this.visibleRange.c2, row ); this._drawRowHeaders( null, 0, row, kHeaderDefault, offsetX, offsetY ); if ( !noCells ) { this._drawGrid( null, tmpRange, offsetX, offsetY ); this._drawGroupData(null, tmpRange, offsetX, offsetY); this._drawGroupData(null, tmpRange, offsetX, offsetY, true); this._drawCellsAndBorders(null, tmpRange, offsetX, offsetY ); } } if ( 0 < col ) { col -= 1; offsetX = this._getOffsetX(0, true); offsetY = undefined; tmpRange = new asc_Range( 0, this.visibleRange.r1, col, this.visibleRange.r2 ); this._drawColumnHeaders( null, 0, col, kHeaderDefault, offsetX, offsetY ); if ( !noCells ) { this._drawGrid( null, tmpRange, offsetX, offsetY ); this._drawGroupData(null, tmpRange, offsetX, offsetY); this._drawGroupData(null, tmpRange, offsetX, offsetY, true); this._drawCellsAndBorders(null, tmpRange, offsetX, offsetY ); } } } }; WorksheetView.prototype._getOffsetY = function (nRow, checkFrozen) { if (nRow == null) { nRow = this.visibleRange.r1 } let scrollCorrect = this.getScrollCorrect(); let frozenRow = checkFrozen && this.topLeftFrozenCell && this.topLeftFrozenCell.getRow0(); if (frozenRow && frozenRow > nRow) { scrollCorrect = 0; } return this._getRowTop(nRow) - this.cellsTop + scrollCorrect; }; WorksheetView.prototype._getOffsetX = function (nCol, checkFrozen) { if (nCol == null) { nCol = this.visibleRange.c1 } let scrollCorrect = this.getHorizontalScrollCorrect(); let frozenCol = checkFrozen && this.topLeftFrozenCell && this.topLeftFrozenCell.getCol0(); if (frozenCol && frozenCol > nCol) { scrollCorrect = 0; } return this._getColLeft(nCol != null ? nCol : this.visibleRange.c1) - this.cellsLeft + scrollCorrect; }; /** Рисует закрепление областей */ WorksheetView.prototype._drawFrozenPaneLines = function (drawingCtx) { // Возможно стоит отрисовывать на overlay, а не на основной канве var ctx = drawingCtx || this.drawingCtx; var lockInfo = this.collaborativeEditing.getLockInfo(c_oAscLockTypeElem.Object, null, this.model.getId(), AscCommonExcel.c_oAscLockNameFrozenPane); var isLocked = this.collaborativeEditing.getLockIntersection(lockInfo, c_oAscLockTypes.kLockTypeOther, false); var color = isLocked ? AscCommonExcel.c_oAscCoAuthoringOtherBorderColor : this.settings.frozenColor; ctx.setLineWidth(1).setStrokeStyle(color).beginPath(); var fHorLine, fVerLine; if (isLocked) { fHorLine = this._dashLineCleverHor; fVerLine = this._dashLineCleverVer; } else { fHorLine = this._lineHorPrevPx; fVerLine = this._lineVerPrevPx; } if (this.topLeftFrozenCell) { var row = this.topLeftFrozenCell.getRow0(); var col = this.topLeftFrozenCell.getCol0(); if (0 < row) { fHorLine.apply(this, [ctx, 0, this._getRowTop(row), ctx.getWidth(), this]); } else { fHorLine.apply(this, [ctx, this.headersLeft, this.headersTop + this.headersHeight, this.headersLeft + this.headersWidth, this]); } if (0 < col) { fVerLine.apply(this, [ctx, this._getColLeft(col), 0, ctx.getHeight(), this]); } else { fVerLine.apply(this, [ctx, this.headersLeft + this.headersWidth, this.headersTop, this.headersTop + this.headersHeight, this]); } ctx.stroke(); } else if (this.model.getSheetView().asc_getShowRowColHeaders()) { fHorLine.apply(this, [ctx, this.headersLeft + this.getRightToLeftOffset(), this.headersTop + this.headersHeight, this.headersLeft + this.headersWidth, this]); fVerLine.apply(this, [ctx, this.headersWidth + this.headersLeft, this.headersTop, this.headersTop + this.headersHeight, this]); ctx.stroke(); } }; /*WorksheetView.prototype._dashLineCleverVer = function (x, y1, y2, _this) { let ctx = this; ctx.dashLineCleverVer(_this.getRightToLeft() ? (_this.getCtxWidth(ctx) - x) : x, y1, y2) return ctx; };*/ /*WorksheetView.prototype._dashLineCleverHor = function (x1, y, x2, _this) { let ctx = this; ctx.dashLineCleverHor(_this.getRightToLeft() ? (_this.getCtxWidth(ctx) - x2) : x1, y, _this.getRightToLeft() ? (_this.getCtxWidth(ctx) - x1) : x2) return ctx; };*/ WorksheetView.prototype.drawFrozenGuides = function ( x, y, target ) { var data, offsetFrozen; var ctx = this.overlayCtx; ctx.clear(); this._drawSelection(); switch ( target ) { case c_oTargetType.FrozenAnchorV: data = this._findColUnderCursor( x, true, true ); if ( data ) { data.col += 1; if ( 0 <= data.col && data.col < this.nColsCount ) { var h = ctx.getHeight(); var offsetX = this._getOffsetX(); offsetFrozen = this.getFrozenPaneOffset( false, true ); offsetX -= offsetFrozen.offsetX; ctx.setFillPattern( this.settings.ptrnLineDotted1 ); this._fillRect( ctx, this._getColLeft(data.col) - offsetX - gridlineSize, 0, 1, h ); } } break; case c_oTargetType.FrozenAnchorH: data = this._findRowUnderCursor( y, true, true ); if ( data ) { data.row += 1; if ( 0 <= data.row && data.row < this.nRowsCount ) { var w = ctx.getWidth(); var offsetY = this._getOffsetY(); offsetFrozen = this.getFrozenPaneOffset( true, false ); offsetY -= offsetFrozen.offsetY; ctx.setFillPattern( this.settings.ptrnLineDotted1 ); this._fillRect( ctx, 0, this._getRowTop(data.row) - offsetY - 1, w, 1 ); } } break; } }; WorksheetView.prototype._isFrozenAnchor = function ( x, y ) { var result = {result: false, cursor: "move", name: ""}; if ( false === this.model.getSheetView().asc_getShowRowColHeaders() ) { return result; } var _this = this; var frozenCell = this.topLeftFrozenCell ? this.topLeftFrozenCell : new AscCommon.CellAddress( 0, 0, 0 ); function isPointInAnchor( x, y, rectX, rectY, rectW, rectH ) { var delta = 2; return (x >= rectX - delta) && (x <= rectX + rectW + delta) && (y >= rectY - delta) && (y <= rectY + rectH + delta); } // vertical var _x = this._getColLeft(frozenCell.getCol0()) - 0.5; var _y = _this.headersTop; var w = 0; var h = _this.headersHeight; if ( isPointInAnchor( x, y, _x, _y, w, h ) ) { result.result = true; result.name = c_oTargetType.FrozenAnchorV; } // horizontal _x = _this.headersLeft; _y = this._getRowTop(frozenCell.getRow0()) - 0.5; w = _this.headersWidth - 0.5; h = 0; if ( isPointInAnchor( x, y, _x, _y, w, h ) ) { result.result = true; result.name = c_oTargetType.FrozenAnchorH; } return result; }; WorksheetView.prototype.applyFrozenAnchor = function ( x, y, target ) { var t = this; var onChangeFrozenCallback = function ( isSuccess ) { if ( false === isSuccess ) { t.overlayCtx.clear(); t._drawSelection(); return; } var lastCol = 0, lastRow = 0, data; if ( t.topLeftFrozenCell ) { lastCol = t.topLeftFrozenCell.getCol0(); lastRow = t.topLeftFrozenCell.getRow0(); } switch ( target ) { case c_oTargetType.FrozenAnchorV: data = t._findColUnderCursor( x, true, true ); if ( data ) { data.col += 1; if ( 0 <= data.col && data.col < t.nColsCount ) { lastCol = data.col; } } break; case c_oTargetType.FrozenAnchorH: data = t._findRowUnderCursor( y, true, true ); if ( data ) { data.row += 1; if ( 0 <= data.row && data.row < t.nRowsCount ) { lastRow = data.row; } } break; } t._updateFreezePane( lastCol, lastRow ); }; this._isLockedFrozenPane( onChangeFrozenCallback ); }; /** Для api закрепленных областей */ WorksheetView.prototype.freezePane = function (type, c, r) { var t = this; var activeCell = this.model.selectionRange.activeCell.clone(); var onChangeFreezePane = function (isSuccess) { if (false === isSuccess) { return; } var col, row, mc; if (type === Asc.c_oAscFrozenPaneAddType.firstRow) { col = 0; row = 1; } else if (type === Asc.c_oAscFrozenPaneAddType.firstCol) { col = 1; row = 0; } else if(type === null && c !== undefined && r !== undefined) { col = c; row = r; } else { if (null !== t.topLeftFrozenCell) { col = row = 0; } else { col = activeCell.col; row = activeCell.row; if (0 !== row || 0 !== col) { mc = t.model.getMergedByCell(row, col); if (mc) { col = mc.c1; row = mc.r1; } } if (0 === col && 0 === row) { col = ((t.visibleRange.c2 - t.visibleRange.c1) / 2) >> 0; row = ((t.visibleRange.r2 - t.visibleRange.r1) / 2) >> 0; } } } t._updateFreezePane(col, row); }; if (this.topLeftFrozenCell && type === Asc.c_oAscFrozenPaneAddType.firstRow) { if (this.topLeftFrozenCell.col === 1 && this.topLeftFrozenCell.row === 2) { return; } } if (this.topLeftFrozenCell && type === Asc.c_oAscFrozenPaneAddType.firstCol) { if (this.topLeftFrozenCell.col === 2 && this.topLeftFrozenCell.row === 1) { return; } } return this._isLockedFrozenPane(onChangeFreezePane); }; WorksheetView.prototype._updateFreezePane = function (col, row, lockDraw) { if (window['IS_NATIVE_EDITOR']) return; var lastCol = 0, lastRow = 0; if (this.topLeftFrozenCell) { lastCol = this.topLeftFrozenCell.getCol0(); lastRow = this.topLeftFrozenCell.getRow0(); } History.Create_NewPoint(); var oData = new AscCommonExcel.UndoRedoData_FromTo(new AscCommonExcel.UndoRedoData_FrozenBBox(new asc_Range(lastCol, lastRow, lastCol, lastRow)), new AscCommonExcel.UndoRedoData_FrozenBBox(new asc_Range(col, row, col, row)), null); History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_ChangeFrozenCell, this.model.getId(), null, oData); var isUpdate = false; if (0 === col && 0 === row) { // Очистка if (null !== this.topLeftFrozenCell) { isUpdate = true; } this.topLeftFrozenCell = this.model.getSheetView().pane = null; } else { // Создание if (null === this.topLeftFrozenCell) { isUpdate = true; } var pane = this.model.getSheetView().pane = new AscCommonExcel.asc_CPane(); this.topLeftFrozenCell = pane.topLeftFrozenCell = new AscCommon.CellAddress(row, col, 0); } this.visibleRange.c1 = col; this.visibleRange.r1 = row; this._updateVisibleRowsCount(true); this._updateVisibleColsCount(true); this.scrollType |= AscCommonExcel.c_oAscScrollType.ScrollVertical | AscCommonExcel.c_oAscScrollType.ScrollHorizontal; if (this.objectRender && this.objectRender.drawingArea) { this.objectRender.drawingArea.init(); } if (!lockDraw) { this.draw(); } // Эвент на обновление if (isUpdate && !this.model.workbook.bUndoChanges && !this.model.workbook.bRedoChanges) { this.handlers.trigger("updateSheetViewSettings"); } }; WorksheetView.prototype._getFreezePaneOffset = function (type, range, bInsert) { if (this.topLeftFrozenCell) { var lastCol = this.topLeftFrozenCell.getCol0(); var lastRow = this.topLeftFrozenCell.getRow0(); var row, col; if ((type === c_oAscInsertOptions.InsertColumns || type === c_oAscInsertOptions.DeleteColumns) && lastCol) { var diffCol; if (bInsert) { if (lastCol >= range.c1) { diffCol = range.c2 - range.c1 + 1; } if (diffCol) { col = lastCol + diffCol; } } else { if (range.c2 <= lastCol) { diffCol = range.c2 - range.c1 + 1; } else if (lastCol >= range.c1) { diffCol = lastCol - range.c1; } if (diffCol > 0) { col = lastCol - diffCol; } } if (col < 0) { col = 0; } } if ((type === c_oAscInsertOptions.InsertRows || type === c_oAscInsertOptions.DeleteRows) && lastRow) { var diffRow; if (bInsert) { if (lastRow >= range.r1) { diffRow = range.r2 - range.r1 + 1; } if (diffRow) { row = lastRow + diffRow; } } else { if (range.r2 <= lastRow) { diffRow = range.r2 - range.r1 + 1; } else if (lastRow >= range.r1) { diffRow = lastRow - range.r1; } if (diffRow > 0) { row = lastRow - diffRow; } } if (row < 0) { row = 0; } } if (row !== undefined || col !== undefined) { return {row: row === undefined ? lastRow : row, col: col === undefined ? lastCol : col}; } } return null; }; /** */ WorksheetView.prototype._drawSelectionElement = function (visibleRange, offsetX, offsetY, args) { let range = args[0]; let selectionLineType = args[1]; let strokeColor = args[2]; let isAllRange = args[3]; let isAllowRetina = args[5] ? 1 : 0; let isAllowRetinaResize = args[6] ? 1 : 0; let colorN = this.settings.activeCellBorderColor2; let ctx = this.overlayCtx; let oIntersection = range.intersectionSimple(visibleRange); if (!oIntersection) { return true; } let fHorLine, fVerLine; let canFill = AscCommonExcel.selectionLineType.Selection & selectionLineType; let isDashLine = AscCommonExcel.selectionLineType.Dash & selectionLineType; let dashThickLine = AscCommonExcel.selectionLineType.DashThick & selectionLineType; if (isDashLine || dashThickLine) { fHorLine = this._dashLineCleverHor; fVerLine = this._dashLineCleverVer; } else { fHorLine = this._lineHorPrevPx; fVerLine = this._lineVerPrevPx; } let firstCol = oIntersection.c1 === visibleRange.c1 && !isAllRange; let firstRow = oIntersection.r1 === visibleRange.r1 && !isAllRange; let drawLeftSide = oIntersection.c1 === range.c1; let drawRightSide = oIntersection.c2 === range.c2; let drawTopSide = oIntersection.r1 === range.r1; let drawBottomSide = oIntersection.r2 === range.r2; if(args[4]) { if(args[4] === 1) { drawLeftSide = false; drawRightSide = false; } else if(args[4] === 2){ drawTopSide = false; drawBottomSide = false; } else if (args[4] === 3) { drawLeftSide = false; drawRightSide = false; drawTopSide = false; drawBottomSide = false; } } let x1 = this._getColLeft(oIntersection.c1) - offsetX; let x2 = this._getColLeft(oIntersection.c2 + 1) - offsetX; let y1 = this._getRowTop(oIntersection.r1) - offsetY; let y2 = this._getRowTop(oIntersection.r2 + 1) - offsetY; if (canFill) { let fillColor = strokeColor.Copy(); fillColor.a = 0.15; ctx.setFillStyle(fillColor); this._fillRect(ctx, x1, y1, x2 - x1, y2 - y1); } let isPagePreview = AscCommonExcel.selectionLineType.ResizeRange & selectionLineType; //меняю толщину линии для селекта(только в случае сплошной линии) и масштаба 200% let isRetina = (!isDashLine || isAllowRetina) && this.getRetinaPixelRatio() >= 2; let widthLine = isDashLine ? 1 : 2; //TODO for scale > 200% use a multiplier of 2 . revise the rendering for scales over 200% if (isRetina) { widthLine = ((widthLine * 2) + 0.5) >> 0//AscCommon.AscBrowser.convertToRetinaValue(widthLine, true); } let thinLineDiff = 0; if (isPagePreview) { widthLine = widthLine + 1; thinLineDiff = isDashLine ? 0 : 1; } //TODO проверить на следующих версиях. сдвиг, который получился опытным путём. проблема только в safari. let notStroke = AscCommonExcel.selectionLineType.NotStroke & selectionLineType; if (!notStroke) { let _diff = 0; if (AscBrowser.isSafari) { _diff = 1; } ctx.setLineWidth(widthLine).setStrokeStyle(strokeColor); ctx.beginPath(); if (drawTopSide && !firstRow) { fHorLine.apply(this, [ctx, x1 - !isDashLine * (2 + isRetina * 1) + _diff + this.getRightToLeftOffset()*1, y1, x2 + !isDashLine * (1 + isRetina * 1) - _diff + this.getRightToLeftOffset()*1, this]); } if (drawBottomSide) { fHorLine.apply(this, [ctx, x1, y2 + !isDashLine * 1 - thinLineDiff, x2, this]); } if (drawLeftSide && !firstCol) { fVerLine.apply(this, [ctx, x1 - this.getRightToLeftOffset()*1, y1, y2 + !isDashLine * (1 + isRetina * 1) - _diff, this]); } if (drawRightSide) { fVerLine.apply(this, [ctx, x2 + !isDashLine * 1 - thinLineDiff -this.getRightToLeftOffset()*1, y1, y2 + !isDashLine * (1 + isRetina * 1), this]); } ctx.closePath().stroke(); } // draw active cell in selection let isActive = AscCommonExcel.selectionLineType.ActiveCell & selectionLineType; if (isActive) { let cell = this.model.getSelection().activeCell; let fs = this.model.getMergedByCell(cell.row, cell.col); fs = oIntersection.intersectionSimple(fs || new asc_Range(cell.col, cell.row, cell.col, cell.row)); if (fs) { let top = this._getRowTop(fs.r1); let left = this._getColLeft(fs.c1); let _x1 = left - offsetX + 1; let _y1 = top - offsetY + 1; let _w = this._getColLeft(fs.c2 + 1) - left - 2 - isRetina * 1; let _h = this._getRowTop(fs.r2 + 1) - top - 2 - isRetina * 1; if (0 < _w && 0 < _h) { this._clearRect(ctx, _x1, _y1, _w, _h); } } } if (canFill && !notStroke) {/*Отрисовка светлой полосы при выборе ячеек для формулы*/ ctx.setLineWidth(1); ctx.setStrokeStyle(colorN); ctx.beginPath(); if (drawTopSide) { fHorLine.apply(this, [ctx, x1 + isRetina * 1 + this.getRightToLeftOffset()*1, y1 + 1 + isRetina * !firstRow * 1, x2 - 1 - isRetina * 1 + this.getRightToLeftOffset()*1, ctx]); } if (drawBottomSide) { fHorLine.apply(this, [ctx, x1 + isRetina * 1+ this.getRightToLeftOffset()*1, y2 - 1 - isRetina * 1, x2 - 1 - isRetina * 1+ this.getRightToLeftOffset()*1, ctx]); } if (drawLeftSide) { fVerLine.apply(this, [ctx, x1 + 1 + isRetina * !firstCol * 1, y1 + isRetina * 1, y2 - 2 - isRetina * !firstCol * 1, ctx]); } if (drawRightSide) { fVerLine.apply(this, [ctx, x2 - 1 - isRetina * 1, y1 + isRetina * 1, y2 - 2 - isRetina * 1, ctx]); } ctx.closePath().stroke(); } // Отрисовка квадратов для move/resize let isResize = AscCommonExcel.selectionLineType.Resize & selectionLineType; let isPromote = AscCommonExcel.selectionLineType.Promote & selectionLineType; if (isResize || isPromote) { //isResize - пока не увеличиваю квадрат при выборе диапазона в формуле, поскольку нужно менять логику очистки селекта в режиме формул let retinaKf = isRetina && (!isResize || isAllowRetinaResize) ? 2 : 1; let size = 5 * retinaKf; let sizeBorder = size + 2 * retinaKf; let diff = Math.floor(size/2) + 1; let diffBorder = Math.floor(sizeBorder/2) + 1 * retinaKf; ctx.setFillStyle(colorN); if (drawRightSide && drawBottomSide) { this._fillRect(ctx, x2 - diffBorder + this.getRightToLeftOffset()*1, y2 - diffBorder, sizeBorder, sizeBorder); } ctx.setFillStyle(strokeColor); if (drawRightSide && drawBottomSide) { this._fillRect(ctx, x2 - diff + this.getRightToLeftOffset()*1, y2 - diff, size, size); } if (isResize) { ctx.setFillStyle(colorN); if (drawLeftSide && drawTopSide) { this._fillRect(ctx, x1 - diffBorder, y1 - diffBorder, sizeBorder, sizeBorder); } if (drawRightSide && drawTopSide) { this._fillRect(ctx, x2 - diffBorder, y1 - diffBorder, sizeBorder, sizeBorder); } if (drawLeftSide && drawBottomSide) { this._fillRect(ctx, x1 - diffBorder, y2 - diffBorder, sizeBorder, sizeBorder); } ctx.setFillStyle(strokeColor); if (drawLeftSide && drawTopSide) { this._fillRect(ctx, x1 - diff, y1 - diff, size, size); } if (drawRightSide && drawTopSide) { this._fillRect(ctx, x2 - diff, y1 - diff, size, size); } if (drawLeftSide && drawBottomSide) { this._fillRect(ctx, x1 - diff, y2 - diff, size, size); } } } return true; }; /**Отрисовывает диапазон с заданными параметрами*/ WorksheetView.prototype._drawElements = function (drawFunction) { var cFrozen = 0, rFrozen = 0, args = Array.prototype.slice.call(arguments, 1), offsetX = this._getOffsetX(), offsetY = this._getOffsetY(), res; if (this.topLeftFrozenCell) { cFrozen = this.topLeftFrozenCell.getCol0(); rFrozen = this.topLeftFrozenCell.getRow0(); offsetX -= this._getColLeft(cFrozen) - this._getColLeft(0); offsetY -= this._getRowTop(rFrozen) - this._getRowTop(0); var oFrozenRange; cFrozen -= 1; rFrozen -= 1; if (0 <= cFrozen && 0 <= rFrozen) { oFrozenRange = new asc_Range(0, 0, cFrozen, rFrozen); res = drawFunction.call(this, oFrozenRange, this._getColLeft(0) - this.cellsLeft, this._getOffsetY(0, true), args); if (!res) { return; } } if (0 <= cFrozen) { oFrozenRange = new asc_Range(0, this.visibleRange.r1, cFrozen, this.visibleRange.r2); let clipX = this._getColLeft(oFrozenRange.c1) - offsetX + this.getHorizontalScrollCorrect(); let clipY = this._getRowTop(oFrozenRange.r1) - offsetY + this.getScrollCorrect(); let clipW = this._getColLeft(this.visibleRange.c2 + 1) - this._getColLeft(oFrozenRange.c1); let clipH = this._getRowTop(this.visibleRange.r2 + 1) - this._getRowTop(oFrozenRange.r1); this.overlayCtx.save().beginPath(); this._rect(this.overlayCtx, clipX, clipY, clipW, clipH) this.overlayCtx.clip(); res = drawFunction.call(this, oFrozenRange, this._getColLeft(0) - this.cellsLeft, offsetY, args); this.overlayCtx.restore(); if (!res) { return; } } if (0 <= rFrozen) { oFrozenRange = new asc_Range(this.visibleRange.c1, 0, this.visibleRange.c2, rFrozen); let clipX = this._getColLeft(oFrozenRange.c1) - offsetX + this.getHorizontalScrollCorrect(); let clipY = this._getRowTop(oFrozenRange.r1) - offsetY + this.getScrollCorrect(); let clipW = this._getColLeft(this.visibleRange.c2 + 1) - this._getColLeft(oFrozenRange.c1); let clipH = this._getRowTop(this.visibleRange.r2 + 1) - this._getRowTop(oFrozenRange.r1); this.overlayCtx.save().beginPath(); this._rect(this.overlayCtx, clipX, clipY, clipW, clipH); this.overlayCtx.clip(); res = drawFunction.call(this, oFrozenRange, offsetX, this._getOffsetY(0, true), args); this.overlayCtx.restore(); if (!res) { return; } } } // Можно вместо call попользовать apply, но тогда нужно каждый раз соединять массив аргументов и 3 объекта let clipX = this._getColLeft(this.visibleRange.c1) - offsetX + this.getHorizontalScrollCorrect(); let clipY = this._getRowTop(this.visibleRange.r1) - offsetY + this.getScrollCorrect(); let clipW = this._getColLeft(this.visibleRange.c2 + 1) - this._getColLeft(this.visibleRange.c1); let clipH = this._getRowTop(this.visibleRange.r2 + 1) - this._getRowTop(this.visibleRange.r1); this.overlayCtx.save().beginPath(); this._rect(this.overlayCtx, clipX, clipY, clipW, clipH) this.overlayCtx.clip(); drawFunction.call(this, this.visibleRange, offsetX, offsetY, args); this.overlayCtx.restore(); }; /** * Рисует выделение вокруг ячеек */ WorksheetView.prototype._drawSelection = function () { var api = window["Asc"]["editor"]; var isShapeSelect = false; if (window['IS_NATIVE_EDITOR']) { return; } if (this.model.getSheetProtection(Asc.c_oAscSheetProtectType.selectUnlockedCells)) { return; } if (!this.overlayCtx) { return; } var selectionDialogMode = this.getSelectionDialogMode(); var dialogOtherRanges = this.getDialogOtherRanges(); this.handlers.trigger("checkLastWork"); // set clipping rect to cells area var ctx = this.overlayCtx; ctx.save().beginPath(); this._rect(ctx, this.cellsLeft, this.cellsTop, ctx.getWidth() - this.cellsLeft, ctx.getHeight() - this.cellsTop) ctx.clip(); //draw foreign cursors if ((this.collaborativeEditing.getCollaborativeEditing() || api.isLiveViewer()) && this.collaborativeEditing.getFast()) { var foreignCursors = this.collaborativeEditing.m_aForeignCursorsData; for (var i in foreignCursors) { if (foreignCursors[i] && foreignCursors[i].sheetId === this.model.Id) { var color = AscCommon.getUserColorById(foreignCursors[i].shortId, null, true); for (var j = 0; j < foreignCursors[i].ranges.length; j++) { this._drawElements(this._drawSelectionElement, foreignCursors[i].ranges[j], AscCommonExcel.selectionLineType.None, color); if (j === 0 && foreignCursors[i].needDrawLabel) { this.Show_ForeignCursorLabel(i, foreignCursors[i], j, color); foreignCursors[i].needDrawLabel = null; } } } } } if (this.workbook.Api.isShowVisibleAreaOleEditor || this.workbook.Api.isEditVisibleAreaOleEditor) { this._drawVisibleArea(); if (this.workbook.Api.isEditVisibleAreaOleEditor) { ctx.restore(); return; } } if (this.isPageBreakPreview(true)) { this._drawPageBreakPreviewLines(); } if(this.isPageBreakPreview(true) && this.pageBreakPreviewSelectionRange) { this._drawPageBreakPreviewSelectionRange(); } if(this.viewPrintLines && !this.isPageBreakPreview()) { this._drawPrintArea(); } this._drawCutRange(); if (dialogOtherRanges) { this._drawCollaborativeElements(); } var isOtherSelectionMode = selectionDialogMode && !this.handlers.trigger('isActive'); if (isOtherSelectionMode) { this._drawSelectRange(); } else { isShapeSelect = this.objectRender.selectedGraphicObjectsExists(); if (isShapeSelect) { if (this.isChartAreaEditMode) { this._drawFormulaRanges(this.oOtherRanges); } } else { if (dialogOtherRanges) { this._drawFormulaRanges(this.oOtherRanges); } this._drawSelectionRange(); if (this.activeFillHandle) { this._drawElements(this._drawSelectionElement, this.activeFillHandle.clone(true), AscCommonExcel.selectionLineType.None, this.settings.activeCellBorderColor); } if (selectionDialogMode) { this._drawSelectRange(); } if (this.workbook.isDrawFormatPainter()) { this._drawFormatPainterRange(); } if (null !== this.activeMoveRange) { let fullColumnRowProps = this.startCellMoveRange.colRowMoveProps; if (fullColumnRowProps) { let shift = fullColumnRowProps.shiftKey; if (shift) { let insertToCol = fullColumnRowProps.colByX; let insertToRow = fullColumnRowProps.rowByY; var selectionRange = (this.dragAndDropRange || this.model.selectionRange.getLast()); if (insertToCol != null && insertToCol >= selectionRange.c1 && insertToCol <= selectionRange.c2) { insertToCol = Math.max(0, selectionRange.c1 - 1); } if (insertToRow != null && insertToRow >= selectionRange.r1 && insertToRow <= selectionRange.r2) { insertToRow = Math.max(0, selectionRange.r1 - 1); } this._drawElements(this._drawLineBetweenRowCol, insertToCol != null ? insertToCol + 1 : null, insertToRow != null ? insertToRow + 1 : null, this.settings.activeCellBorderColor); } else { this._drawElements(this._drawSelectionElement, this.activeMoveRange, AscCommonExcel.selectionLineType.Selection, this.settings.activeCellBorderColor, null, 3); } } else { this._drawElements(this._drawSelectionElement, this.activeMoveRange, AscCommonExcel.selectionLineType.None, new CColor(0, 0, 0)); } } this._drawElements(this.drawOverlayButtons); } } let searchSpecificRange = this.handlers.trigger('selectSearchingResults') && this.workbook.SearchEngine && this.workbook.SearchEngine.getSpecificRange(); if (searchSpecificRange) { this._drawElements(this._drawSelectionElement, searchSpecificRange, AscCommonExcel.selectionLineType.DashThick, window['AscCommonExcel'].c_oAscVisibleAreaOleEditorBorderColor); } this.drawTraceDependents(); let historyChangedRanges = this.workbook.historyChangedRanges && this.workbook.historyChangedRanges[this.model.Id]; if (historyChangedRanges) { for (let i in historyChangedRanges) { let range = historyChangedRanges[i].range; let color = historyChangedRanges[i].color; if (range && color) { this._drawElements(this._drawSelectionElement, range, AscCommonExcel.selectionLineType.Selection | AscCommonExcel.selectionLineType.NotStroke, new CColor(color.r, color.g, color.b)); } } } // restore canvas' original clipping range ctx.restore(); if (!isOtherSelectionMode && !isShapeSelect) { this._drawActiveHeaders(); } }; WorksheetView.prototype.Show_ForeignCursorLabel = function(userId, foreignCursor, index, color) { var Api = window["Asc"]["editor"]; if(!Api) { return; } if (foreignCursor.ShowId) clearTimeout(foreignCursor.ShowId); foreignCursor.ShowId = setTimeout(function() { foreignCursor.ShowId = null; Api.hideForeignSelectLabel(userId); }, AscCommon.FOREIGN_CURSOR_LABEL_HIDETIME); var coord = this.getCellCoord(foreignCursor.ranges[index].c2, foreignCursor.ranges[index].r1); Api.showForeignSelectLabel(userId, coord._x + coord._width, coord._y, color, foreignCursor.isEdit); //this.Update_ForeignCursorLabelPosition(UserId, Coords.X, Coords.Y, Color); }; WorksheetView.prototype._drawSelectionRange = function () { var type, selection = this.model.getSelection(), ranges = selection.ranges; var range, selectionLineType; for (var i = 0, l = ranges.length; i < l; ++i) { range = ranges[i].clone(); type = range.getType(); if (c_oAscSelectionType.RangeMax === type) { range.c2 = this.nColsCount - 1; range.r2 = this.nRowsCount - 1; } else if (c_oAscSelectionType.RangeCol === type) { range.r2 = this.nRowsCount - 1; } else if (c_oAscSelectionType.RangeRow === type) { range.c2 = this.nColsCount - 1; } selectionLineType = AscCommonExcel.selectionLineType.Selection; if (1 === l) { selectionLineType |= AscCommonExcel.selectionLineType.ActiveCell | AscCommonExcel.selectionLineType.Promote; } else if (i === selection.activeCellId) { selectionLineType |= AscCommonExcel.selectionLineType.ActiveCell; } let fullColumnProps = this.startCellMoveRange && this.startCellMoveRange.colRowMoveProps; if (null !== this.activeMoveRange && fullColumnProps && i === l - 1) { this._drawElements(this._drawSelectionElement, range, !fullColumnProps.ctrlKey ? AscCommonExcel.selectionLineType.DashThick : AscCommonExcel.selectionLineType.ActiveCell, this.settings.activeCellBorderColor); } else { this._drawElements(this._drawSelectionElement, range, selectionLineType, this.settings.activeCellBorderColor); } } this.handlers.trigger("drawMobileSelection", this.workbook.mainOverlay, this.settings.activeCellBorderColor); }; WorksheetView.prototype._drawFormatPainterRange = function () { let t = this, color = new CColor(0, 0, 0); let oData = this.workbook.Api.getFormatPainterData(); if(oData && oData.range) { oData.range.ranges.forEach(function (item) { t._drawElements(t._drawSelectionElement, item, AscCommonExcel.selectionLineType.Dash, color); }); } }; WorksheetView.prototype._drawFormulaRanges = function (ranges) { if (!ranges) { return; } ranges = ranges.ranges; var length = AscCommonExcel.c_oAscFormulaRangeBorderColor.length; var strokeColor, colorIndex, uniqueColorIndex = 0, tmpColors = []; for (var i = 0, l = ranges.length; i < l; ++i) { if (ranges[i].noColor) { colorIndex = 0; } else if (ranges[i].chartRangeIndex !== undefined) { colorIndex = ranges[i].chartRangeIndex; } else { colorIndex = asc.getUniqueRangeColor(ranges, i, tmpColors); if (null == colorIndex) { colorIndex = uniqueColorIndex++; } tmpColors.push(colorIndex); } strokeColor = AscCommonExcel.c_oAscFormulaRangeBorderColor[colorIndex % length]; this._drawElements(this._drawSelectionElement, ranges[i], AscCommonExcel.selectionLineType.Selection | (ranges[i].isName ? AscCommonExcel.selectionLineType.None : AscCommonExcel.selectionLineType.Resize), strokeColor, null, null, null, true); } }; WorksheetView.prototype._drawSelectRange = function () { if (!this.model.selectionRange) { return; } var ranges = this.model.selectionRange.ranges; for (var i = 0, l = ranges.length; i < l; ++i) { this._drawElements(this._drawSelectionElement, ranges[i], AscCommonExcel.selectionLineType.Dash, AscCommonExcel.c_oAscCoAuthoringOtherBorderColor); } }; WorksheetView.prototype._drawCollaborativeElements = function () { if ( this.collaborativeEditing.getCollaborativeEditing() ) { this._drawCollaborativeElementsMeOther(c_oAscLockTypes.kLockTypeMine); this._drawCollaborativeElementsMeOther(c_oAscLockTypes.kLockTypeOther); this._drawCollaborativeElementsAllLock(); } }; WorksheetView.prototype._drawCollaborativeElementsAllLock = function () { var currentSheetId = this.model.getId(); var nLockAllType = this.collaborativeEditing.isLockAllOther(currentSheetId); if (Asc.c_oAscMouseMoveLockedObjectType.None !== nLockAllType) { var isAllRange = true, strokeColor = (Asc.c_oAscMouseMoveLockedObjectType.TableProperties === nLockAllType) ? AscCommonExcel.c_oAscCoAuthoringLockTablePropertiesBorderColor : AscCommonExcel.c_oAscCoAuthoringOtherBorderColor, oAllRange = new asc_Range(0, 0, gc_nMaxCol0, gc_nMaxRow0); this._drawElements(this._drawSelectionElement, oAllRange, AscCommonExcel.selectionLineType.Dash, strokeColor, isAllRange); } }; WorksheetView.prototype._drawCollaborativeElementsMeOther = function (type) { var currentSheetId = this.model.getId(), i, strokeColor, arrayCells, oCellTmp; if (c_oAscLockTypes.kLockTypeMine === type) { strokeColor = AscCommonExcel.c_oAscCoAuthoringMeBorderColor; arrayCells = this.collaborativeEditing.getLockCellsMe(currentSheetId); arrayCells = arrayCells.concat(this.collaborativeEditing.getArrayInsertColumnsBySheetId(currentSheetId)); arrayCells = arrayCells.concat(this.collaborativeEditing.getArrayInsertRowsBySheetId(currentSheetId)); } else { strokeColor = AscCommonExcel.c_oAscCoAuthoringOtherBorderColor; arrayCells = this.collaborativeEditing.getLockCellsOther(currentSheetId); } for (i = 0; i < arrayCells.length; ++i) { oCellTmp = new asc_Range(arrayCells[i].c1, arrayCells[i].r1, arrayCells[i].c2, arrayCells[i].r2); this._drawElements(this._drawSelectionElement, oCellTmp, AscCommonExcel.selectionLineType.Dash, strokeColor, null, null, true); } }; WorksheetView.prototype._drawLineBetweenRowCol = function (visibleRange, offsetX, offsetY, args) { let col = args[0]; let row = args[1]; let strokeColor = args[2]; let range = args[3]; let widthLine = args[4] != null ? args[4] : 2; let ctx = this.overlayCtx; if (range) { visibleRange = range.intersection(visibleRange); } if (!visibleRange) { return; } let fHorLine, fVerLine; fHorLine = ctx.lineHorPrevPx; fVerLine = ctx.lineVerPrevPx; if (AscBrowser.retinaPixelRatio >= 2) { widthLine = ((widthLine * 2) + 0.5) >> 0 } if (col != null) { if (!visibleRange.containsCol(col)) { return; } let x1 = this._getColLeft(col) - offsetX; let y1 = this._getRowTop(visibleRange.r1) - offsetY; let y2 = this._getRowTop(visibleRange.r2 + 1) - offsetY; ctx.setLineWidth(widthLine).setStrokeStyle(strokeColor); fVerLine.apply(ctx, [x1, y1, y2]); ctx.closePath().stroke(); } else if (row != null) { if (!visibleRange.containsRow(row)) { return; } let y = this._getRowTop(row) - offsetY; let x1 = this._getColLeft(visibleRange.c1) - offsetX; let x2 = this._getColLeft(visibleRange.c2 + 1) - offsetX; ctx.setLineWidth(widthLine).setStrokeStyle(strokeColor); fHorLine.apply(ctx, [x1, y, x2]); ctx.closePath().stroke(); } return true; }; WorksheetView.prototype.cleanSelection = function (range, isFrozen) { var api = window["Asc"]["editor"]; if (window['IS_NATIVE_EDITOR']) { return; } if (!this.overlayCtx) { return; } isFrozen = !!isFrozen; if (range === undefined) { range = this.visibleRange; } var ctx = this.overlayCtx; var width = ctx.getWidth(); var height = ctx.getHeight(); var offsetX, offsetY, diffWidth = 0, diffHeight = 0; var x1 = Number.MAX_VALUE; var x2 = -Number.MAX_VALUE; var y1 = Number.MAX_VALUE; var y2 = -Number.MAX_VALUE; var _x1, _x2, _y1, _y2; var i; var arnIntersection; if (this.topLeftFrozenCell) { var cFrozen = this.topLeftFrozenCell.getCol0(); var rFrozen = this.topLeftFrozenCell.getRow0(); diffWidth = this._getColLeft(cFrozen) - this._getColLeft(0); diffHeight = this._getRowTop(rFrozen) - this._getRowTop(0); if (!isFrozen) { var oFrozenRange; cFrozen -= 1; rFrozen -= 1; if (0 <= cFrozen && 0 <= rFrozen) { oFrozenRange = new asc_Range(0, 0, cFrozen, rFrozen); this.cleanSelection(oFrozenRange, true); } if (0 <= cFrozen) { oFrozenRange = new asc_Range(0, this.visibleRange.r1, cFrozen, this.visibleRange.r2); this.cleanSelection(oFrozenRange, true); } if (0 <= rFrozen) { oFrozenRange = new asc_Range(this.visibleRange.c1, 0, this.visibleRange.c2, rFrozen); this.cleanSelection(oFrozenRange, true); } } } if (isFrozen) { if (range.c1 !== this.visibleRange.c1) { diffWidth = 0; } if (range.r1 !== this.visibleRange.r1) { diffHeight = 0; } offsetX = this._getOffsetX(range.c1, true) - diffWidth; offsetY = this._getOffsetY(range.r1, true) - diffHeight; } else { offsetX = this._getOffsetX() - diffWidth; offsetY = this._getOffsetY() - diffHeight; } this._activateOverlayCtx(); var t = this; var isRetinaWidth = this.getRetinaPixelRatio() >= 2; var selectionRange = this.model.getSelection(); const isMacLinuxMozilla = (AscCommon.AscBrowser.isLinuxOS || AscCommon.AscBrowser.isMacOs) && AscCommon.AscBrowser.isMozilla; selectionRange.ranges.forEach(function (item, index) { var arnIntersection = item.intersectionSimple(range); if (arnIntersection) { _x1 = t._getColLeft(arnIntersection.c1) - offsetX - 3 - isMacLinuxMozilla * 1; _x2 = t._getColLeft(arnIntersection.c2 + 1) - offsetX + 1 + /* Это ширина "квадрата" для автофильтра от границы ячейки */2; _y1 = t._getRowTop(arnIntersection.r1) - offsetY - 2 - isRetinaWidth * 1 - isMacLinuxMozilla * 1; _y2 = t._getRowTop(arnIntersection.r2 + 1) - offsetY + 1 + /* Это высота "квадрата" для автофильтра от границы ячейки */2; x1 = Math.min(x1, _x1); x2 = Math.max(x2, _x2); y1 = Math.min(y1, _y1); y2 = Math.max(y2, _y2); if (index === selectionRange.activeCellId) { var size = t.getButtonSize(selectionRange.activeCell.row, selectionRange.activeCell.col, true); x2 += size.w; y2 += size.h; } } if (!isFrozen) { t._cleanColumnHeaders(item.c1, item.c2); t._cleanRowHeaders(item.r1, item.r2); } }); this._deactivateOverlayCtx(); // Если есть активное автозаполнения, то нужно его тоже очистить if (this.activeFillHandle !== null) { var activeFillClone = this.activeFillHandle.clone(true); // Координаты для автозаполнения _x1 = this._getColLeft(activeFillClone.c1) - offsetX - 2 - 1; _x2 = this._getColLeft(activeFillClone.c2 + 1) - offsetX + 1 + 2; _y1 = this._getRowTop(activeFillClone.r1) - offsetY - 2 - 1; _y2 = this._getRowTop(activeFillClone.r2 + 1) - offsetY + 1 + 2; // Выбираем наибольший range для очистки x1 = Math.min(x1, _x1); x2 = Math.max(x2, _x2); y1 = Math.min(y1, _y1); y2 = Math.max(y2, _y2); } if (this.collaborativeEditing.getCollaborativeEditing()) { var currentSheetId = this.model.getId(); var nLockAllType = this.collaborativeEditing.isLockAllOther(currentSheetId); if (Asc.c_oAscMouseMoveLockedObjectType.None !== nLockAllType) { this.overlayCtx.clear(); } else { var arrayElementsMe = this.collaborativeEditing.getLockCellsMe(currentSheetId); var arrayElementsOther = this.collaborativeEditing.getLockCellsOther(currentSheetId); var arrayElements = arrayElementsMe.concat(arrayElementsOther); arrayElements = arrayElements.concat(this.collaborativeEditing.getArrayInsertColumnsBySheetId(currentSheetId)); arrayElements = arrayElements.concat(this.collaborativeEditing.getArrayInsertRowsBySheetId(currentSheetId)); for (i = 0; i < arrayElements.length; ++i) { var arFormulaTmp = new asc_Range(arrayElements[i].c1, arrayElements[i].r1, arrayElements[i].c2, arrayElements[i].r2); var aFormulaIntersection = arFormulaTmp.intersection(range); if (aFormulaIntersection) { // Координаты для автозаполнения _x1 = this._getColLeft(aFormulaIntersection.c1) - offsetX - 2; _x2 = this._getColLeft(aFormulaIntersection.c2 + 1) - offsetX + 1 + 2; _y1 = this._getRowTop(aFormulaIntersection.r1) - offsetY - 2; _y2 = this._getRowTop(aFormulaIntersection.r2 + 1) - offsetY + 1 + 2; // Выбираем наибольший range для очистки x1 = Math.min(x1, _x1); x2 = Math.max(x2, _x2); y1 = Math.min(y1, _y1); y2 = Math.max(y2, _y2); } } } } //TODO пересмотреть! возможно стоит очищать частями в зависимости от print_area //print lines view let isTraceDependents = this.traceDependentsManager.isHaveData(); let searchSpecificRange = this.handlers.trigger('selectSearchingResults') && this.workbook.SearchEngine && this.workbook.SearchEngine.isSpecificRange(); if(this.viewPrintLines || this.getCutRange() || (this.isPageBreakPreview(true) && this.pagesModeData) || searchSpecificRange || isTraceDependents) { this.overlayCtx.clear(); if (isTraceDependents) { this.traceDependentsManager.clearCoordsData(); } } let retinaСoef = isRetinaWidth ? 2 : 1; if (this.oOtherRanges) { this.oOtherRanges.ranges.forEach(function (item) { arnIntersection = item.intersectionSimple(range); if (arnIntersection) { _x1 = t._getColLeft(arnIntersection.c1) - offsetX - 3 * retinaСoef; _x2 = arnIntersection.c2 > t.nColsCount ? width : t._getColLeft(arnIntersection.c2 + 1) - offsetX + 3 *retinaСoef; _y1 = t._getRowTop(arnIntersection.r1) - offsetY - 3 * retinaСoef; _y2 = arnIntersection.r2 > t.nRowsCount ? height : t._getRowTop(arnIntersection.r2 + 1) - offsetY + 3 * retinaСoef; x1 = Math.min(x1, _x1); x2 = Math.max(x2, _x2); y1 = Math.min(y1, _y1); y2 = Math.max(y2, _y2); } }); } if (this.workbook.Api.isShowVisibleAreaOleEditor || this.workbook.Api.isEditVisibleAreaOleEditor) { var oleRange = this.getOleSize().getLast(); arnIntersection = oleRange.intersectionSimple(range); // Координаты для видимой области оле-объекта if (arnIntersection) { _x1 = t._getColLeft(oleRange.c1) - offsetX - 3; _x2 = oleRange.c2 > t.nColsCount ? width : t._getColLeft(oleRange.c2 + 1) - offsetX + 1 + 2; _y1 = t._getRowTop(oleRange.r1) - offsetY - 3; _y2 = oleRange.r2 > t.nRowsCount ? height : t._getRowTop(oleRange.r2 + 1) - offsetY + 1 + 2; // Выбираем наибольший range для очистки x1 = Math.min(x1, _x1); x2 = Math.max(x2, _x2); y1 = Math.min(y1, _y1); y2 = Math.max(y2, _y2); } } if (null !== this.activeMoveRange) { let activeMoveRange = this.activeMoveRange; let colRowMoveProps = this.startCellMoveRange && this.startCellMoveRange.colRowMoveProps; let bInsertBetweenRowCol = !!(colRowMoveProps && colRowMoveProps.shiftKey); if (bInsertBetweenRowCol) { if (colRowMoveProps.colByX != null) { activeMoveRange = new Asc.Range(colRowMoveProps.colByX, activeMoveRange.r1, colRowMoveProps.colByX + 1, activeMoveRange.r2); } else if (colRowMoveProps.rowByY != null) { activeMoveRange = new Asc.Range(activeMoveRange.c1, colRowMoveProps.rowByY, activeMoveRange.c2, colRowMoveProps.rowByY + 1); } } arnIntersection = activeMoveRange.intersectionSimple(range); if (arnIntersection) { // Координаты для перемещения диапазона _x1 = this._getColLeft(arnIntersection.c1) - offsetX - 2 - 1*isRetinaWidth; _x2 = this._getColLeft(arnIntersection.c2 + 1) - offsetX + 1 + 2; _y1 = this._getRowTop(arnIntersection.r1) - offsetY - 2 - 1*isRetinaWidth; _y2 = this._getRowTop(arnIntersection.r2 + 1) - offsetY + 1 + 2; // Выбираем наибольший range для очистки x1 = Math.min(x1, _x1); x2 = Math.max(x2, _x2); y1 = Math.min(y1, _y1); y2 = Math.max(y2, _y2); } } if (this.model.copySelection) { selectionRange = this.model.selectionRange; } else if (this.workbook.isDrawFormatPainter()) { let oData = this.workbook.Api.getFormatPainterData(); selectionRange = null; if(oData && oData.range) { selectionRange = oData.range; } } else { selectionRange = null; } if (selectionRange) { selectionRange.ranges.forEach(function (item) { var arnIntersection = item.intersectionSimple(range); if (arnIntersection) { _x1 = t._getColLeft(arnIntersection.c1) - offsetX - 2; _x2 = t._getColLeft(arnIntersection.c2 + 1) - offsetX + 1 + /* Это ширина "квадрата" для автофильтра от границы ячейки */2; _y1 = t._getRowTop(arnIntersection.r1) - offsetY - 2; _y2 = t._getRowTop(arnIntersection.r2 + 1) - offsetY + 1 + /* Это высота "квадрата" для автофильтра от границы ячейки */2; x1 = Math.min(x1, _x1); x2 = Math.max(x2, _x2); y1 = Math.min(y1, _y1); y2 = Math.max(y2, _y2); } }); } let historyChangedRanges = this.workbook.historyChangedRanges && this.workbook.historyChangedRanges[this.model.Id]; if (historyChangedRanges) { historyChangedRanges.forEach(function (item) { var arnIntersection = item && item.range.intersectionSimple(range); if (arnIntersection) { _x1 = t._getColLeft(arnIntersection.c1) - offsetX - 2; _x2 = t._getColLeft(arnIntersection.c2 + 1) - offsetX + 1 + /* Это ширина "квадрата" для автофильтра от границы ячейки */2; _y1 = t._getRowTop(arnIntersection.r1) - offsetY - 2; _y2 = t._getRowTop(arnIntersection.r2 + 1) - offsetY + 1 + /* Это высота "квадрата" для автофильтра от границы ячейки */2; x1 = Math.min(x1, _x1); x2 = Math.max(x2, _x2); y1 = Math.min(y1, _y1); y2 = Math.max(y2, _y2); } }); } //todo для ретины все сдвиги необходимо сделать общими //clean foreign cursors if ((this.collaborativeEditing.getCollaborativeEditing() || api.isLiveViewer()) && this.collaborativeEditing.getFast()) { var foreignCursors = this.collaborativeEditing.m_aForeignCursorsData; for (var n in foreignCursors) { if (foreignCursors[n] && foreignCursors[n].sheetId === this.model.Id) { for (var j = 0; j < foreignCursors[n].ranges.length; j++) { var _range = foreignCursors[n].ranges[j]; arnIntersection = _range.intersectionSimple(range); if (arnIntersection) { _x1 = t._getColLeft(arnIntersection.c1) - offsetX - 3; _x2 = t._getColLeft(arnIntersection.c2 + 1) - offsetX + 1 + /* Это ширина "квадрата" для автофильтра от границы ячейки */2; _y1 = t._getRowTop(arnIntersection.r1) - offsetY - 2 - isRetinaWidth * 1; _y2 = t._getRowTop(arnIntersection.r2 + 1) - offsetY + 1 + /* Это высота "квадрата" для автофильтра от границы ячейки */2; x1 = Math.min(x1, _x1); x2 = Math.max(x2, _x2); y1 = Math.min(y1, _y1); y2 = Math.max(y2, _y2); } } } } } if (!(Number.MAX_VALUE === x1 && -Number.MAX_VALUE === x2 && Number.MAX_VALUE === y1 && -Number.MAX_VALUE === y2)) { if(this.workbook.Api.wb.MobileTouchManager) { //Add radius of mobile pins var nRad = (AscCommon.MOBILE_SELECT_TRACK_ROUND / 2 + 0.5) >> 0; nRad = AscCommon.AscBrowser.convertToRetinaValue(nRad, true); x1 -= nRad; x2 += nRad; y1 -= nRad; y2 += nRad; } ctx.save() .beginPath(); this._rect(ctx, this.cellsLeft, this.cellsTop, ctx.getWidth() - this.cellsLeft, ctx.getHeight() - this.cellsTop) ctx.clip() this._clearRect(ctx, x1, y1, x2 - x1, y2 - y1) ctx.restore(); } return this; }; WorksheetView.prototype.updateSelection = function () { this.cleanSelection(); this._drawSelection(); }; WorksheetView.prototype.updateSelectionWithSparklines = function () { if (!this.checkSelectionSparkline()) { this._drawSelection(); } }; WorksheetView.prototype.addSparklineGroup = function (type, sDataRange, sLocationRange) { var t = this; if (!sDataRange || !sLocationRange) { sDataRange = "a1:c2"; sLocationRange = "e4:e5"; //return Asc.c_oAscError.ID.DataRangeError; } var locationRange; //временный код. locationRange - должен быть привязан только к текущему листу var dataRange = AscCommonExcel.g_oRangeCache.getRange3D(sDataRange); if (!dataRange) { dataRange = AscCommonExcel.g_oRangeCache.getAscRange(sDataRange); } var result = parserHelp.parse3DRef(sLocationRange); if (result) { var sheetModel = t.model.workbook.getWorksheetByName(result.sheet); if (sheetModel) { locationRange = AscCommonExcel.g_oRangeCache.getAscRange(result.range); } } else { locationRange = AscCommonExcel.g_oRangeCache.getAscRange(sLocationRange); } var addSparkline = function (res) { if (res) { History.Create_NewPoint(); History.StartTransaction(); ws.removeSparklines(locationRange); var modelSparkline = new AscCommonExcel.sparklineGroup(true); modelSparkline.setWorksheet(ws); modelSparkline.set(newSparkLine); modelSparkline.setSparklinesFromRange(dataRange, locationRange, true); ws.addSparklineGroups(modelSparkline); History.EndTransaction(); t.workbook._onWSSelectionChanged(); t.workbook.getWorksheet().draw(); } }; //здесь добавляю проверку данных - поскольку требуется проверка одновременно двух значений var error = AscCommonExcel.sparklineGroup.prototype.isValidDataRef(dataRange, locationRange); if (!error) { //чтобы добавить все данные в историю создаём ещё один sparklineGroup и заполняем его всеми необходимыми опциями var ws = this.model; var newSparkLine = new AscCommonExcel.sparklineGroup(); newSparkLine.default(); newSparkLine.type = type != undefined ? type : Asc.c_oAscSparklineType.Column; this._isLockedCells(locationRange, /*subType*/null, addSparkline); return Asc.c_oAscError.ID.No; } else { this.model.workbook.handlers.trigger("asc_onError", error, c_oAscError.Level.NoCritical); } }; // mouseX - это разница стартовых координат от мыши при нажатии и границы WorksheetView.prototype.drawColumnGuides = function ( col, x, y, mouseX ) { // Учитываем координаты точки, где мы начали изменение размера x += mouseX; var ctx = this.overlayCtx; var offsetX = this._getOffsetX(); var offsetFrozen = this.getFrozenPaneOffset( false, true ); offsetX -= offsetFrozen.offsetX; var x1 = this._getColLeft(col) - offsetX - gridlineSize; var h = ctx.getHeight(); var width = Asc.round((this.getRightToLeft() ? (this.getCtxWidth() - x1) - x : (x - x1)) / (this.getZoom(true) * this.getRetinaPixelRatio())); if ( 0 > width ) { width = 0; } if (this.getRightToLeft()) { x1 = this.drawingCtx.getWidth() - x1; } ctx.clear(); this._drawSelection(); ctx.setFillPattern( this.settings.ptrnLineDotted1 ) .fillRect( x1, 0, 1, h ) .fillRect( x, 0, 1, h ); return new asc_CMM( { type : Asc.c_oAscMouseMoveType.ResizeColumn, sizeCCOrPt: this.model.colWidthToCharCount(width), sizePx : width, x : AscCommon.AscBrowser.convertToRetinaValue( this.getRightToLeft() ? x1 : x1 + this._getColumnWidth(col)), y : AscCommon.AscBrowser.convertToRetinaValue(this.cellsTop) } ); }; // mouseY - это разница стартовых координат от мыши при нажатии и границы WorksheetView.prototype.drawRowGuides = function ( row, x, y, mouseY ) { // Учитываем координаты точки, где мы начали изменение размера y += mouseY; var ctx = this.overlayCtx; var offsetY = this._getOffsetY(); var offsetFrozen = this.getFrozenPaneOffset( true, false ); offsetY -= offsetFrozen.offsetY; var y1 = this._getRowTop(row) - offsetY - gridlineSize; var w = ctx.getWidth(); var height = Asc.round((y - y1) / this.getZoom()); if ( 0 > height ) { height = 0; } ctx.clear(); this._drawSelection(); ctx.setFillPattern( this.settings.ptrnLineDotted1 ) .fillRect( 0, y1, w, 1 ) .fillRect( 0, y, w, 1 ); return new asc_CMM( { type : Asc.c_oAscMouseMoveType.ResizeRow, sizeCCOrPt: AscCommonExcel.convertPxToPt(height), sizePx : height, x : AscCommon.AscBrowser.convertToRetinaValue(this.getRightToLeft() ? (this.getCtxWidth() - this.cellsLeft) : this.cellsLeft), y : AscCommon.AscBrowser.convertToRetinaValue(y1 + this._getRowHeight(row)) } ); }; // --- Cache --- WorksheetView.prototype._cleanCache = function (range) { var s = this.cache.sectors; var rows = this.cache.rows; if (range === undefined) { range = this.model.selectionRange.getLast(); } // ToDo now delete all. Change this code for (var i = Asc.floor(range.r1 / kRowsCacheSize), l = Asc.floor(range.r2 / kRowsCacheSize); i <= l; ++i) { //TODO while remove sectors checks. don't clean all need rows // rows added in _fetchRowCache and sectors did'nt init //if (s[i]) { for (var j = i * kRowsCacheSize, k = (i + 1) * kRowsCacheSize; j < k; ++j) { delete rows[j]; } delete s[i]; //} } }; WorksheetView.prototype._checkCacheInitSector = function (row) { var s = this.cache.sectors; var sectorNumber = Asc.floor(row / kRowsCacheSize); if (!s[sectorNumber]) { s[sectorNumber] = true; } }; // ----- Cell text cache ----- /** Очищает кэш метрик текста ячеек */ WorksheetView.prototype._cleanCellsTextMetricsCache = function () { this.cache.sectors = []; }; /** * Обновляет общий кэш и кэширует метрики текста ячеек для указанного диапазона * @param {Asc.Range} [range] Диапазон кэширования текта */ WorksheetView.prototype._prepareCellTextMetricsCache = function (range) { var firstUpdateRow = null; if (!range) { range = this.visibleRange; if (this.topLeftFrozenCell) { var row = this.topLeftFrozenCell.getRow0(); if (0 < row) { firstUpdateRow = asc.getMinValueOrNull(firstUpdateRow, this._prepareCellTextMetricsCache2(0, row - 1)); } } } firstUpdateRow = asc.getMinValueOrNull(firstUpdateRow, this._prepareCellTextMetricsCache2(range.r1, range.r2)); if (null !== firstUpdateRow || this.isChanged) { // Убрал это из _calcCellsTextMetrics, т.к. вызов был для каждого сектора(добавляло тормоза: баг 20388) // Код нужен для бага http://bugzilla.onlyoffice.com/show_bug.cgi?id=13875 this._updateRowPositions(); this._calcVisibleRows(); if (this.objectRender) { this.objectRender.updateDrawingsTransform({target: c_oTargetType.RowResize, row: firstUpdateRow}); } } }; /** * Обновляет общий кэш и кэширует метрики текста ячеек для указанного диапазона (сама реализация, напрямую не вызывать, только из _prepareCellTextMetricsCache) * @param {Number} [r1] r1-r2 диапазон кэширования текта * @param {Number} [r2] r1-r2 диапазон кэширования текта */ WorksheetView.prototype._prepareCellTextMetricsCache2 = function (r1, r2) { var firstUpdateRow = null; var s = this.cache.sectors; for (var i = Asc.floor(r1 / kRowsCacheSize), l = Asc.floor(r2 / kRowsCacheSize); i <= l; ++i) { if (!s[i]) { if (null === firstUpdateRow) { firstUpdateRow = i * kRowsCacheSize; } s[i] = true; this._calcCellsTextMetrics(i * kRowsCacheSize, (i + 1) * kRowsCacheSize - 1); } } return firstUpdateRow; }; /** * Кэширует метрики текста для диапазона ячеек */ WorksheetView.prototype._calcCellsTextMetrics = function (r1, r2) { var t = this; var c2 = this.cols.length === 0 ? this.model.getColsCount() - 1 : this.cols.length - 1; this.model.getRange3(r1, 0, r2, c2)._foreachNoEmpty(function(cell, row, col) { t._addCellTextToCache(col, row); }, null, true); this.isChanged = false; }; WorksheetView.prototype._fetchRowCache = function (row) { return (this.cache.rows[row] = (this.cache.rows[row] || new CacheElement())); }; WorksheetView.prototype._fetchCellCache = function (col, row) { var r = this._fetchRowCache(row); return (r.columns[col] = (r.columns[col] || new CacheElementText())); }; WorksheetView.prototype._fetchCellCacheText = function (col, row) { var r = this._fetchRowCache(row); return (r.columnsWithText[col] = (r.columnsWithText[col] || true)); }; WorksheetView.prototype._getRowCache = function (row) { return this.cache.rows[row]; }; WorksheetView.prototype._getCellCache = function (col, row) { var r = this.cache.rows[row]; return r && r.columnsWithText[col] && r.columns[col]; }; WorksheetView.prototype._getCellTextCache = function (col, row, dontLookupMergedCells) { var c = this._getCellCache(col, row); if (c) { return c; } else if (!dontLookupMergedCells) { // ToDo проверить это условие, возможно оно избыточно var range = this.model.getMergedByCell(row, col); return null !== range ? this._getCellTextCache(range.c1, range.r1, true) : undefined; } return undefined; }; WorksheetView.prototype._changeColWidth = function (col, width) { var oldColWidth = this.getColumnWidthInSymbols(col); var pad = this.settings.cells.padding * 2 + 1; //поскольку width - приходит с учётом зума, то и pad нужно домоножить на зум + далее результат делим на зум, соответсвенно если pad не будет домножен на зум, то в результате будет неточность var zoomScale = this.getZoom(true) * this.getRetinaPixelRatio(); var cc = Math.min(this.model.colWidthToCharCount((width + pad * zoomScale) / (zoomScale)), Asc.c_oAscMaxColumnWidth); if (cc > oldColWidth) { History.Create_NewPoint(); History.StartTransaction(); // Выставляем, что это bestFit this.model.setColBestFit(true, this.model.charCountToModelColWidth(cc), col, col); History.EndTransaction(); // ToDo update cells with shrink to fit this._calcColWidth(col); } }; WorksheetView.prototype._addCellTextToCache = function (col, row, opt_GenerateCacheObj) { let self = this; function makeFnIsGoodNumFormat(flags, width, isWidth) { return function (str) { let widthStr; let widthWithoutZoom = null; if (isWidth && self.workbook.printPreviewState && self.workbook.printPreviewState.isStart()) { //заглушка для печати //попробовать перейти на все расчёты как при 100%(потом * zoom) // но в данном случае есть проблемы с измерением текста //получаем ширину колонки как при 100% и длину строки как при 100%, чтобы не было разницы let _scale = self.getZoom(true)*self.getRetinaPixelRatio(); let _innerDiff = self.settings.cells.padding * 2 + gridlineSize; widthWithoutZoom = Math.ceil((width + _innerDiff - _innerDiff*_scale)/_scale); let realPpiX = self.stringRender.drawingCtx.ppiX; let realPpiY = self.stringRender.drawingCtx.ppiY; let realScaleFactor = self.stringRender.drawingCtx.scaleFactor; self.stringRender.drawingCtx.ppiX = 96; self.stringRender.drawingCtx.ppiY = 96; self.stringRender.drawingCtx.scaleFactor = 1; self.stringRender.fontNeedUpdate = true; widthStr = self.stringRender.measureString(str, flags, width).width; self.stringRender.drawingCtx.ppiX = realPpiX; self.stringRender.drawingCtx.ppiY = realPpiY; self.stringRender.drawingCtx.scaleFactor = realScaleFactor; self.stringRender.fontNeedUpdate = true; } else { widthStr = self.stringRender.measureString(str, flags, width).width; } return widthStr <= (widthWithoutZoom !== null ? widthWithoutZoom : width); }; } let c = this._getCell(col, row); if (null === c || !this.model.isUserProtectedRangesCanView({nCol: col, nRow: row})) { return col; } let showFormulas = false; let viewSettings = this.model.getSheetView(); if (viewSettings && viewSettings.showFormulas) { showFormulas = true; } let getValue2Func = showFormulas ? c.getValueForEdit2 : c.getValue2; let str, tm, strCopy; // Range для замерженной ячейки let fl = this._getCellFlags(c); let mc = fl.merged; if (null !== mc) { if (col !== mc.c1 || row !== mc.r1) { // Проверим внесена ли первая ячейка в cache (иначе если была скрыта первая строка или первый столбец, то мы не внесем) if (undefined === this._getCellTextCache(mc.c1, mc.r1, true)) { return this._addCellTextToCache(mc.c1, mc.r1); } // skip other merged cell from range return mc.c2; } } let mergeType = fl.getMergeType(); let align = c.getAlign(); let va = align.getAlignVertical(); if (va == null && showFormulas) { va = Asc.c_oAscVAlign.Bottom; } let angle = align.getAngle(); let indent = align.getIndent(); if (indent < 0) { indent = 0; } if (align.hor === AscCommon.align_Distributed) { fl.wrapText = true; fl.textAlign = AscCommon.align_Center; } if (c.isEmptyTextString()) { if (!angle && c.isNotDefaultFont() && !(mergeType & c_oAscMergeType.rows)) { // Пустая ячейка с измененной гарнитурой или размером, учитвается в высоте str = getValue2Func.call(c); if (0 < str.length) { strCopy = str[0]; //this.isZooming - in default case(with text) every time recalculate text size -> update row height //this.isZooming -> fix for start editor with system zoom if (!(tm = AscCommonExcel.g_oCacheMeasureEmpty.get(strCopy.format)) || this.isZooming) { // Без текста не будет толка strCopy = strCopy.clone(); strCopy.setFragmentText('A'); tm = this._roundTextMetrics(this.stringRender.measureString([strCopy], fl)); AscCommonExcel.g_oCacheMeasureEmpty.add(strCopy.format, tm); } let cache = this._fetchCellCache(col, row); cache.metrics = tm; this._updateRowHeight(cache, row); } } return mc ? mc.c2 : col; } let verticalText = fl.verticalText = angle === AscCommonExcel.g_nVerticalTextAngle; let dDigitsCount = 0; let colWidth = 0; let cellType = c.getType(); fl.isNumberFormat = (null === cellType || CellValueType.String !== cellType); // Автоподбор делается по любому типу (кроме строки) let numFormatStr = c.getNumFormatStr(); let pad = this.settings.cells.padding * 2 + 1; let sstr, sfl, stm; let isCustomWidth = this.model.getColCustomWidth(col) || verticalText; let angleSin = Math.sin(angle * Math.PI / 180.0); let angleCos = Math.cos(angle * Math.PI / 180.0); if (!isCustomWidth && fl.isNumberFormat && !fl.shrinkToFit && !(mergeType & c_oAscMergeType.cols) && c_oAscCanChangeColWidth.none !== this.canChangeColWidth) { colWidth = this._getColumnWidthInner(col); // Измеряем целую часть числа sstr = getValue2Func.call(c, gc_nMaxDigCountView, function () { return true; }); if ("General" === numFormatStr && c_oAscCanChangeColWidth.all !== this.canChangeColWidth) { sstr = AscCommonExcel.dropDecimalAutofit(sstr); } sfl = fl.clone(); sfl.wrapText = false; stm = this._roundTextMetrics(this.stringRender.measureString(sstr, sfl, colWidth)); let stmPrj = Math.abs(angleCos * stm.width) + Math.abs(angleSin * stm.height); // Если целая часть числа не убирается в ячейку, то расширяем столбец if (stmPrj > colWidth) { this._changeColWidth(col, stmPrj); } // Обновленная ячейка dDigitsCount = this.getColumnWidthInSymbols(col); colWidth = this._getColumnWidthInner(col); } else if (null === mc) { // Обычная ячейка dDigitsCount = this.getColumnWidthInSymbols(col); colWidth = this._getColumnWidthInner(col); // подбираем ширину if (!isCustomWidth && !fl.shrinkToFit && !(mergeType & c_oAscMergeType.cols) && !fl.wrapText && c_oAscCanChangeColWidth.all === this.canChangeColWidth) { sstr = getValue2Func.call(c, gc_nMaxDigCountView, function () { return true; }); stm = this._roundTextMetrics(this.stringRender.measureString(sstr, fl, colWidth)); let stmPrj = Math.abs(angleCos * stm.width) + Math.abs(angleSin * stm.height); if (stmPrj > colWidth) { this._changeColWidth(col, stmPrj); // Обновленная ячейка dDigitsCount = this.getColumnWidthInSymbols(col); colWidth = this._getColumnWidthInner(col); } } } else { // Замерженная ячейка, нужна сумма столбцов for (let i = mc.c1; i <= mc.c2 && i < this.cols.length; ++i) { colWidth += this._getColumnWidth(i); dDigitsCount += this.getColumnWidthInSymbols(i); } colWidth -= pad; } let rowHeight = this._getRowHeight(row); // ToDo dDigitsCount нужно рассчитывать исходя не из дефалтового шрифта и размера, а исходя из текущего шрифта и размера ячейки if (angle === 0 && !fl.shrinkToFit) { str = getValue2Func.call(c, dDigitsCount, makeFnIsGoodNumFormat(fl, colWidth, true)); } else { str = getValue2Func.call(c); } let alignH = align.getAlignHorizontal(); if (showFormulas) { if (alignH == null || fl.isNumberFormat) { alignH = AscCommon.align_Left; } } let ha = c.getAlignHorizontalByValue(alignH); let maxW = fl.wrapText || fl.shrinkToFit || mergeType || asc.isFixedWidthCell(str) ? this._calcMaxWidth(col, row, mc) : undefined; if (verticalText) { fl.textAlign = ha = alignH === null ? AscCommon.align_Center : alignH; angle = 0; } if (indent && AscCommon.align_Distributed === alignH) { maxW -= 2 * indent * 3 * this.defaultSpaceWidth; } if (fl.wrapText) { maxW -= indent * 3 * this.defaultSpaceWidth; } //чтобы грамотно расчитать высоту строки, необходимо знать размер текста в ячейке. если скрыт столбец, то maxW всегда будет 0 и расчёт measureString будет неверным //добавляю следующую заглушку для этого - _getColumnWidthIgnoreHidden tm = this._roundTextMetrics(this.stringRender.measureString(str, fl, maxW === 0 ? Math.max(this._getColumnWidthIgnoreHidden(col) - this.settings.cells.padding * 2 - gridlineSize, 0) : maxW)); if (indent) { let printZoom = this.workbook.printPreviewState && this.workbook.printPreviewState.isStart() ? this.getZoom() : 1; let _defaultSpaceWidth = this.defaultSpaceWidth * printZoom; if (verticalText) { if (Asc.c_oAscVAlign.Bottom === va) { tm.height += indent * 3 * _defaultSpaceWidth; } else if (Asc.c_oAscVAlign.Top === va) { tm.height += indent * 3 * _defaultSpaceWidth; } } else { if (AscCommon.align_Right === alignH) { tm.width += indent * 3 * _defaultSpaceWidth + 1 * printZoom; } else if (AscCommon.align_Left === alignH) { tm.width += indent * 3 * _defaultSpaceWidth; } } } let cto = (mergeType || fl.wrapText || fl.shrinkToFit || showFormulas) ? { maxWidth: maxW - this._getColumnWidthInner(col) + this._getColumnWidth(col), leftSide: 0, rightSide: 0 } : this._calcCellTextOffset(col, row, ha, tm.width); let textBound = {}; if (angle) { // повернутый текст учитывает мерж ячеек по строкам if (mergeType & c_oAscMergeType.rows) { rowHeight = 0; for (let j = mc.r1; j <= mc.r2 && j < this.nRowsCount; ++j) { rowHeight += this._getRowHeight(j); } } let textW = tm.width; if (fl.wrapText) { if (this.model.getRowCustomHeight(row)) { tm = this._roundTextMetrics(this.stringRender.measureString(str, fl, rowHeight)); textBound = this.stringRender.getTransformBound(angle, colWidth, rowHeight, tm.width, ha, va, rowHeight); } else { if (!(mergeType & c_oAscMergeType.rows)) { rowHeight = tm.height; } tm = this._roundTextMetrics(this.stringRender.measureString(str, fl, rowHeight)); textBound = this.stringRender.getTransformBound(angle, colWidth, rowHeight, tm.width, ha, va, tm.width); } } else { textBound = this.stringRender.getTransformBound(angle, colWidth, rowHeight, textW, ha, va, maxW); } // NOTE: если проекция строчки на Y больше высоты ячейки подставлять # и рисовать все по центру if (fl.isNumberFormat) { let textMetricWidth = textW; if (textBound.width > textW) { textMetricWidth = textBound.width; } if (textBound.height > textW) { textMetricWidth = textBound.height; } let prj = Math.ceil(Math.abs(Math.sin(angle * Math.PI / 180.0) * textMetricWidth)); if (prj >= rowHeight) { maxW = rowHeight; str = getValue2Func.call(c, dDigitsCount, makeFnIsGoodNumFormat(fl, rowHeight)); tm = this._roundTextMetrics(this.stringRender.measureString(str, fl, maxW)); if (str[0].format.repeat) { let angleSin = Math.sin(angle * Math.PI / 180.0); if (angle > 0) { textBound.dx = (colWidth - tm.height) / 2; } if (angle < 0) { textBound.dx = (colWidth - tm.height * angleSin) / 2; textBound.dy = (rowHeight - tm.width) / 2; } ha = 0; } } } textBound.height += 3; textBound.dy -= 1.5; } let cache = opt_GenerateCacheObj ? new CacheElementText() : this._fetchCellCache(col, row); cache.state = this.stringRender.getInternalState(); cache.flags = fl; cache.metrics = tm; cache.cellW = cto.maxWidth; cache.cellHA = ha; cache.cellVA = va; cache.sideL = cto.leftSide; cache.sideR = cto.rightSide; cache.cellType = cellType; cache.isFormula = c.isFormula(); cache.angle = angle; cache.textBound = textBound; cache.indent = indent; if (opt_GenerateCacheObj) { return cache; } this._fetchCellCacheText(col, row); //this._checkCacheInitSector(row); if (!angle && !verticalText && (cto.leftSide !== 0 || cto.rightSide !== 0)) { this._addErasedBordersToCache(col - cto.leftSide, col + cto.rightSide, row); } this._updateRowHeight(cache, row, maxW, colWidth); return mc ? mc.c2 : col; }; WorksheetView.prototype._updateRowHeight2 = function (cell) { var fr, fm, lm, f; var align = cell.getAlign(); var angle = align.getAngle(); var va = align.getAlignVertical(); var rowInfo = this.rows[cell.nRow]; var updateDescender = (va === Asc.c_oAscVAlign.Bottom && !angle); var d = this._getRowDescender(cell.nRow); if (cell.getValueMultiText()) { fr = cell.getValue2(); } else { fr = [new AscCommonExcel.Fragment()]; fr[0].format = cell.getFont(); } var th; var cellType = cell.getType(); var wrap = align.getWrap() || align.hor === AscCommon.align_Distributed; // Автоподбор делается по любому типу (кроме строки) var isNumberFormat = !cell.isEmptyTextString() && (null === cellType || CellValueType.String !== cellType); if (angle || isNumberFormat || wrap) { this._addCellTextToCache(cell.nCol, cell.nRow); th = this.updateRowHeightValuePx || AscCommonExcel.convertPtToPx(this._getRowHeightReal(cell.nRow)); } else { th = this.updateRowHeightValuePx || AscCommonExcel.convertPtToPx(this._getRowHeightReal(cell.nRow)); // ToDo with angle and wrap for (var i = 0; i < fr.length; ++i) { f = fr[i].format; if (!f.isEqual2(AscCommonExcel.g_oDefaultFormat.Font) || f.va) { fm = getFontMetrics(f, this.stringRender); lm = this.stringRender._calcLineMetrics2(f.getSize(), f.va, fm); th = Math.min(this.maxRowHeightPx, Math.max(th, lm.th)); if (updateDescender && !f.va) { d = Math.max(d, lm.th - lm.bl); } } } } rowInfo.height = this.workbook.printPreviewState.isStart() ? th * this.getZoom() : Asc.round(th * this.getZoom()); rowInfo._heightForPrint = this.updateRowHeightValuePx ? AscCommonExcel.convertPxToPt(this.updateRowHeightValuePx) : this._getRowHeightReal(cell.nRow); rowInfo.descender = d; return th; }; WorksheetView.prototype._updateRowHeight = function (cache, row, maxW, colWidth) { if (this.skipUpdateRowHeight) { return; } var res = null; var mergeType = cache.flags && cache.flags.getMergeType(); //not find a case where the ms does not update the height with the columns merged ans wrap var isMergedRows = (mergeType & c_oAscMergeType.rows)/* || (mergeType && cache.flags.wrapText)*/; var tm = cache.metrics; let mergedWrapHeight = null; if (mergeType && cache.flags.wrapText) { if (cache.angle) { isMergedRows = true; } else { //ms use ht if multitext cell inside and use text 1 line height metrics if not multitext //while such as detect different text settings into 1 cell. probably, need get info from model let textHeight; if (cache.state && cache.state.lines) { for (let i = 0 ; i < cache.state.lines.length; i++) { if (!textHeight) { textHeight = cache.state.lines[i].th; } else if (textHeight !== cache.state.lines[i].th) { textHeight = null; break; } } } if (textHeight) { mergedWrapHeight = textHeight; } else { let _rowHeight = AscCommonExcel.convertPtToPx(this.model.getRowHeight(row)); if (_rowHeight && !isNaN(_rowHeight)) { mergedWrapHeight = _rowHeight; } } } } var va = cache.cellVA; var textBound = cache.textBound; var rowInfo = this.rows[row]; // update row's descender if (rowInfo && va !== Asc.c_oAscVAlign.Top && va !== Asc.c_oAscVAlign.Center && !mergeType && !cache.angle) { // ToDo move descender in model var newDescender = tm.height - tm.baseline; if (newDescender > this._getRowDescender(row)) { rowInfo.descender = newDescender; } } var isCustomHeight = this.model.getRowCustomHeight(row); // update row's height // Замерженная ячейка (с 2-мя или более строками) не влияет на высоту строк! if (!isCustomHeight && !(window["NATIVE_EDITOR_ENJINE"] && this.notUpdateRowHeight) && !isMergedRows) { var newHeight = mergedWrapHeight ? mergedWrapHeight : tm.height; var oldHeight = this.updateRowHeightValuePx || AscCommonExcel.convertPtToPx(this._getRowHeightReal(row)); if (cache.angle && textBound) { newHeight = Math.max(oldHeight, textBound.height / this.getZoom()); } newHeight = Math.min(this.maxRowHeightPx, Math.max(oldHeight, newHeight)); if (newHeight !== oldHeight) { if (this.updateRowHeightValuePx) { this.updateRowHeightValuePx = newHeight; } //TODO правлю на хотфикс ошибку. это следствие, а не причина. нужно пересмотреть! баг 50489 var _rowHeight = this.workbook.printPreviewState.isStart() ? newHeight * this.getZoom() : Asc.round(newHeight * this.getZoom()); if (rowInfo) { rowInfo.height = _rowHeight; rowInfo._heightForPrint = AscCommonExcel.convertPxToPt(_rowHeight); } History.TurnOff(); res = newHeight; var oldExcludeCollapsed = this.model.bExcludeCollapsed; this.model.bExcludeCollapsed = true; // ToDo delete setRowHeight here // TODO temporary add limit, because minimal zoom change not correct row height if (this.getZoom() >= 0.5) { this.model.setRowHeight(AscCommonExcel.convertPxToPt(newHeight), row, row, false); } this.model.bExcludeCollapsed = oldExcludeCollapsed; History.TurnOn(); if (cache.angle) { if (cache.flags.wrapText && !isCustomHeight) { maxW = tm.width; } cache.textBound = this.stringRender.getTransformBound(cache.angle, colWidth, _rowHeight, tm.width, cache.cellHA, va, maxW); } this.isChanged = true; } } return res; }; WorksheetView.prototype._updateRowsHeight = function () { if (0 === this.arrRecalcRangesWithHeight.length) { return null; } var canChangeColWidth = this.canChangeColWidth; var t = this; var duplicate = {}; var range, cache, row, minRow = gc_nMaxRow0; for (var i = 0; i < this.arrRecalcRangesWithHeight.length; ++i) { range = this.arrRecalcRangesWithHeight[i]; this.canChangeColWidth = this.arrRecalcRangesCanChangeColWidth[i]; this.model.getRowIterator(range.r1, 0, gc_nMaxCol0, function(itRow) { for (var r = range.r1; r <= range.r2 && r < t.rows.length; duplicate[r++] = 1) { if (duplicate[r]) { continue; } if (t.model.getRowCustomHeight(r)) { t._calcHeightRow(0, r); continue; } t.updateRowHeightValuePx = t.defaultRowHeightPx; row = t.rows[r]; row.height = t.workbook.printPreviewState.isStart() ? t.defaultRowHeightPx * t.getZoom() : Asc.round(t.defaultRowHeightPx * t.getZoom()); row._heightForPrint = null; row.descender = t.defaultRowDescender; cache = t._getRowCache(r); itRow.setRow(r); var cell; while (cell = itRow.next()) { if (c_oAscMergeType.rows & getMergeType(t.model.getMergedByCell(cell.nRow, cell.nCol))) { continue; } t.updateRowHeightValuePx = (cache && cache[cell.nCol] ? t._updateRowHeight(cache[cell.nCol], r) : t._updateRowHeight2(cell)) || t.updateRowHeightValuePx; } if (t.updateRowHeightValuePx) { History.TurnOff(); var oldExcludeCollapsed = t.model.bExcludeCollapsed; t.model.bExcludeCollapsed = true; t.model.setRowHeight(AscCommonExcel.convertPxToPt(t.updateRowHeightValuePx), r, r, false); t.model.bExcludeCollapsed = oldExcludeCollapsed; History.TurnOn(); } minRow = Math.min(minRow, range.r1); } }); } this.updateRowHeightValuePx = null; this.arrRecalcRangesWithHeight = []; this.arrRecalcRangesCanChangeColWidth = []; this.canChangeColWidth = canChangeColWidth; this._updateRowPositions(); return minRow; }; WorksheetView.prototype._updateColsWidth = function () { if (0 === this.arrRecalcRangesWithHeight.length) { return null; } var t = this; var duplicate = {}; var range; for (var i = 0; i < this.arrRecalcRangesWithHeight.length; ++i) { range = this.arrRecalcRangesWithHeight[i]; for (var c = range.c1; c <= range.c2 && c < t.cols.length; duplicate[c++] = 1) { if (duplicate[c]) { continue; } if (t.model.getColCustomWidth(c)) { t._calcColWidth(c); } } } this._updateColumnPositions(); }; WorksheetView.prototype._calcMaxWidth = function (col, row, mc) { if (null === mc) { return this._getColumnWidthInner(col); } return this._getColumnWidthInner(mc.c1) + (this._getColLeft(mc.c2 + 1) - this._getColLeft(mc.c1 + 1)); }; WorksheetView.prototype._calcCellTextOffset = function (col, row, textAlign, textWidth) { var ls = 0, rs = 0, i, size; var width = this._getColumnWidth(col); textWidth = textWidth + this.settings.cells.padding; if (textAlign === AscCommon.align_Center || textAlign === AscCommon.align_Distributed) { textWidth /= 2; width /= 2; } if (this.getRightToLeft()) { if (textAlign === AscCommon.align_Left) { textAlign = AscCommon.align_Right; } else if (textAlign === AscCommon.align_Right) { textAlign = AscCommon.align_Left; } } var maxWidth = 0; if (textAlign !== AscCommon.align_Left) { size = width; for (i = col - 1; i >= 0 && this._isCellEmptyOrMerged(i, row); --i) { if (textWidth <= size) { break; } size += this._getColumnWidth(i); } ls = Math.max(col - i - 1, 0); maxWidth += size; } if (textAlign !== AscCommon.align_Right) { size = width; for (i = col + 1; i < gc_nMaxCol && this._isCellEmptyOrMerged(i, row); ++i) { if (textWidth <= size) { break; } size += this._getColumnWidth(i); } rs = Math.max(i - col - 1, 0); maxWidth += size; } return { maxWidth: maxWidth, leftSide: ls, rightSide: rs }; }; WorksheetView.prototype._calcCellsWidth = function (colBeg, colEnd, row) { var inc = colBeg <= colEnd ? 1 : -1, res = []; for (var i = colBeg; (colEnd - i) * inc >= 0; i += inc) { if (i !== colBeg && !this._isCellEmptyOrMerged(i, row)) { break; } res.push(this._getColumnWidth(i)); if (res.length > 1) { res[res.length - 1] += res[res.length - 2]; } } return res; }; // If this cell with overlap text return index of column WorksheetView.prototype._findOverlapCell = function (col, row) { var r = this._getRowCache(row); if (r) { for (var i in r.columnsWithText) { if (!r.columns[i] || 0 === this._getColumnWidth(i)) { continue; } var ct = r.columns[i]; if (!ct) { continue; } i >>= 0; if (col === i) { continue; } var lc = i - ct.sideL, rc = i + ct.sideR; if (col >= lc && col <= rc) { return i; } } } return -1; }; // ----- Merged cells cache ----- WorksheetView.prototype._isMergedCells = function (range) { return range.isEqual(this.model.getMergedByCell(range.r1, range.c1)); }; // ----- Cell borders cache ----- WorksheetView.prototype._addErasedBordersToCache = function (colBeg, colEnd, row) { var rc = this._fetchRowCache(row); for (var col = colBeg; col < colEnd; ++col) { rc.erased[col] = true; } }; WorksheetView.prototype._isLeftBorderErased = function (col, rowCache) { return rowCache && rowCache.erased[col - 1] === true; }; WorksheetView.prototype._isRightBorderErased = function (col, rowCache) { return rowCache && rowCache.erased[col] === true; }; WorksheetView.prototype._calcMaxBorderWidth = function (b1, b2) { // ToDo пересмотреть return Math.max(b1 && b1.w, b2 && b2.w); }; // ----- Cells utilities ----- /** * Возвращает заголовок колонки по индексу * @param {Number} col Индекс колонки * @return {String} */ WorksheetView.prototype._getColumnTitle = function (col) { return AscCommonExcel.g_R1C1Mode ? this._getRowTitle(col) : AscCommon.g_oCellAddressUtils.colnumToColstrFromWsView(col + 1); }; /** * Возвращает заголовок строки по индексу * @param {Number} row Индекс строки * @return {String} */ WorksheetView.prototype._getRowTitle = function (row) { return "" + (row + 1); }; /** * Возвращает ячейку таблицы (из Worksheet) * @param {Number} col Индекс колонки * @param {Number} row Индекс строки * @return {Range} */ WorksheetView.prototype._getCell = function (col, row) { if (col < 0 || col > gc_nMaxCol0 || row < 0 || row > this.gc_nMaxRow0) { return null; } return this.model.getCell3(row, col); }; WorksheetView.prototype._getVisibleCell = function (col, row) { return this.model.getCell3(row, col); }; WorksheetView.prototype._getCellFlags = function (col, row) { var c = row !== undefined ? this._getCell(col, row) : col; var fl = new CellFlags(); if (null !== c) { var align = c.getAlign(); fl.wrapText = align.getWrap(); fl.shrinkToFit = fl.wrapText ? false : align.getShrinkToFit(); fl.merged = c.hasMerged(); fl.textAlign = c.getAlignHorizontalByValue(align.getAlignHorizontal()); fl.readingOrder = align.getReadingOrder(); } return fl; }; WorksheetView.prototype._isCellNullText = function (col, row) { var c = row !== undefined ? this._getCell(col, row) : col; return null === c || c.isNullText(); }; WorksheetView.prototype._isCellEmptyOrMerged = function (col, row) { var c = row !== undefined ? this._getCell(col, row) : col; return null === c || (c.isNullText() && null === c.hasMerged()); }; WorksheetView.prototype._getRange = function (c1, r1, c2, r2) { return this.model.getRange3(r1, c1, r2, c2); }; WorksheetView.prototype._selectColumnsByRange = function () { var ar = this.model.selectionRange.getLast(); var type = ar.getType(); if (c_oAscSelectionType.RangeMax !== type) { this.cleanSelection(); if (c_oAscSelectionType.RangeRow === type) { ar.assign(0, 0, gc_nMaxCol0, gc_nMaxRow0); } else { ar.assign(ar.c1, 0, ar.c2, gc_nMaxRow0); } this._drawSelection(); this._updateSelectionNameAndInfo(); } }; WorksheetView.prototype._selectRowsByRange = function () { var ar = this.model.selectionRange.getLast(); var type = ar.getType(); if (c_oAscSelectionType.RangeMax !== type) { this.cleanSelection(); if (c_oAscSelectionType.RangeCol === type) { ar.assign(0, 0, gc_nMaxCol0, gc_nMaxRow0); } else { ar.assign(0, ar.r1, gc_nMaxCol0, ar.r2); } this._drawSelection(); this._updateSelectionNameAndInfo(); } }; WorksheetView.prototype._selectAllByRange = function () { var ar = this.model.selectionRange.getLast(); var type = ar.getType(); if (this.isMultiSelect() || c_oAscSelectionType.RangeCol === type || c_oAscSelectionType.RangeRow === type) { this._selectColumnsByRange(); this._selectRowsByRange(); } else if (c_oAscSelectionType.RangeMax !== type) { this.cleanSelection(); if (c_oAscSelectionType.RangeCol === type || c_oAscSelectionType.RangeRow === type) { ar.assign(0, 0, gc_nMaxCol0, gc_nMaxRow0); } else { let ar = this.model.selectionRange.getLast(); let newRange; let tableParts = this.model.TableParts; if (tableParts && tableParts.length) { for (let i = 0; i < tableParts.length; i++) { if (tableParts[i].Ref.containsRange(ar)) { //into body table let _dataRange = tableParts[i].getTableRangeForFormula({param: AscCommon.FormulaTablePartInfo.data}); if (_dataRange && _dataRange.containsRange(ar) && !_dataRange.isEqual(ar)) { newRange = _dataRange; } else if (!tableParts[i].Ref.isEqual(ar)) { newRange = tableParts[i].Ref; } else { newRange = ar; } break; } } } if (!newRange) { newRange = this.model.autoFilters.expandRange(ar, true, true, true); } if (newRange) { if (newRange.isEqual(ar)) { ar.assign(0, 0, gc_nMaxCol0, gc_nMaxRow0); } else { ar.assign(newRange.c1, newRange.r1, newRange.c2, newRange.r2); } } } this._drawSelection(); this._updateSelectionNameAndInfo(); } }; /** * Возвращает true, если диапазон больше видимой области, и операции над ним могут привести к задержкам * @param {Asc.Range} range Диапазон для проверки * @returns {Boolean} */ WorksheetView.prototype._isLargeRange = function (range) { var vr = this.visibleRange; return range.c2 - range.c1 + 1 > (vr.c2 - vr.c1 + 1) * 3 || range.r2 - range.r1 + 1 > (vr.r2 - vr.r1 + 1) * 3; }; WorksheetView.prototype.drawDepCells = function () { var ctx = this.overlayCtx, _cc = this.cellCommentator, c, node, that = this; ctx.clear(); this._drawSelection(); var color = new CColor(0, 0, 255); function draw_arrow(context, fromx, fromy, tox, toy) { var headlen = 9, showArrow = tox > that._getColLeft(0) && toy > that._getRowTop(0), dx = tox - fromx, dy = toy - fromy, tox = tox > that._getColLeft(0) ? tox : that._getColLeft(0), toy = toy > that._getRowTop(0) ? toy : that._getRowTop(0), angle = Math.atan2(dy, dx), _a = Math.PI / 18; // ToDo посмотреть на четкость moveTo, lineTo context.save() .setLineWidth(1) .beginPath() .lineDiag .moveTo(fromx, fromy) .lineTo(tox, toy); // .dashLine(fromx-.5, fromy-.5, tox-.5, toy-.5, 15, 5) if (showArrow) { context .moveTo(tox - headlen * Math.cos(angle - _a), toy - headlen * Math.sin(angle - _a)) .lineTo(tox, toy) .lineTo(tox - headlen * Math.cos(angle + _a), toy - headlen * Math.sin(angle + _a)) .lineTo(tox - headlen * Math.cos(angle - _a), toy - headlen * Math.sin(angle - _a)); } context .setStrokeStyle(color) .setFillStyle(color) .stroke() .fill() .closePath() .restore(); } function gCM(_this, col, row) { var metrics = {top: 0, left: 0, width: 0, height: 0, result: false}; // px var fvr = _this.getFirstVisibleRow(); var fvc = _this.getFirstVisibleCol(); var mergedRange = _this.model.getMergedByCell(row, col); if (mergedRange && (fvc < mergedRange.c2) && (fvr < mergedRange.r2)) { var startCol = (mergedRange.c1 > fvc) ? mergedRange.c1 : fvc; var startRow = (mergedRange.r1 > fvr) ? mergedRange.r1 : fvr; metrics.top = _this._getRowTop(startRow) - _this._getRowTop(fvr) + _this._getRowTop(0); metrics.left = _this._getColLeft(startCol) - _this._getColLeft(fvc) + _this._getColLeft(0); metrics.width = _this._getColLeft(mergedRange.c2 + 1) - _this._getColLeft(startCol); metrics.height = _this._getRowHeight(mergedRange.r2 + 1) - _this._getRowHeight(startRow); } else { metrics.top = _this._getRowTop(row) - _this._getRowTop(fvr) + _this._getRowTop(0); metrics.left = _this._getColLeft(col) - _this._getColLeft(fvc) + _this._getColLeft(0); metrics.width = _this._getColumnWidth(col); metrics.height = _this._getRowHeight(row); } metrics.result = true; return metrics; } for (var id in this.depDrawCells) { c = this.depDrawCells[id].from; node = this.depDrawCells[id].to; var mainCellMetrics = gCM(this, c.nCol, c.nRow), nodeCellMetrics, _t1, _t2; for (var id in node) { if (!node[id].isArea) { _t1 = gCM(this, node[id].returnCell().nCol, node[id].returnCell().nRow) nodeCellMetrics = { t: _t1.top, l: _t1.left, w: _t1.width, h: _t1.height, apt: _t1.top + _t1.height / 2, apl: _t1.left + _t1.width / 4 }; } else { var _t1 = gCM(this, node[id].getBBox0().c1, node[id].getBBox0().r1), _t2 = gCM(this, node[id].getBBox0().c2, node[id].getBBox0().r2); nodeCellMetrics = { t: _t1.top, l: _t1.left, w: _t2.left + _t2.width - _t1.left, h: _t2.top + _t2.height - _t1.top, apt: _t1.top + _t1.height / 2, apl: _t1.left + _t1.width / 4 }; } var x1 = Math.floor(nodeCellMetrics.apl), y1 = Math.floor(nodeCellMetrics.apt), x2 = Math.floor( mainCellMetrics.left + mainCellMetrics.width / 4), y2 = Math.floor( mainCellMetrics.top + mainCellMetrics.height / 2); if (x1 < 0 && x2 < 0 || y1 < 0 && y2 < 0) { continue; } if (y1 < this._getRowTop(0)) { y1 -= this._getRowTop(0); } if (y1 < 0 && y2 > 0) { var _x1 = Math.floor(Math.sqrt((x1 - x2) * (x1 - x2) * y1 * y1 / ((y2 - y1) * (y2 - y1)))); // x1 -= (x1-x2>0?1:-1)*_x1; if (x1 > x2) { x1 -= _x1; } else if (x1 < x2) { x1 += _x1; } } else if (y1 > 0 && y2 < 0) { var _x2 = Math.floor(Math.sqrt((x1 - x2) * (x1 - x2) * y2 * y2 / ((y2 - y1) * (y2 - y1)))); // x2 -= (x2-x1>0?1:-1)*_x2; if (x2 > x1) { x2 -= _x2; } else if (x2 < x1) { x2 += _x2; } } if (x1 < 0 && x2 > 0) { var _y1 = Math.floor(Math.sqrt((y1 - y2) * (y1 - y2) * x1 * x1 / ((x2 - x1) * (x2 - x1)))) // y1 -= (y1-y2>0?1:-1)*_y1; if (y1 > y2) { y1 -= _y1; } else if (y1 < y2) { y1 += _y1; } } else if (x1 > 0 && x2 < 0) { var _y2 = Math.floor(Math.sqrt((y1 - y2) * (y1 - y2) * x2 * x2 / ((x2 - x1) * (x2 - x1)))) // y2 -= (y2-y1>0?1:-1)*_y2; if (y2 > y1) { y2 -= _y2; } else if (y2 < y1) { y2 += _y2; } } draw_arrow(ctx, x1 < this._getColLeft(0) ? this._getColLeft(0) : x1, y1 < this._getRowTop(0) ? this._getRowTop(0) : y1, x2, y2); // draw_arrow(ctx, x1, y1, x2, y2); // ToDo посмотреть на четкость rect if (nodeCellMetrics.apl > this._getColLeft(0) && nodeCellMetrics.apt > this._getRowTop(0)) { ctx.save() .beginPath() .arc(Math.floor(nodeCellMetrics.apl), Math.floor(nodeCellMetrics.apt), 3, 0, 2 * Math.PI, false, -0.5, -0.5) .setFillStyle(color) .fill() .closePath() .setLineWidth(1) .setStrokeStyle(color) .rect(nodeCellMetrics.l, nodeCellMetrics.t, nodeCellMetrics.w - 1, nodeCellMetrics.h - 1) .stroke() .restore(); } } } }; WorksheetView.prototype.prepareDepCells = function (se) { this.drawDepCells(); }; WorksheetView.prototype.cleanDepCells = function () { this.depDrawCells = null; this.drawDepCells(); }; // ----- Text drawing ----- WorksheetView.prototype._getPPIX = function () { return this.drawingCtx.getPPIX(); }; WorksheetView.prototype._getPPIY = function () { return this.drawingCtx.getPPIY(); }; WorksheetView.prototype._setDefaultFont = function (drawingCtx) { var ctx = drawingCtx || this.drawingCtx; ctx.setFont(AscCommonExcel.g_oDefaultFormat.Font); }; /** * @param {Asc.TextMetrics} tm * @return {Asc.TextMetrics} */ WorksheetView.prototype._roundTextMetrics = function (tm) { tm.width = Asc.round(tm.width); tm.height = Asc.round(tm.height); tm.baseline = Asc.round(tm.baseline); return tm; }; WorksheetView.prototype._calcTextHorizPos = function (x1, x2, tm, align, skipRtl) { if (this.getRightToLeft() && !skipRtl) { if (align === AscCommon.align_Right) { align = AscCommon.align_Left; } else if (align === AscCommon.align_Left) { align = AscCommon.align_Right; } } switch (align) { case AscCommon.align_Center: case AscCommon.align_Distributed: return Asc.round(0.5 * (x1 + x2 + 1 - tm.width)); case AscCommon.align_Right: return x2 + 1 - this.settings.cells.padding - tm.width; case AscCommon.align_Justify: default: return x1 + this.settings.cells.padding; } }; WorksheetView.prototype._calcTextVertPos = function (y1, h, baseline, tm, align) { switch (align) { case Asc.c_oAscVAlign.Center: case Asc.c_oAscVAlign.Dist: case Asc.c_oAscVAlign.Just: return y1 + Asc.round(0.5 * (h - tm.height * this.getZoom())); case Asc.c_oAscVAlign.Top: return y1; default: return baseline - Asc.round(tm.baseline * this.getZoom()); } }; WorksheetView.prototype._calcTextWidth = function (x1, x2, tm, halign) { switch (halign) { case AscCommon.align_Justify: return x2 + 1 - this.settings.cells.padding * 2 - x1; default: return tm.width; } }; // ----- Scrolling ----- WorksheetView.prototype._calcCellPosition = function (c, r, dc, dr) { var t = this; var vr = t.visibleRange; function findNextCell(col, row, dx, dy) { var state = t._isCellNullText(col, row); var i = col + dx; var j = row + dy; while (i >= 0 && i < t.nColsCount && j >= 0 && j < t.nRowsCount) { var newState = t._isCellNullText(i, j); if (newState !== state) { var ret = {}; ret.col = state ? i : i - dx; ret.row = state ? j : j - dy; if (ret.col !== col || ret.row !== row || state) { return ret; } state = newState; } i += dx; j += dy; } // Проверки для перехода в самый конец (ToDo пока убрал, чтобы не добавлять тормозов) /*if (i === t.nColsCount && state) { i = gc_nMaxCol; } if (j === t.nRowsCount && state) { j = gc_nMaxRow; }*/ return {col: i - dx, row: j - dy}; } function findEOT() { var obr = t.objectRender ? t.objectRender.getMaxColRow() : new AscCommon.CellBase(-1, -1); const eot = t.model.findEOT(); return {col: Math.max(eot.col, obr.col), row: Math.max(eot.row, obr.row)}; } var eot = dc > +2.0001 && dc < +2.9999 && dr > +2.0001 && dr < +2.9999 ? findEOT() : null; var newCol = (function () { if (dc > +0.0001 && dc < +0.9999) { return c + (vr.c2 - vr.c1 + 1); } // PageDown if (dc < -0.0001 && dc > -0.9999) { return c - (vr.c2 - vr.c1 + 1); } // PageUp if (dc > +1.0001 && dc < +1.9999) { return findNextCell(c, r, +1, 0).col; } // Ctrl + -> if (dc < -1.0001 && dc > -1.9999) { return findNextCell(c, r, -1, 0).col; } // Ctrl + <- if (dc > +2.0001 && dc < +2.9999) { return (eot || findNextCell(c, r, +1, 0)).col; } // End if (dc < -2.0001 && dc > -2.9999) { return 0; } // Home return c + dc; })(); var newRow = (function () { if (dr > +0.0001 && dr < +0.9999) { return r + (vr.r2 - vr.r1 + 1); } if (dr < -0.0001 && dr > -0.9999) { return r - (vr.r2 - vr.r1 + 1); } if (dr > +1.0001 && dr < +1.9999) { return findNextCell(c, r, 0, +1).row; } if (dr < -1.0001 && dr > -1.9999) { return findNextCell(c, r, 0, -1).row; } if (dr > +2.0001 && dr < +2.9999) { return !eot ? 0 : eot.row; } if (dr < -2.0001 && dr > -2.9999) { return 0; } return r + dr; })(); if (newCol >= t.nColsCount && newCol <= gc_nMaxCol0) { t.setColsCount(newCol + 1); //t._calcWidthColumns(AscCommonExcel.recalcType.newLines); } if (newRow >= t.nRowsCount && newRow <= gc_nMaxRow0) { t.nRowsCount = newRow + 1; //t._calcHeightRows(AscCommonExcel.recalcType.newLines); } return { col: newCol < 0 ? 0 : Math.min(newCol, t.nColsCount - 1), row: newRow < 0 ? 0 : Math.min(newRow, t.nRowsCount - 1) }; }; WorksheetView.prototype._isColDrawnPartially = function (col, leftCol, diffWidth) { if (col <= leftCol || col > gc_nMaxCol0) { return false; } return this._getColLeft(col + 1) - this._getColLeft(leftCol) + this.cellsLeft + diffWidth > this.drawingCtx.getWidth(); }; WorksheetView.prototype._isRowDrawnPartially = function (row, topRow, diffHeight) { if (row <= topRow || row > gc_nMaxRow0) { return false; } return this._getRowTop(row + 1) - this._getRowTop(topRow) + this.cellsTop + diffHeight > this.drawingCtx.getHeight(); }; WorksheetView.prototype._getMissingWidth = function () { var visibleWidth = this._getColLeft(this.nColsCount) - this._getOffsetX(); var offsetFrozen = this.getFrozenPaneOffset(false, true); visibleWidth += offsetFrozen.offsetX; return this.drawingCtx.getWidth() - visibleWidth; }; WorksheetView.prototype._getMissingHeight = function () { var visibleHeight = this._getRowTop(this.nRowsCount) - this._getOffsetY(); var offsetFrozen = this.getFrozenPaneOffset(true, false); visibleHeight += offsetFrozen.offsetY; return this.drawingCtx.getHeight() - visibleHeight; }; WorksheetView.prototype._updateVisibleRowsCount = function (skipScrollReinit, fChangeRowsCount) { this._calcVisibleRows(); if (gc_nMaxRow !== this.nRowsCount && !this.model.isDefaultHeightHidden()) { var missingHeight = this._getMissingHeight(); if (0 < missingHeight) { var rowHeight = Asc.round(this.defaultRowHeightPx * this.getZoom()); this.nRowsCount = Math.min(this.nRowsCount + Asc.ceil(missingHeight / rowHeight), gc_nMaxRow); fChangeRowsCount && fChangeRowsCount(); this._calcVisibleRows(); if (!skipScrollReinit) { this.handlers.trigger("reinitializeScroll", AscCommonExcel.c_oAscScrollType.ScrollVertical); } } } this._updateDrawingArea(); }; WorksheetView.prototype._updateVisibleColsCount = function (skipScrollReinit, fChangeRowsCount) { this._calcVisibleColumns(); if (gc_nMaxCol !== this.nColsCount && !this.model.isDefaultWidthHidden()) { var missingWidth = this._getMissingWidth(); if (0 < missingWidth) { var colWidth = Asc.round(this.defaultColWidthPx * this.getZoom(true) * this.getRetinaPixelRatio()); this.setColsCount(Math.min(this.nColsCount + Asc.ceil(missingWidth / colWidth), gc_nMaxCol)); fChangeRowsCount && fChangeRowsCount(); this._calcVisibleColumns(); if (!skipScrollReinit) { this.handlers.trigger("reinitializeScroll", AscCommonExcel.c_oAscScrollType.ScrollHorizontal); } } } }; WorksheetView.prototype.scrollVertical = function (delta, editor, initRowsCount) { let t = this; var vr = this.visibleRange; var fixStartRow = new asc_Range(vr.c1, vr.r1, vr.c2, vr.r1); let isReverse = delta < 0; let unitDeltaStep = Asc.round(this.getVScrollStep()); let defaultScrollPxStep = unitDeltaStep * Math.abs(delta); if (defaultScrollPxStep < 1) { return; } defaultScrollPxStep = Math.floor(defaultScrollPxStep); let deltaRows = 0, deltaCorrect = 0; let currentScrollCorrect = this.getScrollCorrect(); let firstRow = vr.r1; let startRowHeight = this._getRowHeight(firstRow); var offsetX, offsetY, diffWidth = 0, diffHeight = 0, cFrozen = 0, rFrozen = 0; if (this.topLeftFrozenCell) { cFrozen = this.topLeftFrozenCell.getCol0(); rFrozen = this.topLeftFrozenCell.getRow0(); diffWidth = this._getColLeft(cFrozen) - this._getColLeft(0); diffHeight = this._getRowTop(rFrozen) - this._getRowTop(0); } const isSmoothScroll = this.workbook.getSmoothScrolling(); if (isSmoothScroll) { //in px if (!isReverse) { //down scroll if (currentScrollCorrect + defaultScrollPxStep >= startRowHeight) { //go to the next row //calculate part of row + new rows delta let allScrollHeight = currentScrollCorrect + defaultScrollPxStep; let scrollHeight = 0; for (let i = firstRow; i < gc_nMaxRow0; i++) { let _rowHeight = this._getRowHeight(i); scrollHeight += _rowHeight; if (scrollHeight >= allScrollHeight) { if (scrollHeight === allScrollHeight) { deltaRows++; } else { deltaCorrect = _rowHeight - (scrollHeight - allScrollHeight); } break; } deltaRows++; } } else { //stay in wr.r1 deltaCorrect = defaultScrollPxStep + currentScrollCorrect; deltaRows = 0; } } else { //up scroll if (currentScrollCorrect - defaultScrollPxStep < 0) { //go to the next row //calculate part of row + new rows delta let allScrollHeight = defaultScrollPxStep - currentScrollCorrect; let scrollHeight = 0; /*if (currentScrollCorrect !== 0) { deltaRows--; }*/ for (let i = firstRow - 1; i >= 0; i--) { let _rowHeight = this._getRowHeight(i); scrollHeight += _rowHeight; if (scrollHeight >= allScrollHeight) { if (scrollHeight === allScrollHeight) { deltaRows--; } else { //if (deltaRows === 0) { deltaRows--; //} deltaCorrect = (scrollHeight - allScrollHeight); } break; } deltaRows--; } } else { //stay in vr.r1 deltaCorrect = currentScrollCorrect - defaultScrollPxStep; deltaRows = 0; } } delta = deltaRows; } this._fixSelectionOfHiddenCells(0, delta >= 0 ? +1 : -1, fixStartRow); var start = this._calcCellPosition(vr.c1, isSmoothScroll ? vr.r1 : fixStartRow.r1, 0, delta).row; fixStartRow.assign(vr.c1, start, vr.c2, start); this._fixSelectionOfHiddenCells(0, delta >= 0 ? +1 : -1, fixStartRow); this._fixVisibleRange(fixStartRow); var reinitScrollY = start !== fixStartRow.r1; // Для скролла вверх обычный сдвиг + дорисовка if (reinitScrollY && 0 > delta) { delta += fixStartRow.r1 - start; } start = fixStartRow.r1; if (start === vr.r1 && (!isSmoothScroll || (isSmoothScroll && currentScrollCorrect === deltaCorrect))) { if (reinitScrollY) { this.scrollType |= AscCommonExcel.c_oAscScrollType.ScrollVertical; this._reinitializeScroll(); } return this; } if (!this.notUpdateRowHeight) { this.cleanHighlightedHeaders(); this.cleanSelection(); this.cellCommentator.cleanSelectedComment(); } var ctx = this.drawingCtx; var ctxW = ctx.getWidth(); var ctxH = ctx.getHeight(); var oldVRE_isPartial = this._isRowDrawnPartially(vr.r2, vr.r1, diffHeight); var oldVR = vr.clone(); var oldStart = vr.r1; var oldEnd = vr.r2; var x = this.cellsLeft; var topOldStart = this._getRowTop(oldStart); var dy = (this._getRowTop(start) + deltaCorrect - (topOldStart + currentScrollCorrect)); isSmoothScroll && this.setScrollCorrect(deltaCorrect); // ToDo стоит тут переделать весь scroll vr.r1 = start; let _beforeRowsCount = this.nRowsCount; this._updateVisibleRowsCount(undefined, function () { if (!isSmoothScroll) { return; } let _expandRowsHeight = 30 * t.defaultRowHeightPx; let nRowsHeightDiff = t._getRowTop(t.nRowsCount) - t._getRowTop(_beforeRowsCount); if (nRowsHeightDiff > 0 && nRowsHeightDiff < _expandRowsHeight) { while (nRowsHeightDiff < _expandRowsHeight) { nRowsHeightDiff += t._getRowHeight(t.nRowsCount); t.nRowsCount++; } } }); // Это необходимо для того, чтобы строки, у которых высота по тексту, рассчитались if (!oldVR.intersectionSimple(vr)) { // Полностью обновилась область this._prepareCellTextMetricsCache(vr); } else { if (isReverse) { // Идем вверх this._prepareCellTextMetricsCache(new asc_Range(vr.c1, start, vr.c2, oldStart - 1)); } else { // Идем вниз this._prepareCellTextMetricsCache(new asc_Range(vr.c1, oldEnd + 1, vr.c2, vr.r2)); } } if (this.notUpdateRowHeight) { return this; } var oldW, dx; var oldH = ctxH - this.cellsTop - Math.abs(dy) - diffHeight; var scrollDown = (dy > 0 && oldH > 0); var y = this.cellsTop + (scrollDown ? dy : 0) + diffHeight; var lastRowHeight = (scrollDown && oldVRE_isPartial) ? ctxH - (this._getRowTop(oldEnd) - topOldStart + this.cellsTop + diffHeight) : 0; //TODO consider all cases when groupWidth needs to be subtracted if (x !== this.cellsLeft) { this.scrollType |= AscCommonExcel.c_oAscScrollType.ScrollHorizontal; this._drawCorner(); this._cleanColumnHeadersRect(); this._drawColumnHeaders(null); dx = this.cellsLeft - x; oldW = ctxW - x - (dx > 0 ? Math.abs(dx) : 0); if (rFrozen > 0 || cFrozen > 0) { // Move frozen area only if there are frozen rows if (rFrozen > 0) { ctx.drawImage(ctx.getCanvas(), x, this.cellsTop, oldW, diffHeight, x + dx, this.cellsTop, oldW, diffHeight); // Move graphic objects in frozen area if (AscBrowser.isSafari) { this.drawingGraphicCtx.moveImageDataSafari(x, this.cellsTop, oldW, diffHeight, x + dx, this.cellsTop); } else { this.drawingGraphicCtx.moveImageData(x, this.cellsTop, oldW, diffHeight, x + dx, this.cellsTop); } } // Redraw freed area after frozen area shift if (dx < 0 && rFrozen > 0) { let clearFrozenX, clearFrozenWidth; if (dx < 0) { // Right shift - frees right part of original area clearFrozenX = x + oldW; clearFrozenWidth = dx; } // Clear freed area ctx.setFillStyle(this.settings.cells.defaultState.background); this._fillRect(ctx, clearFrozenX, this.cellsTop, clearFrozenWidth, diffHeight); this._clearRect(this.drawingGraphicCtx, clearFrozenX, this.cellsTop, clearFrozenWidth, diffHeight); // Redraw freed area this._AddClipRect(ctx, clearFrozenX, this.cellsTop, clearFrozenWidth, diffHeight); this.drawingGraphicCtx.AddClipRect && this._AddClipRect(this.drawingGraphicCtx, clearFrozenX, this.cellsTop, clearFrozenWidth, diffHeight); const frozenRange = new asc_Range(vr.c1, 0, vr.c2, rFrozen - 1); offsetX = this._getOffsetX(0, true); offsetY = this._getOffsetY(0, true); this._drawGrid(null, frozenRange, offsetX, offsetY); this._drawCellsAndBorders(null, frozenRange, offsetX, offsetY); this.af_drawButtons(frozenRange, offsetX, offsetY); this.objectRender.updateRange(frozenRange); this._RemoveClipRect(ctx); this.drawingGraphicCtx.RemoveClipRect && this.drawingGraphicCtx.RemoveClipRect(); } } this._drawFrozenPane(true); } else { dx = 0; x = this.headersLeft - this.groupWidth; oldW = ctxW; } // Перемещаем область lastRowHeight = Math.max(lastRowHeight, 0) var moveHeight = oldH - lastRowHeight; if (moveHeight > 0) { ctx.drawImage(ctx.getCanvas(), x, y, oldW, moveHeight, x + dx, y - dy, oldW, moveHeight); // Заглушка для safari (http://bugzilla.onlyoffice.com/show_bug.cgi?id=25546). Режим 'copy' сначала затирает, а // потом рисует (а т.к. мы рисуем сами на себе, то уже картинка будет пустой) if (AscBrowser.isSafari) { this.drawingGraphicCtx.moveImageDataSafari(x, y, oldW, moveHeight, x + dx, y - dy); } else { this.drawingGraphicCtx.moveImageData(x, y, oldW, moveHeight, x + dx, y - dy); } } // Очищаем область var clearTop = this.cellsTop + diffHeight + (scrollDown && moveHeight > 0 ? moveHeight : 0); var clearHeight = (moveHeight > 0) ? Math.abs(dy) + lastRowHeight : ctxH - (this.cellsTop + diffHeight); let clearOffset = 0; if (isSmoothScroll && (diffHeight + this._getRowTop(0)) !== clearTop) { //need clear full row height let firstDrawRow = vr.r1; if (moveHeight > 0 && scrollDown) { firstDrawRow = oldEnd + ((oldVRE_isPartial || (delta === 0)) ? 0 : 1); } let firstDrawRowPos = this.getCellTopRelative(firstDrawRow, undefined, true); if (firstDrawRowPos && clearTop > firstDrawRowPos) { clearOffset = clearTop - firstDrawRowPos; } } ctx.setFillStyle(this.settings.cells.defaultState.background); this._fillRect(ctx, this.headersLeft - this.groupWidth, clearTop - clearOffset, ctxW, clearHeight + clearOffset); this._clearRect(this.drawingGraphicCtx, this.headersLeft - this.groupWidth, clearTop - clearOffset, ctxW, clearHeight + clearOffset); this._updateDrawingArea(); // Дорисовываем необходимое if (dy < 0 || vr.r2 !== oldEnd || oldVRE_isPartial || dx !== 0 || (clearHeight !== 0 && isSmoothScroll)) { var r1, r2; if (moveHeight > 0) { if (scrollDown) { r1 = oldEnd + ((oldVRE_isPartial || (delta === 0 && isSmoothScroll)) ? 0 : 1); r2 = vr.r2; } else { r1 = vr.r1; r2 = isReverse ? (vr.r1 + (oldVR.r1 - vr.r1 - 1)) : (vr.r1 - 1 - delta); } } else { r1 = vr.r1; r2 = vr.r2; } if (isSmoothScroll && r2 < AscCommon.gc_nMaxRow0) { r2++; } if (r1 > AscCommon.gc_nMaxRow0) { r1 = AscCommon.gc_nMaxRow0; } if (r2 > AscCommon.gc_nMaxRow0) { r2 = AscCommon.gc_nMaxRow0; } if (isSmoothScroll && r2 < r1) { r2 = r1; } let startClip = function () { if (isSmoothScroll) { t._AddClipRect(ctx, t.headersLeft - t.groupWidth, clearTop - clearOffset, ctxW, clearHeight + clearOffset); t.drawingGraphicCtx.AddClipRect && t._AddClipRect(t.drawingGraphicCtx, t.headersLeft - t.groupWidth, clearTop - clearOffset, ctxW, clearHeight + clearOffset); } }; var range = new asc_Range(vr.c1, r1, vr.c2, r2); if (dx === 0) { startClip(); this._drawRowHeaders(null, r1, r2); } else { // redraw all headres, because number of decades in row index has been changed this._drawRowHeaders(null); startClip(); if (dx < 0) { // draw last column var r_; var r1_ = r2 + 1; var r2_ = vr.r2; if (r2_ >= r1_) { r_ = new asc_Range(vr.c2, r1_, vr.c2, r2_); this._drawGrid(null, r_); this._drawGroupData(null, r_); this._drawCellsAndBorders(null, r_); } if (0 < rFrozen) { r_ = new asc_Range(vr.c2, 0, vr.c2, rFrozen - 1); offsetY = this._getOffsetY(0, true); this._drawGrid(null, r_, /*offsetXForDraw*/undefined, offsetY); this._drawGroupData(null, r_, /*offsetXForDraw*/undefined, offsetY); this._drawCellsAndBorders(null, r_, /*offsetXForDraw*/undefined, offsetY); } } } offsetX = this._getOffsetX() - diffWidth; offsetY = this._getOffsetY() - diffHeight; this._drawGrid(null, range); if(dx !== 0) { this._drawGroupData(null); } else { this._drawGroupData(null, range); } this._drawCellsAndBorders(null, range); this.af_drawButtons(range, offsetX, offsetY); this.objectRender.updateRange(range); if (0 < cFrozen) { var frozenRange = dx !== 0 ? new asc_Range(0, vr.r1, cFrozen - 1, vr.r2) : new asc_Range(0, r1, cFrozen - 1, r2); frozenRange.c1 = 0; frozenRange.c2 = cFrozen - 1; offsetX = this._getOffsetX(0, true); this._drawGrid(null, frozenRange, offsetX); this._drawGroupData(null, frozenRange, offsetX); this._drawCellsAndBorders(null, frozenRange, offsetX); this.af_drawButtons(frozenRange, offsetX, offsetY); this.objectRender.updateRange(frozenRange); } } if (isSmoothScroll) { this._RemoveClipRect(ctx); this.drawingGraphicCtx.RemoveClipRect && this.drawingGraphicCtx.RemoveClipRect(); } // Отрисовывать нужно всегда, вдруг бордеры this._drawFrozenPaneLines(); this._fixSelectionOfMergedCells(null, true); this._drawSelection(); //this._cleanPagesModeData(); /*if (!reinitScrollY && this.workbook.getSmoothScrolling()) { reinitScrollY = oldEnd !== vr.r2; }*/ let isNeedExpand = function () { //we must init scroll, if expand scroll range(calculate new rows height) //todo need review let controller = t.workbook.controller; let scrollStep = controller.settings.vscrollStep; if (!t.workbook.Api.isMobileVersion && !AscCommon.AscBrowser.isMacOs && !initRowsCount && isSmoothScroll && !isReverse && t.model.getRowsCount() > t.visibleRange.r2 && controller.vsbMax && scrollStep && controller.vsbMax < (t.getVerticalScrollRange() * scrollStep)) { return true; } return false; }; let _maxRow = this.model.isDefaultHeightHidden() ? this.nRowsCount : gc_nMaxRow; if ((reinitScrollY && !isSmoothScroll) || (reinitScrollY && isSmoothScroll && deltaCorrect !== currentScrollCorrect) || (isReverse && initRowsCount && this._initRowsCount()) || (isSmoothScroll && initRowsCount && this.nRowsCount !== _maxRow) || isNeedExpand()) { this.scrollType |= AscCommonExcel.c_oAscScrollType.ScrollVertical; } if (initRowsCount) { this.scrollType |= AscCommonExcel.c_oAscScrollType.ScrollInitRowsColsCount; } this._reinitializeScroll(); this.handlers.trigger("onDocumentPlaceChanged"); if (editor && this.model.getSelection().activeCell.row >= rFrozen) { editor.move(); } //ToDo this.drawDepCells(); this.cellCommentator.updateActiveComment(); this.cellCommentator.drawCommentCells(); window['AscCommon'].g_specialPasteHelper.SpecialPasteButton_Update_Position(); Asc.editor.toggleChartElementsCallback(); this.handlers.trigger("toggleAutoCorrectOptions", true); //this.model.updateTopLeftCell(this.visibleRange); return this; }; //smooth scroll WorksheetView.prototype.setScrollCorrect = function (val, needDraw) { this.scrollCorrect = val; if (needDraw) { this.draw(); } }; WorksheetView.prototype.getScrollCorrect = function (units) { var u = units >= 0 && units <= 3 ? units : 0; return this.scrollCorrect ? (this.scrollCorrect * asc_getcvt(0/*px*/, u, this._getPPIX())) : 0; }; WorksheetView.prototype.setHorizontalScrollCorrect = function (val, needDraw) { this.horizontalScrollCorrect = val; if (needDraw) { this.draw(); } }; WorksheetView.prototype.getHorizontalScrollCorrect = function (units) { var u = units >= 0 && units <= 3 ? units : 0; return this.horizontalScrollCorrect ? (this.horizontalScrollCorrect * asc_getcvt(0/*px*/, u, this._getPPIX())) : 0; }; WorksheetView.prototype.isScrollCorrect = function () { return !!this.scrollCorrect; }; WorksheetView.prototype.scrollHorizontal = function (delta, editor, initColsCount) { var vr = this.visibleRange; var fixStartCol = new asc_Range(vr.c1, vr.r1, vr.c1, vr.r2); let t = this; let isReverse = delta < 0; let unitDeltaStep = Asc.round(this.getHScrollStep()); let defaultScrollPxStep = unitDeltaStep * Math.abs(delta); if (defaultScrollPxStep < 1) { return; } defaultScrollPxStep = Math.ceil(defaultScrollPxStep); let deltaCols = 0, deltaCorrect = 0; let currentScrollCorrect = this.getHorizontalScrollCorrect(); let firstCol = vr.c1; let startColWidth = this._getColumnWidth(firstCol); var offsetX, offsetY, diffWidth = 0, diffHeight = 0, cFrozen = 0, rFrozen = 0; if (this.topLeftFrozenCell) { cFrozen = this.topLeftFrozenCell.getCol0(); rFrozen = this.topLeftFrozenCell.getRow0(); diffWidth = this._getColLeft(cFrozen) - this._getColLeft(0); diffHeight = this._getRowTop(rFrozen) - this._getRowTop(0); } if (this.workbook.getSmoothScrolling()) { //in px if (!isReverse) { //down scroll if (currentScrollCorrect + defaultScrollPxStep >= startColWidth) { //go to the next row //calculate part of row + new rows delta let allScrollWidth = currentScrollCorrect + defaultScrollPxStep; let scrollWidth = 0; for (let i = firstCol; i < gc_nMaxCol0; i++) { let _colWidth = this._getColumnWidth(i); scrollWidth += _colWidth; if (scrollWidth >= allScrollWidth) { if (scrollWidth === allScrollWidth) { deltaCols++; } else { deltaCorrect = _colWidth - (scrollWidth - allScrollWidth); } break; } deltaCols++; } } else { //stay in wr.r1 deltaCorrect = defaultScrollPxStep + currentScrollCorrect; deltaCols = 0; } } else { //up scroll if (currentScrollCorrect - defaultScrollPxStep < 0) { //go to the next row //calculate part of row + new rows delta let allScrollWidth = defaultScrollPxStep - currentScrollCorrect; let scrollWidth = 0; /*if (currentScrollCorrect !== 0) { deltaRows--; }*/ for (let i = firstCol - 1; i >= 0; i--) { let _rowHeight = this._getColumnWidth(i); scrollWidth += _rowHeight; if (scrollWidth >= allScrollWidth) { if (scrollWidth === allScrollWidth) { deltaCols--; } else { //if (deltaRows === 0) { deltaCols--; //} deltaCorrect = (scrollWidth - allScrollWidth); } break; } deltaCols--; } } else { //stay in vr.r1 deltaCorrect = currentScrollCorrect - defaultScrollPxStep; deltaCols = 0; } } delta = deltaCols; } this._fixSelectionOfHiddenCells(delta >= 0 ? +1 : -1, 0, fixStartCol); var start = this._calcCellPosition(this.workbook.getSmoothScrolling() ? vr.c1 : fixStartCol.c1, vr.r1, delta, 0).col; fixStartCol.assign(start, vr.r1, start, vr.r2); this._fixSelectionOfHiddenCells(delta >= 0 ? +1 : -1, 0, fixStartCol); this._fixVisibleRange(fixStartCol); var reinitScrollX = start !== fixStartCol.c1; // Для скролла влево обычный сдвиг + дорисовка if (reinitScrollX && 0 > delta) { delta += fixStartCol.c1 - start; } start = fixStartCol.c1; if (start === vr.c1 && (!this.workbook.getSmoothScrolling() || (this.workbook.getSmoothScrolling() && currentScrollCorrect === deltaCorrect))) { if (reinitScrollX) { this.scrollType |= AscCommonExcel.c_oAscScrollType.ScrollHorizontal; this._reinitializeScroll(); } return this; } if (!this.notUpdateRowHeight) { this.cleanHighlightedHeaders(); this.cleanSelection(); this.cellCommentator.cleanSelectedComment(); } var ctx = this.drawingCtx; var ctxW = ctx.getWidth(); var ctxH = ctx.getHeight(); var oldStart = vr.c1; var oldEnd = vr.c2; var leftOldStart = this._getColLeft(oldStart); var dx = (this._getColLeft(start) + deltaCorrect - (leftOldStart + currentScrollCorrect)); var oldW = ctxW - this.cellsLeft - Math.abs(dx); var scrollRight = (dx > 0 && oldW > 0); var x = this.cellsLeft + (scrollRight ? dx : 0); var y = this.headersTop - this.groupHeight; x += diffWidth; oldW -= diffWidth; var oldVCE_isPartial = this._isColDrawnPartially(vr.c2, vr.c1, diffWidth); var oldVR = vr.clone(); this.workbook.getSmoothScrolling() && this.setHorizontalScrollCorrect(deltaCorrect); // ToDo стоит тут переделать весь scroll vr.c1 = start; let _beforeColsCount = this.nColsCount; this._updateVisibleColsCount(undefined, function () { if (!t.workbook.getSmoothScrolling()) { return; } let _expandColsWidth = 30 * t.defaultColWidthPx; let nColsWidthDiff = t._getColLeft(t.nColsCount) - t._getColLeft(_beforeColsCount); if (nColsWidthDiff > 0 && nColsWidthDiff < _expandColsWidth) { while (nColsWidthDiff < _expandColsWidth) { nColsWidthDiff += t._getColumnWidth(t.nColsCount); t.nColsCount++; } } }); // Это необходимо для того, чтобы строки, у которых высота по тексту, рассчитались if (!oldVR.intersectionSimple(vr)) { // Полностью обновилась область this._prepareCellTextMetricsCache(vr); } else { if (0 > delta) { // Идем влево this._prepareCellTextMetricsCache(new asc_Range(start, vr.r1, oldStart - 1, vr.r2)); } else { // Идем вправо this._prepareCellTextMetricsCache(new asc_Range(oldEnd + 1, vr.r1, vr.c2, vr.r2)); } } if (this.notUpdateRowHeight) { return this; } var lastColWidth = (scrollRight && oldVCE_isPartial) ? ctxW - (this._getColLeft(oldEnd) - leftOldStart + this.cellsLeft + diffWidth) : 0; // Перемещаем область var moveWidth = oldW - lastColWidth; if (moveWidth > 0) { this._drawImage(ctx, ctx.getCanvas(), x + this.getRightToLeftOffset(), y, moveWidth, ctxH, x - dx + this.getRightToLeftOffset(), y, moveWidth, ctxH); // Заглушка для safari (http://bugzilla.onlyoffice.com/show_bug.cgi?id=25546). Режим 'copy' сначала затирает, а // потом рисует (а т.к. мы рисуем сами на себе, то уже картинка будет пустой) this._moveImageData(x, y, moveWidth, ctxH, x - dx, y, moveWidth, ctxH); } // Очищаем область var clearLeft = this.cellsLeft + diffWidth + (scrollRight && moveWidth > 0 ? moveWidth : 0); var clearWidth = (moveWidth > 0) ? Math.abs(dx) + lastColWidth : ctxW - (this.cellsLeft + diffWidth); let clearOffset = 0; if (this.workbook.getSmoothScrolling() && (diffWidth + this._getColLeft(0)) !== clearLeft) { //need clear full row height let firstDrawCol = vr.c1; if (moveWidth > 0 && scrollRight) { firstDrawCol = oldEnd + ((oldVCE_isPartial || (delta === 0)) ? 0 : 1); } let firstDrawColPos = this.getCellLeftRelative(firstDrawCol, undefined, true); if (firstDrawColPos && clearLeft > firstDrawColPos) { clearOffset = clearLeft - firstDrawColPos; } } ctx.setFillStyle(this.settings.cells.defaultState.background); this._fillRect(ctx, clearLeft - clearOffset + this.getRightToLeftOffset(), y, clearWidth + clearOffset, ctxH); this._clearRect(this.drawingGraphicCtx, clearLeft - clearOffset, y, clearWidth + clearOffset, ctxH); this._updateDrawingArea(); if (this.workbook.getSmoothScrolling()) { this._AddClipRect(ctx, clearLeft - clearOffset + this.getRightToLeftOffset(), y, clearWidth + clearOffset + this.getRightToLeftOffset(), ctxH); this.drawingGraphicCtx.AddClipRect && this._AddClipRect(this.drawingGraphicCtx, clearLeft - clearOffset + this.getRightToLeftOffset(), y, clearWidth + clearOffset + this.getRightToLeftOffset(), ctxH); } // Дорисовываем необходимое if (dx < 0 || vr.c2 !== oldEnd || oldVCE_isPartial || (clearWidth !== 0 && this.workbook.getSmoothScrolling())) { var c1, c2; if (moveWidth > 0) { if (scrollRight) { c1 = oldEnd + ((oldVCE_isPartial || (delta === 0 && this.workbook.getSmoothScrolling())) ? 0 : 1); c2 = vr.c2; } else { c1 = vr.c1; c2 = vr.c1 - 1 - delta; } } else { c1 = vr.c1; c2 = vr.c2; } if (this.workbook.getSmoothScrolling() && c2 < AscCommon.gc_nMaxCol0) { c2++; } if (c1 > AscCommon.gc_nMaxCol0) { c1 = AscCommon.gc_nMaxCol0; } if (c2 > AscCommon.gc_nMaxCol0) { c2 = AscCommon.gc_nMaxCol0; } if (this.workbook.getSmoothScrolling() && c2 < c1) { c2 = c1; } var range = new asc_Range(c1, vr.r1, c2, vr.r2); offsetX = this._getOffsetX() - diffWidth; offsetY = this._getOffsetY() - diffHeight; this._drawColumnHeaders(null, c1, c2); this._drawGrid(null, range); this._drawGroupData(null, range, undefined, undefined, true); this._drawCellsAndBorders(null, range); this.af_drawButtons(range, offsetX, offsetY); this.objectRender.updateRange(range); if (rFrozen) { range.r1 = 0; range.r2 = rFrozen - 1; offsetY = this._getOffsetY(0, true); this._drawGrid(null, range, undefined, offsetY); this._drawGroupData(null, range, undefined, offsetY, true); this._drawCellsAndBorders(null, range, undefined, offsetY); this.af_drawButtons(range, offsetX, offsetY); this.objectRender.updateRange(range); } } if (this.workbook.getSmoothScrolling()) { this._RemoveClipRect(ctx); this.drawingGraphicCtx.RemoveClipRect && this.drawingGraphicCtx.RemoveClipRect(); } // Отрисовывать нужно всегда, вдруг бордеры this._drawFrozenPaneLines(); this._fixSelectionOfMergedCells(null, true); this._drawSelection(); //this._cleanPagesModeData(); if (!reinitScrollX && this.workbook.getSmoothScrolling()) { reinitScrollX = oldEnd !== vr.c2; } if ((reinitScrollX && !this.workbook.getSmoothScrolling()) || (reinitScrollX && this.workbook.getSmoothScrolling() && deltaCorrect !== currentScrollCorrect) || (0 > delta && initColsCount && this._initColsCount()) || (this.workbook.getSmoothScrolling() && initColsCount && this.nColsCount !== gc_nMaxCol)) { if (reinitScrollX && (start - cFrozen) === 0 && 0 > delta && initColsCount) { this._initColsCount(); } this.scrollType |= AscCommonExcel.c_oAscScrollType.ScrollHorizontal; } if (initColsCount) { this.scrollType |= AscCommonExcel.c_oAscScrollType.ScrollInitRowsColsCount; } this._reinitializeScroll(); this.handlers.trigger("onDocumentPlaceChanged"); if (editor && this.model.getSelection().activeCell.col >= cFrozen) { editor.move(); } //ToDo this.drawDepCells(); this.cellCommentator.updateActiveComment(); this.cellCommentator.drawCommentCells(); window['AscCommon'].g_specialPasteHelper.SpecialPasteButton_Update_Position(); Asc.editor.toggleChartElementsCallback(); this.handlers.trigger("toggleAutoCorrectOptions", true); //this.model.updateTopLeftCell(this.visibleRange); return this; }; WorksheetView.prototype.executeScrollDefaultStep = function (callback) { let oView = this.workbook && this.workbook.controller && this.workbook.controller.settings; let defaultStep = 10; let realVScrollPxStep = this.vScrollPxStep; let realHScrollPxStep = this.hScrollPxStep; this.vScrollPxStep = oView ? oView.vscrollStep : defaultStep; this.hScrollPxStep = oView ? oView.hscrollStep : defaultStep; callback(); this.vScrollPxStep = realVScrollPxStep; this.hScrollPxStep = realHScrollPxStep; }; // ----- Selection ----- // x,y - абсолютные координаты относительно листа (без учета заголовков) WorksheetView.prototype.findCellByXY = function (x, y, canReturnNull, skipCol, skipRow) { var i, sum, size, result = new AscFormat.CCellObjectInfo(); if (canReturnNull) { result.col = result.row = null; } x += this.getRightToLeft() ? 0 : this.cellsLeft; y += this.cellsTop; if (this.getRightToLeft()) { x = this.getCtxWidth() - x; } if (!skipCol) { sum = this._getColLeft(this.nColsCount); if (sum < x) { result.col = this.nColsCount; if (!this.model.isDefaultWidthHidden()) { result.col += ((x - sum) / (this.defaultColWidthPx * this.getZoom(true) * this.getRetinaPixelRatio())) | 0; result.col = Math.min(result.col, gc_nMaxCol0); sum += (result.col - this.nColsCount) * (this.defaultColWidthPx * this.getZoom(true) * this.getRetinaPixelRatio()); } } else { sum = this.getRightToLeft() ? 0 : this.cellsLeft; for (i = 0; i < this.nColsCount; ++i) { size = this._getColumnWidth(i); if (sum + size > x) { break; } sum += size; } result.col = i; } if (null !== result.col) { result.colOff = x - sum; } } if (!skipRow) { sum = this._getRowTop(this.nRowsCount); if (sum < y) { result.row = this.nRowsCount; if (!this.model.isDefaultHeightHidden()) { result.row += ((y - sum) / (this.defaultRowHeightPx * this.getZoom())) | 0; result.row = Math.min(result.row, gc_nMaxRow0); sum += (result.row - this.nRowsCount) * (this.defaultRowHeightPx * this.getZoom()); } } else { sum = this.cellsTop; for (i = 0; i < this.nRowsCount; ++i) { size = this._getRowHeight(i); if (sum + size > y) { break; } sum += size; } result.row = i; } if (null !== result.row) { result.rowOff = y - sum; } } return result; }; /** * * @param x * @param canReturnNull * @param half - считать с половиной следующей ячейки * @returns {*} * @private */ WorksheetView.prototype._findColUnderCursor = function (x, canReturnNull, half, ignoreRtl) { var activeCellCol = half ? this._getSelection().activeCell.col : -1; var w, dx = 0; var c = this.visibleRange.c1; var offset = this._getOffsetX(c); var c2, x1, x2, cFrozen, widthDiff = -this.getHorizontalScrollCorrect(); if (!ignoreRtl && this.getRightToLeft()) { x = this.getCtxWidth() - x; } if (x >= this.cellsLeft) { if (this.topLeftFrozenCell) { cFrozen = this.topLeftFrozenCell.getCol0(); widthDiff = this._getColLeft(cFrozen) - this._getColLeft(0); if (x < this.cellsLeft + widthDiff && 0 !== widthDiff) { c = 0; widthDiff = 0; } else { widthDiff -= this.getHorizontalScrollCorrect(); } } for (x1 = this.cellsLeft + widthDiff, c2 = this.nColsCount - 1; c <= c2; ++c, x1 = x2) { w = this._getColumnWidth(c); x2 = x1 + w; dx = half ? w / 2.0 * Math.sign(c - activeCellCol) : 0; if (x1 + dx > x) { if (c !== this.visibleRange.c1) { if (dx) { c -= 1; x2 = x1; x1 -= w; } return {col: c, left: x1, right: x2}; } else { c = c2; break; } } else if (x <= x2 + dx) { return {col: c, left: x1, right: x2}; } } if (!canReturnNull) { x1 = this._getColLeft(c2) - offset; return {col: c2, left: x1, right: x1 + this._getColumnWidth(c2)}; } } else { if (this.topLeftFrozenCell) { cFrozen = this.topLeftFrozenCell.getCol0(); if (0 !== cFrozen) { c = 0; offset = this._getColLeft(c) - this.cellsLeft; } } for (x2 = this.cellsLeft + this._getColumnWidth(c), c2 = 0; c >= c2; --c, x2 = x1) { x1 = this._getColLeft(c) - offset; if (x1 <= x && x < x2) { return {col: c, left: x1, right: x2}; } } if (!canReturnNull) { return {col: c2, left: x1, right: x1 + this._getColumnWidth(c2)}; } } return null; }; /** * * @param y * @param canReturnNull * @param half - считать с половиной следующей ячейки * @returns {*} * @private */ WorksheetView.prototype._findRowUnderCursor = function (y, canReturnNull, half) { var activeCellRow = half ? this._getSelection().activeCell.row : -1; var h, dy = 0; var r = this.visibleRange.r1; var offset = /*this._getRowTop(r) - this.cellsTop*/this._getOffsetY(r); var r2, y1, y2, rFrozen, heightDiff = -this.getScrollCorrect(); if (y >= this.cellsTop) { if (this.topLeftFrozenCell) { rFrozen = this.topLeftFrozenCell.getRow0(); heightDiff = this._getRowTop(rFrozen) - this._getRowTop(0); if (y < this.cellsTop + heightDiff && 0 !== heightDiff) { r = 0; heightDiff = 0; } else { heightDiff -= this.getScrollCorrect(); } } for (y1 = this.cellsTop + heightDiff, r2 = this.nRowsCount - 1; r <= r2; ++r, y1 = y2) { h = this._getRowHeight(r); y2 = y1 + h; dy = half ? h / 2.0 * Math.sign(r - activeCellRow) : 0; if (y1 + dy > y) { if (r !== this.visibleRange.r1) { if (dy) { r -= 1; y2 = y1; y1 -= h; } return {row: r, top: y1, bottom: y2}; } else { r = r2; break; } } else if (y <= y2 + dy) { return {row: r, top: y1, bottom: y2}; } } if (!canReturnNull) { y1 = this._getRowTop(r2) - offset; return {row: r2, top: y1, bottom: y1 + this._getRowHeight(r2)}; } } else { if (this.topLeftFrozenCell) { rFrozen = this.topLeftFrozenCell.getRow0(); if (0 !== rFrozen) { r = 0; offset = this._getRowTop(r) - this.cellsTop; } } for (y2 = this.cellsTop + this._getRowHeight(r), r2 = 0; r >= r2; --r, y2 = y1) { y1 = this._getRowTop(r) - offset; if (y1 <= y && y < y2) { return {row: r, top: y1, bottom: y2}; } } if (!canReturnNull) { return {row: r2, top: y1, bottom: y1 + this._getRowHeight(r2)}; } } return null; }; WorksheetView.prototype._hitResizeCorner = function (x1, y1, x2, y2) { var wEps = AscCommon.global_mouseEvent.KoefPixToMM, hEps = AscCommon.global_mouseEvent.KoefPixToMM; return Math.abs(x2 - x1) <= wEps + 2 && Math.abs(y2 - y1) <= hEps + 2; }; WorksheetView.prototype._hitInRange = function (range, rangeType, vr, x, y, offsetX, offsetY, opt_pageBreakPreviewRange) { var wEps = 2 * AscCommon.global_mouseEvent.KoefPixToMM, hEps = 2 * AscCommon.global_mouseEvent.KoefPixToMM; var cursor, x1, x2, y1, y2, isResize; var col = -1, row = -1; var oFormulaRangeIn = range.intersectionSimple(vr); if (oFormulaRangeIn) { x1 = this._getColLeft(oFormulaRangeIn.c1) - offsetX; x2 = this._getColLeft(oFormulaRangeIn.c2 + 1) - offsetX; y1 = this._getRowTop(oFormulaRangeIn.r1) - offsetY; y2 = this._getRowTop(oFormulaRangeIn.r2 + 1) - offsetY; isResize = AscCommonExcel.selectionLineType.Resize & rangeType; if (isResize && this._hitResizeCorner(x1 - 1, y1 - 1, x, y)) { /*TOP-LEFT*/ cursor = kCurSEResize; col = range.c2; row = range.r2; } else if (isResize && this._hitResizeCorner(x2, y1 - 1, x, y)) { /*TOP-RIGHT*/ cursor = kCurNEResize; col = range.c1; row = range.r2; } else if (isResize && this._hitResizeCorner(x1 - 1, y2, x, y)) { /*BOTTOM-LEFT*/ cursor = kCurNEResize; col = range.c2; row = range.r1; } else if (this._hitResizeCorner(x2, y2, x, y)) { /*BOTTOM-RIGHT*/ cursor = kCurSEResize; col = range.c1; row = range.r1; } else if (opt_pageBreakPreviewRange) { if (hEps <= y - y1 && y - y2 <= hEps) { if (range.c1 === oFormulaRangeIn.c1 && Math.abs(x - x1) <= wEps) { //left side cursor = kCurEWResize; col = range.c1; } else if (range.c2 === oFormulaRangeIn.c2 && Math.abs(x - x2) <= wEps) { //right side cursor = kCurEWResize; col = range.c2; } } if (!cursor && wEps <= x - x1 && x - x2 <= wEps) { if (range.r1 === oFormulaRangeIn.r1 && Math.abs(y - y1) <= hEps) { //top side cursor = kCurNSResize; row = range.r1; } else if (range.r2 === oFormulaRangeIn.r2 && Math.abs(y - y2) <= hEps) { //bottom side cursor = kCurNSResize; row = range.r2; } } } else if ((((range.c1 === oFormulaRangeIn.c1 && Math.abs(x - x1) <= wEps) || (range.c2 === oFormulaRangeIn.c2 && Math.abs(x - x2) <= wEps)) && hEps <= y - y1 && y - y2 <= hEps) || (((range.r1 === oFormulaRangeIn.r1 && Math.abs(y - y1) <= hEps) || (range.r2 === oFormulaRangeIn.r2 && Math.abs(y - y2) <= hEps)) && wEps <= x - x1 && x - x2 <= wEps)) { cursor = kCurMove; } } return cursor ? { cursor: cursor, col: col, row: row } : null; }; WorksheetView.prototype._hitCursorSelectionRange = function (vr, x, y, offsetX, offsetY) { var res = this._hitInRange(this.model.getSelection().getLast(), AscCommonExcel.selectionLineType.Selection | AscCommonExcel.selectionLineType.ActiveCell | AscCommonExcel.selectionLineType.Promote, vr, x, y, offsetX, offsetY); return res ? { cursor: kCurMove === res.cursor ? kCurMove : kCurFillHandle, target: kCurMove === res.cursor ? c_oTargetType.MoveRange : c_oTargetType.FillHandle, col: -1, row: -1 } : null; }; WorksheetView.prototype._hitCursorPageBreakPreviewRange = function (vr, x, y, offsetX, offsetY) { let oPrintPages = this.isPageBreakPreview(true) && this.pagesModeData; let res = null; let _range = null; let pageBreakSelectionType = null;//1 - outer range, 2 - inner if (oPrintPages) { let printRanges = this._getPageBreakPreviewRanges(oPrintPages); //hit in all pages area if (printRanges) { for (let i = 0; i < printRanges.length; i++) { res = this._hitInRange(printRanges[i].range, AscCommonExcel.selectionLineType.Resize, vr, x, y, offsetX, offsetY, true); if (res) { _range = printRanges[i].range.clone(); pageBreakSelectionType = 1; break; } } } //hit inside pages lines if (!res) { let printPages = this.pagesModeData.printPages; if (printPages) { for (let i = 0; i < printPages.length; i++) { res = this._hitInRange(printPages[i].page.pageRange, AscCommonExcel.selectionLineType.Resize, vr, x, y, offsetX, offsetY, true); if (res) { for (let j = 0; j < printRanges.length; j++) { if (printPages[i].page.pageRange.intersection(printRanges[j].range)) { _range = printRanges[j].range.clone(); pageBreakSelectionType = 2; break; } } break; } } } } } return res ? { cursor: res.cursor, target: c_oTargetType.MoveResizeRange, col: res.col, row: res.row, range: _range, pageBreakSelectionType: pageBreakSelectionType } : null; }; WorksheetView.prototype._hitCursorSelectionVisibleArea = function (vr, x, y, offsetX, offsetY) { var range = this.getOleSize() && this.getOleSize().getLast(); if (!range) return null; var res = this._hitInRange(range, AscCommonExcel.selectionLineType.Resize, vr, x, y, offsetX, offsetY); return res ? { cursor: res.cursor, target: c_oTargetType.MoveResizeRange, col: res.col, row: res.row, isOleRange: true } : null; }; WorksheetView.prototype._hitCursorFormulaOrChart = function (vr, x, y, offsetX, offsetY) { if (!this.oOtherRanges) { return null; } var i, l, res; var oFormulaRange; var arrRanges = this.oOtherRanges.ranges; for (i = 0, l = arrRanges.length; i < l; ++i) { oFormulaRange = arrRanges[i]; res = !oFormulaRange.isName && this._hitInRange(oFormulaRange, AscCommonExcel.selectionLineType.Resize, vr, x, y, offsetX, offsetY); if (res) { break; } } return res ? { cursor: res.cursor, target: c_oTargetType.MoveResizeRange, col: res.col, row: res.row, indexFormulaRange: i } : null; }; WorksheetView.prototype._hitCursorTableRightCorner = function (vr, x, y, offsetX, offsetY) { var i, l, res, range; var tables = this.model.TableParts; var retinaKoef = this.getRetinaPixelRatio(); var row, col, baseLw, lnW, baseLnSize, lnSize, kF, x1, x2, y1, y2, rangeIn; var zoom = this.getZoom(); for (i = 0, l = tables.length; i < l; ++i) { range = new Asc.Range(tables[i].Ref.c2, tables[i].Ref.r2, tables[i].Ref.c2, tables[i].Ref.r2); rangeIn = range.intersectionSimple(vr); if(rangeIn) { baseLw = 2; lnW = Math.round(baseLw * zoom * retinaKoef); kF = lnW / baseLw; baseLnSize = 4; lnSize = kF * baseLnSize; row = range.r1; col = range.c1; x2 = this._getColLeft(col + 1) - offsetX; y2 = this._getRowTop(row + 1) - offsetY; x1 = x2 - lnSize; y1 = y2 - lnSize; if(x >= x1 && x <= x2 && y >= y1 && y <= y2) { res = true; break; } } } return res ? { cursor: kCurSEResize, target: c_oTargetType.FillHandle, col: col, row: row, tableIndex: i } : null; }; WorksheetView.prototype._hitCursorTableSelectionChange = function (x, y, row, col) { var i, l, res, range, t = this; var tables = this.model.TableParts; var _checkPos = function (_r1, _c1, isRow, isCol) { var x1 = t._getColLeft(_c1); var y1 = t._getRowTop(_r1); var x2 = t._getColLeft(_c1 + 1); var y2 = t._getRowTop(_r1 + 1); var height = y2 - y1; var width = x2 - x1; var _x2, _y2; //TODO коэффициэнты перепроверить var maxChangeSelectionHeight = 27; var maxChangeSelectionWidth = 24; var percentOfWidth = 0.25; var percentOfHeight = 0.3; if (isRow) { var tableSelectionHeight = height * percentOfHeight; if (tableSelectionHeight > maxChangeSelectionHeight) { tableSelectionHeight = maxChangeSelectionHeight; } _y2 = y1 + tableSelectionHeight; if (y >= y1 && y <= _y2) { return true; } } if (isCol) { var tableSelectionWidth = width * percentOfWidth; if (tableSelectionWidth > maxChangeSelectionWidth) { tableSelectionWidth = maxChangeSelectionWidth; } _x2 = x1 + tableSelectionWidth; if (x >= x1 && x <= _x2) { return true; } } return false; }; var type, cursor; for (i = 0, l = tables.length; i < l; ++i) { var _ref = tables[i].Ref; var onRow = null, onCol = null; range = new Asc.Range(_ref.c1, _ref.r1, _ref.c1, _ref.r2); if (range.contains(col, row)) { if (_checkPos(row, col, null, true)) { onRow = true; } } range = new Asc.Range(_ref.c1, _ref.r1, _ref.c2, _ref.r1); if (range.contains(col, row)) { if (_checkPos(row, col, true)) { onCol = true; } } if (onCol && onRow) { res = true; type = c_oAscChangeSelectionFormatTable.data; cursor = AscCommon.Cursors.SelectTableContent; break; } else if (onCol) { res = true; type = c_oAscChangeSelectionFormatTable.dataColumn; cursor = AscCommon.Cursors.SelectTableColumn; break; } else if (onRow) { res = true; type = c_oAscChangeSelectionFormatTable.row; cursor = AscCommon.Cursors.SelectTableRow; break; } } return res ? { cursor: cursor, target: c_oTargetType.TableSelectionChange, type: type, row: row, col: col, tableIndex: i } : null; }; WorksheetView.prototype.getCursorTypeFromXY = function (x, y, fromDoubleClickCall) { if (this.getRightToLeft()) { x = this.getCtxWidth() - x; } var canEdit = this.workbook.canEdit(); var viewMode = this.handlers.trigger('getViewMode'); this.handlers.trigger("checkLastWork"); var res, c, r, f, offsetX, offsetY, cellCursor; var sheetId = this.model.getId(), userId, lockRangePosLeft, lockRangePosTop, lockInfo, oHyperlink; var widthDiff = 0, heightDiff = 0, isLocked = false, target = c_oTargetType.Cells, row = -1, col = -1, isSelGraphicObject, isNotFirst, userIdForeignSelect, foreignSelectPosLeft, foreignSelectPosTop, shortIdForeignSelect; var dialogOtherRanges = this.getDialogOtherRanges(); var readyMode = !(this.getSelectionDialogMode() || this.getCellEditMode()); var oResDefault = {cursor: kCurDefault, target: c_oTargetType.None, col: -1, row: -1}; var t = this; if(this.workbook.Api.isEyedropperStarted()) { return {cursor: AscCommon.Cursors.Eyedropper, target: c_oTargetType.Cells, color: this.workbook.Api.getEyedropperColor(x, y)}; } const oPlaceholderCursor = this.objectRender.checkCursorPlaceholder(x, y); if (oPlaceholderCursor) { return {cursor: kCurDefault, target: c_oTargetType.Placeholder, col: -1, row: -1, placeholderType: oPlaceholderCursor.placeholderType}; } if (this.workbook.Api.isEditVisibleAreaOleEditor) { if (x >= this.cellsLeft && y >= this.cellsTop) { this._drawElements(function (_vr, _offsetX, _offsetY) { return (null === (res = this._hitCursorSelectionVisibleArea(_vr, x, y, _offsetX, _offsetY))); }); if (res) return res; return {cursor: AscCommon.Cursors.CellCur, target: c_oTargetType.Cells, col: -1, row: -1}; } else { return oResDefault; } } if (readyMode) { var frozenCursor = this._isFrozenAnchor(x, y); if (canEdit && frozenCursor.result) { lockInfo = this.collaborativeEditing.getLockInfo(c_oAscLockTypeElem.Object, null, sheetId, AscCommonExcel.c_oAscLockNameFrozenPane); isLocked = this.collaborativeEditing.getLockIntersection(lockInfo, c_oAscLockTypes.kLockTypeOther, false); if (false !== isLocked) { // Кто-то сделал lock var frozenCell = this.topLeftFrozenCell ? this.topLeftFrozenCell : new AscCommon.CellAddress(0, 0, 0); userId = isLocked.UserId; lockRangePosLeft = this._getColLeft(frozenCell.getCol0()); lockRangePosTop = this._getRowTop(frozenCell.getRow0()); } return { cursor: frozenCursor.cursor, target: frozenCursor.name, col: -1, row: -1, userId: userId, lockRangePosLeft: lockRangePosLeft, lockRangePosTop: lockRangePosTop }; } var drawingInfo = this.objectRender.checkCursorDrawingObject(this.getRightToLeft() ? this.getCtxWidth() - x : x, y); if ((asc["editor"].isStartAddShape || asc["editor"].isInkDrawerOn()) && AscCommonExcel.CheckIdSatetShapeAdd(this.objectRender.controller.curState)) { return {cursor: asc["editor"].isInkDrawerOn() ? kCurDefault : kCurFillHandle , target: c_oTargetType.Shape, col: -1, row: -1}; } if (drawingInfo && drawingInfo.id) { // Возможно картинка с lock lockInfo = this.collaborativeEditing.getLockInfo(c_oAscLockTypeElem.Object, null, sheetId, drawingInfo.id); isLocked = this.collaborativeEditing.getLockIntersection(lockInfo, c_oAscLockTypes.kLockTypeOther, false); if (false !== isLocked) { // Кто-то сделал lock userId = isLocked.UserId; lockRangePosLeft = drawingInfo.object.getVisibleLeftOffset(true); lockRangePosTop = drawingInfo.object.getVisibleTopOffset(true); } if (drawingInfo.hyperlink instanceof ParaHyperlink) { oHyperlink = new AscCommonExcel.Hyperlink(); oHyperlink.Tooltip = drawingInfo.hyperlink.ToolTip; var spl = drawingInfo.hyperlink.Value.split("!"); if (spl.length === 2) { oHyperlink.setLocation(drawingInfo.hyperlink.Value); } else { oHyperlink.Hyperlink = drawingInfo.hyperlink.Value; } cellCursor = {cursor: drawingInfo.cursor, target: c_oTargetType.Cells, col: -1, row: -1, userId: userId}; return { cursor: kCurHyperlink, target: c_oTargetType.Hyperlink, hyperlink: new asc_CHyperlink(oHyperlink), cellCursor: cellCursor, userId: userId }; } return { cursor: drawingInfo.cursor, tooltip: drawingInfo.tooltip, target: c_oTargetType.Shape, drawingId: drawingInfo.id, macro: drawingInfo.macro, col: -1, row: -1, userId: userId, lockRangePosLeft: lockRangePosLeft, lockRangePosTop: lockRangePosTop }; } } if (x >= this.headersLeft && x < this.cellsLeft && y < this.cellsTop && y >= this.headersTop) { return {cursor: kCurCorner, target: c_oTargetType.Corner, col: -1, row: -1}; } var cFrozen = -1, rFrozen = -1; offsetX = this._getOffsetX(); offsetY = this._getOffsetY(); if (this.topLeftFrozenCell) { cFrozen = this.topLeftFrozenCell.getCol0(); rFrozen = this.topLeftFrozenCell.getRow0(); widthDiff = this._getColLeft(cFrozen) - this._getColLeft(0); heightDiff = this._getRowTop(rFrozen) - this._getRowTop(0); offsetX = (x < this.cellsLeft + widthDiff) ? 0 : offsetX - widthDiff; offsetY = (y < this.cellsTop + heightDiff) ? 0 : offsetY - heightDiff; } //TODO проверить! //group row if (readyMode && x <= this.cellsLeft && this.groupWidth && x < this.groupWidth) { if(y > this.groupHeight + this.headersHeight) { r = this._findRowUnderCursor(y, true); } row = -1; if(r) { row = r.row + (isNotFirst && f && y < r.top + 3 ? -1 : 0); } return { cursor: kCurDefault, target: c_oTargetType.GroupRow, col: -1, row: row, mouseY: r ? (((y < r.top + 3) ? r.top : r.bottom) - y - 1) : null }; } //TODO проверить! //group col if (readyMode && y <= this.cellsTop && this.groupHeight && y < this.groupHeight) { c = null; if(x > this.groupWidth + this.headersWidth) { c = this._findColUnderCursor(x, true, null, true); } col = -1; if (c) { col = c.col + (isNotFirst && f && x < c.left + 3 ? -1 : 0); } return { cursor: kCurDefault, target: c_oTargetType.GroupCol, col: col, row: -1, mouseX: c ? (((x < c.left + 3) ? c.left : c.right) - x - 1) : null }; } let isMobileVersion = this.workbook && this.workbook.Api && this.workbook.Api.isMobileVersion; var epsChangeSize = AscCommon.AscBrowser.convertToRetinaValue(3 * AscCommon.global_mouseEvent.KoefPixToMM, true); if (x <= this.cellsLeft && y >= this.cellsTop && x >= this.headersLeft + this.getRightToLeftOffset()) { r = this._findRowUnderCursor(y, true); if (r === null) { return oResDefault; } isNotFirst = (r.row !== (-1 !== rFrozen ? 0 : this.visibleRange.r1)); f = (canEdit || viewMode) && (isNotFirst && y < r.top + epsChangeSize || y >= r.bottom - epsChangeSize) && readyMode && !this.model.getSheetProtection(Asc.c_oAscSheetProtectType.formatRows); let isSelectedFullRow = false; let selection = this._getSelection(); if (selection && selection.ranges) { for (let i = 0 ; i < selection.ranges.length; i++) { let curSelection = selection.ranges[i]; //move cols/rows was planned only for full version if (curSelection.getType() === Asc.c_oAscSelectionType.RangeRow && curSelection.r1 <= r.row && curSelection.r2 >= r.row) { isSelectedFullRow = true; break; } } } if (f && isMobileVersion) { f = isSelectedFullRow; } let _target = c_oTargetType.RowHeader; if (!f && !isMobileVersion) { if (isSelectedFullRow) { _target = c_oTargetType.ColumnRowHeaderMove; } } let _cursor = f ? AscCommon.Cursors.MoveBorderVer : AscCommon.Cursors.SelectTableRow; if (_target === c_oTargetType.ColumnRowHeaderMove) { _cursor = t.startCellMoveRange && t.startCellMoveRange.colRowMoveProps ? "grabbing" : "grab"; } // ToDo В Excel зависимость epsilon от размера ячейки (у нас фиксированный 3) return { cursor: _cursor, target: f ? c_oTargetType.RowResize : _target, col: -1, row: r.row + (isNotFirst && f && y < r.top + epsChangeSize ? -1 : 0), mouseY: f ? (((y < r.top + epsChangeSize) ? r.top : r.bottom) - y - 1) : null }; } if (y <= this.cellsTop && x >= this.cellsLeft && y >= this.headersTop) { c = this._findColUnderCursor(x, true, null, true); if (c === null) { return oResDefault; } isNotFirst = c.col !== (-1 !== cFrozen ? 0 : this.visibleRange.c1); f = (canEdit || viewMode) && (isNotFirst && x < c.left + epsChangeSize || x >= c.right - epsChangeSize) && readyMode && !this.model.getSheetProtection(Asc.c_oAscSheetProtectType.formatColumns); // ToDo В Excel зависимость epsilon от размера ячейки (у нас фиксированный 3) let isSelectedFullCol = false; let selection = this._getSelection(); if (selection && selection.ranges) { for (let i = 0 ; i < selection.ranges.length; i++) { let curSelection = selection.ranges[i]; //move cols/rows was planned only for full version if (curSelection.getType() === Asc.c_oAscSelectionType.RangeCol && curSelection.c1 <= c.col && curSelection.c2 >= c.col) { isSelectedFullCol = true; break; } } } if (f && isMobileVersion) { f = isSelectedFullCol; } let _target = c_oTargetType.ColumnHeader; if (!f && !isMobileVersion) { if (isSelectedFullCol) { _target = c_oTargetType.ColumnRowHeaderMove; } } let _cursor = f ? AscCommon.Cursors.MoveBorderHor : AscCommon.Cursors.SelectTableColumn; if (_target === c_oTargetType.ColumnRowHeaderMove) { _cursor = t.startCellMoveRange && t.startCellMoveRange.colRowMoveProps ? "grabbing" : "grab"; } return { cursor: _cursor, target: f ? c_oTargetType.ColumnResize : _target, col: c.col + (isNotFirst && f && x < c.left + epsChangeSize ? -1 : 0), row: -1, mouseX: f ? (((x < c.left + epsChangeSize) ? c.left : c.right) - x - 1) : null }; } if (this.workbook.Api.getFormatPainterState()) { if (x <= this.cellsLeft && y >= this.cellsTop) { r = this._findRowUnderCursor(y, true); if (r !== null) { target = c_oTargetType.RowHeader; row = r.row; } } if (y <= this.cellsTop && x >= this.cellsLeft) { c = this._findColUnderCursor(x, true, null, true); if (c !== null) { target = c_oTargetType.ColumnHeader; col = c.col; } } let oData = this.workbook.Api.getFormatPainterData(); let sCursor = AscCommon.Cursors.CellFormatPainter; if(oData && oData.isDrawingData()) { sCursor = AscCommon.Cursors.ShapeCopy; } return {cursor: sCursor, target: target, col: col, row: row}; } if (dialogOtherRanges && (this.getFormulaEditMode() || this.isChartAreaEditMode)) { this._drawElements(function (_vr, _offsetX, _offsetY) { return (null === (res = this._hitCursorFormulaOrChart(_vr, x, y, _offsetX, _offsetY))); }); if (res) { return res; } } isSelGraphicObject = this.objectRender.selectedGraphicObjectsExists(); if (dialogOtherRanges && canEdit && !isSelGraphicObject && this.model.getSelection().isSingleRange()) { this._drawElements(function (_vr, _offsetX, _offsetY) { return (null === (res = this._hitCursorSelectionRange(_vr, x, y, _offsetX, _offsetY))); }); if (res) { return res; } } if (dialogOtherRanges && canEdit && !isSelGraphicObject) { this._drawElements(function (_vr, _offsetX, _offsetY) { return (null === (res = this._hitCursorPageBreakPreviewRange(_vr, x, y, _offsetX, _offsetY))); }); if (res) { return res; } } if (readyMode) { this._drawElements(function (_vr, _offsetX, _offsetY) { return (null === (res = this._hitCursorTableRightCorner(_vr, x, y, _offsetX, _offsetY))); }); if (res) { return res; } } if (x > this.cellsLeft && y > this.cellsTop) { c = this._findColUnderCursor(x, true, null, true); r = this._findRowUnderCursor(y, true); if (c === null || r === null) { return oResDefault; } // Проверка на совместное редактирование var lockRange = undefined; var lockAllPosLeft = undefined; var lockAllPosTop = undefined; var userIdAllProps = undefined; var userIdAllSheet = undefined; if (canEdit && this.collaborativeEditing.getCollaborativeEditing() && readyMode) { var c1Recalc = null, r1Recalc = null; var selectRangeRecalc = new asc_Range(c.col, r.row, c.col, r.row); // Пересчет для входящих ячеек в добавленные строки/столбцы var isIntersection = this._recalcRangeByInsertRowsAndColumns(sheetId, selectRangeRecalc); if (false === isIntersection) { lockInfo = this.collaborativeEditing.getLockInfo(c_oAscLockTypeElem.Range, /*subType*/null, sheetId, new AscCommonExcel.asc_CCollaborativeRange(selectRangeRecalc.c1, selectRangeRecalc.r1, selectRangeRecalc.c2, selectRangeRecalc.r2)); isLocked = this.collaborativeEditing.getLockIntersection(lockInfo, c_oAscLockTypes.kLockTypeOther, /*bCheckOnlyLockAll*/false); if (false !== isLocked) { // Кто-то сделал lock userId = isLocked.UserId; lockRange = isLocked.Element["rangeOrObjectId"]; c1Recalc = this.collaborativeEditing.m_oRecalcIndexColumns[sheetId].getLockOther(lockRange["c1"], c_oAscLockTypes.kLockTypeOther); r1Recalc = this.collaborativeEditing.m_oRecalcIndexRows[sheetId].getLockOther(lockRange["r1"], c_oAscLockTypes.kLockTypeOther); if (null !== c1Recalc && null !== r1Recalc) { lockRangePosLeft = this._getColLeft(c1Recalc); lockRangePosTop = this._getRowTop(r1Recalc); // Пересчитываем X и Y относительно видимой области lockRangePosLeft -= offsetX; lockRangePosTop -= offsetY; lockRangePosLeft = this.cellsLeft > lockRangePosLeft ? this.cellsLeft : lockRangePosLeft; lockRangePosTop = this.cellsTop > lockRangePosTop ? this.cellsTop : lockRangePosTop; } } } else { lockInfo = this.collaborativeEditing.getLockInfo(c_oAscLockTypeElem.Range, /*subType*/null, sheetId, null); } // Проверим не удален ли весь лист (именно удален, т.к. если просто залочен, то не рисуем рамку вокруг) lockInfo["type"] = c_oAscLockTypeElem.Sheet; isLocked = this.collaborativeEditing.getLockIntersection(lockInfo, c_oAscLockTypes.kLockTypeOther, /*bCheckOnlyLockAll*/true); if (false !== isLocked) { // Кто-то сделал lock userIdAllSheet = isLocked.UserId; } // Проверим не залочены ли все свойства листа (только если не удален весь лист) if (undefined === userIdAllSheet) { lockInfo["type"] = c_oAscLockTypeElem.Range; lockInfo["subType"] = c_oAscLockTypeElemSubType.InsertRows; isLocked = this.collaborativeEditing.getLockIntersection(lockInfo, c_oAscLockTypes.kLockTypeOther, /*bCheckOnlyLockAll*/true); if (false !== isLocked) { // Кто-то сделал lock userIdAllProps = isLocked.UserId; } } } //проверяем, не попали ли мы в чужой селект if (((canEdit && this.collaborativeEditing.getCollaborativeEditing()) || this.workbook.Api.isLiveViewer()) && readyMode && this.collaborativeEditing.getFast()) { var isForeignSelect = this.collaborativeEditing.getForeignSelectIntersection(c.col, r.row); if (isForeignSelect) { var foreignRow = isForeignSelect.ranges[0].r1; var foreignCol = isForeignSelect.ranges[0].c2; userIdForeignSelect = isForeignSelect.userId; shortIdForeignSelect = isForeignSelect.shortId; foreignSelectPosLeft = this._getColLeft(foreignCol) + this._getColumnWidth(foreignCol); foreignSelectPosTop = this._getRowTop(foreignRow); // Пересчитываем X и Y относительно видимой области foreignSelectPosLeft -= offsetX; foreignSelectPosTop -= offsetY; foreignSelectPosLeft = this.cellsLeft > foreignSelectPosLeft ? this.cellsLeft : foreignSelectPosLeft; foreignSelectPosTop = this.cellsTop > foreignSelectPosTop ? this.cellsTop : foreignSelectPosTop; } } if (canEdit && readyMode) { var _range = new asc_Range(c.col, r.row, c.col, r.row); var pivotButtons = !this.model.inTopAutoFilter(_range) && this.model.getPivotTableButtons(_range); var pivotButton = pivotButtons && pivotButtons.find(function (element) { return element.row === r.row && element.col === c.col; }); var activeCell = this.model.getSelection().activeCell; var dataValidation = this.model.getDataValidation(activeCell.col, activeCell.row); var isDataValidation = dataValidation && dataValidation.isListValues(); var isTableTotal = this.model.isTableTotal(activeCell.col, activeCell.row); col = activeCell.col; row = activeCell.row; this._drawElements(function (_vr, _offsetX, _offsetY) { res = null; var _isDataValidation = false; var _isPivot = false; var _isTableTotal = false; if (_vr.contains(c.col, r.row)) { _offsetX += x; _offsetY += y; if (isDataValidation) { var merged = this.model.getMergedByCell(row, col); if (merged) { row = merged.r1; col = merged.c2; } _isDataValidation = this._hitCursorFilterButton(_offsetX, _offsetY, col, row, true); } else if (pivotButton) { _isPivot = this._hitCursorFilterButton(_offsetX, _offsetY, c.col, r.row, null, pivotButton.idPivotCollapse); } else if (isTableTotal) { _isTableTotal = this._hitCursorFilterButton(_offsetX, _offsetY, col, row, true); } if (_isDataValidation) { res = {cursor: kCurAutoFilter, target: c_oTargetType.FilterObject, col: c.col, row: r.row, isDataValidation: _isDataValidation}; } else if (_isPivot && pivotButton) { if(pivotButton.idPivotCollapse) { if (!pivotButton.idPivotCollapse.hidden) { res = {cursor: kCurHyperlink, target: c_oTargetType.FilterObject, col: c.col, row: r.row, idPivotCollapse: pivotButton.idPivotCollapse}; } } else { res = {cursor: kCurAutoFilter, target: c_oTargetType.FilterObject, col: c.col, row: r.row, idPivot: pivotButton.idPivot}; } } else if (_isTableTotal) { res = {cursor: kCurAutoFilter, target: c_oTargetType.FilterObject, col: c.col, row: r.row, idTableTotal: {id: isTableTotal.index, colId: isTableTotal.colIndex}}; } else if (!pivotButton) { res = this.af_checkCursor(_offsetX, _offsetY, r.row, c.col); if (!res) { res = this._hitCursorTableSelectionChange(_offsetX, _offsetY, r.row, c.col); } } } return (null === res); }); if (res) { return res; } } // Проверим есть ли комменты var comment = readyMode && this.cellCommentator.getComment(c.col, r.row, true); var coords = null; var indexes = null; if (comment) { indexes = [comment.asc_getId()]; coords = this.cellCommentator.getCommentTooltipPosition(comment); } // Проверим, может мы в гиперлинке oHyperlink = readyMode && this.model.getHyperlinkByCell(r.row, c.col); cellCursor = { cursor: AscCommon.Cursors.CellCur, target: c_oTargetType.Cells, col: (c ? c.col : -1), row: (r ? r.row : -1), userId: userId, lockRangePosLeft: lockRangePosLeft, lockRangePosTop: lockRangePosTop, userIdAllProps: userIdAllProps, lockAllPosLeft: lockAllPosLeft, lockAllPosTop: lockAllPosTop, userIdAllSheet: userIdAllSheet, commentIndexes: indexes, commentCoords: coords, userIdForeignSelect: userIdForeignSelect, foreignSelectPosLeft: foreignSelectPosLeft, foreignSelectPosTop: foreignSelectPosTop, shortIdForeignSelect: shortIdForeignSelect }; if(!oHyperlink) { if (t.traceDependentsManager && t.traceDependentsManager.isHaveData) { /* we get the coordinates of all dependence lines and check whether the cursor hits */ let coordsArray = t.traceDependentsManager.tracesCoords; if (coordsArray) { const isClickOnLine = function(x, y, lineCoords, tolerance) { if (tolerance == null) { tolerance = 7; } const x1 = lineCoords.from.x; const y1 = lineCoords.from.y; const x2 = lineCoords.to.x; const y2 = lineCoords.to.y; // Math.hypot(3,4) = 5 - square root of the sum of the squares of its arguments // calculate distance from click point to line let distToLine = Math.abs((y2 - y1) * x - (x2 - x1) * y + x2 * y1 - y2 * x1) / Math.hypot(y2 - y1, x2 - x1); let zoom = t.getZoom(); if (!zoom) { zoom = 1; } tolerance = (zoom < 1) ? tolerance : tolerance * zoom; return distToLine <= tolerance; } for (let i = 0; i < coordsArray.length; i++) { let coordLineInfo = coordsArray[i]; if (isClickOnLine(x, y, coordLineInfo)) { if (fromDoubleClickCall) { return { cursor: kCurDefault, target: c_oTargetType.TraceDependents, cellCursor: cellCursor, coordLineInfo: coordLineInfo }; } else { // set cursor to default and targetType to traceDependents cellCursor.cursor = kCurDefault; cellCursor.target = c_oTargetType.TraceDependents; return cellCursor; } } } } } this.model.getCell3(r.row, c.col)._foreachNoEmpty(function (cell) { if (cell.isFormula()) { cell.processFormula(function(formulaParsed) { let formulaHyperlink = formulaParsed.getFormulaHyperlink(); if (formulaHyperlink) { //запсускаю пересчет в связи с тем, что после открытия значение не рассчитано, // но показывать результат при наведении на ссылку нужно if(null === formulaParsed.value || formulaParsed.getShared()) { formulaParsed.calculate(); } if(formulaParsed.value && formulaParsed.value.hyperlink) { oHyperlink = new AscCommonExcel.Hyperlink(); oHyperlink.Hyperlink = formulaParsed.value.hyperlink; oHyperlink.setHyperlinkFunction(true); } else if(formulaParsed.value && AscCommonExcel.cElementType.array === formulaParsed.value.type) { let firstArrayElem = formulaParsed.value.getElementRowCol(0,0); if(firstArrayElem && firstArrayElem.hyperlink) { oHyperlink = new AscCommonExcel.Hyperlink(); oHyperlink.Hyperlink = firstArrayElem.hyperlink; oHyperlink.setHyperlinkFunction(true); } } oHyperlink && oHyperlink.tryInitLocalLink(t.workbook.model); } }); } }); } if (oHyperlink) { return { cursor: kCurHyperlink, target: c_oTargetType.Hyperlink, hyperlink: new asc_CHyperlink(oHyperlink), cellCursor: cellCursor, userId: userId, lockRangePosLeft: lockRangePosLeft, lockRangePosTop: lockRangePosTop, userIdAllProps: userIdAllProps, userIdAllSheet: userIdAllSheet, lockAllPosLeft: lockAllPosLeft, lockAllPosTop: lockAllPosTop, commentIndexes: indexes, commentCoords: coords }; } return cellCursor; } return oResDefault; }; WorksheetView.prototype._fixSelectionOfMergedCells = function (fixedRange, onlyCells, customSelection) { var selection; var ar = fixedRange ? fixedRange : ((selection = customSelection || this._getSelection()) ? selection.getLast() : null); if (!ar || (onlyCells && c_oAscSelectionType.RangeCells !== ar.getType() && !this.getFormulaEditMode())) { return; } // ToDo - переделать этот момент!!!! var res = this.model.expandRangeByMerged(ar.clone(true)); if (ar.c1 !== res.c1 && ar.c1 !== res.c2) { ar.c1 = ar.c1 <= ar.c2 ? res.c1 : res.c2; } ar.c2 = ar.c1 === res.c1 ? res.c2 : (res.c1); if (ar.r1 !== res.r1 && ar.r1 !== res.r2) { ar.r1 = ar.r1 <= ar.r2 ? res.r1 : res.r2; } ar.r2 = ar.r1 === res.r1 ? res.r2 : res.r1; ar.normalize(); if (!fixedRange) { selection.update(); } }; WorksheetView.prototype._findVisibleCol = function (from, dc, flag) { var to = dc < 0 ? -1 : this.nColsCount, c; for (c = from; c !== to; c += dc) { if (0 < this._getColumnWidth(c)) { return c; } } return flag ? -1 : this._findVisibleCol(from, dc * -1, true); }; WorksheetView.prototype._findVisibleRow = function (from, dr, flag) { var to = dr < 0 ? -1 : this.nRowsCount, r; for (r = from; r !== to; r += dr) { if (0 < this._getRowHeight(r)){ return r; } } return flag ? -1 : this._findVisibleRow(from, dr * -1, true); }; WorksheetView.prototype._fixSelectionOfHiddenCells = function (dc, dr, range) { var ar = (range) ? range : this.model.selectionRange.getLast(), c1, c2, r1, r2, mc, i, arn = ar.clone(true); if (dc === undefined) { dc = +1; } if (dr === undefined) { dr = +1; } if (ar.c2 === ar.c1) { if (0 !== dc && 0 === this._getColumnWidth(ar.c1)) { c1 = c2 = this._findVisibleCol(ar.c1, dc); } } else { if (0 !== dc && this.nColsCount > ar.c2 && 0 === this._getColumnWidth(ar.c2)) { // Проверка для одновременно замерженных и скрытых ячеек (A1:C1 merge, B:C hidden) for (mc = null, i = arn.r1; i <= arn.r2; ++i) { mc = this.model.getMergedByCell(i, ar.c2); if (mc) { break; } } if (!mc) { c2 = this._findVisibleCol(ar.c2, dc); } } } if (c1 < 0 || c2 < 0) { throw new Error("Error: all columns are hidden"); } if (ar.r2 === ar.r1) { if (0 !== dr && 0 === this._getRowHeight(ar.r1)) { r1 = r2 = this._findVisibleRow(ar.r1, dr); } } else { if (0 !== dr && this.nRowsCount > ar.r2 && 0 === this._getRowHeight(ar.r2)) { //Проверка для одновременно замерженных и скрытых ячеек (A1:A3 merge, 2:3 hidden) for (mc = null, i = arn.c1; i <= arn.c2; ++i) { mc = this.model.getMergedByCell(ar.r2, i); if (mc) { break; } } if (!mc) { r2 = this._findVisibleRow(ar.r2, dr); } } } if (r1 < 0 || r2 < 0) { throw new Error("Error: all rows are hidden"); } ar.assign(c1 !== undefined ? c1 : ar.c1, r1 !== undefined ? r1 : ar.r1, c2 !== undefined ? c2 : ar.c2, r2 !== undefined ? r2 : ar.r2); }; WorksheetView.prototype._getRangeByXY = function (x, y) { var c1, r1, c2, r2; if (this.checkRtl(x) < this.cellsLeft && y < this.cellsTop) { c1 = r1 = 0; c2 = gc_nMaxCol0; r2 = gc_nMaxRow0; } else if (this.checkRtl(x) < this.cellsLeft) { r1 = r2 = this._findRowUnderCursor(y).row; c1 = 0; c2 = gc_nMaxCol0; } else if (y < this.cellsTop) { c1 = c2 = this._findColUnderCursor(x).col; r1 = 0; r2 = gc_nMaxRow0; } else { c1 = c2 = this._findColUnderCursor(x).col; r1 = r2 = this._findRowUnderCursor(y).row; } return new asc_Range(c1, r1, c2, r2); }; WorksheetView.prototype._moveActiveCellToXY = function (x, y, customSelection) { var selection = customSelection || this._getSelection(); var ar = selection.getLast(); var range = this._getRangeByXY(x, y); //protection if (this.model.getSheetProtection(Asc.c_oAscSheetProtectType.selectUnlockedCells)) { return; } if (this.model.getSheetProtection(Asc.c_oAscSheetProtectType.selectLockedCells)) { var lockedCell = this.model.getLockedCell(range.c1, range.r1); if (lockedCell || lockedCell === null) { return; } } ar.assign(range.c1, range.r1, range.c2, range.r2); var r = range.r1, c = range.c1; switch (ar.getType()) { case c_oAscSelectionType.RangeCol: r = this.visibleRange.r1; break; case c_oAscSelectionType.RangeRow: c = this.visibleRange.c1; break; case c_oAscSelectionType.RangeMax: r = this.visibleRange.r1; c = this.visibleRange.c1; break; } selection.setActiveCell(r, c); var valid = !this.getFormulaEditMode() && selection.validActiveCell(); this._fixSelectionOfMergedCells(null, valid, customSelection); }; WorksheetView.prototype._moveActiveCellToOffset = function (activeCell, dc, dr, customSelection) { var selection = customSelection || this._getSelection(); var ar = selection.getLast(); var mc = this.model.getMergedByCell(activeCell.row, activeCell.col); var c = mc ? (dc < 0 ? mc.c1 : dc > 0 ? Math.min(mc.c2, this.nColsCount - 1 - dc) : activeCell.col) : activeCell.col; var r = mc ? (dr < 0 ? mc.r1 : dr > 0 ? Math.min(mc.r2, this.nRowsCount - 1 - dr) : activeCell.row) : activeCell.row; var p = this._calcCellPosition(c, r, dc, dr); ar.assign(p.col, p.row, p.col, p.row); this.workbook.MacrosAddData(AscDFH.historydescription_Spreadsheet_SelectRange, [ar]); selection.setActiveCell(p.row, p.col); this._fixSelectionOfHiddenCells(dc >= 0 ? +1 : -1, dr >= 0 ? +1 : -1, ar); this._fixSelectionOfMergedCells(undefined, undefined, customSelection); }; // Движение активной ячейки в выделенной области WorksheetView.prototype._moveActivePointInSelection = function (dc, dr) { var t = this, cell = this.model.selectionRange.activeCell; // Если мы на скрытой строке или ячейке, то двигаться в выделении нельзя (так делает и Excel) if (0 === this._getColumnWidth(cell.col) || 0 === this._getRowHeight(cell.row)) { return; } return this.model.selectionRange.offsetCell(dr, dc, true, function (row, col) { return (0 === ((0 <= row) ? t._getRowHeight(row) : t._getColumnWidth(col))); }); }; WorksheetView.prototype._calcSelectionEndPointByXY = function (x, y, keepType, customSelection) { var originalSelection = customSelection || this._getSelection(); var activeCell = originalSelection.activeCell; var range = this._getRangeByXY(x, y); var selection = originalSelection.clone(); var res = keepType ? selection.getLast() : range.clone(); var type = res.getType(); if (c_oAscSelectionType.RangeRow === type) { res.r1 = Math.min(range.r1, activeCell.row); res.r2 = Math.max(range.r1, activeCell.row); } else if (c_oAscSelectionType.RangeCol === type) { res.c1 = Math.min(range.c1, activeCell.col); res.c2 = Math.max(range.c1, activeCell.col); } else if (c_oAscSelectionType.RangeCells === type) { res.assign(activeCell.col, activeCell.row, range.c1, range.r1, true); } selection.getLast().assign2(res); this._fixSelectionOfMergedCells(res, selection.validActiveCell(), customSelection); return res; }; WorksheetView.prototype._calcSelectionEndPointByOffset = function (dc, dr, customSelection) { var selection = customSelection || this._getSelection(); var ar = selection.getLast(); var activeCell = selection.activeCell; var c1, r1, c2, r2, tmp; var indivisibleCell = ar.clone(true); indivisibleCell.c1 = activeCell.col; indivisibleCell.c2 = activeCell.col; this._fixSelectionOfMergedCells(indivisibleCell, customSelection); tmp = asc.getEndValueRange(dc, ar.c1, ar.c2, indivisibleCell.c1, indivisibleCell.c2); c1 = tmp.x1; c2 = tmp.x2; indivisibleCell = ar.clone(true); indivisibleCell.r1 = activeCell.row; indivisibleCell.r2 = activeCell.row; this._fixSelectionOfMergedCells(indivisibleCell, customSelection); tmp = asc.getEndValueRange(dr, ar.r1, ar.r2, indivisibleCell.r1, indivisibleCell.r2); r1 = tmp.x1; r2 = tmp.x2; var p1 = this._calcCellPosition(c2, r2, dc, dr), p2; var res = new asc_Range(c1, r1, c2 = p1.col, r2 = p1.row, true); dc = Math.sign(dc); dr = Math.sign(dr); this._fixSelectionOfMergedCells(res, customSelection); while (ar.isEqual(res)) { p2 = this._calcCellPosition(c2, r2, dc, dr); res.assign(c1, r1, c2 = p2.col, r2 = p2.row, true); this._fixSelectionOfMergedCells(res, customSelection); if (p1.col === p2.col && p1.row === p2.row) { break; } p1 = p2; } var bIsHidden = false; if (0 !== dc && 0 === this._getColumnWidth(c2)) { c2 = this._findVisibleCol(c2, dc); bIsHidden = true; } if (0 !== dr && 0 === this._getRowHeight(r2)) { r2 = this._findVisibleRow(r2, dr); bIsHidden = true; } if (bIsHidden) { res.assign(c1, r1, c2, r2, true); } return res; }; WorksheetView.prototype._calcActiveRangeOffsetIsCoord = function (x, y, customSelection) { var originalSelection = customSelection || this._getSelection(); var ar = originalSelection.getLast(); if (this.getFormulaEditMode()) { // Для формул нужно сделать ограничение по range (у нас хранится полный диапазон) if (ar.c2 >= this.nColsCount || ar.r2 >= this.nRowsCount) { ar = ar.clone(true); ar.c2 = (ar.c2 >= this.nColsCount) ? this.nColsCount - 1 : ar.c2; ar.r2 = (ar.r2 >= this.nRowsCount) ? this.nRowsCount - 1 : ar.r2; } } var d = new AscCommon.CellBase(0, 0); if (y <= this.cellsTop + 2) { d.row = -1; } else if (y >= this.drawingCtx.getHeight() - 2) { d.row = 1; } if (x <= this.cellsLeft + 2) { d.col = -1; } else if (x >= this.drawingCtx.getWidth() - 2) { d.col = 1; } var type = ar.getType(); if (type === c_oAscSelectionType.RangeRow) { d.col = 0; } else if (type === c_oAscSelectionType.RangeCol) { d.row = 0; } else if (type === c_oAscSelectionType.RangeMax) { d.col = 0; d.row = 0; } return d; }; WorksheetView.prototype._calcRangeOffset = function (range, diffRange, checkFrozen) { let vr = this.visibleRange; let ar = range || this._getSelection().getLast(); if (this.getFormulaEditMode()) { // Для формул нужно сделать ограничение по range (у нас хранится полный диапазон) if (ar.c2 >= this.nColsCount || ar.r2 >= this.nRowsCount) { ar = ar.clone(true); ar.c2 = (ar.c2 >= this.nColsCount) ? this.nColsCount - 1 : ar.c2; ar.r2 = (ar.r2 >= this.nRowsCount) ? this.nRowsCount - 1 : ar.r2; } } let arn = ar.clone(true); let isMC = this._isMergedCells(arn); let adjustRight = ar.c2 >= vr.c2 || ar.c1 >= vr.c2 && isMC; let adjustBottom = ar.r2 >= vr.r2 || ar.r1 >= vr.r2 && isMC; let incX = ar.c1 < vr.c1 && isMC ? arn.c1 - vr.c1 : ar.c2 < vr.c1 ? ar.c2 - vr.c1 : 0; let incY = ar.r1 < vr.r1 && isMC ? arn.r1 - vr.r1 : ar.r2 < vr.r1 ? ar.r2 - vr.r1 : 0; let type = ar.getType(); if (diffRange) { if (diffRange.c1 < 0 && ar.c1 < vr.c1) { incX = arn.c1 - vr.c1; adjustRight = false; } if (diffRange.r1 < 0 && ar.r1 < vr.r1) { incY = arn.r1 - vr.r1; adjustBottom = false; } if(diffRange.c1 === 0 && diffRange.c2 === 0 && diffRange.r1 === 0 && diffRange.r2 === 0) { adjustRight = false; adjustBottom = false; } } let offsetFrozen = this.getFrozenPaneOffset(); let t = this; let _compare = function (start, end, byCol) { let res; if (byCol) { res = t.drawingCtx.getWidth() > t._getColLeft(end + 1) - t._getColLeft(start); } else { res = t.drawingCtx.getHeight() > t._getRowTop(end + 1) - t._getRowTop(start); } return res; }; if (checkFrozen && this.topLeftFrozenCell) { let cFrozen = this.topLeftFrozenCell.getCol0(); let rFrozen = this.topLeftFrozenCell.getRow0(); if (ar.r2 < rFrozen) { incY = 0; } if (ar.c2 < cFrozen) { incX = 0; } } if (adjustRight) { //isMC: if visible range can contains merge range -> try to find offset while (this._isColDrawnPartially(isMC ? (_compare(arn.c1, arn.c2, true) ? arn.c2 : arn.c1) : ar.c2, vr.c1 + incX, offsetFrozen.offsetX)) { ++incX; } } if (adjustBottom) { while (this._isRowDrawnPartially(isMC ? (_compare(arn.r1, arn.r2) ? arn.r2 : arn.r1) : ar.r2, vr.r1 + incY, offsetFrozen.offsetY)) { ++incY; } } return new AscCommon.CellBase(type === c_oAscSelectionType.RangeRow || type === c_oAscSelectionType.RangeCells ? incY : 0, type === c_oAscSelectionType.RangeCol || type === c_oAscSelectionType.RangeCells ? incX : 0); }; WorksheetView.prototype._scrollToRange = function (range) { if (window['IS_NATIVE_EDITOR']) { return null; } var vr = this.visibleRange; var nRowsCount = this.nRowsCount; var nColsCount = this.nColsCount; var selection = this.model.selectionRange || this.model.copySelection; var ar = range || selection.getLast(); if (this.getFormulaEditMode()) { // Для формул нужно сделать ограничение по range (у нас хранится полный диапазон) if (ar.c2 >= this.nColsCount || ar.r2 >= this.nRowsCount) { ar = ar.clone(true); ar.c2 = (ar.c2 >= this.nColsCount) ? this.nColsCount - 1 : ar.c2; ar.r2 = (ar.r2 >= this.nRowsCount) ? this.nRowsCount - 1 : ar.r2; } } var arn = ar.clone(true); var scroll = 0; if (!this.workbook.getSmoothScrolling() && !(this.workbook.SearchEngine && this.workbook.SearchEngine.changingSelection)) { if (arn.r1 < vr.r1) { scroll = this._rowDiffToSmooth(arn.r1, vr.r1); } else if (arn.r1 >= vr.r2) { this.nRowsCount = arn.r2 + 1; this._prepareCellTextMetricsCache(new asc_Range(vr.c1, vr.r2, vr.c2, arn.r2 + 1)); scroll = this.getVerticalScrollRange(true); if (scroll > this._rowToSmooth(arn.r1)) { scroll = this._rowToSmooth(arn.r1); } scroll -= this._rowDiffToSmooth(vr.r1, (this.topLeftFrozenCell ? this.topLeftFrozenCell.getRow0() : 0)); this.nRowsCount = nRowsCount; } } else { let toCenter = true; let offsetFrozen = this.getFrozenPaneOffset(true, false); let ctxH = this.drawingCtx.getHeight() - offsetFrozen.offsetY - this.cellsTop; var rFrozen = this.topLeftFrozenCell && this.topLeftFrozenCell.getRow0(); if (!rFrozen || arn.r1 > rFrozen) { if (arn.r1 < vr.r1) { scroll = this._rowDiffToSmooth(arn.r1, vr.r1, true) - this.getScrollCorrect() / this.getVScrollStep(); if (scroll && toCenter) { scroll -= ((ctxH - this._getRowHeight(arn.r1))/2)/this.getVScrollStep(); } } else if (arn.r1 >= vr.r2) { this.nRowsCount = arn.r2 + 1; this._prepareCellTextMetricsCache(new asc_Range(vr.c1, vr.r2, vr.c2, arn.r2 + 1)); this.nRowsCount = nRowsCount; scroll = -this._rowDiffToSmooth(vr.r1, arn.r1, true) - this.getScrollCorrect() / this.getVScrollStep(); if (scroll && toCenter) { scroll -= (ctxH/2 - this._getRowHeight(arn.r1)/2)/this.getVScrollStep(); } } } } if (scroll) { this.scrollType |= AscCommonExcel.c_oAscScrollType.ScrollVertical; this.scrollVertical(scroll, null, true); } scroll = 0; if (!this.workbook.getSmoothScrolling() && !(this.workbook.SearchEngine && this.workbook.SearchEngine.changingSelection)) { if (arn.c1 < vr.c1) { scroll = this._colDiffToSmooth(arn.c1, vr.c1); } else if (arn.c1 >= vr.c2) { this.setColsCount(arn.c2 + 1 + 1); scroll = this.getHorizontalScrollRange(); if (scroll > this._colToSmooth(arn.c1)) { scroll = this._colToSmooth(arn.c1); } scroll -= this._colDiffToSmooth(vr.c1, (this.topLeftFrozenCell ? this.topLeftFrozenCell.getCol0() : 0)); this.setColsCount(nColsCount); } } else { let toCenter = true; let offsetFrozen = this.getFrozenPaneOffset(false, true); let ctxW = this.drawingCtx.getWidth() - offsetFrozen.offsetX - this.cellsLeft; var cFrozen = this.topLeftFrozenCell && this.topLeftFrozenCell.getCol0(); if (!cFrozen || arn.c1 > cFrozen) { if (arn.c1 < vr.c1) { scroll = this._colDiffToSmooth(arn.c1, vr.c1, true) - this.getHorizontalScrollCorrect() / this.getHScrollStep(); if (scroll && toCenter) { scroll -= ((ctxW - this._getColumnWidth(arn.c1))/2)/this.getHScrollStep(); } } else if (arn.c1 >= vr.c2) { this.setColsCount(arn.c2 + 1 + 1); this.setColsCount(nColsCount); scroll = -this._colDiffToSmooth(vr.c1, arn.c1, true) - this.getHorizontalScrollCorrect() / this.getHScrollStep(); if (scroll && toCenter) { scroll -= (ctxW/2 - this._getColumnWidth(arn.c1)/2)/this.getHScrollStep(); } } } } if (scroll) { this.scrollType |= AscCommonExcel.c_oAscScrollType.ScrollHorizontal; this.scrollHorizontal(scroll, null, true); } return null; }; WorksheetView.prototype.scrollToOleSize = function () { var oleSize = this.getOleSize().getLast(); if (oleSize) { this.scrollToCell(oleSize.r1, oleSize.c1); } }; /** * @param {Range} [range] * @returns {AscCommon.CellBase} */ WorksheetView.prototype._calcActiveCellOffset = function (range) { var vr = this.visibleRange; var activeCell = this.model.selectionRange.activeCell; var ar = range ? range : this.model.selectionRange.getLast(); var mc = this.model.getMergedByCell(activeCell.row, activeCell.col); var startCol = mc ? mc.c1 : activeCell.col; var startRow = mc ? mc.r1 : activeCell.row; var incX = startCol < vr.c1 ? startCol - vr.c1 : 0; var incY = startRow < vr.r1 ? startRow - vr.r1 : 0; var type = ar.getType(); var offsetFrozen = this.getFrozenPaneOffset(); // adjustRight if (startCol >= vr.c2) { while (this._isColDrawnPartially(startCol, vr.c1 + incX, offsetFrozen.offsetX)) { ++incX; } } // adjustBottom if (startRow >= vr.r2) { while (this._isRowDrawnPartially(startRow, vr.r1 + incY, offsetFrozen.offsetY)) { ++incY; } } return new AscCommon.CellBase(type === c_oAscSelectionType.RangeRow || type === c_oAscSelectionType.RangeCells ? incY : 0, type === c_oAscSelectionType.RangeCol || type === c_oAscSelectionType.RangeCells ? incX : 0); }; // Потеряем ли мы что-то при merge ячеек WorksheetView.prototype.getSelectionMergeInfo = function (options) { // ToDo now check only last selection range var t = this; var arn = this.model.selectionRange.getLast().clone(true); var range = this.model.getRange3(arn.r1, arn.c1, arn.r2, arn.c2); var lastRow = -1, res; if (this.cellCommentator.isMissComments(arn)) { return true; } switch (options) { case c_oAscMergeOptions.Merge: case c_oAscMergeOptions.MergeCenter: res = range._foreachNoEmptyByCol(function(cell) { if (false === t._isCellNullText(cell)) { if (-1 !== lastRow) { return true; } lastRow = cell.nRow; } }); break; case c_oAscMergeOptions.MergeAcross: res = range._foreachNoEmpty(function(cell) { if (false === t._isCellNullText(cell)) { if (lastRow === cell.nRow) { return true; } lastRow = cell.nRow; } }); break; } return !!res; }; //нужно ли спрашивать пользователя о расширении диапазона WorksheetView.prototype.getSelectionSortInfo = function () { //в случае попытки сортировать мультиселект, необходимо выдавать ошибку var arn = this.model.selectionRange.getLast().clone(true); //null - не выдавать сообщение и не расширять, false - не выдавать сообщение и расширЯть, true - выдавать сообщение var bResult = Asc.c_oAscSelectionSortExpand.expandAndNotShowMessage; //если внутри форматированной таблиц, никогда не выдаем сообщение if(this.model.autoFilters._isTablePartsContainsRange(arn) || this.model.inPivotTable(arn)) { bResult = Asc.c_oAscSelectionSortExpand.notExpandAndNotShowMessage; } else if(!arn.isOneCell())//в случае одной выделенной ячейки - всегда не выдаём сообщение и автоматически расширяем { //если одна замерженная ячейка var cell = this.model.getRange3(arn.r1, arn.c1, arn.r2, arn.c2); var isMerged = cell.hasMerged(); if(isMerged && isMerged.isEqual(arn)) { return Asc.c_oAscSelectionSortExpand.expandAndNotShowMessage; } var colCount = arn.c2 - arn.c1 + 1; var rowCount = arn.r2 - arn.r1 + 1; //если выделено более одного столбца и более одной строки - не выдаем сообщение и не расширяем if(colCount > 1 && rowCount > 1) { bResult = Asc.c_oAscSelectionSortExpand.notExpandAndNotShowMessage; } else { //далее проверяем есть ли смежные ячейки у startCol/startRow var activeCell = this.model.selectionRange.activeCell; var activeCellRange = new Asc.Range(activeCell.col, activeCell.row, activeCell.col, activeCell.row); var expandRange = this.model.autoFilters.expandRange(activeCellRange, true); expandRange = this.model.autoFilters.checkExpandRangeForSort(expandRange); if (this.model.isUserProtectedRangesIntersection(expandRange)) { return c_oAscError.ID.ProtectedRangeByOtherUser; } if (this.model.getSheetProtection()) { var difference = arn.difference(expandRange); if (difference && difference.length) { for (var i = 0; i < difference.length; i++) { if (!this.model.protectedRangesContainsRange(difference[i], true) && this.model.isLockedRange(difference[i])) { return Asc.c_oAscSelectionSortExpand.showLockMessage; } } } } //если диапазон не расширяется за счет близлежащих ячеек - не выдаем сообщение и не расширяем if(arn.isEqual(expandRange) || activeCellRange.isEqual(expandRange)) { bResult = Asc.c_oAscSelectionSortExpand.notExpandAndNotShowMessage; } else if(arn.c1 === expandRange.c1 && arn.c2 === expandRange.c2) { bResult = Asc.c_oAscSelectionSortExpand.notExpandAndNotShowMessage; } else { bResult = Asc.c_oAscSelectionSortExpand.showExpandMessage; } } } return bResult; }; WorksheetView.prototype.getSelectionMathInfo = function (callback) { //TODO при выделении большого количетсва данных функция работает долго var oSelectionMathInfo = new asc_CSelectionMathInfo(); if (window["NATIVE_EDITOR_ENJINE"] || this.getSelectionDialogMode()) { return oSelectionMathInfo; } let t = this; let oAsyncSelectionMathInfo = t.asyncOperations && t.asyncOperations[asyncOperationsTypes["mathInfo"]]; if (oAsyncSelectionMathInfo) { oAsyncSelectionMathInfo.stop(); oAsyncSelectionMathInfo.clear(); oAsyncSelectionMathInfo = null; } let action = function (stopFunc, props) { let _ranges = props && props.ranges ? props.ranges : t.model.selectionRange.ranges; let _oExistCells = props && props.oExistCells ? props.oExistCells : {}; let _oSelectionMathInfo = props.oSelectionMathInfo; if (!_oSelectionMathInfo || !_ranges) { return; } for (let i = 0; i < _ranges.length; i++) { var cellValue; let item = _ranges[i]; var range = t.model.getRange3(item.r1, item.c1, item.r2, item.c2); let needBreak = false; let _col, _row; range._setPropertyNoEmpty(null, null, function (cell, r) { var idCell = cell.nCol + '-' + cell.nRow; if (!_oExistCells[idCell] && !cell.isNullTextString() && 0 < t._getRowHeight(r)) { _oExistCells[idCell] = true; ++_oSelectionMathInfo.count; if (CellValueType.Number === cell.getType()) { cellValue = cell.getNumberValue(); if (0 === _oSelectionMathInfo.countNumbers) { _oSelectionMathInfo.min = _oSelectionMathInfo.max = cellValue; } else { _oSelectionMathInfo.min = Math.min(_oSelectionMathInfo.min, cellValue); _oSelectionMathInfo.max = Math.max(_oSelectionMathInfo.max, cellValue); } ++_oSelectionMathInfo.countNumbers; props.sum += cellValue; } } _col = cell.nCol; _row = cell.nRow; if (stopFunc && stopFunc()) { needBreak = true; return true; } }); if (props.ranges) { if (needBreak) { if (_ranges[i].c2 === _col && _ranges[i].r2 === _row) { props.ranges = props.ranges.splice(i + 1); } else { let breakRange = _ranges[i]; props.ranges = props.ranges.splice(i + 1); //break before _col/_row and after and push into this.ranges let afterRanges = breakRange.sliceAfter(_col, _row); if (afterRanges) { props.ranges = props.ranges.concat(afterRanges) } } break; } else if (i === props.ranges.length - 1) { props.ranges = []; break; } } } }; let afterAction = function (_props) { let _oSelectionMathInfo = _props.oSelectionMathInfo; if (!_oSelectionMathInfo) { callback && callback(oSelectionMathInfo); return; } let sum = _props.sum; if (1 < _oSelectionMathInfo.count && 0 < _oSelectionMathInfo.countNumbers) { // Мы должны отдавать в формате активной ячейки var activeCell = t.model.selectionRange.activeCell; var numFormat = t.model.getRange3(activeCell.row, activeCell.col, activeCell.row, activeCell.col).getNumFormat(); if (Asc.c_oAscNumFormatType.Time === numFormat.getType()) { // Для времени нужно отдавать в формате [h]:mm:ss (http://bugzilla.onlyoffice.com/show_bug.cgi?id=26271) numFormat = AscCommon.oNumFormatCache.get('[h]:mm:ss'); } _oSelectionMathInfo.sum = numFormat.formatToMathInfo(sum, CellValueType.Number, t.settings.mathMaxDigCount); _oSelectionMathInfo.average = numFormat.formatToMathInfo(sum / _oSelectionMathInfo.countNumbers, CellValueType.Number, t.settings.mathMaxDigCount); _oSelectionMathInfo.min = numFormat.formatToMathInfo(_oSelectionMathInfo.min, CellValueType.Number, t.settings.mathMaxDigCount); _oSelectionMathInfo.max = numFormat.formatToMathInfo(_oSelectionMathInfo.max, CellValueType.Number, t.settings.mathMaxDigCount); } callback && callback(_oSelectionMathInfo); }; let nLargeArea = 3000000; let selectionSize = this.model.selectionRange.getSize(); if (selectionSize > nLargeArea) { if (!t.asyncOperations) { t.asyncOperations = {}; } //clean previous info t.handlers.trigger("selectionMathInfoChanged", oSelectionMathInfo); oAsyncSelectionMathInfo = new cAsyncAction(); t.asyncOperations[asyncOperationsTypes["mathInfo"]] = oAsyncSelectionMathInfo; oAsyncSelectionMathInfo.action = action; oAsyncSelectionMathInfo.callback = afterAction; oAsyncSelectionMathInfo.checkContinue = function () { return oAsyncSelectionMathInfo.props.ranges.length > 0; }; oAsyncSelectionMathInfo.props = {}; oAsyncSelectionMathInfo.props.oExistCells = {}; oAsyncSelectionMathInfo.props.oSelectionMathInfo = oSelectionMathInfo; oAsyncSelectionMathInfo.props.sum = 0; let cloneRanges = []; this.model.selectionRange.ranges.forEach(function (item) { cloneRanges.push(item.clone()); }); oAsyncSelectionMathInfo.props.ranges = cloneRanges; oAsyncSelectionMathInfo.start(); } else { let simpleProps = {oSelectionMathInfo: oSelectionMathInfo, sum: 0}; action(null, simpleProps); afterAction(simpleProps); } }; WorksheetView.prototype.getSelectionName = function (bRangeText) { if (this.isSelectOnShape) { const oController = this.objectRender.controller; if (oController && oController.selectedObjects.length === 1) { const oGroupSelection = oController.selection.groupSelection; if (oGroupSelection) { if (oGroupSelection.selectedObjects.length === 1) { return oGroupSelection.selectedObjects[0].getObjectName(); } } else { return oController.selectedObjects[0].getObjectName(); } } return " "; } var selection = this.model.selectionRange || this.model.copySelection; var ar = selection.getLast(); var cell = selection.activeCell; var mc = this.model.getMergedByCell(cell.row, cell.col); var c1 = mc ? mc.c1 : cell.col, r1 = mc ? mc.r1 : cell.row, ar_norm = ar.normalize(), mc_norm = mc ? mc.normalize() : null, c2 = mc_norm ? mc_norm.isEqual(ar_norm) ? mc_norm.c1 : ar_norm.c2 : ar_norm.c2, r2 = mc_norm ? mc_norm.isEqual(ar_norm) ? mc_norm.r1 : ar_norm.r2 : ar_norm.r2, selectionSize = !bRangeText ? "" : (function (r) { var rc = Math.abs(r.r2 - r.r1) + 1; var cc = Math.abs(r.c2 - r.c1) + 1; switch (r.getType()) { case c_oAscSelectionType.RangeCells: return rc + "R x " + cc + "C"; case c_oAscSelectionType.RangeCol: return cc + "C"; case c_oAscSelectionType.RangeRow: return rc + "R"; case c_oAscSelectionType.RangeMax: return gc_nMaxRow + "R x " + gc_nMaxCol + "C"; } return ""; })(ar); if (selectionSize) { return selectionSize; } var dN = new Asc.Range(ar_norm.c1, ar_norm.r1, c2, r2, true); var defName = parserHelp.get3DRef(this.model.getName(), dN.getAbsName()); defName = this.model.workbook.findDefinesNames(defName, this.model.getId(), true); if (defName) { return defName; } return (new Asc.Range(c1, r1, c1, r1)).getName(AscCommonExcel.g_R1C1Mode ? AscCommonExcel.referenceType.A : AscCommonExcel.referenceType.R); }; WorksheetView.prototype.convertOffsetToSmooth = function (offset) { if (!this.workbook.getSmoothScrolling()) { return offset; } let vr = this.visibleRange; if (offset.col !== 0) { let x1 = this.getCellLeft(vr.c1); let x2 = this.getCellLeft(Math.max(vr.c1 + offset.col, 0)); let rowsWidth = x2 - x1; let unitDeltaStep = this.getHScrollStep(); offset.col = rowsWidth / unitDeltaStep; offset.col -= this.getHorizontalScrollCorrect() / unitDeltaStep; } if (offset.row !== 0) { let y1 = this.getCellTop(vr.r1); let y2 = this.getCellTop(Math.max(vr.r1 + offset.row, 0)); let rowsHeight = y2 - y1; let unitDeltaStep = this.getVScrollStep(); offset.row = rowsHeight / unitDeltaStep; offset.row -= this.getScrollCorrect() / unitDeltaStep; } return offset; }; WorksheetView.prototype._colDiffToSmooth = function (from, to, skipScrollCorrect) { if (!this.workbook.getSmoothScrolling()) { return from - to; } let x1 = this.getCellLeft(from); let x2 = this.getCellLeft(to); let colsWidth = x1 - x2; let unitDeltaStep = this.getHScrollStep(); let res = colsWidth / unitDeltaStep; if (!skipScrollCorrect) { res = res < 0 ? res - this.getHorizontalScrollCorrect() / unitDeltaStep : res + this.getHorizontalScrollCorrect() / unitDeltaStep; } return res; }; WorksheetView.prototype._colToSmooth = function (val) { if (!this.workbook.getSmoothScrolling()) { return val; } let x1 = this.getCellLeft(val); let unitDeltaStep = this.getHScrollStep(); return x1 / unitDeltaStep; }; WorksheetView.prototype._rowDiffToSmooth = function (from, to, skipScrollCorrect) { if (!this.workbook.getSmoothScrolling()) { return from - to; } let y1 = this.getCellTop(from); let y2 = this.getCellTop(to); let rowsHeight = y1 - y2; let unitDeltaStep = this.getVScrollStep(); let res = rowsHeight / unitDeltaStep; if (!skipScrollCorrect) { res = res < 0 ? res - this.getScrollCorrect() / unitDeltaStep : res + this.getScrollCorrect() / unitDeltaStep; } return res; }; WorksheetView.prototype._rowToSmooth = function (val) { if (!this.workbook.getSmoothScrolling()) { return val; } let y1 = this.getCellTop(val); let unitDeltaStep = this.getVScrollStep(); return y1 / unitDeltaStep; }; WorksheetView.prototype.getSelectionRangeValue = function (absName, addSheet, addBook) { return this.getSelectionRangeValues(absName, addSheet, addBook).join(AscCommon.FormulaSeparators.functionArgumentSeparator); }; WorksheetView.prototype.getSelectionRangeValues = function (absName, addSheet, addBook) { // ToDo проблема с выбором целого столбца/строки var name, res = []; absName = absName || this.workbook.dialogAbsName; addSheet = addSheet || this.workbook.getDialogSheetName(); addBook = addBook || this.workbook.getDialogBookName(); if (this.model.selectionRange) { var ranges = this.model.selectionRange.ranges; //formula edit mode - check tables selection if (ranges.length === 1 && this.getFormulaEditMode()) { let tables = this.model.autoFilters.getTablesIntersectionRange(ranges[0]); if (tables && tables.length === 1) { let sTable = tables[0].getSelectionString(this.model.getSelection().activeCell, ranges[0]); if (sTable) { res.push(sTable); return res; } } } } for (let i = 0; i < ranges.length; ++i) { var name, res = []; absName = absName || this.workbook.dialogAbsName; addSheet = addSheet || this.workbook.getDialogSheetName(); addBook = addBook || this.workbook.getDialogBookName(); if (this.model.selectionRange) { var ranges = this.model.selectionRange.ranges; if (ranges.length === 1 && ranges[0].isOneCell() && this.getFormulaEditMode()) { let range = ranges[0]; /**@type {CT_pivotTableDefinition[]} */ let pivotTables = this.model.getPivotTablesIntersectingRange(range); if (pivotTables.length === 1) { let pivotTable = pivotTables[0]; let formula = pivotTable.getGetPivotDataFormulaByActiveCell(range.r1, range.c1, addSheet); if (formula) { res.push(formula); return res; } } } } for (let i = 0; i < ranges.length; ++i) { var range = ranges[i]; //делаю условие только для формул, просмотреть все остальные диапазоны if (this.getFormulaEditMode()) { var isMerged = this.model.getMergedByCell(range.r1, range.c1); if (isMerged && isMerged.isEqual(range)) { range = new Asc.Range(range.c1, range.r1, range.c1, range.r1); } } // ToDo проблема с выбором целого столбца/строки name = range.getName(absName ? AscCommonExcel.referenceType.A : AscCommonExcel.referenceType.R); let exPath = ""; if (addBook) { let api = this.getApi(); let isLocalDesktop = window["AscDesktopEditor"] && window["AscDesktopEditor"]["IsLocalFile"]() && window["AscDesktopEditor"]["LocalFileGetSaved"](); let externalSelectionController = this.workbook.externalSelectionController; let fromPath = isLocalDesktop && externalSelectionController && externalSelectionController.activeTabFormula && externalSelectionController.activeTabFormula.path; let thisPath = isLocalDesktop && window["AscDesktopEditor"]["LocalFileGetSourcePath"](); let titleName; if (fromPath && thisPath) { titleName = buildRelativePath(thisPath, fromPath); exPath = "[" + titleName + "]" name = "'" + exPath + this.model.getName() + "'!" + name; addSheet = false; } else { titleName = api.DocInfo.Title; exPath = "[" + titleName + "]"; } } if (addSheet) { name = parserHelp.get3DRef(exPath + this.model.getName(), name); } res.push(name); } } return res; }; WorksheetView.prototype.getSelectionInfo = function () { return this.objectRender.selectedGraphicObjectsExists() ? this._getSelectionInfoObject() : this._getSelectionInfoCell(); }; WorksheetView.prototype._getSelectionInfoCell = function () { var selectionRange = this.model.selectionRange; var cell = selectionRange.activeCell; var mc = this.model.getMergedByCell(cell.row, cell.col); var c1 = mc ? mc.c1 : cell.col; var r1 = mc ? mc.r1 : cell.row; var c = this._getVisibleCell(c1, r1); var cellType = c.getType(); var isNumberFormat = (!cellType || CellValueType.Number === cellType); var cell_info = new asc_CCellInfo(); cell_info.xfs = c.getXfs(false).clone(); AscCommonExcel.g_ActiveCell = new Asc.Range(c1, r1, c1, r1); cell_info.text = c.getValueForEdit(true); var tablePartsOptions = selectionRange.isSingleRange() ? this.model.autoFilters.searchRangeInTableParts(selectionRange.getLast()) : -2; var curTablePart = tablePartsOptions >= 0 ? this.model.TableParts[tablePartsOptions] : null; var tableStyleInfo = curTablePart && curTablePart.TableStyleInfo ? curTablePart.TableStyleInfo : null; cell_info.autoFilterInfo = new asc_CAutoFilterInfo(); var pivotTable; if (-2 === tablePartsOptions) { cell_info.autoFilterInfo.isAutoFilter = null; cell_info.autoFilterInfo.isApplyAutoFilter = false; } else if ((pivotTable = this.model.inPivotTable(selectionRange.getLast()))) { if (pivotTable.canSortByCell(cell.row, cell.col)) { cell_info.autoFilterInfo.isAutoFilter = true; } else { cell_info.autoFilterInfo.isAutoFilter = null; } cell_info.autoFilterInfo.isApplyAutoFilter = pivotTable.isClearFilterButtonEnabled(); } else { var checkApplyFilterOrSort = this.model.autoFilters.checkApplyFilterOrSort(tablePartsOptions); cell_info.autoFilterInfo.isAutoFilter = checkApplyFilterOrSort.isAutoFilter; cell_info.autoFilterInfo.isApplyAutoFilter = checkApplyFilterOrSort.isFilterColumns; cell_info.autoFilterInfo.isSlicerAdded = checkApplyFilterOrSort.isSlicerAdded; } if (curTablePart !== null) { cell_info.formatTableInfo = new AscCommonExcel.asc_CFormatTableInfo(); cell_info.formatTableInfo.tableName = curTablePart.DisplayName; if (tableStyleInfo) { cell_info.formatTableInfo.tableStyleName = tableStyleInfo.Name; cell_info.formatTableInfo.bandVer = tableStyleInfo.ShowColumnStripes; cell_info.formatTableInfo.firstCol = tableStyleInfo.ShowFirstColumn; cell_info.formatTableInfo.lastCol = tableStyleInfo.ShowLastColumn; cell_info.formatTableInfo.bandHor = tableStyleInfo.ShowRowStripes; } cell_info.formatTableInfo.lastRow = curTablePart.TotalsRowCount !== null; cell_info.formatTableInfo.firstRow = curTablePart.HeaderRowCount === null; cell_info.formatTableInfo.tableRange = curTablePart.Ref.getAbsName(); cell_info.formatTableInfo.filterButton = curTablePart.isShowButton(); cell_info.formatTableInfo.altText = curTablePart.altText; cell_info.formatTableInfo.altTextSummary = curTablePart.altTextSummary; this.af_setDisableProps(curTablePart, cell_info.formatTableInfo); } cell_info.styleName = c.getStyleName(); // ToDo activeRange type cell_info.selectionType = selectionRange.getLast().getType(); cell_info.multiselect = !selectionRange.isSingleRange(); cell_info.lockText = ("" !== cell_info.text && (isNumberFormat || c.isFormula())); // Получаем гиперссылку (//ToDo) var ar = selectionRange.getLast().clone(); let isOneColSelected = Math.abs(ar.c2 - ar.c1) + 1; var range = this.model.getRange3(ar.r1, ar.c1, ar.r2, ar.c2); var hyperlink = range.getHyperlink(); var oHyperlink; if (null !== hyperlink) { // Гиперлинк oHyperlink = new asc_CHyperlink(hyperlink); oHyperlink.asc_setText(cell_info.text); cell_info.hyperlink = oHyperlink; } else { cell_info.hyperlink = null; } //можно было бы просто возвратить от фукнции getComment undefined, но в билдере уже используется данная функция //и резуьтат документирован. оставляю так. cell_info.comment = this.cellCommentator.getComment(c1, r1, false, true); if (cell_info.comment && !AscCommon.UserInfoParser.canViewComment(cell_info.comment.sUserName)) { cell_info.comment = undefined; } cell_info.merge = range.isOneCell() ? Asc.c_oAscMergeOptions.Disabled : null !== range.hasMerged() ? Asc.c_oAscMergeOptions.Merge : Asc.c_oAscMergeOptions.None; var sheetId = this.model.getId(); var lockInfo; // Пересчет для входящих ячеек в добавленные строки/столбцы var isIntersection = this._recalcRangeByInsertRowsAndColumns(sheetId, ar); if (false === isIntersection) { lockInfo = this.collaborativeEditing.getLockInfo(c_oAscLockTypeElem.Range, /*subType*/null, sheetId, new AscCommonExcel.asc_CCollaborativeRange(ar.c1, ar.r1, ar.c2, ar.r2)); if (false !== this.collaborativeEditing.getLockIntersection(lockInfo, c_oAscLockTypes.kLockTypeOther, /*bCheckOnlyLockAll*/false)) { // Уже ячейку кто-то редактирует cell_info.isLocked = true; } } isIntersection = this.model.isUserProtectedRangesIntersection(ar); if (true === isIntersection) { cell_info.isUserProtected = true; } if (null !== curTablePart) { var tableAr = curTablePart.Ref.clone(); isIntersection = this._recalcRangeByInsertRowsAndColumns(sheetId, tableAr); if (false === isIntersection) { lockInfo = this.collaborativeEditing.getLockInfo(c_oAscLockTypeElem.Range, /*subType*/null, sheetId, new AscCommonExcel.asc_CCollaborativeRange(tableAr.c1, tableAr.r1, tableAr.c2, tableAr.r2)); if (false !== this.collaborativeEditing.getLockIntersection(lockInfo, c_oAscLockTypes.kLockTypeOther, /*bCheckOnlyLockAll*/false)) { // Уже таблицу кто-то редактирует cell_info.isLockedTable = true; } } } cell_info.sparklineInfo = this.model.getSparklineGroup(c1, r1); if (cell_info.sparklineInfo) { lockInfo = this.collaborativeEditing.getLockInfo(c_oAscLockTypeElem.Object, /*subType*/null, sheetId, cell_info.sparklineInfo.Get_Id()); if (false !== this.collaborativeEditing.getLockIntersection(lockInfo, c_oAscLockTypes.kLockTypeOther, /*bCheckOnlyLockAll*/false)) { cell_info.isLockedSparkline = true; } } cell_info.pivotTableInfo = this.model.getPivotTable(c1, r1); if (cell_info.pivotTableInfo) { lockInfo = this.collaborativeEditing.getLockInfo(c_oAscLockTypeElem.Object, /*subType*/null, sheetId, cell_info.pivotTableInfo.Get_Id()); if (false !== this.collaborativeEditing.getLockIntersection(lockInfo, c_oAscLockTypes.kLockTypeOther, /*bCheckOnlyLockAll*/false)) { cell_info.isLockedPivotTable = true; } } cell_info.dataValidation = this.model.getDataValidation(c1, r1); lockInfo = this.collaborativeEditing.getLockInfo(c_oAscLockTypeElem.Object, /*subType*/null, sheetId, AscCommonExcel.c_oAscHeaderFooterEdit); if (false !== this.collaborativeEditing.getLockIntersection(lockInfo, c_oAscLockTypes.kLockTypeOther, /*bCheckOnlyLockAll*/false)) { cell_info.isLockedHeaderFooter = true; } cell_info.selectedColsCount = isOneColSelected; return cell_info; }; WorksheetView.prototype._getSelectionInfoObject = function () { var objectInfo = new asc_CCellInfo(); var xfs = new AscCommonExcel.CellXfs(); var horAlign = null, vertAlign = null, angle = null; let readingOrder = null; var graphicObjects = this.objectRender.getSelectedGraphicObjects(); if (graphicObjects.length) { objectInfo.selectionType = this.objectRender.getGraphicSelectionType(graphicObjects[0].Id); } let oController = this.objectRender.controller; let oDocContent = oController.getTargetDocContent(); if(oDocContent) { let oPr = new CSelectedElementsInfo({CheckAllSelection : true}) let oSelectedInfo = oDocContent.GetSelectedElementsInfo(oPr); let oMath = oSelectedInfo.GetMath(); } var textPr = oController.getParagraphTextPr(); var theme = oController.getTheme(); if (textPr && theme && theme.themeElements && theme.themeElements.fontScheme) { textPr.ReplaceThemeFonts(theme.themeElements.fontScheme); } var paraPr = oController.getParagraphParaPr(); if (!paraPr && textPr) { paraPr = new CParaPr(); } if (textPr && paraPr) { objectInfo.text = oController.GetSelectedText(true); horAlign = paraPr.Jc; readingOrder = paraPr.Bidi === true ? Asc.c_oReadingOrderTypes.RTL : null; vertAlign = Asc.c_oAscVAlign.Center; var shape_props = oController.getDrawingProps().shapeProps; if (shape_props) { switch (shape_props.verticalTextAlign) { case AscFormat.VERTICAL_ANCHOR_TYPE_BOTTOM: vertAlign = Asc.c_oAscVAlign.Bottom; break; case AscFormat.VERTICAL_ANCHOR_TYPE_CENTER: vertAlign = Asc.c_oAscVAlign.Center; break; case AscFormat.VERTICAL_ANCHOR_TYPE_TOP: case AscFormat.VERTICAL_ANCHOR_TYPE_DISTRIBUTED: case AscFormat.VERTICAL_ANCHOR_TYPE_JUSTIFIED: vertAlign = Asc.c_oAscVAlign.Top; break; } switch (shape_props.vert) { case AscFormat.nVertTTvert: angle = -90; break; case AscFormat.nVertTTvert270: angle = 90; break; default: angle = 0; break; } } if (textPr.Unifill && theme) { textPr.Unifill.check(theme, oController.getColorMap()); } var font = new AscCommonExcel.Font(); font.assignFromTextPr(textPr); xfs.setFont(font); var shapeHyperlink = oController.getHyperlinkInfo(); if (shapeHyperlink && (shapeHyperlink instanceof ParaHyperlink)) { var hyperlink = new AscCommonExcel.Hyperlink(); hyperlink.Tooltip = shapeHyperlink.ToolTip; var spl = shapeHyperlink.Value.split("!"); if (spl.length === 2) { hyperlink.setLocation(shapeHyperlink.Value); } else { hyperlink.Hyperlink = shapeHyperlink.Value; } objectInfo.hyperlink = new asc_CHyperlink(hyperlink); objectInfo.hyperlink.asc_setText(shapeHyperlink.GetSelectedText(true, true)); } } var align = new AscCommonExcel.Align(); align.setAlignHorizontal(horAlign); align.setReadingOrder(readingOrder); align.setAlignVertical(vertAlign); align.setAngle(angle); xfs.setAlign(align); objectInfo.xfs = xfs; // ToDo Нужно выставить правильный Fill // ToDo locks return objectInfo; }; // Получаем координаты активной ячейки WorksheetView.prototype.getActiveCellCoord = function (useUpRightMerge) { var selection = this.model.getSelection(); var row = selection.activeCell.row; var col = selection.activeCell.col; if (useUpRightMerge) { var merged = this.model.getMergedByCell(selection.activeCell.row, selection.activeCell.col); if (merged) { row = merged.r1; col = merged.c2; } } return this.getCellCoord(col, row); }; WorksheetView.prototype.getCellCoord = function (col, row) { var offsetX = 0, offsetY = 0; var vrCol = this.visibleRange.c1, vrRow = this.visibleRange.r1; if ( this.topLeftFrozenCell ) { var offsetFrozen = this.getFrozenPaneOffset(); var cFrozen = this.topLeftFrozenCell.getCol0(); var rFrozen = this.topLeftFrozenCell.getRow0(); if ( col >= cFrozen ) { offsetX = offsetFrozen.offsetX; } else { vrCol = 0; } if ( row >= rFrozen ) { offsetY = offsetFrozen.offsetY; } else { vrRow = 0; } } var xL = this._getColLeft(col); var yL = this._getRowTop(row); // Пересчитываем X и Y относительно видимой области xL -= (this._getOffsetX(vrCol)); yL -= (this._getOffsetY(vrRow)); // Пересчитываем X и Y относительно закрепленной области xL += offsetX; yL += offsetY; if (this.getRightToLeft()) { xL = this.getCtxWidth() - xL; } var width = this._getColumnWidth(col); if (this.getRightToLeft()) { width = -width; } var height = this._getRowHeight(row); if ( AscBrowser.isCustomScaling() ) { xL = AscCommon.AscBrowser.convertToRetinaValue(xL); yL = AscCommon.AscBrowser.convertToRetinaValue(yL); width = AscCommon.AscBrowser.convertToRetinaValue(width); height = AscCommon.AscBrowser.convertToRetinaValue(height); } return new AscCommon.asc_CRect( xL, yL, width, height ); }; WorksheetView.prototype._endSelectionShape = function () { var isSelectOnShape = this.isSelectOnShape; if (this.isSelectOnShape) { const oApi = Asc.editor || editor; this.isSelectOnShape = oApi.controller.isShapeAction = false; var bCleanSelection = false; if(this.objectRender.controller && this.objectRender.controller.getChartForRangesDrawing()) { bCleanSelection = true; } this.objectRender.unselectDrawingObjects(); if(bCleanSelection) { if(this.overlayCtx) { this.overlayCtx.clear(); } } this._drawSelection(); window['AscCommon'].g_specialPasteHelper.SpecialPasteButton_Update_Position(); } return isSelectOnShape; }; WorksheetView.prototype._updateSelectionNameAndInfo = function () { this.handlers.trigger("selectionNameChanged", this.getSelectionName(/*bRangeText*/false)); this.handlers.trigger("selectionChanged"); let t = this; this.getSelectionMathInfo(function (info) { t.handlers.trigger("selectionMathInfoChanged", info); }); }; WorksheetView.prototype.getSelectionShape = function () { return this.isSelectOnShape; }; WorksheetView.prototype.setSelectionShape = function ( isSelectOnShape ) { this.isSelectOnShape = isSelectOnShape; // отправляем евент для получения свойств картинки, шейпа или группы this.model.workbook.handlers.trigger( "asc_onHideComment" ); this._updateSelectionNameAndInfo(); window['AscCommon'].g_specialPasteHelper.SpecialPasteButton_Update_Position(); }; WorksheetView.prototype.setSelection = function (range, onlyCells) { if (!Array.isArray(range)) { range = [AscCommonExcel.Range.prototype.createFromBBox(this.model, range)]; } this.cleanSelection(); var bbox, bFirst = true; for (var i = 0; i < range.length; ++i) { bbox = range[i].getBBox0(); var type = bbox.getType(); if (type === c_oAscSelectionType.RangeCells || type === c_oAscSelectionType.RangeCol || type === c_oAscSelectionType.RangeRow || type === c_oAscSelectionType.RangeMax) { if (bFirst) { this.model.selectionRange.clean(); bFirst = false; } else { this.model.selectionRange.addRange(); } this.model.selectionRange.getLast().assign2(bbox); } } if (!bFirst) { this.model.selectionRange.update(); } this._fixSelectionOfMergedCells(null, onlyCells); this.updateSelectionWithSparklines(); this._updateSelectionNameAndInfo(); this._scrollToRange(); }; WorksheetView.prototype.setActiveCell = function (cell) { this.cleanSelection(); this.model.selectionRange.setActiveCell(cell.row, cell.col); var valid = !this.getFormulaEditMode() && this._getSelection().validActiveCell(); this._fixSelectionOfMergedCells(null, valid); this.updateSelectionWithSparklines(); this._updateSelectionNameAndInfo(); this._scrollToRange(); }; WorksheetView.prototype.changeSelectionStartPoint = function (x, y, isCoord, isCtrl) { this.cleanSelection(); this.endEditChart(); var activeCell = this._getSelection().activeCell.clone(); if (isCtrl) { this.model.selectionRange.addRange(); } else { this.model.selectionRange.clean(); } var ret = {}; var isChangeSelectionShape = false; var comment; if (isCoord) { comment = this.cellCommentator.getCommentByXY(x, y, true); // move active range to coordinates x,y this._moveActiveCellToXY(x, y); isChangeSelectionShape = this._endSelectionShape(); } else { comment = this.cellCommentator.getComment(x, y, true); // move active range to offset x,y this._moveActiveCellToOffset(activeCell, x, y); ret = this._calcRangeOffset(null, null, true); } if (!comment) { this.cellCommentator.resetLastSelectedId(); } if (!isChangeSelectionShape) { if (isCoord) { this._drawSelection(); } else { this.updateSelectionWithSparklines(); } } if (this.getSelectionDialogMode()) { // Смена диапазона let externalFormulaEditMode = this.workbook.externalSelectionController.getExternalFormulaEditMode(); this.handlers.trigger("selectionRangeChanged", this.getSelectionRangeValue(externalFormulaEditMode, externalFormulaEditMode, externalFormulaEditMode)); } else { this.handlers.trigger("selectionNameChanged", this.getSelectionName(/*bRangeText*/false)); if (!isCoord) { this.handlers.trigger("selectionChanged"); let t = this; this.getSelectionMathInfo(function (info) { t.handlers.trigger("selectionMathInfoChanged", info); }); } } //ToDo this.drawDepCells(); return ret; }; WorksheetView.prototype._drawVisibleArea = function () { var selectionLineType = AscCommonExcel.selectionLineType.DashThick; if (this.workbook.Api.isEditVisibleAreaOleEditor) { selectionLineType |= AscCommonExcel.selectionLineType.Resize; } var range = this.getOleSize().getLast(); this._drawElements(this._drawSelectionElement, range, selectionLineType, AscCommonExcel.c_oAscVisibleAreaOleEditorBorderColor); }; WorksheetView.prototype._drawPageBreakPreviewSelectionRange = function () { var range = this.pageBreakPreviewSelectionRange; if (this.pageBreakPreviewSelectionRange.pageBreakSelectionType === 2) { this._drawElements(this._drawLineBetweenRowCol, range.colByX, range.rowByY, this.settings.activeCellBorderColor, range, 2); } else { this._drawElements(this._drawSelectionElement, range, AscCommonExcel.selectionLineType.ResizeRange, this.settings.activeCellBorderColor); } }; WorksheetView.prototype.changeVisibleAreaStartPoint = function (x, y, isCtrl, isRelative) { this.cleanSelection(); this._endSelectionShape(); this.endEditChart(); var oleSize = this.getOleSize(); var activeCell = oleSize.activeCell.clone(); oleSize.clean(); var ret = {}; if (!isRelative) { this._moveActiveCellToXY(x, y, oleSize); } else { this._moveActiveCellToOffset(activeCell, x, y, oleSize); ret = this._calcRangeOffset(oleSize.getLast()); } this._drawSelection(); return ret; }; WorksheetView.prototype.changeVisibleAreaEndPoint = function (x, y, isCtrl, isRelative) { if (!isRelative) { if (x < this.cellsLeft) x = this.cellsLeft + 1; if (y < this.cellsTop) y = this.cellsTop + 1; } var isChangeSelectionShape = !isRelative ? this._endSelectionShape() : false; var oleSize = this.getOleSize(); var ar = oleSize.getLast(); var newRange = !isRelative ? this._calcSelectionEndPointByXY(x, y, undefined, oleSize) : this._calcSelectionEndPointByOffset(x, y, oleSize); var diffRange = {c1: newRange.c1 - ar.c1, c2: newRange.c2 - ar.c2, r1: newRange.r1 - ar.r1, r2: newRange.r2 - ar.r2}; var isEqual = newRange.isEqual(ar); if (!isEqual || isChangeSelectionShape) { this.cleanSelection(); ar.assign2(newRange); this._drawSelection(); } return !isRelative ? this._calcActiveRangeOffsetIsCoord(x, y, oleSize) : this._calcRangeOffset(oleSize.getLast(), diffRange); }; // Смена селекта по нажатию правой кнопки мыши WorksheetView.prototype.changeSelectionStartPointRightClick = function (x, y, target) { var isSelectOnShape = this._endSelectionShape(); this.model.workbook.handlers.trigger("asc_onHideComment"); var val, c1, c2, r1, r2, range; val = this._findColUnderCursor(x, true); if (val) { c1 = c2 = val.col; if (c_oTargetType.ColumnResize === target && 0 < c1 && 0 === this._getColumnWidth(c1 - 1)) { c1 = c2 = c1 - 1; } } else { c1 = 0; c2 = gc_nMaxCol0; } val = this._findRowUnderCursor(y, true); if (val) { r1 = r2 = val.row; if (c_oTargetType.RowResize === target && 0 < r1 && 0 === this._getRowHeight(r1 - 1)) { r1 = r2 = r1 - 1; } } else { r1 = 0; r2 = gc_nMaxRow0; } range = new asc_Range(c1, r1, c2, r2); if (!this.model.selectionRange.containsRange(range)) { // Не попали в выделение (меняем первую точку) this.cleanSelection(); this.model.selectionRange.clean(); this.setSelection(range, true); this._drawSelection(); this._updateSelectionNameAndInfo(); } else if (isSelectOnShape) { this._updateSelectionNameAndInfo(); } }; /** * * @param x - координата или прибавка к column * @param y - координата или прибавка к row * @param isCoord - выделение с помощью мышки или с клавиатуры. При выделении с помощью мышки, не нужно отправлять эвенты о смене выделения и информации * @param keepType * @returns {*} */ WorksheetView.prototype.changeSelectionEndPoint = function (x, y, isCoord, keepType) { var isChangeSelectionShape = isCoord ? this._endSelectionShape() : false; var ar = this._getSelection().getLast(); var newRange = isCoord ? this._calcSelectionEndPointByXY(x, y, keepType) : this._calcSelectionEndPointByOffset(x, y); var diffRange = {c1: newRange.c1 - ar.c1, c2: newRange.c2 - ar.c2, r1: newRange.r1 - ar.r1, r2: newRange.r2 - ar.r2}; var isEqual = newRange.isEqual(ar); if (!isEqual || isChangeSelectionShape) { //protection if (this.model.getSheetProtection(Asc.c_oAscSheetProtectType.selectUnlockedCells)) { return; } if (this.model.getSheetProtection(Asc.c_oAscSheetProtectType.selectLockedCells)) { var lockedCell = this.model.getLockedCell(newRange.c2, newRange.r2); if (lockedCell || lockedCell === null) { return; } } this.cleanSelection(); ar.assign2(newRange); this._drawSelection(); //ToDo this.drawDepCells(); if (this.getSelectionDialogMode()) { let externalFormulaEditMode = this.workbook.externalSelectionController.getExternalFormulaEditMode(); this.handlers.trigger("selectionRangeChanged", this.getSelectionRangeValue(externalFormulaEditMode, externalFormulaEditMode, externalFormulaEditMode)); } else { this.handlers.trigger("selectionNameChanged", this.getSelectionName(/*bRangeText*/true)); if (!isCoord) { this.handlers.trigger("selectionChanged"); let t = this; this.getSelectionMathInfo(function (info) { t.handlers.trigger("selectionMathInfoChanged", info); }); } } } this.model.workbook.handlers.trigger("asc_onHideComment"); return isCoord ? this._calcActiveRangeOffsetIsCoord(x, y) : this._calcRangeOffset(undefined, diffRange, true); }; // Окончание выделения WorksheetView.prototype.changeSelectionDone = function () { if (this.workbook.Api.getFormatPainterState()) { this.applyFormatPainter(); } else { this.checkSelectionSparkline(); } }; // Обработка движения в выделенной области WorksheetView.prototype.changeSelectionActivePoint = function (dc, dr) { var ret, res; if (0 === dc && 0 === dr) { return this._calcActiveCellOffset(); } res = this._moveActivePointInSelection(dc, dr); if (0 === res) { return this.changeSelectionStartPoint(dc, dr, /*isCoord*/false, false); } else if (-1 === res) { return null; } // Очищаем выделение this.cleanSelection(); this.endEditChart(); // Перерисовываем this.updateSelectionWithSparklines(); // Смотрим, ушли ли мы за границу видимой области ret = this._calcActiveCellOffset(); // Эвент обновления this.handlers.trigger("selectionNameChanged", this.getSelectionName(/*bRangeText*/false)); this.handlers.trigger("selectionChanged"); return ret; }; WorksheetView.prototype.checkSelectionSparkline = function () { if (!this.getSelectionShape() && !this.getCellEditMode()) { var cell = this.model.selectionRange.activeCell; var mc = this.model.getMergedByCell(cell.row, cell.col); var c1 = mc ? mc.c1 : cell.col; var r1 = mc ? mc.r1 : cell.row; var oSparklineInfo = this.model.getSparklineGroup(c1, r1); if (oSparklineInfo) { this.cleanSelection(); this.endEditChart(); var range = oSparklineInfo.getLocationRanges(); range.ranges.forEach(function (item) { item.isName = true; item.noColor = true; }); this.oOtherRanges = range; this._drawSelection(); return true; } } }; // ----- Changing cells ----- WorksheetView.prototype.applyFormatPainter = function () { let oData = this.workbook.Api.getFormatPainterData(); let oRange = oData && oData.range; if(oRange) { let t = this; let from = oRange.getLast(), to = this.model.selectionRange.getLast().clone(); let onApplyFormatPainterCallback = function (isSuccess) { // Очищаем выделение t.cleanSelection(); if (isSuccess) { AscCommonExcel.promoteFromTo(from, t.workbook.getFormatPainterSheet(), to, t.model); } // Сбрасываем параметры if (c_oAscFormatPainterState.kMultiple !== t.workbook.Api.getFormatPainterState()) { t.handlers.trigger('onStopFormatPainter', true); } if (isSuccess) { t._updateRange(to); } // Перерисовываем t.draw(); }; let result = AscCommonExcel.preparePromoteFromTo(from, to); if (!result) { // ToDo вывести ошибку onApplyFormatPainterCallback(false); return; } if (this.model.isUserProtectedRangesIntersection(to)) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ProtectedRangeByOtherUser, c_oAscError.Level.NoCritical); return; } //проверку отдельно добавляю, возможно стоит добавить внутрь preparePromoteFromTo if (this.model.getSheetProtection() && this.model.getSheetProtection(Asc.c_oAscSheetProtectType.formatCells)) { this.checkProtectRangeOnEdit([to], function (success) { if (success) { t._isLockedCells(to, null, onApplyFormatPainterCallback); } else { onApplyFormatPainterCallback(false); } }) } else { this._isLockedCells(to, null, onApplyFormatPainterCallback); } } }; WorksheetView.prototype.canFillHandle = function (range, checkColRowLimits) { //if don't have empty rows/columns //if all range is empty if (!range) { range = this.model.selectionRange.getLast().clone(); } range = typeof range === "string" ? AscCommonExcel.g_oRangeCache.getAscRange(range) : range; if (this.model.autoFilters._isEmptyRange(range)) { return false; } let rangeType = range && range.getType(); if (checkColRowLimits && (rangeType === c_oAscSelectionType.RangeRow || rangeType === c_oAscSelectionType.RangeCol || rangeType === c_oAscSelectionType.RangeMax)) { return false; } if (this.model.autoFilters._isEmptyRange(new Asc.Range(range.c1, range.r1, range.c2, range.r1))) { return true; } if (this.model.autoFilters._isEmptyRange(new Asc.Range(range.c1, range.r2, range.c2, range.r2))) { return true; } if (this.model.autoFilters._isEmptyRange(new Asc.Range(range.c1, range.r1, range.c1, range.r2))) { return true; } if (this.model.autoFilters._isEmptyRange(new Asc.Range(range.c2, range.r1, range.c2, range.r2))) { return true; } return false; }; WorksheetView.prototype.fillHandleDone = function (range) { let t = this; let doFill = function (_start, _end) { t.model.selectionRange.getLast().assign2(_start); t.activeFillHandle = _end.clone(); if (_start.r1 !== _end.r1 || _start.r2 !== _end.r2) { t.fillHandleDirection = 1; if (_start.r1 === _end.r1 && _start.r1 <= _end.r2 && _start.r2 >= _end.r2) { //inside range, go up t.activeFillHandle.r2 = _end.r2 + 1; t.activeFillHandle.r1 = _start.r2; t.fillHandleArea = 2; } else if (_end.r1 < _start.r1) { t.activeFillHandle.r2 = _end.r1; t.activeFillHandle.r1 = _start.r2; t.fillHandleArea = 1; } else if (_start.r1 === _end.r1 && _end.r2 > _start.r2) { t.activeFillHandle.r2 = _end.r2; t.activeFillHandle.r1 = _end.r1; t.fillHandleArea = 3; } } else { t.fillHandleDirection = 0; if (_start.c1 === _end.c1 && _start.c1 <= _end.c2 && _start.c2 >= _end.c2) { //inside range, gp down t.activeFillHandle.c2 = _end.c2 + 1; t.activeFillHandle.c1 = _start.c2; t.fillHandleArea = 2; } else if (_end.c1 < _start.c1) { t.activeFillHandle.c2 = _end.c1; t.activeFillHandle.c1 = _start.c2; t.fillHandleArea = 1; } else if (_start.c1 === _end.c1 && _end.c2 > _start.c2) { t.activeFillHandle.c2 = _end.c2; t.activeFillHandle.c1 = _end.c1; t.fillHandleArea = 3; } } t.applyFillHandle(null, null, null, true); }; //only end range - selected range //1. search base var activeCell = this.model.selectionRange.activeCell.clone(); if (!range) { range = this.model.selectionRange.getLast().clone(); } range = typeof range === "string" ? AscCommonExcel.g_oRangeCache.getAscRange(range) : range; let i; let baseRow1 = range.r1; let baseRow2 = range.r2; for (i = range.r1; i <= range.r2; i++) { if (this.model.autoFilters._isEmptyRange(new Asc.Range(range.c1, i, range.c2, i))) { baseRow1++; } else { break; } } for (i = range.r2; i >= range.r1; i--) { if (this.model.autoFilters._isEmptyRange(new Asc.Range(range.c1, i, range.c2, i))) { baseRow2--; } else { break; } } let baseCol1 = range.c1; let baseCol2 = range.c2; for (i = range.c1; i <= range.c2; i++) { if (this.model.autoFilters._isEmptyRange(new Asc.Range(i, range.r1, i, range.r2))) { baseCol1++; } else { break; } } for (i = range.c2; i >= range.c1; i--) { if (this.model.autoFilters._isEmptyRange(new Asc.Range(i, range.r1, i, range.r2))) { baseCol2--; } else { break; } } History.Create_NewPoint(); History.StartTransaction(); let baseRange = new Asc.Range(baseCol1, baseRow1, baseCol2, baseRow2); //1. take base and expand up/down in empty cells if (range.r1 !== baseRow1) { doFill(baseRange, new Asc.Range(baseRange.c1, range.r1, baseRange.c2, baseRange.r2)); } if (range.r2 !== baseRow2) { doFill(baseRange, new Asc.Range(baseRange.c1, baseRange.r1, baseRange.c2, range.r2)); } //get new base baseRange = new Asc.Range(baseCol1, range.r1, baseCol2, range.r2); //2. take base and expand left/right in empty cells if (range.c1 !== baseCol1) { doFill(baseRange, new Asc.Range(range.c1, baseRange.r1, baseRange.c2, baseRange.r2)); } if (range.c2 !== baseCol2) { doFill(baseRange, new Asc.Range(baseRange.c1, baseRange.r1, range.c2, baseRange.r2)); } History.SetSelection(range); History.SetSelectionRedo(range); History.EndTransaction(); t.model.selectionRange.getLast().assign2(range); t.model.selectionRange.activeCell = activeCell; t.draw(); }; /* Функция для работы автозаполнения (selection). (x, y) - координаты точки мыши на области */ WorksheetView.prototype.changeSelectionFillHandle = function (x, y, tableIndex) { // Возвращаемый результат var ret = null; var t = this, table; var _checkTableRange = function () { var _range = t.activeFillHandle; if (table) { var _tableRange = table.Ref; if (_range.c2 < _tableRange.c1) { _range.c2 = _tableRange.c1; _range.c1 = _tableRange.c1; } var _r2 = table.isHeaderRow() ? _tableRange.r1 + 1 : _tableRange.r1; if (_range.r2 < _r2) { _range.r2 = _r2; _range.r1 = _tableRange.r1; } } }; var _getTableByIndex = function (index) { return t.model.TableParts && t.model.TableParts[index] ? t.model.TableParts[index] : null; }; // Если мы только первый раз попали сюда, то копируем выделенную область if (null === this.activeFillHandle) { if (undefined !== tableIndex) { table = _getTableByIndex(tableIndex); this.activeFillHandle = table ? table.Ref.clone() : null; this.resizeTableIndex = tableIndex; } else { this.activeFillHandle = this.model.getSelection().getLast().clone(); } // Для первого раза нормализуем (т.е. первая точка - это левый верхний угол) this.activeFillHandle.normalize(); return ret; } // Очищаем выделение, будем рисовать заново this.cleanSelection(); // Копируем выделенную область table = undefined !== this.resizeTableIndex ? _getTableByIndex(this.resizeTableIndex) : null; var ar = table ? table.Ref.clone() : this.model.getSelection().getLast().clone(true); // Получаем координаты левого верхнего угла выделения var xL = this._getColLeft(ar.c1, true); var yL = this._getRowTop(ar.r1); // Получаем координаты правого нижнего угла выделения var xR = this._getColLeft(ar.c2 + 1, true); var yR = this._getRowTop(ar.r2 + 1); // range для пересчета видимой области var activeFillHandleCopy; // Колонка по X и строка по Y var colByX = this._findColUnderCursor(x, /*canReturnNull*/false, true).col; var rowByY = this._findRowUnderCursor(y, /*canReturnNull*/false, true).row; // Колонка по X и строка по Y (без половинчатого счета). Для сдвига видимой области var colByXNoDX = this._findColUnderCursor(x, /*canReturnNull*/false, false).col; var rowByYNoDY = this._findRowUnderCursor(y, /*canReturnNull*/false, false).row; // Сдвиг в столбцах и строках от крайней точки var dCol; var dRow; // Пересчитываем X и Y относительно видимой области x += (this._getColLeft(this.visibleRange.c1, true) - this.cellsLeft); y += (this._getRowTop(this.visibleRange.r1) - this.cellsTop); // Вычисляем расстояние от (x, y) до (xL, yL) var dXL = x - xL; var dYL = y - yL; // Вычисляем расстояние от (x, y) до (xR, yR) var dXR = x - xR; var dYR = y - yR; var dXRMod; var dYRMod; // Определяем область попадания и точку /* (1) (2) (3) ------------|-----------------------|------------ | | (4) | (5) | (6) | | ------------|-----------------------|------------ (7) (8) (9) */ // Область точки (x, y) var _tmpArea = 0; if (dXR <= 0) { // Области (1), (2), (4), (5), (7), (8) if (dXL <= 0) { // Области (1), (4), (7) if (dYR <= 0) { // Области (1), (4) if (dYL <= 0) { // Область (1) _tmpArea = 1; } else { // Область (4) _tmpArea = 4; } } else { // Область (7) _tmpArea = 7; } } else { // Области (2), (5), (8) if (dYR <= 0) { // Области (2), (5) if (dYL <= 0) { // Область (2) _tmpArea = 2; } else { // Область (5) _tmpArea = 5; } } else { // Область (3) _tmpArea = 8; } } } else { // Области (3), (6), (9) if (dYR <= 0) { // Области (3), (6) if (dYL <= 0) { // Область (3) _tmpArea = 3; } else { // Область (6) _tmpArea = 6; } } else { // Область (9) _tmpArea = 9; } } // Проверяем, в каком направлении движение switch (_tmpArea) { case 2: case 8: // Двигаемся по вертикали. this.fillHandleDirection = 1; break; case 4: case 6: // Двигаемся по горизонтали. this.fillHandleDirection = 0; break; case 1: // Сравниваем расстояния от точки до левого верхнего угла выделения dXRMod = Math.abs(x - xL); dYRMod = Math.abs(y - yL); // Сдвиги по столбцам и строкам dCol = Math.abs(colByX - ar.c1); dRow = Math.abs(rowByY - ar.r1); // Определим направление позднее this.fillHandleDirection = -1; break; case 3: // Сравниваем расстояния от точки до правого верхнего угла выделения dXRMod = Math.abs(x - xR); dYRMod = Math.abs(y - yL); // Сдвиги по столбцам и строкам dCol = Math.abs(colByX - ar.c2); dRow = Math.abs(rowByY - ar.r1); // Определим направление позднее this.fillHandleDirection = -1; break; case 7: // Сравниваем расстояния от точки до левого нижнего угла выделения dXRMod = Math.abs(x - xL); dYRMod = Math.abs(y - yR); // Сдвиги по столбцам и строкам dCol = Math.abs(colByX - ar.c1); dRow = Math.abs(rowByY - ar.r2); // Определим направление позднее this.fillHandleDirection = -1; break; case 5: case 9: // Сравниваем расстояния от точки до правого нижнего угла выделения dXRMod = Math.abs(dXR); dYRMod = Math.abs(dYR); // Сдвиги по столбцам и строкам dCol = Math.abs(colByX - ar.c2); dRow = Math.abs(rowByY - ar.r2); // Определим направление позднее this.fillHandleDirection = -1; break; } //console.log(_tmpArea); // Возможно еще не определили направление if (-1 === this.fillHandleDirection) { // Проверим сдвиги по столбцам и строкам, если не поможет, то рассчитываем по расстоянию if (0 === dCol && 0 !== dRow) { // Двигаемся по вертикали. this.fillHandleDirection = 1; } else if (0 !== dCol && 0 === dRow) { // Двигаемся по горизонтали. this.fillHandleDirection = 0; } else if (dXRMod >= dYRMod) { // Двигаемся по горизонтали. this.fillHandleDirection = 0; } else { // Двигаемся по вертикали. this.fillHandleDirection = 1; } } // Проверяем, в каком направлении движение if (0 === this.fillHandleDirection) { // Определяем область попадания и точку /* | | | | (1) | (2) | (3) | | | | */ if (table) { this.fillHandleArea = 3; } else if (dXR <= 0) { // Область (1) или (2) if (dXL <= 0) { // Область (1) this.fillHandleArea = 1; } else { // Область (2) this.fillHandleArea = 2; } } else { // Область (3) this.fillHandleArea = 3; } // Находим колонку для точки this.activeFillHandle.c2 = colByX; switch (this.fillHandleArea) { case 1: // Первая точка (xR, yR), вторая точка (x, yL) this.activeFillHandle.c1 = ar.c2; this.activeFillHandle.r1 = ar.r2; this.activeFillHandle.r2 = ar.r1; // Случай, если мы еще не вышли из внутренней области if (this.activeFillHandle.c2 == ar.c1) { this.fillHandleArea = 2; } break; case 2: // Первая точка (xR, yR), вторая точка (x, yL) this.activeFillHandle.c1 = ar.c2; this.activeFillHandle.r1 = ar.r2; this.activeFillHandle.r2 = ar.r1; if (this.activeFillHandle.c2 > this.activeFillHandle.c1) { // Ситуация половинки последнего столбца this.activeFillHandle.c1 = ar.c1; this.activeFillHandle.r1 = ar.r1; this.activeFillHandle.c2 = ar.c1; this.activeFillHandle.r2 = ar.r1; } break; case 3: // Первая точка (xL, yL), вторая точка (x, yR) this.activeFillHandle.c1 = ar.c1; this.activeFillHandle.r1 = ar.r1; this.activeFillHandle.r2 = ar.r2; break; } if (table) { _checkTableRange(); } // Копируем в range для пересчета видимой области activeFillHandleCopy = this.activeFillHandle.clone(); activeFillHandleCopy.c2 = colByXNoDX; } else { // Определяем область попадания и точку /* (1) ____________________________ (2) ____________________________ (3) */ if (table) { this.fillHandleArea = 3; } else if (dYR <= 0) { // Область (1) или (2) if (dYL <= 0) { // Область (1) this.fillHandleArea = 1; } else { // Область (2) this.fillHandleArea = 2; } } else { // Область (3) this.fillHandleArea = 3; } // Находим строку для точки this.activeFillHandle.r2 = rowByY; switch (this.fillHandleArea) { case 1: // Первая точка (xR, yR), вторая точка (xL, y) this.activeFillHandle.c1 = ar.c2; this.activeFillHandle.r1 = ar.r2; this.activeFillHandle.c2 = ar.c1; // Случай, если мы еще не вышли из внутренней области if (this.activeFillHandle.r2 == ar.r1) { this.fillHandleArea = 2; } break; case 2: // Первая точка (xR, yR), вторая точка (xL, y) this.activeFillHandle.c1 = ar.c2; this.activeFillHandle.r1 = ar.r2; this.activeFillHandle.c2 = ar.c1; if (this.activeFillHandle.r2 > this.activeFillHandle.r1) { // Ситуация половинки последней строки this.activeFillHandle.c1 = ar.c1; this.activeFillHandle.r1 = ar.r1; this.activeFillHandle.c2 = ar.c1; this.activeFillHandle.r2 = ar.r1; } break; case 3: // Первая точка (xL, yL), вторая точка (xR, y) this.activeFillHandle.c1 = ar.c1; this.activeFillHandle.r1 = ar.r1; this.activeFillHandle.c2 = ar.c2; break; } if (table) { _checkTableRange(); } // Копируем в range для пересчета видимой области activeFillHandleCopy = this.activeFillHandle.clone(); activeFillHandleCopy.r2 = rowByYNoDY; } //console.log ("row1: " + this.activeFillHandle.r1 + " col1: " + this.activeFillHandle.c1 + " row2: " + this.activeFillHandle.r2 + " col2: " + this.activeFillHandle.c2); // Перерисовываем this._drawSelection(); // Смотрим, ушли ли мы за границу видимой области ret = this._calcRangeOffset(activeFillHandleCopy); this.model.workbook.handlers.trigger("asc_onHideComment"); return ret; }; /* Функция для применения автозаполнения */ WorksheetView.prototype.applyFillHandle = function (x, y, ctrlPress, opt_doNotDraw, callback) { let t = this; if (null !== this.resizeTableIndex) { let table = t.model.TableParts && t.model.TableParts[t.resizeTableIndex] ? t.model.TableParts[t.resizeTableIndex] : null; if (table && t.activeFillHandle) { let isError = this.af_checkChangeRange(t.activeFillHandle); if (isError !== null) { this.model.workbook.handlers.trigger("asc_onError", isError, c_oAscError.Level.NoCritical); } else { t.af_changeTableRange(table.DisplayName, t.activeFillHandle.clone()); } } !opt_doNotDraw && this.cleanSelection(); t.activeFillHandle = null; t.resizeTableIndex = null; t.fillHandleDirection = -1; !opt_doNotDraw && t._drawSelection(); callback && callback(false); return; } // Текущее выделение (к нему применится автозаполнение) let arn = t.model.selectionRange.getLast(); let range = t.model.getRange3(arn.r1, arn.c1, arn.r2, arn.c2); // Были ли изменения let bIsHaveChanges = false; // Вычисляем индекс сдвига let nIndex = 0; /*nIndex*/ if (0 === this.fillHandleDirection) { // Горизонтальное движение nIndex = this.activeFillHandle.c2 - arn.c1; if (2 === this.fillHandleArea) { // Для внутренности нужно вычесть 1 из значения bIsHaveChanges = arn.c2 !== (this.activeFillHandle.c2 - 1); } else { bIsHaveChanges = arn.c2 !== this.activeFillHandle.c2; } } else { // Вертикальное движение nIndex = this.activeFillHandle.r2 - arn.r1; if (2 === this.fillHandleArea) { // Для внутренности нужно вычесть 1 из значения bIsHaveChanges = arn.r2 !== (this.activeFillHandle.r2 - 1); } else { bIsHaveChanges = arn.r2 !== this.activeFillHandle.r2; } } // Меняли ли что-то if (bIsHaveChanges && (this.activeFillHandle.r1 !== this.activeFillHandle.r2 || this.activeFillHandle.c1 !== this.activeFillHandle.c2)) { // Диапазон ячеек, который мы будем менять let changedRange = arn.clone(); // Очищаем выделение this.cleanSelection(); if (2 === this.fillHandleArea) { // Мы внутри, будет удаление cбрасываем первую ячейку // Проверяем, удалили ли мы все (если да, то область не меняется) if (arn.c1 !== this.activeFillHandle.c2 || arn.r1 !== this.activeFillHandle.r2) { // Уменьшаем диапазон (мы удалили не все) if (0 === this.fillHandleDirection) { // Горизонтальное движение (для внутренности необходимо вычесть 1) arn.c2 = this.activeFillHandle.c2 - 1; changedRange.c1 = changedRange.c2; changedRange.c2 = this.activeFillHandle.c2; } else { // Вертикальное движение (для внутренности необходимо вычесть 1) arn.r2 = this.activeFillHandle.r2 - 1; changedRange.r1 = changedRange.r2; changedRange.r2 = this.activeFillHandle.r2; } } } else { // Мы вне выделения. Увеличиваем диапазон if (0 === this.fillHandleDirection) { // Горизонтальное движение if (1 === this.fillHandleArea) { arn.c1 = this.activeFillHandle.c2; changedRange.c2 = changedRange.c1 - 1; changedRange.c1 = this.activeFillHandle.c2; } else { arn.c2 = this.activeFillHandle.c2; changedRange.c1 = changedRange.c2 + 1; changedRange.c2 = this.activeFillHandle.c2; } } else { // Вертикальное движение if (1 === this.fillHandleArea) { arn.r1 = this.activeFillHandle.r2; changedRange.r2 = changedRange.r1 - 1; changedRange.r1 = this.activeFillHandle.r2; } else { arn.r2 = this.activeFillHandle.r2; changedRange.r1 = changedRange.r2 + 1; changedRange.r2 = this.activeFillHandle.r2; } } } changedRange.normalize(); let applyFillHandleCallback = function (res) { if (res) { // Автозаполняем ячейки let oCanPromote = range.canPromote(/*bCtrl*/ctrlPress, /*bVertical*/(1 === t.fillHandleDirection), nIndex); if (null != oCanPromote) { History.Create_NewPoint(); History.StartTransaction(); AscCommonExcel.executeInR1C1Mode(false, function () { range.promote(/*bCtrl*/ctrlPress, /*bVertical*/(1 === t.fillHandleDirection), nIndex, oCanPromote); // Вызываем функцию пересчета для заголовков форматированной таблицы t.model.checkChangeTablesContent(arn); let api = t.getApi(); api.onWorksheetChange(oCanPromote.to); // Сбрасываем параметры автозаполнения t.activeFillHandle = null; t.fillHandleDirection = -1; History.SetSelection(range.bbox.clone()); History.SetSelectionRedo(oCanPromote.to.clone()); History.EndTransaction(); }); // clear traces if (t.traceDependentsManager) { t.traceDependentsManager.clearAll(); } // Обновляем выделенные ячейки t._updateRange(arn); t.model.workbook.handlers.trigger("cleanCutData", null, true); t.model.workbook.handlers.trigger("cleanCopyData"); !opt_doNotDraw && t.draw(); callback && callback(true); } else { t.handlers.trigger("onErrorEvent", c_oAscError.ID.CannotFillRange, c_oAscError.Level.NoCritical); t.model.selectionRange.assign2(range.bbox); // Сбрасываем параметры автозаполнения t.activeFillHandle = null; t.fillHandleDirection = -1; t.updateSelection(); callback && callback(false); } } else { // Сбрасываем параметры автозаполнения t.activeFillHandle = null; t.fillHandleDirection = -1; // Перерисовываем !opt_doNotDraw && t._drawSelection(); callback && callback(false); } }; if (this.model.isUserProtectedRangesIntersection(changedRange)) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ProtectedRangeByOtherUser, c_oAscError.Level.NoCritical); return; } //если все разлоченные ячейки - разрешаем. если перекрываем один защищенный диапазон(с паролем) - запрашиваем пароль, если более одного - ошибка //если хоть одна залоченная ячейка, которая не принадлежит защищенному диапазону - ошибка if (this.model.getSheetProtection()) { this.checkProtectRangeOnEdit([changedRange], function (success) { if (success) { t._isLockedCells(changedRange, /*subType*/null, applyFillHandleCallback); } else { // Сбрасываем параметры автозаполнения t.activeFillHandle = null; t.fillHandleDirection = -1; // Перерисовываем !opt_doNotDraw && t._drawSelection(); callback && callback(false); } }, true); return; } if (this.model.inPivotTable(changedRange)) { // Сбрасываем параметры автозаполнения this.activeFillHandle = null; this.fillHandleDirection = -1; // Перерисовываем !opt_doNotDraw && this._drawSelection(); callback && callback(false); this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.LockedCellPivot, c_oAscError.Level.NoCritical); return; } if (this.intersectionFormulaArray(changedRange)) { // Сбрасываем параметры автозаполнения this.activeFillHandle = null; this.fillHandleDirection = -1; // Перерисовываем !opt_doNotDraw && this._drawSelection(); callback && callback(false); this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.CannotChangeFormulaArray, c_oAscError.Level.NoCritical); return; } // Можно ли применять автозаполнение ? this._isLockedCells(changedRange, /*subType*/null, applyFillHandleCallback); } else { // Ничего не менялось, сбрасываем выделение this.cleanSelection(); // Сбрасываем параметры автозаполнения this.activeFillHandle = null; this.fillHandleDirection = -1; // Перерисовываем !opt_doNotDraw && this._drawSelection(); callback && callback(false); } }; WorksheetView.prototype.applyFillHandleDoubleClick = function () { //1. если есть внизу расширяемых значений данные - диапазон расширяем строго по данным столбцам вниз до тех пор //пока хотя бы одная ячейка не станет пустой в строке ниже //2. если внизу только пустые строки - дёргае expandRange и идём до ближайшей непустой var range; var activeRange = this.model.selectionRange && this.model.selectionRange.getLast(); if (activeRange) { if (activeRange.r2 === gc_nMaxRow0) { return; } if (activeRange.r2 + 1 >= this.model.cellsByColRowsCount - 1) { return; } //проверям следующую строку после активной //если есть хотя бы одна пустая ячейка, то автозаполнение не применяем var nextRowRange = new Asc.Range(activeRange.c1, activeRange.r2 + 1, activeRange.c2, activeRange.r2 + 1); if (this.model.autoFilters._isContainEmptyCell(nextRowRange)) { //если все пустые, то идём до ближайшей не пустой, в привном случае не применяем а/з if (this.model.autoFilters._isEmptyRange(nextRowRange)) { var expandRange = this.model.autoFilters.expandRange(activeRange); if (expandRange.r2 > activeRange.r2) { //диапазон, на который расширились var newExpandRange = new Asc.Range(activeRange.c1, activeRange.r2 + 1, activeRange.c2, expandRange.r2); var firstNotEmptyCell = this.model.autoFilters._getFirstNotEmptyCell(newExpandRange); if (firstNotEmptyCell) { if (firstNotEmptyCell.nRow > activeRange.r2) { //берём диапазон до ближайшей пустой range = new Asc.Range(activeRange.c1, activeRange.r1, activeRange.c2, firstNotEmptyCell.nRow - 1); } } else { //берём весь расширенный диапазон range = new Asc.Range(activeRange.c1, activeRange.r1, activeRange.c2, expandRange.r2); } } } } else { //если все непустые, то идём до ближайшей строки, где есть хотя бы одна пустая var firstEmptyCell = this.model.autoFilters._getFirstEmptyCellByRow(activeRange.r2, activeRange.c1, activeRange.c2); if (firstEmptyCell && firstEmptyCell.nRow > activeRange.r1) { range = new Asc.Range(activeRange.c1, activeRange.r1, activeRange.c2, firstEmptyCell.nRow - 1); } } if (range) { this.fillHandleDirection = 1; //this.fillHandleArea = ; this.activeFillHandle = range; this.applyFillHandle(); } } }; /* Функция для работы перемещения диапазона (selection). (x, y) - координаты точки мыши на области * ToDo нужно переделать, чтобы moveRange появлялся только после сдвига от текущей ячейки */ WorksheetView.prototype.changeSelectionMoveRangeHandle = function (x, y, colRowMoveProps) { // Возвращаемый результат var ret = null; //если выделена ячейка заголовка ф/т, меняем выделение с ячейки на столбец ф/т //если выделена вся видимая часть форматированной таблицы, но не выделены последние скрытые строчки var selectionRange = (this.dragAndDropRange || this.model.selectionRange.getLast()).clone(); if (null === this.startCellMoveRange) { this.af_changeSelectionTablePart(selectionRange); } // Колонка по X и строка по Y var colByX = this._findColUnderCursor(x, /*canReturnNull*/false, false).col; var rowByY = this._findRowUnderCursor(y, /*canReturnNull*/false, false).row; var type = selectionRange.getType(); if (type === c_oAscSelectionType.RangeRow) { colByX = 0; } else if (type === c_oAscSelectionType.RangeCol) { rowByY = 0; } else if (type === c_oAscSelectionType.RangeMax) { colByX = 0; rowByY = 0; } // Если мы только первый раз попали сюда, то копируем выделенную область if (null === this.startCellMoveRange) { // Учитываем погрешность (мы должны быть внутри диапазона при старте) if (colByX < selectionRange.c1) { colByX = selectionRange.c1; } else if (colByX > selectionRange.c2) { colByX = selectionRange.c2; } if (rowByY < selectionRange.r1) { rowByY = selectionRange.r1; } else if (rowByY > selectionRange.r2) { rowByY = selectionRange.r2; } this.startCellMoveRange = new asc_Range(colByX, rowByY, colByX, rowByY); this.startCellMoveRange.isChanged = false; // Флаг, сдвигались ли мы от первоначального диапазона //added new options for move all colls/rows if (colRowMoveProps) { this.startCellMoveRange.colRowMoveProps = colRowMoveProps; } return ret; } // Разница, на сколько мы сдвинулись var colDelta = colByX - this.startCellMoveRange.c1; var rowDelta = rowByY - this.startCellMoveRange.r1; // Проверяем, нужно ли отрисовывать перемещение (сдвигались или нет) if (false === this.startCellMoveRange.isChanged && 0 === colDelta && 0 === rowDelta) { return ret; } // Выставляем флаг this.startCellMoveRange.isChanged = true; // Очищаем выделение, будем рисовать заново this.cleanSelection(); this.activeMoveRange = selectionRange; // Для первого раза нормализуем (т.е. первая точка - это левый верхний угол) this.activeMoveRange.normalize(); // Выставляем this.activeMoveRange.c1 += colDelta; if (0 > this.activeMoveRange.c1) { colDelta -= this.activeMoveRange.c1; this.activeMoveRange.c1 = 0; } this.activeMoveRange.c2 += colDelta; this.activeMoveRange.r1 += rowDelta; if (0 > this.activeMoveRange.r1) { rowDelta -= this.activeMoveRange.r1; this.activeMoveRange.r1 = 0; } this.activeMoveRange.r2 += rowDelta; // Перерисовываем this._drawSelection(); var d = new AscCommon.CellBase(0, 0); /*var d = { deltaX : this.activeMoveRange.c1 < this.visibleRange.c1 ? this.activeMoveRange.c1-this.visibleRange.c1 : this.activeMoveRange.c2>this.visibleRange.c2 ? this.activeMoveRange.c2-this.visibleRange.c2 : 0, deltaY : this.activeMoveRange.r1 < this.visibleRange.r1 ? this.activeMoveRange.r1-this.visibleRange.r1 : this.activeMoveRange.r2>this.visibleRange.r2 ? this.activeMoveRange.r2-this.visibleRange.r2 : 0 }; while ( this._isColDrawnPartially( this.activeMoveRange.c2, this.visibleRange.c1 + d.deltaX) ) {++d.deltaX;} while ( this._isRowDrawnPartially( this.activeMoveRange.r2, this.visibleRange.r1 + d.deltaY) ) {++d.deltaY;}*/ if (y <= this.cellsTop + 2) { d.row = -1; } else if (y >= this.drawingCtx.getHeight() - 2) { d.row = 1; } if (x <= this.cellsLeft + 2) { d.col = -1; } else if (x >= this.drawingCtx.getWidth() - 2) { d.col = 1; } this.model.workbook.handlers.trigger("asc_onHideComment"); type = this.activeMoveRange.getType(); if (type === c_oAscSelectionType.RangeRow) { d.col = 0; } else if (type === c_oAscSelectionType.RangeCol) { d.row = 0; } else if (type === c_oAscSelectionType.RangeMax) { d.col = 0; d.row = 0; } if (this.startCellMoveRange.colRowMoveProps && this.startCellMoveRange.colRowMoveProps.shiftKey && this.activeMoveRange) { if (this.activeMoveRange.getType() === Asc.c_oAscSelectionType.RangeCol) { this.startCellMoveRange.colRowMoveProps.colByX = colByX; } else if (this.activeMoveRange.getType() === Asc.c_oAscSelectionType.RangeRow) { this.startCellMoveRange.colRowMoveProps.rowByY = rowByY; } } return d; }; WorksheetView.prototype.changeChartSelectionMoveResizeRangeHandle = function(x, y, targetInfo) { // Колонка по X и строка по Y var colByX = this._findColUnderCursor(x, /*canReturnNull*/false, false).col; var rowByY = this._findRowUnderCursor(y, /*canReturnNull*/false, false).row; var i; var indexFormulaRange = targetInfo.indexFormulaRange; var otherRanges = this.oOtherRanges.ranges; var oActiveRange = otherRanges[indexFormulaRange], colDelta, rowDelta; var ar = oActiveRange.clone(), arTmp; var oTopActiveRange = null, oLeftActiveRange = null, oValActiveRange = null; var r1 = null, r2 = null, c1 = null, c2 = null, delta; if(oActiveRange.separated) { switch (targetInfo.cursor) { case kCurNEResize: case kCurSEResize:{ if (colByX < this.startCellMoveResizeRange2.c1) { c2 = this.startCellMoveResizeRange2.c1; c1 = colByX; } else if (colByX > this.startCellMoveResizeRange2.c1) { c1 = this.startCellMoveResizeRange2.c1; c2 = colByX; } else { c1 = this.startCellMoveResizeRange2.c1; c2 = this.startCellMoveResizeRange2.c1 } if (rowByY < this.startCellMoveResizeRange2.r1) { r2 = this.startCellMoveResizeRange2.r2; r1 = rowByY; } else if (rowByY > this.startCellMoveResizeRange2.r1) { r1 = this.startCellMoveResizeRange2.r1; r2 = rowByY; } else { r1 = this.startCellMoveResizeRange2.r1; r2 = this.startCellMoveResizeRange2.r1; } if(oActiveRange.chartRangeIndex !== 2) { if(Math.abs(ar.c2 - ar.c1) > Math.abs(ar.r2 - ar.r1)) { r1 = Math.min(ar.r1, ar.r2); r2 = r1; } else if(Math.abs(ar.c2 - ar.c1) < Math.abs(ar.r2 - ar.r1)) { c1 = Math.min(ar.c1, ar.c2); c2 = c1; } else { if(Math.abs(this.startCellMoveResizeRange2.c1 - colByX) > Math.abs(this.startCellMoveResizeRange2.r1 - rowByY)){ r1 = Math.min(ar.r1, ar.r2); r2 = r1; } else { c1 = Math.min(ar.c1, ar.c2); c2 = c1; } } } break; } case kCurMove: { colDelta = colByX - this.startCellMoveResizeRange2.c1; c1 = this.startCellMoveResizeRange.c1 + colDelta; c2 = this.startCellMoveResizeRange.c2 + colDelta; delta = Math.min(c1, c2); if(delta < 0) { c1 -= delta; c2 -= delta; } rowDelta = rowByY - this.startCellMoveResizeRange2.r1; r1 = this.startCellMoveResizeRange.r1 + rowDelta; r2 = this.startCellMoveResizeRange.r2 + rowDelta; delta = Math.min(r1, r2); if(delta < 0) { r1 -= delta; r2 -= delta; } break; } } arTmp = oActiveRange.clone(); if(r1 !== null && r2 !== null) { arTmp.r1 = r1; arTmp.r2 = r2; } if(c1 !== null && c2 !== null) { arTmp.c1 = c1; arTmp.c2 = c2; } oActiveRange.assign2(arTmp); } else { for(i = 0; i < otherRanges.length; ++i) { if(otherRanges[i].chartRangeIndex === 0) { oValActiveRange = otherRanges[i]; } else if(otherRanges[i].chartRangeIndex === 1) { if(oValActiveRange) { if(oValActiveRange.vert) { oLeftActiveRange = otherRanges[i]; } else { oTopActiveRange = otherRanges[i]; } } } else if(otherRanges[i].chartRangeIndex === 2) { if(oValActiveRange) { if(oValActiveRange.vert) { oTopActiveRange = otherRanges[i]; } else { oLeftActiveRange = otherRanges[i]; } } } } if(!oValActiveRange) { return; } switch (targetInfo.cursor) { case kCurNEResize: case kCurSEResize:{ if(oValActiveRange === oActiveRange || oTopActiveRange === oActiveRange) { if (colByX < this.startCellMoveResizeRange2.c1) { c2 = this.startCellMoveResizeRange2.c1; c1 = colByX; } else if (colByX > this.startCellMoveResizeRange2.c1) { c1 = this.startCellMoveResizeRange2.c1; c2 = colByX; } else { c1 = this.startCellMoveResizeRange2.c1; c2 = this.startCellMoveResizeRange2.c1 } } if(oValActiveRange === oActiveRange || oLeftActiveRange === oActiveRange) { if (rowByY < this.startCellMoveResizeRange2.r1) { r2 = this.startCellMoveResizeRange2.r2; r1 = rowByY; } else if (rowByY > this.startCellMoveResizeRange2.r1) { r1 = this.startCellMoveResizeRange2.r1; r2 = rowByY; } else { r1 = this.startCellMoveResizeRange2.r1; r2 = this.startCellMoveResizeRange2.r1; } } if(oLeftActiveRange && oLeftActiveRange !== oActiveRange && (c1 <= oLeftActiveRange.c2)) { c1 = oLeftActiveRange.c2 + 1; } if(oTopActiveRange && oTopActiveRange !== oActiveRange && (r1 <= oTopActiveRange.r2)) { r1 = oTopActiveRange.r2 + 1; } break; } case kCurMove: { if(oActiveRange === oValActiveRange || oActiveRange === oTopActiveRange) { colDelta = colByX - this.startCellMoveResizeRange2.c1; if(colDelta < 0 && oLeftActiveRange && (this.startCellMoveResizeRange.c1 + colDelta <= oLeftActiveRange.c2)) { colDelta += (oLeftActiveRange.c2 - (this.startCellMoveResizeRange.c1 + colDelta) + 1); } c1 = this.startCellMoveResizeRange.c1 + colDelta; c2 = this.startCellMoveResizeRange.c2 + colDelta; delta = Math.min(c1, c2); if(delta < 0) { c1 -= delta; c2 -= delta; } } if(oActiveRange === oValActiveRange || oActiveRange === oLeftActiveRange) { rowDelta = rowByY - this.startCellMoveResizeRange2.r1; if(rowDelta < 0 && oTopActiveRange && (this.startCellMoveResizeRange.r1 + rowDelta <= oTopActiveRange.r2)) { rowDelta += (oTopActiveRange.r2 - (this.startCellMoveResizeRange.r1 + rowDelta) + 1); } r1 = this.startCellMoveResizeRange.r1 + rowDelta; r2 = this.startCellMoveResizeRange.r2 + rowDelta; delta = Math.min(r1, r2); if(delta < 0) { r1 -= delta; r2 -= delta; } } break; } } if(oValActiveRange) { arTmp = oValActiveRange.clone(); if(r1 !== null && r2 !== null) { arTmp.r1 = r1; arTmp.r2 = r2; } if(c1 !== null && c2 !== null) { arTmp.c1 = c1; arTmp.c2 = c2; } oValActiveRange.assign2(arTmp); } if(oLeftActiveRange) { arTmp = oLeftActiveRange.clone(); if(r1 !== null && r2 !== null) { arTmp.r1 = r1; arTmp.r2 = r2; } oLeftActiveRange.assign2(arTmp); } if(oTopActiveRange) { arTmp = oTopActiveRange.clone(); if(c1 !== null && c2 !== null) { arTmp.c1 = c1; arTmp.c2 = c2; } oTopActiveRange.assign2(arTmp); } } this._drawSelection(); }; WorksheetView.prototype._startMoveResizeRangeHandle = function (x, y, targetInfo, range) { var ar = range.clone(); // Колонка по X и строка по Y var colByX = this._findColUnderCursor(x, /*canReturnNull*/false, false).col; var rowByY = this._findRowUnderCursor(y, /*canReturnNull*/false, false).row; if ((targetInfo.cursor === kCurNEResize || targetInfo.cursor === kCurSEResize)) { this.startCellMoveResizeRange = ar.clone(true); this.startCellMoveResizeRange2 = new asc_Range(targetInfo.col, targetInfo.row, targetInfo.col, targetInfo.row, true); } else { this.startCellMoveResizeRange = ar.clone(true); if (colByX < ar.c1) { colByX = ar.c1; } else if (colByX > ar.c2) { colByX = ar.c2; } if (rowByY < ar.r1) { rowByY = ar.r1; } else if (rowByY > ar.r2) { rowByY = ar.r2; } this.startCellMoveResizeRange2 = new asc_Range(colByX, rowByY, colByX, rowByY); } return null; }; WorksheetView.prototype._endMoveResizeRangeHandle = function (x, y, targetInfo, range) { var d = new AscCommon.CellBase(0, 0); var colByX = this._findColUnderCursor(x, /*canReturnNull*/false, false).col; var rowByY = this._findRowUnderCursor(y, /*canReturnNull*/false, false).row; var type = this.startCellMoveResizeRange.getType(); var ar = range.clone(); this.overlayCtx.clear(); if (targetInfo.cursor === kCurNEResize || targetInfo.cursor === kCurSEResize) { if (colByX < this.startCellMoveResizeRange2.c1) { ar.c2 = this.startCellMoveResizeRange2.c1; ar.c1 = colByX; } else if (colByX > this.startCellMoveResizeRange2.c1) { ar.c1 = this.startCellMoveResizeRange2.c1; ar.c2 = colByX; } else { ar.c1 = this.startCellMoveResizeRange2.c1; ar.c2 = this.startCellMoveResizeRange2.c1 } if (rowByY < this.startCellMoveResizeRange2.r1) { ar.r2 = this.startCellMoveResizeRange2.r2; ar.r1 = rowByY; } else if (rowByY > this.startCellMoveResizeRange2.r1) { ar.r1 = this.startCellMoveResizeRange2.r1; ar.r2 = rowByY; } else { ar.r1 = this.startCellMoveResizeRange2.r1; ar.r2 = this.startCellMoveResizeRange2.r1; } } else { this.startCellMoveResizeRange.normalize(); type = this.startCellMoveResizeRange.getType(); var colDelta = type !== c_oAscSelectionType.RangeRow && type !== c_oAscSelectionType.RangeMax ? colByX - this.startCellMoveResizeRange2.c1 : 0; var rowDelta = type !== c_oAscSelectionType.RangeCol && type !== c_oAscSelectionType.RangeMax ? rowByY - this.startCellMoveResizeRange2.r1 : 0; ar.c1 = this.startCellMoveResizeRange.c1 + colDelta; if (0 > ar.c1) { colDelta -= ar.c1; ar.c1 = 0; } ar.c2 = this.startCellMoveResizeRange.c2 + colDelta; ar.r1 = this.startCellMoveResizeRange.r1 + rowDelta; if (0 > ar.r1) { rowDelta -= ar.r1; ar.r1 = 0; } ar.r2 = this.startCellMoveResizeRange.r2 + rowDelta; } if (y <= this.cellsTop + 2) { d.row = -1; } else if (y >= this.drawingCtx.getHeight() - 2) { d.row = 1; } if (x <= this.cellsLeft + 2) { d.col = -1; } else if (x >= this.drawingCtx.getWidth() - 2) { d.col = 1; } type = this.startCellMoveResizeRange.getType(); if (type === c_oAscSelectionType.RangeRow) { d.col = 0; } else if (type === c_oAscSelectionType.RangeCol) { d.row = 0; } else if (type === c_oAscSelectionType.RangeMax) { d.col = 0; d.row = 0; } ar = range.assign2(ar.clone(true)); this._drawSelection(); return {range: ar, delta: d}; }; WorksheetView.prototype.changeSelectionMoveResizeVisibleAreaHandle = function (x, y, targetInfo) { if (!targetInfo) { return; } var oleSize = this.getOleSize().getLast(); if (null === this.startCellMoveResizeRange) { return this._startMoveResizeRangeHandle(x, y, targetInfo, oleSize); } return this._endMoveResizeRangeHandle(x, y, targetInfo, oleSize).delta; }; WorksheetView.prototype.changePageBreakPreviewAreaHandle = function (x, y, targetInfo) { if (!targetInfo) { return; } var _range = targetInfo.range; this.pageBreakPreviewSelectionRange = _range; this.pageBreakPreviewSelectionRange.pageBreakSelectionType = targetInfo.pageBreakSelectionType; if (null === this.startCellMoveResizeRange) { this.startCellMoveResizeRange = _range.clone(true); if (targetInfo.pageBreakSelectionType === 2) { if (targetInfo.cursor === kCurEWResize) { this.startCellMoveResizeRange.colByX = targetInfo.col + 1; } else { this.startCellMoveResizeRange.rowByY = targetInfo.row + 1; } } return; } return this._endResizePageBreakPreviewRangeHandle(x, y, targetInfo, _range).delta; }; WorksheetView.prototype._endResizePageBreakPreviewRangeHandle = function (x, y, targetInfo, range) { var d = new AscCommon.CellBase(0, 0); var colByX = this._findColUnderCursor(x, /*canReturnNull*/false, false).col; var rowByY = this._findRowUnderCursor(y, /*canReturnNull*/false, false).row; var ar = range.clone(); this.overlayCtx.clear(); if (targetInfo.pageBreakSelectionType === 2) { if (targetInfo.cursor === kCurEWResize) { range.colByX = colByX; ar.colByX = colByX; } else { range.rowByY = rowByY; ar.rowByY = rowByY; } } else { if (targetInfo.cursor === kCurEWResize) { if (this.startCellMoveResizeRange.c1 === targetInfo.col) { //left border ar.c1 = Math.min(colByX, this.startCellMoveResizeRange.c2); } else if (this.startCellMoveResizeRange.c2 === targetInfo.col) { //right border ar.c2 = Math.max(colByX, this.startCellMoveResizeRange.c1); } } else if (targetInfo.cursor === kCurNSResize) { if (this.startCellMoveResizeRange.r1 === targetInfo.row) { //top border ar.r1 = Math.min(rowByY, this.startCellMoveResizeRange.r2); } else if (this.startCellMoveResizeRange.r2 === targetInfo.row) { //bottom border ar.r2 = Math.max(rowByY, this.startCellMoveResizeRange.r1); } } else if (targetInfo.cursor === kCurSEResize) { //left up / right down if (this.startCellMoveResizeRange.r1 === targetInfo.row) { //right down ar.c2 = Math.max(colByX, this.startCellMoveResizeRange.c1); ar.r2 = Math.max(rowByY, this.startCellMoveResizeRange.r1); } else if (this.startCellMoveResizeRange.r2 === targetInfo.row) { //left up ar.r1 = Math.min(rowByY, this.startCellMoveResizeRange.r2); ar.c1 = Math.min(colByX, this.startCellMoveResizeRange.c2); } } else if (targetInfo.cursor === kCurNEResize) { //right up / left down if (this.startCellMoveResizeRange.r1 === targetInfo.row) { //left down ar.r2 = Math.max(rowByY, this.startCellMoveResizeRange.r1); ar.c1 = Math.min(colByX, this.startCellMoveResizeRange.c2); } else if (this.startCellMoveResizeRange.r2 === targetInfo.row) { //right up ar.r1 = Math.min(rowByY, this.startCellMoveResizeRange.r2); ar.c2 = Math.max(colByX, this.startCellMoveResizeRange.c1); } } ar = range.assign2(ar.clone(true)); } if (y <= this.cellsTop + 2) { d.row = -1; } else if (y >= this.drawingCtx.getHeight() - 2) { d.row = 1; } if (x <= this.cellsLeft + 2) { d.col = -1; } else if (x >= this.drawingCtx.getWidth() - 2) { d.col = 1; } let type = this.startCellMoveResizeRange.getType(); if (type === c_oAscSelectionType.RangeRow) { d.col = 0; } else if (type === c_oAscSelectionType.RangeCol) { d.row = 0; } else if (type === c_oAscSelectionType.RangeMax) { d.col = 0; d.row = 0; } this._drawSelection(); return {range: ar, delta: d}; }; WorksheetView.prototype.changeSelectionMoveResizeRangeHandle = function (x, y, targetInfo, editor) { // Возвращаемый результат if (!targetInfo) { return null; } if (this.getFormulaEditMode()) { editor.cleanSelectRange(); } var index = targetInfo.indexFormulaRange; var initialRange = this.oOtherRanges.ranges[index]; if (null === this.startCellMoveResizeRange) { return this._startMoveResizeRangeHandle(x, y, targetInfo, initialRange); } // очищаем выделение this.overlayCtx.clear(); if (!this.getFormulaEditMode()) { return this.changeChartSelectionMoveResizeRangeHandle(x, y, targetInfo); } var res = this._endMoveResizeRangeHandle(x, y, targetInfo, initialRange); if (res.range) { editor.changeCellRange(res.range, true); return res.delta; } }; WorksheetView.prototype._cleanSelectionMoveRange = function () { // Перерисовываем и сбрасываем параметры this.cleanSelection(); this.activeMoveRange = null; this.startCellMoveRange = null; this._drawSelection(); }; /* Функция для применения перемещения диапазона */ WorksheetView.prototype.applyMoveRangeHandle = function (ctrlKey) { if (null === this.activeMoveRange) { // Сбрасываем параметры this.startCellMoveRange = null; return; } this.model.workbook.handlers.trigger("cleanCutData", null, true); this.model.workbook.handlers.trigger("cleanCopyData"); let arnFrom = this.model.selectionRange.getLast(); let arnTo = this.activeMoveRange.clone(true); if (arnFrom.isEqual(arnTo)) { this._cleanSelectionMoveRange(); return; } if (this.model.isUserProtectedRangesIntersection(arnFrom) || this.model.isUserProtectedRangesIntersection(arnTo)) { this._cleanSelectionMoveRange(); this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ProtectedRangeByOtherUser, c_oAscError.Level.NoCritical); return; } if (this.model.getSheetProtection() && (this.model.isLockedRange(arnFrom) || this.model.isLockedRange(arnTo))) { this._cleanSelectionMoveRange(); this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ChangeOnProtectedSheet, c_oAscError.Level.NoCritical); return; } let errorPivot = this.model.checkMovePivotTable(arnFrom, arnTo, ctrlKey); if (c_oAscError.ID.No !== errorPivot) { this._cleanSelectionMoveRange(); this.model.workbook.handlers.trigger("asc_onError", errorPivot, c_oAscError.Level.NoCritical); return; } let t = this; let doMove = function (success) { if (!success) { shiftMove && History.EndTransaction(); return; } if (shiftMove) { arnTo = t.model.selectionRange.getLast().clone(); if (lastSelection.getType() === c_oAscSelectionType.RangeCol && lastSelection.c1 > arnTo.c1) { let diff = arnFrom.c2 - arnFrom.c1 + 1; arnFrom = new asc_Range(lastSelection.c1 + diff, lastSelection.r1, lastSelection.c2 + diff, lastSelection.r2); } else if (lastSelection.getType() === c_oAscSelectionType.RangeRow && lastSelection.r1 > arnTo.r1) { let diff = arnFrom.r2 - arnFrom.r1 + 1; arnFrom = new asc_Range(lastSelection.c1, lastSelection.r1 + diff, lastSelection.c2, lastSelection.r2 + diff); } else { arnFrom = lastSelection; } } //***array-formula*** //теперь не передаю 3 параметром в функцию checkMoveFormulaArray ctrlKey, поскольку undo/redo для //клонирования части формулы работает некорректно //при undo созданную формулу обходимо не переносить, а удалять //TODO пересомтреть! if (!t.checkMoveFormulaArray(arnFrom, arnTo)) { t._cleanSelectionMoveRange(); t.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.CannotChangeFormulaArray, c_oAscError.Level.NoCritical); shiftMove && History.EndTransaction(); return; } let _moveCallback = function (_success) { if (!_success) { History.EndTransaction(); return; } if (!ctrlKey) { let insProp = null != colByX ? c_oAscDeleteOptions.DeleteCellsAndShiftLeft : c_oAscDeleteOptions.DeleteCellsAndShiftTop; t.model.selectionRange.getLast().assign2(arnFrom); t.changeWorksheet("delCell", insProp, function (_success) { if (!_success) { History.EndTransaction(); return; } let changedRange = arnTo.adjustRange(arnFrom, !colByX); t.setSelection(changedRange ? changedRange : arnTo); History.EndTransaction(); }); } else { History.EndTransaction(); } }; let resmove = t.model._prepareMoveRange(arnFrom, arnTo); if (resmove === -2) { t.handlers.trigger("onErrorEvent", c_oAscError.ID.CannotMoveRange, c_oAscError.Level.NoCritical); t._cleanSelectionMoveRange(); } else if (resmove === -1) { t.model.workbook.handlers.trigger("asc_onConfirmAction", Asc.c_oAscConfirm.ConfirmReplaceRange, function (can) { if (can) { t.moveRangeHandle(arnFrom, arnTo, ctrlKey, null, shiftMove && _moveCallback); } else { t._cleanSelectionMoveRange(); } }); } else { t.moveRangeHandle(arnFrom, arnTo, ctrlKey, null, shiftMove && _moveCallback); } }; //shift cols/rows and move let colByX, rowByY; let lastSelection; let shiftMove = this.startCellMoveRange.colRowMoveProps && this.startCellMoveRange.colRowMoveProps.shiftKey; if (shiftMove) { lastSelection = t.model.selectionRange.getLast().clone(); colByX = this.startCellMoveRange.colRowMoveProps.colByX; rowByY = this.startCellMoveRange.colRowMoveProps.rowByY; if (colByX != null) { let colStart = colByX + 1; let colEnd = colStart + lastSelection.c2 - lastSelection.c1; t.model.selectionRange.getLast().assign(colStart, lastSelection.r1, colEnd, lastSelection.r2); } else if (rowByY != null) { let rowStart = rowByY + 1; let rowEnd = rowStart + lastSelection.r2 - lastSelection.r1; t.model.selectionRange.getLast().assign(lastSelection.c1, rowStart, lastSelection.c2, rowEnd); } if (t.model.selectionRange.getLast().isEqual(lastSelection) !== true &&(colByX != null || rowByY != null)) { History.Create_NewPoint(); History.StartTransaction(); let insProp = null != colByX ? c_oAscInsertOptions.InsertCellsAndShiftRight : c_oAscInsertOptions.InsertCellsAndShiftDown; this.changeWorksheet("insCell", insProp, doMove, true); } else { this._cleanSelectionMoveRange(); } } else { doMove(true); } }; WorksheetView.prototype.applyCutRange = function (arnFrom, arnTo, opt_wsTo) { var moveToOtherSheet = opt_wsTo && opt_wsTo.model && this.model !== opt_wsTo.model; if (!moveToOtherSheet && arnFrom.isEqual(arnTo)) { return; } var errorPivot = this.model.checkMovePivotTable(arnFrom, arnTo, false, opt_wsTo && opt_wsTo.model); if (c_oAscError.ID.No !== errorPivot) { this.model.workbook.handlers.trigger("asc_onError", errorPivot, c_oAscError.Level.NoCritical); return; } //***array-formula*** //теперь не передаю 3 параметром в функцию checkMoveFormulaArray ctrlKey, поскольку undo/redo для //клонирования части формулы работает некорректно //при undo созданную формулу обходимо не переносить, а удалять //TODO пересомтреть! if (!this.checkMoveFormulaArray(arnFrom, arnTo, null, opt_wsTo)) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.CannotChangeFormulaArray, c_oAscError.Level.NoCritical); return; } var resmove = this.model._prepareMoveRange(arnFrom, arnTo, opt_wsTo && opt_wsTo.model); if (resmove === -2) { this.handlers.trigger("onErrorEvent", c_oAscError.ID.CannotMoveRange, c_oAscError.Level.NoCritical); } else if (resmove === -1) { var t = this; this.model.workbook.handlers.trigger("asc_onConfirmAction", Asc.c_oAscConfirm.ConfirmReplaceRange, function (can) { if (can) { t.moveRangeHandle(arnFrom, arnTo, null, opt_wsTo); } }); } else { this.moveRangeHandle(arnFrom, arnTo, null, opt_wsTo); } }; WorksheetView.prototype.applyMoveResizeRangeHandle = function () { if (!this.getFormulaEditMode() && !this.startCellMoveResizeRange.isEqual(this.moveRangeDrawingObjectTo)) { this.objectRender.applyMoveResizeRange(this.oOtherRanges); } if (this.workbook.Api.isEditVisibleAreaOleEditor) { const oOleSize = this.getOleSize(); oOleSize.addPointToLocalHistory(); } this.startCellMoveResizeRange = null; this.startCellMoveResizeRange2 = null; this.moveRangeDrawingObjectTo = null; }; WorksheetView.prototype.applyResizePageBreakPreviewRangeHandle = function () { let fromRange = this.startCellMoveResizeRange; let toRange = this.pageBreakPreviewSelectionRange; if (!this.getFormulaEditMode()) { if (this.pageBreakPreviewSelectionRange.pageBreakSelectionType === 2) { //change page breaks if (toRange.colByX) { if (toRange.colByX !== fromRange.colByX) { this.changeRowColBreaks(fromRange.colByX, toRange.colByX, fromRange, true, true) } } else { if (toRange.rowByY !== fromRange.rowByY) { this.changeRowColBreaks(fromRange.rowByY, toRange.rowByY, fromRange, null, true) } } } else if (!fromRange.isEqual(toRange)) { //change all area var printArea = this.model.workbook.getDefinesNames("Print_Area", this.model.getId()); if(printArea && printArea.sheetId === this.model.getId()) { this.changePrintArea(Asc.c_oAscChangePrintAreaType.change, [toRange], [fromRange]) } else { this.changePrintArea(Asc.c_oAscChangePrintAreaType.set, [toRange]); } } } this.pageBreakPreviewSelectionRange = null; this.updateSelection(); this.startCellMoveResizeRange = null; }; WorksheetView.prototype.moveRangeHandle = function (arnFrom, arnTo, copyRange, opt_wsTo, callback) { //opt_wsTo - for test reasons only var t = this; var wsTo = opt_wsTo ? opt_wsTo : this; var onApplyMoveRangeHandleCallback = function (isSuccess) { if (false === isSuccess) { wsTo.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.LockedAllError, c_oAscError.Level.NoCritical); wsTo._cleanSelectionMoveRange(); callback && callback(false); return; } var onApplyMoveAutoFiltersCallback = function (isSuccess) { if (false === isSuccess) { wsTo.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.LockedAllError, c_oAscError.Level.NoCritical); wsTo._cleanSelectionMoveRange(); callback && callback(false); return; } var hasMerged = t.model.getRange3(arnFrom.r1, arnFrom.c1, arnFrom.r2, arnFrom.c2).hasMerged(); // Очищаем выделение wsTo.cleanSelection(); // clear traces if (t.traceDependentsManager) { t.traceDependentsManager.clearAll(); } //ToDo t.cleanDepCells(); History.Create_NewPoint(); if (opt_wsTo === undefined) { History.SetSelection(arnFrom.clone()); } History.SetSelectionRedo(arnTo.clone()); History.StartTransaction(); t.model.autoFilters._preMoveAutoFilters(arnFrom, arnTo, copyRange, opt_wsTo); t.model._moveRange(arnFrom, arnTo, copyRange, opt_wsTo && opt_wsTo.model); t.cellCommentator.moveRangeComments(arnFrom, arnTo, copyRange, opt_wsTo); t.moveCellWatches(arnFrom, arnTo, copyRange, opt_wsTo); if (!opt_wsTo && !copyRange && arnFrom) { } var oRangeFrom = new AscCommonExcel.Range(t.model, arnFrom.r1, arnFrom.c1, arnFrom.r2, arnFrom.c2); var oRangeTo = new AscCommonExcel.Range(t.model, arnTo.r1, arnTo.c1, arnTo.r2, arnTo.c2); Asc.editor.wbModel.handleChartsOnMoveRange(oRangeFrom, oRangeTo); // Вызываем функцию пересчета для заголовков форматированной таблицы t.model.checkChangeTablesContent(arnFrom); wsTo.model.checkChangeTablesContent(arnTo); t.model.autoFilters.reDrawFilter(arnFrom); t.model.autoFilters.afterMoveAutoFilters(arnFrom, arnTo, opt_wsTo); if (opt_wsTo) { History.SetSheetUndo(wsTo.model.getId()); } History.EndTransaction(); wsTo._updateRange(arnTo); t._updateRange(arnFrom); wsTo.model.selectionRange.assign2(arnTo); // Сбрасываем параметры wsTo.activeMoveRange = null; wsTo.startCellMoveRange = null; // Тут будет отрисовка select-а wsTo.draw(); // Вызовем на всякий случай, т.к. мы можем уже обновиться из-за формул ToDo возможно стоит убрать это в дальнейшем (но нужна переработка формул) - http://bugzilla.onlyoffice.com/show_bug.cgi?id=24505 wsTo._updateSelectionNameAndInfo(); if (hasMerged && false !== t.model.autoFilters._intersectionRangeWithTableParts(arnTo)) { //не делаем действий в asc_onConfirmAction, потому что во время диалога может выполниться autosave и новые измения добавятся в точку, которую уже отправили //тем более результат диалога ни на что не влияет wsTo.model.workbook.handlers.trigger("asc_onConfirmAction", Asc.c_oAscConfirm.ConfirmPutMergeRange, function () { }); } t.workbook.Api.onWorksheetChange(arnFrom); t.workbook.Api.onWorksheetChange(arnTo); callback && callback(true); }; if (t.model.autoFilters._searchFiltersInRange(arnFrom, true)) { t._isLockedAll(onApplyMoveAutoFiltersCallback); if (copyRange) { //TODO перепроверить лок t._isLockedDefNames(null, null); } } else { onApplyMoveAutoFiltersCallback(); } }; if (this.model.isUserProtectedRangesIntersection([arnFrom, arnTo])) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ProtectedRangeByOtherUser, c_oAscError.Level.NoCritical); this._cleanSelectionMoveRange(); callback && callback(false); return; } if (this.af_isCheckMoveRange(arnFrom, arnTo, opt_wsTo)) { if (opt_wsTo) { this._isLockedCells([arnFrom], null, opt_wsTo._isLockedCells([arnTo], null, onApplyMoveRangeHandleCallback)); } else { this._isLockedCells([arnFrom, arnTo], null, onApplyMoveRangeHandleCallback); } } else { this._cleanSelectionMoveRange(); } }; WorksheetView.prototype.isEmptyCellsSheet = function () { return !(this.rows.length || this.cols.length); }; WorksheetView.prototype.isHaveOnlyOneChart = function (bReturnChart) { const arrCharts = this.getCharts(); const bHaveOnlyOneChart = this.isEmptyCellsSheet() && arrCharts.length === 1 && this.model.Drawings.length === 1; if (bReturnChart) { return bHaveOnlyOneChart ? arrCharts[0] : null; } return bHaveOnlyOneChart; }; WorksheetView.prototype.emptySelection = function ( options, bIsCut, isMineComments ) { // Удаляем выделенные графичекие объекты if ( this.objectRender.selectedGraphicObjectsExists() ) { var isIntoShape = this.objectRender.controller.getTargetDocContent(); var isMobileVersion = this.workbook && this.workbook.Api && this.workbook.Api.isMobileVersion; if((bIsCut || isMobileVersion) && isIntoShape) { if(isIntoShape.Selection && isIntoShape.Selection.Use) { var oSelectedObject = AscFormat.getTargetTextObject(this.objectRender.controller); if(oSelectedObject && oSelectedObject.getObjectType() === AscDFH.historyitem_type_Shape) { if(!oSelectedObject.canEditText()) { if(this.model.getSheetProtection(Asc.c_oAscSheetProtectType.objects)) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ChangeOnProtectedSheet, c_oAscError.Level.NoCritical); return; } return; } } this.objectRender.controller.remove(-1, undefined, undefined, undefined, undefined); } } else { if(!this.objectRender.controller.deleteSelectedObjects()) { if(this.model.getSheetProtection(Asc.c_oAscSheetProtectType.objects)) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ChangeOnProtectedSheet, c_oAscError.Level.NoCritical); return; } } } } else { this.setSelectionInfo( "empty", options, null, isMineComments ); } }; WorksheetView.prototype.isNeedSelectionCut = function () { var res = true; if (AscCommon.g_clipboardBase.bCut && !this.objectRender.selectedGraphicObjectsExists() && !AscCommon.g_clipboardBase.forceCutSelection) { res = false; } return res; }; WorksheetView.prototype.isMultiSelect = function () { if(!this.objectRender.selectedGraphicObjectsExists()) { return !this.model.selectionRange.isSingleRange(); } return null; }; WorksheetView.prototype.setSelectionInfo = function (prop, val, onlyActive, isMineComments) { // Проверка глобального лока if (this.collaborativeEditing.getGlobalLock() || !window["Asc"]["editor"].canEdit()) { if (prop === "paste" && AscCommonExcel.g_clipboardExcel.pasteProcessor.pasteCallBack) { AscCommonExcel.g_clipboardExcel.pasteProcessor.pasteCallBack(false); AscCommonExcel.g_clipboardExcel.pasteProcessor.pasteCallBack = null; } return; } const t = this; const ws = t.model; let checkRange = []; let activeCell = this.model.selectionRange.activeCell.clone(); let arn = this.model.selectionRange.getLast().clone(true); const revertSelection = function () { if (val.originalSelectBeforePaste && val.originalSelectBeforePaste.ranges) { t.model.selectionRange.ranges = val.originalSelectBeforePaste.ranges; } }; const onSelectionCallback = function (isSuccess) { if (false === isSuccess) { if (AscCommonExcel.g_clipboardExcel.pasteProcessor.pasteCallBack) { AscCommonExcel.g_clipboardExcel.pasteProcessor.pasteCallBack(false); } AscCommonExcel.g_clipboardExcel.pasteProcessor.pasteCallBack = null; return; } var hasUpdates = false; var callTrigger = false; var res; var mc, r, cell; var expansionTableRange; let changeDigNumFormat; function makeBorder(b) { var border = new AscCommonExcel.BorderProp(); if (b === false) { border.setStyle(c_oAscBorderStyles.None); } else if (b) { if (b.style !== null && b.style !== undefined) { border.setStyle(b.style); } if (b.color !== null && b.color !== undefined) { if (b.color instanceof Asc.asc_CColor) { border.c = AscCommonExcel.CorrectAscColor(b.color); } } } return border; } const checkIndent = function (_range) { if (_range) { var _align = _range.getAlign(); if (_align && _align.getIndent && 0 != _align.getIndent()) { return true; } } return false; }; const doByAllRange = function (_range, callback) { let isAllProperty = false; let _allColProps = t.model.getAllCol(); if (!_allColProps || !_allColProps.xfs) { let _allRowProps = t.model.getAllRow(); if (!_allRowProps || !_allRowProps.xfs) { _range._foreachColNoEmpty(function (_col) { if (_col && _col.xfs) { isAllProperty = true; return true; } }); if (!isAllProperty) { _range._foreachRowNoEmpty(function (_row) { if (_row && _row.xfs) { isAllProperty = true; return true; } }); } } } if (isAllProperty) { callback(_range, true); } else { callback(_range); } }; History.Create_NewPoint(); History.StartTransaction(); let oStartActionInfo = t.getStartActionForSelectionInfo(prop, val); if (oStartActionInfo) { t.workbook.StartAction(oStartActionInfo.nDescription, oStartActionInfo.additional); } checkRange.forEach(function (item, i) { var c, _align, _verticalText; var bIsUpdate = true; var range = t.model.getRange3(item.r1, item.c1, item.r2, item.c2); var isLargeRange = t._isLargeRange(range.bbox); var canChangeColWidth = c_oAscCanChangeColWidth.none; if (prop !== "paste" && t.model.autoFilters.bIsExcludeHiddenRows(range, activeCell)) { t.model.excludeHiddenRows(true); } switch (prop) { case "fn": range.setFontname(val); canChangeColWidth = c_oAscCanChangeColWidth.numbers; break; case "fs": range.setFontsize(val); canChangeColWidth = c_oAscCanChangeColWidth.numbers; break; case "b": range.setBold(val); break; case "i": range.setItalic(val); break; case "u": range.setUnderline(val); break; case "s": range.setStrikeout(val); break; case "fa": range.setFontAlign(val); break; case "a": _align = range.getAlign(); _verticalText = _align && _align.angle === AscCommonExcel.g_nVerticalTextAngle; if (!(val === AscCommon.align_Right || val === AscCommon.align_Left) && !_verticalText && checkIndent(range)) { range.setIndent(0); } range.setAlignHorizontal(val); break; case "readingOrder": range.setReadingOrder(val); break; case "va": range.setAlignVertical(val); break; case "c": range.setFontcolor(val); break; case "f": range.setFill(val || null); break; case "bc": range.setFillColor(val || null); break; // ToDo можно делать просто отрисовку case "wrap": range.setWrap(val); break; case "shrink": range.setShrinkToFit(val); break; case "value": if (val instanceof AscCommonExcel.CCellValue) { range.setValueData(new AscCommonExcel.UndoRedoData_CellValueData(null, val)); } else { range.setValue(val); } expansionTableRange = range.bbox; break; case "totalRowFunc": const _tableInfo = t.model.autoFilters.getTableByActiveCell(); if (_tableInfo) { const _table = _tableInfo.table; var _tF = t.model.autoFilters._changeTotalsRowData(_table, range.bbox, {totalFunction: val}); if (_tF) { range.setValue(_tF[0]); } } break; case "format": range.setNumFormat(val); canChangeColWidth = c_oAscCanChangeColWidth.numbers; break; case "angle": if (val !== 0 && val !== AscCommonExcel.g_nVerticalTextAngle && checkIndent(range)) { range.setIndent(0); } range.setAngle(val); break; case "indent": _align = range.getAlign(); if (_align) { _verticalText = _align.angle === AscCommonExcel.g_nVerticalTextAngle; if (!_verticalText && !(_align.hor === AscCommon.align_Right || _align.hor === AscCommon.align_Left)) { range.setAlignHorizontal(AscCommon.align_Left); } if (_align.angle !== 0 && !_verticalText) { range.setAngle(0); } } range.setIndent(val); break; case "applyProtection": range.setApplyProtection(val); break; case "locked": range.setLocked(val); break; case "hiddenFormulas": range.setHiddenFormulas(val); break; case "rh": range.removeHyperlink(null, true); break; case "border": if (isLargeRange && !callTrigger) { callTrigger = true; t.handlers.trigger("slowOperation", true); } // None if (val.length < 1) { range.setBorder(null); break; } res = new AscCommonExcel.Border(); res.initDefault(); // Diagonal res.d = makeBorder(val[c_oAscBorderOptions.DiagD] || val[c_oAscBorderOptions.DiagU]); res.dd = !!val[c_oAscBorderOptions.DiagD]; res.du = !!val[c_oAscBorderOptions.DiagU]; // Vertical res.l = makeBorder(val[c_oAscBorderOptions.Left]); res.iv = makeBorder(val[c_oAscBorderOptions.InnerV]); res.r = makeBorder(val[c_oAscBorderOptions.Right]); // Horizontal res.t = makeBorder(val[c_oAscBorderOptions.Top]); res.ih = makeBorder(val[c_oAscBorderOptions.InnerH]); res.b = makeBorder(val[c_oAscBorderOptions.Bottom]); // Change border range.setBorder(res); break; case "merge": if (isLargeRange && !callTrigger) { callTrigger = true; t.handlers.trigger("slowOperation", true); } _align = range.getAlign(); _verticalText = _align && _align.angle === AscCommonExcel.g_nVerticalTextAngle; if (val === c_oAscMergeOptions.MergeCenter && checkIndent(range) && !_verticalText) { range.setIndent(0); } switch (val) { case c_oAscMergeOptions.MergeCenter: case c_oAscMergeOptions.Merge: let mergeRes = range.merge(val); /* call an error if it returns from merge */ if (mergeRes && mergeRes.errorType) { t.handlers.trigger("onErrorEvent", mergeRes.errorType, c_oAscError.Level.NoCritical); break; } t.cellCommentator.mergeComments(range.getBBox0()); break; case c_oAscMergeOptions.None: range.unmerge(); break; case c_oAscMergeOptions.MergeAcross: for (res = range.bbox.r1; res <= range.bbox.r2; ++res) { let mergeRes = t.model.getRange3(res, range.bbox.c1, res, range.bbox.c2).merge(val); /* call an error if it returns from merge */ if (mergeRes && mergeRes.errorType) { t.handlers.trigger("onErrorEvent", mergeRes.errorType, c_oAscError.Level.NoCritical); break; } cell = new asc_Range(range.bbox.c1, res, range.bbox.c2, res); t.cellCommentator.mergeComments(cell); } break; } break; case "sort": if (isLargeRange && !callTrigger) { callTrigger = true; t.handlers.trigger("slowOperation", true); } var opt_by_rows = false; //var props = t.getSortProps(true); //t.cellCommentator.sortComments(range.sort(val.type, opt_by_rows ? activeCell.row : activeCell.col, val.color, true, opt_by_rows, props.levels)); t.cellCommentator.sortComments(t.model._doSort(range, val.type, opt_by_rows ? activeCell.row : activeCell.col, val.color, true, opt_by_rows)); if (t.model.getSheetProtection()) { if (!(t.model.protectedRangesContainsRange(range.bbox) || !t.model.isLockedRange(range.bbox))) { t.handlers.trigger("asc_onError", c_oAscError.ID.ChangeOnProtectedSheet, c_oAscError.Level.NoCritical); return; } } t.setSortProps(t._generateSortProps(val.type, opt_by_rows ? activeCell.row : activeCell.col, val.color, true, opt_by_rows, range.bbox), true); break; case "customSort": if (isLargeRange && !callTrigger) { callTrigger = true; t.handlers.trigger("slowOperation", true); } if (t.model.getSheetProtection()) { if (!(t.model.protectedRangesContainsRange(range.bbox) || !t.model.isLockedRange(range.bbox))) { t.handlers.trigger("asc_onError", c_oAscError.ID.ChangeOnProtectedSheet, c_oAscError.Level.NoCritical); return; } } t.setSortProps(val); break; case "empty": if (isLargeRange && !callTrigger) { callTrigger = true; t.handlers.trigger("slowOperation", true); } /* отключаем отрисовку на случай необходимости пересчета ячеек, заносим ячейку, при необходимости в список перерисовываемых */ t.model.workbook.dependencyFormulas.lockRecal(); if (AscCommonExcel.bIsSupportDynamicArrays) { //***dynamic array-formula*** let changedDynamicArraysList; // checking affected arrays only for cases of deleting values ​​in cells if (val === c_oAscCleanOptions.All || val === c_oAscCleanOptions.Text || val === c_oAscCleanOptions.Formula) { changedDynamicArraysList = ws.getChangedArrayList(); if (changedDynamicArraysList) { // go through changed dynamic arrays, and delete all|partitional values? for (let array in changedDynamicArraysList) { let arrayData = changedDynamicArraysList[array]; let formula = arrayData.formula; let dynamicbbox = arrayData.range; let range = (formula && formula.aca && formula.ca) ? t.model.getRange3(dynamicbbox.r1, dynamicbbox.c1, dynamicbbox.r1, dynamicbbox.c1) : t.model.getRange3(dynamicbbox.r1, dynamicbbox.c1, dynamicbbox.r2, dynamicbbox.c2); // todo create clear function for cells (clearRange?) if (arrayData.doDelete) { // delete all cells range.cleanText(); let listenerId = arrayData.formula && arrayData.formula.getListenerId(); // remove from volatilate listeners ws.workbook.dependencyFormulas.endListeningVolatileArray(listenerId); } else if (arrayData.doRecalc) { // delete all cells except the first one range.cleanTextExceptFirst(); ws.workbook.dependencyFormulas.addToVolatileArrays(formula); } } ws.clearChangedArrayList(); } } } switch(val) { case c_oAscCleanOptions.All: doByAllRange (range, function (_range, ignoreNoEmpty) { _range.cleanAll(ignoreNoEmpty); }); t.model.deletePivotTables(range.bbox); t.model.removeSparklines(range.bbox); t.model.clearDataValidation([range.bbox], true); t.model.clearConditionalFormattingRulesByRanges([range.bbox]); // Удаляем комментарии //TODO isMineComments - используется только здесь // временный флаг, как только в сдк появится класс для групп, добавить этот флаг туда isMineComments = isMineComments ? (t.model.workbook.oApi.DocInfo && t.model.workbook.oApi.DocInfo.get_UserId()) : null; t.cellCommentator.deleteCommentsRange(range.bbox, isMineComments); break; case c_oAscCleanOptions.Text: case c_oAscCleanOptions.Formula: range.cleanText(); t.model.deletePivotTables(range.bbox); break; case c_oAscCleanOptions.Format: t.model.clearConditionalFormattingRulesByRanges([range.bbox]); doByAllRange (range, function (_range, ignoreNoEmpty) { _range.cleanFormat(ignoreNoEmpty); }); break; case c_oAscCleanOptions.Hyperlinks: range.cleanHyperlinks(); break; case c_oAscCleanOptions.Sparklines: t.model.removeSparklines(range.bbox); break; case c_oAscCleanOptions.SparklineGroups: t.model.removeSparklineGroups(range.bbox); break; } // recalculate all volatile arrays on page t.model.recalculateVolatileArrays(); t.model.excludeHiddenRows(false); // Если нужно удалить автофильтры - удаляем if (window['AscCommonExcel'].filteringMode) { if (val === c_oAscCleanOptions.All || val === c_oAscCleanOptions.Text) { t.model.autoFilters.isEmptyAutoFilters(range.bbox); } else if (val === c_oAscCleanOptions.Format) { t.model.autoFilters.cleanFormat(range.bbox); } } // Вызываем функцию пересчета для заголовков форматированной таблицы if (val === c_oAscCleanOptions.All || val === c_oAscCleanOptions.Text) { t.model.checkChangeTablesContent(range.bbox); } /* возвращаем отрисовку. и перерисовываем ячейки с предварительным пересчетом */ t.model.workbook.dependencyFormulas.unlockRecal(); break; case "changeDigNum": { //change format by active cell if (!changeDigNumFormat && 0 === i) { let colWidth = t.getColumnWidthInSymbols(activeCell.col) let cell = t.model.getRange3(activeCell.row, activeCell.col, activeCell.row, activeCell.col); changeDigNumFormat = cell.getShiftedNumFormat(val, colWidth); } if (changeDigNumFormat) { range.setNumFormat(changeDigNumFormat); canChangeColWidth = c_oAscCanChangeColWidth.numbers; } break; } case "changeFontSize": mc = t.model.getMergedByCell(activeCell.row, activeCell.col); c = mc ? mc.c1 : activeCell.col; r = mc ? mc.r1 : activeCell.row; cell = t._getVisibleCell(c, r); var oldFontSize = cell.getFont().getSize(); var newFontSize = asc_incDecFonSize(val, oldFontSize); if (null !== newFontSize) { range.setFontsize(newFontSize); canChangeColWidth = c_oAscCanChangeColWidth.numbers; } break; case "style": range.setCellStyle(val); canChangeColWidth = c_oAscCanChangeColWidth.numbers; break; case "paste": var specialPasteHelper = window['AscCommon'].g_specialPasteHelper; specialPasteHelper.specialPasteProps = specialPasteHelper.specialPasteProps ? specialPasteHelper.specialPasteProps : new Asc.SpecialPasteProps(); if(val.pasteAllSheet) { specialPasteHelper.specialPasteProps.asc_setProps(Asc.c_oSpecialPasteProps.formulaColumnWidth); } t.cellPasteHelper.loadDataBeforePaste(isLargeRange, val, bIsUpdate, canChangeColWidth, checkPasteRange); bIsUpdate = false; break; case "hyperlink": if (t.model.isUserProtectedRangesIntersection(new Asc.Range(activeCell.col, activeCell.row, activeCell.col, activeCell.row))) { t.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ProtectedRangeByOtherUser, c_oAscError.Level.NoCritical); return; } if (t.model.getSheetProtection(Asc.c_oAscSheetProtectType.insertHyperlinks)) { return; } if (val && val.hyperlinkModel) { if (Asc.c_oAscHyperlinkType.RangeLink === val.asc_getType()) { val.hyperlinkModel._updateLocation(); if (null === val.hyperlinkModel.LocationRangeBbox && null !== val.hyperlinkModel.LocationSheet) { bIsUpdate = false; break; } } if (null !== val.asc_getText()) { // Вставим текст в активную ячейку (а не так, как MSExcel в первую ячейку диапазона) mc = t.model.getMergedByCell(activeCell.row, activeCell.col); c = mc ? mc.c1 : activeCell.col; r = mc ? mc.r1 : activeCell.row; t.model.getRange3(r, c, r, c).setValue(val.asc_getText()); // Вызываем функцию пересчета для заголовков форматированной таблицы t.model.checkChangeTablesContent(range.bbox); } val.hyperlinkModel.Ref = range; range.setHyperlink(val.hyperlinkModel); break; } else { bIsUpdate = false; break; } case "changeTextCase": range.changeTextCase(val); break; default: bIsUpdate = false; break; } t.model.excludeHiddenRows(false); if (bIsUpdate) { t.canChangeColWidth = canChangeColWidth; t._updateRange(item); t.canChangeColWidth = c_oAscCanChangeColWidth.none; hasUpdates = true; } }); if (AscCommonExcel.g_clipboardExcel.pasteProcessor.pasteCallBack) { AscCommonExcel.g_clipboardExcel.pasteProcessor.pasteCallBack(true); AscCommonExcel.g_clipboardExcel.pasteProcessor.pasteCallBack = null; } t.model.workbook.handlers.trigger("cleanCutData", true, true); if (prop !== "paste") { t.model.workbook.handlers.trigger("cleanCopyData", true); } //в случае, если вставляем из глобального буфера, транзакцию закрываем внутри функции loadDataBeforePaste на callbacks от загрузки шрифтов и картинок if (prop !== "paste") { History.EndTransaction(); if(expansionTableRange) { t.applyTableAutoExpansion(expansionTableRange); } } t.workbook.FinalizeAction(); if (hasUpdates) { t.draw(); } if (callTrigger) { t.handlers.trigger("slowOperation", false); } if(prop === "paste") { if(val.needDraw) { t.draw(); } else { val.needDraw = true; } } }; var checkPasteRange; if ("paste" === prop) { if (val.onlyImages) { onSelectionCallback(true); return; } else if (!val.fromBinary && this.isMultiSelect()) { t.handlers.trigger("onErrorEvent", c_oAscError.ID.PasteMultiSelectError, c_oAscError.Level.NoCritical); if (AscCommonExcel.g_clipboardExcel.pasteProcessor.pasteCallBack) { AscCommonExcel.g_clipboardExcel.pasteProcessor.pasteCallBack(false); AscCommonExcel.g_clipboardExcel.pasteProcessor.pasteCallBack = null; } return false; } else { if (val.fromBinary) { //при вставке извне не работает эта обработка в мс //не клонирую, поскольку нигде меняться не будет val.originalSelectBeforePaste = this.model.selectionRange ? this.model.selectionRange.clone() : null; if (!this.changeSelectOnMultiSelect()) { val.originalSelectBeforePaste = undefined; } } var newRange = this.cellPasteHelper.checkPastedRange(val); checkPasteRange = newRange && newRange.length ? newRange : [newRange]; checkRange = [checkPasteRange[0]]; if (!newRange) { revertSelection(); return false; } for (let j = 0; j < checkPasteRange.length; j++) { let _checkRange = checkPasteRange[j]; if (this.intersectionFormulaArray(_checkRange)) { t.handlers.trigger("onErrorEvent", c_oAscError.ID.CannotChangeFormulaArray, c_oAscError.Level.NoCritical); revertSelection(); return false; } if (val.data && val.data.pivotTables && val.data.pivotTables.length > 0) { var intersectionTableParts = this.model.autoFilters.getTablesIntersectionRange(_checkRange); for (var i = 0; i < intersectionTableParts.length; i++) { if (intersectionTableParts[i] && intersectionTableParts[i].Ref && !_checkRange.containsRange(intersectionTableParts[i].Ref)) { t.handlers.trigger("onErrorEvent", c_oAscError.ID.PivotOverlap, c_oAscError.Level.NoCritical); revertSelection(); return false; } } } if (this.model._isPivotsIntersectRangeButNotInIt(_checkRange)) { t.handlers.trigger("onErrorEvent", c_oAscError.ID.PasteInPivot, c_oAscError.Level.NoCritical); revertSelection(); return false; } } } } else if (onlyActive) { checkRange.push(new asc_Range(activeCell.col, activeCell.row, activeCell.col, activeCell.row)); } else { this.model.selectionRange.ranges.forEach(function (item) { checkRange.push(item.clone()); }); } if (this.model.isUserProtectedRangesIntersection(checkRange)) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ProtectedRangeByOtherUser, c_oAscError.Level.NoCritical); return false; } if (prop !== "sort" && prop !== "customSort" && this.model.getSheetProtection(Asc.c_oAscSheetProtectType.formatCells)) { if (!this.model.protectedRangesContainsRanges(checkRange) && this.model.isIntersectLockedRanges(checkRange)) { this.handlers.trigger("onErrorEvent", c_oAscError.ID.ChangeOnProtectedSheet, c_oAscError.Level.NoCritical); return false; } } if (("merge" === prop || "sort" === prop || "hyperlink" === prop || "rh" === prop || "customSort" === prop) && this.model.inPivotTable(checkRange)) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.LockedCellPivot, c_oAscError.Level.NoCritical); return; } if ("empty" === prop && !this.model.checkDeletePivotTables(checkRange)) { // ToDo other error this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.LockedCellPivot, c_oAscError.Level.NoCritical); return; } if ("empty" === prop && this.intersectionFormulaArray(arn)) { t.handlers.trigger("onErrorEvent", c_oAscError.ID.CannotChangeFormulaArray, c_oAscError.Level.NoCritical); return; } if ("sort" === prop) { var aMerged = this.model.mergeManager.get(checkRange); if (aMerged.outer.length > 0 || (aMerged.inner.length > 0 && null == window['AscCommonExcel']._isSameSizeMerged(checkRange, aMerged.inner, true))) { t.handlers.trigger("onErrorEvent", c_oAscError.ID.CannotFillRange, c_oAscError.Level.NoCritical); return; } } if ("paste" === prop) { var _pasteCallback = function (_success) { if (false === _success) { return; } var pasteContent = val.data; var fonts = pasteContent.props && pasteContent.props.fontsNew ? pasteContent.props.fontsNew : val.fontsNew; //изначально планировалось заранее выполнить все асинхронные операции перед вызовом onSelectionCallback //но в случае с мультиселектом вставленные ф/т(при вставке ф/т нужно лочить лист и и/д) могут пересекаться друг с другом //и в этом случае предварительная проверка на предмет лока затруднена t._loadFonts(fonts, onSelectionCallback); }; //проверка защиты. пока ставлю здесь. возможно где-то выше придётся поставить(но там нужно знать диапазоны вставки). this.checkProtectRangeOnEdit(checkPasteRange, function (isSuccess) { if (!isSuccess) { return; } if (t.cellPasteHelper.isNeedLockedAllOnPaste(val)) { t._isLockedAll(function (success) { if (!success) { t.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.LockedAllError, c_oAscError.Level.NoCritical); return; } t._isLockedCells(checkRange, /*subType*/null, _pasteCallback); }); } else { t._isLockedCells(checkRange, /*subType*/null, _pasteCallback); } }); } else { var oApi = Asc.editor; var oWSView = this; if(oApi.isSliderDragged()) { this.objectRender.applySliderCallbacks( function() { oWSView._isLockedCells(checkRange, /*subType*/null, onSelectionCallback); }, function() { History.StartTransaction(); onSelectionCallback(true); History.EndTransaction(); } ); } else { this._isLockedCells(checkRange, /*subType*/null, onSelectionCallback); } } // убрал paste здесь так как не работает здесь для метода pasteHTML if (/*prop == "paste" ||*/ prop == "empty" || prop == "hyperlink" || prop == "sort") this.workbook.Api.onWorksheetChange(checkRange); }; WorksheetView.prototype.getStartActionForSelectionInfo = function(prop, val) { const startActionMap = { "fn": AscDFH.historydescription_Spreadsheet_SetCellFontName,// "fs": AscDFH.historydescription_Spreadsheet_SetCellFontSize,// "b": AscDFH.historydescription_Spreadsheet_SetCellBold,// "i": AscDFH.historydescription_Spreadsheet_SetCellItalic,// "u": AscDFH.historydescription_Spreadsheet_SetCellUnderline,// "s": AscDFH.historydescription_Spreadsheet_SetCellStrikeout,// "a": AscDFH.historydescription_Spreadsheet_SetCellAlign,// "readingOrder": AscDFH.historydescription_Spreadsheet_SetCellReadingOrder,// "va": AscDFH.historydescription_Spreadsheet_SetCellVertAlign,// "c": AscDFH.historydescription_Spreadsheet_SetCellTextColor,// "f": AscDFH.historydescription_Spreadsheet_SetCellFill, "bc": AscDFH.historydescription_Spreadsheet_SetCellBackgroundColor,// "wrap": AscDFH.historydescription_Spreadsheet_SetCellWrap,// //"shrink": AscDFH.historydescription_Spreadsheet_SetCellShrinkToFit, "value": AscDFH.historydescription_Spreadsheet_SetCellValue, //"totalRowFunc": AscDFH.historydescription_Spreadsheet_SetTotalRowFunction, "format": AscDFH.historydescription_Spreadsheet_SetCellFormat, "angle": AscDFH.historydescription_Spreadsheet_SetCellAngle, //"indent": AscDFH.historydescription_Spreadsheet_SetCellIndent, //"applyProtection": AscDFH.historydescription_Spreadsheet_SetCellApplyProtection, //"locked": AscDFH.historydescription_Spreadsheet_SetCellLocked, //"hiddenFormulas": AscDFH.historydescription_Spreadsheet_SetCellHiddenFormulas, //"rh": AscDFH.historydescription_Spreadsheet_SetCellHyperlinkRemove, "border": AscDFH.historydescription_Spreadsheet_SetCellBorder, "merge": AscDFH.historydescription_Spreadsheet_SetCellMerge, "sort": AscDFH.historydescription_Spreadsheet_SetCellSort, //"customSort": AscDFH.historydescription_Spreadsheet_SetCellCustomSort, "empty": AscDFH.historydescription_Spreadsheet_SetCellEmpty, "changeDigNum": AscDFH.historydescription_Spreadsheet_SetCellChangeDigNum, "changeFontSize": AscDFH.historydescription_Spreadsheet_SetCellChangeFontSize, //"style": AscDFH.historydescription_Spreadsheet_SetCellStyle, //"paste": AscDFH.historydescription_Spreadsheet_SetCellPaste, "hyperlink": AscDFH.historydescription_Spreadsheet_SetCellHyperlink, "changeTextCase": AscDFH.historydescription_Spreadsheet_SetCellChangeTextCase, "addComment": AscDFH.historydescription_Spreadsheet_AddComment, }; if (prop === "changeDigNum") { let activeCell = this.model.selectionRange.activeCell.clone(); let colWidth = this.getColumnWidthInSymbols(activeCell.col); let cell = this.model.getRange3(activeCell.row, activeCell.col, activeCell.row, activeCell.col); let changeDigNumFormat = cell.getShiftedNumFormat(val, colWidth); val = changeDigNumFormat; } if (prop === "fa") { switch (val) { case 0: return {nDescription: AscDFH.historydescription_Spreadsheet_SetCellSuperscript, additional: false}; case 1: return {nDescription: AscDFH.historydescription_Spreadsheet_SetCellSubscript, additional: true}; case 2: return {nDescription: AscDFH.historydescription_Spreadsheet_SetCellSuperscript, additional: true}; default: return {nDescription: AscDFH.historydescription_Spreadsheet_SetCellSuperscript, additional: false}; } } if (prop === "angle" && (val === 90 || val === - 90 || val === 0 || val === 255)) { return {nDescription: AscDFH.historydescription_Spreadsheet_SetCellAngle, additional: val}; } return startActionMap[prop] ? {nDescription: startActionMap[prop], additional: val} : null; }; WorksheetView.prototype.specialPaste = function (props) { this.cellPasteHelper.specialPaste(props); }; WorksheetView.prototype.showSpecialPasteOptions = function (options/*, range, positionShapeContent*/) { this.cellPasteHelper.showSpecialPasteOptions(options); }; WorksheetView.prototype.updateSpecialPasteButton = function () { this.cellPasteHelper.updateSpecialPasteButton(); }; WorksheetView.prototype.getSpecialPasteCoords = function (range, isVisible) { this.cellPasteHelper.getSpecialPasteCoords(range, isVisible); }; WorksheetView.prototype.changeSelectOnMultiSelect = function () { //разбиваем селект в зависимости от наличия скрытых строк внутри фильтра var t = this; var breakRange; if (this.model.AutoFilter && this.model.AutoFilter.isApplyAutoFilter()) { //отсеиваем все скрытые строки breakRange = new Asc.Range(0, 0, gc_nMaxCol0, gc_nMaxRow0); } else { //проверяем, попала ли активная ячейка в ф/т с примененным а/ф и в зависимости от этого составляем список скрытых внутри строк const tableInfo = this.model.autoFilters.getTableByActiveCell(); const table = tableInfo && tableInfo.table; if (table && table.isApplyAutoFilter()) { breakRange = table.Ref; } } var breakRangeByHiddenRows = function (_range, intersection) { //чтобы не усложнять логику прохожусь по всем строкам селекта var tempRanges = []; var tempRange; for (var j = _range.r1; j <= _range.r2; j++) { var isHidden = t.model.getRowHidden(j); if (j >= intersection.r1 && j <= intersection.r2 && isHidden) { if (tempRange) { tempRanges.push(tempRange); } tempRange = null; } else { if (!tempRange) { tempRange = new Asc.Range(_range.c1, j, _range.c2, j); } else { tempRange.r2++; } if (j === _range.r2) { tempRanges.push(tempRange); } } } return tempRanges; }; var isChange; var newRanges = []; if (breakRange) { var sr = this.model.selectionRange; for (var i = 0; i < sr.ranges.length; i++) { if (sr.ranges[i]) { var intersection = sr.ranges[i].intersection(breakRange); if (intersection) { //нужно пройтись по всем строкам пересечения и отсеять скрытые var breakRanges = breakRangeByHiddenRows(sr.ranges[i], intersection); if (breakRanges.length > 1) { isChange = true; } newRanges = newRanges.concat(breakRanges); } else { newRanges.push(sr.ranges[i].clone()); } } } } if (isChange && newRanges.length) { this.model.selectionRange.ranges = newRanges; return true; } return false; }; WorksheetView.prototype._isLockedHeaderFooter = function (callback) { var lockInfo = this.collaborativeEditing.getLockInfo(c_oAscLockTypeElem.Object, null, this.model.getId(), AscCommonExcel.c_oAscHeaderFooterEdit); this.collaborativeEditing.lock([lockInfo], callback); }; WorksheetView.prototype.getHeaderFooterLockInfo = function () { var lockInfo = this.collaborativeEditing.getLockInfo(c_oAscLockTypeElem.Object, null, this.model.getId(), AscCommonExcel.c_oAscHeaderFooterEdit); return lockInfo; }; WorksheetView.prototype._isLockedLayoutOptions = function (callback) { var lockInfo = this.collaborativeEditing.getLockInfo(c_oAscLockTypeElem.Object, null, this.model.getId(), AscCommonExcel.c_oAscLockLayoutOptions); this.collaborativeEditing.lock([lockInfo], callback); }; WorksheetView.prototype.getLayoutLockInfo = function () { var lockInfo = this.collaborativeEditing.getLockInfo(c_oAscLockTypeElem.Object, null, this.model.getId(), AscCommonExcel.c_oAscLockLayoutOptions); return lockInfo; }; WorksheetView.prototype._isLockedPrintScaleOptions = function (callback) { var lockInfo = this.collaborativeEditing.getLockInfo(c_oAscLockTypeElem.Object, null, this.model.getId(), AscCommonExcel.c_oAscLockPrintScaleOptions); this.collaborativeEditing.lock([lockInfo], callback); }; // Залочена ли панель для закрепления WorksheetView.prototype._isLockedFrozenPane = function (callback) { var lockInfo = this.collaborativeEditing.getLockInfo(c_oAscLockTypeElem.Object, null, this.model.getId(), AscCommonExcel.c_oAscLockNameFrozenPane); this.collaborativeEditing.lock([lockInfo], callback); }; WorksheetView.prototype._isLockedDefNames = function (callback, defNameId) { var lockInfo = this.collaborativeEditing.getLockInfo(c_oAscLockTypeElem.Object, null /*c_oAscLockTypeElemSubType.DefinedNames*/, -1, defNameId); this.collaborativeEditing.lock([lockInfo], callback); }; WorksheetView.prototype._isLockedCF = function (callback, cFIdArr) { if (!cFIdArr || !cFIdArr.length) { return; } var lockInfos = []; var sheetId = AscCommonExcel.CConditionalFormattingRule.sStartLockCFId + this.model.getId(); for (var i = 0; i < cFIdArr.length; i++) { var lockInfo = this.collaborativeEditing.getLockInfo(c_oAscLockTypeElem.Object, null, sheetId, cFIdArr[i]); lockInfos.push(lockInfo); } this.collaborativeEditing.lock(lockInfos, callback); }; WorksheetView.prototype._isLockedProtectedRange = function (callback, arr) { if (!arr || !arr.length) { return; } var lockInfos = []; var sheetId = Asc.CProtectedRange.sStartLock + this.model.getId(); for (var i = 0; i < arr.length; i++) { var lockInfo = this.collaborativeEditing.getLockInfo(c_oAscLockTypeElem.Object, null, sheetId, arr[i]); lockInfos.push(lockInfo); } this.collaborativeEditing.lock(lockInfos, callback); }; // Залочен ли весь лист WorksheetView.prototype._isLockedAll = function (callback) { var ar = this.model.getSelection().getLast(); var lockInfo = this.collaborativeEditing.getLockInfo(c_oAscLockTypeElem.Range, /*subType*/ c_oAscLockTypeElemSubType.ChangeProperties, this.model.getId(), new AscCommonExcel.asc_CCollaborativeRange(ar.c1, ar.r1, ar.c2, ar.r2)); this.collaborativeEditing.lock([lockInfo], callback); }; // Пересчет для входящих ячеек в добавленные строки/столбцы WorksheetView.prototype._recalcRangeByInsertRowsAndColumns = function (sheetId, ar) { var isIntersection = false, isIntersectionC1 = true, isIntersectionC2 = true, isIntersectionR1 = true, isIntersectionR2 = true; do { if (isIntersectionC1 && this.collaborativeEditing.isIntersectionInCols(sheetId, ar.c1)) { ar.c1 += 1; } else { isIntersectionC1 = false; } if (isIntersectionR1 && this.collaborativeEditing.isIntersectionInRows(sheetId, ar.r1)) { ar.r1 += 1; } else { isIntersectionR1 = false; } if (isIntersectionC2 && this.collaborativeEditing.isIntersectionInCols(sheetId, ar.c2)) { ar.c2 -= 1; } else { isIntersectionC2 = false; } if (isIntersectionR2 && this.collaborativeEditing.isIntersectionInRows(sheetId, ar.r2)) { ar.r2 -= 1; } else { isIntersectionR2 = false; } if (ar.c1 > ar.c2 || ar.r1 > ar.r2) { isIntersection = true; break; } } while (isIntersectionC1 || isIntersectionC2 || isIntersectionR1 || isIntersectionR2) ; if (false === isIntersection) { ar.c1 = this.collaborativeEditing.getLockMeColumn(sheetId, ar.c1); ar.c2 = this.collaborativeEditing.getLockMeColumn(sheetId, ar.c2); ar.r1 = this.collaborativeEditing.getLockMeRow(sheetId, ar.r1); ar.r2 = this.collaborativeEditing.getLockMeRow(sheetId, ar.r2); } return isIntersection; }; // Функция проверки lock (возвращаемый результат нельзя использовать в качестве ответа, он нужен только для редактирования ячейки) WorksheetView.prototype._isLockedCells = function (range, subType, callback) { var sheetId = this.model.getId(); var isIntersection = false; var newCallback = callback; var t = this; this.collaborativeEditing.onStartCheckLock(); var isArrayRange = Array.isArray(range); var nLength = isArrayRange ? range.length : 1; var nIndex = 0; var ar = null; var arrLocks = []; for (; nIndex < nLength; ++nIndex) { ar = isArrayRange ? range[nIndex].clone(true) : range.clone(true); if (c_oAscLockTypeElemSubType.InsertColumns !== subType && c_oAscLockTypeElemSubType.InsertRows !== subType) { // Пересчет для входящих ячеек в добавленные строки/столбцы isIntersection = this._recalcRangeByInsertRowsAndColumns(sheetId, ar); } if (false === isIntersection) { arrLocks.push(this.collaborativeEditing.getLockInfo(c_oAscLockTypeElem.Range, subType, sheetId, new AscCommonExcel.asc_CCollaborativeRange(ar.c1, ar.r1, ar.c2, ar.r2))); if (c_oAscLockTypeElemSubType.InsertColumns === subType) { newCallback = function (isSuccess) { if (isSuccess) { t.collaborativeEditing.addColsRange(sheetId, ar.clone(true)); t.collaborativeEditing.addCols(sheetId, ar.c1, ar.c2 - ar.c1 + 1); } callback(isSuccess); }; } else if (c_oAscLockTypeElemSubType.InsertRows === subType) { newCallback = function (isSuccess) { if (isSuccess) { t.collaborativeEditing.addRowsRange(sheetId, ar.clone(true)); t.collaborativeEditing.addRows(sheetId, ar.r1, ar.r2 - ar.r1 + 1); } callback(isSuccess); }; } else if (c_oAscLockTypeElemSubType.DeleteColumns === subType) { newCallback = function (isSuccess) { if (isSuccess) { t.collaborativeEditing.removeColsRange(sheetId, ar.clone(true)); t.collaborativeEditing.removeCols(sheetId, ar.c1, ar.c2 - ar.c1 + 1); } callback(isSuccess); }; } else if (c_oAscLockTypeElemSubType.DeleteRows === subType) { newCallback = function (isSuccess) { if (isSuccess) { t.collaborativeEditing.removeRowsRange(sheetId, ar.clone(true)); t.collaborativeEditing.removeRows(sheetId, ar.r1, ar.r2 - ar.r1 + 1); } callback(isSuccess); }; } } else { if (c_oAscLockTypeElemSubType.InsertColumns === subType) { t.collaborativeEditing.addColsRange(sheetId, ar.clone(true)); t.collaborativeEditing.addCols(sheetId, ar.c1, ar.c2 - ar.c1 + 1); } else if (c_oAscLockTypeElemSubType.InsertRows === subType) { t.collaborativeEditing.addRowsRange(sheetId, ar.clone(true)); t.collaborativeEditing.addRows(sheetId, ar.r1, ar.r2 - ar.r1 + 1); } else if (c_oAscLockTypeElemSubType.DeleteColumns === subType) { t.collaborativeEditing.removeColsRange(sheetId, ar.clone(true)); t.collaborativeEditing.removeCols(sheetId, ar.c1, ar.c2 - ar.c1 + 1); } else if (c_oAscLockTypeElemSubType.DeleteRows === subType) { t.collaborativeEditing.removeRowsRange(sheetId, ar.clone(true)); t.collaborativeEditing.removeRows(sheetId, ar.r1, ar.r2 - ar.r1 + 1); } } } return this.collaborativeEditing.lock(arrLocks, newCallback); }; WorksheetView.prototype._onChangeSheetViewSettings = function (type) { if (AscCH.historyitem_Worksheet_SetDisplayHeadings === type) { this._calcHeaderRowHeight(); //ToDo оставить только _calcHeaderRowHeight, а в нем выставить необходимость обновления this._updateRowPositions(); this._updateVisibleRowsCount(/*skipScrolReinit*/true); } }; WorksheetView.prototype.changeSheetViewSettings = function (type, val) { // Проверка глобального лока if (this.collaborativeEditing.getGlobalLock() || !window["Asc"]["editor"].canEdit()) { return; } let t = this; var onChangeSheetViewSettings = function (isSuccess) { if (false === isSuccess) { return; } let fullUpdate = false; if (AscCH.historyitem_Worksheet_SetDisplayHeadings === type) { t.model.setDisplayHeadings(val); } else if (AscCH.historyitem_Worksheet_SetShowZeros === type) { t.model.setShowZeros(val); } else if (AscCH.historyitem_Worksheet_SetShowFormulas === type) { t.model.setShowFormulas(val); fullUpdate = true; } else if (AscCH.historyitem_Worksheet_SetRightToLeft === type) { t.model.setRightToLeft(val, true); t.workbook.checkScrollRtl(val); if (t.objectRender) { t.objectRender.updateDrawingsTransform({target: c_oTargetType.ColumnResize, col: 0}); let drawings = t.objectRender.controller.getDrawingObjects(); for (var i = 0; i < drawings.length; ++i) { if (!drawings[i].group) { AscFormat.CheckSpPrXfrm3(drawings[i], true); } else { AscFormat.CheckSpPrXfrm(drawings[i], true); } } t.objectRender.controller.recalculate(true); } t.model.workbook.handlers.trigger("asc_onHideMathTrack"); t.model.workbook.handlers.trigger("asc_onHideSpecialPasteOptions"); t.model.workbook.handlers.trigger("asc_onHideComment"); fullUpdate = true; } else { t.model.setDisplayGridlines(val); } if (fullUpdate) { t.changeWorksheet("update", {reinitRanges: true}); } else { t.draw(); } }; if (AscCH.historyitem_Worksheet_SetRightToLeft === type) { onChangeSheetViewSettings(true); } else { this._isLockedAll(onChangeSheetViewSettings); } }; WorksheetView.prototype.changeWorksheet = function (prop, val, callback, lockDraw) { // Проверка глобального лока let isViewModeUpdate = val && val.viewModeUpdate; if (this.collaborativeEditing.getGlobalLock() || (!window["Asc"]["editor"].canEdit() && !this.workbook.Api.VersionHistory && !isViewModeUpdate)) { return; } var t = this; var arn = this.model.selectionRange.getLast().clone(); var checkRange = arn.clone(); var range, count; var oRecalcType = AscCommonExcel.recalcType.recalc; var reinitRanges = false; var updateDrawingObjectsInfo = null; var updateDrawingObjectsInfo2 = null;//{bInsert: false, operType: c_oAscInsertOptions.InsertColumns, updateRange: arn} var isUpdateCols = false, isUpdateRows = false; var isCheckChangeAutoFilter; var functionModelAction = null; var lockRange, arrChangedRanges = []; var isError; let isUpdateDefaultWidth = false; var onChangeWorksheetCallback = function (isSuccess) { if (false === isSuccess) { callback && callback(false); return; } asc_applyFunction(functionModelAction); t._initCellsArea(oRecalcType); if (oRecalcType) { t.cache.reset(); } t._cleanCellsTextMetricsCache(); t.objectRender.bUpdateMetrics = false; t._prepareCellTextMetricsCache(); t.objectRender.bUpdateMetrics = true; arrChangedRanges = arrChangedRanges.concat(t.model.hiddenManager.getRecalcHidden()); t.cellCommentator.updateAreaComments(); if (t.objectRender) { if (reinitRanges) { t._updateDrawingArea(); } if (null !== updateDrawingObjectsInfo) { t.objectRender.updateSizeDrawingObjects(updateDrawingObjectsInfo); } if (null !== updateDrawingObjectsInfo2) { t.objectRender.updateDrawingObject(updateDrawingObjectsInfo2.bInsert, updateDrawingObjectsInfo2.operType, updateDrawingObjectsInfo2.updateRange); } t.model.onUpdateRanges(arrChangedRanges); var aRanges = []; var oBBox; for (var nRange = 0; nRange < arrChangedRanges.length; ++nRange) { oBBox = arrChangedRanges[nRange]; aRanges.push(new AscCommonExcel.Range(t.model, oBBox.r1, oBBox.c1, oBBox.r2, oBBox.c2)); } if (updateDrawingObjectsInfo2 && updateDrawingObjectsInfo2.updateRange) { var nOperType = updateDrawingObjectsInfo2.operType; var oUpdateRange = updateDrawingObjectsInfo2.updateRange; switch (nOperType) { case c_oAscInsertOptions.InsertColumns: case c_oAscDeleteOptions.DeleteColumns: case c_oAscInsertOptions.InsertCellsAndShiftRight: case c_oAscDeleteOptions.DeleteCellsAndShiftLeft: { aRanges.push(new AscCommonExcel.Range(t.model, oUpdateRange.r1, oUpdateRange.c1, oUpdateRange.r2, gc_nMaxCol0)); break; } case c_oAscInsertOptions.InsertRows: case c_oAscInsertOptions.InsertCellsAndShiftDown: case c_oAscDeleteOptions.DeleteRows: case c_oAscDeleteOptions.DeleteCellsAndShiftTop: { aRanges.push(new AscCommonExcel.Range(t.model, oUpdateRange.r1, oUpdateRange.c1, gc_nMaxRow0, oUpdateRange.c2)); break; } } } Asc.editor.wb.handleDrawingsOnWorkbookChange(aRanges); } if (isUpdateDefaultWidth) { let beforeDefaultWidth = t.defaultColWidthPx; let beforeDefaultHeight = t.defaultRowHeightPx; t._initWorksheetDefaultWidth(); if (t.defaultColWidthPx !== beforeDefaultWidth) { //we must recalculate before draw t._updateVisibleColsCount(true); } if (t.defaultRowHeightPx !== beforeDefaultHeight) { //we must recalculate before draw t._updateVisibleRowsCount(true); } } t.scrollType |= AscCommonExcel.c_oAscScrollType.ScrollVertical | AscCommonExcel.c_oAscScrollType.ScrollHorizontal; t.draw(lockDraw); if (isUpdateCols) { t._updateVisibleColsCount(); } if (isUpdateRows) { t._updateVisibleRowsCount(); } t.handlers.trigger("selectionChanged"); t.getSelectionMathInfo(function (info) { t.handlers.trigger("selectionMathInfoChanged", info); }); t._cleanPagesModeData(); callback && callback(true); }; var checkDeleteCellsFilteringMode = function () { if (!window['AscCommonExcel'].filteringMode) { if (val === c_oAscDeleteOptions.DeleteCellsAndShiftLeft || val === c_oAscDeleteOptions.DeleteColumns) { //запрещаем в этом режиме удалять столбцы return false; } else if (val === c_oAscDeleteOptions.DeleteCellsAndShiftTop || val === c_oAscDeleteOptions.DeleteRows) { var tempRange = arn; if (val === c_oAscDeleteOptions.DeleteRows) { tempRange = new asc_Range(0, checkRange.r1, gc_nMaxCol0, checkRange.r2); } //запрещаем удалять последнюю строку фильтра и его заголовок + запрещаем удалять ф/т var autoFilter = t.model.AutoFilter; if (autoFilter && autoFilter.Ref) { var ref = autoFilter.Ref; //нельзя удалять целиком а/ф if (tempRange.containsRange(ref)) { return false; } else if (tempRange.containsRange(new asc_Range(ref.c1, ref.r1, ref.c2, ref.r1))) { //нельзя удалять первую строку а/ф return false; } /*else if (ref.r2 === ref.r1 + 1) { //нельзя удалять последнюю строку тела а/ф if (tempRange.containsRange(new asc_Range(ref.c1, ref.r1 + 1, ref.c2, ref.r1 + 1))) { return false; } }*/ } //нельзя целиком удалять ф/т var tableParts = t.model.TableParts; for (var i = 0; i < tableParts.length; i++) { if (tempRange.containsRange(tableParts[i].Ref)) { return false; } } } } return true; }; var changeFreezePane; var _checkFreezePaneOffset = function (_type, _range, callback, bInsert) { var isArrayRange = Array.isArray(_range); var nLength = isArrayRange ? range.length : 1; //если имеем дело с мультидиапазонами, то сюда они уже приходят уникальными и отсортированными в обратном порядке //поэтому складываю сдвиги for (var i = 0; i < nLength; i++) { var curRange = isArrayRange ? _range[i] : _range; var _changeFreezePane = t._getFreezePaneOffset(_type, curRange, bInsert); if (!changeFreezePane) { changeFreezePane = _changeFreezePane; } else if (_changeFreezePane && (_changeFreezePane.row || _changeFreezePane.col)) { changeFreezePane.col += _changeFreezePane.col; changeFreezePane.row += _changeFreezePane.row; } } if (changeFreezePane) { t._isLockedFrozenPane(function (_success) { if (_success) { callback(); } }); } else { callback(); } }; var multiRanges; var minUpdateIndex; var doMultiRanges = function (_func, _start, _end, _byCol) { History.Create_NewPoint(); History.StartTransaction(); var _selectionRange = t.model.selectionRange; if (_selectionRange && _selectionRange.ranges) { //необходимо объединить пересекающиеся диапазоны и сортировать от конца к началу if (!multiRanges) { multiRanges = new AscCommonExcel.MultiplyRange(_selectionRange.ranges).unionByRowCol(_byCol); } if (multiRanges) { for (var i = 0; i < multiRanges.length; i++) { var _range = multiRanges[i]; if (_byCol) { if (_range.c1 < minUpdateIndex) { minUpdateIndex = _range.c1; } _func(_range.c1, _range.c2, _range); } else { if (_range.r1 < minUpdateIndex) { minUpdateIndex = _range.r1; } _func(_range.r1, _range.r2, _range); } } } } else { _func(val, _start, _end); } History.EndTransaction(); }; //check user protect let checkUserRanges = t.model.selectionRange && t.model.selectionRange.ranges; if (prop === "colWidth" || prop === "showCols" || prop === "groupCols" || prop === "hideCols" || (prop === "delCell" && val === c_oAscDeleteOptions.DeleteColumns)) { if (!checkUserRanges || prop === "groupCols") { checkUserRanges = new Asc.Range(checkRange.c1, 0, checkRange.c2, gc_nMaxRow0); } } else if (prop === "rowHeight" || prop === "showRows" || prop === "groupRows" || prop === "hideRows" || (prop === "delCell" && val === c_oAscDeleteOptions.DeleteRows)) { if (!checkUserRanges || prop === "groupRows") { checkUserRanges = new Asc.Range(0, checkRange.r1, gc_nMaxCol0, checkRange.r2); } } else if (prop === "delCell" && (val === c_oAscDeleteOptions.DeleteCellsAndShiftLeft || c_oAscDeleteOptions.DeleteCellsAndShiftTop)) { checkUserRanges = arn; } if (checkUserRanges) { if (t.model.isUserProtectedRangesIntersection(checkUserRanges)) { t.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ProtectedRangeByOtherUser, c_oAscError.Level.NoCritical); return false; } } switch (prop) { case "colWidth": if (t.model.getSheetProtection(Asc.c_oAscSheetProtectType.formatColumns)) { return; } functionModelAction = function () { minUpdateIndex = checkRange.c1; doMultiRanges( function (start, end) { t.model.setColWidth(val, start, end); }, checkRange.c1, checkRange.c2, true); isUpdateCols = true; oRecalcType = AscCommonExcel.recalcType.full; reinitRanges = true; updateDrawingObjectsInfo = {target: c_oTargetType.ColumnResize, col: minUpdateIndex}; if (checkRange.getType() === c_oAscSelectionType.RangeMax || checkRange.getType() === c_oAscSelectionType.RangeRow) { isUpdateDefaultWidth = true; } }; this._isLockedAll(onChangeWorksheetCallback); break; case "showCols": if (t.model.getSheetProtection(Asc.c_oAscSheetProtectType.formatColumns)) { return; } functionModelAction = function () { minUpdateIndex = arn.c1; doMultiRanges( function (start, end) { t.model.setColHidden(false, start, end); }, arn.c1, arn.c2, true); t._updateGroups(true); oRecalcType = AscCommonExcel.recalcType.full; reinitRanges = true; updateDrawingObjectsInfo = {target: c_oTargetType.ColumnResize, col: minUpdateIndex} }; this._isLockedAll(onChangeWorksheetCallback); break; case "hideCols": if (t.model.getSheetProtection(Asc.c_oAscSheetProtectType.formatColumns)) { return; } functionModelAction = function () { minUpdateIndex = arn.c1; doMultiRanges( function (start, end) { t.model.setColHidden(true, start, end); }, arn.c1, arn.c2, true); //TODO _updateRowGroups нужно перенести в onChangeWorksheetCallback с соответсвующим флагом обновления t._updateGroups(true); oRecalcType = AscCommonExcel.recalcType.full; reinitRanges = true; updateDrawingObjectsInfo = {target: c_oTargetType.ColumnResize, col: minUpdateIndex}; }; this._isLockedAll(onChangeWorksheetCallback); break; case "rowHeight": if (t.model.getSheetProtection(Asc.c_oAscSheetProtectType.formatRows)) { return; } functionModelAction = function () { // Приводим к px (чтобы было ровно) val = val / AscCommonExcel.sizePxinPt; val = (val | val) * AscCommonExcel.sizePxinPt; minUpdateIndex = checkRange.r1; doMultiRanges( function (start, end) { t.model.setRowHeight(Math.min(val, Asc.c_oAscMaxRowHeight), start, end, true); }, checkRange.r1, checkRange.r2); isUpdateRows = true; oRecalcType = AscCommonExcel.recalcType.full; reinitRanges = true; updateDrawingObjectsInfo = {target: c_oTargetType.RowResize, row: minUpdateIndex}; if (checkRange.getType() === c_oAscSelectionType.RangeMax || checkRange.getType() === c_oAscSelectionType.RangeCol) { isUpdateDefaultWidth = true; } }; return this._isLockedAll(onChangeWorksheetCallback); case "showRows": if (t.model.getSheetProtection(Asc.c_oAscSheetProtectType.formatRows)) { return; } functionModelAction = function () { //TODO пока убираю проверку на FilteringMode. перепроверить, нужна ли она?! //AscCommonExcel.checkFilteringMode(function () { minUpdateIndex = checkRange.r1; doMultiRanges( function (start, end, updateRange) { t.model.setRowHidden(false, start, end); t.model.autoFilters.reDrawFilter(updateRange ? updateRange : arn); }, arn.r1, arn.r2); //TODO _updateRowGroups нужно перенести в onChangeWorksheetCallback с соответсвующим флагом обновления t._updateGroups(); oRecalcType = AscCommonExcel.recalcType.full; reinitRanges = true; updateDrawingObjectsInfo = {target: c_oTargetType.RowResize, row: minUpdateIndex}; //}); }; this._isLockedAll(onChangeWorksheetCallback); break; case "hideRows": if (t.model.getSheetProtection(Asc.c_oAscSheetProtectType.formatRows)) { return; } functionModelAction = function () { //AscCommonExcel.checkFilteringMode(function () { minUpdateIndex = checkRange.r1; doMultiRanges( function (start, end, updateRange) { t.model.setRowHidden(true, start, end); t.model.autoFilters.reDrawFilter(updateRange ? updateRange : arn); }, arn.r1, arn.r2); //TODO _updateRowGroups нужно перенести в onChangeWorksheetCallback с соответсвующим флагом обновления t._updateGroups(); oRecalcType = AscCommonExcel.recalcType.full; reinitRanges = true; updateDrawingObjectsInfo = {target: c_oTargetType.RowResize, row: minUpdateIndex}; //}); }; this._isLockedAll(onChangeWorksheetCallback); break; case "insCell": if (!window['AscCommonExcel'].filteringMode) { if (val === c_oAscInsertOptions.InsertCellsAndShiftRight || val === c_oAscInsertOptions.InsertColumns) { return; } } t.model.workbook.handlers.trigger("cleanCutData", true, true); t.model.workbook.handlers.trigger("cleanCopyData", true); range = t.model.getRange3(arn.r1, arn.c1, arn.r2, arn.c2); switch (val) { case c_oAscInsertOptions.InsertCellsAndShiftRight: isCheckChangeAutoFilter = t.af_checkInsDelCells(arn, c_oAscInsertOptions.InsertCellsAndShiftRight, prop); if (isCheckChangeAutoFilter === false) { return; } functionModelAction = function () { History.Create_NewPoint(); History.StartTransaction(); if (range.addCellsShiftRight()) { oRecalcType = AscCommonExcel.recalcType.full; reinitRanges = true; t.cellCommentator.updateCommentsDependencies(true, val, arn); t.shiftCellWatches(true, val, arn); t.model.shiftDataValidation(true, val, arn, true); updateDrawingObjectsInfo2 = {bInsert: true, operType: val, updateRange: arn}; } History.EndTransaction(); t.workbook.Api.onWorksheetChange(checkRange); }; arrChangedRanges.push(lockRange = new asc_Range(arn.c1, arn.r1, gc_nMaxCol0, arn.r2)); count = checkRange.c2 - checkRange.c1 + 1; if (this.model.checkShiftPivotTable(arn, new AscCommon.CellBase(0, count))) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.LockedCellPivot, c_oAscError.Level.NoCritical); return; } if (!this.model.checkShiftArrayFormulas(arn, new AscCommon.CellBase(0, count))) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.CannotChangeFormulaArray, c_oAscError.Level.NoCritical); return; } this._isLockedCells(lockRange, null, onChangeWorksheetCallback); break; case c_oAscInsertOptions.InsertCellsAndShiftDown: isCheckChangeAutoFilter = t.af_checkInsDelCells(arn, c_oAscInsertOptions.InsertCellsAndShiftDown, prop); if (isCheckChangeAutoFilter === false) { return; } functionModelAction = function () { History.Create_NewPoint(); History.StartTransaction(); if (range.addCellsShiftBottom()) { oRecalcType = AscCommonExcel.recalcType.full; reinitRanges = true; t.cellCommentator.updateCommentsDependencies(true, val, arn); t.shiftCellWatches(true, val, arn); t.model.shiftDataValidation(true, val, arn, true); updateDrawingObjectsInfo2 = {bInsert: true, operType: val, updateRange: arn}; } History.EndTransaction(); t.workbook.Api.onWorksheetChange(checkRange); }; arrChangedRanges.push(lockRange = new asc_Range(arn.c1, arn.r1, arn.c2, gc_nMaxRow0)); count = checkRange.c2 - checkRange.c1 + 1; if (this.model.checkShiftPivotTable(arn, new AscCommon.CellBase(count, 0))) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.LockedCellPivot, c_oAscError.Level.NoCritical); return; } if (!this.model.checkShiftArrayFormulas(arn, new AscCommon.CellBase(count, 0))) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.CannotChangeFormulaArray, c_oAscError.Level.NoCritical); return; } this._isLockedCells(lockRange, null, onChangeWorksheetCallback); break; case c_oAscInsertOptions.InsertColumns: if (t.model.getSheetProtection(Asc.c_oAscSheetProtectType.insertColumns)) { return; } isCheckChangeAutoFilter = t.model.autoFilters.isRangeIntersectionSeveralTableParts(arn); if (isCheckChangeAutoFilter === true) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.AutoFilterChangeFormatTableError, c_oAscError.Level.NoCritical); return; } lockRange = new asc_Range(arn.c1, 0, arn.c2, gc_nMaxRow0); count = arn.c2 - arn.c1 + 1; if (this.model.checkShiftPivotTable(lockRange, new AscCommon.CellBase(0, count))) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.LockedCellPivot, c_oAscError.Level.NoCritical); return; } if (!this.model.checkShiftArrayFormulas(lockRange, new AscCommon.CellBase(0, count))) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.CannotChangeFormulaArray, c_oAscError.Level.NoCritical); return; } var oRangeFrom = new AscCommonExcel.Range(t.model, arn.r1, arn.c1, arn.r2, AscCommon.gc_nMaxCol0); var oRangeTo = new AscCommonExcel.Range(t.model, arn.r1, arn.c1 + count, arn.r2, arn.c2 + count); functionModelAction = function () { History.Create_NewPoint(); History.StartTransaction(); oRecalcType = AscCommonExcel.recalcType.full; reinitRanges = true; t.model.insertColsBefore(arn.c1, count); t._updateGroups(true); updateDrawingObjectsInfo2 = {bInsert: true, operType: val, updateRange: arn}; t.cellCommentator.updateCommentsDependencies(true, val, arn); t.shiftCellWatches(true, val, arn); t.model.shiftDataValidation(true, val, arn, true); if (changeFreezePane) { t._updateFreezePane(changeFreezePane.col, changeFreezePane.row, true); } oRangeTo.bbox.r2 = oRangeTo.bbox.r1; oRangeTo.bbox.c2 = oRangeTo.bbox.c1 + count; Asc.editor.wbModel.handleChartsOnMoveRange(oRangeFrom, oRangeTo, true); History.EndTransaction(); t.workbook.Api.onWorksheetChange({r1: 0, c1: checkRange.c1, r2: AscCommon.gc_nMaxRow0, c2: checkRange.c2}); }; arrChangedRanges.push(lockRange); _checkFreezePaneOffset(val, lockRange, function () { t._isLockedCells(lockRange, c_oAscLockTypeElemSubType.InsertColumns, onChangeWorksheetCallback); }, true); break; case c_oAscInsertOptions.InsertRows: if (t.model.getSheetProtection(Asc.c_oAscSheetProtectType.insertRows)) { return; } lockRange = new asc_Range(0, arn.r1, gc_nMaxCol0, arn.r2); count = arn.r2 - arn.r1 + 1; if (this.model.checkShiftPivotTable(lockRange, new AscCommon.CellBase(count, 0))) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.LockedCellPivot, c_oAscError.Level.NoCritical); return; } if (!this.model.checkShiftArrayFormulas(lockRange, new AscCommon.CellBase(count, 0))) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.CannotChangeFormulaArray, c_oAscError.Level.NoCritical); return; } var oRangeFrom = new AscCommonExcel.Range(t.model, arn.r1, arn.c1, AscCommon.gc_nMaxRow0, arn.c2); var oRangeTo = new AscCommonExcel.Range(t.model, arn.r1 + count, arn.c1, arn.r2 + count, arn.c2); functionModelAction = function () { oRecalcType = AscCommonExcel.recalcType.full; reinitRanges = true; t.model.insertRowsBefore(arn.r1, count); t._updateGroups(); updateDrawingObjectsInfo2 = {bInsert: true, operType: val, updateRange: arn}; t.cellCommentator.updateCommentsDependencies(true, val, arn); t.shiftCellWatches(true, val, arn); t.model.shiftDataValidation(true, val, arn, true); if (changeFreezePane) { t._updateFreezePane(changeFreezePane.col, changeFreezePane.row, true); } oRangeTo.bbox.r2 = oRangeTo.bbox.r1 + count; oRangeTo.bbox.c2 = oRangeTo.bbox.c1; Asc.editor.wbModel.handleChartsOnMoveRange(oRangeFrom, oRangeTo, false); t.workbook.Api.onWorksheetChange({r1: checkRange.r1, c1 : 0, r2: checkRange.r2, c2: AscCommon.gc_nMaxCol0}); }; arrChangedRanges.push(lockRange); _checkFreezePaneOffset(val, lockRange, function () { t._isLockedCells(lockRange, c_oAscLockTypeElemSubType.InsertRows, onChangeWorksheetCallback); }, true); break; } break; case "delCell": if (!checkDeleteCellsFilteringMode()) { return; } t.model.workbook.handlers.trigger("cleanCutData", true, true); t.model.workbook.handlers.trigger("cleanCopyData", true); range = t.model.getRange3(checkRange.r1, checkRange.c1, checkRange.r2, checkRange.c2); switch (val) { case c_oAscDeleteOptions.DeleteCellsAndShiftLeft: isCheckChangeAutoFilter = t.af_checkInsDelCells(arn, c_oAscDeleteOptions.DeleteCellsAndShiftLeft, prop); if (isCheckChangeAutoFilter === false) { return; } if (t.model.getSheetProtection() && t.model.isLockedRange(arn)) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.DeleteColumnContainsLockedCell, c_oAscError.Level.NoCritical); return; } functionModelAction = function () { History.Create_NewPoint(); History.StartTransaction(); if (isCheckChangeAutoFilter === true) { t.model.autoFilters.isEmptyAutoFilters(arn, c_oAscDeleteOptions.DeleteCellsAndShiftLeft); } if (range.deleteCellsShiftLeft(function () { t.cellCommentator.updateCommentsDependencies(false, val, checkRange); t.shiftCellWatches(false, val, arn); t.model.shiftDataValidation(false, val, checkRange, true); t._cleanCache(lockRange); })) { updateDrawingObjectsInfo2 = {bInsert: false, operType: val, updateRange: arn}; } History.EndTransaction(); reinitRanges = true; t.workbook.Api.onWorksheetChange(checkRange); }; arrChangedRanges.push( lockRange = new asc_Range(checkRange.c1, checkRange.r1, gc_nMaxCol0, checkRange.r2)); count = checkRange.c2 - checkRange.c1 + 1; if (this.model.checkShiftPivotTable(arn, new AscCommon.CellBase(0, -count))) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.LockedCellPivot, c_oAscError.Level.NoCritical); return; } if (!this.model.checkShiftArrayFormulas(arn, new AscCommon.CellBase(0, -count))) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.CannotChangeFormulaArray, c_oAscError.Level.NoCritical); return; } if (t.cellCommentator.isContainsOtherComments(arn)) { return; } this._isLockedCells(lockRange, null, onChangeWorksheetCallback); break; case c_oAscDeleteOptions.DeleteCellsAndShiftTop: isCheckChangeAutoFilter = t.af_checkInsDelCells(arn, c_oAscDeleteOptions.DeleteCellsAndShiftTop, prop); if (isCheckChangeAutoFilter === false) { return; } if (t.model.getSheetProtection() && t.model.isLockedRange(arn)) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.DeleteRowContainsLockedCell, c_oAscError.Level.NoCritical); return; } functionModelAction = function () { History.Create_NewPoint(); History.StartTransaction(); if (isCheckChangeAutoFilter === true) { t.model.autoFilters.isEmptyAutoFilters(arn, c_oAscDeleteOptions.DeleteCellsAndShiftTop); } if (range.deleteCellsShiftUp(function () { t.cellCommentator.updateCommentsDependencies(false, val, checkRange); t.shiftCellWatches(false, val, arn); t.model.shiftDataValidation(false, val, checkRange, true); t._cleanCache(lockRange); })) { updateDrawingObjectsInfo2 = {bInsert: false, operType: val, updateRange: arn}; } History.EndTransaction(); reinitRanges = true; t.workbook.Api.onWorksheetChange(checkRange); }; arrChangedRanges.push( lockRange = new asc_Range(checkRange.c1, checkRange.r1, checkRange.c2, gc_nMaxRow0)); count = checkRange.c2 - checkRange.c1 + 1; if (this.model.checkShiftPivotTable(arn, new AscCommon.CellBase(-count, 0))) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.LockedCellPivot, c_oAscError.Level.NoCritical); return; } if (!this.model.checkShiftArrayFormulas(arn, new AscCommon.CellBase(-count, 0))) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.CannotChangeFormulaArray, c_oAscError.Level.NoCritical); return; } if (t.cellCommentator.isContainsOtherComments(arn)) { return; } this._isLockedCells(lockRange, null, onChangeWorksheetCallback); break; case c_oAscDeleteOptions.DeleteColumns: //сначала првоеряем doMultiRanges(function (start, end, updateRange) { if (isError) { return; } lockRange = new asc_Range(start, 0, end, gc_nMaxRow0); if (t.model.getSheetProtection(Asc.c_oAscSheetProtectType.deleteColumns)) { isError = true; return; } else if (t.model.getSheetProtection() && t.model.isLockedRange(lockRange)) { t.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.DeleteColumnContainsLockedCell, c_oAscError.Level.NoCritical); isError = true; return; } isCheckChangeAutoFilter = t.model.autoFilters.isActiveCellsCrossHalfFTable(updateRange, c_oAscDeleteOptions.DeleteColumns, prop); if (isCheckChangeAutoFilter === false) { isError = true; return; } count = updateRange.c2 - updateRange.c1 + 1; if (t.model.checkShiftPivotTable(lockRange, new AscCommon.CellBase(0, -count))) { t.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.LockedCellPivot, c_oAscError.Level.NoCritical); isError = true; return; } if (!t.model.checkShiftArrayFormulas(lockRange, new AscCommon.CellBase(0, -count))) { t.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.CannotChangeFormulaArray, c_oAscError.Level.NoCritical); isError = true; return; } if (t.cellCommentator.isContainsOtherComments(lockRange)) { isError = true; return; } arrChangedRanges.push(lockRange); }, null, null, true); if (isError) { return; } functionModelAction = function () { oRecalcType = AscCommonExcel.recalcType.full; reinitRanges = true; History.Create_NewPoint(); History.StartTransaction(); doMultiRanges( function (start, end, updateRange) { t.cellCommentator.updateCommentsDependencies(false, val, updateRange); t.shiftCellWatches(false, val, arn); t.model.shiftDataValidation(false, val, updateRange, true); t.model.autoFilters.isEmptyAutoFilters(updateRange, c_oAscDeleteOptions.DeleteColumns); t.model.removeCols(updateRange.c1, updateRange.c2); if (updateDrawingObjectsInfo2 && updateDrawingObjectsInfo2.updateRange) { updateDrawingObjectsInfo2.updateRange.union(updateRange); } else { updateDrawingObjectsInfo2 = {bInsert: false, operType: val, updateRange: updateRange}; } t.workbook.Api.onWorksheetChange({r1: 0, c1: checkRange.c1, r2: AscCommon.gc_nMaxRow0, c2: checkRange.c2}); }, null, null, true); t._updateGroups(true); if (changeFreezePane) { t._updateFreezePane(changeFreezePane.col, changeFreezePane.row, true); } History.EndTransaction(); }; _checkFreezePaneOffset(val, arrChangedRanges, function () { t._isLockedCells(arrChangedRanges, c_oAscLockTypeElemSubType.DeleteColumns, onChangeWorksheetCallback); }); break; case c_oAscDeleteOptions.DeleteRows: //сначала првоеряем doMultiRanges(function (start, end, updateRange) { if (isError) { return; } lockRange = new asc_Range(0, updateRange.r1, gc_nMaxCol0, updateRange.r2); if (t.model.getSheetProtection(Asc.c_oAscSheetProtectType.deleteRows)) { isError = true; return; } else if (t.model.getSheetProtection() && t.model.isLockedRange(lockRange)) { t.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.DeleteRowContainsLockedCell, c_oAscError.Level.NoCritical); isError = true; return; } isCheckChangeAutoFilter = t.model.autoFilters.isActiveCellsCrossHalfFTable(updateRange, c_oAscDeleteOptions.DeleteRows, prop); if (isCheckChangeAutoFilter === false) { isError = true; return; } count = updateRange.r2 - updateRange.r1 + 1; if (t.model.checkShiftPivotTable(lockRange, new AscCommon.CellBase(-count, 0))) { t.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.LockedCellPivot, c_oAscError.Level.NoCritical); isError = true; return; } if (!t.model.checkShiftArrayFormulas(lockRange, new AscCommon.CellBase(-count, 0))) { t.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.CannotChangeFormulaArray, c_oAscError.Level.NoCritical); isError = true; return; } if (t.cellCommentator.isContainsOtherComments(lockRange)) { isError = true; return; } arrChangedRanges.push(lockRange); }); if (isError) { return; } functionModelAction = function () { oRecalcType = AscCommonExcel.recalcType.full; reinitRanges = true; History.Create_NewPoint(); History.StartTransaction(); doMultiRanges( function (start, end, updateRange) { checkRange = t.model.autoFilters.checkDeleteAllRowsFormatTable(updateRange, true); t.cellCommentator.updateCommentsDependencies(false, val, checkRange); t.shiftCellWatches(false, val, arn); t.model.shiftDataValidation(false, val, checkRange, true); t.model.autoFilters.isEmptyAutoFilters(updateRange, c_oAscDeleteOptions.DeleteRows); var bExcludeHiddenRows = t.model.autoFilters.bIsExcludeHiddenRows(checkRange, t.model.selectionRange.activeCell); t.model.removeRows(checkRange.r1, checkRange.r2, bExcludeHiddenRows); t._updateSlicers(updateRange); if (updateDrawingObjectsInfo2 && updateDrawingObjectsInfo2.updateRange) { updateDrawingObjectsInfo2.updateRange.union(updateRange); } else { updateDrawingObjectsInfo2 = {bInsert: false, operType: val, updateRange: updateRange}; } t.workbook.Api.onWorksheetChange({r1: checkRange.r1, c1 : 0, r2: checkRange.r2, c2: AscCommon.gc_nMaxCol0}); }); t._updateGroups(); if (changeFreezePane) { t._updateFreezePane(changeFreezePane.col, changeFreezePane.row, true); } History.EndTransaction(); }; arrChangedRanges.push(lockRange); _checkFreezePaneOffset(val, lockRange, function () { t._isLockedCells(lockRange, c_oAscLockTypeElemSubType.DeleteRows, onChangeWorksheetCallback); }); break; } this.handlers.trigger("selectionNameChanged", t.getSelectionName(/*bRangeText*/false)); break; case "groupRows": if (!val && !this.checkSetGroup(arn)) { return; } functionModelAction = function () { History.Create_NewPoint(); History.StartTransaction(); t.model.setGroupRow(val, arn.r1, arn.r2); //TODO _updateRowGroups нужно перенести в onChangeWorksheetCallback с соответсвующим флагом обновления t._updateGroups(); History.EndTransaction(); /*oRecalcType = AscCommonExcel.recalcType.full; reinitRanges = true; updateDrawingObjectsInfo = {target: c_oTargetType.RowResize, row: arn.r1};*/ }; this._isLockedAll(onChangeWorksheetCallback); break; case "groupCols": if (!val && !this.checkSetGroup(arn, true)) { return; } functionModelAction = function () { History.Create_NewPoint(); History.StartTransaction(); t.model.setGroupCol(val, arn.c1, arn.c2); //TODO _updateRowGroups нужно перенести в onChangeWorksheetCallback с соответсвующим флагом обновления t._updateGroups(true); History.EndTransaction(); /*oRecalcType = AscCommonExcel.recalcType.full; reinitRanges = true; updateDrawingObjectsInfo = {target: c_oTargetType.RowResize, row: arn.r1};*/ }; this._isLockedAll(onChangeWorksheetCallback); break; case "clearOutline": var groupArrCol = this.arrColGroups ? this.arrColGroups.groupArr : null; var groupArrRow = this.arrRowGroups ? this.arrRowGroups.groupArr : null; if (!groupArrCol && !groupArrRow) { return; } functionModelAction = t.clearOutline(); this._isLockedAll(onChangeWorksheetCallback); break; case "update": if (val !== undefined) { lockDraw = true === val.lockDraw; reinitRanges = !!val.reinitRanges; } onChangeWorksheetCallback(true); break; } }; WorksheetView.prototype._autoFitColumnWidth = function (col, r1, r2, onlyIfMore, pivotButtons) { var width = null; var row, ct, c, fl, str, maxW, tm, mc, isMerged, oldWidth, oldColWidth; var lastHeight = null; var hasButton; if (null == r1) { r1 = 0; } if (null == r2) { r2 = this.model.getRowsCount() - 1; } oldColWidth = this.getColumnWidthInSymbols(col); this.canChangeColWidth = c_oAscCanChangeColWidth.all; for (row = r1; row <= r2; ++row) { // пересчет метрик текста this._addCellTextToCache(col, row); ct = this._getCellTextCache(col, row); if (ct === undefined) { continue; } fl = ct.flags; isMerged = fl.isMerged(); if (isMerged) { mc = fl.merged; // Для замерженных ячеек (с 2-мя или более колонками) оптимизировать не нужно if (mc.c1 !== mc.c2) { continue; } } var angleSin = Math.sin(ct.angle * Math.PI / 180.0); var angleCos = Math.cos(ct.angle * Math.PI / 180.0); var calcWidth; if (ct.metrics.height > this.maxRowHeightPx) { if (isMerged) { continue; } // Запоминаем старую ширину (в случае, если у нас по высоте не уберется) oldWidth = ct.metrics.width; lastHeight = null; // вычисление новой ширины столбца, чтобы высота текста была меньше maxRowHeightPx c = this._getCell(col, row); str = c.getValue2(); maxW = ct.metrics.width + this.maxDigitWidth * this.getZoom(true) * this.getRetinaPixelRatio(); while (1) { tm = this._roundTextMetrics(this.stringRender.measureString(str, fl, maxW)); if (tm.height <= this.maxRowHeightPx) { break; } if (lastHeight === tm.height) { // Ситуация, когда у нас текст не уберется по высоте (http://bugzilla.onlyoffice.com/show_bug.cgi?id=19974) tm.width = oldWidth; break; } lastHeight = tm.height; maxW += this.maxDigitWidth * this.getZoom(true) * this.getRetinaPixelRatio(); } calcWidth = Math.abs(tm.width * angleCos) + Math.abs(ct.metrics.height * angleSin); } else { calcWidth = Math.abs(ct.metrics.width * angleCos) + Math.abs(ct.metrics.height * angleSin); hasButton = this._checkFilterButtonInRange(col, row) || pivotButtons.find(function (element) { return element.row === row && element.col === col; }); if (hasButton && CellValueType.String === ct.cellType) { calcWidth += this._getFilterButtonSize(); } } width = Math.max(width, calcWidth); } width = width / (this.getZoom(true) * this.getRetinaPixelRatio()); this.canChangeColWidth = c_oAscCanChangeColWidth.none; var pad, cc, cw; if (width > 0) { pad = this.settings.cells.padding * 2 + 1; cc = Math.min(this.model.colWidthToCharCount(width + pad), Asc.c_oAscMaxColumnWidth); } else { cc = this.defaultColWidthChars; } if (cc === oldColWidth || (onlyIfMore && cc < oldColWidth)) { return false; } History.Create_NewPoint(); History.StartTransaction(); // Выставляем, что это bestFit cw = this.model.charCountToModelColWidth(cc); // ToDo 2 times may be called setColBestFit. From addCellTextToCache->_changeColWidth and this this.model.setColBestFit(true, cw, col, col); History.EndTransaction(); this._calcColWidth(col); return true; }; WorksheetView.prototype._autoFitColumnsWidth = function (ranges, onlyIfMore) { var c1, c2, range; var max = this.model.getColsCount(); for (var i = 0; i < ranges.length; ++i) { range = ranges[i]; c1 = range.c1; c2 = Math.min(range.c2, max); var pivotButtons = this.model.getPivotTableButtons(range); for (; c1 <= c2; ++c1) { this._autoFitColumnWidth(c1, range.r1, range.r2, onlyIfMore, pivotButtons); } } }; WorksheetView.prototype.autoFitColumnsWidth = function (col) { if (this.model.isUserProtectedRangesIntersection(new Asc.Range(col, 0, col, gc_nMaxRow0))) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ProtectedRangeByOtherUser, c_oAscError.Level.NoCritical); return false; } if (this.model.getSheetProtection(Asc.c_oAscSheetProtectType.formatColumns)) { return; } var viewMode = this.handlers.trigger('getViewMode'); var t = this; var r1 = 0, r2 = this.model.getRowsCount() - 1; var ranges = []; if (null !== col) { //if col contains into selected range let selectionRanges = this.model.selectionRange.ranges; for (let i = 0; i < selectionRanges.length; ++i) { if (!(selectionRanges[i].getType() === c_oAscSelectionType.RangeMax || selectionRanges[i].getType() === c_oAscSelectionType.RangeCol)) { break; } if (selectionRanges[i].containsCol(col)) { col = null; break; } } } if (null !== col) { ranges.push(new Asc.Range(col, r1, col, r2)); } else { let selectionRanges = this.model.selectionRange.ranges; for (let i = 0; i < selectionRanges.length; ++i) { ranges.push(new Asc.Range(selectionRanges[i].c1, r1, selectionRanges[i].c2, r2)); } } var onChangeCallback = function (isSuccess) { if (false === isSuccess) { return; } if (viewMode) { History.TurnOff(); } History.Create_NewPoint(); History.StartTransaction(); // ToDo multi-select var oSelection = ranges[0].clone(); oSelection.r1 = 0; oSelection.r2 = gc_nMaxRow0; History.SetSelection(oSelection); History.SetSelectionRedo(oSelection); t._autoFitColumnsWidth(ranges); t.draw(); History.EndTransaction(); if (viewMode) { History.TurnOn(); } }; if (viewMode) { onChangeCallback(true); } else { this._isLockedAll(onChangeCallback); } }; WorksheetView.prototype.autoFitRowHeight = function (r1, r2) { if (this.model.isUserProtectedRangesIntersection(new Asc.Range(0, r1, gc_nMaxCol0, r2))) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ProtectedRangeByOtherUser, c_oAscError.Level.NoCritical); return false; } if (this.model.getSheetProtection(Asc.c_oAscSheetProtectType.formatRows)) { return; } var viewMode = this.handlers.trigger('getViewMode'); var t = this; if (null === r1) { var lastSelection = this.model.selectionRange.getLast(); r1 = lastSelection.r1; r2 = lastSelection.r2; } var onChangeCallback = function (isSuccess) { if (false === isSuccess) { return; } var r; for (r = r1; r <= r2; ++r) { if (t.model.getRowCustomHeight(r)) { break; } } if (r2 < r) { t._updateRange(new Asc.Range(0, r1, gc_nMaxCol0, r2)); t.draw(); return; } if (viewMode) { History.TurnOff(); } History.Create_NewPoint(); var oSelection = History.GetSelection(); if (null != oSelection) { oSelection = oSelection.clone(); oSelection.assign(0, r1, gc_nMaxCol0, r2); History.SetSelection(oSelection); History.SetSelectionRedo(oSelection); } History.StartTransaction(); t.model.setRowBestFit(true, AscCommonExcel.oDefaultMetrics.RowHeight, r1, r2); t._updateRange(new Asc.Range(0, r1, gc_nMaxCol0, r2)); t.draw(); History.EndTransaction(); if (viewMode) { History.TurnOn(); } }; if (viewMode) { onChangeCallback(true); } else { this._isLockedAll(onChangeCallback); } }; // ----- Search ----- WorksheetView.prototype._isCellEqual = function (c, r, options) { var cell, cellText; // Не пользуемся RegExp, чтобы не возиться со спец.символами var mc = this.model.getMergedByCell(r, c); cell = mc ? this._getVisibleCell(mc.c1, mc.r1) : this._getVisibleCell(c, r); cellText = (options.lookIn === Asc.c_oAscFindLookIn.Formulas) ? cell.getValueForEdit() : cell.getValue(); if (true !== options.isMatchCase) { cellText = cellText.toLowerCase(); } if ((cellText.indexOf(options.findWhat) >= 0) && (true !== options.isWholeCell || options.findWhat.length === cellText.length)) { return (mc ? new asc_Range(mc.c1, mc.r1, mc.c1, mc.r1) : new asc_Range(c, r, c, r)); } return null; }; WorksheetView.prototype.findCellText = function (options) { var self = this; if (true !== options.isMatchCase) { options.findWhat = options.findWhat.toLowerCase(); } var selectionRange = options.selectionRange || this.model.selectionRange; var lastRange = selectionRange.getLast(); var ar = selectionRange.activeCell; var c = ar.col; var r = ar.row; var merge = this.model.getMergedByCell(r, c); options.findInSelection = Asc.c_oAscSearchBy.Sheet === options.scanOnOnlySheet && !(selectionRange.isSingleRange() && (lastRange.isOneCell() || lastRange.isEqual(merge))); var minC, minR, maxC, maxR; if (options.findInSelection) { minC = lastRange.c1; minR = lastRange.r1; maxC = lastRange.c2; maxR = lastRange.r2; } else { minC = 0; minR = 0; maxC = this.cols.length - 1; maxR = this.rows.length - 1; } var inc = options.scanForward ? +1 : -1; var isEqual; function findNextCell() { var ct = undefined; do { if (options.scanByRows) { c += inc; if (c < minC || c > maxC) { c = options.scanForward ? minC : maxC; r += inc; } } else { r += inc; if (r < minR || r > maxR) { r = options.scanForward ? minR : maxR; c += inc; } } if (c < minC || c > maxC || r < minR || r > maxR) { return undefined; } self.model._getCellNoEmpty(r, c, function(cell){ if (cell && !cell.isNullTextString()) { ct = true; } }); } while (!ct); return ct; } while (findNextCell()) { isEqual = this._isCellEqual(c, r, options); if (null !== isEqual) { return isEqual; } } // Продолжаем циклический поиск if (options.scanForward) { // Идем вперед с первой ячейки if (options.scanByRows) { c = minC - 1; r = minR; maxR = ar.row; } else { c = minC; r = minR - 1; maxC = ar.col; } } else { // Идем назад с последней c = maxC; r = maxR; if (options.scanByRows) { c = maxC + 1; r = maxR; minR = ar.row; } else { c = maxC; r = maxR + 1; minC = ar.col; } } while (findNextCell()) { isEqual = this._isCellEqual(c, r, options); if (null !== isEqual) { return isEqual; } } return null; }; WorksheetView.prototype.replaceCellText = function (options, lockDraw, callback, bSearchEngine) { // Очищаем результаты options.countFind = 0; options.countReplace = 0; var cell, tmp; var aReplaceCells = []; if (options.isReplaceAll) { //TODO нужно ли запускать ещё раз поиск?! if (!bSearchEngine) { this.model._findAllCells(options); var findResult = this.model.lastFindOptions.findResults.values; for (var row in findResult) { for (var col in findResult[row]) { var r = row; var c = col; if (!this.model.lastFindOptions.scanByRows) { tmp = c; c = r; r = tmp; } c |= 0; r |= 0; aReplaceCells.push(new Asc.Range(c, r, c, r)); } } } else { this.workbook.SearchEngine.forEachElementsBySheet(this.model.index, function (elem) { var r = elem.row; var c = elem.col; c |= 0; r |= 0; aReplaceCells.push(new Asc.Range(c, r, c, r)); }); } } else { cell = bSearchEngine ? this.workbook.SearchEngine.GetCurrentElem() : this.model.selectionRange.activeCell; // Попробуем сначала найти if (cell) { var isEqual = this._isCellEqual(cell.col, cell.row, options); if (isEqual) { aReplaceCells.push(isEqual); } } } if (0 === aReplaceCells.length) { return callback(options); } this.model.clearFindResults(); //***searchEngine //this.workbook.SearchEngine && this.workbook.SearchEngine.clearFindResults(options.isReplaceAll ? null : aReplaceCells); return this._replaceCellsText(aReplaceCells, options, lockDraw, callback); }; WorksheetView.prototype._replaceCellsText = function (aReplaceCells, options, lockDraw, callback) { var t = this; if (this.model.inPivotTable(aReplaceCells)) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.LockedCellPivot, c_oAscError.Level.NoCritical); options.error = true; this.draw(lockDraw); return callback(options); } options.indexInArray = 0; options.countFind = aReplaceCells.length; //находим общее количество повторений, в тч внутри текста if (options.isReplaceAll && !options.isSpellCheck) { options.countFind = 0; for (var i = 0; i < aReplaceCells.length; i++) { var c = t._getVisibleCell(aReplaceCells[i].c1, aReplaceCells[i].r1); var cellValue = c.getValueForEdit(); options.countFind += (cellValue.match(options.findRegExp)||[]).length } } options.countReplace = 0; //lock all if large replaced range let bCollaborativeEditing = this.collaborativeEditing.getCollaborativeEditing(); if (options.isReplaceAll && (false === bCollaborativeEditing || (this.workbook.SearchEngine && this.workbook.SearchEngine.checkMaxReplacedCells()))) { let aReplaceCellsUnion = false === bCollaborativeEditing ? aReplaceCells : new AscCommonExcel.MultiplyRange(aReplaceCells).getUnionRanges(); this._isLockedCells(aReplaceCellsUnion, /*subType*/null, function (success) { if (!success) { callback && callback(); return; } t._replaceCellTextFast(aReplaceCells, options, lockDraw, callback, true); }); } else { this._replaceCellText(aReplaceCells, options, lockDraw, callback, false); } }; WorksheetView.prototype._replaceCellTextFast = function (aReplaceCells, options, lockDraw, callback, oneUser) { // Use CReplaceCellTextManager for asynchronous text replacement processing if (!this._replaceCellTextManager) { this._replaceCellTextManager = new CReplaceCellTextManager(); } // Start asynchronous processing using timer this._replaceCellTextManager.Begin(this, aReplaceCells, options, lockDraw, callback, oneUser); }; WorksheetView.prototype._replaceCellText = function (aReplaceCells, options, lockDraw, callback, oneUser) { var t = this; var needLockCell = !oneUser; var isSC = options.isSpellCheck; if (options.indexInArray >= aReplaceCells.length) { //49467 - проблема в том, что пересчёт запускается после отрисовки на endTransaction this.model.workbook.dependencyFormulas.unlockRecal(); this.draw(lockDraw); return callback(options); } if (!oneUser && isSC) { needLockCell = false; var cell = aReplaceCells[options.indexInArray]; ++options.indexInArray; var cellValue = t._getVisibleCell(cell.c1, cell.r1).getValueForEdit(); var newCellValue = AscCommonExcel.replaceSpellCheckWords(cellValue, options); if (cellValue !== newCellValue) { needLockCell = true; } --options.indexInArray; } var onReplaceCallback = function (isSuccess) { var cell = aReplaceCells[options.indexInArray]; ++options.indexInArray; if (false !== isSuccess) { var c = t._getVisibleCell(cell.c1, cell.r1); var cellValue = c.getValueForEdit(); var v, newValue, oldCellValue = cellValue; // Check replace cell for spell. Replace full cell to fix skip first words (otherwise replace) if (!isSC) { cellValue = cellValue.replace(options.findRegExp, function () { ++options.countReplace; return options.replaceWith; }); } else { cellValue = AscCommonExcel.replaceSpellCheckWords(cellValue, options); } var isNeedToSave = oldCellValue === cellValue ? false : true; // get first fragment and change its text v = c.getValueForEdit2().slice(0, 1); // Создаем новый массив, т.к. getValueForEdit2 возвращает ссылку newValue = []; newValue[0] = new AscCommonExcel.Fragment({text: cellValue, format: v[0].format.clone()}); if (isNeedToSave && !t._saveCellValueAfterEdit(c, newValue, /*flags*/undefined, /*isNotHistory*/true, /*lockDraw*/ true)) { options.error = true; t.draw(lockDraw); return callback(options); } //***searchEngine if (isNeedToSave) { t.workbook.SearchEngine.removeFromSearchElems(cell.c1, cell.r1, t.model); } } window.setTimeout(function () { t._replaceCellText(aReplaceCells, options, lockDraw, callback, oneUser); }, 1); }; if (aReplaceCells[options.indexInArray] && this.model.isUserProtectedRangesIntersection(aReplaceCells[options.indexInArray])) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ProtectedRangeByOtherUser, c_oAscError.Level.NoCritical); return callback ? callback(options) : null; } return !needLockCell ? onReplaceCallback(true) : this._isLockedCells(aReplaceCells[options.indexInArray], /*subType*/null, onReplaceCallback); }; WorksheetView.prototype.findCell = function (reference) { var mc; var translatePrintArea = AscCommonExcel.tryTranslateToPrintArea(reference); var ranges; if (translatePrintArea) { ranges = AscCommonExcel.getRangeByRef(translatePrintArea, this.model, true, true); } if (!ranges || 0 === ranges.length) { ranges = AscCommonExcel.getRangeByRef(reference, this.model, true, true); } //добавил проверка на имя среза //проверить, возможно стоит добавить проверку на ошибку в ref именованного диапазона if (this.workbook.model.getSlicerCacheByCacheName(reference)) { return []; } var t = this; if (0 === ranges.length && this.workbook.canEdit()) { //проверяем на совпадение с именем диапазона в другом формате var changeModeRanges; AscCommonExcel.executeInR1C1Mode(!AscCommonExcel.g_R1C1Mode, function () { changeModeRanges = AscCommonExcel.getRangeByRef(reference, t.model, true, true); }); if(changeModeRanges && changeModeRanges.length){ this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.InvalidReferenceOrName, c_oAscError.Level.NoCritical); return ranges; } /*TODO: сделать поиск по названиям автофигур, должен искать до того как вызвать поиск по именованным диапазонам*/ if (this.collaborativeEditing.getGlobalLock() || !this.handlers.trigger("getLockDefNameManagerStatus")) { this.handlers.trigger("onErrorEvent", c_oAscError.ID.LockCreateDefName, c_oAscError.Level.NoCritical); this._updateSelectionNameAndInfo(); } else { // ToDo multiselect defined names var selectionLast = this.model.selectionRange.getLast(); mc = selectionLast.isOneCell() ? this.model.getMergedByCell(selectionLast.r1, selectionLast.c1) : null; var defName; AscCommonExcel.executeInR1C1Mode(false, function () { defName = t.model.workbook.editDefinesNames(null, new Asc.asc_CDefName(reference, parserHelp.get3DRef(t.model.getName(), (mc || selectionLast).getAbsName()))); }); if (defName) { this._isLockedDefNames(null, defName.getNodeId()); this.traceDependentsManager && this.traceDependentsManager.clearAll(true); } else { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.InvalidReferenceOrName, c_oAscError.Level.NoCritical); } } } return ranges; }; /* Ищет дополнение для ячейки */ WorksheetView.prototype.getCellAutoCompleteValues = function (cell, maxCount) { var merged = this._getVisibleCell(cell.col, cell.row).hasMerged(); if (merged) { cell = new AscCommon.CellBase(merged.r1, merged.c1); } var arrValues = [], objValues = {}; var range = this.findCellAutoComplete(cell, 1, maxCount); this.getColValues(range, cell.col, arrValues, objValues); range = this.findCellAutoComplete(cell, -1, maxCount); this.getColValues(range, cell.col, arrValues, objValues); arrValues.sort(); return arrValues; }; /* Ищет дополнение для ячейки (снизу или сверху) */ WorksheetView.prototype.findCellAutoComplete = function (cellActive, step, maxCount) { var col = cellActive.col, row = cellActive.row; row += step; if (!maxCount) { maxCount = Number.MAX_VALUE; } var count = 0, isBreak = false, end = 0 < step ? this.model.getRowsCount() - 1 : 0, isEnd = true, colsCount = this.model.getColsCount(), range = new asc_Range(col, row, col, row); for (; row * step <= end && count < maxCount; row += step, isEnd = true, ++count) { for (col = range.c1; col <= range.c2; ++col) { this.model._getCellNoEmpty(row, col, function(cell) { if (cell && false === cell.isNullText()) { isEnd = false; isBreak = true; } }); if (isBreak) { isBreak = false; break; } } // Идем влево по колонкам for (col = range.c1 - 1; col >= 0; --col) { this.model._getCellNoEmpty(row, col, function(cell) { isBreak = (null === cell || cell.isNullText()); }); if (isBreak) { isBreak = false; break; } isEnd = false; } range.c1 = col + 1; // Идем вправо по колонкам for (col = range.c2 + 1; col < colsCount; ++col) { this.model._getCellNoEmpty(row, col, function(cell) { isBreak = (null === cell || cell.isNullText()); }); if (isBreak) { isBreak = false; break; } isEnd = false; } range.c2 = col - 1; if (isEnd) { break; } } if (0 < step) { range.r2 = row - 1; } else { range.r1 = row + 1; } return range.r1 <= range.r2 ? range : null; }; /* Формирует уникальный массив */ WorksheetView.prototype.getColValues = function (range, col, arrValues, objValues) { if (null === range) { return; } var row, value, valueLowCase; for (row = range.r1; row <= range.r2; ++row) { this.model._getCellNoEmpty(row, col, function(cell) { if (cell && CellValueType.String === cell.getType()) { value = cell.getValue(); valueLowCase = value.toLowerCase(); if (!objValues.hasOwnProperty(valueLowCase)) { arrValues.push(value); objValues[valueLowCase] = 1; } } }); } }; WorksheetView.prototype.cloneSelection = function (start, selectRange) { this.cleanSelection(); this.model.cloneSelection(start, selectRange); if (start) { if (this.isSelectOnShape) { this.objectRender.controller.checkChartForProps(true); } } else { this.endEditChart(); this.objectRender.controller.checkChartForProps(false); } }; WorksheetView.prototype._isFormula = function ( val ) { return (0 < val.length && 1 < val[0].getFragmentText().length && '=' === val[0].getFragmentText().charAt( 0 )); }; WorksheetView.prototype.canConverToFormula = function ( formulaText ) { if (formulaText && formulaText.length > 1) { return formulaText[0] === "+" || formulaText[0] === "-"; } return false; }; WorksheetView.prototype.getActiveCell = function (x, y, isCoord) { var col, row; if (isCoord) { col = this._findColUnderCursor(x, true); row = this._findRowUnderCursor(y, true); if (!col || !row) { return false; } col = col.col; row = row.row; } else { var activeCell = this.model.getSelection().activeCell; col = activeCell.col; row = activeCell.row; } // Проверим замерженность var mergedRange = this.model.getMergedByCell(row, col); return mergedRange ? mergedRange : new asc_Range(col, row, col, row); }; WorksheetView.prototype._saveCellValueAfterEdit = function (c, val, flags, isNotHistory, lockDraw) { const t = this; const ws = t.model; let bbox = c.bbox; let ctrlKey = flags && flags.ctrlKey; let shiftKey = flags && flags.shiftKey; let applyByArray = ctrlKey && shiftKey; //t.model.workbook.dependencyFormulas.lockRecal(); let arrayCannotExpand; // flag, needed to avoid selecting the entire expected dynamic range in situations where the array cannot open //***array-formula*** const changeRangesIfArrayFormula = function() { if(ctrlKey) { //TODO есть баг с тем, что не лочатся все ячейки при данном действии // c = dynamicSelectionRange && !arrayCannotExpand ? t._getRange(dynamicSelectionRange.c1, dynamicSelectionRange.r1, dynamicSelectionRange.c2, dynamicSelectionRange.r2) : t.getSelectedRange(); c = dynamicSelectionRange ? t._getRange(dynamicSelectionRange.c1, dynamicSelectionRange.r1, dynamicSelectionRange.c2, dynamicSelectionRange.r2) : t.getSelectedRange(); var isAllColumnSelect = c && c.bbox && (c.bbox.getType() === c_oAscSelectionType.RangeMax || c.bbox.getType() === c_oAscSelectionType.RangeCol); if(c.bbox.isOneCell()) { //проверяем, есть ли формула массива в этой ячейке t.model._getCell(c.bbox.r1, c.bbox.c1, function(cell){ var formulaRef = cell && cell.formulaParsed && cell.formulaParsed.ref ? cell.formulaParsed.ref : null; if(formulaRef) { c = t.model.getRange3(formulaRef.r1, formulaRef.c1, formulaRef.r2, formulaRef.c2); } }); } else if ((!flags || !flags.notCheckMax) && isAllColumnSelect) { var allRows = t.model.getRowsCount(); var filledRows; if (window["AscDesktopEditor"]) { filledRows = Math.max(c_maxColFillDataCount, allRows); bbox = new Asc.Range(c.bbox.c1, 0, c.bbox.c2, filledRows - 1); c = t._getRange(bbox.c1, bbox.r1, bbox.c2, bbox.r2); if (filledRows -1 !== gc_nMaxRow0) { t.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.FillAllRowsWarning, c_oAscError.Level.NoCritical, [filledRows, allRows], function () { if (!flags) { flags = [] } flags.notCheckMax = true; t._saveCellValueAfterEdit(c, val, flags, isNotHistory, lockDraw); }); } } else { filledRows = c_maxColFillDataCount; bbox = new Asc.Range(c.bbox.c1, 0, c.bbox.c2, filledRows - 1); c = t._getRange(bbox.c1, bbox.r1, bbox.c2, bbox.r2); t.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.FillAllRowsWarning, c_oAscError.Level.NoCritical, [filledRows, allRows]); } return; } bbox = c.bbox; // set selection if dynamic arrays are used if (dynamicSelectionRange) { ws.copySelection && ws.copySelection.assign2(bbox); } } }; let startTransaction = function () { if (!isNotHistory) { History.Create_NewPoint(); History.StartTransaction(); } }; let endTransaction = function () { if (!isNotHistory) { History.EndTransaction(); } }; startTransaction(); let dynamicSelectionRange = null; let isFormula = this._isFormula(val); let newFP, parseResult; let isFormulaFromVal; let valText = val[0].getFragmentText(); let _numFormat = c && c.getNumFormat && c.getNumFormat(); let _isTextFormat = _numFormat && _numFormat.getType && _numFormat.getType() === Asc.c_oAscNumFormatType.Text; let canConverToFormula = !_isTextFormat && this.canConverToFormula(valText); let cellWithFormula = new AscCommonExcel.CCellWithFormula(this.model, bbox.r1, bbox.c1); if (!isFormula && canConverToFormula) { newFP = new AscCommonExcel.parserFormula(valText, cellWithFormula, this.model); parseResult = new AscCommonExcel.ParseResult(); // todo add backlight when choosing Ref/Range if (newFP.parse(AscCommonExcel.oFormulaLocaleInfo.Parse, AscCommonExcel.oFormulaLocaleInfo.DigitSep, parseResult) || !(parseResult.error !== c_oAscError.ID.FrmlParenthesesCorrectCount)) { if ((newFP.outStack.length === 1 && newFP.outStack[0].type === AscCommonExcel.cElementType.number) || (newFP.outStack.length === 2 && newFP.outStack[0].type === AscCommonExcel.cElementType.number && newFP.outStack[1].type === AscCommonExcel.cElementType.operator && newFP.outStack[1].name === "un_minus")) { isFormulaFromVal = false; isFormula = false; } else { valText = "=" + valText; val[0].setFragmentText(valText); isFormulaFromVal = true; isFormula = true; } } } if (isFormula) { let calculateResult = new AscCommonExcel.CalculateResult(true); //перед созданием точки в истории, проверяю, валидная ли формула cellWithFormula = isFormulaFromVal ? cellWithFormula : new AscCommonExcel.CCellWithFormula(this.model, bbox.r1, bbox.c1); newFP = isFormulaFromVal ? newFP : new AscCommonExcel.parserFormula(valText.substring(1), cellWithFormula, this.model); parseResult = isFormulaFromVal ? parseResult : new AscCommonExcel.ParseResult(); if (!isFormulaFromVal && !newFP.parse(AscCommonExcel.oFormulaLocaleInfo.Parse, AscCommonExcel.oFormulaLocaleInfo.DigitSep, parseResult)) { if (parseResult.error !== c_oAscError.ID.FrmlWrongFunctionName && parseResult.error !== c_oAscError.ID.FrmlParenthesesCorrectCount) { this.model.workbook.handlers.trigger("asc_onError", parseResult.error, c_oAscError.Level.NoCritical); endTransaction(); return; } } // we check for new links to external data if (parseResult.externalReferenesNeedAdd) { t.model.workbook.addExternalReferencesAfterParseFormulas(parseResult.externalReferenesNeedAdd); // then we parse the formula again to obtain the correct outStack and external link indexes newFP = new AscCommonExcel.parserFormula(valText.substring(1), cellWithFormula, this.model); if (!newFP.parse(AscCommonExcel.oFormulaLocaleInfo.Parse, AscCommonExcel.oFormulaLocaleInfo.DigitSep, parseResult)) { this.model.workbook.handlers.trigger("asc_onError", parseResult.error, c_oAscError.Level.NoCritical); endTransaction(); return; } } if (!applyByArray && AscCommonExcel.bIsSupportDynamicArrays) { /* if we write not through cse, then check the formula for the presence of ref */ /* if ref exists, write the formula as an array formula and also find its dimensions for further expansion */ let isRef = newFP.findRefByOutStack(); if (isRef) { // if formula has ref, calculate it to get the final size of ref let formulaRes = newFP.calculate(null, null, null, null, calculateResult); applyByArray = true; ctrlKey = true; if ((newFP.aca && newFP.ca)) { // array cannot expand // set ref to the first(parent) cell arrayCannotExpand = true; dynamicSelectionRange = new Asc.Range(newFP.parent.nCol, newFP.parent.nRow, newFP.parent.nCol, newFP.parent.nRow); t.model.workbook.dependencyFormulas.addToVolatileArrays(newFP); } else { let dimension = formulaRes.getDimensions(); dynamicSelectionRange = new Asc.Range(newFP.parent.nCol, newFP.parent.nRow, newFP.parent.nCol + dimension.col - 1, newFP.parent.nRow + dimension.row - 1); } } else if (newFP.ref) { applyByArray = true; ctrlKey = true; dynamicSelectionRange = newFP.ref; } } else if (!applyByArray && !ctrlKey) { // TODO ctrlKey+enter used to fills the selected cell range with the current entry. Dynamic arrays will have to work the same // refInfo = {cannoChangeFormulaArray: true|false, applyByArray: true|false, ctrlKey: true|false, dynamicRange: range} let canAutoExpand, refInfo; if (parseResult.error === c_oAscError.ID.FrmlParenthesesCorrectCount) { // parse again with correct amount of parentheses newFP = new AscCommonExcel.parserFormula(newFP.getFormula(), cellWithFormula, this.model); if (!newFP.parse(AscCommonExcel.oFormulaLocaleInfo.Parse, AscCommonExcel.oFormulaLocaleInfo.DigitSep, parseResult)) { this.model.workbook.handlers.trigger("asc_onError", parseResult.error, c_oAscError.Level.NoCritical); endTransaction(); return; } } canAutoExpand = newFP.findRefByOutStack(true); refInfo = canAutoExpand ? ws.getRefDynamicInfo(newFP, calculateResult) : false; if (refInfo) { if (refInfo.cannotChangeFormulaArray) { t.handlers.trigger("onErrorEvent", c_oAscError.ID.CannotChangeFormulaArray, c_oAscError.Level.NoCritical); endTransaction(); return false; } applyByArray = refInfo.applyByArray; ctrlKey = refInfo.ctrlKey; dynamicSelectionRange = refInfo.dynamicRange; } } // preliminary calculation of the formula // if calculateResult.error is not empty - return this error if (calculateResult && calculateResult.error != null) { this.model.workbook.handlers.trigger("asc_onError", calculateResult.error, c_oAscError.Level.NoCritical); endTransaction(); return false; } } const pivotTable = c.worksheet.getPivotTable(c.bbox.c1, c.bbox.r1); // if there is a formula use setValue, otherwise setValue2 if (isFormula) { if (pivotTable) { this.workbook.Api.sendEvent('asc_onError', Asc.c_oAscError.ID.FormulaInPivotFieldName, Asc.c_oAscError.Level.NoCritical); endTransaction(); return; } // ToDo - при вводе формулы в заголовок автофильтра надо писать "0" //***array-formula*** let ret = true; changeRangesIfArrayFormula(); //***dynamic array-formula*** let changedDynamicArraysList = AscCommonExcel.bIsSupportDynamicArrays ? ws.getChangedArrayList() : null; if(ctrlKey) { this.model.workbook.dependencyFormulas.lockRecal(); } // before putting a value in the selected cell, need to check whether the given range concerns any of the arrays (daf) on the page // collect a list of all affected arrays and go through each of them // if the main cell was affected, then need to clear the entire array (we will also need to update the DepGraph dependency list) // if the main cell has NOT been affected, we need to execute cell.setValue("") or Range.setValue("") for all child cells of the array, and set the aca=true flag for the main cell if (changedDynamicArraysList) { for (let array in changedDynamicArraysList) { let arrayData = changedDynamicArraysList[array]; let formula = arrayData.formula; let dynamicbbox = arrayData.range; let range = (formula && formula.aca && formula.ca) ? t.model.getRange3(dynamicbbox.r1, dynamicbbox.c1, dynamicbbox.r1, dynamicbbox.c1) : t.model.getRange3(dynamicbbox.r1, dynamicbbox.c1, dynamicbbox.r2, dynamicbbox.c2); if (arrayData.doDelete) { // delete all cells range.cleanText(); // remove listener let listenerId = arrayData.formula && arrayData.formula.getListenerId(); ws.workbook.dependencyFormulas.endListeningVolatileArray(listenerId); } else if (arrayData.doRecalc) { // delete all cells except the first one range.cleanTextExceptFirst(); // add to volatile ws.workbook.dependencyFormulas.addToVolatileArrays(formula); } } ws.clearChangedArrayList(); } if (applyByArray) this.workbook.MacrosAddData(AscDFH.historydescription_Spreadsheet_SetCellFormula, AscCommonExcel.getFragmentsText(val)); else this.workbook.MacrosAddData(AscDFH.historydescription_Spreadsheet_SetCellValue, AscCommonExcel.getFragmentsText(val)); // set the value to the selected range c.setValue(AscCommonExcel.getFragmentsText(val), function (r) { ret = r; }, null, applyByArray ? bbox : ((!applyByArray && ctrlKey) ? null : undefined), null, AscCommonExcel.bIsSupportDynamicArrays ? dynamicSelectionRange : null); this.workbook.FinalizeAction(); // recalc all volatile arrays on page t.model.recalculateVolatileArrays(); //***array-formula*** if(ctrlKey) { this.model.workbook.dependencyFormulas.unlockRecal(); } if (!ret) { endTransaction(); //t.model.workbook.dependencyFormulas.unlockRecal(); return false; } isFormula = c.isFormula(); this.model.checkChangeTablesContent(bbox); } else { //***array-formula*** changeRangesIfArrayFormula(); if (AscCommonExcel.bIsSupportDynamicArrays) { //***dynamic array-formula*** let changedDynamicArraysList = ws.getChangedArrayList(); if (changedDynamicArraysList) { // go through changed dynamic arrays, and delete all|partitional values? for (let array in changedDynamicArraysList) { let arrayData = changedDynamicArraysList[array]; let formula = arrayData.formula; let dynamicbbox = arrayData.range; let range = (formula && formula.aca && formula.ca) ? t.model.getRange3(dynamicbbox.r1, dynamicbbox.c1, dynamicbbox.r1, dynamicbbox.c1) : t.model.getRange3(dynamicbbox.r1, dynamicbbox.c1, dynamicbbox.r2, dynamicbbox.c2); // todo create clear function for cells (clearRange?) if (arrayData.doDelete) { // delete all cells range.cleanText(); // remove listener let listenerId = arrayData.formula && arrayData.formula.getListenerId(); ws.workbook.dependencyFormulas.endListeningVolatileArray(listenerId); } else if (arrayData.doRecalc) { // delete all cells except the first one range.cleanTextExceptFirst(); // add to volatile ws.workbook.dependencyFormulas.addToVolatileArrays(formula); } } ws.clearChangedArrayList(); } } this.workbook.MacrosAddData(AscDFH.historydescription_Spreadsheet_SetCellValue, AscCommonExcel.getFragmentsText(val)); // set the value to the selected range if (pivotTable) { pivotTable.editCell(c.bbox, AscCommonExcel.getFragmentsText(val)); } else { c.setValue2(val, true); } // recalculate all volatile arrays on page t.model.recalculateVolatileArrays(); // Вызываем функцию пересчета для заголовков форматированной таблицы this.model.checkChangeTablesContent(bbox); } if (!isFormula) { if (-1 !== AscCommonExcel.getFragmentsText(val).indexOf(kNewLine)) { c.setWrap(true); } } endTransaction(); if(isFormula && !applyByArray) { c._foreach(function(cell){ cell._adjustCellFormat(); }); } var emptyValue = val && val.length === 1 && val[0] && val[0].text === ""; if (!emptyValue) { t.applyTableAutoExpansion(bbox, applyByArray); } //t.model.workbook.dependencyFormulas.unlockRecal(); this.canChangeColWidth = isNotHistory ? c_oAscCanChangeColWidth.none : c_oAscCanChangeColWidth.numbers; this._updateRange(bbox); if (bbox && (bbox.getType() === c_oAscSelectionType.RangeMax || bbox.getType() === c_oAscSelectionType.RangeCol)) { this.scrollType |= AscCommonExcel.c_oAscScrollType.ScrollVertical; if (bbox.getType() === c_oAscSelectionType.RangeMax) { this.scrollType |= AscCommonExcel.c_oAscScrollType.ScrollHorizontal; } } this.canChangeColWidth = c_oAscCanChangeColWidth.none; this.draw(lockDraw); if (isFormula) { this.workbook.Api.onWorksheetChange(bbox); } // если вернуть false, то редактор не закроется return true; }; WorksheetView.prototype.openCellEditor = function (editor, enterOptions, selectionRange) { var t = this, col, row, c, fl, mc, bg, isMerged; let wsModel = this.model; //todo after remove check native if (window['IS_NATIVE_EDITOR'] && wsModel.getSheetProtection(Asc.c_oAscSheetProtectType.selectLockedCells) && wsModel.getSheetProtection(Asc.c_oAscSheetProtectType.selectUnlockedCells)) { wsModel.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ChangeOnProtectedSheet, c_oAscError.Level.NoCritical); return; } let activeCell = selectionRange && selectionRange.activeCell ? selectionRange.activeCell : wsModel.selectionRange.activeCell; if (window['IS_NATIVE_EDITOR'] && activeCell && wsModel.getSheetProtection() && wsModel.isLockedRange(new Asc.Range(activeCell.col, activeCell.row, activeCell.col, activeCell.row))) { wsModel.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ChangeOnProtectedSheet, c_oAscError.Level.NoCritical); return; } if (selectionRange) { this.model.selectionRange = selectionRange; } if (this.oOtherRanges) { this.cleanSelection(); this.endEditChart(); this._drawSelection(); } var cell = this.model.selectionRange.activeCell; function getVisibleRangeObject() { var vr = t.visibleRange.clone(), offsetX = 0, offsetY = 0; if (t.topLeftFrozenCell) { var cFrozen = t.topLeftFrozenCell.getCol0(); var rFrozen = t.topLeftFrozenCell.getRow0(); if (0 < cFrozen) { if (col >= cFrozen) { offsetX = t._getColLeft(cFrozen) - t._getColLeft(0) - t.getHorizontalScrollCorrect(); } else { vr.c1 = 0; vr.c2 = cFrozen - 1; } } else { offsetX -= t.getHorizontalScrollCorrect(); } if (0 < rFrozen) { if (row >= rFrozen) { offsetY = t._getRowTop(rFrozen) - t._getRowTop(0) - t.getScrollCorrect(); } else { vr.r1 = 0; vr.r2 = rFrozen - 1; } } else { offsetY -= t.getScrollCorrect(); } } else { offsetX -= t.getHorizontalScrollCorrect(); offsetY -= t.getScrollCorrect(); } return {vr: vr, offsetX: offsetX, offsetY: offsetY}; } col = cell.col; row = cell.row; //TODO need only 1 redraw if (row === t.visibleRange.r1) { this.setScrollCorrect(0, true); } if (col === t.visibleRange.c1) { this.setHorizontalScrollCorrect(0, true); } // Возможно стоит заменить на ячейку из кеша c = this._getVisibleCell(col, row); fl = this._getCellFlags(c); isMerged = fl.isMerged(); if (isMerged) { mc = fl.merged; c = this._getVisibleCell(mc.c1, mc.r1); fl = this._getCellFlags(c); } if (this.getRightToLeft() && col === 0) { fl.wrapText = true; } var align = c.getAlign(); var indent = align && align.indent; if (AscCommon.align_Distributed === fl.textAlign) { fl.textAlign = AscCommon.align_Center; } let offset = this._calcActiveCellOffset(); if (this.topLeftFrozenCell) { if (col < this.topLeftFrozenCell.getCol0()) { offset.col = 0; } if (row < this.topLeftFrozenCell.getRow0()) { offset.row = 0; } } this.handlers.trigger("onScroll", offset); bg = c.getFillColor(); var font = c.getFont(); // Скрываем окно редактирования комментария this.model.workbook.handlers.trigger("asc_onHideComment"); var _fragmentsTmp = c.getValueForEdit2(); var fragments = []; for (var i = 0; i < _fragmentsTmp.length; ++i) { fragments.push(_fragmentsTmp[i].clone()); } var arrAutoComplete = this.getCellAutoCompleteValues(cell, kMaxAutoCompleteCellEdit); var arrAutoCompleteLC = asc.arrayToLowerCase(arrAutoComplete); this.model.workbook.handlers.trigger("cleanCutData", true, true); this.model.workbook.handlers.trigger("cleanCopyData", true); editor.open({ enterOptions: enterOptions, fragments: fragments, flags: fl, font: font, background: bg || this.settings.cells.defaultState.background, zoom: this.getZoom(), isAddPersentFormat: enterOptions.quickInput && Asc.c_oAscNumFormatType.Percent === c.getNumFormatType(), autoComplete: arrAutoComplete, autoCompleteLC: arrAutoCompleteLC, bbox: c.bbox, cellNumFormat: c.getNumFormatType(), saveValueCallback: function (val, flags, callback) { var saveCellValueCallback = function (success) { if (!success) { if (callback) { return callback(false); } else { return false; } } let _compare = function (_oldReferenceIds, _newReferenceIds) { if (_oldReferenceIds && _newReferenceIds && _oldReferenceIds.length === _newReferenceIds.length) { for (let i = 0; i < _newReferenceIds.length; i++) { if (_oldReferenceIds[i] !== _newReferenceIds[i]) { return false; } } return true; } return false; }; // let beforeExternalReferences = t.getExternalReferencesByCell(c, null, true); let bRes = t._saveCellValueAfterEdit(c, val, flags, /*isNotHistory*/false, /*lockDraw*/false); let afterExternalReferences = t.getExternalReferencesByCell(c, true, true); if (afterExternalReferences) { //t.model.workbook.handlers.trigger("asc_onNeedUpdateExternalReference"); t.updateExternalReferenceByCell(c, true, null, true); } if (callback) { return callback(bRes); } else { return bRes; } }; var text = AscCommonExcel.getFragmentsText(val); var dataValidation = t.model.getDataValidation(col, row); if (dataValidation && dataValidation.allowBlank && 0 === text.length) { dataValidation = null; } if (dataValidation) { var checkCell, setValueError; AscFormat.ExecuteNoHistory(function () { checkCell = t.model.getCellForValidation(row, col, val, t._isFormula(val) ? text : null, function (_res) { setValueError = !_res; }); }, this, []); if (setValueError) { // Error sent from another function return false; } //если в качестве условия введена формула, необходимо чтобы данные временно были в ячейке //поскольку формула может ссылаться на данную ячейку var oldValueData; //дополнительно ещё проверим на наличие данной ячейки в стеке формулы //если её там нет - временно подменять значение не нужно var isNeedChange = Asc.EDataValidationType.Custom === dataValidation.type /*&& dataValidation.checkFormulaStackOnCell(row, col)*/; var temporarySetValue = function (_val) { if (isNeedChange) { c._foreach(function (cell) { if (cell.nCol === col && cell.nRow === row) { if (_val) { //temporary set oldValueData = cell.getValueData(); cell._setValueData(_val.value); } else { //revert cell._setValueData(oldValueData.value); } } }); } }; temporarySetValue(checkCell.getValueData()); if (!dataValidation.checkValue(checkCell, t.model)) { t.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.DataValidate, c_oAscError.Level.NoCritical, dataValidation); editor.setFocus(true); temporarySetValue(); return false; } else { temporarySetValue(); } } //***array-formula*** let ref = null; let isDynamicRef = null; if (flags.ctrlKey && flags.shiftKey) { //необходимо проверить на выделение массива частично var activeRange = t.getSelectedRange(); var doNotApply = false; var formulaRef; if (!activeRange.bbox.isOneCell()) { if (t.model.autoFilters.isIntersectionTable(activeRange.bbox)) { t.handlers.trigger("onErrorEvent", c_oAscError.ID.MultiCellsInTablesFormulaArray, c_oAscError.Level.NoCritical); return false; } else if (t.model.inPivotTable(activeRange.bbox)) { t.handlers.trigger("onErrorEvent", c_oAscError.ID.LockedCellPivot, c_oAscError.Level.NoCritical); return false; } else { activeRange._foreachNoEmpty(function (cell) { ref = cell.formulaParsed && cell.formulaParsed.ref ? cell.formulaParsed.ref : null; if (ref && !activeRange.bbox.containsRange(ref)) { doNotApply = true; return false; } }); } } else { activeRange._foreachNoEmpty(function (cell) { formulaRef = cell.formulaParsed && cell.formulaParsed.ref ? cell.formulaParsed.ref : null; }); } if (doNotApply) { t.handlers.trigger("onErrorEvent", c_oAscError.ID.CannotChangeFormulaArray, c_oAscError.Level.NoCritical); return false; } else { var lockedRange = formulaRef ? formulaRef : activeRange.bbox; t._isLockedCells(lockedRange, /*subType*/null, saveCellValueCallback); } } else { // check activeCell for the presence of an array formula c._foreachNoEmpty(function (cell) { if (cell) { let formula = cell.formulaParsed; let arrayFormulaRef = formula && formula.getArrayFormulaRef(); let dynamicRange = formula && formula.getDynamicRef(); ref = formula && arrayFormulaRef ? arrayFormulaRef : null; isDynamicRef = formula && dynamicRange ? true : null; if (isDynamicRef && AscCommonExcel.bIsSupportDynamicArrays) { let name = dynamicRange.getName(AscCommonExcel.referenceType.R); let arrayInfo = {range: dynamicRange, doDelete: false, doRecalc: true, formula: formula}; // check this cell. If this is the first cell of dynamic range, delete this range, else delete all elements except the first if (cell.nRow === dynamicRange.r1 && cell.nCol === dynamicRange.c1) { arrayInfo.doRecalc = false arrayInfo.doDelete = true } t.model.addChangedArray(name, arrayInfo); } } }); if (ref && !ref.isOneCell()) { if (isDynamicRef && AscCommonExcel.bIsSupportDynamicArrays) { return saveCellValueCallback(true); } else { t.handlers.trigger("onErrorEvent", c_oAscError.ID.CannotChangeFormulaArray, c_oAscError.Level.NoCritical); return false; } } else { return saveCellValueCallback(true); } } }, getSides: function () { var _c1, _r1, _c2, _r2, ri = 0, bi = 0; let isRtl = t.getRightToLeft(); if (isMerged) { _c1 = isRtl ? mc.c2 : mc.c1; _c2 = isRtl ? mc.c1 : mc.c2; _r1 = mc.r1; _r2 = mc.r2; } else { _c1 = _c2 = col; _r1 = _r2 = row; } var vro = getVisibleRangeObject(); var i, w, h, arrLeftS = [], arrRightS = [], arrBottomS = []; var offsX = t._getColLeft(vro.vr.c1) - t._getColLeft(0) - vro.offsetX; if (isRtl) { offsX = -offsX; } var offsY = t._getRowTop(vro.vr.r1) - t._getRowTop(0) - vro.offsetY; var cellX = t._getColLeft(_c1, true) - offsX, cellY = t._getRowTop(_r1) - offsY; var _left = cellX; if (isRtl) { for (i = _c1; i >= vro.vr.c1; --i) { w = t._getColumnWidth(i); if (0 < w) { arrLeftS.push(_left); } _left -= w; } } else { for (i = _c1; i <= vro.vr.c2; ++i) { w = t._getColumnWidth(i); if (0 < w) { arrLeftS.push(_left); } _left -= w; } } if (_c2 > vro.vr.c2) { _c2 = vro.vr.c2; } _left = cellX; if (isRtl) { for (i = _c1; i >= vro.vr.c1; --i) { w = t._getColumnWidth(i); _left += w; if (0 < w) { arrRightS.push(_left); } if (_c2 === i) { ri = arrRightS.length - 1; } } } else { for (i = _c1; i <= vro.vr.c2; ++i) { w = t._getColumnWidth(i); _left += w; if (0 < w) { arrRightS.push(_left); } if (_c2 === i) { ri = arrRightS.length - 1; } } } w = t.drawingCtx.getWidth(); if (arrRightS[arrRightS.length - 1] > w) { arrRightS[arrRightS.length - 1] = w; } if (_r2 > vro.vr.r2) { _r2 = vro.vr.r2; } var _top = cellY; for (i = _r1; i <= vro.vr.r2; ++i) { h = t._getRowHeight(i); _top += h; if (0 < h) { arrBottomS.push(_top); } if (_r2 === i) { bi = arrBottomS.length - 1; } } h = t.drawingCtx.getHeight(); if (arrBottomS[arrBottomS.length - 1] > h) { arrBottomS[arrBottomS.length - 1] = h; } if (indent) { if (AscCommon.align_Right === align.hor) { arrRightS[ri] -= indent * 3 * t.defaultSpaceWidth + 1; } else if (AscCommon.align_Left === align.hor) { cellX += indent * 3 * t.defaultSpaceWidth; } } return {l: arrLeftS, r: arrRightS, b: arrBottomS, cellX: cellX, cellY: cellY, ri: ri, bi: bi}; }, checkVisible: function () { return null !== t.getCellVisibleRange(c.bbox.c1, c.bbox.r1); } }); }; WorksheetView.prototype.updateRanges = function (ranges, skipHeight) { if (0 < ranges.length) { for (var i = 0; i < ranges.length; ++i) { this._updateRange(ranges[i], skipHeight); } } }; WorksheetView.prototype._updateRange = function (range, skipHeight) { this._cleanCache(range); if (c_oAscSelectionType.RangeMax === range.getType()) { // ToDo refactoring. Clean this only delete/insert/update info rows/column this.rows = []; this.cols = []; } if (skipHeight) { this.arrRecalcRanges.push(range); } else { this.arrRecalcRangesWithHeight.push(range); this.arrRecalcRangesCanChangeColWidth.push(this.canChangeColWidth); } this._cleanPagesModeData(); }; WorksheetView.prototype._reinitializeScroll = function () { this.handlers.trigger("reinitializeScroll", this.scrollType); this.scrollType = 0; }; WorksheetView.prototype._recalculate = function () { var ranges = this.arrRecalcRangesWithHeight.concat(this.arrRecalcRanges, this.model.hiddenManager.getRecalcHidden()); if (0 < ranges.length) { this.arrRecalcRanges = []; // ToDo refactoring this!!! this._calcHeightRows(AscCommonExcel.recalcType.newLines); this._calcWidthColumns(AscCommonExcel.recalcType.newLines); this._updateColsWidth(); this._updateVisibleColsCount(/*skipScrolReinit*/true); var minRow = this._updateRowsHeight(); this._updateVisibleRowsCount(/*skipScrolReinit*/true); this._updateSelectionNameAndInfo(); if (null !== minRow) { if (this.objectRender) { this.objectRender.updateDrawingsTransform({target: c_oTargetType.RowResize, row: minRow}); } } this.model.onUpdateRanges(ranges); var aRanges = []; var oBBox; for(var nRange = 0; nRange < ranges.length; ++nRange) { oBBox = ranges[nRange]; aRanges.push(new AscCommonExcel.Range(this.model, oBBox.r1, oBBox.c1, oBBox.r2, oBBox.c2)); } Asc.editor.wb.handleDrawingsOnWorkbookChange(aRanges); this.cellCommentator.updateActiveComment(); if (this._initRowsCount()) { this.scrollType |= AscCommonExcel.c_oAscScrollType.ScrollVertical; } if (this._initColsCount()) { this.scrollType |= AscCommonExcel.c_oAscScrollType.ScrollHorizontal; } this.handlers.trigger("onDocumentPlaceChanged"); } else { //for example, after change size we must recalculate drawings offset(right-to-left mode) //todo need review if (this.getRightToLeft() && this.objectRender) { this.objectRender.updateDrawingsTransform({target: c_oTargetType.RowResize, row: 0}); } } this._updateColumnPositions(); this._reinitializeScroll(); }; WorksheetView.prototype._updateDrawingArea = function () { if(this.workbook.Api.isEyedropperStarted()) { this.workbook.Api.clearEyedropperImgData(); } if (this.objectRender && this.objectRender.drawingArea) { this.objectRender.drawingArea.reinitRanges(); } }; WorksheetView.prototype.endEditChart = function () { if (this.isChartAreaEditMode) { this.isChartAreaEditMode = false; } this.oOtherRanges = null; }; WorksheetView.prototype.addAutoFilter = function (styleName, addFormatTableOptionsObj, range) { // Проверка глобального лока if (this.collaborativeEditing.getGlobalLock() || !window["Asc"]["editor"].canEdit()) { return; } if (!this.handlers.trigger("getLockDefNameManagerStatus")) { this.handlers.trigger("onErrorEvent", c_oAscError.ID.LockCreateDefName, c_oAscError.Level.NoCritical); return; } if (!window['AscCommonExcel'].filteringMode) { return; } var t = this; var ar = range ? range : this.model.selectionRange.getLast().clone(); var isChangeAutoFilterToTablePart = function (addFormatTableOptionsObj) { var res = false; var worksheet = t.model; var activeRange = AscCommonExcel.g_oRangeCache.getAscRange(addFormatTableOptionsObj.asc_getRange()); if (activeRange && worksheet.AutoFilter && activeRange.containsRange(worksheet.AutoFilter.Ref) && activeRange.r1 === worksheet.AutoFilter.Ref.r1) { res = true; } return res; }; var filterRange, bIsChangeFilterToTable, addNameColumn; var onChangeAutoFilterCallback = function (isSuccess) { if (false === isSuccess) { t.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.LockedAllError, c_oAscError.Level.NoCritical); t.handlers.trigger("selectionChanged"); return; } if (addFormatTableOptionsObj) { t.traceDependentsManager && t.traceDependentsManager.clearAll(); } let _prepareTextMetrics = function () { t._cleanCellsTextMetricsCache(); t.objectRender.bUpdateMetrics = false; t._prepareCellTextMetricsCache(); t.objectRender.bUpdateMetrics = true; }; var addFilterCallBack; if (bIsChangeFilterToTable)//CHANGE FILTER TO TABLEPART { addFilterCallBack = function (isSuccess) { if (false === isSuccess) { return; } History.Create_NewPoint(); History.StartTransaction(); t.model.autoFilters.changeAutoFilterToTablePart(styleName, ar, addFormatTableOptionsObj); _prepareTextMetrics(); t._updateRange(filterRange); t._autoFitColumnsWidth([new Asc.Range(filterRange.c1, filterRange.r1, filterRange.c2, filterRange.r1)], true); t.draw(); History.EndTransaction(); }; if(ar.containsRange(filterRange)) { filterRange = ar.clone(); } if (addNameColumn) { filterRange.r2 = filterRange.r2 + 1; } t._isLockedCells(filterRange, /*subType*/null, addFilterCallBack); } else//ADD { addFilterCallBack = function (isSuccess) { if (false === isSuccess) { return; } History.Create_NewPoint(); History.StartTransaction(); t.workbook.StartAction(AscDFH.historydescription_Spreadsheet_AddAutoFilter, {style: styleName, range: ar, info: filterInfo}); var type = ar.getType(); var isSlowOperation = false; if (c_oAscSelectionType.RangeMax === type || c_oAscSelectionType.RangeRow === type || c_oAscSelectionType.RangeCol === type) { isSlowOperation = null != styleName; } if (isSlowOperation) { t.handlers.trigger("slowOperation", true); } var slowOperationCallback = function() { //add to model t.model.autoFilters.addAutoFilter(styleName, ar, addFormatTableOptionsObj, null, null, filterInfo); //updates if (styleName && addNameColumn) { t.setSelection(filterRange); } //приходится принудительно запускать пересчёт перед функцией _onUpdateFormatTable //для грамотного отображения формул(#46170) //TODO пересчёт происходит два раза! в unlockRecal и EndTransaction. t.model.workbook.dependencyFormulas.unlockRecal(); if (styleName) { _prepareTextMetrics(); t._updateRange(filterRange); t._autoFitColumnsWidth([new Asc.Range(filterRange.c1, filterRange.r1, filterRange.c2, filterRange.r1)], true); } t.draw(); t.handlers.trigger("selectionChanged"); History.EndTransaction(); if (isSlowOperation) { t.handlers.trigger("slowOperation", false); } }; if(isSlowOperation) { window.setTimeout(function() { slowOperationCallback(); t.workbook.FinalizeAction(); }, 0); } else { slowOperationCallback(); t.workbook.FinalizeAction(); } }; if (styleName == null) { addFilterCallBack(true); } else { t._isLockedCells(filterRange, null, addFilterCallBack) } } }; //calculate filter range var filterInfo; if (addFormatTableOptionsObj && isChangeAutoFilterToTablePart(addFormatTableOptionsObj) === true) { filterRange = t.model.AutoFilter.Ref.clone(); addNameColumn = false; if (addFormatTableOptionsObj === false) { addNameColumn = true; } else if (typeof addFormatTableOptionsObj == 'object') { addNameColumn = !addFormatTableOptionsObj.asc_getIsTitle(); } bIsChangeFilterToTable = true; } else { if (styleName == null) { filterRange = ar && ar.isOneCell() ? ar.clone() : t.model.autoFilters.cutRangeByDefinedCells(ar); ar = filterRange; } else { filterInfo = t.model.autoFilters._getFilterInfoByAddTableProps(ar, addFormatTableOptionsObj, true); filterRange = filterInfo.filterRange; addNameColumn = filterInfo.addNameColumn; } } let isTable = !!styleName; var checkFilterRange = filterInfo ? filterInfo.rangeWithoutDiff : filterRange; if (t._checkAddAutoFilter(checkFilterRange, styleName, addFormatTableOptionsObj) === true) { this.model.workbook.handlers.trigger("cleanCutData", true, true); this.model.workbook.handlers.trigger("cleanCopyData", true); var _doAdd = function () { t._isLockedAll(onChangeAutoFilterCallback); t._isLockedDefNames(null, null); }; var oRange = this.model.getRange3(checkFilterRange.r1, checkFilterRange.c1, checkFilterRange.r1, checkFilterRange.c2); if (!addNameColumn && isTable && oRange.isFormulaContains()) { this.model.workbook.handlers.trigger("asc_onConfirmAction", Asc.c_oAscConfirm.ConfirmReplaceFormulaInTable, function (can) { if (can) { _doAdd(); } else { t.handlers.trigger("selectionChanged"); } }); } else { _doAdd(); } } else//для того, чтобы в случае ошибки кнопка отжималась! { t.handlers.trigger("selectionChanged"); } }; WorksheetView.prototype.changeAutoFilter = function (tableName, optionType, val, opt_callback) { // Проверка глобального лока if (this.collaborativeEditing.getGlobalLock() || !window["Asc"]["editor"].canEdit()) { if (opt_callback) { opt_callback(false); } return; } var t = this; var ar = this.model.selectionRange.getLast().clone(); //check user range protect var isChangeStyle = Asc.c_oAscChangeFilterOptions.style === optionType; var isTablePartsContainsRange = this.model.autoFilters._isTablePartsContainsRange(ar); var filterRange = null; if (isChangeStyle) { if (isTablePartsContainsRange !== null) { filterRange = isTablePartsContainsRange.Ref; } } else { if (!val) { if (isTablePartsContainsRange && isTablePartsContainsRange.Ref) { filterRange = isTablePartsContainsRange.Ref; } else if (this.model.AutoFilter) { filterRange = this.model.AutoFilter.Ref; } } else { var filterInfo = this.model.autoFilters._getFilterInfoByAddTableProps(ar); filterRange = filterInfo.filterRange; } } if (filterRange && this.model.isUserProtectedRangesIntersection(filterRange)) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ProtectedRangeByOtherUser, c_oAscError.Level.NoCritical); return; } var isProtectFilter = this.model.getSheetProtection(Asc.c_oAscSheetProtectType.autoFilter); var isProtectFormat = this.model.getSheetProtection(Asc.c_oAscSheetProtectType.formatCells); if (!window['AscCommonExcel'].filteringMode || (!isChangeStyle && isProtectFilter) || (isChangeStyle && isProtectFormat)) { if (opt_callback) { opt_callback(false); } return; } this.model.workbook.handlers.trigger("cleanCutData", true, true); this.model.workbook.handlers.trigger("cleanCopyData", true); var onChangeAutoFilterCallback = function (isSuccess) { if (false === isSuccess) { if (opt_callback) { opt_callback(false); } t.handlers.trigger("selectionChanged"); return; } switch (optionType) { case Asc.c_oAscChangeFilterOptions.filter: { //DELETE if (!val) { if (null === filterRange) { return; } filterRange = filterRange && filterRange.clone(); var deleteFilterCallBack = function (_success) { if (!_success) { return; } t.model.autoFilters.deleteAutoFilter(ar, tableName); t.af_drawButtons(filterRange); t._onUpdateFormatTable(filterRange); }; t._isLockedCells(filterRange, /*subType*/null, deleteFilterCallBack); } else//ADD ONLY FILTER { var addFilterCallBack = function (_success) { if (!_success) { if (opt_callback) { opt_callback(false); } return; } History.Create_NewPoint(); History.StartTransaction(); t.model.autoFilters.addAutoFilter(null, ar); History.EndTransaction(); t._onUpdateFormatTable(filterRange); if (opt_callback) { opt_callback(true); } }; t._isLockedCells(filterRange, null, addFilterCallBack) } break; } case Asc.c_oAscChangeFilterOptions.style://CHANGE STYLE { var changeStyleFilterCallBack = function (_success) { if (!_success) { return; } History.Create_NewPoint(); History.StartTransaction(); //TODO внутри вызывается _isTablePartsContainsRange t.model.autoFilters.changeTableStyleInfo(val, ar, tableName); History.EndTransaction(); t._updateRange(filterRange); t.draw(); }; filterRange = filterRange && filterRange.clone(); t._isLockedCells(filterRange, /*subType*/null, changeStyleFilterCallBack); break; } } }; if (isChangeStyle) { onChangeAutoFilterCallback(true); } else { this._isLockedAll(onChangeAutoFilterCallback); } }; WorksheetView.prototype.applyAutoFilter = function (autoFilterObject) { var isPivot = autoFilterObject && autoFilterObject.pivotObj; var checkProtectProp = isPivot ? Asc.c_oAscSheetProtectType.pivotTables : Asc.c_oAscSheetProtectType.autoFilter; if (this.model.getSheetProtection(checkProtectProp)) { return; } var t = this; var ar = this.model.selectionRange.getLast().clone(); //todo filteringMode //pivot var cellId = autoFilterObject.asc_getCellId(); if (cellId) { var cellRange = AscCommonExcel.g_oRangeCache.getAscRange(cellId); var pivotTable = !this.model.inTopAutoFilter(cellRange) && this.model.inPivotTable(cellRange); if (pivotTable) { pivotTable.asc_filterByCell(this.model.workbook.oApi, autoFilterObject, cellRange.r1, cellRange.c1); return; } } let filterRange = autoFilterObject && autoFilterObject.getFilterRef(this.model); if (filterRange && this.model.isUserProtectedRangesIntersection(filterRange)) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ProtectedRangeByOtherUser, c_oAscError.Level.NoCritical); return; } var nActive = t.model.getActiveNamedSheetViewId(); var onChangeAutoFilterCallback = function (isSuccess) { if (false === isSuccess && nActive === null) { t.model.workbook.slicersUpdateAfterChangeTable(autoFilterObject.displayName); t.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.LockedAllError, c_oAscError.Level.NoCritical); return; } var applyFilterProps = t.model.autoFilters.applyAutoFilter(autoFilterObject, ar); if (!applyFilterProps) { return false; } var minChangeRow = applyFilterProps.minChangeRow; var rangeOldFilter = applyFilterProps.rangeOldFilter; //если срез находится на одном листе, а таблица на другом //в данном случае пересчёт для ф/т нужен, а перерисовка не нужна var differentSheetApply = t.model.index !== t.workbook.model.nActive; if (null !== rangeOldFilter && !t.model.workbook.bUndoChanges && !t.model.workbook.bRedoChanges) { t.objectRender.bUpdateMetrics = false; t._onUpdateFormatTable(rangeOldFilter, differentSheetApply); t.objectRender.bUpdateMetrics = true; if (applyFilterProps.nOpenRowsCount !== applyFilterProps.nAllRowsCount) { t.handlers.trigger('onFilterInfo', applyFilterProps.nOpenRowsCount, applyFilterProps.nAllRowsCount); } } if (null !== minChangeRow) { t.objectRender.updateSizeDrawingObjects({target: c_oTargetType.RowResize, row: minChangeRow}); } }; if (!window['AscCommonExcel'].filteringMode && t.model.getActiveNamedSheetViewId() === null) { History.LocalChange = true; onChangeAutoFilterCallback(); History.LocalChange = false; } else { //лочу даже в режиме вью. для того чтобы избежать кофликтов - допустим, когда один пользователь сортирует //второй - фильтрует this._isLockedAll(onChangeAutoFilterCallback); } }; WorksheetView.prototype.reapplyAutoFilter = function (tableName) { var t = this; var ar = this.model.selectionRange.getLast().clone(); let filter = tableName ? this.model.getTableByName(tableName) : this.model.AutoFilter; if (filter && filter.Ref && this.model.isUserProtectedRangesIntersection(filter.Ref)) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ProtectedRangeByOtherUser, c_oAscError.Level.NoCritical); return; } var onChangeAutoFilterCallback = function (isSuccess) { if (false === isSuccess) { return; } //reApply History.Create_NewPoint(); History.StartTransaction(); if (tableName === null) { t.model.autoFilters.expandAutoFilter() } var applyFilterProps = t.model.autoFilters.reapplyAutoFilter(tableName, ar); //reSort var filter = applyFilterProps.filter; if (filter && filter.SortState && filter.SortState.SortConditions && filter.SortState.SortConditions[0]) { var sortState = filter.SortState; var rangeWithoutHeaderFooter = filter.getRangeWithoutHeaderFooter(); var sortRange = t.model.getRange3(rangeWithoutHeaderFooter.r1, rangeWithoutHeaderFooter.c1, rangeWithoutHeaderFooter.r2, rangeWithoutHeaderFooter.c2); var startCol = sortState.SortConditions[0].Ref.c1; var type; var rgbColor = null; switch (sortState.SortConditions[0].ConditionSortBy) { case Asc.ESortBy.sortbyCellColor: { type = Asc.c_oAscSortOptions.ByColorFill; rgbColor = sortState.SortConditions[0].dxf.fill.bg(); break; } case Asc.ESortBy.sortbyFontColor: { type = Asc.c_oAscSortOptions.ByColorFont; rgbColor = sortState.SortConditions[0].dxf.font.getColor(); break; } default: { type = Asc.c_oAscSortOptions.ByColorFont; if (sortState.SortConditions[0].ConditionDescending) { type = Asc.c_oAscSortOptions.Descending; } else { type = Asc.c_oAscSortOptions.Ascending; } } } var sort = t.model._doSort(sortRange, type, startCol, rgbColor, null, null, null, sortState); t.cellCommentator.sortComments(sort); } t.model.autoFilters._resetTablePartStyle(); History.EndTransaction(); var minChangeRow = applyFilterProps.minChangeRow; var updateRange = applyFilterProps.updateRange; if (updateRange && !t.model.workbook.bUndoChanges && !t.model.workbook.bRedoChanges) { t.objectRender.bUpdateMetrics = false; t._onUpdateFormatTable(updateRange); t.objectRender.bUpdateMetrics = true; } if (null !== minChangeRow) { t.objectRender.updateSizeDrawingObjects({target: c_oTargetType.RowResize, row: minChangeRow}); } }; if (!window['AscCommonExcel'].filteringMode && t.model.getActiveNamedSheetViewId() === null) { History.LocalChange = true; onChangeAutoFilterCallback(); History.LocalChange = false; } else { this._isLockedAll(onChangeAutoFilterCallback); } }; WorksheetView.prototype.applyAutoFilterByType = function (autoFilterObject) { if (this.model.getSheetProtection(Asc.c_oAscSheetProtectType.autoFilter)) { return; } var t = this; var activeCell = this.model.selectionRange.activeCell.clone(); var ar = this.model.selectionRange.getLast().clone(); let filterRange = autoFilterObject && autoFilterObject.getFilterRef(this.model, activeCell); if (filterRange && this.model.isUserProtectedRangesIntersection(filterRange)) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ProtectedRangeByOtherUser, c_oAscError.Level.NoCritical); return; } //нельзя применять если столбец, где находится активная ячейка, не определен if (!this.model.getColDataNoEmpty(activeCell.col)) { t.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.AutoFilterDataRangeError, c_oAscError.Level.NoCritical); return; } var isStartRangeIntoFilterOrTable = t.model.autoFilters.isStartRangeContainIntoTableOrFilter(activeCell); var isApplyAutoFilter = null, isAddAutoFilter = null, cellId = null, isFromatTable = null; if (null !== isStartRangeIntoFilterOrTable)//into autofilter or format table { isFromatTable = !(-1 === isStartRangeIntoFilterOrTable); var filterRef = isFromatTable ? t.model.TableParts[isStartRangeIntoFilterOrTable].Ref : t.model.AutoFilter.Ref; cellId = t.model.autoFilters._rangeToId(new Asc.Range(ar.c1, filterRef.r1, ar.c1, filterRef.r1)); isApplyAutoFilter = true; if (isFromatTable && !t.model.TableParts[isStartRangeIntoFilterOrTable].AutoFilter)//add autofilter to tablepart { isAddAutoFilter = true; } } else//without filter { isAddAutoFilter = true; isApplyAutoFilter = true; } var onChangeAutoFilterCallback = function (isSuccess) { if (false === isSuccess) { t.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.LockedAllError, c_oAscError.Level.NoCritical); return; } History.Create_NewPoint(); History.StartTransaction(); if (null !== isAddAutoFilter) { //delete old filter if (!isFromatTable && t.model.AutoFilter && t.model.AutoFilter.Ref) { t.model.autoFilters.isEmptyAutoFilters(t.model.AutoFilter.Ref); } //add new filter t.model.autoFilters.addAutoFilter(null, ar, null); //generate cellId if (null === cellId) { cellId = t.model.autoFilters._rangeToId( new Asc.Range(activeCell.col, t.model.AutoFilter.Ref.r1, activeCell.col, t.model.AutoFilter.Ref.r1)); } } if (null !== isApplyAutoFilter) { autoFilterObject.asc_setCellId(cellId); var filter = autoFilterObject.filter; if (c_oAscAutoFilterTypes.CustomFilters === filter.type) { t.model._getCell(activeCell.row, activeCell.col, function (cell) { filter.filter.CustomFilters[0].Val = cell.getValueWithoutFormat(); }); } else if (c_oAscAutoFilterTypes.ColorFilter === filter.type) { t.model._getCell(activeCell.row, activeCell.col, function (cell) { if (filter.filter && filter.filter.dxf && filter.filter.dxf.fill) { var xfs = cell.getCompiledStyleCustom(false, true, true); if (false === filter.filter.CellColor) { var fontColor = xfs && xfs.font ? xfs.font.getColor() : null; //TODO добавлять дефолтовый цвет шрифта в случае, если цвет шрифта не указан if (null !== fontColor) { filter.filter.dxf.fill.fromColor(fontColor); } } else { //TODO просмотерть ситуации без заливки var cellColor = null !== xfs && xfs.fill && xfs.fill.bg() ? xfs.fill.bg() : null; filter.filter.dxf.fill.fromColor(null !== cellColor ? new AscCommonExcel.RgbColor(cellColor.getRgb()) : null); } } }); } var applyFilterProps = t.model.autoFilters.applyAutoFilter(autoFilterObject, ar, true); if (!applyFilterProps) { History.EndTransaction(); return false; } var minChangeRow = applyFilterProps.minChangeRow; var rangeOldFilter = applyFilterProps.rangeOldFilter; History.EndTransaction(); if (null !== rangeOldFilter && !t.model.workbook.bUndoChanges && !t.model.workbook.bRedoChanges) { t.objectRender.bUpdateMetrics = false; t._onUpdateFormatTable(rangeOldFilter); t.objectRender.bUpdateMetrics = true; } if (null !== minChangeRow) { t.objectRender.updateSizeDrawingObjects({target: c_oTargetType.RowResize, row: minChangeRow}); } } else { History.EndTransaction(); } }; if (null === isAddAutoFilter)//do not add autoFilter { var api = window["Asc"]["editor"]; if (!window['AscCommonExcel'].filteringMode && t.model.getActiveNamedSheetViewId() === null) { History.LocalChange = true; onChangeAutoFilterCallback(); History.LocalChange = false; } else { var activeId = t.model.getActiveNamedSheetViewId(); if (null !== activeId) { //api._isLockedNamedSheetView([t.model.aNamedSheetViews[nActive]], function (_success) { onChangeAutoFilterCallback(true); //}); } else { this._isLockedAll(onChangeAutoFilterCallback); } } } else//add autofilter + apply { if (!window['AscCommonExcel'].filteringMode) { return; } if (t._checkAddAutoFilter(ar, null, autoFilterObject, true) === true) { this._isLockedAll(onChangeAutoFilterCallback); this._isLockedDefNames(null, null); } } }; WorksheetView.prototype.sortRange = function (type, cellId, displayName, color, bIsExpandRange) { var t = this; var ar = this.model.selectionRange.getLast().clone(); if (!window['AscCommonExcel'].filteringMode) { return; } //pivot var activeRangeOrCellId = ar; var activeCellOrCellId = this.model.selectionRange.activeCell; if (cellId && typeof cellId == 'string') { activeRangeOrCellId = AscCommonExcel.g_oRangeCache.getAscRange(cellId); activeCellOrCellId = new AscCommon.CellBase(activeRangeOrCellId.r1, activeRangeOrCellId.c1); } //TODO проверка защиты var pivotTable = this.model.inPivotTable(activeRangeOrCellId); if (pivotTable) { if (pivotTable.location && pivotTable.location.ref && this.model.isUserProtectedRangesIntersection(pivotTable.location.ref)) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ProtectedRangeByOtherUser, c_oAscError.Level.NoCritical); return; } if (this.model.getSheetProtection(Asc.c_oAscSheetProtectType.pivotTables)) { return; } pivotTable.asc_sortByCell(t.model.workbook.oApi, type, activeCellOrCellId.row, activeCellOrCellId.col); return; } if (this.model.getSheetProtection(Asc.c_oAscSheetProtectType.sort)) { return; } //autoFilters var sortProps = t.model.autoFilters.getPropForSort(cellId, ar, displayName); var cloneSortProps = sortProps; var isFilter = sortProps && sortProps.curFilter && sortProps.curFilter.isAutoFilter(); var filterRef; if(bIsExpandRange && isFilter) { //в случае расширения диапазона если мы находимся внутри а/ф игнорируются наcтройки filterRef = sortProps.curFilter.Ref; sortProps = null; } var expandRange; var selectionRange = t.model.selectionRange; var activeCell = selectionRange.activeCell.clone(); var activeRange = selectionRange.getLast(); if (null === sortProps) { //expand selectionRange if (bIsExpandRange) { expandRange = t.model.autoFilters.expandRange(activeRange); expandRange = t.model.autoFilters.checkExpandRangeForSort(expandRange); var bIgnoreFirstRow = window['AscCommonExcel'].ignoreFirstRowSort(t.model, expandRange); if (bIgnoreFirstRow) { expandRange.r1++; } else if(expandRange && filterRef && filterRef.containsRange(expandRange) && expandRange.r1 === filterRef.r1) { sortProps = cloneSortProps; } } } var onChangeAutoFilterCallback = function (isSuccess) { if (false === isSuccess) { t.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.LockedAllError, c_oAscError.Level.NoCritical); return; } var onSortAutoFilterCallBack = function (success) { if (false === success) { return; } History.Create_NewPoint(); History.StartTransaction(); var rgbColor = color ? new AscCommonExcel.RgbColor((color.asc_getR() << 16) + (color.asc_getG() << 8) + color.asc_getB()) : null; var sort = t.model._doSort(sortProps.sortRange, type, sortProps.startCol, rgbColor); t.cellCommentator.sortComments(sort); t.model.autoFilters.sortColFilter(type, cellId, ar, sortProps, displayName, rgbColor); History.EndTransaction(); t._onUpdateFormatTable(sortProps.sortRange.bbox); t.objectRender.updateSizeDrawingObjects({target: c_oTargetType.RowResize, row: sortProps.sortRange.bbox.r1}); }; if (null === sortProps) { var rgbColor = color ? new AscCommonExcel.RgbColor((color.asc_getR() << 16) + (color.asc_getG() << 8) + color.asc_getB()) : null; //expand selectionRange if(bIsExpandRange && expandRange) { //change selection t.setSelection(expandRange); selectionRange.activeCell = activeCell; } //sort t.setSelectionInfo("sort", {type: type, color: rgbColor}); //TODO возможно стоит возвратить selection обратно } else if (false !== sortProps) { t._isLockedCells(sortProps.sortRange.bbox, /*subType*/null, onSortAutoFilterCallBack); } }; var doSortRange = sortProps ? sortProps.sortRange.bbox : expandRange; if (!doSortRange) { doSortRange = activeRange; } if (doSortRange && this.model.isUserProtectedRangesIntersection(doSortRange)) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ProtectedRangeByOtherUser, c_oAscError.Level.NoCritical); return; } if (this.model.getSheetProtection(Asc.c_oAscSheetProtectType.sort)) { return; } this.checkProtectRangeOnEdit([doSortRange], function (success) { if (success) { if (t.model.inPivotTable(doSortRange)) { t.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.LockedCellPivot, c_oAscError.Level.NoCritical); return; } if(!t.intersectionFormulaArray(doSortRange, true)) { t._isLockedAll(onChangeAutoFilterCallback); } else { t.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.CannotChangeFormulaArray, c_oAscError.Level.NoCritical); } } }) }; WorksheetView.prototype.getAddFormatTableOptions = function (range, isPivot) { //TODO обработать в интерфейсе null if (this.model.getSheetProtection()) { return null; } var selectionRange = this.model.selectionRange.getLast(); //TODO возможно стоит перенести getAddFormatTableOptions во view return this.model.autoFilters.getAddFormatTableOptions(selectionRange, range, isPivot); }; WorksheetView.prototype.clearFilter = function () { var t = this; var ar = this.model.selectionRange.getLast().clone(); //pivot if (Asc.CT_pivotTableDefinition.prototype.asc_removeFilters) { var pivotTable = this.model.inPivotTable(ar); if (pivotTable) { pivotTable.asc_removeFilters(this.model.workbook.oApi); return; } } //в особом режиме не лочим лист при фильтрации var nActive = t.model.getActiveNamedSheetViewId(); var onChangeAutoFilterCallback = function (isSuccess) { if (false === isSuccess && null === nActive) { return; } let _doApply = function () { var updateRange = t.model.autoFilters.isApplyAutoFilterInCell(ar, true); if (false !== updateRange) { t._onUpdateFormatTable(updateRange); t.objectRender.updateSizeDrawingObjects({target: c_oTargetType.RowResize, row: updateRange.r1}); t._updateSlicers(updateRange); } }; if (t.model.getActiveNamedSheetViewId() !== null) { _doApply(); } else { AscCommonExcel.checkFilteringMode(_doApply); } }; this._isLockedAll(onChangeAutoFilterCallback); }; WorksheetView.prototype.clearFilterColumn = function (cellId, displayName) { var t = this; //pivot if (Asc.CT_pivotTableDefinition.prototype.asc_removeFilterByCell) { if (cellId) { var cellRange = AscCommonExcel.g_oRangeCache.getAscRange(cellId); var pivotTable = this.model.inPivotTable(cellRange); if (pivotTable) { pivotTable.asc_removeFilterByCell(this.model.workbook.oApi, cellRange.r1, cellRange.c1); return; } } } //в особом режиме не лочим лист при фильтрации var nActive = t.model.getActiveNamedSheetViewId(); var onChangeAutoFilterCallback = function (isSuccess) { if (false === isSuccess && nActive === null) { t.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.LockedAllError, c_oAscError.Level.NoCritical); return; } let _doApply = function () { var updateRange = t.model.autoFilters.clearFilterColumn(cellId, displayName); if (false !== updateRange) { t._onUpdateFormatTable(updateRange); t.objectRender.updateSizeDrawingObjects({target: c_oTargetType.RowResize, row: updateRange.r1}); t._updateSlicers(updateRange); } } if (t.model.getActiveNamedSheetViewId() !== null) { _doApply(); } else { AscCommonExcel.checkFilteringMode(_doApply); } }; this._isLockedAll(onChangeAutoFilterCallback); }; /** * Обновление при изменениях форматированной таблицы * @param range - обновляемый диапазон (он же диапазон для выделения * @private */ WorksheetView.prototype._onUpdateFormatTable = function (range, lockDraw) { // ToDo сделать правильное обновление при скрытии/раскрытии строк/столбцов this._initCellsArea(AscCommonExcel.recalcType.full); this.cache.reset(); this._cleanCellsTextMetricsCache(); this._prepareCellTextMetricsCache(); this._updateDrawingArea(); var arrChanged = [new asc_Range(range.c1, 0, range.c2, gc_nMaxRow0)]; this.model.onUpdateRanges(arrChanged); var aRanges = []; var oBBox; for(var nRange = 0; nRange < arrChanged.length; ++nRange) { oBBox = arrChanged[nRange]; aRanges.push(new AscCommonExcel.Range(this.model, oBBox.r1, oBBox.c1, oBBox.r2, oBBox.c2)); } Asc.editor.wb.handleDrawingsOnWorkbookChange(aRanges); this.scrollType |= AscCommonExcel.c_oAscScrollType.ScrollVertical | AscCommonExcel.c_oAscScrollType.ScrollHorizontal; this.draw(lockDraw); this._updateSelectionNameAndInfo(); }; WorksheetView.prototype._loadFonts = function (fonts, callback) { var api = window["Asc"]["editor"]; api._loadFonts(fonts, callback); }; WorksheetView.prototype.setData = function (oData) { History.Clear(); History.TurnOff(); var oAllRange = this.model.getRange3(0, 0, this.model.getRowsCount(), this.model.getColsCount()); oAllRange.cleanAll(); var row, oCell; for (var r = 0; r < oData.length; ++r) { row = oData[r]; for (var c = 0; c < row.length; ++c) { if (row[c]) { oCell = this._getVisibleCell(c, r); oCell.setValue(row[c]); } } } History.TurnOn(); this._updateRange(oAllRange.bbox); // ToDo Стоит обновить nRowsCount и nColsCount this.draw(); }; WorksheetView.prototype.getData = function () { var arrResult, arrCells = [], c, r, row, lastC = -1, lastR = -1, val; var maxCols = Math.min(this.model.getColsCount(), gc_nMaxCol); var maxRows = Math.min(this.model.getRowsCount(), gc_nMaxRow); for (r = 0; r < maxRows; ++r) { row = []; for (c = 0; c < maxCols; ++c) { this.model._getCellNoEmpty(r, c, function(cell) { if (cell && '' !== (val = cell.getValue())) { lastC = Math.max(lastC, c); lastR = Math.max(lastR, r); } else { val = ''; } }); row.push(val); } arrCells.push(row); } arrResult = arrCells.slice(0, lastR + 1); ++lastC; if (lastC < maxCols) { for (r = 0; r < arrResult.length; ++r) { arrResult[r] = arrResult[r].slice(0, lastC); } } return arrResult; }; WorksheetView.prototype._getFilterButtonSize = function (collapsePivot) { return AscCommon.AscBrowser.convertToRetinaValue(!collapsePivot ? filterSizeButton : collapsePivotSizeButton, true); }; WorksheetView.prototype.getButtonSize = function (row, col, isDataValidation) { var colWidth = this._getColumnWidth(col); var rowHeight = this._getRowHeight(row); var _notChangeScaleWidth = isDataValidation && col !== AscCommon.gc_nMaxCol0; var width, height, index; width = height = this._getFilterButtonSize(); if (colWidth < width && rowHeight < height && !_notChangeScaleWidth) { if (rowHeight < colWidth) { index = rowHeight / height; width = width * index; height = rowHeight; } else { index = colWidth / width; width = colWidth; height = height * index; } } else if (colWidth < width && !_notChangeScaleWidth) { index = colWidth / width; width = colWidth; height = height * index; } else if (rowHeight < height) { index = rowHeight / height; width = width * index; height = rowHeight; } return {w: width, h: height}; }; WorksheetView.prototype.af_drawButtons = function (updatedRange, offsetX, offsetY) { var i, ws = this.model; var t = this; if (ws.workbook.bUndoChanges || ws.workbook.bRedoChanges) { return false; } offsetX -= this.getRightToLeftOffset(); var drawCurrentFilterButtons = function (filter) { var autoFilter = filter.isAutoFilter() ? filter : filter.AutoFilter; if (!filter.Ref) { return; } var range = new Asc.Range(filter.Ref.c1, filter.Ref.r1, filter.Ref.c2, filter.Ref.r1); if (range.isIntersect(updatedRange)) { var row = range.r1; //TODO sheet view var sortConditions = filter.isApplySortConditions() ? filter.SortState.SortConditions : null; for (var col = range.c1; col <= range.c2; col++) { if (col >= updatedRange.c1 && col <= updatedRange.c2) { var isSetFilter = false; var isShowButton = true; var isSortState = null;//true - ascending, false - descending var i; var colId = filter.isAutoFilter() ? t.model.autoFilters._getTrueColId(autoFilter, col - range.c1, true) : col - range.c1; var filterColumns = t.model.getNamedSheetViewFilterColumns(filter.DisplayName); var viewSheetMode = false; if (!filterColumns) { filterColumns = autoFilter.FilterColumns; } else { viewSheetMode = true; } if (filterColumns && filterColumns.length) { var filterColumn = null, filterColumnWithMerge = null; for (i = 0; i < filterColumns.length; i++) { var _filterColumn = viewSheetMode ? filterColumns[i].filter : filterColumns[i]; if (_filterColumn.ColId === col - range.c1) { filterColumn = _filterColumn; } if (colId === col - range.c1 && filterColumn !== null) { filterColumnWithMerge = filterColumn; break; } else if (_filterColumn.ColId === colId) { filterColumnWithMerge = _filterColumn; } } if (filterColumnWithMerge && filterColumnWithMerge.isApplyAutoFilter()) { isSetFilter = true; } if (filterColumn && filterColumn.ShowButton === false) { isShowButton = false; } } if (sortConditions && sortConditions.length) { for (i = 0; i < sortConditions.length; i++) { var sortCondition = sortConditions[i]; if (colId === sortCondition.Ref.c1 - range.c1) { isSortState = !!(sortCondition.ConditionDescending); } } } if (isShowButton === false) { continue; } t.af_drawCurrentButton(offsetX - t.getRightToLeftOffset(), offsetY, {isSortState: isSortState, isSetFilter: isSetFilter, row: row, col: col}); } } } }; var pivotButtons = this.model.getPivotTableButtons(updatedRange); for (i = 0; i < pivotButtons.length; ++i) { this.af_drawCurrentButton(offsetX, offsetY, pivotButtons[i]); } if (ws.AutoFilter) { drawCurrentFilterButtons(ws.AutoFilter); } if (ws.TableParts && ws.TableParts.length) { for (i = 0; i < ws.TableParts.length; i++) { if (ws.TableParts[i].AutoFilter && ws.TableParts[i].HeaderRowCount !== 0) { drawCurrentFilterButtons(ws.TableParts[i], true); } if (!ws.getSheetProtection()) { this._drawRightDownTableCorner(ws.TableParts[i], updatedRange, offsetX, offsetY); } } } return true; }; WorksheetView.prototype.drawOverlayButtons = function (visibleRange, offsetX, offsetY) { let viewMode = !this.workbook.canEdit(); if (viewMode) { return; } var activeCell = this.model.getSelection().activeCell; if (visibleRange.contains2(activeCell)) { var dataValidation = this.model.getDataValidation(activeCell.col, activeCell.row); var isDataValidationList = dataValidation && dataValidation.isListValues(); var merged; if (isDataValidationList) { merged = this.model.getMergedByCell(activeCell.row, activeCell.col); } if (isDataValidationList || this.model.isTableTotal(activeCell.col, activeCell.row)) { this.af_drawCurrentButton(offsetX, offsetY, { isOverlay: true, isSortState: null, isSetFilter: false, row: isDataValidationList && merged ? merged.r1 : activeCell.row, col: isDataValidationList && merged ? merged.c2 : activeCell.col }); } return false; } return true; }; WorksheetView.prototype.af_drawCurrentButton = function (offsetX, offsetY, props) { var t = this; var ctx = props.isOverlay ? this.overlayCtx : this.drawingCtx; var isDataValidation = props.isOverlay; let isClip = null; if (!isDataValidation && this._clipDrawingRect(ctx, new Asc.Range(props.col, props.row, props.col, props.row), clipType.range)) { isClip = true; } if (props.idPivotCollapse) { this._drawPivotCollapseButton(offsetX, offsetY, props); if (isClip) { this._RemoveClipRect(ctx); } return; } var isMobileRetina = false; var isPivotCollapsed = false; //TODO пересмотреть масштабирование!!! var isApplyAutoFilter = props.isSetFilter; var isApplySortState = props.isSortState; var row = props.row; var col = props.col; var widthButtonPx, heightButtonPx; widthButtonPx = heightButtonPx = this._getFilterButtonSize(isPivotCollapsed); var widthBorder = 1; var scaleIndex = 1; var m_oColor = new CColor(120, 120, 120); var widthWithBorders = widthButtonPx; var heightWithBorders = heightButtonPx; var width = widthButtonPx - widthBorder * 2; var height = heightButtonPx - widthBorder * 2; var colWidth = t._getColumnWidth(col); var rowHeight = t._getRowHeight(row); if (rowHeight < heightWithBorders) { widthWithBorders = widthWithBorders * (rowHeight / heightWithBorders); heightWithBorders = rowHeight; } //стартовая позиция кнопки var x1; if (isDataValidation) { var _maxColDiff = col === AscCommon.gc_nMaxCol0 ? widthWithBorders - widthBorder : 0; x1 = t._getColLeft(col + 1) - _maxColDiff - 0.5 - offsetX; } else { x1 = t._getColLeft(col + 1) - widthWithBorders - 0.5 - offsetX; } //-1 смещение относительно нижней границы ячейки на 1px var y1 = t._getRowTop(row + 1) - heightWithBorders - 0.5 - offsetY - 1; var _drawButtonFrame = function (startX, startY, width, height) { //TODO нужен цвет для заливки ctx.setFillStyle(isPivotCollapsed ? new CColor(227, 228, 228) : t.settings.cells.defaultState.background); ctx.setLineWidth(1); ctx.setStrokeStyle(t.settings.cells.defaultState.border); var _diff = isPivotCollapsed ? 1 : 0; t._fillRect(ctx, startX + _diff, startY + _diff, width - _diff, height - _diff); if (isPivotCollapsed) { ctx.beginPath(); t._lineHor(ctx, startX + _diff, startY, startX + width); t._lineHor(ctx, startX + _diff, startY + height, startX + width); t._lineVer(ctx, startX, startY + _diff, startY + height); t._lineVer(ctx, startX + width, startY + _diff, startY + height); ctx.stroke(); } else { t._strokeRect(ctx, startX, startY, width, height); } }; var _drawSortArrow = function (startX, startY, isDescending, heightArrow) { //isDescending = true - стрелочка смотрит вниз //рисуем сверху вниз ctx.beginPath(); t._lineVer(ctx, startX, startY, startY + heightArrow * scaleIndex); var tmp; var x = startX; var y = startY; var heightArrow1 = heightArrow * scaleIndex; var height = 3 * scaleIndex; var x1, x2, y1, i; if (isDescending) { for (i = 0; i < height; i++) { tmp = i; x1 = x - tmp; x2 = x - tmp + 1; y1 = y - tmp + heightArrow1 - 1; t._lineHor(ctx, x1, y1, x2); x1 = x + tmp; x2 = x + tmp + 1; y1 = y - tmp + heightArrow1 - 1; t._lineHor(ctx, x1, y1, x2); } } else { for (i = 0; i < height; i++) { tmp = i; x1 = x - tmp; x2 = x - tmp + 1; y1 = y + tmp; t._lineHor(ctx, x1, y1, x2); x1 = x + tmp; x2 = x + tmp + 1; y1 = y + tmp; t._lineHor(ctx, x1, y1, x2); } } if (isMobileRetina) { ctx.setLineWidth(t.getRetinaPixelRatio() * 2); } else { ctx.setLineWidth(t.getRetinaPixelRatio()); } ctx.setStrokeStyle(m_oColor); ctx.stroke(); }; var _drawFilterMark = function (x, y, height) { var heightLine = Math.round(height); var heightCleanLine = heightLine - 2; ctx.beginPath(); t._moveTo(ctx, x, y); t._lineTo(ctx, x, y - heightCleanLine); ctx.setLineWidth(2 * t.getRetinaPixelRatio() * (isMobileRetina ? 2 : 1)); ctx.setStrokeStyle(m_oColor); ctx.stroke(); var heightTriangle = 4; y = y - heightLine + 1; _drawFilterDreieck(x, y, heightTriangle, 2); }; var _drawFilterDreieck = function (x, y, height, base) { ctx.beginPath(); if (isMobileRetina) { ctx.setLineWidth(t.getRetinaPixelRatio() * 2); } else { ctx.setLineWidth(t.getRetinaPixelRatio()); } x = x + 1; var diffY = (height / 2); height = height * scaleIndex; for (var i = 0; i < height; i++) { t._lineHor(ctx, x - (i + base), y + (height - i) - diffY, x + i) } ctx.setStrokeStyle(m_oColor); ctx.stroke(); }; //TODO пересмотреть отрисовку кнопок + отрисовку при масштабировании var _drawButton = function (upLeftXButton, upLeftYButton) { //квадрат кнопки рисуем _drawButtonFrame(upLeftXButton, upLeftYButton, width, height); //координаты центра var centerX = upLeftXButton + (width / 2); var centerY = upLeftYButton + (height / 2); var heigthObj, marginTop; if (null !== isApplySortState && isApplyAutoFilter) { heigthObj = Math.ceil(height / 2) + 2; marginTop = Math.floor((height - heigthObj) / 2); centerY = upLeftYButton + heigthObj + marginTop; _drawSortArrow(upLeftXButton + 4 * scaleIndex, upLeftYButton + 5 * scaleIndex, isApplySortState, 8); _drawFilterMark(centerX + 3, centerY, heigthObj); } else if (null !== isApplySortState) { _drawSortArrow(upLeftXButton + width - 5 * scaleIndex, upLeftYButton + 3 * scaleIndex, isApplySortState, 10); _drawFilterDreieck(centerX - 3, centerY + 1, 3, 1); } else if (isApplyAutoFilter) { heigthObj = Math.ceil(height / 2) + 2; marginTop = Math.floor((height - heigthObj) / 2); centerY = upLeftYButton + heigthObj + marginTop; _drawFilterMark(centerX + 1, centerY, heigthObj); } else if (isPivotCollapsed) { } else { _drawFilterDreieck(centerX, centerY, 4, 1); } }; //TODO!!! некорректно рисуется кнопка при уменьшении масштаба и уменьшении размера строки var _notChangeScaleWidth = isDataValidation && col !== AscCommon.gc_nMaxCol0; var diffX = 0; var diffY = 0; if ((colWidth - 2) < width && rowHeight < (height + 2) && !_notChangeScaleWidth) { if (rowHeight < colWidth) { scaleIndex = rowHeight / height; width = width * scaleIndex; height = rowHeight; } else { scaleIndex = colWidth / width; diffY = width - colWidth; diffX = width - colWidth; width = colWidth; height = height * scaleIndex; } } else if ((colWidth - 2) < width && !_notChangeScaleWidth) { scaleIndex = colWidth / width; //смещения по x и y diffY = width - colWidth; diffX = width - colWidth + 2; width = colWidth; height = height * scaleIndex; } else if ((rowHeight - widthBorder * 2) < height) { scaleIndex = rowHeight / (height + widthBorder * 2); width = width * scaleIndex; height = rowHeight - widthBorder * 2; } if (window['IS_NATIVE_EDITOR']) { isMobileRetina = true; } scaleIndex *= this.getRetinaPixelRatio(); _drawButton(x1 + diffX, y1 + diffY); if (isClip) { this._RemoveClipRect(ctx); } }; WorksheetView.prototype._drawPivotCollapseButton = function (offsetX, offsetY, props) { var ctx = props.isOverlay ? this.overlayCtx : this.drawingCtx; var buttonProps = this._getPropsCollapseButton(offsetX, offsetY, props); if (buttonProps) { var img = props.idPivotCollapse.hidden ? null : (props.idPivotCollapse.sd ? pivotCollapseButtonOpen : pivotCollapseButtonClose); if (!img) { return; } var width = buttonProps.w; var height = buttonProps.h; var startX = buttonProps.x; var startY = buttonProps.y; var iconSize = buttonProps.size; var rect = new AscCommon.asc_CRect(startX, startY, width, height); var graphics = (ctx && ctx.DocumentRenderer) || this.handlers.trigger('getMainGraphics'); var dScale = asc_getcvt(0, 3, this._getPPIX()); rect._x *= dScale; rect._y *= dScale; rect._width *= dScale; rect._height *= dScale; AscFormat.ExecuteNoHistory( function (img, rect, imgSize) { var geometry = new AscFormat.CreateGeometry("rect"); geometry.Recalculate(imgSize, imgSize, true); var oUniFill = new AscFormat.builder_CreateBlipFill(img, "stretch"); graphics.SaveGrState(); var oMatrix = new AscCommon.CMatrix(); oMatrix.tx = rect._x; oMatrix.ty = rect._y; graphics.transform3(oMatrix); var shapeDrawer = new AscCommon.CShapeDrawer(); shapeDrawer.Graphics = graphics; shapeDrawer.fromShape2(new AscFormat.CColorObj(null, oUniFill, geometry), graphics, geometry); shapeDrawer.draw(geometry); graphics.RestoreGrState(); }, this, [img, rect, iconSize * dScale * this.getZoom()] ); } }; WorksheetView.prototype._getPropsCollapseButton = function (offsetX, offsetY, props) { var row = props.row; var col = props.col; var ct = this._getCellTextCache(col, row); if (!ct) { return null; } var c = this._getVisibleCell(col, row); var isMerged = ct.flags.isMerged(), range, isWrapped = ct.flags.wrapText; if (isMerged) { range = ct.flags.merged; } var colL = isMerged ? range.c1 : Math.max(col, col - ct.sideL); var colR = isMerged ? Math.min(range.c2, this.nColsCount - 1) : Math.min(col, col + ct.sideR); var rowT = isMerged ? range.r1 : row; var rowB = isMerged ? Math.min(range.r2, this.nRowsCount - 1) : row; var isTrimmedR = !isMerged && colR !== col + ct.sideR; var x1 = this._getColLeft(colL) - offsetX; var y1 = this._getRowTop(rowT) - offsetY; var w = this._getColLeft(colR + 1) - offsetX - x1; var h = this._getRowTop(rowB + 1) - offsetY - y1; var x2 = x1 + w - (isTrimmedR ? 0 : gridlineSize); var y2 = y1 + h; var bl = y2 - Asc.round((isMerged ? (ct.metrics.height - ct.metrics.baseline) : this._getRowDescender(rowB)) * this.getZoom()); var x1ct = isMerged ? x1 : this._getColLeft(col) - offsetX; var x2ct = isMerged ? x2 : x1ct + this._getColumnWidth(col) - gridlineSize; var textX = this._calcTextHorizPos(x1ct, x2ct, ct.metrics, /*ct.cellHA*/AscCommon.align_Left); var textY = this._calcTextVertPos(y1, h, bl, ct.metrics, ct.cellVA); //var textW = this._calcTextWidth(x1ct, x2ct, ct.metrics, ct.cellHA); //TODO пока решили не учитывать позицию текста. кнопка всегда прижата к левому краю. учитывается только левый индент var fontSize = c.getFont().getSize(); var cfIterator = this.model.getConditionalFormattingRangeIterator(); var align = c.getAlign(); var cellHA = align.getAlignHorizontal(); if (this._getCellCF(cfIterator, c, row, col, Asc.ECfType.iconSet) /*&& AscCommon.align_Left === cellHA*/) { textX += AscCommon.AscBrowser.convertToRetinaValue(getCFIconSize(fontSize) * this.getZoom(), true); } var indent = align.getIndent(); if (indent) { /*if (AscCommon.align_Right === cellHA) { x -= indent * 3 * this.defaultSpaceWidth; } else*/ if (AscCommon.align_Left === cellHA) { textX += indent * 3 * this.defaultSpaceWidth; } } var iconSize = this._getFilterButtonSize(true); //TODO 2? textX += 2 * this.getZoom(); textY += (ct.metrics.height / 2 - iconSize / 2) * this.getZoom(); return {size: iconSize, x: textX, y: textY, w: iconSize, h: iconSize}; }; WorksheetView.prototype._drawRightDownTableCorner = function (table, updatedRange, offsetX, offsetY) { var t = this; var ctx = t.drawingCtx; var retinaKoef = this.getRetinaPixelRatio(); var row = table.Ref.r2; var col = table.Ref.c2; if (!updatedRange.contains(col, row)) { return; } var m_oColor = new CColor(72, 93, 177); var zoom = t.getZoom(); var baseLw = 2; var baseLnSize = 4; var lnW = Math.round(baseLw * zoom * retinaKoef); //смотрим насколько изменилась толщина линиии - настолько и изменился масштаб var kF = lnW / baseLw; var lnSize = baseLnSize * kF; var x1 = t._getColLeft(col) + t._getColumnWidth(col) - offsetX - 2; var y1 = t._getRowTop(row) + t._getRowHeight(row) - offsetY - 2; ctx.setLineWidth(lnW); var diff = Math.floor((lnW - 1) / 2); ctx.beginPath(); t._lineVer(ctx, x1 - diff, y1 + 1, y1 - lnSize + 1); t._lineHor(ctx, x1 + 1, y1 - diff, x1 - lnSize + 1); ctx.setStrokeStyle(m_oColor); ctx.stroke(); }; WorksheetView.prototype.af_checkCursor = function (x, y, r, c) { var aWs = this.model; var t = this; var result = null; var _isShowButtonInFilter = function (col, filter) { var result = true; var autoFilter = filter.isAutoFilter() ? filter : filter.AutoFilter; if (filter.HeaderRowCount === 0) { result = null; } else if (autoFilter && autoFilter.FilterColumns)//проверяем скрытые ячейки { var colId = col - autoFilter.Ref.c1; for (var i = 0; i < autoFilter.FilterColumns.length; i++) { if (autoFilter.FilterColumns[i].ColId === colId) { if (autoFilter.FilterColumns[i].ShowButton === false) { result = null; } break; } } } else if (!filter.isAutoFilter() && autoFilter === null)//если форматированная таблица и отсутсвует а/ф { result = null; } return result; }; var checkCurrentFilter = function (filter, num) { var range = new Asc.Range(filter.Ref.c1, filter.Ref.r1, filter.Ref.c2, filter.Ref.r1); if (range.contains(c, r) && _isShowButtonInFilter(c, filter)) { var row = range.r1; for (var col = range.c1; col <= range.c2; col++) { if (col === c) { if (t._hitCursorFilterButton(x, y, col, row)) { result = {cursor: kCurAutoFilter, target: c_oTargetType.FilterObject, col: -1, row: -1, idFilter: {id: num, colId: col - range.c1}}; break; } } } } else if (!filter.isAutoFilter() && filter.isTotalsRow() && filter.Ref.r2 === r && c >= filter.Ref.c1 + 1 && c <= filter.Ref.c2 + 1) { if (t._hitCursorFilterButton(x, y, c, r, true)) { result = {cursor: kCurAutoFilter, target: c_oTargetType.FilterObject, col: -1, row: -1, idFilter: {id: num, colId: col - range.c1}}; } } }; if (aWs.AutoFilter && aWs.AutoFilter.Ref) { checkCurrentFilter(aWs.AutoFilter, null); } if (aWs.TableParts && aWs.TableParts.length && !result) { for (var i = 0; i < aWs.TableParts.length; i++) { if (aWs.TableParts[i].AutoFilter) { checkCurrentFilter(aWs.TableParts[i], i); } } } return result; }; WorksheetView.prototype._hitCursorFilterButton = function (x, y, col, row, isDataValidation, pivotCollapse) { var buttonSize = this.getButtonSize(row, col, isDataValidation); var width = buttonSize.w, height = buttonSize.h; var top, left, x1, y1, x2, y2; top = this._getRowTop(row + 1); left = this._getColLeft(col + 1); y1 = top - height - 0.5; y2 = top - 0.5; if (isDataValidation && col !== AscCommon.gc_nMaxCol0) { x1 = left + 0.5; x2 = left + width + 0.5; } else if (pivotCollapse && !pivotCollapse.hidden) { var zoom = this.getZoom(); var buttonProps = this._getPropsCollapseButton(0, 0, {row: row, col: col}); if (buttonProps) { x1 = buttonProps.x; x2 = buttonProps.x + buttonProps.w * zoom; y1 = buttonProps.y; y2 = buttonProps.y + buttonProps.h * zoom; } } else { x1 = left - width - 0.5; x2 = left - 0.5; } return (x >= x1 && x <= x2 && y >= y1 && y <= y2); }; WorksheetView.prototype._checkAddAutoFilter = function (activeRange, styleName, oTableProps, filterByCellContextMenu) { if (this.model.isUserProtectedRangesIntersection(activeRange)) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ProtectedRangeByOtherUser, c_oAscError.Level.NoCritical); return false; } if (this.model.getSheetProtection(Asc.c_oAscSheetProtectType.autoFilter)) { return; } //write error, if not add autoFilter and return false var result = true; var worksheet = this.model; var filter = worksheet.AutoFilter; var _isOneCell = function(_range) { var res = null; if (_range.isOneCell()) { res = true; } else { var merged = worksheet.getMergedByCell(_range.r1, _range.c1); if(merged && merged.isEqual(_range)) { res = true; } } return res; }; var fullRange = activeRange; if((styleName && oTableProps) && (!oTableProps.isTitle || activeRange.r1 === activeRange.r2)) { fullRange = new Asc.Range(activeRange.c1, activeRange.r1, activeRange.c2, activeRange.r2 + 1); } if (filter && styleName && filter.Ref.isIntersect(activeRange) && !(filter.Ref.containsRange(activeRange) && (activeRange.isOneCell() || (filter.Ref.isEqual(activeRange))) || (filter.Ref.r1 === activeRange.r1 && activeRange.containsRange(filter.Ref)))) { worksheet.workbook.handlers.trigger("asc_onError", c_oAscError.ID.AutoFilterDataRangeError, c_oAscError.Level.NoCritical); result = false; } else if (filter && styleName && filter.Ref.r1 === activeRange.r2 + 1 && oTableProps.isTitle === false) { worksheet.workbook.handlers.trigger("asc_onError", c_oAscError.ID.AutoFilterDataRangeError, c_oAscError.Level.NoCritical); result = false; } else if (!styleName && activeRange.isOneCell() && worksheet.autoFilters._isEmptyRange(activeRange, 1)) { //add filter to empty range - if select contains 1 cell worksheet.workbook.handlers.trigger("asc_onError", c_oAscError.ID.AutoFilterDataRangeError, c_oAscError.Level.NoCritical); result = false; } else if (!styleName && !_isOneCell(activeRange) && worksheet.autoFilters._isEmptyRange(activeRange, 0)) { //add filter to empty range worksheet.workbook.handlers.trigger("asc_onError", c_oAscError.ID.AutoFilterDataRangeError, c_oAscError.Level.NoCritical); result = false; } else if (!styleName && filterByCellContextMenu && false === worksheet.autoFilters._getAdjacentCellsAF(activeRange, this).isIntersect(activeRange)) { //TODO _getAdjacentCellsAF стоит заменить на expandRange ? //add filter to empty range worksheet.workbook.handlers.trigger("asc_onError", c_oAscError.ID.AutoFilterDataRangeError, c_oAscError.Level.NoCritical); result = false; } else if (styleName && oTableProps && oTableProps.isTitle === false && worksheet.autoFilters._isEmptyCellsUnderRange(activeRange) == false && worksheet.autoFilters._isPartTablePartsUnderRange(activeRange)) { //add format table without title if down another format table worksheet.workbook.handlers.trigger("asc_onError", c_oAscError.ID.AutoFilterChangeFormatTableError, c_oAscError.Level.NoCritical); result = false; } else if (this.model.inPivotTable(fullRange)) { worksheet.workbook.handlers.trigger("asc_onError", c_oAscError.ID.LockedCellPivot, c_oAscError.Level.NoCritical); result = false; } else if(styleName && this.intersectionFormulaArray(activeRange, true, true)) { worksheet.workbook.handlers.trigger("asc_onError", c_oAscError.ID.MultiCellsInTablesFormulaArray, c_oAscError.Level.NoCritical); result = false; } return result; }; WorksheetView.prototype.showAutoFilterOptionsFromActiveCell = function () { const oWorksheet = this.model; const oActiveCell = this.model.getSelection().activeCell; const oIdFilter = {colId: 0, id: null}; const oFilter = oWorksheet.AutoFilter; if (oFilter) { const mergedCell = oWorksheet.getMergedByCell(oActiveCell.row, oActiveCell.col); if (mergedCell) { if (oFilter.Ref.containsCol(mergedCell.c1) && (oFilter.Ref.r1 === mergedCell.r1)) { oIdFilter.colId = mergedCell.c1 - oFilter.Ref.c1; this.af_setDialogProp(oIdFilter); return true; } } else if (oFilter.Ref.containsCol(oActiveCell.col) && (oFilter.Ref.r1 === oActiveCell.row)) { oIdFilter.colId = oActiveCell.col - oFilter.Ref.c1; this.af_setDialogProp(oIdFilter); return true; } } const oFilters = oWorksheet.autoFilters; const oTableInfo = oFilters && oFilters.getTableByActiveCell(); if (oTableInfo) { const oTable = oTableInfo.table; if (!oTable.isHeaderRow()) { return false; } const oTableFilter = oTable.AutoFilter; if (oTableFilter && oTableFilter.Ref.containsCol(oActiveCell.col) && (oTableFilter.Ref.r1 === oActiveCell.row)) { const nColId = oActiveCell.col - oTableFilter.Ref.c1; if (oTableFilter.isHideButton(nColId)) { return false; } const nTableId = oTableInfo.id; oIdFilter.colId = nColId; oIdFilter.id = nTableId; this.af_setDialogProp(oIdFilter); return true; } } return false; }; WorksheetView.prototype.pivot_setDialogProp = function (idPivot) { if (!idPivot) { return; } var pivotTable = this.model.getPivotTableById(idPivot.id); if (!pivotTable) { return; } //set menu object var autoFilterObject = new Asc.AutoFiltersOptions(); autoFilterObject.asc_setCellCoord(this.getCellCoord(idPivot.col, idPivot.row)); autoFilterObject.asc_setCellId(new AscCommon.CellBase(idPivot.row, idPivot.col).getName()); pivotTable.fillAutoFiltersOptions(autoFilterObject, idPivot.fld); return autoFilterObject; }; WorksheetView.prototype._checkFilterButtonInRange = function (c, r) { //TODO добавить проверку на isHidden у кнопки if (this.model.TableParts) { var tablePart; for (var i = 0; i < this.model.TableParts.length; i++) { tablePart = this.model.TableParts[i]; if (tablePart.Ref.contains(c, r) && tablePart.Ref.r1 === r) { return true; } } } return this.model.AutoFilter && this.model.AutoFilter.Ref.contains(c, r) && this.model.AutoFilter.Ref.r1 === r; }; WorksheetView.prototype.af_setDialogProp = function (filterProp, tooltipPreview) { if (!filterProp) { return; } if (!tooltipPreview && this.model.getSheetProtection(Asc.c_oAscSheetProtectType.autoFilter)) { return; } let rowButton; let colButton; let autoFilterObject = this.model.autoFilters.getAutoFiltersOptions(this.model, filterProp, function (r, c) { rowButton = r; colButton = c; }, tooltipPreview); if (autoFilterObject) { let cellCoord = this.getCellCoord(colButton, rowButton); autoFilterObject.asc_setCellCoord(cellCoord); } if (tooltipPreview) { return autoFilterObject; } else { this.handlers.trigger("setAutoFiltersDialog", autoFilterObject); } }; WorksheetView.prototype.af_changeSelectionTablePart = function (activeRange) { var t = this; var tableParts = t.model.TableParts; var _changeSelectionToAllTablePart = function () { var tablePart; for (var i = 0; i < tableParts.length; i++) { tablePart = tableParts[i]; if (tablePart.Ref.intersection(activeRange)) { if (t.model.autoFilters._activeRangeContainsTablePart(activeRange, tablePart.Ref)) { var newActiveRange = new Asc.Range(tablePart.Ref.c1, tablePart.Ref.r1, tablePart.Ref.c2, tablePart.Ref.r2); t.setSelection(newActiveRange); } break; } } }; var _changeSelectionFromCellToColumn = function () { if (tableParts && tableParts.length && activeRange.isOneCell()) { for (var i = 0; i < tableParts.length; i++) { if (tableParts[i].HeaderRowCount !== 0 && tableParts[i].Ref.containsRange(activeRange) && tableParts[i].Ref.r1 === activeRange.r1) { var newActiveRange = new Asc.Range(activeRange.c1, activeRange.r1, activeRange.c1, tableParts[i].Ref.r2); if (!activeRange.isEqual(newActiveRange)) { t.setSelection(newActiveRange); } break; } } } }; if (activeRange.isOneCell()) { _changeSelectionFromCellToColumn(activeRange); } else { _changeSelectionToAllTablePart(activeRange); } }; WorksheetView.prototype.af_isCheckMoveRange = function (arnFrom, arnTo, opt_wsTo) { var ws = this.model; var tableParts = ws.TableParts; var tablePart; var checkMoveRangeIntoApplyAutoFilter = function (arnTo) { if (ws.AutoFilter && ws.AutoFilter.Ref && arnTo.intersection(ws.AutoFilter.Ref) && !arnFrom.isEqual(ws.AutoFilter.Ref)) { //если затрагиваем скрытые строки а/ф - выдаём ошибку if (ws.autoFilters._searchHiddenRowsByFilter(ws.AutoFilter, arnTo)) { return false; } } return true; }; //1) если выделена часть форматированной таблицы и ещё часть(либо полностью) var counterIntersection = 0; var counterContains = 0; for (var i = 0; i < tableParts.length; i++) { tablePart = tableParts[i]; if (tablePart.Ref.intersection(arnFrom)) { if (arnFrom.containsRange(tablePart.Ref)) { counterContains++; } else { counterIntersection++; } } } if ((counterIntersection > 0 && counterContains > 0) || (counterIntersection > 1)) { ws.workbook.handlers.trigger("asc_onError", c_oAscError.ID.AutoFilterDataRangeError, c_oAscError.Level.NoCritical); return false; } //2)если затрагиваем перемещаемым диапазоном часть а/ф со скрытыми строчками if (!opt_wsTo && !checkMoveRangeIntoApplyAutoFilter(arnTo)) { ws.workbook.handlers.trigger("asc_onError", c_oAscError.ID.AutoFilterMoveToHiddenRangeError, c_oAscError.Level.NoCritical); return false; } return true; }; WorksheetView.prototype.changeTableSelection = function (tableName, optionType, opt_row, opt_col) { var t = this; var ws = this.model; var tablePart = ws.autoFilters._getFilterByDisplayName(tableName); if (!tablePart || (tablePart && !tablePart.Ref)) { return false; } var refTablePart = tablePart.Ref; var lastSelection = this.model.selectionRange.getLast(); var startCol = undefined !== opt_col ? opt_col : lastSelection.c1; var endCol = undefined !== opt_col ? opt_col : lastSelection.c2; var startRow = undefined !== opt_row ? opt_row : lastSelection.r1; var endRow = undefined !== opt_row ? opt_row : lastSelection.r2; var rangeWithoutHeaderFooter; switch (optionType) { case c_oAscChangeSelectionFormatTable.all: { startCol = refTablePart.c1; endCol = refTablePart.c2; startRow = refTablePart.r1; endRow = refTablePart.r2; break; } case c_oAscChangeSelectionFormatTable.data: { rangeWithoutHeaderFooter = tablePart.getRangeWithoutHeaderFooter(); if (undefined === opt_row) { startCol = lastSelection.c1 < refTablePart.c1 ? refTablePart.c1 : lastSelection.c1; endCol = lastSelection.c2 > refTablePart.c2 ? refTablePart.c2 : lastSelection.c2; } else { startCol = rangeWithoutHeaderFooter.c1; endCol = rangeWithoutHeaderFooter.c2; } startRow = rangeWithoutHeaderFooter.r1; endRow = rangeWithoutHeaderFooter.r2; if (undefined !== opt_row) { if (lastSelection.isEqual(rangeWithoutHeaderFooter)) { startRow = refTablePart.r1; endRow = refTablePart.r2; } else if (lastSelection.isEqual(refTablePart)) { startRow = rangeWithoutHeaderFooter.r1; } } break; } case c_oAscChangeSelectionFormatTable.row: { startCol = refTablePart.c1; endCol = refTablePart.c2; if (undefined === opt_row) { startRow = lastSelection.r1 < refTablePart.r1 ? refTablePart.r1 : lastSelection.r1; endRow = lastSelection.r2 > refTablePart.r2 ? refTablePart.r2 : lastSelection.r2; } break; } case c_oAscChangeSelectionFormatTable.column: { if (undefined === opt_col) { startCol = lastSelection.c1 < refTablePart.c1 ? refTablePart.c1 : lastSelection.c1; endCol = lastSelection.c2 > refTablePart.c2 ? refTablePart.c2 : lastSelection.c2; } startRow = refTablePart.r1; endRow = refTablePart.r2; break; } case c_oAscChangeSelectionFormatTable.dataColumn: { rangeWithoutHeaderFooter = tablePart.getRangeWithoutHeaderFooter(); startRow = rangeWithoutHeaderFooter.r1; endRow = rangeWithoutHeaderFooter.r2; if (undefined !== opt_row) { if (lastSelection.c1 === startCol && lastSelection.c2 === endCol) { if (lastSelection.r1 === rangeWithoutHeaderFooter.r1 && lastSelection.r2 === rangeWithoutHeaderFooter.r2) { startRow = refTablePart.r1; endRow = refTablePart.r2; } else if (lastSelection.r1 === refTablePart.r1 && lastSelection.r2 === refTablePart.r2) { startRow = rangeWithoutHeaderFooter.r1; } } else if (lastSelection.isEqual(refTablePart)) { startRow = rangeWithoutHeaderFooter.r1; } } break; } } t._endSelectionShape(); //todo обработать выделение при клике с зажатым ctrl t.setSelection(new Asc.Range(startCol, startRow, endCol, endRow)); }; WorksheetView.prototype.af_changeFormatTableInfo = function (tableName, optionType, val) { var tablePart = this.model.autoFilters._getFilterByDisplayName(tableName); var t = this; var ar = this.model.selectionRange.getLast(); if (!tablePart || (tablePart && !tablePart.TableStyleInfo)) { return false; } if (!window['AscCommonExcel'].filteringMode) { return false; } var isChangeTableInfo = this.af_checkChangeTableInfo(tablePart, optionType); if (isChangeTableInfo !== false) { var lockRange = isChangeTableInfo.lockRange ? isChangeTableInfo.lockRange : null; var updateRange = isChangeTableInfo.updateRange; var callback = function (isSuccess) { if (false === isSuccess) { t.handlers.trigger("selectionChanged"); return; } History.Create_NewPoint(); History.StartTransaction(); var newTableRef = t.model.autoFilters.changeFormatTableInfo(tableName, optionType, val); if (newTableRef.r1 > ar.r1 || newTableRef.r2 < ar.r2) { var startRow = newTableRef.r1 > ar.r1 ? newTableRef.r1 : ar.r1; var endRow = newTableRef.r2 < ar.r2 ? newTableRef.r2 : ar.r2; var newActiveRange = new Asc.Range(ar.c1, startRow, ar.c2, endRow); t.setSelection(newActiveRange); History.SetSelectionRedo(newActiveRange); } History.EndTransaction(); t._onUpdateFormatTable(updateRange); if (optionType === 5 ) { var r = (val ? newTableRef.r2 : updateRange.r2); t.workbook.Api.onWorksheetChange({r1: r, c1: newTableRef.c1, r2: r, c2: newTableRef.c2}); } else if (optionType === 4) { var r = (val ? newTableRef.r1 : updateRange.r1); t.workbook.Api.onWorksheetChange({r1: r, c1: newTableRef.c1, r2: r, c2: newTableRef.c2}); } }; lockRange = lockRange ? lockRange : t.af_getLockRangeTableInfo(tablePart, optionType, val); if (lockRange) { t._isLockedCells(lockRange, null, callback); } else { callback(); } } }; WorksheetView.prototype.af_checkChangeTableInfo = function (table, optionType) { var res = table.Ref; var t = this; var ws = this.model, range; var lockRange = null; var pivotError; var sendError = function () { if (pivotError) { t.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.LockedCellPivot, c_oAscError.Level.NoCritical); } else { ws.workbook.handlers.trigger("asc_onError", c_oAscError.ID.AutoFilterChangeFormatTableError, c_oAscError.Level.NoCritical); } t.handlers.trigger("selectionChanged"); }; var checkShift = function (range) { var result = false; if (t.model.checkShiftPivotTable(range, new AscCommon.CellBase(1, 0))) { pivotError = true; return false; } if (!t.model.autoFilters._isPartTablePartsUnderRange(range) && !t.model.autoFilters.isPartFilterUnderRange(range)) { result = true; //проверяем ещё на наличие части объединенной ячейки //для объединенной ячейки - ms выдаёт другую ошибку //TODO мы сейчас выдаём одинаковую ошибку для случаев с форматированной таблицей внизу и объединенной областью. пересмотреть! //пока комментирую проверку на объединенные ячейки var downRange = Asc.Range(range.c1, range.r2 + 1, range.c2, gc_nMaxRow0); var mergedRange = ws.getMergedByRange(downRange); if (mergedRange && mergedRange.all) { for (var i = 0; i < mergedRange.all.length; i++) { if (mergedRange.all[i] && mergedRange.all[i].bbox) { if (mergedRange.all[i].bbox.intersection(mergedRange) && !mergedRange.all[i].bbox.containsRange(mergedRange)) { result = false; break; } } } } } return result; }; switch (optionType) { case c_oAscChangeTableStyleInfo.rowHeader: { //добавляем строку заголовков. нужно чтобы либо сверху была пустая строка, либо был возможен сдвиг диапазона вниз if (!table.isHeaderRow()) { range = Asc.Range(table.Ref.c1, table.Ref.r1 - 1, table.Ref.c2, table.Ref.r1 - 1); if (!this.model.autoFilters._isEmptyRange(range, 0)) { if (!checkShift(table.Ref)) { sendError(); res = false; } else { //в данном случае возвращаем не диапазон лока, а диапазон обновления данных lockRange = Asc.Range(table.Ref.c1, table.Ref.r1 - 1, table.Ref.c2, gc_nMaxRow0); res = table.Ref; } } } break; } case c_oAscChangeTableStyleInfo.rowTotal: { range = new Asc.Range(table.Ref.c1, table.Ref.r2 + 1, table.Ref.c2, table.Ref.r2 + 1); if (table.isTotalsRow()) { if (checkShift(table.Ref)) { //сдвиг диапазона вверх //в данном случае возвращаем не диапазон лока, а диапазон обновления данных lockRange = Asc.Range(table.Ref.c1, table.Ref.r2 - 1, table.Ref.c2, gc_nMaxRow0); res = table.Ref; } } else { // добавляем строку if (checkShift(table.Ref)) { //сдвиг диапазона вниз lockRange = Asc.Range(table.Ref.c1, table.Ref.r2 + 1, table.Ref.c2, gc_nMaxRow0); res = Asc.Range(table.Ref.c1, table.Ref.r1, table.Ref.c2, table.Ref.r2 + 1); } else if (!this.model.autoFilters._isEmptyRange(range, 0)) { sendError(); res = false; } } break; } } return res ? {updateRange: res, lockRange: lockRange} : res; }; WorksheetView.prototype.af_getLockRangeTableInfo = function (tablePart, optionType, val) { var res = null; switch (optionType) { case c_oAscChangeTableStyleInfo.columnBanded: case c_oAscChangeTableStyleInfo.columnFirst: case c_oAscChangeTableStyleInfo.columnLast: case c_oAscChangeTableStyleInfo.rowBanded: case c_oAscChangeTableStyleInfo.filterButton: { res = tablePart.Ref; break; } case c_oAscChangeTableStyleInfo.rowTotal: { if (val === false) { res = tablePart.Ref; } else { var rangeUpTable = new Asc.Range(tablePart.Ref.c1, tablePart.Ref.r2 + 1, tablePart.Ref.c2, tablePart.Ref.r2 + 1); if(this.model.autoFilters._isEmptyRange(rangeUpTable, 0) && this.model.autoFilters.searchRangeInTableParts(rangeUpTable) === -1){ res = new Asc.Range(tablePart.Ref.c1, tablePart.Ref.r1, tablePart.Ref.c2, tablePart.Ref.r2 + 1); } else{ res = new Asc.Range(tablePart.Ref.c1, tablePart.Ref.r2 + 1, tablePart.Ref.c2, gc_nMaxRow0); } } break; } case c_oAscChangeTableStyleInfo.rowHeader: { if (val === false) { res = tablePart.Ref; } else { var rangeUpTable = new Asc.Range(tablePart.Ref.c1, tablePart.Ref.r1 - 1, tablePart.Ref.c2, tablePart.Ref.r1 - 1); if(this.model.autoFilters._isEmptyRange(rangeUpTable, 0) && this.model.autoFilters.searchRangeInTableParts(rangeUpTable) === -1){ res = new Asc.Range(tablePart.Ref.c1, tablePart.Ref.r1 - 1, tablePart.Ref.c2, tablePart.Ref.r2); } else{ res = new Asc.Range(tablePart.Ref.c1, tablePart.Ref.r1 - 1, tablePart.Ref.c2, gc_nMaxRow0); } } break; } } return res; }; WorksheetView.prototype.af_insertCellsInTable = function (tableName, optionType) { var t = this; var ws = this.model; var tablePart = ws.autoFilters._getFilterByDisplayName(tableName); if (!tablePart || (tablePart && !tablePart.Ref)) { return false; } var insertCellsAndShiftDownRight = function (arn, displayName, type) { var range = t.model.getRange3(arn.r1, arn.c1, arn.r2, arn.c2); var isCheckChangeAutoFilter = t.af_checkInsDelCells(arn, type, "insCell", true); if (isCheckChangeAutoFilter === false) { return; } var callback = function (isSuccess) { if (false === isSuccess) { return; } History.Create_NewPoint(); History.StartTransaction(); var shiftCells = type === c_oAscInsertOptions.InsertCellsAndShiftRight ? range.addCellsShiftRight(displayName) : range.addCellsShiftBottom(displayName); var deferredHistoryAction = t.model.autoFilters.deferredHistoryAction; if (deferredHistoryAction) { History.Add(AscCommonExcel.g_oUndoRedoAutoFilters, deferredHistoryAction._type, t.model.getId(), t.model.selectionRange.getLast().clone(), deferredHistoryAction); t.model.autoFilters.deferredHistoryAction = null; } History.EndTransaction(); if (shiftCells) { t.cellCommentator.updateCommentsDependencies(true, type, arn); t.shiftCellWatches(true, type, arn); t.model.shiftDataValidation(true, type, arn, true); t.objectRender.updateDrawingObject(true, type, arn); t._onUpdateFormatTable(range); } }; var r2 = type === c_oAscInsertOptions.InsertCellsAndShiftRight ? tablePart.Ref.r2 : gc_nMaxRow0; var c2 = type !== c_oAscInsertOptions.InsertCellsAndShiftRight ? tablePart.Ref.c2 : gc_nMaxCol0; var changedRange = new asc_Range(tablePart.Ref.c1, tablePart.Ref.r1, c2, r2); t._isLockedCells(changedRange, null, callback); }; var newActiveRange = this.model.selectionRange.getLast().clone(); var displayName = undefined; var type = null; var totalRow = tablePart.isTotalsRow(); switch (optionType) { case c_oAscInsertOptions.InsertTableRowAbove: { newActiveRange.c1 = tablePart.Ref.c1; newActiveRange.c2 = tablePart.Ref.c2; type = c_oAscInsertOptions.InsertCellsAndShiftDown; break; } case c_oAscInsertOptions.InsertTableRowBelow: { newActiveRange.c1 = tablePart.Ref.c1; newActiveRange.c2 = tablePart.Ref.c2; newActiveRange.r1 = totalRow ? tablePart.Ref.r2 : tablePart.Ref.r2 + 1; newActiveRange.r2 = totalRow ? tablePart.Ref.r2 : tablePart.Ref.r2 + 1; if (!totalRow) { displayName = tableName; } type = c_oAscInsertOptions.InsertCellsAndShiftDown; break; } case c_oAscInsertOptions.InsertTableColLeft: { newActiveRange.r1 = tablePart.Ref.r1; newActiveRange.r2 = tablePart.Ref.r2; type = c_oAscInsertOptions.InsertCellsAndShiftRight; break; } case c_oAscInsertOptions.InsertTableColRight: { newActiveRange.c1 = tablePart.Ref.c2 + 1; newActiveRange.c2 = tablePart.Ref.c2 + 1; newActiveRange.r1 = tablePart.Ref.r1; newActiveRange.r2 = tablePart.Ref.r2; displayName = tableName; type = c_oAscInsertOptions.InsertCellsAndShiftRight; break; } } var _cellBase = new AscCommon.CellBase(type !== c_oAscInsertOptions.InsertCellsAndShiftRight ? newActiveRange.r2 - newActiveRange.r1 + 1 : 0, type !== c_oAscInsertOptions.InsertCellsAndShiftRight ? 0 : newActiveRange.c2 - newActiveRange.c1 + 1); if (t.model.checkShiftPivotTable(tablePart.Ref, _cellBase)) { t.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.LockedCellPivot, c_oAscError.Level.NoCritical); return; } insertCellsAndShiftDownRight(newActiveRange, displayName, type) }; WorksheetView.prototype.af_deleteCellsInTable = function (tableName, optionType) { var t = this; var ws = this.model; var tablePart = ws.autoFilters._getFilterByDisplayName(tableName); if (!tablePart || (tablePart && !tablePart.Ref)) { return false; } var deleteCellsAndShiftLeftTop = function (arn, type) { var isCheckChangeAutoFilter = t.af_checkInsDelCells(arn, type, "delCell", true); if (isCheckChangeAutoFilter === false) { return; } var callback = function (isSuccess) { if (false === isSuccess) { return; } History.Create_NewPoint(); History.StartTransaction(); if (isCheckChangeAutoFilter === true) { t.model.autoFilters.isEmptyAutoFilters(arn, type); } var preDeleteAction = function () { t.cellCommentator.updateCommentsDependencies(false, type, arn); t.shiftCellWatches(false, val, arn); t.model.shiftDataValidation(false, type, arn, true); }; var res; var range; if (type === c_oAscDeleteOptions.DeleteCellsAndShiftLeft) { range = t.model.getRange3(arn.r1, arn.c1, arn.r2, arn.c2); res = range.deleteCellsShiftLeft(preDeleteAction); } else { arn = t.model.autoFilters.checkDeleteAllRowsFormatTable(arn, true); range = t.model.getRange3(arn.r1, arn.c1, arn.r2, arn.c2); res = range.deleteCellsShiftUp(preDeleteAction); } History.EndTransaction(); if (res) { t.objectRender.updateDrawingObject(true, type, arn); t._onUpdateFormatTable(range); t._updateSlicers(arn); } }; var r2 = type === c_oAscDeleteOptions.DeleteCellsAndShiftLeft ? tablePart.Ref.r2 : gc_nMaxRow0; var c2 = type !== c_oAscDeleteOptions.DeleteCellsAndShiftLeft ? tablePart.Ref.c2 : gc_nMaxCol0; var changedRange = new asc_Range(tablePart.Ref.c1, tablePart.Ref.r1, c2, r2); t._isLockedCells(changedRange, null, callback); }; var deleteTableCallback = function (ref) { if (!window['AscCommonExcel'].filteringMode) { return false; } var callback = function (isSuccess) { if (false === isSuccess) { return; } History.Create_NewPoint(); History.StartTransaction(); t.model.autoFilters.isEmptyAutoFilters(ref); var cleanRange = t.model.getRange3(ref.r1, ref.c1, ref.r2, ref.c2); cleanRange.cleanAll(); t.cellCommentator.deleteCommentsRange(cleanRange.bbox); History.EndTransaction(); t._onUpdateFormatTable(ref); }; t._isLockedCells(ref, null, callback); }; var newActiveRange = this.model.selectionRange.getLast().clone(); var val = null; switch (optionType) { case c_oAscDeleteOptions.DeleteColumns: { newActiveRange.r1 = tablePart.Ref.r1; newActiveRange.r2 = tablePart.Ref.r2; val = c_oAscDeleteOptions.DeleteCellsAndShiftLeft; break; } case c_oAscDeleteOptions.DeleteRows: { newActiveRange.c1 = tablePart.Ref.c1; newActiveRange.c2 = tablePart.Ref.c2; val = c_oAscDeleteOptions.DeleteCellsAndShiftTop; break; } case c_oAscDeleteOptions.DeleteTable: { deleteTableCallback(tablePart.Ref.clone()); break; } } if (val !== null) { deleteCellsAndShiftLeftTop(newActiveRange, val); } }; WorksheetView.prototype.af_changeDisplayNameTable = function (tableName, newName) { this.model.autoFilters.changeDisplayNameTable(tableName, newName); }; WorksheetView.prototype.af_checkInsDelCells = function (activeRange, val, prop, isFromFormatTable) { var ws = this.model; var res = true; var filterError; if (!window['AscCommonExcel'].filteringMode) { if (val === c_oAscInsertOptions.InsertCellsAndShiftRight || val === c_oAscInsertOptions.InsertColumns) { return false; } else if (val === c_oAscDeleteOptions.DeleteCellsAndShiftLeft || val === c_oAscDeleteOptions.DeleteColumns) { return false; } } var intersectionTableParts = ws.autoFilters.getTablesIntersectionRange(activeRange); var isPartTablePartsUnderRange = ws.autoFilters._isPartTablePartsUnderRange(activeRange); var isPartTablePartsRightRange = ws.autoFilters.isPartTablePartsRightRange(activeRange); var isOneTableIntersection = intersectionTableParts && intersectionTableParts.length === 1 ? intersectionTableParts[0] : null; var isPartFilterUnderRange = ws.autoFilters.isPartFilterUnderRange(activeRange, true); var isPartFilterRightRange = ws.autoFilters.isPartFilterRightRange(activeRange, true); var isPartTablePartsByRowCol = ws.autoFilters._isPartTablePartsByRowCol(activeRange); var allTablesInside = true; if (intersectionTableParts && intersectionTableParts.length) { for (var i = 0; i < intersectionTableParts.length; i++) { if (intersectionTableParts[i] && intersectionTableParts[i].Ref && !activeRange.containsRange(intersectionTableParts[i].Ref)) { allTablesInside = false; break; } } } //TODO перепроверить -> //когда выделено несколько колонок и нажимаем InsertCellsAndShiftRight(аналогично со строками) //ms в данном случае выдаёт ошибку, но пока не вижу никаких ограничений для данного действия var checkInsCells = function () { switch (val) { case c_oAscInsertOptions.InsertCellsAndShiftDown: { if (isFromFormatTable) { //если внизу находится часть форматированной таблицы или это часть форматированной таблицы if (isPartTablePartsUnderRange) { res = false; } else if (isOneTableIntersection !== null && !(isOneTableIntersection.Ref.c1 === activeRange.c1 && isOneTableIntersection.Ref.c2 === activeRange.c2)) { res = false; } } else { if (isPartTablePartsUnderRange) { res = false; } /*else if (intersectionTableParts && null !== isOneTableIntersection) { res = false; } else if (isOneTableIntersection && !isOneTableIntersection.Ref.isEqual(activeRange)) { res = false; }*/ else if (isPartTablePartsByRowCol && isPartTablePartsByRowCol.cols) { res = false; } } if (res && isPartFilterUnderRange) { res = false; filterError = true; } break; } case c_oAscInsertOptions.InsertCellsAndShiftRight: { //если справа находится часть форматированной таблицы или это часть форматированной таблицы if (isFromFormatTable) { if (isPartTablePartsRightRange) { res = false; } } else { if (isPartTablePartsRightRange) { res = false; } /*else if (intersectionTableParts && null !== isOneTableIntersection) { res = false; } else if (isOneTableIntersection && !isOneTableIntersection.Ref.isEqual(activeRange)) { res = false; } */ else if (isPartTablePartsByRowCol && isPartTablePartsByRowCol.rows) { res = false; } } if (res && isPartFilterRightRange) { res = false; filterError = true; } break; } case c_oAscInsertOptions.InsertColumns: { break; } case c_oAscInsertOptions.InsertRows: { break; } } }; var checkDelCells = function () { switch (val) { case c_oAscDeleteOptions.DeleteCellsAndShiftTop: { if (isFromFormatTable) { if (isPartTablePartsUnderRange) { res = false; } } else { if (isPartTablePartsUnderRange) { res = false; } /*else if (!isOneTableIntersection && null !== isOneTableIntersection) { res = false; } else if (isOneTableIntersection && !isOneTableIntersection.Ref.isEqual(activeRange)) { res = false; }*/ else if (!allTablesInside) { res = false; } } if (res && isPartFilterUnderRange) { res = false; filterError = true; } break; } case c_oAscDeleteOptions.DeleteCellsAndShiftLeft: { if (isFromFormatTable) { if (isPartTablePartsRightRange) { res = false; } } else { if (isPartTablePartsRightRange) { res = false; } /*else if (!isOneTableIntersection && null !== isOneTableIntersection) { res = false; } else if (isOneTableIntersection && !isOneTableIntersection.Ref.isEqual(activeRange)) { res = false; }*/ else if (!allTablesInside) { res = false; } } if (res && isPartFilterRightRange) { res = false; filterError = true; } break; } case c_oAscDeleteOptions.DeleteColumns: { break; } case c_oAscDeleteOptions.DeleteRows: { break; } } }; prop === "insCell" ? checkInsCells() : checkDelCells(); if (res === false) { if (filterError) { ws.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ChangeFilteredRangeError, c_oAscError.Level.NoCritical); } else { ws.workbook.handlers.trigger("asc_onError", c_oAscError.ID.AutoFilterChangeFormatTableError, c_oAscError.Level.NoCritical); } } return res; }; WorksheetView.prototype.af_setDisableProps = function (tablePart, formatTableInfo) { var selectionRange = this.model.selectionRange; var lastRange = selectionRange.getLast(); var activeCell = selectionRange.activeCell; if (!tablePart) { return false; } var refTable = tablePart.Ref; var refTableContainsActiveRange = selectionRange.isSingleRange() && refTable.containsRange(lastRange); //если курсор стоит в нижней строке, то разрешаем добавление нижней строки formatTableInfo.isInsertRowBelow = (refTableContainsActiveRange && ((tablePart.TotalsRowCount === null && activeCell.row === refTable.r2) || (tablePart.TotalsRowCount !== null && activeCell.row === refTable.r2 - 1))); //если курсор стоит в правом столбце, то разрешаем добавление одного столбца правее formatTableInfo.isInsertColumnRight = (refTableContainsActiveRange && activeCell.col === refTable.c2); //если внутри находится вся активная область или если выходит активная область за границу справа formatTableInfo.isInsertColumnLeft = refTableContainsActiveRange; //если внутри находится вся активная область(кроме строки заголовков) или если выходит активная область за границу снизу formatTableInfo.isInsertRowAbove = (refTableContainsActiveRange && ((lastRange.r1 > refTable.r1 && tablePart.HeaderRowCount === null) || (lastRange.r1 >= refTable.r1 && tablePart.HeaderRowCount !== null))); //если есть заголовок, и в данных всего одна строка //todo пределать все проверки HeaderRowCount на вызов функции isHeaderRow var dataRange = tablePart.getRangeWithoutHeaderFooter(); if(refTable.r1 === lastRange.r1 && refTable.r2 === lastRange.r2) { formatTableInfo.isDeleteRow = true; } else if((tablePart.isHeaderRow() || tablePart.isTotalsRow()) && dataRange.r1 === dataRange.r2 && lastRange.r1 === lastRange.r2 && dataRange.r1 === lastRange.r1) { formatTableInfo.isDeleteRow = false; } else { formatTableInfo.isDeleteRow = refTableContainsActiveRange && !(lastRange.r1 <= refTable.r1 && lastRange.r2 >= refTable.r1 && null === tablePart.HeaderRowCount); } formatTableInfo.isDeleteColumn = true; formatTableInfo.isDeleteTable = true; if (!window['AscCommonExcel'].filteringMode) { formatTableInfo.isDeleteColumn = false; formatTableInfo.isInsertColumnRight = false; formatTableInfo.isInsertColumnLeft = false; } }; WorksheetView.prototype.af_convertTableToRange = function (tableName) { var t = this; if (!window['AscCommonExcel'].filteringMode) { return; } var callback = function (isSuccess) { if (false === isSuccess) { return; } History.Create_NewPoint(); History.StartTransaction(); t.model.autoFilters.convertTableToRange(tableName); History.EndTransaction(); t._onUpdateFormatTable(lockRange); }; var table = t.model.autoFilters._getFilterByDisplayName(tableName); var lockRange = null !== table ? table.Ref : null; var callBackLockedDefNames = function (isSuccess) { if (false === isSuccess) { return; } t._isLockedCells(lockRange, null, callback); }; //лочим данный именованный диапазон var defNameId = t.model.workbook.dependencyFormulas.getDefNameByName(tableName, t.model.getId()); defNameId = defNameId ? defNameId.getNodeId() : null; t._isLockedDefNames(callBackLockedDefNames, defNameId); }; WorksheetView.prototype.af_changeTableRange = function (tableName, range, callbackAfterChange, doNotUpdate) { var t = this; if (typeof range === "string") { range = AscCommonExcel.g_oRangeCache.getAscRange(range); } if (!window['AscCommonExcel'].filteringMode) { return; } var callback = function (isSuccess) { if (false === isSuccess) { if (callbackAfterChange) { callbackAfterChange(isSuccess); } return; } History.Create_NewPoint(); History.StartTransaction(); var tablePart = t.model.autoFilters._getFilterByDisplayName(tableName); var oldRange = tablePart && tablePart.Ref.clone(); var oldRangeWithoutHeader = tablePart && tablePart.getRangeWithoutHeaderFooter(); t.model.autoFilters.changeTableRange(tableName, range); var newRange = tablePart.Ref; //расширяем условное форматирование //если тело колоки заполнено УФ, тогда расширяем его диапазон на ячейки ниже //ms ещё изменяет УФ при уменьшении ф/т, что мне кажется может мешать работе, пока не реализую if (tablePart && newRange.containsRange(oldRange)) { var aRules = t.model.getConditionalFormattingRules(); if (aRules) { for (var j in aRules) { var oRule = aRules[j]; var ranges = oRule && oRule.ranges; if (ranges) { var isChange = false; var newRanges = []; for (var k = 0, length3 = ranges.length; k < length3; k++) { if (ranges[k].isEqual(oldRange) || ranges[k].isEqual(oldRangeWithoutHeader)) { newRanges.push(new Asc.Range(ranges[k].c1, ranges[k].r1, ranges[k].c2, newRange.r2)); isChange = true; } else { var isPush = false; for (var i = 0; i < tablePart.TableColumns.length; i++) { var rangeColumnWithoutHeader = tablePart.getColumnRange(i, true, null, oldRange); var rangeColumn = tablePart.getColumnRange(i, null, null, oldRange); if (ranges[k].isEqual(rangeColumnWithoutHeader) || ranges[k].isEqual(rangeColumn)) { newRanges.push(new Asc.Range(ranges[k].c1, ranges[k].r1, ranges[k].c2, newRange.r2)); isChange = true; isPush = true; break; } } if (!isPush) { newRanges.push(ranges[k].clone()); } } } if (isChange) { var toRule = oRule.clone(); toRule.ranges = newRanges; toRule.id = oRule.id; t.model.setCFRule(toRule); } } } } } History.EndTransaction(); if (!doNotUpdate) { t._onUpdateFormatTable(range); } //TODO добавить перерисовку таблицы и перерисовку шаблонов if (callbackAfterChange) { callbackAfterChange(true); } }; //TODO возможно не стоит лочить весь диапазон. проверить: когда один ползователь меняет диапазон, другой снимает а/ф с ф/т. в этом случае в deleteAutoFilter передавать не range а имя ф/т var table = t.model.autoFilters._getFilterByDisplayName(tableName); var tableRange = null !== table ? table.Ref : null; if (tableRange && range && tableRange.isEqual(range)) { if (callbackAfterChange) { callbackAfterChange(false); } else { return false; } } var lockRange = range; if (null !== tableRange) { var r1 = tableRange.r1 < range.r1 ? tableRange.r1 : range.r1; var r2 = tableRange.r2 > range.r2 ? tableRange.r2 : range.r2; var c1 = tableRange.c1 < range.c1 ? tableRange.c1 : range.c1; var c2 = tableRange.c2 > range.c2 ? tableRange.c2 : range.c2; lockRange = new Asc.Range(c1, r1, c2, r2); } var callBackLockedDefNames = function (isSuccess) { if (false === isSuccess) { if (callbackAfterChange) { callbackAfterChange(isSuccess); } return; } var callbackLockAll = function (_success) { if (false === _success) { if (callbackAfterChange) { callbackAfterChange(_success); } return; } t._isLockedCells(lockRange, null, callback); }; t._isLockedAll(callbackLockAll); }; //лочим данный именованный диапазон при смене размера ф/т var defNameId = t.model.workbook.dependencyFormulas.getDefNameByName(tableName, t.model.getId()); defNameId = defNameId ? defNameId.getNodeId() : null; t._isLockedDefNames(callBackLockedDefNames, defNameId); }; WorksheetView.prototype.af_checkChangeRange = function (range) { var res = null; var intersectionTables = this.model.autoFilters.getTablesIntersectionRange(range); var merged; if (intersectionTables.length > 0) { var tablePart = intersectionTables[0]; if (range.r1 === range.r2) { res = c_oAscError.ID.FTChangeTableRangeError; } else if (range.r1 !== tablePart.Ref.r1)//первая строка таблицы не равна первой строке выделенного диапазона { res = c_oAscError.ID.FTChangeTableRangeError; } else if (intersectionTables.length !== 1)//выделено несколько таблиц { res = c_oAscError.ID.FTRangeIncludedOtherTables; } else if (this.model.AutoFilter && this.model.AutoFilter.Ref && this.model.AutoFilter.Ref.isIntersect(range)) { res = c_oAscError.ID.FTChangeTableRangeError; } else if((merged = this.model.getMergedByRange(range)) && merged.all && merged.all.length !== 0) { //TODO необходимо изменить название ошибки!!! res = c_oAscError.ID.FTChangeTableRangeError; } else if(this.intersectionFormulaArray(range, true, true)) { res = c_oAscError.ID.MultiCellsInTablesFormulaArray; } } else { res = c_oAscError.ID.FTChangeTableRangeError; } return res; }; WorksheetView.prototype.checkMoveFormulaArray = function(from, to, ctrlKey, opt_wsTo) { //***array-formula*** var res = true; //TODO вместо getRange3 нужна функция, которая может заканчивать цикл по ячейкам if(!ctrlKey) { //проверяем from, затрагиваем ли мы часть формулы массива res = !this.intersectionFormulaArray(from); } //проверяем to, затрагиваем ли мы часть формулы массива var ws = opt_wsTo ? opt_wsTo : this; if(res && to) { res = !ws.intersectionFormulaArray(to); } return res; }; WorksheetView.prototype.intersectionFormulaArray = function(range, notCheckContains, checkOneCellArray) { //checkOneCellArray - ф/т можно добавить поверх формулы массива, которая содержит 1 ячейку, если более - то ошибка //notCheckContains - ф/т нельзя добавить, если мы пересекаемся или содержим ф/т var res = false; this.model.getRange3(range.r1, range.c1, range.r2, range.c2)._foreachNoEmpty(function(cell) { if(cell.isFormula()) { var formulaParsed = cell.getFormulaParsed(); var arrayFormulaRef = formulaParsed.getArrayFormulaRef(); if(arrayFormulaRef && (!checkOneCellArray || (checkOneCellArray && !arrayFormulaRef.isOneCell()))) { if(notCheckContains) { res = true; } else if(!notCheckContains && !range.containsRange(arrayFormulaRef)){ res = true; } } } }); return res; }; WorksheetView.prototype.intersectionFormulaArray2 = function(range, notCheckContains, checkOneCellArray) { const t = this; const ws = this.model; //checkOneCellArray - ф/т можно добавить поверх формулы массива, которая содержит 1 ячейку, если более - то ошибка //notCheckContains - ф/т нельзя добавить, если мы пересекаемся или содержим ф/т // this function, in addition to checking cse formulas, checks dynamic arrays and fills in the list of changed arrays let res = false; for (let row = range.r1; row <= range.r2; row++) { for (let col = range.c1; col <= range.c2; col++) { if (res) { return res; } ws._getCell(row, col, function(cell) { if(cell.isFormula()) { let formulaParsed = cell.getFormulaParsed(); let arrayFormulaRef = formulaParsed.getArrayFormulaRef(); let dynamicRange = formulaParsed.getDynamicRef(); if (arrayFormulaRef && dynamicRange) { let name = dynamicRange.getName(AscCommonExcel.referenceType.R); let arrayInfo = {range: dynamicRange, doDelete: false, doRecalc: true, formula: formulaParsed}; // check this cell. If this is the first cell of dynamic range, delete this range, else delete all elements except the first if (cell.nRow === dynamicRange.r1 && cell.nCol === dynamicRange.c1) { arrayInfo.doRecalc = false arrayInfo.doDelete = true } ws.addChangedArray(name, arrayInfo); } else if(arrayFormulaRef && (!checkOneCellArray || (checkOneCellArray && !arrayFormulaRef.isOneCell()))) { if(notCheckContains) { res = true; } else if(!notCheckContains && !range.containsRange(arrayFormulaRef)){ res = true; } } } }); } } return res; }; // Convert coordinates methods WorksheetView.prototype.ConvertXYToLogic = function (x, y) { var c = this.visibleRange.c1, cFrozen, widthDiff; var r = this.visibleRange.r1, rFrozen, heightDiff; if (this.topLeftFrozenCell) { cFrozen = this.topLeftFrozenCell.getCol0(); widthDiff = this._getColLeft(cFrozen) - this._getColLeft(0); if (x < this.cellsLeft + widthDiff && 0 !== widthDiff) { c = 0; } rFrozen = this.topLeftFrozenCell.getRow0(); heightDiff = this._getRowTop(rFrozen) - this._getRowTop(0); if (y < this.cellsTop + heightDiff && 0 !== heightDiff) { r = 0; } } x += this._getColLeft(c) - this.cellsLeft - this.cellsLeft; y += this._getRowTop(r) - this.cellsTop - this.cellsTop; x *= asc_getcvt(0/*px*/, 3/*mm*/, this._getPPIX()); y *= asc_getcvt(0/*px*/, 3/*mm*/, this._getPPIY()); return {X: x, Y: y}; }; WorksheetView.prototype.ConvertLogicToXY = function (xL, yL) { xL *= asc_getcvt(3/*mm*/, 0/*px*/, this._getPPIX()); yL *= asc_getcvt(3/*mm*/, 0/*px*/, this._getPPIY()); var c = this.visibleRange.c1, cFrozen, widthDiff = 0; var r = this.visibleRange.r1, rFrozen, heightDiff = 0; if (this.topLeftFrozenCell) { cFrozen = this.topLeftFrozenCell.getCol0(); widthDiff = this._getColLeft(cFrozen) - this._getColLeft(0); if (xL < widthDiff && 0 !== widthDiff) { c = 0; widthDiff = 0; } rFrozen = this.topLeftFrozenCell.getRow0(); heightDiff = this._getRowTop(rFrozen) - this._getRowTop(0); if (yL < heightDiff && 0 !== heightDiff) { r = 0; heightDiff = 0; } } xL -= (this._getColLeft(c) - widthDiff - this.cellsLeft - this.cellsLeft); yL -= (this._getRowTop(r) - heightDiff - this.cellsTop - this.cellsTop); return {X: xL, Y: yL}; }; /** Для api layout */ WorksheetView.prototype.changeDocSize = function (width, height) { var t = this; var pageOptions = t.model.PagePrintOptions; var onChangeDocSize = function (isSuccess) { if (false === isSuccess) { return; } History.Create_NewPoint(); History.StartTransaction(); pageOptions.pageSetup.asc_setWidth(width); pageOptions.pageSetup.asc_setHeight(height); History.EndTransaction(); t.recalcPrintScale(); t.changeViewPrintLines(true); if(t.viewPrintLines) { t.updateSelection(); } window["Asc"]["editor"]._onUpdateLayoutMenu(t.model.Id); }; return this._isLockedLayoutOptions(onChangeDocSize); }; WorksheetView.prototype.changePageOrient = function (orientation) { var pageOptions = this.model.PagePrintOptions; var t = this; var callback = function (isSuccess) { if (false === isSuccess) { return; } History.Create_NewPoint(); History.StartTransaction(); pageOptions.pageSetup.asc_setOrientation(orientation); History.EndTransaction(); t.recalcPrintScale(); t.changeViewPrintLines(true); if(t.viewPrintLines) { t.updateSelection(); } window["Asc"]["editor"]._onUpdateLayoutMenu(t.model.Id); }; return this._isLockedLayoutOptions(callback); }; WorksheetView.prototype.changePageMargins = function (oMargins, bHorCentered, bVerCentered, nHeader, nFooter) { var t = this; var pageOptions = t.model.PagePrintOptions; var pageMargins = pageOptions.asc_getPageMargins(); var callback = function (isSuccess) { if (false === isSuccess) { return; } History.Create_NewPoint(); History.StartTransaction(); if (oMargins) { pageMargins.asc_setLeft(oMargins.asc_getLeft()); pageMargins.asc_setRight(oMargins.asc_getRight()); pageMargins.asc_setTop(oMargins.asc_getTop()); pageMargins.asc_setBottom(oMargins.asc_getBottom()); } if (bHorCentered != null) { pageOptions.asc_setHorizontalCentered(bHorCentered); } if (bVerCentered != null) { pageOptions.asc_setVerticalCentered(bVerCentered); } History.EndTransaction(); t.recalcPrintScale(); t.changeViewPrintLines(true); if(t.viewPrintLines) { t.updateSelection(); } window["Asc"]["editor"]._onUpdateLayoutMenu(t.model.Id); }; return this._isLockedLayoutOptions(callback); }; WorksheetView.prototype.setPageOption = function (callback, val) { var t = this; var onChangeDocSize = function (isSuccess) { if (false === isSuccess) { return; } History.Create_NewPoint(); History.StartTransaction(); callback(val); t.recalcPrintScale(); t.changeViewPrintLines(true); History.EndTransaction(); if(t.viewPrintLines) { t.updateSelection(); } }; return this._isLockedLayoutOptions(onChangeDocSize); }; WorksheetView.prototype.setPageOptions = function (obj) { var t = this; var viewMode = !this.workbook.canEdit(); if(!obj) { return; } var onChangeDocSize = function (isSuccess) { if (false === isSuccess) { return; } t.savePageOptions(obj, viewMode); t.recalcPrintScale(); t.changeViewPrintLines(true); if(t.viewPrintLines) { t.updateSelection(); } }; return viewMode ? onChangeDocSize(true) : this._isLockedLayoutOptions(onChangeDocSize); }; WorksheetView.prototype.setPrintHeadings = function (val) { var pageOptions = this.model.PagePrintOptions; var t = this; var callback = function (isSuccess) { if (false === isSuccess) { return; } History.Create_NewPoint(); History.StartTransaction(); pageOptions.asc_setHeadings(val); History.EndTransaction(); t.recalcPrintScale(); t.changeViewPrintLines(true); if(t.viewPrintLines) { t.updateSelection(); } window["Asc"]["editor"]._onUpdateLayoutMenu(t.model.Id); }; return this._isLockedLayoutOptions(callback); }; WorksheetView.prototype.setGridLines = function (val) { var pageOptions = this.model.PagePrintOptions; var t = this; var callback = function (isSuccess) { if (false === isSuccess) { return; } History.Create_NewPoint(); History.StartTransaction(); pageOptions.asc_setGridLines(val); History.EndTransaction(); t.recalcPrintScale(); t.changeViewPrintLines(true); if(t.viewPrintLines) { t.updateSelection(); } window["Asc"]["editor"]._onUpdateLayoutMenu(t.model.Id); }; return this._isLockedLayoutOptions(callback); }; WorksheetView.prototype.savePageOptions = function (obj, viewMode) { var pageOptions = this.model.PagePrintOptions; if (viewMode) { History.TurnOff(); } History.Create_NewPoint(); History.StartTransaction(); var pageSetupModel = pageOptions.asc_getPageSetup(); var oldFitToWidth = pageSetupModel.asc_getFitToWidth(); var oldFitToHeight = pageSetupModel.asc_getFitToHeight(); var pageSetupObj = obj.asc_getPageSetup(); var newFitToWidth = pageSetupObj.asc_getFitToWidth(); var newFitToHeight = pageSetupObj.asc_getFitToHeight(); //если поменялись scaling - fit sheet on.. -> необходимо пересчитать scaling if (oldFitToWidth != newFitToWidth || oldFitToHeight != newFitToHeight) { this.fitToWidthHeight(newFitToWidth, newFitToHeight); } if (newFitToWidth === 0 && newFitToHeight === 0) { pageOptions.asc_getPageSetup().asc_setScale(pageSetupObj.asc_getScale()); } pageOptions.asc_setOptions(obj); this._changePrintTitles(obj.printTitlesWidth, obj.printTitlesHeight); //может прийти только из превью if (pageSetupObj.headerFooter) { var tempEditor = new AscCommonExcel.CHeaderFooterEditor(); tempEditor.setPropsFromInterface(pageSetupObj.headerFooter); tempEditor._saveToModel(this, null, true); } this.recalcPrintScale(); this.changeViewPrintLines(true); //window["Asc"]["editor"]._onUpdateLayoutMenu(this.model.nSheetId); History.EndTransaction(); if (viewMode) { History.TurnOn(); } if (this.viewPrintLines) { this.updateSelection(); } }; WorksheetView.prototype.changePrintArea = function (type, opt_ranges, opt_range_from) { var t = this; var wb = window["Asc"]["editor"].wb; //TODO нужно ли лочить именованные диапазоны при изменении особого именованного диапазона - Print_Area var callback = function (isSuccess) { if (false === isSuccess) { return; } var getRangesStr = function(ranges, oldStr) { var str = oldStr ? oldStr : ""; var selectionLast = opt_ranges ? opt_ranges[opt_ranges.length - 1] : t.model.selectionRange.getLast(); var mc = selectionLast.isOneCell() ? t.model.getMergedByCell(selectionLast.r1, selectionLast.c1) : null; for(var i = 0; i < ranges.length; i++) { if(i === 0 && str !== "") { str += ","; } AscCommonExcel.executeInR1C1Mode(false, function () { str += parserHelp.get3DRef(t.model.getName(), (mc || ranges[i]).getAbsName()); }); if(i !== ranges.length - 1) { str += ","; } } return str; }; var printArea = t.model.workbook.getDefinesNames("Print_Area", t.model.getId()); if(printArea && printArea.sheetId !== t.model.getId()) { printArea = null; } var oldDefName, oldScope, newRef, newDefName, oldRef; switch (type) { case Asc.c_oAscChangePrintAreaType.set: { //если нет такого именнованного диапазона - создаём. если есть - меняем ref oldDefName = printArea ? printArea.getAscCDefName() : null; oldScope = oldDefName ? oldDefName.asc_getScope() : t.model.index; newRef = getRangesStr(opt_ranges ? opt_ranges : t.model.selectionRange.ranges); newDefName = new Asc.asc_CDefName("Print_Area", newRef, oldScope, null, null, null, true); t.changeViewPrintLines(true); wb.editDefinedNames(oldDefName, newDefName); break; } case Asc.c_oAscChangePrintAreaType.clear: { if(printArea) { wb.delDefinedNames(printArea.getAscCDefName()); } break; } case Asc.c_oAscChangePrintAreaType.add: { //расширяем именованный диапазон oldDefName = printArea ? printArea.getAscCDefName() : null; if(oldDefName) { oldScope = oldDefName ? oldDefName.asc_getScope() : t.model.index; oldRef = oldDefName.asc_getRef(); newRef = getRangesStr(opt_ranges ? opt_ranges : t.model.selectionRange.ranges, oldRef); newDefName = new Asc.asc_CDefName("Print_Area", newRef, oldScope, null, null, null, true); t.recalcPrintScale(); t.changeViewPrintLines(true); wb.editDefinedNames(oldDefName, newDefName); } break; } case Asc.c_oAscChangePrintAreaType.change: { oldDefName = printArea ? printArea.getAscCDefName() : null; if(oldDefName && opt_ranges && opt_range_from) { let areaRefsArr; AscCommonExcel.executeInR1C1Mode(false, function () { areaRefsArr = AscCommonExcel.getRangeByRef(printArea.ref, t.model, true, true, true) }); let newRanges = []; let isChanged = null; for (let i = 0; i < areaRefsArr.length; i++) { let isFind = null; for (let j = 0; j < opt_range_from.length; j++) { if (opt_range_from[j].isEqual(areaRefsArr[i].bbox)) { isFind = opt_ranges[j]; isChanged = true; break; } } newRanges.push(isFind ? isFind : areaRefsArr[i].bbox); } if (isChanged) { oldScope = oldDefName ? oldDefName.asc_getScope() : t.model.index; oldRef = oldDefName.asc_getRef(); newRef = getRangesStr(newRanges); newDefName = new Asc.asc_CDefName("Print_Area", newRef, oldScope, null, null, null, true); t.recalcPrintScale(); t.changeViewPrintLines(true); wb.editDefinedNames(oldDefName, newDefName); } } break; } } }; return callback(); }; WorksheetView.prototype.canAddPrintArea = function () { var res = false, t = this; var printArea = this.model.workbook.getDefinesNames("Print_Area", this.model.getId()); if(printArea && printArea.sheetId === this.model.getId()) { var selection = this.model.selectionRange.ranges; var areaRefsArr; AscCommonExcel.executeInR1C1Mode(false, function () { areaRefsArr = AscCommonExcel.getRangeByRef(printArea.ref, t.model, true, true, true) }); if(areaRefsArr && areaRefsArr.length) { res = true; for(var i = 0; i < areaRefsArr.length; i++) { var range = areaRefsArr[i]; //todo проверирить если есть валидные области, нужно ли в данном случае сразу возвращать false if(range && range.bbox) { range = range.bbox; } else { return false; } for(var j = 0; j < selection.length; j++) { if(selection[j].intersection(range)) { return false; } } } } } return res; }; WorksheetView.prototype.changeRowColBreaks = function (from, to, range, byCol, opt_handle_move) { var t = this; if (from === -1 || to === -1) { return; } var onChangeCallback = function (isSuccess) { if (false === isSuccess) { return; } History.Create_NewPoint(); History.StartTransaction(); //remove all breaks on path(from->to) if (opt_handle_move) { let reverse = from > to; let firstIndex = !reverse ? from : to; let lastIndex = !reverse ? to : from; for (let i = firstIndex; i <= lastIndex; i++) { if (i === from) { continue; } t.model.changeRowColBreaks(i, null, range, byCol, true); } } t.model.changeRowColBreaks(from, to, range, byCol, true); t.changeViewPrintLines(true); if(t.viewPrintLines) { t.updateSelection(); } window["Asc"]["editor"]._onUpdateLayoutMenu(t.model.Id); History.EndTransaction(); }; //do lock print settings this._isLockedLayoutOptions(onChangeCallback); }; WorksheetView.prototype.insertPageBreak = function () { let t = this; let onChangeCallback = function (isSuccess) { if (false === isSuccess) { return; } History.Create_NewPoint(); History.StartTransaction(); if (!addedRowBreak) { t.model.changeRowColBreaks(null, activeCell.row, range, null, true); } if (!addedColBreak) { t.model.changeRowColBreaks(null, activeCell.col, range, true, true); } t.changeViewPrintLines(true); if(t.viewPrintLines) { t.updateSelection(); } window["Asc"]["editor"]._onUpdateLayoutMenu(t.model.Id); History.EndTransaction(); }; let activeCell = t.model.getSelection().activeCell; let range = t.model.getPrintAreaRangeByRowCol(activeCell.row, activeCell.col); let addedRowBreak = t.model.isBreak(activeCell.row, range); let addedColBreak = t.model.isBreak(activeCell.col, range, true); //do lock print settings if (!addedRowBreak || !addedColBreak) { this._isLockedLayoutOptions(onChangeCallback); } }; WorksheetView.prototype.removePageBreak = function () { let t = this; let onChangeCallback = function (isSuccess) { if (false === isSuccess) { return; } History.Create_NewPoint(); History.StartTransaction(); let activeCell = t.model.getSelection().activeCell; let range = t.model.getPrintAreaRangeByRowCol(activeCell.row, activeCell.col); t.model.changeRowColBreaks(activeCell.row, null, range, null, true); t.model.changeRowColBreaks(activeCell.col, null, range, true, true); t.changeViewPrintLines(true); if(t.viewPrintLines) { t.updateSelection(); } window["Asc"]["editor"]._onUpdateLayoutMenu(t.model.Id); History.EndTransaction(); }; //do lock print settings this._isLockedLayoutOptions(onChangeCallback); }; WorksheetView.prototype.resetAllPageBreaks = function () { let t = this; let onChangeCallback = function (isSuccess) { if (false === isSuccess) { return; } History.Create_NewPoint(); History.StartTransaction(); t.model.resetAllPageBreaks(); t.changeViewPrintLines(true); if(t.viewPrintLines) { t.updateSelection(); } window["Asc"]["editor"]._onUpdateLayoutMenu(t.model.Id); History.EndTransaction(); }; //do lock print settings this._isLockedLayoutOptions(onChangeCallback); }; WorksheetView.prototype.changePrintTitles = function (cols, rows) { var t = this; var onChangePrintTitles = function (isSuccess) { if (false === isSuccess) { return; } History.Create_NewPoint(); History.StartTransaction(); t._changePrintTitles(cols, rows); t.changeViewPrintLines(true); if(t.viewPrintLines) { t.updateSelection(); } window["Asc"]["editor"]._onUpdateLayoutMenu(t.model.Id); History.EndTransaction(); }; //лочу по аналогии со всеми опциями из print settings this._isLockedLayoutOptions(onChangePrintTitles); }; WorksheetView.prototype.getPrintTitlesRange = function (prop, byCol) { var res = null; var t = this; switch (prop) { case Asc.c_oAscPrintTitlesRangeType.first: { if(byCol) { res = new Asc.Range(0, 0, 0, gc_nMaxRow0); } else { res = new Asc.Range(0, 0, gc_nMaxCol0, 0); } break; } case Asc.c_oAscPrintTitlesRangeType.frozen: { if(this.topLeftFrozenCell) { if(byCol) { var cFrozen = this.topLeftFrozenCell.getCol0(); res = new Asc.Range(0, 0, cFrozen, gc_nMaxRow0); } else { var rFrozen = this.topLeftFrozenCell.getRow0(); res = new Asc.Range(0, 0, gc_nMaxCol0, rFrozen); } } break; } case Asc.c_oAscPrintTitlesRangeType.current: { var printTitles = this.model.workbook.getDefinesNames("Print_Titles", this.model.getId()); var c1, c2, r1, r2; if (printTitles) { var printTitleRefs; AscCommonExcel.executeInR1C1Mode(false, function () { printTitleRefs = AscCommonExcel.getRangeByRef(printTitles.ref, t.model, true, true) }); if (printTitleRefs && printTitleRefs.length) { for (var i = 0; i < printTitleRefs.length; i++) { var bbox = printTitleRefs[i].bbox; if (bbox) { if (c_oAscSelectionType.RangeCol === bbox.getType()) { c1 = bbox.c1; c2 = bbox.c2; } else if(c_oAscSelectionType.RangeRow === bbox.getType()) { r1 = bbox.r1; r2 = bbox.r2; } } } } } if (byCol && c1 !== undefined) { res = new Asc.Range(c1, 0, c2, gc_nMaxRow0); } else if(r1 !== undefined && !byCol) { res = new Asc.Range(0, r1, gc_nMaxCol0, r2); } break; } } return res ? res.getAbsName() : null; }; WorksheetView.prototype._changePrintTitles = function (cols, rows) { var t = this; var _convertRangeStr = function(_val, _byCols) { var _res; //из интерфейса приходит в виду g_R1C1Mode AscCommonExcel.executeInR1C1Mode(AscCommonExcel.g_R1C1Mode, function () { _res = AscCommonExcel.g_oRangeCache.getAscRange(_val); }); _res = _byCols ? new Asc.Range(_res.c1, 0, _res.c2, gc_nMaxRow0) : new Asc.Range(0, _res.r1, gc_nMaxCol0, _res.r2); //в модель ->в виде A1B1 AscCommonExcel.executeInR1C1Mode(false, function () { _res = parserHelp.get3DRef(t.model.getName(), _res.getAbsName()); }); return _res; }; History.Create_NewPoint(); History.StartTransaction(); var printTitles = this.model.workbook.getDefinesNames("Print_Titles", this.model.getId()); var oldDefName = printTitles ? printTitles.getAscCDefName() : null; var oldScope = oldDefName ? oldDefName.asc_getScope() : this.model.index; var newRef; if(cols) { newRef = _convertRangeStr(cols, true); } if(rows) { newRef = (newRef ? (newRef + ',') : '') + _convertRangeStr(rows); } if(!newRef) { if(printTitles) { this.workbook.delDefinedNames(printTitles.getAscCDefName()); } } else { var newDefName = new Asc.asc_CDefName("Print_Titles", newRef, oldScope, null, null, null, true); this.workbook.editDefinedNames(oldDefName, newDefName); } History.EndTransaction(); }; WorksheetView.prototype.changeViewPrintLines = function (val) { this.viewPrintLines = val; }; WorksheetView.prototype.getRangeText = function (range, delimiter) { var t = this; if (range === undefined) { range = this.model.selectionRange.getLast(); } if(delimiter === undefined) { delimiter = "\n"; } var firstDefCell; var res = ""; var bImptyText = true; var maxRow = Math.min(range.r2, t.rows.length - 1); this.model.getRange3(range.r1, range.c1, maxRow, range.c2)._foreach2(function(cell, r, c) { if(cell !== null) { var text = cell.getValueForEdit(); //извлекаем тест до первого переноса строки //TODO ms в данном случае показывает на первом preview всю ячейку в одну строку, а на втором preview обрубает до первого переноса строки text = text.split(/\r?\n/)[0]; if(text !== "") { res += text; bImptyText = false; } firstDefCell = true; } if(r !== maxRow && firstDefCell) { res += delimiter; } }); return bImptyText ? "" : res; }; //GROUP DATA FUNCTIONS WorksheetView.prototype._updateGroups = function(bCol, start, end, bUpdateOnlyRowLevelMap, bUpdateOnlyRange) { if (this.workbook.getDrawRestriction("groups")) { this.groupHeight = 0; this.groupWidth = 0; return; } if(bCol) { if(bUpdateOnlyRowLevelMap) { //this.arrColGroups.levelMap = this.getGroupDataArray(bCol, start, end, bUpdateOnlyRowLevelMap, bUpdateOnlyRange).levelMap; } else { this.arrColGroups = this.getGroupDataArray(bCol, start, end); var oldGroupHeight = this.groupHeight; this.groupHeight = this.getGroupCommonWidth(this.getGroupCommonLevel(bCol), bCol); //TODO пересмотреть! добавлено, потому что при undo не вызывается if(oldGroupHeight !== this.groupHeight) { this._calcHeaderRowHeight(); } } } else { if(bUpdateOnlyRowLevelMap) { //this.arrRowGroups.levelMap = this.getGroupDataArray(bCol, start, end, bUpdateOnlyRowLevelMap, bUpdateOnlyRange).levelMap; } else { this.arrRowGroups = this.getGroupDataArray(bCol, start, end); this.groupWidth = this.getGroupCommonWidth(this.getGroupCommonLevel()); } } }; WorksheetView.prototype._updateGroupsWidth = function() { if (this.workbook.getDrawRestriction("groups")) { return; } this.groupHeight = this.getGroupCommonWidth(this.getGroupCommonLevel(true), true); this.groupWidth = this.getGroupCommonWidth(this.getGroupCommonLevel()); }; WorksheetView.prototype.getGroupDataArray = function (bCol, start, end, bUpdateOnlyRowLevelMap, bUpdateOnlyRange) { //проходимся по диапазону, и проверяем верхние/нижние строчки на наличия в них аттрибута outLineLevel //возможно стоит добавить кэш для отрисовки if(start === undefined) { start = 0; end = bCol ? gc_nMaxCol : gc_nMaxRow; } /*var levelMap = {}; if(bUpdateOnlyRange) { if(bCol && this.arrColGroups && this.arrColGroups.levelMap) { levelMap = this.arrColGroups.levelMap; } else if(this.arrRowGroups && this.arrRowGroups.levelMap) { levelMap = this.arrRowGroups.levelMap; } }*/ var res = null; var up = true, down = true; var fProcess = function(val){ var outLineLevel = val ? val.getOutlineLevel() : null; //levelMap[val.index] = {level: outLineLevel, collapsed: false}; if(bUpdateOnlyRowLevelMap) { return; } var continueRange = function(level, index) { var tempNeedPush = true; if(!res[level] || undefined === res[level][index]) { return true; } if(val.index === res[level][index].start - 1) { res[level][index].start--; tempNeedPush = false; } else if(val.index === res[level][index].end + 1) { res[level][index].end++; tempNeedPush = false; } else if(val.index >= res[level][index].start && val.index <= res[level][index].end) { tempNeedPush = false; } return tempNeedPush; }; if(!outLineLevel) { if(start === val.index) { up = false; } else if(end === val.index) { down = false; } } else { if(!res) { res = []; } if(!res[outLineLevel]) { res[outLineLevel] = []; } var needPush = true; for(var j = 0; j < res[outLineLevel].length; j++) { if(!continueRange(outLineLevel, j)) { needPush = false; break; } } if(needPush) { res[outLineLevel].push({start: val.index, end: val.index}); } //расширяем предыдущие(младшие) уровни //для того что - младший уровень не может быть меньше старшего for(var n = 1; n < outLineLevel; n++) { var bAdd = false; if(!res[n]) { bAdd = true; if(res[outLineLevel]) { res[n] = [{start: res[outLineLevel][res[outLineLevel].length - 1].start, end: res[outLineLevel][res[outLineLevel].length - 1].end}]; } else { res[n] = []; } } var bContinue = false; for(var m = 0; m < res[n].length; m++) { if(!continueRange(n, m)) { bContinue = true; } } //если не расширен данный(предыдущий) уровень или не добавлен новый элемент, тогда в него добавляем строки текущего if(!bContinue && !bAdd) { res[n].push({start: res[outLineLevel][res[outLineLevel].length - 1].start, end: res[outLineLevel][res[outLineLevel].length - 1].end}); } } } }; var _allProps = bCol ? this.model.oAllCol : null/*this.model.oSheetFormatPr.oAllRow*/; var allOutLineLevel = _allProps ? _allProps.getOutlineLevel() : 0; if(!allOutLineLevel) { //allOutLineLevel = bCol ? this.model.oSheetFormatPr.nOutlineLevelCol : null/*this.model.oSheetFormatPr.nOutlineLevelRow*/; } if(allOutLineLevel) { if(!res) { res = []; } if(!res[allOutLineLevel]) { res[allOutLineLevel] = []; } res[allOutLineLevel].push({start: 0, end: bCol ? gc_nMaxCol0 : gc_nMaxRow0}); } if(bCol) { this.model.getRange3(0, start, 0, end)._foreachColNoEmpty(fProcess); } else { this.model.getRange3(start, 0, end, 0)._foreachRowNoEmpty(fProcess); } if(!bUpdateOnlyRange) { while(up) { start--; if(start < 0) { break; } bCol ? fProcess(this.model._getColNoEmptyWithAll(start)) : this.model._getRowNoEmptyWithAll(start, fProcess); } var maxCount = bCol ? this.model.getColsCount() : this.model.getRowsCount(); var cMaxCount = bCol ? gc_nMaxCol0 : gc_nMaxRow0; while(down) { end++; if(end > maxCount || end > cMaxCount) { break; } bCol ? fProcess(this.model._getColNoEmptyWithAll(start)) : this.model._getRowNoEmptyWithAll(start, fProcess); } } //TODO возможно стоит вначале пройтись по старому groupArr и проставить всем столбцам/строкам false - могут быть проблемы при удалении всех групп и тд //val.setCollapsed(false); //вычисляем опцию collapsed уже после основных вычислений //связано с тем, что она проставляется в строке/столбце, следующей за последней в группе //если последний столбец/строка скрыты, то в следующей ячейке необходимо проставить collapsed = true //не записываю в историю, а высчитываю каждый раз здесь в связи с тем // что при удалении столбца/строки с данным свойством, оно переходит следующему столбцу/строке, те столбцу/строке //следующему за последней скрытой в группе //TODO рассмотреть: запись свойства collapsed только на сохранение var groupArr, index, i, j; if(res) { groupArr = bCol ? this.arrColGroups : this.arrRowGroups; groupArr = groupArr ? groupArr.groupArr : null; if(groupArr) { for(i = 0; i < groupArr.length; i++) { if (groupArr[i]) { for (j = 0; j < groupArr[i].length; j++) { index = groupArr[i][j].end; } } } } } groupArr = res; if(!groupArr) { groupArr = bCol ? this.arrColGroups : this.arrRowGroups; groupArr = groupArr ? groupArr.groupArr : null; } return {groupArr: res/*, levelMap: levelMap*/}; }; WorksheetView.prototype._drawGroupData = function ( drawingCtx, range, leftFieldInPx, topFieldInPx, bCol /*width, height*/ ) { if (this.workbook.getDrawRestriction("groups")) { return; } var t = this; if ( !range ) { range = this.visibleRange; } this._drawGroupDataMenu(drawingCtx, bCol); var ctx = drawingCtx || this.drawingCtx; var offsetX = (undefined !== leftFieldInPx) ? leftFieldInPx : this._getOffsetX(); var offsetY = (undefined !== topFieldInPx) ? topFieldInPx : this._getOffsetY(); if (!drawingCtx && this.topLeftFrozenCell) { if (undefined === leftFieldInPx) { var cFrozen = this.topLeftFrozenCell.getCol0(); offsetX -= this._getColLeft(cFrozen) - this._getColLeft(0); } if (undefined === topFieldInPx) { var rFrozen = this.topLeftFrozenCell.getRow0(); offsetY -= this._getRowTop(rFrozen) - this._getRowTop(0); } } let isClip = null; if (this._clipDrawingRect(ctx, range, bCol ? clipType.groupCols : clipType.groupRows)) { isClip = true; } var zoom = this.getZoom(); if(zoom > 1) { zoom = 1; } var st = this.settings.header.style[kHeaderDefault]; var x1, y1, x2, y2, arrayLines, groupData; var lineWidth = AscCommon.AscBrowser.convertToRetinaValue(2, true); var lineWidthDiff = lineWidth % 2 === 0 ? lineWidth : lineWidth - 0.5; var thickLineDiff = AscCommon.AscBrowser.isCustomScalingAbove2() ? 0.5 : 0; var tempButtonMap = [];//чтобы не рисовать точки там где кпопки var bFirstLine = true; var _buttonSize = this._getGroupButtonSize(); var buttonSize = AscCommon.AscBrowser.convertToRetinaValue(_buttonSize, true); var padding = AscCommon.AscBrowser.convertToRetinaValue(1, true); var buttons = []; var endPosArr = {}; var i, j, l, index, diff, startPos, endPos, paddingTop, pointLevel; if(bCol) { y1 = 0; x1 = this._getColLeft(range.c1) - offsetX; x2 = this._getColLeft(range.c2 + 1) - offsetX; y2 = this.groupHeight; //фон для группировки ctx.setFillStyle(this.settings.header.style[kHeaderDefault].background); this._fillRect(ctx, x1 + (this.getRightToLeft() ? 1 : 0), y1, x2 - x1 + (this.getRightToLeft() ? 1 : 0), y2 - y1); ctx.setStrokeStyle(this.settings.header.editorBorder).setLineWidth(1).beginPath(); this._lineHorPrevPx(ctx, x1, y2, x2); ctx.stroke(); groupData = this.arrColGroups ? this.arrColGroups : this.getGroupDataArray(true, range.r1, range.r2); if(!groupData || !groupData.groupArr) { return; } arrayLines = groupData.groupArr; //rowLevelMap = groupData.levelMap; ctx.setStrokeStyle(this.settings.header.groupDataBorder).setLineWidth(lineWidth).beginPath(); var _summaryRight = this.model.sheetPr ? this.model.sheetPr.SummaryRight : true; var minCol; var maxCol; var startX, endX, widthNextRow, collasedEndRow; for(i = 0; i < arrayLines.length; i++) { if(arrayLines[i]) { index = bFirstLine ? 1 : i; var posY = padding * 2 + buttonSize / 2 - padding + (index - 1) * buttonSize; for(j = 0; j < arrayLines[i].length; j++) { if(_summaryRight) { if(endPosArr[arrayLines[i][j].end]) { continue; } endPosArr[arrayLines[i][j].end] = 1; startX = Math.max(arrayLines[i][j].start, range.c1); endX = Math.min(arrayLines[i][j].end + 1, range.c2 + 1); minCol = (minCol === undefined || minCol > startX) ? startX : minCol; maxCol = (maxCol === undefined || maxCol < endX) ? endX : maxCol; diff = startX === arrayLines[i][j].start ? AscCommon.AscBrowser.convertToRetinaValue(3, true) : 0; startPos = this._getColLeft(startX) + diff - offsetX; endPos = this._getColLeft(endX) - offsetX; widthNextRow = /*this.getColWidth(endX)*/this._getColLeft(endX + 1) - this._getColLeft(endX); paddingTop = (widthNextRow - buttonSize) / 2; if(paddingTop < 0) { paddingTop = 0; } //button if(endX === arrayLines[i][j].end + 1) { //TODO ms обрезает кнопки сверху/снизу if(widthNextRow && endX >= startX) { if(!tempButtonMap[i]) { tempButtonMap[i] = []; } tempButtonMap[i][endX] = 1; buttons.push({r: endX, level: i}); } } if(startPos > endPos) { continue; } collasedEndRow = this._getGroupCollapsed(arrayLines[i][j].end + 1, bCol); //var collasedEndRow = rowLevelMap[arrayLines[i][j].end + 1] && rowLevelMap[arrayLines[i][j].end + 1].collapsed if(!collasedEndRow) { this._lineHorPrevPx(ctx, startPos, posY, endPos + paddingTop); } // _ //| if(!collasedEndRow && startX === arrayLines[i][j].start) { t._lineVerPrevPx(ctx, startPos, posY - lineWidthDiff + thickLineDiff, posY + 4 * padding); } } else { if(endPosArr[arrayLines[i][j].start]) { continue; } endPosArr[arrayLines[i][j].start] = 1; startX = Math.max(arrayLines[i][j].start - 1, range.c1); endX = Math.min(arrayLines[i][j].end + 1, range.c2 + 1); minCol = (minCol === undefined || minCol > startX) ? startX : minCol; maxCol = (maxCol === undefined || maxCol < endX) ? endX : maxCol; diff = /*startX === arrayLines[i][j].start ? AscCommon.AscBrowser.convertToRetinaValue(3, true) :*/ 0; startPos = this._getColLeft(startX) + diff - offsetX; endPos = this._getColLeft(endX) - offsetX; widthNextRow = this._getColLeft(startX + 1) - this._getColLeft(startX); paddingTop = startX === arrayLines[i][j].start - 1 ? (widthNextRow + buttonSize) / 2 : 0; if(paddingTop < 0) { paddingTop = 0; } //button if(startX === arrayLines[i][j].start - 1) { //TODO ms обрезает кнопки сверху/снизу if(widthNextRow && endX >= startX) { if(!tempButtonMap[i]) { tempButtonMap[i] = []; } tempButtonMap[i][startX] = 1; buttons.push({r: startX, level: i}); } } if(startPos > endPos) { continue; } collasedEndRow = this._getGroupCollapsed(arrayLines[i][j].start - 1, bCol); if( endPos > startPos + paddingTop - 1*padding) { if(!collasedEndRow && endPos > startPos + paddingTop - 1*padding) { //ctx.lineVerPrevPx(posX, startPos - paddingTop - 1*padding, endPos); t._lineHorPrevPx(ctx, startPos + paddingTop - 1*padding, posY, endPos); } // _ // | if(!collasedEndRow && endX === arrayLines[i][j].end + 1 && endPos > startPos + paddingTop - 1*padding) { //this._lineHorPrevPx(ctx, posX - lineWidth + thickLineDiff, endPos, posX + 4*padding); t._lineVerPrevPx(ctx, endPos, posY - lineWidthDiff + thickLineDiff, posY + 4 * padding); } } } } bFirstLine = false; } } //TODO не рисовать точки на местах линий и кнопок for(l = minCol; l < maxCol; l++) { pointLevel = this._getGroupLevel(l, bCol); /*if(!rowLevelMap[l]) { continue; } pointLevel = rowLevelMap[l].level;*/ var colWidth = /*this.getColWidth(endX)*/this._getColLeft(l + 1) - this._getColLeft(l); if(pointLevel === 0 || (tempButtonMap[pointLevel + 1] && tempButtonMap[pointLevel + 1][l]) || colWidth === 0) { continue; } t._lineVerPrevPx(ctx, this._getColLeft(l) - offsetX + colWidth / 2, 7 * padding + pointLevel * buttonSize, 7 * padding + (pointLevel) * buttonSize + 2 * padding); //this._lineHorPrevPx(ctx, 7 + pointLevel * buttonSize, this._getRowTop(l) - offsetY + colWidth / 2, 7 + (pointLevel) * buttonSize + 2); } ctx.stroke(); ctx.closePath(); } else { x1 = 0; y1 = this._getRowTop(range.r1) - offsetY; x2 = this.groupWidth; y2 = this._getRowTop(range.r2 + 1) - offsetY; ctx.setFillStyle(this.settings.header.style[kHeaderDefault].background); t._fillRect(ctx, x1, y1, x2 - x1, y2 - y1); ctx.setStrokeStyle(this.settings.header.editorBorder).setLineWidth(1).beginPath(); t._lineVerPrevPx(ctx, x2 - (this.getRightToLeft() ? 1 : 0), y1, y2); ctx.stroke(); groupData = this.arrRowGroups ? this.arrRowGroups : this.getGroupDataArray(null, range.r1, range.r2); if(!groupData || !groupData.groupArr) { return; } arrayLines = groupData.groupArr; //rowLevelMap = groupData.levelMap; ctx.setStrokeStyle(this.settings.header.groupDataBorder).setLineWidth(lineWidth).beginPath(); var checkPrevHideLevel = function(level, row) { var res = false; for(var n = level - 1; n >= 0; n--) { if(arrayLines[n]) { for(var m = 0; m < arrayLines[n].length; m++) { if (row >= arrayLines[n][m].start && row <= arrayLines[n][m].end && t._getGroupCollapsed(arrayLines[n][m].start - 1)) { res = true; break; } } } } return res; }; var _summaryBelow = this.model.sheetPr ? this.model.sheetPr.SummaryBelow : true; var minRow; var maxRow; var startY, endY, heightNextRow; for(i = 0; i < arrayLines.length; i++) { if(arrayLines[i]) { index = bFirstLine ? 1 : i; var posX = padding * 2 + buttonSize / 2 - padding + (index - 1) * buttonSize; for(j = 0; j < arrayLines[i].length; j++) { if(_summaryBelow) { if(endPosArr[arrayLines[i][j].end]) { continue; } endPosArr[arrayLines[i][j].end] = 1; startY = Math.max(arrayLines[i][j].start, range.r1); endY = Math.min(arrayLines[i][j].end + 1, range.r2 + 1); minRow = (minRow === undefined || minRow > startY) ? startY : minRow; maxRow = (maxRow === undefined || maxRow < endY) ? endY : maxRow; diff = startY === arrayLines[i][j].start ? 3 * padding : 0; startPos = this._getRowTop(startY) + diff - offsetY; endPos = this._getRowTop(endY) - offsetY; heightNextRow = this._getRowHeight(endY); paddingTop = (heightNextRow - buttonSize) / 2; if(paddingTop < 0) { paddingTop = 0; } //button if(endY === arrayLines[i][j].end + 1) { //TODO ms обрезает кнопки сверху/снизу if(heightNextRow && endY >= startY) { if(!tempButtonMap[i]) { tempButtonMap[i] = []; } tempButtonMap[i][endY] = 1; buttons.push({r: endY, level: i}); } } if(startPos > endPos) { continue; } var collasedEndCol = this._getGroupCollapsed(arrayLines[i][j].end + 1); //var collasedEndCol = rowLevelMap[arrayLines[i][j].end + 1] && rowLevelMap[arrayLines[i][j].end + 1].collapsed; if(!collasedEndCol) { this._lineVerPrevPx(ctx, posX - this.getRightToLeftOffset(), startPos, endPos + paddingTop); } // _ //| if(!collasedEndCol && startY === arrayLines[i][j].start) { this._lineHorPrevPx(ctx, posX - lineWidthDiff + thickLineDiff + this.getRightToLeftOffset(), startPos, posX + 4*padding + this.getRightToLeftOffset()); } } else { if(endPosArr[arrayLines[i][j].start]) { continue; } endPosArr[arrayLines[i][j].start] = 1; startY = Math.max(arrayLines[i][j].start - 1, range.r1); endY = Math.min(arrayLines[i][j].end + 1, range.r2 + 1); minRow = (minRow === undefined || minRow > startY) ? startY : minRow; maxRow = (maxRow === undefined || maxRow < endY) ? endY : maxRow; diff = /*startY === arrayLines[i][j].start - 1 ? 3 * padding :*/ 0; startPos = (startY === arrayLines[i][j].start - 1 ? this._getRowTop(startY + 1) : this._getRowTop(startY)) + diff - offsetY; endPos = this._getRowTop(endY) - offsetY; heightNextRow = this._getRowHeight(startY); paddingTop = startY === arrayLines[i][j].start - 1 ? (heightNextRow - buttonSize) / 2 : 0; if(paddingTop < 0) { paddingTop = 0; } //button if(startY === arrayLines[i][j].start - 1) { //TODO ms обрезает кнопки сверху/снизу if(heightNextRow && endY >= startY) { if(!tempButtonMap[i]) { tempButtonMap[i] = []; } tempButtonMap[i][startY] = 1; buttons.push({r: startY, level: i}); } } if(startPos > endPos) { continue; } if(endPos > startPos - paddingTop - 1*padding) { var collapsedStartRow = this._getGroupCollapsed(arrayLines[i][j].start - 1); var hiddenStartRow = this._getHidden(arrayLines[i][j].start); if(!collapsedStartRow && !hiddenStartRow) { this._lineVerPrevPx(ctx, posX, startPos - paddingTop - 1*padding, endPos); } // |_ if(!collapsedStartRow && !hiddenStartRow && endY === arrayLines[i][j].end + 1 && !checkPrevHideLevel(i, arrayLines[i][j].start)) { this._lineHorPrevPx(ctx, posX - lineWidthDiff + thickLineDiff, endPos, posX + 4*padding); } } } } bFirstLine = false; } } //TODO не рисовать точки на местах линий и кнопок for(l = minRow; l < maxRow; l++) { pointLevel = this._getGroupLevel(l, bCol); /*if(!rowLevelMap[l]) { continue; } pointLevel = rowLevelMap[l].level;*/ var rowHeight = this._getRowHeight(l); if(pointLevel === 0 || (tempButtonMap[pointLevel + 1] && tempButtonMap[pointLevel + 1][l]) || rowHeight === 0) { continue; } this._lineHorPrevPx(ctx, padding * 7 + pointLevel * buttonSize, this._getRowTop(l) - offsetY + rowHeight / 2, padding * 7 + (pointLevel) * buttonSize + padding * 2); } ctx.stroke(); ctx.closePath(); } if (isClip) { this._RemoveClipRect(ctx); } this._drawGroupDataButtons(drawingCtx, buttons, leftFieldInPx, topFieldInPx, bCol); }; WorksheetView.prototype._drawGroupDataButtons = function(drawingCtx, buttons, leftFieldInPx, topFieldInPx, bCol) { if (this.workbook.getDrawRestriction("groups")) { return; } if(!buttons) { return; } var groupData = bCol ? this.arrColGroups : this.arrRowGroups; if(!groupData || !groupData.groupArr) { return; } //var rowLevelMap = groupData.levelMap; var ctx = drawingCtx || this.drawingCtx; var offsetX = 0, offsetY = 0; if(bCol) { offsetX = (undefined !== leftFieldInPx) ? leftFieldInPx : this._getOffsetX(); if (!drawingCtx && this.topLeftFrozenCell) { if (undefined === leftFieldInPx) { var cFrozen = this.topLeftFrozenCell.getCol0(); offsetX -= this._getColLeft(cFrozen) - this._getColLeft(0); } } } else { offsetY = (undefined !== topFieldInPx) ? topFieldInPx : this._getOffsetY(); if (!drawingCtx && this.topLeftFrozenCell) { if (undefined === topFieldInPx) { var rFrozen = this.topLeftFrozenCell.getRow0(); offsetY -= this._getRowTop(rFrozen) - this._getRowTop(0); } } } //buttons //проходимся 2 раза, поскольку разная толщина у рамки и у -/+ var i, val, level, diff, pos, x, y, w, h, active; var borderSize = AscCommon.AscBrowser.convertToRetinaValue(1, true); ctx.setStrokeStyle(this.settings.header.groupDataBorder).setLineWidth( borderSize ).beginPath(); for(i = 0; i < buttons.length; i++) { val = buttons[i].r; level = buttons[i].level; pos = this._getGroupDataButtonPos(val, level, bCol); x = pos.x; y = pos.y; w = pos.w; h = pos.h; x = x - offsetX; y = y - offsetY; this._AddClipRect(ctx, bCol ? pos.pos - borderSize - offsetX : x - borderSize, bCol ? y - borderSize : pos.pos - borderSize - offsetY, bCol ? pos.size + borderSize : w + borderSize + this.getRightToLeftOffset(), bCol ? h + borderSize : pos.size + borderSize); ctx.beginPath(); if(buttons[i].clean) { this._clearRect(ctx, x, y, w, h); } this._lineHorPrevPx(ctx, x, y, x + w + this.getRightToLeftOffset()); this._lineHorPrevPx(ctx, x + w, y + h, x); this._lineVerPrevPx(ctx, x + w, y, y + h); this._lineVerPrevPx(ctx, x, y + h, y - borderSize); ctx.stroke(); this._RemoveClipRect(ctx); } ctx.closePath(); ctx.setStrokeStyle(this.settings.header.groupDataBorder).setLineWidth( AscCommon.AscBrowser.convertToRetinaValue(2, true)).beginPath(); var sizeLine = AscCommon.AscBrowser.convertToRetinaValue(8, true); //var paddingLine = AscCommon.AscBrowser.convertToRetinaValue(3, true); diff = AscCommon.AscBrowser.convertToRetinaValue(1, true); for(i = 0; i < buttons.length; i++) { val = buttons[i].r; level = buttons[i].level; active = buttons[i].active; diff = active ? 1 : 0; pos = this._getGroupDataButtonPos(val, level, bCol); x = pos.x; y = pos.y; w = pos.w; h = pos.h; x = x - offsetX; y = y - offsetY; this._AddClipRect(ctx, bCol ? pos.pos - offsetX : x, bCol ? y : pos.pos - offsetY, bCol ? pos.size : w, bCol ? h : pos.size); ctx.beginPath(); var paddingLine = Math.floor((w - sizeLine - borderSize) / 2); if(w > sizeLine + 2) { if(this._getGroupCollapsed(val, bCol)/*rowLevelMap[val] && rowLevelMap[val].collapsed*/) { this._lineHorPrevPx(ctx, x + paddingLine + this.getRightToLeftOffset(), y + h / 2 + 1, x + sizeLine + paddingLine + this.getRightToLeftOffset()); this._lineVerPrevPx(ctx, x + paddingLine + sizeLine / 2 + 1 - this.getRightToLeftOffset(), y + h / 2 - sizeLine / 2, y + h / 2 + sizeLine / 2); } else { x += this.getRightToLeftOffset(); this._lineHorPrevPx(ctx, x + paddingLine, y + h / 2 + diff, x + sizeLine + paddingLine); } } ctx.stroke(); this._RemoveClipRect(ctx); } ctx.closePath(); }; WorksheetView.prototype._getGroupDataButtonPos = function(val, level, bCol) { //возвращает позицию без учета сдвига offsetY var zoom = this.getZoom(); if(zoom > 1) { zoom = 1; } var _buttonSize = this._getGroupButtonSize(); var buttonSize = AscCommon.AscBrowser.convertToRetinaValue(_buttonSize, true); var padding = AscCommon.AscBrowser.convertToRetinaValue(1, true); if(bCol) { var endPosX = this._getColLeft(val); var colW = this._getColLeft(val + 1) - this._getColLeft(val); var posY = padding * 2 + buttonSize / 2 - padding + (level - 1) * buttonSize; x = endPosX + colW/2 - buttonSize / 2; y = posY - Math.floor(AscCommon.AscBrowser.convertToRetinaValue(6, true) * zoom); } else { var endPosY = this._getRowTop(val); var rowH = this._getRowHeight(val); var posX = padding * 2 + buttonSize / 2 - padding + (level - 1) * buttonSize; var x = posX - Math.floor(AscCommon.AscBrowser.convertToRetinaValue(6, true) * zoom); var y = endPosY + rowH/2 - buttonSize / 2; } var w = buttonSize - padding; var h = buttonSize - padding; return {x: x, y: y, w: w, h: h, size: bCol ? colW : rowH, pos: bCol ? endPosX : endPosY}; }; WorksheetView.prototype._getGroupLevel = function(index, bCol) { var res; var fProcess = function(val) { res = val ? val.getOutlineLevel() : 0; }; bCol ? fProcess(this.model._getColNoEmptyWithAll(index)) : this.model._getRowNoEmptyWithAll(index, fProcess); return res; }; WorksheetView.prototype._getGroupCollapsed = function(index, bCol) { var res; var getCollapsed = function(val) { res = val ? val.getCollapsed() : false; }; bCol ? getCollapsed(this.model._getColNoEmptyWithAll(index)) : this.model._getRowNoEmptyWithAll(index, getCollapsed); return res; }; WorksheetView.prototype._getHidden = function(index, bCol) { var res; var callback = function(val) { res = val ? val.getHidden() : false; }; bCol ? callback(this.model._getColNoEmptyWithAll(index)) : this.model._getRowNoEmptyWithAll(index, callback); return res; }; //GROUP MENU BUTTONS WorksheetView.prototype._drawGroupDataMenu = function ( drawingCtx, bCol ) { var ctx = drawingCtx || this.drawingCtx; var groupData; if(bCol) { groupData = this.arrColGroups ? this.arrColGroups : null; } else { groupData = this.arrRowGroups ? this.arrRowGroups : null; } if(!groupData || !groupData.groupArr) { return; } var st = this.settings.header.style[kHeaderDefault]; var x1, y1, x2, y2; if(bCol) { x1 = this.headersLeft; y1 = 0; x2 = this.headersLeft + this.headersWidth; y2 = this.groupHeight; } else { x1 = 0; y1 = this.headersTop; x2 = this.groupWidth; y2 = this.headersTop + this.headersHeight; } ctx.setFillStyle(st.background); this._fillRect(ctx, x1, y1, x2 - x1, y2 - y1); //угол до кнопок ctx.setFillStyle(st.background); this._fillRect(ctx, 0, 0, this.headersLeft, this.headersTop); ctx.setStrokeStyle(this.settings.header.editorBorder).setLineWidth(1).beginPath(); this._lineHorPrevPx(ctx, x1, y2, x2); this._lineVerPrevPx(ctx, x2, y1, y2); //угол до кнопок this._lineHorPrevPx(ctx, 0, this.headersTop, this.headersLeft); this._lineVerPrevPx(ctx, this.headersLeft, 0, this.headersTop); ctx.stroke(); ctx.closePath(); if(false === this.model.getSheetView().asc_getShowRowColHeaders()) { return; } if(groupData.groupArr.length) { for(var i = 0; i < groupData.groupArr.length; i++) { this._drawGroupDataMenuButton(ctx, i, null, null, bCol); } ctx.stroke(); ctx.closePath(); } }; WorksheetView.prototype._drawGroupDataMenuButton = function ( drawingCtx, level, bActive, bClean, bCol ) { if (this.workbook.getDrawRestriction("groups")) { return; } var ctx = drawingCtx || this.drawingCtx; var st = this.settings.header.style[kHeaderDefault]; var props = this.getGroupDataMenuButPos(level, bCol); var x = props.x; var y = props.y; var w = props.w; var h = props.h; if(bClean) { this._clearRect(this.drawingCtx, x, y, w, h); } ctx.beginPath(); ctx.setStrokeStyle(this.settings.header.style[kHeaderDefault].border).setLineWidth( AscCommon.AscBrowser.convertToRetinaValue(1, true)).beginPath(); this._lineHorPrevPx(ctx, x, y, x + w); this._lineVerPrevPx(ctx, x + w, y, y + h); this._lineHorPrevPx(ctx, x + w, y + h, x); this._lineVerPrevPx(ctx, x, y + h, y - AscCommon.AscBrowser.convertToRetinaValue(1, true)); var text = level + 1 + ""; var sr = this.stringRender; var zoom = 1/*this.getZoom()*/; var factor = asc.round(zoom * 1000) / 1000; var dc = sr.drawingCtx; var oldPpiX = dc.ppiX; var oldPpiY = dc.ppiY; var oldScaleFactor = dc.scaleFactor; dc.ppiX = asc.round(dc.ppiX / dc.scaleFactor * factor * 1000) / 1000; dc.ppiY = asc.round(dc.ppiY / dc.scaleFactor * factor * 1000) / 1000; /*if (AscCommon.AscBrowser.isRetina) { dc.ppiX = AscCommon.AscBrowser.convertToRetinaValue(dc.ppiX, true); dc.ppiY = AscCommon.AscBrowser.convertToRetinaValue(dc.ppiY, true); }*/ dc.scaleFactor = factor; var tm = this._roundTextMetrics(sr.measureString(text)); dc.ppiX = oldPpiX; dc.ppiY = oldPpiY; dc.scaleFactor = oldScaleFactor; if(w > tm.width + 3) { var diff = bActive ? 1 : 0; ctx.setFillStyle(st.color); this._fillText(ctx, text, x + (this.getRightToLeft() ? w : w/2) - tm.width / 2 + diff, y + Asc.round(tm.baseline) + h / 2 - tm.height / 2 + diff, undefined, sr.charWidths); } ctx.stroke(); ctx.closePath(); }; WorksheetView.prototype.getGroupDataMenuButPos = function (level, bCol) { //var buttonSize = AscCommon.AscBrowser.convertToRetinaValue(Math.min(16, bCol ? this.headersWidth : this.headersHeight), true) - 1 * padding; var zoom = this.getZoom(); if(zoom > 1) { zoom = 1; } var _buttonSize = this._getGroupButtonSize(); var padding = AscCommon.AscBrowser.convertToRetinaValue(1, true); var buttonSize = AscCommon.AscBrowser.convertToRetinaValue(_buttonSize, true) - padding; //TODO учитывать будущий отступ для группировке колонок! var x, y; if(bCol) { x = this.headersLeft + this.headersWidth/2 - buttonSize/2; y = padding * 2 + level * (buttonSize + padding); } else { x = padding * 2 + level * (buttonSize + padding); y = this.headersTop + this.headersHeight/2 - buttonSize/2; } return {x: x, y: y, w: buttonSize, h: buttonSize}; }; WorksheetView.prototype.getGroupCommonLevel = function (bCol) { var res = 0; var func = function(elem) { var outLineLevel = elem.getOutlineLevel(); if(outLineLevel && outLineLevel > res) { res = outLineLevel; } }; //TODO пересмотреть общее свойство outlineLevelRow/outlineLevelCol /*var _allProps = bCol ? this.model.getAllCol() : this.model.getAllRow(); var allOutLineLevel = _allProps ? _allProps.getOutlineLevel() : 0;*/ if(bCol) { this.model.getRange3(0, 0, 0, gc_nMaxCol0)._foreachColNoEmpty(func); } else { this.model.getRange3(0, 0, gc_nMaxRow0, 0)._foreachRowNoEmpty(func); } return /*res && allOutLineLevel > res ? allOutLineLevel :*/ res; }; WorksheetView.prototype.getGroupCommonWidth = function (level, bCol) { //width group menu - padding left - 2px, padding right - 2px, 1 section - 16px var zoom = this.getZoom(); if(zoom > 1) { zoom = 1; } var res = 0; if(level > 0) { var padding = 2; /*var headersSize; //так как headersHeight и headersWidth рассчитывается после вызова данной функции, рассчитываем ихъ здесь самостоятельно if(!bCol) { headersSize = (false === this.model.getSheetView().asc_getShowRowColHeaders()) ? 0 : Asc.round(this.headersHeightByFont * this.getZoom()); } else { if (false === this.model.getSheetView().asc_getShowRowColHeaders()) { headersSize = 0; } else { // Ширина колонки заголовков считается - max число знаков в строке - перевести в символы - перевести в пикселы var numDigit = Math.max(AscCommonExcel.calcDecades(this.visibleRange.r2 + 1), 3); var nCharCount = this.model.charCountToModelColWidth(numDigit); headersSize = Asc.round(this.model.modelColWidthToColWidth(nCharCount) * this.getZoom()); } }*/ var _buttonSize = this._getGroupButtonSize(); res = padding * 2 + _buttonSize + _buttonSize * level; } return AscCommon.AscBrowser.convertToRetinaValue(res, true); }; WorksheetView.prototype._getGroupButtonSize = function () { var zoom = this.getZoom(); if(zoom > 1) { zoom = 1; } //var headersWidth = this.headersWidth; //if(!headersWidth) { var numDigit = Math.max(AscCommonExcel.calcDecades(this.visibleRange.r2 + 1), 3); var nCharCount = this.model.charCountToModelColWidth(numDigit); var headersWidth = Asc.round(this.model.modelColWidthToColWidth(nCharCount) * zoom * this.getRetinaPixelRatio()); //} //var headersHeight = this.headersHeight; //if(!headersHeight) { var headersHeight = Asc.round(this.headersHeightByFont * zoom); //} return Math.min(Math.floor(16 * zoom), headersWidth - 1, headersHeight - 1); }; WorksheetView.prototype.groupRowClick = function (x, y, target, type) { //разрешаем открывать/скрывать группы во вьювере var viewMode = this.handlers.trigger('getViewMode') || window["Asc"]["editor"].isRestrictionComments(); if(this.collaborativeEditing.getGlobalLock() && !viewMode) { return; } if (this.workbook.getDrawRestriction("groups")) { return; } if (!viewMode) { var currentSheetId = this.model.getId(); var nLockAllType = this.collaborativeEditing.isLockAllOther(currentSheetId); if (Asc.c_oAscMouseMoveLockedObjectType.Sheet === nLockAllType || Asc.c_oAscMouseMoveLockedObjectType.TableProperties === nLockAllType) { return; } } var t = this; var bCol = c_oTargetType.GroupCol === target.target; var offsetX = /*(undefined !== leftFieldInPx) ? leftFieldInPx : */this._getOffsetX(); if (/*!drawingCtx &&*/ this.topLeftFrozenCell) { //if (undefined === leftFieldInPx) { var cFrozen = this.topLeftFrozenCell.getCol0(); offsetX -= this._getColLeft(cFrozen) - this._getColLeft(0); //} } var offsetY = /*(undefined !== topFieldInPx) ? topFieldInPx : */this._getOffsetY(); if (/*!drawingCtx &&*/ this.topLeftFrozenCell) { //if (undefined === topFieldInPx) { var rFrozen = this.topLeftFrozenCell.getRow0(); offsetY -= this._getRowTop(rFrozen) - this._getRowTop(0); //} } if(AscCommon.getPtrEvtName("move") === type) { if(t.clickedGroupButton) { var props; bCol = t.clickedGroupButton.bCol; if(bCol) { offsetY = 0; } else { offsetX = 0; } if(undefined !== t.clickedGroupButton.r) { props = t._getGroupDataButtonPos(t.clickedGroupButton.r, t.clickedGroupButton.level, bCol); if(props) { if (x >= props.x - offsetX && x <= props.x + props.w - offsetX && y >= props.y - offsetY && y <= props.y - offsetY + props.h) { return true; } else { t._drawGroupDataButtons(null, [{r: t.clickedGroupButton.r, level: t.clickedGroupButton.level, active: false, clean: true}], undefined, undefined, bCol); t.clickedGroupButton = null; return false; } } } else { props = this.getGroupDataMenuButPos(t.clickedGroupButton.level, bCol); if(x >= props.x && y >= props.y && x <= props.x + props.w && y <= props.y + props.h) { return true; } else { this._drawGroupDataMenuButton(null, t.clickedGroupButton.level, false, true, bCol); t.clickedGroupButton = null; return false; } } } } if((target.row < 0 && !bCol) || (target.col < 0 && bCol)) { //проверяем, возможно мы попали в одну из кнопок управления уровнями return this._groupRowMenuClick(x, y, target, type, bCol); } if(bCol) { offsetY = 0; } else { offsetX = 0; } var _summaryRight = this.model.sheetPr ? this.model.sheetPr.SummaryRight : true; var _summaryBelow = this.model.sheetPr ? this.model.sheetPr.SummaryBelow : true; var mouseDownClick; var doClick = function() { var arrayLines = bCol ? t.arrColGroups.groupArr : t.arrRowGroups.groupArr; /*var levelMap = bCol ? t.arrColGroups.levelMap : t.arrRowGroups.levelMap;*/ var endPosArr = {}; for(var i = 0; i < arrayLines.length; i++) { var props, collapsed; if(arrayLines[i]) { for(var j = 0; j < arrayLines[i].length; j++) { if((!bCol && !_summaryBelow) || (bCol && !_summaryRight)) { if(endPosArr[arrayLines[i][j].start]) { continue; } endPosArr[arrayLines[i][j].start] = 1; if((arrayLines[i][j].start - 1 === target.row && !bCol) || (arrayLines[i][j].start - 1 === target.col && bCol)) { props = t._getGroupDataButtonPos(arrayLines[i][j].start - 1, i, bCol); collapsed = t._getGroupCollapsed(arrayLines[i][j].start - 1, bCol);/*levelMap[arrayLines[i][j].end + 1] && levelMap[arrayLines[i][j].end + 1].collapsed*/ if(props) { if(x >= props.x - offsetX && x <= props.x + props.w - offsetX && y >= props.y - offsetY && y <= props.y - offsetY + props.h) { if(AscCommon.getPtrEvtName("up") === type) { t._tryChangeGroup(arrayLines[i][j], collapsed, i, bCol); t.clickedGroupButton = null; } else if(AscCommon.getPtrEvtName("down") === type) { //перерисовываем кнопку в нажатом состоянии t._drawGroupDataButtons(null, [{r: arrayLines[i][j].start - 1, level: i, active: true, clean: true}], undefined, undefined, bCol); t.clickedGroupButton = {level: i, r: arrayLines[i][j].start - 1, bCol: bCol}; mouseDownClick = true; } return; } } } } else { if(endPosArr[arrayLines[i][j].end]) { continue; } endPosArr[arrayLines[i][j].end] = 1; if((arrayLines[i][j].end + 1 === target.row && !bCol) || (arrayLines[i][j].end + 1 === target.col && bCol)) { props = t._getGroupDataButtonPos(arrayLines[i][j].end + 1, i, bCol); collapsed = t._getGroupCollapsed(arrayLines[i][j].end + 1, bCol);/*levelMap[arrayLines[i][j].end + 1] && levelMap[arrayLines[i][j].end + 1].collapsed*/ x = t.checkRtl(x); if(props) { if(x >= props.x - offsetX && x <= props.x + props.w - offsetX && y >= props.y - offsetY && y <= props.y - offsetY + props.h) { if(AscCommon.getPtrEvtName("up") === type) { t._tryChangeGroup(arrayLines[i][j], collapsed, i, bCol); t.clickedGroupButton = null; } else if(AscCommon.getPtrEvtName("down") === type) { //перерисовываем кнопку в нажатом состоянии t._drawGroupDataButtons(null, [{r: arrayLines[i][j].end + 1, level: i, active: true, clean: true}], undefined, undefined, bCol); t.clickedGroupButton = {level: i, r: arrayLines[i][j].end + 1, bCol: bCol}; mouseDownClick = true; } return; } } } } } } } }; var prevOutlineLevel = null; var outLineLevel; var func = function(val) { if(prevOutlineLevel === null) { prevOutlineLevel = val.getOutlineLevel(); } else { outLineLevel = val.getOutlineLevel(); } }; if(bCol) { //TODO не учитывается oAllCol if(_summaryRight) { this.model.getRange3(0, target.col - 1,0, target.col)._foreachColNoEmpty(func); } else { this.model.getRange3(0, target.col,0, target.col + 1)._foreachColNoEmpty(func); } } else { if(_summaryBelow) { this.model.getRange3(target.row - 1, 0, target.row, 0)._foreachRowNoEmpty(func); } else { this.model.getRange3(target.row, 0, target.row + 1, 0)._foreachRowNoEmpty(func); } } //проверяем предыдущую строку - если там есть outLineLevel, а в следующей outLineLevel c другим индексом, тогда в следующей может быть кнопка управления группой if(outLineLevel !== prevOutlineLevel) { doClick(); } if(mouseDownClick) { return true; } }; WorksheetView.prototype._groupRowMenuClick = function (x, y, target, type, bCol) { //разрешаем открывать/скрывать группы во вьювере var viewMode = this.handlers.trigger('getViewMode') || window["Asc"]["editor"].isRestrictionComments(); if(this.collaborativeEditing.getGlobalLock() && !viewMode) { return; } if (this.workbook.getDrawRestriction("groups")) { return; } if (!viewMode) { var currentSheetId = this.model.getId(); var nLockAllType = this.collaborativeEditing.isLockAllOther(currentSheetId); if (Asc.c_oAscMouseMoveLockedObjectType.Sheet === nLockAllType || Asc.c_oAscMouseMoveLockedObjectType.TableProperties === nLockAllType) { return; } } x = this.checkRtl(x); //TODO для группировки колонок - y должен быть больше поля колонок var bButtonClick = !bCol && x <= this.cellsLeft && this.groupWidth && x < this.groupWidth && y < this.cellsTop; if(!bButtonClick) { bButtonClick = bCol && y <= this.cellsTop && this.groupHeight && y < this.groupHeight && x < this.cellsLeft; } if(bButtonClick) { var groupArr; if(bCol) { groupArr = this.arrColGroups ? this.arrColGroups.groupArr : null; } else { groupArr = this.arrRowGroups ? this.arrRowGroups.groupArr : null; } if(!groupArr) { return; } var props; for(var i = 0; i <= groupArr.length; i++) { props = this.getGroupDataMenuButPos(i, bCol); if(x >= props.x && y >= props.y && x <= props.x + props.w && y <= props.y + props.h) { if("mouseup" === type || "pointerup" === type) { this.hideGroupLevel(i + 1, bCol); this.clickedGroupButton = null; } else if("mousedown" === type || "pointerdown" === type){ this._drawGroupDataMenuButton(null, i, true, true, bCol); this.clickedGroupButton = {level: i, bCol: bCol}; return true; } break; } } } }; WorksheetView.prototype._tryChangeGroup = function (pos, collapsed, level, bCol) { var viewMode = this.handlers.trigger('getViewMode') || window["Asc"]["editor"].isRestrictionComments(); // Проверка глобального лока if (this.collaborativeEditing.getGlobalLock() && !viewMode) { return; } if (this.workbook.getDrawRestriction("groups")) { return; } //при закрытии группы всем внутренним строкам проставляется hidden //при открытии группы проходимся по всем строкам и открываем только те, которые не закрыты внутренними группами //а для тех что закрыты внутренними группами - ещё раз скрыаем их var start = pos.start; var end = pos.end; var t = this; var functionModelAction = null; var onChangeWorksheetCallback = function (isSuccess) { if (false === isSuccess) { return; } if (viewMode) { History.TurnOff(); } asc_applyFunction(functionModelAction); if (viewMode) { History.TurnOn(); } if(bCol) { t._updateAfterChangeGroup(undefined, null, true); } else { t._updateAfterChangeGroup(null, null, true); } }; functionModelAction = function () { var _summaryBelow = t.model.sheetPr ? t.model.sheetPr.SummaryBelow : true; var _summaryRight = t.model.sheetPr ? t.model.sheetPr.SummaryRight : true; var isNeedRecal = !bCol ? t.model.needRecalFormulas(start, end) : null; if(isNeedRecal) { t.model.workbook.dependencyFormulas.lockRecal(); } History.Create_NewPoint(); History.StartTransaction(); var oldExcludeCollapsed = t.model.bExcludeCollapsed; t.model.bExcludeCollapsed = true; var changeModelFunc = bCol ? t.model.setColHidden : t.model.setRowHidden; var collapsedFunction = bCol ? t.model.setCollapsedCol : t.model.setCollapsedRow; if(!collapsed) {//скрываем changeModelFunc.call(t.model, true, start, end); if((!_summaryBelow && !bCol) || (!_summaryRight && bCol)) { collapsedFunction.call(t.model, !collapsed, start - 1); } else { collapsedFunction.call(t.model, !collapsed, end + 1); } //hideFunc(true, start, end); //t.model.autoFilters.reDrawFilter(arn); } else { //открываем все строки, кроме внутренних групп //внутренние группы скрываем, если среди них есть раскрытые changeModelFunc.call(t.model, false, start, end); if((!_summaryBelow && !bCol) || (!_summaryRight && bCol)) { collapsedFunction.call(t.model, !collapsed, start - 1); } else { collapsedFunction.call(t.model, !collapsed, end + 1); } var groupArr/*, levelMap*/; if(bCol) { groupArr = t.arrColGroups ? t.arrColGroups.groupArr : null; //levelMap = t.arrColGroups ? t.arrColGroups.levelMap : null; } else { groupArr = t.arrRowGroups ? t.arrRowGroups.groupArr : null; //levelMap = t.arrRowGroups ? t.arrRowGroups.levelMap : null; } if(groupArr) { for(var i = level + 1; i <= groupArr.length; i++) { if(!groupArr[i]) { continue; } for(var j = 0; j < groupArr[i].length; j++) { if((!_summaryBelow && !bCol) || (!_summaryRight && bCol)) { if(groupArr[i][j] && groupArr[i][j].start > start && groupArr[i][j].end <= end) { if(t._getGroupCollapsed(groupArr[i][j].start - 1, bCol)) { changeModelFunc.call(t.model, true, groupArr[i][j].start, groupArr[i][j].end); } } } else { if(groupArr[i][j] && groupArr[i][j].start >= start && groupArr[i][j].end < end) { if(t._getGroupCollapsed(groupArr[i][j].end + 1, bCol)) { changeModelFunc.call(t.model, true, groupArr[i][j].start, groupArr[i][j].end); } } } } } } } t.model.bExcludeCollapsed = oldExcludeCollapsed; History.EndTransaction(); if(isNeedRecal) { t.model.workbook.dependencyFormulas.unlockRecal(); } }; if(viewMode) { onChangeWorksheetCallback(); } else { this._isLockedAll(onChangeWorksheetCallback); } }; WorksheetView.prototype.hideGroupLevel = function (level, bCol) { var viewMode = this.handlers.trigger('getViewMode') || window["Asc"]["editor"].isRestrictionComments(); var t = this, groupArr; if(bCol) { groupArr = this.arrColGroups ? this.arrColGroups.groupArr : null; } else { groupArr = this.arrRowGroups ? this.arrRowGroups.groupArr : null; } //var rowLevelMap = t.arrRowGroups ? t.arrRowGroups.rowLevelMap : null; if(!groupArr) { return; } // Проверка глобального лока if (this.collaborativeEditing.getGlobalLock() && !viewMode) { return; } var onChangeWorksheetCallback = function (isSuccess) { if (false === isSuccess) { return; } if (viewMode) { History.TurnOff(); } asc_applyFunction(callback); if (viewMode) { History.TurnOn(); } if(bCol) { t._updateAfterChangeGroup(undefined, null, true); } else { t._updateAfterChangeGroup(null, undefined, true); } //тут требуется обновить только rowLevelMap //t._updateGroups(bCol, undefined, undefined, true); }; var callback = function() { History.Create_NewPoint(); History.StartTransaction(); var isNeedRecal = false; if(!bCol) { for(var i = 0; i <= level; i++) { if(!groupArr[i]) { continue; } for(var j = 0; j < groupArr[i].length; j++) { isNeedRecal = t.model.needRecalFormulas(groupArr[i][j].start, groupArr[i][j].end); if(isNeedRecal) { break; } } } } if(isNeedRecal) { t.model.workbook.dependencyFormulas.lockRecal(); } //TODO check filtering mode var oldExcludeCollapsed = t.model.bExcludeCollapsed; var _summaryBelow = t.model.sheetPr ? t.model.sheetPr.SummaryBelow : true; var _summaryRight = t.model.sheetPr ? t.model.sheetPr.SummaryRight : true; t.model.bExcludeCollapsed = true; for(i = 0; i <= level; i++) { if(!groupArr[i]) { continue; } for(j = 0; j < groupArr[i].length; j++) { if(bCol) { t.model.setColHidden(i >= level, groupArr[i][j].start, groupArr[i][j].end); if(_summaryRight) { t.model.setCollapsedCol(i >= level, groupArr[i][j].end + 1); } else { t.model.setCollapsedCol(i >= level, groupArr[i][j].start - 1); } } else { t.model.setRowHidden(i >= level, groupArr[i][j].start, groupArr[i][j].end); if(_summaryBelow) { t.model.setCollapsedRow(i >= level, groupArr[i][j].end + 1); } else { t.model.setCollapsedRow(i >= level, groupArr[i][j].start - 1); } } } } t.model.bExcludeCollapsed = oldExcludeCollapsed; History.EndTransaction(); if(isNeedRecal) { t.model.workbook.dependencyFormulas.unlockRecal(); } }; if(viewMode) { onChangeWorksheetCallback(); } else { this._isLockedAll(onChangeWorksheetCallback); } }; WorksheetView.prototype.changeGroupDetails = function (bExpand) { //multiselect if(this.model.selectionRange.ranges.length > 1) { return; } var ar = this.model.selectionRange.getLast().clone(); var t = this; //ms делает следущим образом: //закрываем группы, кнопки которых попали в выделение. если же ни одна из кнопок не попала - смотрим пересечение с группой с максимальным уровнем //TODO если кнопка группа с наименьшим уровнем попала в выделение и внутри этой группы на предыдущей строке есть кнопка группы с меньшим уровнем, //TODO то скрываем именно внутреннюю группу - это необходимо сделать! касается только группы с самым наименьшим уровенем, далее внутренни группы не нужно проверять var getNeedGroups = function(groupArr, /*levelMap,*/ bCol) { var maxGroupIndexMap = {}, deleteIndexes = {}; var selectPartGroup, curLevel = 0; var container = []; if(groupArr) { for(var i = 0; i < groupArr.length; i++) { if(groupArr[i]) { for(var j = 0; j < groupArr[i].length; j++) { //TODO COLUMNS! - bCol var collapsed = t._getGroupCollapsed(groupArr[i][j].end + 1, bCol); //полностью выделена группа, если выделена кнопка if(groupArr[i][j].end + 1 >= ar.r1 && groupArr[i][j].end + 1 <= ar.r2 && undefined === maxGroupIndexMap[groupArr[i][j].end]) { if(!deleteIndexes[groupArr[i][j].end] && undefined !== maxGroupIndexMap[groupArr[i][j].end + 1] && !collapsed /*!levelMap[groupArr[i][j].end + 1].collapsed*/) { delete container[maxGroupIndexMap[groupArr[i][j].end + 1]]; deleteIndexes[maxGroupIndexMap[groupArr[i][j].end + 1]] = 1; } else { maxGroupIndexMap[groupArr[i][j].end] = container.length; } if(!bExpand && !collapsed/*(!levelMap[groupArr[i][j].end + 1] || !levelMap[groupArr[i][j].end + 1].collapsed)*/) { container.push(groupArr[i][j]); } } else { //частичное выделение - выбираем максимальный уровень, первую по счёту группу var outLineGroupRange; if(bCol) { outLineGroupRange = Asc.Range(groupArr[i][j].start, 0, groupArr[i][j].end, gc_nMaxRow); } else { outLineGroupRange = Asc.Range(0, groupArr[i][j].start, gc_nMaxCol, groupArr[i][j].end); } if(!collapsed && i > curLevel && outLineGroupRange.intersection(ar)) { selectPartGroup = groupArr[i][j]; curLevel = i; } } } } } } return {container: container, selectPartGroup: selectPartGroup}; }; var needGroups = getNeedGroups(t.arrRowGroups.groupArr/*, t.arrRowGroups.levelMap*/); var allGroupSelectedRow = needGroups.container; var selectPartRowGroup = needGroups.selectPartGroup; if(allGroupSelectedRow.length) { selectPartRowGroup = null; } needGroups = getNeedGroups(t.arrColGroups.groupArr, /*t.arrColGroups.levelMap,*/ true); var allGroupSelectedCol = needGroups.container; var selectPartColGroup = needGroups.selectPartGroup; if(allGroupSelectedCol.length) { selectPartColGroup = null; } var onChangeWorksheetCallback = function (isSuccess) { if (false === isSuccess) { return; } asc_applyFunction(callback); t._updateAfterChangeGroup(null, null); }; //TODO необходимо не закрывать полностью выделенные 1 уровни var callback = function(isSuccess) { if (false === isSuccess) { return; } History.Create_NewPoint(); History.StartTransaction(); //строки var i; if(allGroupSelectedRow.length) { for(i = 0; i < allGroupSelectedRow.length; i++) { if(!allGroupSelectedRow[i]) { continue; } //если блок попал полностью под выделение t.model.setRowHidden(!bExpand, allGroupSelectedRow[i].start, allGroupSelectedRow[i].end); } } if(selectPartRowGroup) { t.model.setRowHidden(!bExpand, selectPartRowGroup.start, selectPartRowGroup.end); } //столбцы if(allGroupSelectedCol.length) { for(i = 0; i < allGroupSelectedCol.length; i++) { if(!allGroupSelectedCol[i]) { continue; } //если блок попал полностью под выделение t.model.setColHidden(!bExpand, allGroupSelectedCol[i].start, allGroupSelectedCol[i].end); } } if(selectPartColGroup) { t.model.setColHidden(!bExpand, selectPartColGroup.start, selectPartColGroup.end); } History.EndTransaction(); }; if(selectPartRowGroup || selectPartColGroup || allGroupSelectedRow.length || allGroupSelectedCol.length) { this._isLockedAll(onChangeWorksheetCallback); } }; //самый простой вариант реализации данной функции //ориентируемся по первой строке выделенного диапазона //попали внутрь группы или затронули кнопку - выполняем действие //приоритет у группы с максимальным уровнем WorksheetView.prototype.changeGroupDetailsSimple = function (bExpand) { //multiselect if (this.model.selectionRange.ranges.length > 1) { return; } var ar = this.model.selectionRange.getLast().clone(); var t = this; var getNeedGroups = function(groupArr, bCol) { var res; if(groupArr) { for(var i = 0; i < groupArr.length; i++) { if(groupArr[i]) { for(var j = 0; j < groupArr[i].length; j++) { //полностью выделена группа, если выделена кнопка if(!bCol && groupArr[i][j].start <= ar.r1 && groupArr[i][j].end + 1 >= ar.r1) { res = groupArr[i][j]; } else if(groupArr[i][j].start <= ar.c1 && groupArr[i][j].end + 1 >= ar.c1) { res = groupArr[i][j]; } } } } } return res; }; var needGroups = getNeedGroups(t.arrRowGroups.groupArr); var allGroupSelectedRow = needGroups; needGroups = getNeedGroups(t.arrColGroups.groupArr, true); var allGroupSelectedCol = needGroups; var onChangeWorksheetCallback = function (isSuccess) { if (false === isSuccess) { return; } asc_applyFunction(callback); t._updateAfterChangeGroup(null, null); }; //TODO необходимо не закрывать полностью выделенные 1 уровни var callback = function(isSuccess) { if (false === isSuccess) { return; } History.Create_NewPoint(); History.StartTransaction(); //строки var i; if(allGroupSelectedRow) { //если блок попал полностью под выделение t.model.setRowHidden(!bExpand, allGroupSelectedRow.start, allGroupSelectedRow.end); } //столбцы if(allGroupSelectedCol) { //если блок попал полностью под выделение t.model.setColHidden(!bExpand, allGroupSelectedCol.start, allGroupSelectedCol.end); } History.EndTransaction(); }; if(allGroupSelectedRow || allGroupSelectedCol) { this._isLockedAll(onChangeWorksheetCallback); } }; WorksheetView.prototype._updateAfterChangeGroup = function(updateRow, updateCol, changeRowCol) { var t = this; var oRecalcType = AscCommonExcel.recalcType.recalc; var lockDraw = false; // Параметр, при котором не будет отрисовки (т.к. мы просто обновляем информацию на неактивном листе) var arrChangedRanges = []; t._initCellsArea(oRecalcType); if(changeRowCol) { t.cache.reset(); } t._cleanCellsTextMetricsCache(); t._prepareCellTextMetricsCache(); arrChangedRanges = arrChangedRanges.concat(t.model.hiddenManager.getRecalcHidden()); t.cellCommentator.updateAreaComments(); if (t.objectRender) { t._updateDrawingArea(); t.model.onUpdateRanges(arrChangedRanges); var aRanges = []; var oBBox; for(var nRange = 0; nRange < arrChangedRanges.length; ++nRange) { oBBox = arrChangedRanges[nRange]; aRanges.push(new AscCommonExcel.Range(t.model, oBBox.r1, oBBox.c1, oBBox.r2, oBBox.c2)); } Asc.editor.wb.handleDrawingsOnWorkbookChange(aRanges); } if(updateRow) { t._updateGroups(null); } else if(updateRow === null) { t._updateGroups(false, undefined, undefined, true); } if(updateCol) { t._updateGroups(true); } else if(updateCol === null) { t._updateGroups(true, undefined, undefined, true); } t.draw(lockDraw); t.handlers.trigger("reinitializeScroll", AscCommonExcel.c_oAscScrollType.ScrollVertical | AscCommonExcel.c_oAscScrollType.ScrollHorizontal); t.handlers.trigger("selectionChanged"); t.getSelectionMathInfo(function (info) { t.handlers.trigger("selectionMathInfoChanged", info); }); }; WorksheetView.prototype.clearOutline = function() { var t = this; //TODO check filtering mode var ar = t.model.selectionRange; //если активной является 1 ячейка, то сбрасываем все группы var isOneCell = 1 === ar.ranges.length && ar.ranges[0].isOneCell(); var groupArrCol= t.arrColGroups ? t.arrColGroups.groupArr : null; var groupArrRow = t.arrRowGroups ? t.arrRowGroups.groupArr : null; var doChangeRowArr = [], doChangeColArr = []; var range, intersection; for(var n = 0; n < ar.ranges.length; n++) { if(groupArrRow) { for(var i = 0; i <= groupArrRow.length; i++) { if(!groupArrRow[i]) { continue; } for(var j = 0; j < groupArrRow[i].length; j++) { range = Asc.Range(0, groupArrRow[i][j].start, gc_nMaxCol, groupArrRow[i][j].end); if(isOneCell) { intersection = range; } else { intersection = ar.ranges[n].intersection(range); } if(intersection) { doChangeRowArr.push(intersection); } } } } if(groupArrCol) { for(i = 0; i <= groupArrCol.length; i++) { if(!groupArrCol[i]) { continue; } for(j = 0; j < groupArrCol[i].length; j++) { range = Asc.Range(groupArrCol[i][j].start, 0, groupArrCol[i][j].end, gc_nMaxRow); if(isOneCell) { intersection = range; } else { intersection = ar.ranges[n].intersection(range); } if(intersection) { doChangeColArr.push(intersection); } } } } } var callback = function(isSuccess) { if(!isSuccess) { return; } History.Create_NewPoint(); History.StartTransaction(); var ar = t.model.selectionRange.getLast(); var _type = ar.getType(); if(_type === c_oAscSelectionType.RangeMax || _type === c_oAscSelectionType.RangeRow) { if(t.model.oAllCol) { t.model.oAllCol.setOutlineLevel(0); } } if(_type === c_oAscSelectionType.RangeMax || _type === c_oAscSelectionType.RangeCol) { if(t.model.oSheetFormatPr && t.model.oSheetFormatPr.oAllRow) { t.model.oSheetFormatPr.oAllRow.setOutlineLevel(0); } } for(var j in doChangeRowArr) { t.model.setRowHidden(false, doChangeRowArr[j].r1, doChangeRowArr[j].r2); t.model.setOutlineRow(0, doChangeRowArr[j].r1, doChangeRowArr[j].r2); } for(j in doChangeColArr) { t.model.setColHidden(false, doChangeColArr[j].c1, doChangeColArr[j].c2); t.model.setOutlineCol(0, doChangeColArr[j].c1, doChangeColArr[j].c2); } History.EndTransaction(); t._updateGroups(null); t._updateGroups(true); }; if(doChangeRowArr.length || doChangeColArr.length) { this._isLockedAll(callback); } }; WorksheetView.prototype.checkAddGroup = function(bUngroup) { //true - rows, false - columns, null - show dialog, undefined - error //multiselect if(this.model.selectionRange.ranges.length > 1) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.CopyMultiselectAreaError, c_oAscError.Level.NoCritical); return; } if(bUngroup && !this._isGroupSheet()) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.CannotUngroupError, c_oAscError.Level.NoCritical); return; } var res = null; var ar = this.model.selectionRange.getLast().clone(); var type = ar.getType(); if (c_oAscSelectionType.RangeCol === type) { res = false; } else if(c_oAscSelectionType.RangeRow === type) { res = true; } return res; }; WorksheetView.prototype._isGroupSheet = function() { //проверка на то, есть ли вообще группировка на листе var res = false; if((this.arrRowGroups && this.arrRowGroups.groupArr) || (this.arrColGroups && this.arrColGroups.groupArr)) { res = true; } return res; }; WorksheetView.prototype.checkSetGroup = function(range, bCol) { var res = true; var c_maxLevel = window['AscCommonExcel'].c_maxOutlineLevel; var maxLevel, i; if(!bCol && this.arrRowGroups && this.arrRowGroups.groupArr) { if(this.arrRowGroups.groupArr[c_maxLevel]) { maxLevel = this.arrRowGroups.groupArr[c_maxLevel]; for(i = 0; i < maxLevel.length; i++) { if(range.r1 >= maxLevel[i].start && range.r2 <= maxLevel[i].end) { res = false; break; } } } } else if(bCol && (this.arrColGroups && this.arrColGroups.groupArr)) { if(this.arrColGroups.groupArr[c_maxLevel]) { maxLevel = this.arrColGroups.groupArr[c_maxLevel]; for(i = 0; i < maxLevel.length; i++) { if(range.c1 >= maxLevel[i].start && range.c2 <= maxLevel[i].end) { res = false; break; } } } } return res; }; WorksheetView.prototype.asc_setGroupSummary = function(val, bCol) { var t = this; var groupArr = bCol ? this.arrColGroups : this.arrRowGroups; groupArr = groupArr ? groupArr.groupArr : null; var collapsedIndexes = []; if(groupArr) { for(var i = 0; i < groupArr.length; i++) { if (groupArr[i]) { for (var j = 0; j < groupArr[i].length; j++) { var collapsedFrom, collapsedTo; if(val === false) { collapsedFrom = groupArr[i][j].end + 1; collapsedTo = groupArr[i][j].start - 1; } else { collapsedFrom = groupArr[i][j].start - 1; collapsedTo = groupArr[i][j].end + 1; } var fromCollapsed = this._getGroupCollapsed(collapsedFrom, bCol); if(fromCollapsed !== this._getGroupCollapsed(collapsedTo, bCol) && collapsedTo > 0 && collapsedFrom > 0) { collapsedIndexes[collapsedTo] = fromCollapsed; } } } } } var callback = function(success) { if(!success) { return; } History.Create_NewPoint(); History.StartTransaction(); bCol ? t.model.setSummaryRight(val) : t.model.setSummaryBelow(val); for(var n in collapsedIndexes) { bCol ? t.model.setCollapsedCol(collapsedIndexes[n], n) : t.model.setCollapsedRow(collapsedIndexes[n], n); } History.EndTransaction(); if(bCol) { t._updateAfterChangeGroup(undefined, null); } else { t._updateAfterChangeGroup(null); } }; this._isLockedAll(callback); }; WorksheetView.prototype.expandActiveCellByFormulaArray = function(activeCellRange) { var formulaRef; if(!activeCellRange) { return activeCellRange; } this.model.getRange3(activeCellRange.r1, activeCellRange.c1, activeCellRange.r1, activeCellRange.c1)._foreachNoEmpty(function(cell) { formulaRef = cell.formulaParsed && cell.formulaParsed.ref ? cell.formulaParsed.ref : null; }); return formulaRef ? formulaRef : activeCellRange; }; WorksheetView.prototype.getSortProps = function(bExpand) { var sortSettings = null; var t = this; //todo добавить локи //перед этой функцией необходимо вызвать getSelectionSortInfo - необходимо ли расширять //bExpand - ответ от этой функции, который протаскивается через интерфейс //если мультиселект - дизейбл кнопки sort var selection = t.model.selectionRange.getLast(); //TODO is it need here? if (t.model.isUserProtectedRangesIntersection(selection)) { t.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ProtectedRangeByOtherUser, c_oAscError.Level.NoCritical); return false; } if (this.model.getSheetProtection(Asc.c_oAscSheetProtectType.sort)) { return; } if (this.model.getSheetProtection()) { if (!(t.model.protectedRangesContainsRange(selection) || !t.model.isLockedRange(selection))) { this.handlers.trigger("asc_onError", c_oAscError.ID.ChangeOnProtectedSheet, c_oAscError.Level.NoCritical); return; } } var activeCell = t.model.selectionRange.activeCell.clone(); var oldSelection = selection.clone(); var autoFilter = t.model.AutoFilter; var modelSort, dataHasHeaders, columnSort; var tables = t.model.autoFilters.getTablesIntersectionRange(selection); var lockChangeHeaders, lockChangeOrientation, caseSensitive; //проверяем, возможно находится рядом а/ф var tryExpandRange = t.model.autoFilters.expandRange(selection, true); if(tables && tables.length) { if(tables && tables && tables.length === 1 && tables[0].Ref.containsRange(selection)) { selection = tables[0].getRangeWithoutHeaderFooter(); columnSort = true; dataHasHeaders = true; modelSort = tables[0].SortState; lockChangeHeaders = true; lockChangeOrientation = true; } else { t.workbook.handlers.trigger("asc_onError", c_oAscError.ID.AutoFilterDataRangeError, c_oAscError.Level.NoCritical); return false; } } else if(autoFilter && autoFilter.Ref && (autoFilter.Ref.isEqual(selection) || (selection.isOneCell() && (autoFilter.Ref.containsRange(selection) || autoFilter.Ref.containsRange(tryExpandRange))))) { selection = autoFilter.getRangeWithoutHeaderFooter(); columnSort = true; dataHasHeaders = true; modelSort = autoFilter.SortState; lockChangeHeaders = true; lockChangeOrientation = true; } else { if(bExpand) { selection = tryExpandRange ? tryExpandRange : t.model.autoFilters.expandRange(selection, true); } selection = t.model.autoFilters.cutRangeByDefinedCells(selection); if(bExpand) { selection = t.model.autoFilters.checkExpandRangeForSort(selection); } //в модели лежит флаг columnSort - если он true значит сортируем по строке(те перемещаем колонки) //в настройках флаг columnSort - означает, что сортируем по колонке modelSort = this.model.sortState; columnSort = modelSort ? !modelSort.ColumnSort : true; caseSensitive = modelSort ? modelSort.CaseSensitive : false; var isOneRow = selection.r1 === selection.r2; if(isOneRow || !columnSort) { if(isOneRow) { lockChangeHeaders = true; } dataHasHeaders = false; } if(columnSort) { if(modelSort) { dataHasHeaders = /*!modelSort.Ref.isEqual(selection) ?*/ modelSort._hasHeaders /*: false*/; } else { dataHasHeaders = window['AscCommonExcel'].ignoreFirstRowSort(t.model, selection); } } //для columnSort - добавлять с1++ if (dataHasHeaders) { selection.r1++; } //если пустой дипазон, выдаём ошибку if(t.model.autoFilters._isEmptyRange(selection, 0)) { t.workbook.handlers.trigger("asc_onError", c_oAscError.ID.AutoFilterDataRangeError, c_oAscError.Level.NoCritical); return false; } } //change selection t.cleanSelection(); t.model.selectionRange.getLast().assign2(selection); if(!selection.contains(activeCell.col, activeCell.row)) { t.model.selectionRange.activeCell = new AscCommon.CellBase(selection.r1, selection.c1); } t._drawSelection(); sortSettings = new Asc.CSortProperties(this); //необходимо ещё сохранять значение старого селекта, чтобы при нажатии пользователя на отмену - откатить sortSettings.selection = oldSelection; //заголовки sortSettings.hasHeaders = dataHasHeaders; sortSettings.columnSort = columnSort; sortSettings.caseSensitive = caseSensitive; sortSettings.lockChangeHeaders = lockChangeHeaders; sortSettings.lockChangeOrientation = lockChangeOrientation; var getSortLevel = function(sortCondition) { var level = new Asc.CSortPropertiesLevel(); var index = columnSort ? sortCondition.Ref.c1 - selection.c1 : sortCondition.Ref.r1 - selection.r1; var name = sortSettings.getNameColumnByIndex(index, selection); level.index = index; level.name = name; //TODO добавить функцию в CSortPropertiesLevel для получения всех цветов(при открытии соответсвующего меню) //TODO перенести в отдельную константу Descending/Ascending level.descending = sortCondition.ConditionDescending ? Asc.c_oAscSortOptions.Descending : Asc.c_oAscSortOptions.Ascending; level.sortBy = sortCondition.ConditionSortBy; var conditionSortBy = sortCondition.ConditionSortBy; var sortColor = null; switch (conditionSortBy) { case Asc.ESortBy.sortbyCellColor: { level.sortBy = Asc.c_oAscSortOptions.ByColorFill; if(sortCondition.dxf && sortCondition.dxf.fill) { if(sortCondition.dxf.fill && sortCondition.dxf.fill.patternFill) { if(sortCondition.dxf.fill.patternFill.bgColor) { sortColor = sortCondition.dxf.fill.patternFill.bgColor; } else if(sortCondition.dxf.fill.patternFill.fgColor) { sortColor = sortCondition.dxf.fill.patternFill.fgColor; } } } //sortColor = sortCondition.dxf && sortCondition.dxf.fill ? sortCondition.dxf.fill.bg() : null; break; } case Asc.ESortBy.sortbyFontColor: { level.sortBy = Asc.c_oAscSortOptions.ByColorFont; sortColor = sortCondition.dxf && sortCondition.dxf.font && sortCondition.dxf.font.c ? sortCondition.dxf.font.getColor() : null; break; } case Asc.ESortBy.sortbyIcon: { level.sortBy = Asc.c_oAscSortOptions.ByIcon; break; } default: { level.sortBy = Asc.c_oAscSortOptions.ByValue; break; } } var ascColor = null; if (null !== sortColor) { ascColor = new Asc.asc_CColor(); ascColor.asc_putR(sortColor.getR()); ascColor.asc_putG(sortColor.getG()); ascColor.asc_putB(sortColor.getB()); ascColor.asc_putA(sortColor.getA()); level.color = ascColor; } return level; }; //столбцы/строки с настройками if(modelSort) { //заполняем только в случае пересечения if(selection.intersection(modelSort.Ref)) { for(var i = 0; i < modelSort.SortConditions.length; i++) { if(modelSort.SortConditions[i].Ref.intersection(selection)) { if(!sortSettings.levels) { sortSettings.levels = []; } sortSettings.levels.push(getSortLevel(modelSort.SortConditions[i])); } } } } sortSettings._newSelection = selection; sortSettings.generateSortList(); return sortSettings; }; WorksheetView.prototype.setSortProps = function(props, doNotSortRange, bCancel) { if (this.model.getSheetProtection(Asc.c_oAscSheetProtectType.sort)) { return; } var t = this; var selection = t.model.selectionRange.getLast(); if (t.model.isUserProtectedRangesIntersection(selection)) { t.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ProtectedRangeByOtherUser, c_oAscError.Level.NoCritical); return false; } if (this.model.getSheetProtection()) { if (!(t.model.protectedRangesContainsRange(selection) || !t.model.isLockedRange(selection))) { this.handlers.trigger("asc_onError", c_oAscError.ID.ChangeOnProtectedSheet, c_oAscError.Level.NoCritical); return; } } var activeCell = t.model.selectionRange.activeCell.clone(); var revertSelection = function() { t.cleanSelection(); t.model.selectionRange.getLast().assign2(props.selection.clone()); if(!selection.contains(activeCell.col, activeCell.row)) { t.model.selectionRange.activeCell = new AscCommon.CellBase(selection.r1, selection.c1); } t._drawSelection(); }; //TODO selection не сохраняется при применении сортировки, поскольку создаётся новый CSortProperties в интерфейсе if(bCancel && props && props.selection) { revertSelection(); return; } if(!props || !props.levels || !props.levels.length) { return false; } var aMerged = this.model.mergeManager.get(selection); if (aMerged.outer.length > 0 || (aMerged.inner.length > 0 && null == window['AscCommonExcel']._isSameSizeMerged(selection, aMerged.inner, true))) { t.handlers.trigger("onErrorEvent", c_oAscError.ID.CannotFillRange, c_oAscError.Level.NoCritical); return; } //TODO отдельная обработка для таблиц var callback = function(obj) { t.model.setCustomSort(props, obj, doNotSortRange, t.cellCommentator); if(obj && !obj.isAutoFilter()) { t._onUpdateFormatTable(selection); } if(props && props.selection) { revertSelection(); } }; //TODO lock var tables = t.model.autoFilters.getTablesIntersectionRange(selection); var obj; if(tables && tables.length) { obj = tables[0]; } else if(t.model.AutoFilter && t.model.AutoFilter.Ref && t.model.AutoFilter.Ref.intersection(selection)) { obj = t.model.AutoFilter; } this._isLockedAll(callback(obj)); }; WorksheetView.prototype._generateSortProps = function(nOption, nStartRowCol, sortColor, opt_guessHeader, opt_by_row, range) { var sortSettings = new Asc.CSortProperties(this); var columnSort = sortSettings.columnSort = opt_by_row !== true; var getSortLevel = function() { var level = new Asc.CSortPropertiesLevel(); level.index = columnSort ? nStartRowCol - range.c1 : nStartRowCol - range.r1; level.descending = nOption != Asc.c_oAscSortOptions.Ascending; level.sortBy = nOption; level.color = sortColor; return level; }; sortSettings.levels = []; sortSettings.levels.push(getSortLevel()); sortSettings._newSelection = range; return sortSettings; }; WorksheetView.prototype.checkCustomSortRange = function (range, bRow) { var res = null; var ar = this.model.copySelection.getLast(); if((bRow && range.r1 !== range.r2) || (!bRow && range.c1 !== range.c2)) { res = c_oAscError.ID.CustomSortMoreOneSelectedError; } else if(((bRow && (range.r1 < ar.r1 || range.r1 > ar.r2)) || (!bRow && (range.c1 < ar.c1 || range.c1 > ar.c2)))) { res = c_oAscError.ID.CustomSortNotOriginalSelectError; } return res; }; WorksheetView.prototype.applyTableAutoExpansion = function (bbox, applyByArray) { if (!window['AscCommonExcel'].g_IncludeNewRowColInTable) { return; } var t = this; var api = window["Asc"]["editor"]; var bFast = api.collaborativeEditing.m_bFast; var bIsSingleUser = !api.collaborativeEditing.getCollaborativeEditing(); var oAutoExpansionTable = t.model.autoFilters.checkTableAutoExpansion(bbox); if (oAutoExpansionTable && !applyByArray) { if (this.model.isUserProtectedRangesIntersection(oAutoExpansionTable.range)) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ProtectedRangeByOtherUser, c_oAscError.Level.NoCritical); return; } if (this.model.getSheetProtection()) { return; } var callback = function (success) { if (!success) { return; } if (bFast && !bIsSingleUser) { t.handlers.trigger("toggleAutoCorrectOptions"); return; } var options = { props: [Asc.c_oAscAutoCorrectOptions.UndoTableAutoExpansion], cell: bbox, wsId: t.model.getId() }; t.handlers.trigger("toggleAutoCorrectOptions", true, options); }; t.af_changeTableRange(oAutoExpansionTable.name, oAutoExpansionTable.range, callback); } else { t.handlers.trigger("toggleAutoCorrectOptions"); } }; WorksheetView.prototype.getRemoveDuplicates = function(bExpand) { var settings = null; var t = this; //bExpand - ответ от этой функции, который протаскивается через интерфейс //если мультиселект - дизейбл кнопки var selection = t.model.selectionRange.getLast(); var activeCell = t.model.selectionRange.activeCell.clone(); var oldSelection = selection.clone(); var autoFilter = t.model.AutoFilter; var dataHasHeaders; var tables = t.model.autoFilters.getTablesIntersectionRange(selection); var lockChangeHeaders, lockChangeOrientation, caseSensitive; //проверяем, возможно находится рядом а/ф var tryExpandRange = t.model.autoFilters.expandRange(selection, true); if(tables && tables.length) { if(tables && tables && tables.length === 1 && tables[0].Ref.containsRange(selection)) { selection = tables[0].getRangeWithoutHeaderFooter(); dataHasHeaders = true; } else { t.workbook.handlers.trigger("asc_onError", c_oAscError.ID.AutoFilterDataRangeError, c_oAscError.Level.NoCritical); return false; } } else if(autoFilter && autoFilter.Ref && (autoFilter.Ref.isEqual(selection) || (selection.isOneCell() && (autoFilter.Ref.containsRange(selection) || autoFilter.Ref.containsRange(tryExpandRange))))) { selection = autoFilter.getRangeWithoutHeaderFooter(); dataHasHeaders = true; } else { if(bExpand) { selection = tryExpandRange ? tryExpandRange : t.model.autoFilters.expandRange(selection, true); } selection = t.model.autoFilters.cutRangeByDefinedCells(selection); if(bExpand) { selection = t.model.autoFilters.checkExpandRangeForSort(selection); } dataHasHeaders = window['AscCommonExcel'].ignoreFirstRowSort(t.model, selection); //для columnSort - добавлять с1++ if (dataHasHeaders) { selection.r1++; } //если пустой дипазон, выдаём ошибку if(t.model.autoFilters._isEmptyRange(selection, 0) || selection.r1 === selection.r2) { t.workbook.handlers.trigger("asc_onError", c_oAscError.ID.AutoFilterDataRangeError, c_oAscError.Level.NoCritical); return false; } } //change selection t.cleanSelection(); t.model.selectionRange.getLast().assign2(selection); if(!selection.contains(activeCell.col, activeCell.row)) { t.model.selectionRange.activeCell = new AscCommon.CellBase(selection.r1, selection.c1); } t._drawSelection(); //в плане взаимодействия с интерефесом очень много общего с кастомной сортировкой //из-за того, что из сортировки здесь требуется несколько полей + чтобы не было путанницы // передаваемый объект создаю другой settings = new Asc.CRemoveDuplicatesProps(this); //необходимо ещё сохранять значение старого селекта, чтобы при нажатии пользователя на отмену - откатить settings.selection = oldSelection; //заголовки settings.hasHeaders = dataHasHeaders; settings._newSelection = selection; settings.generateColumnList(); return settings; }; WorksheetView.prototype.setRemoveDuplicates = function(props, bCancel) { var t = this; var selection = t.model.selectionRange.getLast(); var activeCell = t.model.selectionRange.activeCell.clone(); var revertSelection = function() { t.cleanSelection(); t.model.selectionRange.getLast().assign2(props.selection.clone()); if(!selection.contains(activeCell.col, activeCell.row)) { t.model.selectionRange.activeCell = new AscCommon.CellBase(selection.r1, selection.c1); } t._drawSelection(); }; if (bCancel || !props || !props.columnList) { revertSelection(); return; } var aMerged = this.model.mergeManager.get(selection); if (aMerged.outer.length > 0 || (aMerged.inner.length > 0 && null == window['AscCommonExcel']._isSameSizeMerged(selection, aMerged.inner, true))) { revertSelection(); t.handlers.trigger("onErrorEvent", c_oAscError.ID.CannotFillRange, c_oAscError.Level.NoCritical); return; } var i, startSortCol, colMap = []; for (i = 0; i < props.columnList.length; i++) { if (props.columnList[i].asc_getVisible()) { var _colIndex = i + selection.c1; colMap[_colIndex] = 1; if(undefined === startSortCol) { startSortCol = _colIndex; } } } if (undefined === startSortCol) { revertSelection(); return; } var firstLockRow; var deleteIndexes = []; var deleteIndexesMap = []; var repeatArr = []; var aSortElems = []; for (i = selection.r1; i <= selection.r2; i++) { var cell = t.model.getCell3(i, startSortCol); var value = cell.getValueWithFormat(); aSortElems.push({index: i}); if (repeatArr.hasOwnProperty(value)) { for (var n = 0; n < repeatArr[value].length; n++) { var _notEqual = false; for (var j = startSortCol + 1; j <= selection.c2; j++) { if (!colMap[j]) { continue; } var cell1 = t.model.getCell3(i, j); var cell2 = t.model.getCell3(repeatArr[value][n], j); var val1 = cell1.getValueWithFormat(); var val2 = cell2.getValueWithFormat(); if (val1 !== val2) { _notEqual = true; break; } } if (!_notEqual) { deleteIndexes.push(i); deleteIndexesMap[i] = 1; if (undefined === firstLockRow) { firstLockRow = i; } break; } } if (_notEqual) { repeatArr[value].push(i); } } else { if(!repeatArr[value]) { repeatArr[value] = []; } repeatArr[value].push(i); } } var _removeDuplicates = function(success) { if (!success) { if (isStartTransaction) { History.EndTransaction(); } return; } if(!isStartTransaction) { History.Create_NewPoint(); History.StartTransaction(); } var tableIntersection; var filterIntersection = t.model.AutoFilter && t.model.AutoFilter.Ref.intersection(selection); if (filterIntersection) { //unhide t.model.setRowHidden(false, filterIntersection.r1, filterIntersection.r2); } else if (t.model.TableParts) { for (var i = 0; i < t.model.TableParts.length; i++) { var _intersection = selection.intersection(t.model.TableParts[i].Ref); if (_intersection) { tableIntersection = t.model.TableParts[i]; t.model.setRowHidden(false, _intersection.r1, _intersection.r2); break; } } } aSortElems.sort(function(a, b) { if ((deleteIndexesMap[a.index] && deleteIndexesMap[b.index]) || (!deleteIndexesMap[a.index] && !deleteIndexesMap[b.index])) { return 0; } else if (!deleteIndexesMap[a.index] && deleteIndexesMap[b.index]) { return -1; } else { return 1; } }); var aSortData = []; for (var i = 0; i < aSortElems.length; i++) { var oldIndex = aSortElems[i].index; var newIndex = i + selection.r1; if (oldIndex !== newIndex) { aSortData.push(new AscCommonExcel.UndoRedoData_FromToRowCol(true, oldIndex, newIndex)); } } if (deleteIndexes.length) { //удаляем for (var j = 0; j < deleteIndexes.length; j++) { var deleteRange = t.model.getRange3(deleteIndexes[j], selection.c1, deleteIndexes[j], selection.c2); deleteRange.cleanAll(); t.model.deletePivotTables(deleteRange.bbox); t.model.removeSparklines(deleteRange.bbox); t.cellCommentator.deleteCommentsRange(deleteRange.bbox); } //сортируем if (aSortData.length) { var sortRange = t.model.getRange3(selection.r1, selection.c1, selection.r2, selection.c2); var oUndoRedoBBox = new AscCommonExcel.UndoRedoData_BBox({r1: selection.r1, c1: selection.c1, r2: selection.r2, c2: selection.c2}); var _historyElem = new AscCommonExcel.UndoRedoData_SortData(oUndoRedoBBox, aSortData); sortRange._sortByArray(oUndoRedoBBox, aSortData); var range = new Asc.Range(selection.r1, selection.c1, selection.r2, selection.c2); History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_Sort, t.model.getId(), range, _historyElem); } } if (filterIntersection) { t.model.autoFilters.reapplyAutoFilter(null); } else if (tableIntersection) { t.model.autoFilters.reapplyAutoFilter(tableIntersection.DisplayName); t.model.autoFilters._setColorStyleTable(tableIntersection.Ref, tableIntersection, null, true); } History.EndTransaction(); t._updateRange(selection); t._updateSlicers(selection); t.draw(); if (deleteIndexes.length) { props.setDuplicateValues(deleteIndexes.length); props.setUniqueValues(selection.r2 - selection.r1 - deleteIndexes.length + 1); } t.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.RemoveDuplicates, c_oAscError.Level.NoCritical, props); }; if (undefined !== firstLockRow) { var lockRange = new Asc.Range(selection.c1, firstLockRow, selection.c2, selection.r2); if (this.intersectionFormulaArray(lockRange)) { this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.CannotChangeFormulaArray, c_oAscError.Level.NoCritical); return; } var tableContains = this.model.autoFilters.getTablesIntersectionRange(selection); var isStartTransaction = false; if (tableContains && tableContains.length) { if (tableContains.length === 1) { var name = tableContains[0].DisplayName; var ref = tableContains[0].Ref; var newRef = new Asc.Range(ref.c1, ref.r1, ref.c2, ref.r2 - deleteIndexes.length); History.Create_NewPoint(); History.StartTransaction(); isStartTransaction = true; this.af_changeTableRange(name, newRef, _removeDuplicates, true); } } else { this._isLockedCells(lockRange, /*subType*/null, _removeDuplicates); } } else { t.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.RemoveDuplicates, c_oAscError.Level.NoCritical, props); } }; WorksheetView.prototype.getDrawingDocument = function() { if(this.model) { return this.model.getDrawingDocument(); } return null; }; WorksheetView.prototype.rangeToRectAbs = function(oRange, units) { var left = this.getCellLeft(0, units); var top = this.getCellTop(0, units); var l = this.checkRtl(this.getCellLeft(oRange.c1, units) - left, null, units); var t = this.getCellTop(oRange.r1, units) - top; var r = this.checkRtl(this.getCellLeft(oRange.c2, units) + this.getColumnWidth(oRange.c2, units) - left, null, units); var b = this.getCellTop(oRange.r2, units) + this.getRowHeight(oRange.r2, units) - top; if (this.getRightToLeft()) { let _r = r; r = l; l = _r; } return new AscFormat.CGraphicBounds(l - this.getRightToLeftOffset(), t, r, b); }; WorksheetView.prototype.rangeToRectRel = function(oRange, units, checkFrozenArea) { var l = this.checkRtl(this.getCellLeftRelative(oRange.c1, units, checkFrozenArea), null, units); var t = this.getCellTopRelative(oRange.r1, units, checkFrozenArea); var r = this.checkRtl(this.getCellLeftRelative(oRange.c2, units) + this.getColumnWidth(oRange.c2, units), null, units); var b = this.getCellTopRelative(oRange.r2, units) + this.getRowHeight(oRange.r2, units); if (this.getRightToLeft()) { let _r = r; r = l; l = _r; } return new AscFormat.CGraphicBounds(l - this.getRightToLeftOffset(), t, r, b); }; //интерфейс /*отдаём массив данных для интерефейса - beforeInsertSlicer добавляем срезы от интерфейса - insertSlicers //данные для отображения генерируем данные для отображения в шейпа по имени - getFilterValuesBySlicerName //обновление view после применения автофильтра изменяем отображения на основне данных модели по имени ф/т - updateSlicerViewAfterTableChange //обновляем модель среза принимаем данные от шейпа для того чтобы изменить ф/т - setFilterValuesFromSlicer изменяется имя колонки ф/т - changeSlicerAfterSetTableColName изменяется имя ф/т - setSlicerTableName удаляем срез - deleteSlicer */ WorksheetView.prototype.beforeInsertSlicer = function () { //чтобы лишний раз не проверять - может быть взять информацию из cellinfo? const tableInfo = this.model.autoFilters.getTableByActiveCell(); if (tableInfo) { const table = tableInfo.table; var res = []; for (var j = 0; j < table.TableColumns.length; j++) { res.push(table.TableColumns[j].getTableColumnName()); } return res; } var ar = this.model.selectionRange.getLast().clone(); //pivot var pivotTable = this.model.inPivotTable(ar); if (pivotTable) { return pivotTable.getSlicerCaption(); } return null; }; WorksheetView.prototype.insertSlicers = function (arr) { if (this.collaborativeEditing.getGlobalLock() || !window["Asc"]["editor"].canEdit()) { return; } var t = this; var type, name, pivotTable; var callback = function (success) { if (!success) { History.EndTransaction(); return; } //добавляем в структуру for (var i = 0; i < arr.length; i++) { var slicer = t.model.insertSlicer(arr[i], name, type, pivotTable); arr[i] = slicer.name; } t.objectRender.addSlicers(arr); History.EndTransaction(); }; History.Create_NewPoint(); History.StartTransaction(); //чтобы лишний раз не проверять - может быть взять информацию из cellinfo? const tableInfo = this.model.autoFilters.getTableByActiveCell(); var lockRanges = [], colRange, needAddFilter, pivotLockInfos = []; if (tableInfo) { const table = tableInfo.table; type = window['AscCommonExcel'].insertSlicerType.table; name = table.DisplayName; if (!table.AutoFilter) { needAddFilter = true; } for (var k = 0; k < arr.length; k++) { colRange = this.model.getTableRangeColumnByName(name, arr[k]); if (colRange) { lockRanges.push(colRange); } } } else { var ar = this.model.selectionRange.getLast().clone(); //pivot pivotTable = this.model.inPivotTable(ar); if (pivotTable) { type = window['AscCommonExcel'].insertSlicerType.pivotTable; pivotTable.fillLockInfo(pivotLockInfos, t.collaborativeEditing); } } if (needAddFilter) { this.changeAutoFilter(name, Asc.c_oAscChangeFilterOptions.filter, true, function (success) { if (!success) { History.EndTransaction(); return; } //TODO перепроверить лок t._isLockedDefNames(callback); }); } else { var callbackLockCell = function (success) { if (!success) { History.EndTransaction(); return; } //TODO перепроверить лок if (pivotLockInfos.length > 0) { t.collaborativeEditing.lock(pivotLockInfos, function(success){ if (!success) { History.EndTransaction(); return; } t._isLockedDefNames(callback); }); } else { t._isLockedDefNames(callback); } }; if(lockRanges.length > 0) { this._isLockedCells(lockRanges, null, callbackLockCell); } else { callbackLockCell(true); } } }; WorksheetView.prototype.deleteSlicer = function (name) { var t = this; var callback = function (success) { if (!success) { return; } t.model.deleteSlicer(name); }; var slicer = this.model.getSlicerByName(name); if (slicer) { this.checkLockSlicers([slicer], true, callback); } }; WorksheetView.prototype.setSlicer = function (slicer, obj) { if (this.collaborativeEditing.getGlobalLock() || !window["Asc"]["editor"].canEdit()) { return; } var callback = function (success) { if (!success) { return; } History.Create_NewPoint(); History.StartTransaction(); slicer.set(obj); History.EndTransaction(); }; if (slicer) { this.checkLockSlicers([slicer], true, callback); } }; WorksheetView.prototype.setFilterValuesFromSlicer = function (slicer, val) { if (this.collaborativeEditing.getGlobalLock() || !window["Asc"]["editor"].canEdit()) { return; } var ws = this.model; var obj; if (slicer && slicer.cacheDefinition) { var slicerCache = slicer.cacheDefinition; obj = slicerCache.getFilterObj(); } var checkFilterItems = function (_elems, _setItemsVisible) { if (_elems) { for (var i = 0; i < _elems.length; i++) { if (!_setItemsVisible && _elems[i].visible === true) { return true; } if (_setItemsVisible) { _elems[i].visible = true; } } return false; } return true; }; var createSimpleFilterOptions = function () { //get values var colId = obj.colId; var table = obj.obj; var displayName = table.DisplayName; var rangeButton = new Asc.Range(table.Ref.c1 + colId, table.Ref.r1, table.Ref.c1 + colId, table.Ref.r1); var cellId = ws.autoFilters._rangeToId(rangeButton); //get filter object var filterObj = new Asc.AutoFilterObj(); filterObj.type = c_oAscAutoFilterTypes.Filters; //set menu object var autoFilterObject = new Asc.AutoFiltersOptions(); autoFilterObject.asc_setCellId(cellId); autoFilterObject.asc_setValues(val); autoFilterObject.asc_setFilterObj(filterObj); autoFilterObject.asc_setDiplayName(displayName); return autoFilterObject; }; if (obj) { var type = slicerCache.getType(); switch (type) { case window['AscCommonExcel'].insertSlicerType.table: { if (!checkFilterItems(val)) { checkFilterItems(val, true); } this.applyAutoFilter(createSimpleFilterOptions()); break; } case window['AscCommonExcel'].insertSlicerType.pivotTable: { if (!checkFilterItems(val)) { checkFilterItems(val, true); } slicerCache.applyPivotFilterWithLock(this.model.workbook.oApi, val, slicer.name, null, false); break; } } } }; WorksheetView.prototype.getFilterValuesBySlicerName = function (name) { //получаем данные для отображения в шейпе //в связанном шейпе хранится имя cSlicer //чтобы получить скрытые/открытые значения используем slicerCache //внутри получаем имя форматированной(сводной) таблицы и имя колонки var slicerCache = this.model.getSlicerCachesBySourceName(name); return slicerCache ? slicerCache.getFilterValues() : null; }; WorksheetView.prototype.updateSlicerViewAfterTableChange = function (tableName) { var slicers = this.model.getSlicersByTableName(tableName); for (var i = 0; i < slicers.length; i++) { var filterValues = this.getFilterValuesBySlicerName(slicers[i].Name); //update current view //updateView(slicers[i].Name, filterValues) } }; WorksheetView.prototype.updateSlicerAfterChangeTable = function (type, tableName, val) { /*var slicers = this.model.getSlicersByTableName(tableName); for (var i = 0; i < slicers.length; i++) { switch (type) { case window['AscCommonExcel'].insertSlicerType.table: { //TODO сформировать объект autoFiltersObject this.applyAutoFilter(); break; } case window['AscCommonExcel'].insertSlicerType.pivotTable: { break; } } }*/ }; WorksheetView.prototype.checkLockSlicers = function (slicers, doLockRange, callback) { var t = this; var _lockMap = []; var lockInfoArr = []; var lockRanges = []; var cache, defNameId, lockInfo, lockRange; for (var i = 0; i < slicers.length; i++) { cache = slicers[i].getCacheDefinition(); if (!_lockMap[cache.name]) { _lockMap[cache.name] = 1; defNameId = this.model.workbook.dependencyFormulas.getDefNameByName(cache.name, this.model.getId()); defNameId = defNameId ? defNameId.getNodeId() : null; lockInfo = this.collaborativeEditing.getLockInfo(c_oAscLockTypeElem.Object, null, -1, defNameId); lockInfoArr.push(lockInfo); if (doLockRange) { lockRange = cache.getRange(); if (lockRange) { lockRanges.push(lockRange); } } } } var _callback = function (success) { if (!success && callback) { callback(false); } if (lockRanges && lockRanges.length) { t._isLockedCells(lockRanges, /*subType*/null, callback); } else { callback(true); } }; if (lockInfoArr && lockInfoArr.length) { this.collaborativeEditing.lock(lockInfoArr, _callback); } else { _callback(true); } }; WorksheetView.prototype.tryPasteSlicers = function (arr, callback) { var t = this; var _callback = function (success) { if (!success) { callback(false); return; } var newNames = []; for (var i = 0; i < arr.length; i++) { var slicer = arr[i].clone(t.model); slicer.name = slicer.generateName(slicer.name); //клонируем, перегенерируем имя, имя кэша и проверяем sourceName у кэша if (modelCaches[i]) { slicer.cacheDefinition = modelCaches[i]; } else { //тут необходимо ещё проверить, соответсвует ли внутренняя структура var _type = slicer.cacheDefinition.getType(); if (_type === window['AscCommonExcel'].insertSlicerType.table) { var table = slicer.cacheDefinition.getTableSlicerCache(); if (!table || !t.model.workbook.getTableIndexColumnByName(table.tableId, table.column)) { continue; } } else if (_type === window['AscCommonExcel'].insertSlicerType.pivotTable) { if (!slicer.cacheDefinition.moveToWb(t.model.workbook)) { continue; } } slicer.cacheDefinition.name = slicer.cacheDefinition.generateSlicerCacheName(slicer.name); var newDefName = new Asc.asc_CDefName(slicer.cacheDefinition.name, "#N/A", null, Asc.c_oAscDefNameType.slicer); t.model.workbook.editDefinesNames(null, newDefName); } History.Add(AscCommonExcel.g_oUndoRedoWorksheet, AscCH.historyitem_Worksheet_SlicerAdd, t.model.getId(), null, new AscCommonExcel.UndoRedoData_FromTo(null, slicer)); t.model.aSlicers.push(slicer); newNames[i] = slicer.name; } callback(true, newNames); }; var lockRanges = [], isLockDefNames, slicerPasted, cachePasted, modelCache, _range, pivotLockInfos = []; var modelCaches = []; for (var i = 0; i < arr.length; i++) { slicerPasted = arr[i]; cachePasted = slicerPasted.getCacheDefinition(); modelCache = this.model.workbook.getSlicerCacheByCacheName(cachePasted.name); if (modelCache) { var _type = modelCache.getType(); if (_type === window['AscCommonExcel'].insertSlicerType.table) { _range = modelCache.getRange(); if (_range) { lockRanges.push(_range); } } else if (_type === window['AscCommonExcel'].insertSlicerType.pivotTable) { modelCache.getPivotTables().map(function(pivotTable){ pivotTable.fillLockInfo(pivotLockInfos, t.collaborativeEditing); }); } modelCaches[i] = modelCache; } else { _range = cachePasted.getRange(); if (_range) { lockRanges.push(_range); } isLockDefNames = true; } } this._isLockedCells(lockRanges, null, function(success) { if (success) { if (isLockDefNames) { //TODO перепроверить лок t._isLockedDefNames(function(isLockedDefNames) { if (isLockedDefNames) { if (pivotLockInfos.length > 0) { t.collaborativeEditing.lock(pivotLockInfos, _callback); } else { _callback(true); } } else { _callback(false); } }); } else { if (pivotLockInfos.length > 0) { t.collaborativeEditing.lock(pivotLockInfos, _callback); } else { _callback(true); } } } else { callback(false); } }); }; WorksheetView.prototype._updateSlicers = function (range) { //пока только для таблиц var tables = this.model.autoFilters.getTablesIntersectionRange(range); if (tables) { for (var i = 0; i < tables.length; i++) { this.model.autoFilters.updateSlicer(tables[i].DisplayName); } } }; WorksheetView.prototype.getDefaultDefinedNameText = function () { var selectionRange = this.model.selectionRange; var cell = selectionRange.activeCell; var mc = this.model.getMergedByCell(cell.row, cell.col); var c1 = mc ? mc.c1 : cell.col; var r1 = mc ? mc.r1 : cell.row; var c = this._getVisibleCell(c1, r1); var text = null; if (!c.isFormula()) { text = c.getValueForEdit(true); if (text && text.length > window['AscCommonExcel'].g_nDefNameMaxLength) { text = null; } else if (text) { if (!isNaN(text)) { text = null; } else if (text[0] && !isNaN(text[0])) { //TODO text = "_" + text; } } } return !text ? "" : text; }; WorksheetView.prototype.setDataValidationProps = function (props) { var t = this; var _selection = this.model.getSelection().ranges; var callback = function (success) { if (!success) { return; } History.Create_NewPoint(); History.StartTransaction(); t.model.setDataValidationProps(props); t.handlers.trigger("selectionChanged"); t.draw(); History.EndTransaction(); }; //TODO необходимо ли лочить каждый объект data validate? var lockRanges = this.model.dataValidations ? this.model.dataValidations.expandRanges(_selection) : _selection; this._isLockedCells(lockRanges, /*subType*/null, callback); }; WorksheetView.prototype.setDataValidationSameSettings = function (props, val) { var _selection = this.model.getSelection().ranges; var t = this; //AscCommonExcel.Range.prototype.createFromBBox(this.model, range) var getRangeSelection = function (oldRanges) { var _ranges = []; for (var i = 0; i < oldRanges.length; i++) { _ranges.push(AscCommonExcel.Range.prototype.createFromBBox(t, oldRanges[i].clone())); } return _ranges; }; //здесь не будем проверять лок //если какая-то ячейка окажется залочена, то дальнейшего применения не произойдёт if (val) { //поскольку объект может быть измененным, использую тот, который лежит в модели var modelDataValidation = this.model.dataValidations.getById(props.Id); if (modelDataValidation && modelDataValidation.data) { modelDataValidation = modelDataValidation.data; } else { return; } var elems = this.model.dataValidations.getSameSettingsElems(modelDataValidation); if (elems) { props._tempSelection = _selection; var newSelection = []; for (var i = 0; i < elems.length; i++) { newSelection = newSelection.concat(elems[i].ranges); } this.setSelection(getRangeSelection(newSelection)); } } else if (props._tempSelection) { this.setSelection(getRangeSelection(props._tempSelection)); } }; WorksheetView.prototype.setCF = function (arr, deleteIdArr, presetId) { var t = this; var callback = function (success) { if (!success) { return; } History.Create_NewPoint(); History.StartTransaction(); var j, n; if (deleteIdArr) { for (j = 0; j < deleteIdArr.length; j++) { var _oRule = t.model.getCFRuleById(deleteIdArr[j]); var _ranges; if (_oRule) { _ranges = _oRule.ranges; } t.model.deleteCFRule(deleteIdArr[j], true); if (_ranges) { for (n = 0; n < _ranges.length; n++) { t._updateRange(_ranges[n]); } } } } if (arr && arr[nActive]) { for (j = 0; j < arr[nActive].length; j++) { t.model.setCFRule(arr[nActive][j]); if (arr[nActive][j].ranges) { for (n = 0; n < arr[nActive][j].ranges.length; n++) { t._updateRange(arr[nActive][j].ranges[n]); } } } } //TODO возможно здесь необходимо пересчитать формулы t.draw(); History.EndTransaction(); }; var _checkRule = function (_rule) { if (_rule) { if (!arr) { arr = []; } if (!arr[nActive]) { arr[nActive] = []; } arr[nActive].push(_rule); if (_rule.priority === null) { _rule.priority = 1; //двигаем приоритет у всех остальных и добавляем их в список измененных if (t.model.isConditionalFormattingRules()) { t.model.forEachConditionalFormattingRules(function (val) { var _id = val.id; var oRule = val.clone(); oRule.id = _id; oRule.priority++; arr[nActive].push(oRule); }) } } if (_rule.ranges === null) { _rule.ranges = []; if (t.model.selectionRange && t.model.selectionRange.ranges) { for (var j = 0; j < t.model.selectionRange.ranges.length; j++) { _rule.ranges.push(t.model.selectionRange.ranges[j].clone()); } } } } }; var nActive = this.model.workbook.nActive; var i; if (presetId !== undefined) { //data bar/icons/scale presets _checkRule(t.model.generateCFRuleFromPreset(presetId)); } else if (arr && arr.length === 1 && undefined === arr[0].length) { //other presets var presetRule = arr[0]; arr = []; _checkRule(presetRule); } var unitedArr = []; if (arr) { if (arr[nActive]) { for (i = 0; i < arr[nActive].length; i++) { unitedArr.push(arr[nActive][i].id); } } } if (deleteIdArr && deleteIdArr.length) { unitedArr = unitedArr.concat(deleteIdArr); } this._isLockedCF(callback, unitedArr); }; WorksheetView.prototype.deleteCF = function (arr, type) { var t = this, _ranges; var callback = function (success) { if (!success) { return; } History.Create_NewPoint(); History.StartTransaction(); var updateRanges = []; for (var i = 0; i < arr.length; i++) { //TODO для мультиселекта - передать массив! updateRanges = updateRanges.concat(arr[i].ranges); t.model.tryClearCFRule(arr[i], _ranges); } //TODO возможно здесь необходимо пересчитать формулы if (updateRanges) { for (i = 0; i < updateRanges.length; i++) { t._updateRange(updateRanges[i]); } } t.draw(); History.EndTransaction(); }; switch (type) { case Asc.c_oAscSelectionForCFType.selection: _ranges = this.model.selectionRange.getLast(); break; case Asc.c_oAscSelectionForCFType.table: var thisTableIndex = this.model.autoFilters.searchRangeInTableParts(this.model.selectionRange.getLast()); if (thisTableIndex >= 0) { _ranges = this.model.TableParts[thisTableIndex].Ref; } break; case Asc.c_oAscSelectionForCFType.pivot: var _activeCell = this.model.selectionRange.activeCell; var _pivot = this.model.getPivotTable(_activeCell.col, _activeCell.row); if (_pivot) { _ranges = _pivot.location && _pivot.location.ref; } break; } if (_ranges) { _ranges = [_ranges]; } var lockArr = []; if (arr) { for (var i = 0; i < arr.length; i++) { lockArr.push(arr[i].id); } } this._isLockedCF(callback, lockArr); }; WorksheetView.prototype.updateTopLeftCell = function () { var t = this; var callback = function () { t.model.updateTopLeftCell(t.visibleRange); }; if (AscCommon.g_specialPasteHelper) { AscCommon.g_specialPasteHelper.executeWithoutHideButton(callback); } else { callback(); } }; WorksheetView.prototype.getApi = function() { return this.workbook && this.workbook.Api; } /** * * @param { number } row index of row * @param { number } column index of column */ WorksheetView.prototype.scrollToCell = function (row, column) { var visibleRange = this.getVisibleRange(); var topRow = visibleRange.r1; var leftCol = visibleRange.c1; var rowDelta = row - topRow; var columnDelta = column - leftCol; this.scrollVertical(rowDelta); this.scrollHorizontal(columnDelta); } WorksheetView.prototype.scrollToTopLeftCell = function () { var topLeftCell = this.model.getTopLeftCell(); if (topLeftCell) { this._scrollToRange(topLeftCell); } }; WorksheetView.prototype._initTopLeftCell = function () { var topLeftCell = this.model.getTopLeftCell(); if (topLeftCell) { this.visibleRange = topLeftCell.clone(); } }; WorksheetView.prototype.getCurrentTopLeftCell = function () { return this.model.generateTopLeftCellFromRange(this.visibleRange); }; WorksheetView.prototype.setProtectedRanges = function (arr, deleteArr) { var t = this; var callback = function (success) { if (!success) { return; } History.Create_NewPoint(); History.StartTransaction(); var j; if (deleteIdArr) { for (j = 0; j < deleteIdArr.length; j++) { t.model.deleteProtectedRange(deleteIdArr[j], true); } } if (arr) { for (j = 0; j < arr.length; j++) { t.model.setProtectedRange(arr[j]); } } History.EndTransaction(); }; var i; var deleteIdArr; if (deleteArr) { deleteIdArr = []; for (i = 0; i < deleteArr.length; i++) { deleteIdArr.push(deleteArr[i].Id); } } var unitedArr = []; if (arr) { for (i = 0; i < arr.length; i++) { unitedArr.push(arr[i].Id); } } if (deleteIdArr && deleteIdArr.length) { unitedArr = unitedArr.concat(deleteIdArr); } //TODO протащить всё для локов, аналогично CF this._isLockedProtectedRange(callback, unitedArr); }; WorksheetView.prototype.updateAfterChangeSheetProtection = function () { var sheetProtection = this.model.sheetProtection; if (sheetProtection && sheetProtection.getSheet()) { //selection var canSelectLockedCells = !sheetProtection.getSelectLockedCells(); var canSelectUnLockedCells = !sheetProtection.getSelectUnlockedCells(); if (!canSelectLockedCells && canSelectUnLockedCells) { //если стоим на заблокированной ячейке, то меняем селект на незаблокированный var isUnlocked = this.model.getUnlockedCellInRange(this.model.selectionRange.getLast()); if (!isUnlocked) { isUnlocked = this.model.getUnlockedCellInRange(); } //меняем селект if (isUnlocked) { this.setSelection(new Asc.Range(isUnlocked.nCol, isUnlocked.nRow, isUnlocked.nCol, isUnlocked.nRow)); } else { //нужно сделать так, чтобы селект вообще не отображался } } } if(this.model.getSheetProtection(Asc.c_oAscSheetProtectType.objects)) { this._endSelectionShape(); } else { var oObjectRender = this.objectRender; if(oObjectRender && oObjectRender.controller) { oObjectRender.OnUpdateOverlay(); oObjectRender.controller.updateSelectionState(true); } } var ar = this.model.selectionRange && this.model.selectionRange.getLast(); if (ar) { this._updateRange(ar); } this.draw(); }; WorksheetView.prototype.checkProtectRangeOnEdit = function (aRanges, callback, checkLockedRangeOnProtect, textAreaBlurFunc) { var t = this; var wsModel = this.model; var isProtectSheet = wsModel.getSheetProtection(); if (!aRanges || !isProtectSheet) { callback(true); return; } //если выделить ничего нельзя, то и редактировать возможности нет if (wsModel.getSheetProtection(Asc.c_oAscSheetProtectType.selectLockedCells) && wsModel.getSheetProtection(Asc.c_oAscSheetProtectType.selectUnlockedCells)) { return; } var checkRange = function (_protectedRanges, _range) { var needCheckPasswordDialog = true; for (var j = 0; j < _protectedRanges.length; j++) { if (!_protectedRanges[j].asc_isPassword() || _protectedRanges[j]._isEnterPassword) { needCheckPasswordDialog = false; break; } } if (needCheckPasswordDialog) { aCheckPasswordRanges.push(new AscCommon.CellBase(_range.r1, _range.c1)); } }; var aCheckPasswordRanges = []; for (var i = 0; i < aRanges.length; i++) { var range = aRanges[i]; var lockedCell = isProtectSheet && wsModel.isLockedRange(range); var protectedRanges; if (lockedCell) { if (checkLockedRangeOnProtect) { var lockedRanges = wsModel.getLockedRanges(range); for (var n = 0; n < lockedRanges.length; n++) { protectedRanges = wsModel.protectedRangesContainsRange(lockedRanges[i]); if (!protectedRanges) { textAreaBlurFunc && textAreaBlurFunc(); t.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ChangeOnProtectedSheet, c_oAscError.Level.NoCritical); callback(false); return false; } else { checkRange(protectedRanges, lockedRanges[i]); } } } else { protectedRanges = wsModel.protectedRangesContainsRange(range); if (!protectedRanges) { textAreaBlurFunc && textAreaBlurFunc(); t.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ChangeOnProtectedSheet, c_oAscError.Level.NoCritical); callback(false); return false; } else { checkRange(protectedRanges, range); } } } } //в сдучае, допустим, мультиселекта, когда попадаем в несколько диапазонов с паролем, выдаём ошибку //в дальнейшем можно использовать Promise.all if (aCheckPasswordRanges.length > 1) { textAreaBlurFunc && textAreaBlurFunc(); this.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ChangeOnProtectedSheet, c_oAscError.Level.NoCritical); callback(false); } else if (aCheckPasswordRanges.length === 1) { textAreaBlurFunc && textAreaBlurFunc(); //внутри asc_onConfirmAction дёргаем checkProtectedRangesPassword this.model.workbook.handlers.trigger("asc_onConfirmAction", Asc.c_oAscConfirm.ConfirmChangeProtectRange, function (can, isCancel) { if (!can && !isCancel) { t.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.PasswordIsNotCorrect, c_oAscError.Level.NoCritical); } callback(can); }, aCheckPasswordRanges[0]); } else { callback(true); } }; WorksheetView.prototype.isProtectActiveCell = function () { var t = this; var wsModel = this.model; var isProtectSheet = wsModel && wsModel.getSheetProtection(); if (isProtectSheet) { var activeCell = wsModel.selectionRange && wsModel.selectionRange.activeCell; if (activeCell) { return wsModel.getLockedCell(activeCell.col, activeCell.row) && !wsModel.protectedRangesContains(activeCell.col, activeCell.row); } } return false; }; WorksheetView.prototype.isUserProtectActiveCell = function () { var t = this; var wsModel = this.model; if (wsModel.userProtectedRanges && wsModel.userProtectedRanges.length) { var activeCell = wsModel.selectionRange && wsModel.selectionRange.activeCell; if (activeCell) { return this.model.isUserProtectedRangesIntersection(new Asc.Range(activeCell.col, activeCell.row, activeCell.col, activeCell.row)); } } return false; }; WorksheetView.prototype.executeWithFirstActiveCellInMerge = function (runFunction) { var wsModel = this.model; var activeCell = wsModel.selectionRange && wsModel.selectionRange.activeCell; var realRow = activeCell && activeCell.row; var realCol = activeCell && activeCell.col; var merged = this.model.getMergedByCell(realRow, realCol); if (merged) { activeCell.row = merged.r1; activeCell.col = merged.c1; runFunction(); } else { runFunction(); return; } activeCell.row = realRow; activeCell.col = realCol; }; WorksheetView.prototype.getMaxRowColWithData = function (doNotRecalc) { let modelRowsCount = this.model.getRowsCount(); let modelColsCount = this.model.getColsCount(); /*if (modelRowsCount > nMaxPrintRows) { return null; }*/ let range = new asc_Range(0, 0, modelColsCount - 1, modelRowsCount - 1); let maxCell = this._calculateMaxPrintRange(range, doNotRecalc/*, modelRowsCount > nMaxPrintRows*/); /*if (!maxCell) { return maxCell; }*/ let maxCol = maxCell.col; let maxRow = maxCell.row; maxCell = this.model.getSparkLinesMaxColRow(); maxCol = Math.max(maxCol, maxCell.col); maxRow = Math.max(maxRow, maxCell.row); maxCell = this.model.autoFilters.getMaxColRow(); maxCol = Math.max(maxCol, maxCell.col); maxRow = Math.max(maxRow, maxCell.row); // Получаем максимальную колонку/строку для изображений/чатов maxCell = this.objectRender && this.objectRender.getMaxColRow(); if (maxCell) { maxCol = Math.max(maxCol, maxCell.col); maxRow = Math.max(maxRow, maxCell.row); } return {row: maxRow, col: maxCol}; }; WorksheetView.prototype.updateExternalReferenceByCell = function (c, initStructure, callback, forceUpdate) { var t = this; var externalReferences = this.getExternalReferencesByCell(c, initStructure); this.workbook.doUpdateExternalReference(externalReferences, callback, forceUpdate); }; WorksheetView.prototype.getExternalReferencesByCell = function (c, initStructure, opt_get_only_ids) { let t = this; let externalReferences = []; t.model._getCell(c.bbox.r1, c.bbox.c1, function (cell) { if (cell && cell.isFormula()) { let fP = cell.formulaParsed; let needCalc = false; if (fP) { for (let i = 0; i < fP.outStack.length; i++) { let type = fP.outStack[i].type; if ((AscCommonExcel.cElementType.cellsRange3D === type || AscCommonExcel.cElementType.cell3D === type || AscCommonExcel.cElementType.name3D === type) && fP.outStack[i].externalLink) { let eR = t.model.workbook.getExternalLink(fP.outStack[i].externalLink); if (eR) { externalReferences.push(opt_get_only_ids ? eR.Id : eR.getAscLink()); if (initStructure) { if (AscCommonExcel.cElementType.name3D === type) { eR.initDefinedName(fP.outStack[i]); } else { eR.initRows(fP.outStack[i].getRange()); } } } } else if (initStructure && fP.outStack[i].type === AscCommonExcel.cElementType.func && fP.outStack[i].name === "IMPORTRANGE") { needCalc = true; } } } if (needCalc) { let importRangeLinks = fP.importFunctionsRangeLinks; if (importRangeLinks) { for (let i in importRangeLinks) { let eR = t.model.workbook.getExternalLink(i); if (eR) { externalReferences.push(opt_get_only_ids ? eR.Id : eR.getAscLink()); if (initStructure) { for (let j in importRangeLinks[i]) { let rangeOptions = importRangeLinks[i][j]; let externalWs = eR.worksheets && eR.worksheets[rangeOptions.sheet]; if (!externalWs) { externalWs = t.model.workbook.getExternalWorksheetByName(i, rangeOptions.sheet); } if (externalWs) { let _range = externalWs.getRange2(rangeOptions.range); eR.initRows(_range); } } } } } } } } }); return externalReferences.length ? externalReferences : null; }; WorksheetView.prototype.shiftCellWatches = function (bInsert, operType, updateRange) { let i, cellWatch, cellWatchRange, aRemoveCellWatches = [], updatedIndexes/*map[index] = obj*/; let aCellWatches = this.model.aCellWatches; let indexDiff = 0; if (aCellWatches && aCellWatches.length) { for (i = 0; i < this.workbook.model.aWorksheets.length; i++) { let ws = this.workbook.model.aWorksheets[i]; if (ws === this.model ) { break; } else if (ws.aCellWatches && ws.aCellWatches.length) { indexDiff += ws.aCellWatches.length; } } } for (let i = 0; i < aCellWatches.length; i++) { cellWatch = aCellWatches[i]; cellWatchRange = cellWatch && cellWatch.r; if (!cellWatchRange) { continue; } let isChanged = false; if (bInsert) { switch (operType) { case c_oAscInsertOptions.InsertCellsAndShiftDown: if ((cellWatchRange.r1 >= updateRange.r1) && (cellWatchRange.c1 >= updateRange.c1) && (cellWatchRange.c1 <= updateRange.c2)) { cellWatch.setOffset( updateRange.r2 - updateRange.r1 + 1); isChanged = true; } break; case c_oAscInsertOptions.InsertCellsAndShiftRight: if ((cellWatchRange.c1 >= updateRange.c1) && (cellWatchRange.r1 >= updateRange.r1) && (cellWatchRange.r1 <= updateRange.r2)) { cellWatch.setOffset(null, updateRange.c2 - updateRange.c1 + 1); isChanged = true; } break; case c_oAscInsertOptions.InsertColumns: if (cellWatchRange.c1 >= updateRange.c1) { cellWatch.setOffset(null, updateRange.c2 - updateRange.c1 + 1); isChanged = true; } break; case c_oAscInsertOptions.InsertRows: if (cellWatchRange.r1 >= updateRange.r1) { cellWatch.setOffset(updateRange.r2 - updateRange.r1 + 1); isChanged = true; } break; } } else { switch (operType) { case c_oAscDeleteOptions.DeleteCellsAndShiftTop: if ((cellWatchRange.r1 > updateRange.r2) && (cellWatchRange.c1 >= updateRange.c1) && (cellWatchRange.c1 <= updateRange.c2)) { cellWatch.setOffset(-(updateRange.r2 - updateRange.r1 + 1)); isChanged = true; } else if (updateRange.contains(cellWatchRange.c1, cellWatchRange.r1)) { aRemoveCellWatches.push(cellWatchRange); } break; case c_oAscDeleteOptions.DeleteCellsAndShiftLeft: if ((cellWatchRange.c1 > updateRange.c2) && (cellWatchRange.r1 >= updateRange.r1) && (cellWatchRange.r1 <= updateRange.r2)) { cellWatch.setOffset(null, -(updateRange.c2 - updateRange.c1 + 1)); isChanged = true; } else if (updateRange.contains(cellWatchRange.c1, cellWatchRange.r1)) { aRemoveCellWatches.push(cellWatchRange); } break; case c_oAscDeleteOptions.DeleteColumns: if (cellWatchRange.c1 > updateRange.c2) { cellWatch.setOffset(null, -(updateRange.c2 - updateRange.c1 + 1)); isChanged = true; } else if ((updateRange.c1 <= cellWatchRange.c1) && (updateRange.c2 >= cellWatchRange.c1)) { aRemoveCellWatches.push(cellWatchRange); } break; case c_oAscDeleteOptions.DeleteRows: if (cellWatchRange.r1 > updateRange.r2) { cellWatch.setOffset(-(updateRange.r2 - updateRange.r1 + 1)); isChanged = true; } else if ((updateRange.r1 <= cellWatchRange.r1) && (updateRange.r2 >= cellWatchRange.r1)) { aRemoveCellWatches.push(cellWatchRange); } break; } } if (isChanged) { if (!updatedIndexes) { updatedIndexes = {}; } cellWatch.recalculate(true); updatedIndexes[indexDiff + i] = cellWatch; } } if (updatedIndexes) { this.model.workbook.handlers.trigger("asc_onUpdateCellWatches", updatedIndexes); } if (aRemoveCellWatches.length) { for (let j = 0; j < aRemoveCellWatches.length; j++) { this.model.deleteCellWatch(aRemoveCellWatches[j], true); } } }; WorksheetView.prototype.moveCellWatches = function (from, to, copy, opt_wsTo) { if (from && to) { var colOffset = to.c1 - from.c1; var rowOffset = to.r1 - from.r1; var modelTo = opt_wsTo ? opt_wsTo.model : this.model; var cellWatches = this.model.getCellWatchesByRange(from); if (!copy) { this.model.deleteCellWatchesByRange(from, true); } modelTo.deleteCellWatchesByRange(to, true); for (var i = 0; i < cellWatches.length; ++i) { var newCellWatch = cellWatches[i].clone(); newCellWatch.r.c1 += colOffset; newCellWatch.r.c2 += colOffset; newCellWatch.r.r1 += rowOffset; newCellWatch.r.r2 += rowOffset; modelTo.addCellWatch(newCellWatch.r, true); } } }; WorksheetView.prototype._cleanPagesModeData = function () { this.pagesModeData = null; }; WorksheetView.prototype.pagesModeDataContains = function (col, row) { let res = null; if (this.isPageBreakPreview(true) && this.pagesModeData && this.pagesModeData.printPages) { res = false; let printPages = this.pagesModeData.printPages; for (let i = 0; i < printPages.length; i++) { if (printPages[i].page && printPages[i].page.pageRange && printPages[i].page.pageRange.contains(col, row)) { res = true; break; } } } return res; }; WorksheetView.prototype._getPageBreakPreviewRanges = function (oPrintPages) { let printRanges = null; oPrintPages = oPrintPages || (this.isPageBreakPreview(true) && this.pagesModeData && this.pagesModeData.printPages); if (oPrintPages) { printRanges = this.pagesModeData.printRanges; if (!printRanges) { let printPages = this.pagesModeData.printPages; let startRange = printPages && printPages[0] && printPages[0].page && printPages[0].page.pageRange; let endRange = printPages && printPages[printPages.length - 1] && printPages[printPages.length - 1].page && printPages[printPages.length - 1].page.pageRange; if (startRange && endRange) { printRanges = [{ range: new Asc.Range(startRange.c1, startRange.r1, endRange.c2, endRange.r2), start: 0, end: printPages.length }]; } } } return printRanges; }; WorksheetView.prototype.onChangePageSetupProps = function () { this._cleanPagesModeData(); if (this.isPageBreakPreview(true)) { this.model && this.model.PagePrintOptions && this.model.PagePrintOptions.initPrintTitles(); if (this.workbook && this.workbook.model && this.workbook.model.getActiveWs() === this.model) { this.draw(this.lockDraw); } } }; WorksheetView.prototype.isPageBreakPreview = function (checkPrintPreviewMode) { var isPrintPreview = this.workbook.printPreviewState && this.workbook.printPreviewState.isStart(); if (checkPrintPreviewMode && isPrintPreview) { return false; } return this.model && this.model.getSheetViewType() === AscCommonExcel.ESheetViewType.pageBreakPreview; }; WorksheetView.prototype.setSheetViewType = function (val) { if (this.model && this.model.setSheetViewType(val, true)) { this._cleanPagesModeData(); this.draw(); } }; WorksheetView.prototype.setColsCount = function (val) { this.nColsCount = val; }; WorksheetView.prototype.getRetinaPixelRatio = function () { return AscBrowser.retinaPixelRatio; }; //cell trace dependents/precedents WorksheetView.prototype.tracePrecedents = function () { if (this.traceDependentsManager) { this.traceDependentsManager.calculatePrecedents(); this.updateSelection(); } }; WorksheetView.prototype.traceDependents = function () { if (this.traceDependentsManager) { this.traceDependentsManager.calculateDependents(); this.updateSelection(); } }; WorksheetView.prototype.removeTraceArrows = function (type) { if (this.traceDependentsManager && this.traceDependentsManager.isHaveData()) { this.cleanSelection(); this.traceDependentsManager.clear(type); this.updateSelection(); } }; WorksheetView.prototype.changeLegacyDrawingHFPictures = function (picturesMap) { //lock? if (!picturesMap) { return; } this.model.changeLegacyDrawingHFPictures(picturesMap); }; WorksheetView.prototype.removeLegacyDrawingHFPictures = function (aPictures) { //lock? if (!aPictures) { return; } this.model.removeLegacyDrawingHFPictures(aPictures); }; /** * Method applies series settings when user confirms "Series" settings in dialog window or context menu. * @param {Asc.c_oAscFillType} type * @param {asc_CSeriesSettings} [settings] */ WorksheetView.prototype.applySeriesSettings = function (type, settings) { const oThis = this; const cSerial = settings ? new AscCommonExcel.CSerial(settings) : null; const oRange = this.model.getSelection().getLast(); const oRangeModel = this.model.getRange3(oRange.r1, oRange.c1, oRange.r2, oRange.c2); const sNumFormat = oRangeModel.getXfs() && oRangeModel.getXfs().num && oRangeModel.getXfs().num.getFormat(); const bDateType = !!(sNumFormat && AscCommon.oNumFormatCache.get(sNumFormat).isDateTimeFormat()); let oRanges = this.model.getSelection(); let aRanges = oRanges.ranges; let _setSelection = function (_newSelectionRange) { //aRanges[0].assign(_newSelectionRange.c1, _newSelectionRange.r1, _newSelectionRange.c2, _newSelectionRange.r2); oThis.setSelection(_newSelectionRange); }; let prepareFillHandle = function (selectionRange) { let cloneSelection = selectionRange.clone(); let _applyFillHandleSettings = function (_fillRange, _direction, _area) { oThis.activeFillHandle = _fillRange; oThis.fillHandleDirection = _direction; oThis.fillHandleArea = _area; }; let oneRow = selectionRange.isOneRow(); let oneCol = selectionRange.isOneCol(); let ws = oThis.model; let aMergedCells = ws.mergeManager.get(selectionRange).all; if (type === c_oAscFillType.fillDown) { if (oneRow && selectionRange.r1 === 0) { return false; } if (aMergedCells.length) { let oMergedRange = aMergedCells[0].bbox; selectionRange.assign(oMergedRange.c1, oMergedRange.r1, oMergedRange.c2, oMergedRange.r2); } else { selectionRange.assign(selectionRange.c1, selectionRange.r1 - 1*oneRow, selectionRange.c2, selectionRange.r1 - 1*oneRow); } _applyFillHandleSettings(cloneSelection, 1, 3); } else if (type === c_oAscFillType.fillUp) { if (oneRow && selectionRange.r2 === gc_nMaxRow0) { return false; } if (aMergedCells.length) { let oMergedRange = aMergedCells[aMergedCells.length - 1].bbox; selectionRange.assign(oMergedRange.c1, oMergedRange.r1, oMergedRange.c2, oMergedRange.r2); } else { selectionRange.assign(selectionRange.c1, selectionRange.r2 + 1 * oneRow, selectionRange.c2, selectionRange.r2 + 1 * oneRow); } _applyFillHandleSettings(new asc_Range(cloneSelection.c2, cloneSelection.r2, cloneSelection.c1, cloneSelection.r1), 1, 1); } else if (type === c_oAscFillType.fillRight) { if (oneCol && selectionRange.c1 === 0) { return false; } if (aMergedCells.length) { let oMergedRange = aMergedCells[0].bbox; selectionRange.assign(oMergedRange.c1, oMergedRange.r1, oMergedRange.c2, oMergedRange.r2); } else { selectionRange.assign(selectionRange.c1 - 1*oneCol, selectionRange.r1, selectionRange.c1 - 1*oneCol, selectionRange.r2); } _applyFillHandleSettings(cloneSelection, 0, 3); } else if (type === c_oAscFillType.fillLeft) { if (oneCol && selectionRange.c2 === gc_nMaxCol0) { return false; } if (aMergedCells.length) { let oMergedRange = aMergedCells[aMergedCells.length - 1].bbox; selectionRange.assign(oMergedRange.c1, oMergedRange.r1, oMergedRange.c2, oMergedRange.r2); } else { selectionRange.assign(selectionRange.c2 + 1 * oneCol, selectionRange.r1, selectionRange.c2 + 1 * oneCol, selectionRange.r2); } _applyFillHandleSettings(new asc_Range(cloneSelection.c2, cloneSelection.r2, cloneSelection.c1, cloneSelection.r1), 0, 1); } return true; }; let _setScrollType = function (_typeSelection) { if (_typeSelection === Asc.c_oAscSelectionType.RangeCol || _typeSelection === Asc.c_oAscSelectionType.RangeMax) { oThis.scrollType |= AscCommonExcel.c_oAscScrollType.ScrollVertical; } if (_typeSelection === Asc.c_oAscSelectionType.RangeRow || _typeSelection === Asc.c_oAscSelectionType.RangeMax) { oThis.scrollType |= AscCommonExcel.c_oAscScrollType.ScrollHorizontal; } }; switch (type) { case c_oAscFillType.copyCells: if (!this.activeFillHandle) { return; } // Selected one cell with number type data for copy cells changes ctrlPress logic to false if (oRange.isOneCell() && oRangeModel.getType() === AscCommon.CellValueType.Number && !bDateType) { this.applyFillHandle(null, null, false, null); } else { this.applyFillHandle(null, null, true, null); } break; case c_oAscFillType.fillSeries: case c_oAscFillType.fillDays: case c_oAscFillType.fillWeekdays: case c_oAscFillType.fillMonths: case c_oAscFillType.fillYears: if (!this.activeFillHandle) { return; } // Selected one cell with number type data for fills series changes ctrlPress logic to true if (oRange.isOneCell() && oRangeModel.getType() === AscCommon.CellValueType.Number && !bDateType) { this.applyFillHandle(null, null, true, null); } else { this.model.setFillHandleRightClick(true); this.model.setFillMenuChosenProp(type); this.applyFillHandle(null, null, false, null); this.model.setFillHandleRightClick(false); this.model.setFillMenuChosenProp(null); } break; case c_oAscFillType.linearTrend: case c_oAscFillType.growthTrend: if (!cSerial) { return; } this._isLockedCells(oRangeModel, /*subType*/null, function (success) { if (!success) { return; } cSerial.setFromRange(oRangeModel); cSerial.setActiveFillHandle(oThis.activeFillHandle); cSerial.exec(); oThis._updateRange(oThis.activeFillHandle); _setSelection(oThis.activeFillHandle); oThis.cleanFillHandleProps(true); oThis.draw(); }); break; case c_oAscFillType.series: if (!cSerial) { return; } if (this.activeFillHandle != null) { cSerial.setActiveFillHandle(this.activeFillHandle); } this._isLockedCells(aRanges, /*subType*/null, function (success) { if (!success) { return; } History.Create_NewPoint(); History.StartTransaction(); for (let i = 0; i < aRanges.length; i++) { const oRangeModel = oThis.model.getRange3(aRanges[i].r1, aRanges[i].c1, aRanges[i].r2, aRanges[i].c2); cSerial.setFromRange(oRangeModel); cSerial.exec(); } if (oThis.activeFillHandle) { _setSelection(oThis.activeFillHandle); //History.SetSelection(oThis.activeFillHandle.clone()); History.SetSelectionRedo(oThis.activeFillHandle.clone()); oThis._updateRange(oThis.activeFillHandle); } History.EndTransaction(); oThis.cleanFillHandleProps(true); //update for (let i = 0; i < aRanges.length; i++) { let typeSelection = aRanges[i] && aRanges[i].getType(); if (typeSelection === Asc.c_oAscSelectionType.RangeCol || typeSelection === Asc.c_oAscSelectionType.RangeMax) { oThis._cleanCache(aRanges[i]); oThis.arrRecalcRangesWithHeight.push(new Asc.Range(0, 0, oThis.visibleRange.c2, oThis.visibleRange.r2)); oThis.arrRecalcRangesCanChangeColWidth.push(oThis.canChangeColWidth); } else { oThis._updateRange(aRanges[i]); } _setScrollType(typeSelection); } oThis.model.workbook.handlers.trigger("cleanCutData", null, true); oThis.model.workbook.handlers.trigger("cleanCopyData"); oThis.draw(); }); break; case c_oAscFillType.fillDown: case c_oAscFillType.fillLeft: case c_oAscFillType.fillRight: case c_oAscFillType.fillUp: //don't work in ms if (aRanges.length > 1) { return; } let _cloneSelection = aRanges[0].clone(); if (prepareFillHandle(aRanges[0])) { History.Create_NewPoint(); History.StartTransaction(); let isCtrlKey = true; oThis.model.setActiveFillType(type); oThis.applyFillHandle(null, null, isCtrlKey, true, function (success) { _setSelection(_cloneSelection); History.SetSelection(_cloneSelection); History.SetSelectionRedo(_cloneSelection); History.EndTransaction(); let typeSelection = _cloneSelection.getType(); if ((type === c_oAscFillType.fillDown || type === c_oAscFillType.fillUp) && (typeSelection === Asc.c_oAscSelectionType.RangeCol || typeSelection === Asc.c_oAscSelectionType.RangeMax)) { oThis.scrollType |= AscCommonExcel.c_oAscScrollType.ScrollVertical; } if ((type === c_oAscFillType.fillLeft || type === c_oAscFillType.fillRight) && (typeSelection === Asc.c_oAscSelectionType.RangeRow || typeSelection === Asc.c_oAscSelectionType.RangeMax)) { oThis.scrollType |= AscCommonExcel.c_oAscScrollType.ScrollHorizontal; } if ((typeSelection === Asc.c_oAscSelectionType.RangeCol || typeSelection === Asc.c_oAscSelectionType.RangeMax)) { oThis.arrRecalcRangesWithHeight = []; oThis.arrRecalcRangesWithHeight.push(new Asc.Range(0, 0, oThis.visibleRange.c2, oThis.visibleRange.r2)); } oThis.draw(); oThis.model.setActiveFillType(null); }); } break; } }; WorksheetView.prototype.cleanFillHandleProps = function (opt_doNotDraw) { this.activeFillHandle = null; this.resizeTableIndex = null; this.fillHandleDirection = -1; if (!opt_doNotDraw) { this.draw(); } }; WorksheetView.prototype.getRenderingSettings = function () { return this.renderingSettings; }; WorksheetView.prototype.setRenderingSettings = function (val) { this.renderingSettings = val; }; WorksheetView.prototype.initRenderingSettings = function () { this.renderingSettings = new CRenderingSettings(); return this.renderingSettings; }; WorksheetView.prototype.getVScrollStep = function () { let isMobileVersion = this.workbook && this.workbook.Api && this.workbook.Api.isMobileVersion; return this.vScrollPxStep * this.getZoom() * (isMobileVersion ? this.getRetinaPixelRatio() : 1); }; WorksheetView.prototype.getHScrollStep = function () { return this.hScrollPxStep * this.getZoom() * this.getRetinaPixelRatio(); }; WorksheetView.prototype.checkRtl = function (x, ctx, units, checkOffsets) { if (this.getRightToLeft()) { let u = units >= 0 && units <= 3 ? units : 0; let kf = asc_getcvt(0/*px*/, u, this._getPPIX()); if (!ctx) { ctx = this.drawingCtx; } return this.getCtxWidth(ctx, checkOffsets) * kf - x; } return x; }; WorksheetView.prototype.getRightToLeft = function () { let sheetViewSettings = this.getSheetViewSettings(true); return sheetViewSettings.rightToLeft; }; WorksheetView.prototype.setRightToLeft = function (val) { let sheetViewSettings = this.getSheetViewSettings(true); sheetViewSettings.rightToLeft = val; }; WorksheetView.prototype.getCtxWidth = function (ctx, checkOffsets) { if (!ctx) { ctx = this.drawingCtx; } let res; let renderingSettings = this.getRenderingSettings(); if (renderingSettings && renderingSettings.getCtxWidth()) { let offset = checkOffsets ? (renderingSettings.getPageLeftOffset() + renderingSettings.getPageLeftOffset()) : 0; let printScale = renderingSettings.printScale ? renderingSettings.printScale : 1; res = (renderingSettings.getCtxWidth()/printScale - offset); } else { res = ctx.getWidth(); } return res; }; WorksheetView.prototype.getRightToLeftOffset = function () { return this.getRightToLeft() ? 1 : 0; }; WorksheetView.prototype.checkGraphicObjectsBounds = function () { this.objectRender.updateSizeDrawingObjects({target: c_oTargetType.ColumnResize, col: 100}); this.objectRender.updateDrawingsTransform({target: c_oTargetType.ColumnResize, col: 100}); this.objectRender.updateRange(new Asc.Range(0, 0, gc_nMaxCol0, gc_nMaxCol0)); }; WorksheetView.prototype._lineHor = function (ctx, x1, y, x2) { ctx.lineHor(this.getRightToLeft() ? (this.getCtxWidth(ctx) - x1) : x1, y, this.getRightToLeft() ? (this.getCtxWidth(ctx) - x2) : x2) return ctx; }; WorksheetView.prototype._lineVer = function (ctx, x, y1, y2) { ctx.lineVer(this.getRightToLeft() ? (this.getCtxWidth(ctx) - x) : x, y1, y2) return ctx; }; WorksheetView.prototype._lineDiag = function (ctx, x1, y1, x2, y2) { ctx.lineDiag(this.getRightToLeft() ? (this.getCtxWidth(ctx) - x1) : x1, y1, this.getRightToLeft() ? (this.getCtxWidth(ctx) - x2) : x2, y2); return ctx; }; WorksheetView.prototype._lineVerPrevPx = function (ctx, x, y1, y2) { ctx.lineVerPrevPx(this.getRightToLeft() ? (this.getCtxWidth(ctx) - x) : x, y1, y2) return ctx; }; WorksheetView.prototype._lineHorPrevPx = function (ctx, x1, y, x2) { ctx.lineHorPrevPx(this.getRightToLeft() ? (this.getCtxWidth(ctx) - x1) : x1, y, this.getRightToLeft() ? (this.getCtxWidth(ctx) - x2) : x2) return ctx; }; WorksheetView.prototype._dashLineCleverHor = function (ctx, x1, y, x2) { ctx.dashLineCleverHor(this.getRightToLeft() ? (this.getCtxWidth(ctx) - x2) : x1, y, this.getRightToLeft() ? (this.getCtxWidth(ctx) - x1) : x2); return ctx; }; WorksheetView.prototype._dashLineCleverVer = function (ctx, x, y1, y2) { ctx.dashLineCleverVer(this.getRightToLeft() ? (this.getCtxWidth(ctx) - x) : x, y1, y2); return ctx; }; WorksheetView.prototype._AddClipRect = function (ctx, x, y, w, h, skipRtl) { let _x = this.getRightToLeft() && !skipRtl ? (this.getCtxWidth(ctx) - x - w) : x; ctx.AddClipRect && ctx.AddClipRect(_x, y, w, h); if (this.stringRender) { this.stringRender.addClipRect(_x, y, w, h); } return ctx; }; WorksheetView.prototype._RemoveClipRect = function (ctx) { ctx.RemoveClipRect && ctx.RemoveClipRect(); if (this.stringRender) { this.stringRender.removeClipRect(); } return ctx; }; WorksheetView.prototype._moveTo = function (ctx, x, y) { ctx.moveTo(this.getRightToLeft() ? (this.getCtxWidth(ctx) - x) : x, y); return ctx; }; WorksheetView.prototype._lineTo = function (ctx, x, y) { ctx.lineTo(this.getRightToLeft() ? (this.getCtxWidth(ctx) - x) : x, y); return ctx; }; WorksheetView.prototype._fillRect = function (ctx, x, y, w, h) { ctx.fillRect(this.getRightToLeft() ? (this.getCtxWidth(ctx) - x - w) : x, y, w, h); return ctx; }; WorksheetView.prototype._clearRect = function (ctx, x, y, w, h) { ctx.clearRect(this.getRightToLeft() ? (this.getCtxWidth(ctx) - x - w) : x, y, w, h); return ctx; }; WorksheetView.prototype._rect = function (ctx, x, y, w, h) { ctx.rect(this.getRightToLeft() ? (this.getCtxWidth(ctx) - x - w) : x, y, w, h); return ctx; }; WorksheetView.prototype._clearRectByY = function (ctx, x, y, w, h) { ctx.clearRectByY(this.getRightToLeft() ? (this.getCtxWidth(ctx) - x - w) : x, y, w, h); return ctx; }; WorksheetView.prototype._clearRectByX = function (ctx, x, y, w, h) { ctx.clearRectByX(this.getRightToLeft() ? (this.getCtxWidth(ctx) - x - w) : x, y, w, h); return ctx; }; WorksheetView.prototype._drawText = function (stringRender, ctx, textX, textY, textW, color, skipRtl) { stringRender.render(ctx, this.getRightToLeft() && !skipRtl ? (this.getCtxWidth(ctx) - textX - textW) : textX, textY, textW, color); return stringRender; }; WorksheetView.prototype._fillText = function (ctx, text, x, y, maxWidth, charWidths, angle) { ctx.fillText( text, this.getRightToLeft() ? (this.getCtxWidth(ctx) - x) : x, y, maxWidth, charWidths, angle) return ctx; }; WorksheetView.prototype._strokeRect = function (ctx, x, y, w, h) { ctx.strokeRect(this.getRightToLeft() ? (this.getCtxWidth(ctx) - x - w) : x, y, w, h); return ctx; }; WorksheetView.prototype._drawImage = function (ctx, img, sx, sy, sw, sh, dx, dy, dw, dh) { ctx.drawImage(img, this.getRightToLeft() ? (this.getCtxWidth(ctx) - sx - sw) : sx, sy, sw, sh, this.getRightToLeft() ? (this.getCtxWidth(ctx) - dx - dw) : dx, dy, dw, dh); return ctx; }; WorksheetView.prototype._moveImageData = function (sx, sy, sw, sh, dx, dy, dw, dh) { if (AscBrowser.isSafari) { this.drawingGraphicCtx.moveImageDataSafari(this.getRightToLeft() ? (this.getCtxWidth() - sx - sw) : sx, sy, sw, sh, this.getRightToLeft() ? (this.getCtxWidth() - dx - dw) : dx, dy); } else { this.drawingGraphicCtx.moveImageData(this.getRightToLeft() ? (this.getCtxWidth() - sx - sw) : sx, sy, sw, sh, this.getRightToLeft() ? (this.getCtxWidth() - dx - dw) : dx, dy); } }; WorksheetView.prototype.removeAllInks = function () { const model = this.model; const oController = this.objectRender && this.objectRender.controller; if (oController) { const arrInks = model.getAllInks(); oController.removeAllInks(arrInks); } }; WorksheetView.prototype.getSelectionCoords = function () { let range = this._getSelection(); range = range && range.getLast(); if (!range) { return null; } var visibleRange = this.getVisibleRange(); var intersectionVisibleRange = visibleRange.intersection(range); if (!intersectionVisibleRange && this.topLeftFrozenCell) { var cFrozen = this.topLeftFrozenCell.getCol0(); var rFrozen = this.topLeftFrozenCell.getRow0(); cFrozen -= 1; rFrozen -= 1; var frozenRange; if (0 <= cFrozen && 0 <= rFrozen) { frozenRange = new asc_Range(0, 0, cFrozen, rFrozen); intersectionVisibleRange = frozenRange.intersection(range); } if (!intersectionVisibleRange && 0 <= cFrozen) { frozenRange = new asc_Range(0, this.visibleRange.r1, cFrozen, this.visibleRange.r2); intersectionVisibleRange = frozenRange.intersection(range); } if (!intersectionVisibleRange && 0 <= rFrozen) { frozenRange = new asc_Range(this.visibleRange.c1, 0, this.visibleRange.c2, rFrozen); intersectionVisibleRange = frozenRange.intersection(range); } } let res = null; if (!intersectionVisibleRange) { range = visibleRange; intersectionVisibleRange = visibleRange; } if (range && intersectionVisibleRange) { let _elem = this.workbook.Api && this.workbook.Api.HtmlElement let offs = _elem && AscCommon.UI && AscCommon.UI.getBoundingClientRect && AscCommon.UI.getBoundingClientRect(_elem); if (offs) { res = []; res[0] = this.getCellCoord(range.c1, range.r1); res[1] = this.getCellCoord(intersectionVisibleRange.c2, intersectionVisibleRange.r2); if (this.getRightToLeft()) { res[0]._x += res[0]._width; res[1]._x += res[1]._width; } res[0]._x += offs.left; res[1]._x += offs.left; res[0]._y += offs.top; res[1]._y += offs.top; } } return res; }; function CRenderingSettings() { this.splitRowBG = null; //number - how much row need skip, every 2,3 and.. this.ctxWidth = null; this.leftOffset = null; this.rightOffset = null; } CRenderingSettings.prototype.setSplitRowBG = function (val) { this.splitRowBG = val; }; CRenderingSettings.prototype.getSplitRowBG = function () { return this.splitRowBG; }; CRenderingSettings.prototype.isSkipRowBG = function (startRow, row) { let res = null; if (this.splitRowBG) { if ((row - startRow + 1) % this.splitRowBG === 0) { return true; } } return res; }; CRenderingSettings.prototype.getCtxWidth = function () { return this.ctxWidth; }; CRenderingSettings.prototype.setCtxWidth = function (val) { this.ctxWidth = val; }; CRenderingSettings.prototype.setPageLeftOffset = function (val) { this.pageLeftOffset = val; }; CRenderingSettings.prototype.setPageRightOffset = function (val) { this.pageRightOffset = val; }; CRenderingSettings.prototype.getPageLeftOffset = function () { return this.pageLeftOffset; }; CRenderingSettings.prototype.getPageRightOffset = function () { return this.pageRightOffset; }; function cAsyncAction() { this.timer = null; this.props = null;//options for current action this.callback = null;//after action call function this.action = null;//action function this.checkContinue = null;//passed to the action function and return end of action true/false this.interval = 20; } cAsyncAction.prototype.clear = function () { this.props = null; }; cAsyncAction.prototype.start = function () { this.stop(); let oThis = this; this.timer = setTimeout(function () { oThis.continueAction(); }, this.interval); }; cAsyncAction.prototype.continueAction = function () { let oThis = this; let nStartTime = performance.now(); this.action && this.action(function () { if (performance.now() - nStartTime > oThis.interval) { return true; } return false; }, this.props); if (this.checkContinue && this.checkContinue()) { this.timer = setTimeout(function () { oThis.continueAction(); }, this.interval); } else { this.timer = null; this.callback && this.callback(this.props); } }; cAsyncAction.prototype.stop = function () { if (this.timer) { clearTimeout(this.timer); } this.timer = null; }; function CCellPasteHelper(ws) { this.ws = ws; } CCellPasteHelper.prototype.loadDataBeforePaste = function (isLargeRange, val, bIsUpdate, canChangeColWidth, pasteToRange) { let t = this; let ws = this.ws; let specialPasteHelper = window['AscCommon'].g_specialPasteHelper; let specialPasteProps = specialPasteHelper.specialPasteProps; let selectData; let specialPasteChangeColWidth = specialPasteProps && specialPasteProps.width; let revertSelection = function () { if (val && val.originalSelectBeforePaste) { ws.model.selectionRange.ranges = val.originalSelectBeforePaste.ranges; } }; let fromBinaryExcel = val.fromBinary; let pasteContent = val.data; let pastedInfo = []; let callback = function () { let maxRow = Math.min(Math.max(ws.model.getRowsCount(), ws.visibleRange.r2) + 1, gc_nMaxRow); let maxCol = Math.min(Math.max(ws.model.getColsCount(), ws.visibleRange.c2) + 1, gc_nMaxCol); for (let j = 0; j < pasteToRange.length; j++) { _doPaste(pasteToRange[j]); if (!selectData && !fromBinaryExcel) { History.EndTransaction(); revertSelection(); window['AscCommon'].g_specialPasteHelper.Paste_Process_End(); return; } } let _selection; if (fromBinaryExcel) { for (let n = 0; n < pastedInfo.length; n++) { if (pastedInfo && pastedInfo[n] && pastedInfo[n].selectData && pastedInfo[n].selectData[0]) { _selection = ws.model.selectionRange.ranges[n]; _selection.c2 = pastedInfo[n].selectData[0].c2; _selection.r2 = pastedInfo[n].selectData[0].r2; } } } else { _selection = ws.model.selectionRange.getLast(); if (pastedInfo && pastedInfo[0] && pastedInfo[0].selectData && pastedInfo[0].selectData[0]) { _selection.c2 = pastedInfo[0].selectData[0].c2; _selection.r2 = pastedInfo[0].selectData[0].r2; } } History.EndTransaction(); selectData = selectData ? selectData.selectData : null; if (!selectData) { revertSelection(); window['AscCommon'].g_specialPasteHelper.Paste_Process_End(); return; } let arn = selectData[0]; if (bIsUpdate) { if (isLargeRange) { ws.handlers.trigger("slowOperation", false); } if (specialPasteChangeColWidth) { ws.changeWorksheet("update"); } else { //clean cache for all paste range let updateRanges = pasteToRange ? pasteToRange : selectData[0]; let pastedRangeMaxCol, pastedRangeMaxRow; if (updateRanges.length) { for (let i = 0; i < updateRanges.length; i++) { if (!pastedRangeMaxCol || updateRanges[i].c2 > pastedRangeMaxCol) { pastedRangeMaxCol = updateRanges[i].c2; } if (!pastedRangeMaxRow || updateRanges[i].r2 > pastedRangeMaxRow) { pastedRangeMaxRow = updateRanges[i].r2; } ws._cleanCache(updateRanges[i]); } } else { pastedRangeMaxCol = updateRanges.c2; pastedRangeMaxRow = updateRanges.r2; ws._cleanCache(updateRanges); } if (pastedRangeMaxCol < maxCol) { maxCol = Math.max(ws.visibleRange.c2, pastedRangeMaxCol); } if (pastedRangeMaxRow < maxRow) { maxRow = Math.max(ws.visibleRange.r2, pastedRangeMaxRow); } //update only max defined previous data ws._updateRange(Asc.Range(0, 0, maxCol, maxRow)); } } revertSelection(); window['AscCommon'].g_specialPasteHelper.Paste_Process_End(); if (val.needDraw) { ws.draw(); } else { val.needDraw = true; } let oSelection = History.GetSelection(); if (null != oSelection) { oSelection = oSelection.clone(); //TODO selectData! oSelection.assign(arn.c1, arn.r1, arn.c2, arn.r2); History.SetSelection(oSelection); History.SetSelectionRedo(oSelection); } if (val.pasteAllSheet) { History.EndTransaction(); } }; let _doPaste = function (_pasteToRange) { //paste from excel binary if (fromBinaryExcel) { AscCommonExcel.executeInR1C1Mode(false, function () { selectData = t._pasteData(isLargeRange, fromBinaryExcel, pasteContent, bIsUpdate, _pasteToRange, null, val); }); } else { let imagesFromWord = pasteContent.props.addImagesFromWord; if (imagesFromWord && imagesFromWord.length !== 0 && !(window["Asc"]["editor"] && window["Asc"]["editor"].isChartEditor) && specialPasteProps.images) { let oObjectsForDownload = AscCommon.GetObjectsForImageDownload(pasteContent.props._aPastedImages); let oImageMap; //if already load images on server if (AscCommonExcel.g_clipboardExcel.pasteProcessor.alreadyLoadImagesOnServer === true) { oImageMap = {}; for (let i = 0, length = oObjectsForDownload.aBuilderImagesByUrl.length; i < length; ++i) { let url = oObjectsForDownload.aUrls[i]; //get name from array already load on server urls let name = AscCommonExcel.g_clipboardExcel.pasteProcessor.oImages[url]; let aImageElem = oObjectsForDownload.aBuilderImagesByUrl[i]; if (name) { if (Array.isArray(aImageElem)) { for (let j = 0; j < aImageElem.length; ++j) { let imageElem = aImageElem[j]; if (null != imageElem) { imageElem.SetUrl(name); } } } oImageMap[i] = name; } else { oImageMap[i] = url; } } selectData = t._pasteData(isLargeRange, fromBinaryExcel, pasteContent, bIsUpdate, _pasteToRange, null, val); AscCommonExcel.g_clipboardExcel.pasteProcessor._insertImagesFromBinaryWord(ws, pasteContent, oImageMap); } else { oImageMap = pasteContent.props.oImageMap; if (window["NATIVE_EDITOR_ENJINE"]) { //TODO для мобильных приложений - не рабочий код! AscCommon.ResetNewUrls(pasteContent.props.data, oObjectsForDownload.aUrls, oObjectsForDownload.aBuilderImagesByUrl, oImageMap); selectData = t._pasteData(isLargeRange, fromBinaryExcel, pasteContent, bIsUpdate, _pasteToRange, null, val); AscCommonExcel.g_clipboardExcel.pasteProcessor._insertImagesFromBinaryWord(ws, pasteContent, oImageMap); } else { selectData = t._pasteData(isLargeRange, fromBinaryExcel, pasteContent, bIsUpdate, _pasteToRange, null, val); AscCommonExcel.g_clipboardExcel.pasteProcessor._insertImagesFromBinaryWord(ws, pasteContent, oImageMap); } } } else { selectData = t._pasteData(isLargeRange, fromBinaryExcel, pasteContent, bIsUpdate, _pasteToRange, val.bText, val); } if (selectData && selectData.adjustFormatArr && selectData.adjustFormatArr.length) { for (let i = 0; i < selectData.adjustFormatArr.length; i++) { selectData.adjustFormatArr[i]._foreach(function (cell) { cell._adjustCellFormat(); }); } } } pastedInfo.push(selectData); }; callback(); }; CCellPasteHelper.prototype._pasteData = function (isLargeRange, fromBinary, val, bIsUpdate, pasteToRange, bText, pasteInfo) { var ws = this.ws; var t = this; var specialPasteHelper = window['AscCommon'].g_specialPasteHelper; var specialPasteProps = specialPasteHelper.specialPasteProps; if (val.props && val.props.onlyImages === true) { if (!specialPasteHelper.specialPasteStart) { ws.handlers.trigger("showSpecialPasteOptions", [Asc.c_oSpecialPasteProps.picture]); } return; } if (!specialPasteHelper.specialPasteStart) { if (pasteInfo && pasteInfo.originalSelectBeforePaste) { specialPasteHelper.selectionRange = pasteInfo.originalSelectBeforePaste; } else { specialPasteHelper.selectionRange = ws.model.selectionRange ? ws.model.selectionRange.clone() : null; } window['AscCommon'].g_specialPasteHelper.isAppliedOperation = false; } var callTrigger = false; if (isLargeRange) { callTrigger = true; ws.handlers.trigger("slowOperation", true); } //если вставка производится внутрь ф/т, расширяем её вниз var activeTable = ws.model.autoFilters.getTableContainActiveCell(ws.model.selectionRange.activeCell); var newRange; if (pasteToRange && activeTable && specialPasteProps.formatTable) { var delta = pasteToRange.r2 - activeTable.Ref.r2; if (delta > 0) { //TODO пересмотреть! //пока сделал при вставке в ф/т расширяем только в случае, если внизу есть пустые строки, сдвиг не делаем //потому что в случае совместного редактирования необходимо лочить весь лист(из-за сдвига) //и так же необходимо заранее расширить область обновления, чтобы данные внизу ф/т перерисовались //и ещё excel ругается, когда область вставки затрагивает несколько таблиц - причём не во всех случаях - просмотреть! //так же рассмотреть ситуацию, когда вставляется ниже последней строки ф/т заполненные текстом даные(если хоть 1 ячека содержит текст) - баг 26402 if (false && !ws.model.autoFilters._isPartTablePartsUnderRange(activeTable.Ref)) { //сдвигаем и расширяем ws.model.getRange3(activeTable.Ref.r2 + 1, activeTable.Ref.c1, activeTable.Ref.r2 + delta, activeTable.Ref.c2).addCellsShiftBottom(); newRange = new Asc.Range(activeTable.Ref.c1, activeTable.Ref.r1, activeTable.Ref.c2, activeTable.Ref.r2 + delta); } else { //в противном случае используем ячейки внизу таблицы без сдвига, перед этим проверяем на предмет наличия пустых строк под таблицей var tempRange = new Asc.Range(activeTable.Ref.c1, activeTable.Ref.r2 + 1, activeTable.Ref.c2, activeTable.Ref.r2 + delta); if (ws.model.autoFilters._isEmptyRange(tempRange, 0)) { //расширяем таблицу вниз newRange = new Asc.Range(activeTable.Ref.c1, activeTable.Ref.r1, activeTable.Ref.c2, activeTable.Ref.r2 + delta); } } if (newRange) { ws.model.autoFilters.changeTableRange(activeTable.DisplayName, newRange); } } } var pasteRange = AscCommonExcel.g_clipboardExcel.pasteProcessor.activeRange; var activeCellsPasteFragment = typeof pasteRange === "string" ? AscCommonExcel.g_oRangeCache.getAscRange(pasteRange) : pasteRange; //для бага 26402 - добавляю возможность продолжения ф/т если вставляем фрагмент по ширине такой же как и ф/т //и имеет хоть одну ячейку с данными if (specialPasteProps.formatTable && window['AscCommonExcel'].g_IncludeNewRowColInTable) { var tableIndexAboveRange = ws.model.autoFilters.searchRangeInTableParts( new Asc.Range(pasteToRange.c1, pasteToRange.r1 - 1, pasteToRange.c1, pasteToRange.r1 - 1)); var tableAboveRange = ws.model.TableParts[tableIndexAboveRange]; if (tableAboveRange && tableAboveRange.Ref && !tableAboveRange.isTotalsRow() && tableAboveRange.Ref.c1 === pasteToRange.c1 && tableAboveRange.Ref.c2 === pasteToRange.c2) { //далее проверяем наличие ф/т в области вставки if (-1 === ws.model.autoFilters.searchRangeInTableParts(pasteToRange)) { //проверям на наличие хотя бы одной значимой ячейки в диапазоне, который вставляем if (activeCellsPasteFragment && fromBinary && !val.autoFilters._isEmptyRange(activeCellsPasteFragment, 0)) { newRange = new Asc.Range(tableAboveRange.Ref.c1, tableAboveRange.Ref.r1, pasteToRange.c2, pasteToRange.r2); //продлеваем ф/т ws.model.autoFilters.changeTableRange(tableAboveRange.DisplayName, newRange); } } } } //добавляем форматированные таблицы var i; var arnToRange = pasteToRange ? pasteToRange : ws.model.selectionRange.getLast(); var tablesMap = null, intersectionRangeWithTableParts; var activeRange = fromBinary && AscCommonExcel.g_clipboardExcel.pasteProcessor.activeRange; var refInsertBinary = activeRange && AscCommonExcel.g_oRangeCache.getAscRange(activeRange); if (fromBinary && val.TableParts && val.TableParts.length && specialPasteProps.formatTable) { var range, tablePartRange, tables = val.TableParts, diffRow, diffCol, curTable, bIsAddTable; for (i = 0; i < tables.length; i++) { curTable = tables[i]; tablePartRange = curTable.Ref; diffRow = tablePartRange.r1 - refInsertBinary.r1 + arnToRange.r1; diffCol = tablePartRange.c1 - refInsertBinary.c1 + arnToRange.c1; range = ws.model.getRange3(diffRow, diffCol, diffRow + (tablePartRange.r2 - tablePartRange.r1), diffCol + (tablePartRange.c2 - tablePartRange.c1)); //если в активную область при записи попала лишь часть таблицы if (activeCellsPasteFragment && !activeCellsPasteFragment.containsRange(tablePartRange)) { continue; } //если область вставки содержит форматированную таблицу, которая пересекается с вставляемой форматированной таблицей intersectionRangeWithTableParts = ws.model.autoFilters._intersectionRangeWithTableParts(range.bbox); if (intersectionRangeWithTableParts) { continue; } if (curTable.style) { range.cleanFormat(); } //TODO использовать bWithoutFilter из tablePart var bWithoutFilter = false; if (!curTable.AutoFilter) { bWithoutFilter = true; } var offset = new AscCommon.CellBase(range.bbox.r1 - tablePartRange.r1, range.bbox.c1 - tablePartRange.c1); var newDisplayName = ws.model.workbook.dependencyFormulas.getNextTableName(); var props = { bWithoutFilter: bWithoutFilter, tablePart: curTable, offset: offset, displayName: newDisplayName }; var tableStyleInfoName = curTable.TableStyleInfo ? curTable.TableStyleInfo.Name : null; ws.model.autoFilters.addAutoFilter(tableStyleInfoName, range.bbox, true, true, props); if (null === tablesMap) { tablesMap = {}; } tablesMap[curTable.DisplayName] = newDisplayName; bIsAddTable = true; } if (bIsAddTable) { ws._isLockedDefNames(null, null); } } if (specialPasteProps.formatTable) { ws.model.deletePivotTables(pasteToRange); } if (fromBinary && val.pivotTables && val.pivotTables.length && specialPasteProps.formatTable) { for (i = 0; i < val.pivotTables.length; i++) { var pivot = val.pivotTables[i]; pivot.prepareToPaste(ws.model, new AscCommon.CellBase(arnToRange.r1 - refInsertBinary.r1, arnToRange.c1 - refInsertBinary.c1), true); ws.model.workbook.oApi._changePivotSimple(pivot, true, false, function () { ws.model.insertPivotTable(pivot, true, true); }); } } //data validation if (specialPasteProps.val && specialPasteProps.format) { ws.model.clearDataValidation([pasteToRange], true); } if (fromBinary && val.dataValidations && val.dataValidations.elems.length && specialPasteProps.val && specialPasteProps.format) { var aMultiples = AscCommonExcel.g_clipboardExcel.pasteProcessor.multipleSettings; var oMultiple; if (aMultiples) { for (i = 0; i < aMultiples.length; i++) { if (aMultiples[i].pasteInRange && aMultiples[i].pasteInRange.isEqual(pasteToRange)) { oMultiple = aMultiples[i]; break; } } } //TODO transpose! var xW = oMultiple ? (oMultiple.w / oMultiple.pasteW) : 1; var xH = oMultiple ? (oMultiple.h / oMultiple.pasteH) : 1; var _pasteH = oMultiple ? oMultiple.pasteH : 0; var _pasteW = oMultiple ? oMultiple.pasteW : 0; for (i = 0; i < xW; i++) { for (var j = 0; j < xH; j++) { var _offset = new AscCommon.CellBase(arnToRange.r1 - refInsertBinary.r1 + j*_pasteH, arnToRange.c1 - refInsertBinary.c1 + i*_pasteW); for (var n = 0; n < val.dataValidations.elems.length; n++) { var dataValidation = val.dataValidations.elems[n].clone(); if (dataValidation.prepeareToPaste(refInsertBinary, _offset)) { if (refInsertBinary) { var formulaOffset = new AscCommon.CellBase(pasteToRange.r1 - refInsertBinary.r1, pasteToRange.c1 - refInsertBinary.c1); dataValidation._init(ws.model, true); //TODO //MS сдвигает немного иначе - при отрицательных значениях сдвига вычитает из максимальной строки/столбца //мы делаем аналогично формулам //для того, чтобы сделать как в ms необходимо переделать сдвиг диапазонов для формул //и нужно ли это? кто ожидает в случае такого копирования подобный результат? dataValidation.setOffset(formulaOffset); //dataValidation._buildDependencies(); } ws.model.addDataValidation(dataValidation, true); } } } } } if (fromBinary && refInsertBinary) { var offsetAll = new AscCommon.CellBase(arnToRange.r1 - refInsertBinary.r1, arnToRange.c1 - refInsertBinary.c1); //conditional formatting if (specialPasteProps.format) { ws.model.moveConditionalFormatting(refInsertBinary, arnToRange, true, offsetAll, ws.model, val, specialPasteProps.transpose); } //sparklines if (specialPasteProps.val && specialPasteProps.format) { ws.model.moveSparklineGroup(refInsertBinary, arnToRange, false, offsetAll, ws.model, val); } //protected ranges if (specialPasteProps.format) { ws.model.moveProtectedRange(refInsertBinary, arnToRange, true, offsetAll, ws.model, val); } } //делаем unmerge ф/т intersectionRangeWithTableParts = ws.model.autoFilters._intersectionRangeWithTableParts(arnToRange); if (intersectionRangeWithTableParts && intersectionRangeWithTableParts.length) { var tablePart; for (i = 0; i < intersectionRangeWithTableParts.length; i++) { tablePart = intersectionRangeWithTableParts[i]; ws.model.getRange3(tablePart.Ref.r1, tablePart.Ref.c1, tablePart.Ref.r2, tablePart.Ref.c2).unmerge(); } } ws.model.workbook.dependencyFormulas.lockRecal(); var pastedData; if (fromBinary) { pastedData = t.pasteFromBinary(val, null, tablesMap, pasteToRange); } else { if (bText) { specialPasteProps.font = false; } pastedData = t.pasteFromHTML(val, null, specialPasteProps); } var api = ws.getApi(); api.onWorksheetChange(pasteToRange); if (specialPasteHelper.specialPasteStart) { if (window['Asc'].c_oSpecialPasteOperation.none !== specialPasteProps.operation && null !== specialPasteProps.operation) { if (pasteInfo && pasteInfo.originalSelectBeforePaste) { specialPasteHelper.selectionRange = pasteInfo.originalSelectBeforePaste; } else { specialPasteHelper.selectionRange = ws.model.selectionRange ? ws.model.selectionRange.clone() : null; } } } ws.model.checkChangeTablesContent(ws.model.selectionRange.getLast()); if (!pastedData) { bIsUpdate = false; ws.model.workbook.dependencyFormulas.unlockRecal(); if (callTrigger) { ws.handlers.trigger("slowOperation", false); } return; } var arrFormula = pastedData[1]; var adjustFormatArr = []; for (i = 0; i < arrFormula.length; ++i) { var rangeF = arrFormula[i].range; var valF = arrFormula[i].val; var arrayRef = arrFormula[i].arrayRef; if (arrFormula[i].ca) { AscCommonExcel.g_cCalcRecursion.setCellPasteValue(arrFormula[i].oldValue); } //***array-formula*** if (arrayRef && window['AscCommonExcel'].bIsSupportArrayFormula) { var rangeFormulaArray = ws.model.getRange3(arrayRef.r1, arrayRef.c1, arrayRef.r2, arrayRef.c2); rangeFormulaArray.setValue(valF, function (r) { //ret = r; }, true, arrayRef); History.Add(AscCommonExcel.g_oUndoRedoArrayFormula, AscCH.historyitem_ArrayFromula_AddFormula, ws.model.getId(), new Asc.Range(arrayRef.c1, arrayRef.r1, arrayRef.c2, arrayRef.r2), new AscCommonExcel.UndoRedoData_ArrayFormula(arrayRef, valF)); } else if (rangeF.isOneCell()) { rangeF.setValue(valF, null, true); if (!fromBinary) { adjustFormatArr.push(rangeF); } } else { var oBBox = rangeF.getBBox0(); ws.model._getCell(oBBox.r1, oBBox.c1, function (cell) { cell.setValue(valF, null, true); }); } // todo it works correctly, external dependencies are loaded, but additional checks are needed // let afterExternalReferences = ws.getExternalReferencesByCell(rangeF, true, true); // if (afterExternalReferences /*&& !_compare(afterExternalReferences, beforeExternalReferences)*/) { // //t.model.workbook.handlers.trigger("asc_onNeedUpdateExternalReference"); // ws.updateExternalReferenceByCell(rangeF, true); // } } ws.model.workbook.dependencyFormulas.unlockRecal(); //добавил для случая, когда вставка формулы проиходит в заголовок таблицы if (arrFormula && arrFormula.length) { ws.model.checkChangeTablesContent(ws.model.selectionRange.getLast()); } //for special paste if (!window['AscCommon'].g_specialPasteHelper.specialPasteStart) { var checkTablesPaste = function () { var _res = false; if (val.TableParts && val.TableParts.length && activeCellsPasteFragment) { for (var i = 0; i < val.TableParts.length; i++) { if (activeCellsPasteFragment.containsRange(val.TableParts[i].Ref)) { _res = true; break; } } } return _res; }; if (!(pasteInfo && pasteInfo.originalSelectBeforePaste && pasteInfo.originalSelectBeforePaste.ranges && pasteInfo.originalSelectBeforePaste.ranges.length === 1) && ws.isMultiSelect()) { window['AscCommon'].g_specialPasteHelper.CleanButtonInfo(); window['AscCommon'].g_specialPasteHelper.Special_Paste_Hide_Button(); } else { //var specialPasteShowOptions = new Asc.SpecialPasteShowOptions(); var isTablePasted = checkTablesPaste(); var allowedSpecialPasteProps; var sProps = Asc.c_oSpecialPasteProps; if (fromBinary) { allowedSpecialPasteProps = [sProps.paste, sProps.pasteOnlyFormula, sProps.formulaNumberFormat, sProps.formulaAllFormatting, sProps.formulaWithoutBorders, sProps.formulaColumnWidth, sProps.pasteOnlyValues, sProps.valueNumberFormat, sProps.valueAllFormating, sProps.pasteOnlyFormating, sProps.comments, sProps.columnWidth]; if (isAllowPasteLink(pasteInfo.wb)) { allowedSpecialPasteProps.push(sProps.link); } if (!isTablePasted) { //add transpose property allowedSpecialPasteProps.push(sProps.transpose); } } else { //matchDestinationFormatting - пока не добавляю, так как работает как и values if (bText) { allowedSpecialPasteProps = [sProps.keepTextOnly, sProps.useTextImport]; } else { allowedSpecialPasteProps = [sProps.sourceformatting, sProps.destinationFormatting]; } } if (specialPasteHelper.specialPasteData.images && specialPasteHelper.specialPasteData.images.length && !(window["Asc"]["editor"] && window["Asc"]["editor"].isChartEditor)) { allowedSpecialPasteProps.push(sProps.picture); } window['AscCommon'].g_specialPasteHelper.CleanButtonInfo(); window['AscCommon'].g_specialPasteHelper.buttonInfo.asc_setOptions(allowedSpecialPasteProps); if (fromBinary) { window['AscCommon'].g_specialPasteHelper.buttonInfo.asc_setShowPasteSpecial(true); } if (isTablePasted) { window['AscCommon'].g_specialPasteHelper.buttonInfo.asc_setContainTables(true); } window['AscCommon'].g_specialPasteHelper.buttonInfo.setRange(pastedData[0]); } } else { window['AscCommon'].g_specialPasteHelper.buttonInfo.setRange(pastedData[0]); window['AscCommon'].g_specialPasteHelper.SpecialPasteButton_Update_Position(); } return {selectData: pastedData, adjustFormatArr: adjustFormatArr}; }; CCellPasteHelper.prototype.pasteFromHTML = function (pasteContent, isCheckSelection, specialPasteProps) { var t = this; var ws = this.ws; var lastSelection = ws.model.selectionRange.getLast(); var arn = AscCommonExcel.g_clipboardExcel.pasteProcessor && AscCommonExcel.g_clipboardExcel.pasteProcessor.activeRange ? AscCommonExcel.g_clipboardExcel.pasteProcessor.activeRange : lastSelection; var arrFormula = []; var numFor = 0; var rMax = pasteContent.content.length + pasteContent.props.rowSpanSpCount + arn.r1; var cMax = pasteContent.props.cellCount + arn.c1; var isMultiple = false; var firstCell = ws.model.getRange3(arn.r1, arn.c1, arn.r1, arn.c1); var isMergedFirstCell = firstCell.hasMerged(); var rangeUnMerge = ws.model.getRange3(arn.r1, arn.c1, rMax - 1, cMax - 1); var isOneMerge = false; //если вставляем в мерженную ячейку, диапазон которой больше или равен var fPasteCell = pasteContent.content[0] && pasteContent.content[0][0]; var colSpanCompare = fPasteCell && cMax - arn.c1 === fPasteCell.colSpan; var rowSpanCompare = fPasteCell && rMax - arn.r1 === fPasteCell.rowSpan; if (arn.c2 >= cMax - 1 && arn.r2 >= rMax - 1 && isMergedFirstCell && isMergedFirstCell.isEqual(arn) && colSpanCompare && rowSpanCompare) { if (!isCheckSelection && pasteContent.content[0] && pasteContent.content[0][0]) { pasteContent.content[0][0].colSpan = isMergedFirstCell.c2 - isMergedFirstCell.c1 + 1; pasteContent.content[0][0].rowSpan = isMergedFirstCell.r2 - isMergedFirstCell.r1 + 1; } isOneMerge = true; } else { //проверка на наличие части объединённой ячейки в области куда осуществляем вставку for (var rFirst = arn.r1; rFirst < rMax; ++rFirst) { for (var cFirst = arn.c1; cFirst < cMax; ++cFirst) { var range = ws.model.getRange3(rFirst, cFirst, rFirst, cFirst); var merged = range.hasMerged(); if (merged) { if (merged.r1 < arn.r1 || merged.r2 > rMax - 1 || merged.c1 < arn.c1 || merged.c2 > cMax - 1) { //ошибка в случае если вставка происходит в часть объедененной ячейки if (isCheckSelection) { return arn; } else { ws.handlers.trigger("onErrorEvent", c_oAscError.ID.PastInMergeAreaError, c_oAscError.Level.NoCritical); return; } } } } } } var rMax2 = rMax; var cMax2 = cMax; rMax = pasteContent.content.length; if (isCheckSelection) { var newArr = arn.clone(true); newArr.r2 = rMax2 - 1; newArr.c2 = cMax2 - 1; if (isMultiple || isOneMerge) { newArr.r2 = lastSelection.r2; newArr.c2 = lastSelection.c2; } return newArr; } //если не возникает конфликт, делаем unmerge if (specialPasteProps.format) { rangeUnMerge.unmerge(); //ws.cellCommentator.deleteCommentsRange(rangeUnMerge.bbox); } if (!isOneMerge) { arn.r2 = (rMax2 - 1 > 0) ? (rMax2 - 1) : 0; arn.c2 = (cMax2 - 1 > 0) ? (cMax2 - 1) : 0; } var maxARow = 1, maxACol = 1, plRow = 0, plCol = 0; var mergeArr = []; var putInsertedCellIntoRange = function (row, col, currentObj) { var pastedRangeProps = {}; var contentCurrentObj = currentObj.content; var range = ws.model.getRange3(row, col, row, col); //value if (contentCurrentObj.length === 1) { var onlyOneChild = contentCurrentObj[0]; pastedRangeProps.val = onlyOneChild.text; pastedRangeProps.font = onlyOneChild.format; } else { pastedRangeProps.value2 = contentCurrentObj; pastedRangeProps.val = currentObj.textVal; } pastedRangeProps.alignVertical = currentObj.alignVertical; if (contentCurrentObj.length === 1 && contentCurrentObj[0].format) { var fs = contentCurrentObj[0].format.getSize(); if (fs !== '' && fs !== null && fs !== undefined) { pastedRangeProps.fontSize = fs; } } //fontFamily if (currentObj.props && currentObj.props.fontName) { pastedRangeProps.fontName = currentObj.props.fontName; } //AlignHorizontal if (!isOneMerge) { pastedRangeProps.alignHorizontal = currentObj.alignHorizontal; } //for merge var isMerged = false; for (var mergeCheck = 0; mergeCheck < mergeArr.length; ++mergeCheck) { if (mergeArr[mergeCheck].contains(col, row)) { isMerged = true; } } if ((currentObj.colSpan > 1 || currentObj.rowSpan > 1) && !isMerged) { var offsetCol = currentObj.colSpan - 1; var offsetRow = currentObj.rowSpan - 1; pastedRangeProps.offsetLast = new AscCommon.CellBase(offsetRow, offsetCol); mergeArr.push(new Asc.Range(range.bbox.c1, range.bbox.r1, range.bbox.c2 + offsetCol, range.bbox.r2 + offsetRow)); if (contentCurrentObj[0] == undefined) { pastedRangeProps.val = ''; } pastedRangeProps.merge = c_oAscMergeOptions.Merge; } //borders if (!isOneMerge) { pastedRangeProps.borders = currentObj.borders; } //wrap pastedRangeProps.wrap = currentObj.wrap; //fill if (currentObj.bc && currentObj.bc.rgb) { pastedRangeProps.fillColor = currentObj.bc; } //hyperlink if (currentObj.hyperLink || currentObj.location) { pastedRangeProps.hyperLink = currentObj; } //indent pastedRangeProps.indent = currentObj.indent; //apply props by cell t._setPastedDataByCurrentRange(range, pastedRangeProps, {arrFormula: arrFormula}, specialPasteProps); }; var oldDecimalSep, oldGroupSep; if (specialPasteProps.advancedOptions) { var _numberDecimalSeparator = specialPasteProps.advancedOptions.numberDecimalSeparator; if (_numberDecimalSeparator && isNaN(_numberDecimalSeparator)) { oldDecimalSep = AscCommon.g_oDefaultCultureInfo.NumberDecimalSeparator; AscCommon.g_oDefaultCultureInfo.NumberDecimalSeparator = specialPasteProps.advancedOptions.numberDecimalSeparator; } _numberDecimalSeparator = specialPasteProps.advancedOptions.numberGroupSeparator; if (_numberDecimalSeparator && isNaN(_numberDecimalSeparator)) { oldGroupSep = AscCommon.g_oDefaultCultureInfo.NumberGroupSeparator; AscCommon.g_oDefaultCultureInfo.NumberGroupSeparator = specialPasteProps.advancedOptions.numberGroupSeparator; } } for (var autoR = 0; autoR < maxARow; ++autoR) { for (var autoC = 0; autoC < maxACol; ++autoC) { for (var r = 0; r < rMax; ++r) { if (!pasteContent.content[r]) { continue; } for (var c = 0; c < pasteContent.content[r].length; ++c) { if (undefined !== pasteContent.content[r][c]) { var pasteIntoRow = r + autoR * plRow + arn.r1; var pasteIntoCol = c + autoC * plCol + arn.c1; var currentObj = pasteContent.content[r][c]; putInsertedCellIntoRange(pasteIntoRow, pasteIntoCol, currentObj); } } } } } if (specialPasteProps.advancedOptions) { if (oldDecimalSep) { AscCommon.g_oDefaultCultureInfo.NumberDecimalSeparator = oldDecimalSep; } if (oldGroupSep) { AscCommon.g_oDefaultCultureInfo.NumberGroupSeparator = oldGroupSep; } } if (isMultiple) { arn.r2 = lastSelection.r2; arn.c2 = lastSelection.c2; } ws.isChanged = true; return [arn, arrFormula]; }; CCellPasteHelper.prototype.pasteFromBinary = function (val, isCheckSelection, tablesMap, pasteToRange) { var pasteRange = AscCommonExcel.g_clipboardExcel.pasteProcessor.activeRange; if (typeof pasteRange === "string") { AscCommonExcel.executeInR1C1Mode(false, function () { pasteRange = AscCommonExcel.g_oRangeCache.getAscRange(pasteRange); }); } var pastedCol = pasteRange.c2 - pasteRange.c1 + 1; var pastedRow = pasteRange.r2 - pasteRange.r1 + 1; var _checkSize = function (_range) { var _col = _range.c2 - _range.c1 + 1; var _row = _range.r2 - _range.r1 + 1; if (_col % pastedCol === 0 && _row % pastedRow === 0) { return true; } if (_col % pastedCol === 0 && pastedRow === 1) { return true; } if (_row % pastedRow === 0 && pastedCol === 1) { return true; } if (_row === 1 && _col === 1) { return true; } return false; }; let ws = this.ws; var selectRanges = ws.model.selectionRange.ranges; var i; if (selectRanges.length > 1) { for (i = 0; i < selectRanges.length; i++) { if (!_checkSize(selectRanges[i])) { //error return; } } } let specialPasteProp = window['AscCommon'].g_specialPasteHelper && window['AscCommon'].g_specialPasteHelper.specialPasteProps && window['AscCommon'].g_specialPasteHelper.specialPasteProps.property; let fromSelectionRange = val.selectionRange.getLast(); let fromSelectionRangeType = fromSelectionRange.getType(); if (!isCheckSelection) { if (fromSelectionRangeType === window["Asc"].c_oAscSelectionType.RangeMax || fromSelectionRangeType === window["Asc"].c_oAscSelectionType.RangeCol) { if (specialPasteProp == null || specialPasteProp === Asc.c_oSpecialPasteProps.formulaAllFormatting || specialPasteProp === Asc.c_oSpecialPasteProps.formulaWithoutBorders || specialPasteProp === Asc.c_oSpecialPasteProps.valueAllFormating || specialPasteProp === Asc.c_oSpecialPasteProps.pasteOnlyFormating) { window['AscCommon'].g_specialPasteHelper && window['AscCommon'].g_specialPasteHelper.specialPasteProps.asc_setProps(Asc.c_oSpecialPasteProps.formulaColumnWidth); } } } var res; if (isCheckSelection) { for (i = 0; i < selectRanges.length; i++) { //если всталвляем ссылки, то в случае если изначально была выделена только 1 ячейка - подбираем диапазон вставки, в случае нескольких - //оставляем первоначальный диапазон var _selection; if (specialPasteProp === Asc.c_oSpecialPasteProps.link) { if (!selectRanges[i].isOneCell()) { _selection = selectRanges[i].clone(); } else { _selection = this._pasteFromBinary(val, isCheckSelection, tablesMap, selectRanges[i]); } } else { _selection = this._pasteFromBinary(val, isCheckSelection, tablesMap, selectRanges[i]); } if (!res) { res = []; } res.push(_selection); } } else { res = this._pasteFromBinary(val, isCheckSelection, tablesMap, pasteToRange); } return res; }; CCellPasteHelper.prototype._pasteFromBinary = function (val, isCheckSelection, tablesMap, pasteInRange) { var t = this; var ws = this.ws; var trueActiveRange = pasteInRange ? pasteInRange.clone() : ws.model.selectionRange.getLast().clone(); var arn = pasteInRange ? pasteInRange.clone() : ws.model.selectionRange.getLast().clone(); var arrFormula = []; var specialPasteHelper = window['AscCommon'].g_specialPasteHelper; var specialPasteProps = specialPasteHelper.specialPasteProps; var isPastingLink = specialPasteProps && specialPasteProps.property === Asc.c_oSpecialPasteProps.link; var pasteRange = AscCommonExcel.g_clipboardExcel.pasteProcessor.activeRange; var activeCellsPasteFragment; if (typeof pasteRange === "string") { AscCommonExcel.executeInR1C1Mode(false, function () { activeCellsPasteFragment = AscCommonExcel.g_oRangeCache.getAscRange(pasteRange); }); } else { activeCellsPasteFragment = pasteRange; } if (isPastingLink && !isCheckSelection) { if (!activeCellsPasteFragment.isOneCell()) { activeCellsPasteFragment.r2 = activeCellsPasteFragment.r1 + (arn.r2 - arn.r1); activeCellsPasteFragment.c2 = activeCellsPasteFragment.c1 + (arn.c2 - arn.c1); } } var countPasteRow = activeCellsPasteFragment.r2 - activeCellsPasteFragment.r1 + 1; var countPasteCol = activeCellsPasteFragment.c2 - activeCellsPasteFragment.c1 + 1; if (specialPasteProps && specialPasteProps.transpose) { countPasteRow = activeCellsPasteFragment.c2 - activeCellsPasteFragment.c1 + 1; countPasteCol = activeCellsPasteFragment.r2 - activeCellsPasteFragment.r1 + 1; } var rMax = countPasteRow + arn.r1; var cMax = countPasteCol + arn.c1; if (cMax > gc_nMaxCol0) { cMax = gc_nMaxCol0; } if (rMax > gc_nMaxRow0) { rMax = gc_nMaxRow0; } var isMultiple = false; var firstCell = ws.model.getRange3(arn.r1, arn.c1, arn.r1, arn.c1); var isMergedFirstCell = firstCell.hasMerged(); var isOneMerge = false; var startCell = val.getCell3(activeCellsPasteFragment.r1, activeCellsPasteFragment.c1); var isMergedStartCell = startCell.hasMerged(); var firstValuesCol; var firstValuesRow; if (isMergedStartCell != null) { firstValuesCol = isMergedStartCell.c2 - isMergedStartCell.c1; firstValuesRow = isMergedStartCell.r2 - isMergedStartCell.r1; } else { firstValuesCol = 0; firstValuesRow = 0; } var excludeHiddenRows = ws.model.autoFilters.bIsExcludeHiddenRows(pasteInRange ? pasteInRange.clone() : ws.model.selectionRange.getLast(), ws.model.selectionRange.activeCell); var hiddenRowsArray = {}; var getOpenRowsCount = function (oRange) { var res = oRange.r2 - oRange.r1 + 1; if (false && excludeHiddenRows) { var tempRange = ws.model.getRange3(oRange.r1, 0, oRange.r2, 0); tempRange._foreachRowNoEmpty(function (row) { if (row.getHidden()) { res--; if (!isCheckSelection) { hiddenRowsArray[row.index] = 1; } } }); } return res; }; if (!isMergedFirstCell) { if (arn.c1 === arn.c2 && arn.r2 > arn.r1 && countPasteCol > 1 && countPasteRow === 1) { //если всталяем одну строку в одну колонку arn.c2 = arn.c1 + countPasteCol - 1; trueActiveRange.c2 = arn.c2; } else if (arn.r1 === arn.r2 && arn.c2 > arn.c1 && countPasteRow > 1 && countPasteCol === 1) { //если всталяем одну колонку в одну строку arn.r2 = arn.r1 + countPasteRow - 1; trueActiveRange.r2 = arn.r2; } } var rowDiff = arn.r1 - activeCellsPasteFragment.r1; var colDiff = arn.c1 - activeCellsPasteFragment.c1; var newPasteRange = new Asc.Range(arn.c1 - colDiff, arn.r1 - rowDiff, arn.c2 - colDiff, arn.r2 - rowDiff); //если вставляем в мерженную ячейку, диапазон которой больше или меньше, но не равен выделенной области if (isMergedFirstCell && isMergedFirstCell.isEqual(arn) && cMax - arn.c1 === (firstValuesCol + 1) && rMax - arn.r1 === (firstValuesRow + 1) && !newPasteRange.isEqual(activeCellsPasteFragment)) { isOneMerge = true; rMax = arn.r2 + 1; cMax = arn.c2 + 1; } else if (arn.c2 >= cMax - 1 && arn.r2 >= rMax - 1) { //если область кратная куску вставки var widthArea = arn.c2 - arn.c1 + 1; var heightArea = getOpenRowsCount(arn); var widthPasteFr = cMax - arn.c1; var heightPasteFr = rMax - arn.r1; //если кратны, то обрабатываем if (widthArea % widthPasteFr === 0 && heightArea % heightPasteFr === 0) { //Для случая, когда выделен весь диапазон, запрещаю множественную вставку if (arn.getType() !== window["Asc"].c_oAscSelectionType.RangeMax && arn.getType() !== window["Asc"].c_oAscSelectionType.RangeCol && arn.getType() !== window["Asc"].c_oAscSelectionType.RangeRow) { isMultiple = true; if (!AscCommonExcel.g_clipboardExcel.pasteProcessor.multipleSettings) { AscCommonExcel.g_clipboardExcel.pasteProcessor.multipleSettings = []; } AscCommonExcel.g_clipboardExcel.pasteProcessor.multipleSettings.push({ w: widthArea, h: heightArea, pasteW: widthPasteFr, pasteH: heightPasteFr, pasteInRange: pasteInRange }); } } else if (firstCell.hasMerged() !== null)//в противном случае ошибка { if (isCheckSelection) { return arn; } else { ws.handlers.trigger("onError", c_oAscError.ID.PastInMergeAreaError, c_oAscError.Level.NoCritical); return; } } } else { //проверка на наличие части объединённой ячейки в области куда осуществляем вставку for (var rFirst = arn.r1; rFirst < rMax; ++rFirst) { for (var cFirst = arn.c1; cFirst < cMax; ++cFirst) { var range = ws.model.getRange3(rFirst, cFirst, rFirst, cFirst); var merged = range.hasMerged(); if (merged) { if (merged.r1 < arn.r1 || merged.r2 > rMax - 1 || merged.c1 < arn.c1 || merged.c2 > cMax - 1) { //ошибка в случае если вставка происходит в часть объедененной ячейки if (isCheckSelection) { return arn; } else { ws.handlers.trigger("onErrorEvent", c_oAscError.ID.PastInMergeAreaError, c_oAscError.Level.NoCritical); return; } } } } } } var rMax2 = rMax; var cMax2 = cMax; var getLockRange = function () { var newArr = arn.clone(true); newArr.r2 = rMax2 - 1; newArr.c2 = cMax2 - 1; if (isMultiple || isOneMerge) { newArr.r2 = arn.r2; newArr.c2 = arn.c2; } return newArr; }; if (isCheckSelection) { return getLockRange(); } var bboxUnMerge = getLockRange(); var rangeUnMerge = ws.model.getRange3(bboxUnMerge.r1, bboxUnMerge.c1, bboxUnMerge.r2, bboxUnMerge.c2); //если не возникает конфликт, делаем unmerge if (specialPasteProps.format) { rangeUnMerge.unmerge(); ws.cellCommentator.deleteCommentsRange(rangeUnMerge.bbox); } if (!isOneMerge) { arn.r2 = rMax2 - 1; arn.c2 = cMax2 - 1; } var maxARow = 1, maxACol = 1, plRow = 0, plCol = 0; if (isMultiple)//случай автозаполнения сложных форм { if (specialPasteProps.format) { ws.model.getRange3(trueActiveRange.r1, trueActiveRange.c1, trueActiveRange.r2, trueActiveRange.c2) .unmerge(); } maxARow = heightArea / heightPasteFr; maxACol = widthArea / widthPasteFr; plRow = (rMax2 - arn.r1); plCol = (arn.c2 - arn.c1) + 1; } else { trueActiveRange.r2 = arn.r2; trueActiveRange.c2 = arn.c2; } //необходимо проверить, пересекаемся ли мы с фоматированной таблицей //если да, то подхватывать dxf при вставке не нужно var intersectionAllRangeWithTables = ws.model.autoFilters._intersectionRangeWithTableParts(trueActiveRange); var addComments = function (pasteRow, pasteCol, comments) { var comment; var isMergedCell = val.getMergedByCell(pasteRow, pasteCol); for (var i = 0; i < comments.length; i++) { comment = comments[i]; var _isMergedContain = isMergedCell && isMergedCell.contains(comment.nCol, comment.nRow); if (_isMergedContain || (comment.nCol === pasteCol && comment.nRow === pasteRow)) { var commentData = comment.clone(true); //change nRow, nCol commentData.asc_putCol(nCol); commentData.asc_putRow(nRow); ws.cellCommentator.addComment(commentData, true); } } }; var mergeArr = []; var checkMerge = function (range, curMerge, nRow, nCol, rowDiff, colDiff, pastedRangeProps) { var isMerged = false; for (var mergeCheck = 0; mergeCheck < mergeArr.length; ++mergeCheck) { if (mergeArr[mergeCheck].contains(nCol, nRow)) { isMerged = true; } } if (!isOneMerge) { if (curMerge != null && !isMerged) { var offsetCol = curMerge.c2 - curMerge.c1; if (offsetCol + nCol >= gc_nMaxCol0) { offsetCol = gc_nMaxCol0 - nCol; } var offsetRow = curMerge.r2 - curMerge.r1; if (offsetRow + nRow >= gc_nMaxRow0) { offsetRow = gc_nMaxRow0 - nRow; } pastedRangeProps.offsetLast = new AscCommon.CellBase(offsetRow, offsetCol); if (specialPasteProps.transpose) { mergeArr.push(new Asc.Range(curMerge.c1 + arn.c1 - activeCellsPasteFragment.r1 + colDiff, curMerge.r1 + arn.r1 - activeCellsPasteFragment.c1 + rowDiff, curMerge.c2 + arn.c1 - activeCellsPasteFragment.r1 + colDiff, curMerge.r2 + arn.r1 - activeCellsPasteFragment.c1 + rowDiff)); } else { mergeArr.push(new Asc.Range(curMerge.c1 + arn.c1 - activeCellsPasteFragment.c1 + colDiff, curMerge.r1 + arn.r1 - activeCellsPasteFragment.r1 + rowDiff, curMerge.c2 + arn.c1 - activeCellsPasteFragment.c1 + colDiff, curMerge.r2 + arn.r1 - activeCellsPasteFragment.r1 + rowDiff)); } } } else { if (!isMerged) { pastedRangeProps.offsetLast = new AscCommon.CellBase(isMergedFirstCell.r2 - isMergedFirstCell.r1, isMergedFirstCell.c2 - isMergedFirstCell.c1); mergeArr.push(new Asc.Range(isMergedFirstCell.c1, isMergedFirstCell.r1, isMergedFirstCell.c2, isMergedFirstCell.r2)); } } }; var getTableDxf = function (pasteRow, pasteCol, newVal) { var dxf = null; if (false !== intersectionAllRangeWithTables) { return {dxf: null}; } var tables = val.autoFilters._intersectionRangeWithTableParts(newVal.bbox); var blocalArea = true; if (tables && tables[0]) { var table = tables[0]; var styleInfo = table.TableStyleInfo; var styleForCurTable = styleInfo ? ws.model.workbook.TableStyles.AllStyles[styleInfo.Name] : null; if (activeCellsPasteFragment.containsRange(table.Ref)) { blocalArea = false; } if (!styleForCurTable) { return null; } var headerRowCount = 1; var totalsRowCount = 0; if (null != table.HeaderRowCount) { headerRowCount = table.HeaderRowCount; } if (null != table.TotalsRowCount) { totalsRowCount = table.TotalsRowCount; } var bbox = new Asc.Range(table.Ref.c1, table.Ref.r1, table.Ref.c2, table.Ref.r2); styleForCurTable.initStyle(val.sheetMergedStyles, bbox, styleInfo, headerRowCount, totalsRowCount); val._getCell(pasteRow, pasteCol, function (cell) { if (cell) { dxf = cell.getCompiledStyle(); } if (null === dxf) { pasteRow = pasteRow - table.Ref.r1; pasteCol = pasteCol - table.Ref.c1; dxf = val.getCompiledStyle(pasteRow, pasteCol); } }); } return {dxf: dxf, blocalArea: blocalArea}; }; var findFormulaArrayFirstCell = function (_arr, _cell) { var res = null; if (_arr && _cell) { for (var n = 0; n < _arr.length; n++) { if (_arr[n].ref && _arr[n].ref.contains(_cell.nCol, _cell.nRow)) { res = _arr[n].newVal; break; } } } return res; }; var _getPasteLinkIndex = function () { var pastedWb = val.workbook; var linkInfo = t.getPastedLinkInfo(pastedWb, pastedWb && pastedWb.aWorksheets[0]); pasteLinkIndex = null; if (linkInfo) { if (linkInfo.type === -1) { pasteLinkIndex = linkInfo.index; pasteSheetLinkName = linkInfo.sheet; //необходимо положить нужные данные в SheetDataSet var modelExternalReference = ws.model.workbook.externalReferences[pasteLinkIndex - 1]; if (modelExternalReference) { modelExternalReference.updateSheetData(pasteSheetLinkName, pastedWb.aWorksheets[0], [activeCellsPasteFragment]); ws.model.workbook.changeExternalReference(pasteLinkIndex, modelExternalReference); } } else if (linkInfo.type === -2) { //добавляем var referenceData; var name = pastedWb.Core.title; if (window["AscDesktopEditor"] && window["AscDesktopEditor"]["IsLocalFile"]()) { name = linkInfo.path; } else { if (pastedWb && pastedWb.Core) { referenceData = {}; referenceData["fileKey"] = pastedWb.Core.contentStatus; referenceData["instanceId"] = pastedWb.Core.category; } } var pastedSheetName = pastedWb.aWorksheets[0].sName; var newExternalReference = new AscCommonExcel.ExternalReference(); newExternalReference.referenceData = referenceData; newExternalReference.Id = name; //newExternalReference.addSheetName(pastedSheetName, true); //необходимо взять данные с листа. если лист ещё не создан, то взять этот лист и положить в ExternalReferences //+ положить нужные данные в SheetDataSet //вставляемый фрагмент - ориентируюсь на activeCellsPasteFragment newExternalReference.addSheet(pastedWb.aWorksheets[0], [activeCellsPasteFragment]); ws.model.workbook.addExternalReferences([newExternalReference]); pasteLinkIndex = referenceData ? ws.model.workbook.getExternalReferenceByReferenceData(referenceData, true) : ws.model.workbook.getExternalLinkIndexByName(name); if (pasteLinkIndex != null) { pasteSheetLinkName = pastedSheetName; } } else if (linkInfo.type === 1) { pasteSheetLinkName = linkInfo.sheet; } } }; var isLinkToOtherWorkbook = false; var pasteLinkIndex = -1; var pasteSheetLinkName = null; var colsWidth = {}; var pastedFormulaArray = []; var putInsertedCellIntoRange = function (toRow, toCol, fromRow, fromCol, rowDiff, colDiff, range, newVal, curMerge, transposeRange) { var pastedRangeProps = {}; if (isPastingLink) { if (-1 === pasteLinkIndex) { _getPasteLinkIndex(); } if (pasteLinkIndex != null) { isLinkToOtherWorkbook = true; } t._pasteCellLink(range, fromRow, fromCol, arrFormula, pasteSheetLinkName, pasteLinkIndex); return; } //range может далее изменится в связи с наличием мерженных ячеек, firstRange - не меняется(ему делаем setValue, как первой ячейке в диапазоне мерженных) var firstRange = range.clone(); //****paste comments**** if (specialPasteProps.comment && val.aComments && val.aComments.length) { addComments(fromRow, fromCol, val.aComments); } //merge checkMerge(range, curMerge, toRow, toCol, rowDiff, colDiff, pastedRangeProps); /*if (!isOneMerge) { pastedRangeProps._cellStyle = newVal.getStyle(); }*/ //set style if (!isOneMerge) { pastedRangeProps.cellStyle = newVal.getStyleName(); } if (!isOneMerge)//settings for cell(format) { //format var numFormat = newVal.getNumFormat(); var nameFormat; if (numFormat && numFormat.sFormat) { nameFormat = numFormat.sFormat; } pastedRangeProps.numFormat = nameFormat; } if (!isOneMerge)//settings for cell { var align = newVal.getAlign(); //vertical align pastedRangeProps.alignVertical = align.getAlignVertical(); //horizontal align pastedRangeProps.alignHorizontal = align.getAlignHorizontal(); //borders var fullBorders; if (specialPasteProps.transpose) { //TODO сделано для правильного отображения бордеров при транспонирования. возможно стоит использовать эту функцию во всех ситуациях. проверить! fullBorders = newVal.getBorder(newVal.bbox.r1, newVal.bbox.c1).clone(); } else { fullBorders = newVal.getBorderFull(); } if (pastedRangeProps.offsetLast && pastedRangeProps.offsetLast.col > 0 && curMerge && fullBorders) { //для мерженных ячеек, правая границу var endMergeCell = val.getCell3(fromRow, curMerge.c2); var fullBordersEndMergeCell = endMergeCell.getBorderFull(); if (fullBordersEndMergeCell && fullBordersEndMergeCell.r) { fullBorders.r = fullBordersEndMergeCell.r; } } pastedRangeProps.bordersFull = fullBorders; //fill pastedRangeProps.fill = newVal.getFill(); //wrap //range.setWrap(newVal.getWrap()); pastedRangeProps.wrap = align.getWrap(); //angle pastedRangeProps.angle = align.getAngle(); //hyperlink pastedRangeProps.hyperlinkObj = newVal.getHyperlink(); pastedRangeProps.font = newVal.getFont(); pastedRangeProps.shrinkToFit = align.getShrinkToFit(); pastedRangeProps.indent = align.getIndent(); pastedRangeProps.hidden = newVal.getHidden(); if (!t.ws.model.getSheetProtection()) { pastedRangeProps.locked = newVal.getLocked(); } } var tableDxf = getTableDxf(fromRow, fromCol, newVal); if (tableDxf && tableDxf.blocalArea) { pastedRangeProps.tableDxfLocal = tableDxf.dxf; } else if (tableDxf) { pastedRangeProps.tableDxf = tableDxf.dxf; } if (undefined === colsWidth[toCol]) { colsWidth[toCol] = val._getCol(fromCol); } pastedRangeProps.colsWidth = colsWidth; //***array-formula*** var fromCell; val._getCell(fromRow, fromCol, function (cell) { fromCell = cell; var _formulaArrayRef = cell.formulaParsed && cell.formulaParsed.getArrayFormulaRef(); if (_formulaArrayRef) { //для ситуаций, когда нужно при вставке преобразовать формулу массива в набор формул //это случается, когда при специальной вставке выбираешь арифметическую операцию, а во //фрагменте вставке находится формула массива pastedFormulaArray.push({ref: _formulaArrayRef, newVal: newVal}); } }); //apply props by cell var formulaProps = { firstRange: firstRange, arrFormula: arrFormula, tablesMap: tablesMap, newVal: newVal, isOneMerge: isOneMerge, val: val, activeCellsPasteFragment: activeCellsPasteFragment, transposeRange: transposeRange, cell: fromCell, fromRange: activeCellsPasteFragment, fromBinary: true, formulaArrayFirstCell: findFormulaArrayFirstCell(pastedFormulaArray, fromCell) }; t._setPastedDataByCurrentRange(range, pastedRangeProps, formulaProps, specialPasteProps); }; //случай, когда при копировании был выделен целый стобец/строка var fromSelectionRange = val.selectionRange.getLast(); var fromSelectionRangeType = fromSelectionRange.getType(); //MS для случая копирования полностью выделенных столбцов/строк по-разному осуществляет вставку //в этот же документ вставляется вся строка/столбец, затирая все данные в строке/столбце //в другой документ вставляется лишь фрагмент с данными //сделал как 2 вариант в ms - стоит пересмотреть if (Asc.c_oAscSelectionType.RangeCol === fromSelectionRangeType || Asc.c_oAscSelectionType.RangeRow === fromSelectionRangeType || Asc.c_oAscSelectionType.RangeMax === fromSelectionRangeType) { maxARow = 1; maxACol = 1; } var getNextNoHiddenRow = function (index) { var startIndex = index; while (hiddenRowsArray[index]) { index++; } return index - startIndex; }; var hiddenRowCount = {}; for (var autoR = 0; autoR < maxARow; ++autoR) { for (var autoC = 0; autoC < maxACol; ++autoC) { if (!hiddenRowCount[autoC]) { hiddenRowCount[autoC] = 0; } for (var r = 0; r < rMax - arn.r1; ++r) { for (var c = 0; c < cMax - arn.c1; ++c) { if (false && isMultiple && hiddenRowsArray[r + autoR * plRow + arn.r1 + hiddenRowCount[autoC]]) { hiddenRowCount[autoC] += getNextNoHiddenRow(r + autoR * plRow + arn.r1 + hiddenRowCount[autoC]); } var pasteRow = r + activeCellsPasteFragment.r1; var pasteCol = c + activeCellsPasteFragment.c1; if (specialPasteProps.transpose) { pasteRow = c + activeCellsPasteFragment.r1; pasteCol = r + activeCellsPasteFragment.c1; } var newVal = val.getCell3(pasteRow, pasteCol); if (undefined !== newVal) { var nRow = r + autoR * plRow + arn.r1 + hiddenRowCount[autoC]; var nCol = c + autoC * plCol + arn.c1; if (nRow > gc_nMaxRow0) { nRow = gc_nMaxRow0; } if (nCol > gc_nMaxCol0) { nCol = gc_nMaxCol0; } var curMerge = newVal.hasMerged(); if (curMerge && specialPasteProps.transpose) { curMerge = curMerge.clone(); var r1 = curMerge.r1; var r2 = curMerge.r2; var c1 = curMerge.c1; var c2 = curMerge.c2; curMerge.r1 = c1; curMerge.r2 = c2; curMerge.c1 = r1; curMerge.c2 = r2; } range = ws.model.getRange3(nRow, nCol, nRow, nCol); var transposeRange = null; if (specialPasteProps.transpose) { transposeRange = ws.model.getRange3(c + autoR * plRow + arn.r1, r + autoC * plCol + arn.c1, c + autoR * plRow + arn.r1, r + autoC * plCol + arn.c1); } putInsertedCellIntoRange(nRow, nCol, pasteRow, pasteCol, autoR * plRow, autoC * plCol, range, newVal, curMerge, transposeRange); //если замержили range c = range.bbox.c2 - autoC * plCol - arn.c1; if (c === cMax) { r = range.bbox.r2 - autoC * plCol - arn.r1; } } } } } } if (isLinkToOtherWorkbook) { ws.model.workbook.handlers.trigger("asc_onNeedUpdateExternalReference") } ws.isChanged = true; return [trueActiveRange, arrFormula]; }; CCellPasteHelper.prototype._setPastedDataByCurrentRange = function (range, rangeStyle, formulaProps, specialPasteProps) { var t = this; var ws = this.ws; var firstRange, arrFormula, tablesMap, newVal, isOneMerge, val, activeCellsPasteFragment, transposeRange; if (formulaProps) { //TODO firstRange возможно стоит убрать(добавлено было для правки бага 27745) firstRange = formulaProps.firstRange; arrFormula = formulaProps.arrFormula; tablesMap = formulaProps.tablesMap; newVal = formulaProps.newVal; isOneMerge = formulaProps.isOneMerge; val = formulaProps.val; activeCellsPasteFragment = formulaProps.activeCellsPasteFragment; transposeRange = formulaProps.transposeRange; } if (specialPasteProps && specialPasteProps.skipBlanks && newVal && newVal.isNullText()) { return; } var _calculateSpecialOperation = function (part1, part2, _operation, _isFormula) { if (part1 !== null && part2 !== null) { var _res = null; switch (_operation) { case window['Asc'].c_oSpecialPasteOperation.add: { if (_isFormula) { _res = part1 + "+" + part2; } else { _res = part1 + part2; } break; } case window['Asc'].c_oSpecialPasteOperation.subtract: { if (_isFormula) { _res = part1 + "-" + part2; } else { _res = part1 - part2; } break; } case window['Asc'].c_oSpecialPasteOperation.multiply: { if (_isFormula) { _res = part1 + "*" + part2; } else { _res = part1 * part2; } break; } case window['Asc'].c_oSpecialPasteOperation.divide: { if (_isFormula) { _res = part1 + "/" + part2; } else { if (part2 === 0) { _res = AscCommon.cErrorLocal["div"]; } else { _res = part1 / part2; } } break; } } } return _res; }; var applySpecialOperation = function (_pastedVal, _modelVal, _operation, isEmptyPasted, isEmptyModel) { if (_operation === null) { return _pastedVal; } var _typePasted = _pastedVal && _pastedVal.value && !isEmptyPasted ? _pastedVal.value.type : null; var _typeModel = _modelVal && _modelVal.value && !isEmptyModel ? _modelVal.value.type : null; var res = null; var _calculateRes = undefined; if (_typePasted === CellValueType.Number && _typeModel === CellValueType.Number) { _calculateRes = _calculateSpecialOperation(_modelVal.value.number, _pastedVal.value.number, _operation); } else if (_typePasted === CellValueType.Number && isEmptyModel) { _calculateRes = _calculateSpecialOperation(0, _pastedVal.value.number, _operation); } else if (_typeModel === CellValueType.Number && isEmptyPasted) { _calculateRes = _calculateSpecialOperation(_modelVal.value.number, 0, _operation); } else { res = _modelVal; } if (_calculateRes !== undefined) { if (!isNaN(_calculateRes)) { _pastedVal.value.number = _calculateRes; } else { _pastedVal.value.text = _calculateRes; _pastedVal.value.type = CellValueType.Error; _pastedVal.value.number = null; } res = _pastedVal; } return res; }; var applySpecialOperationFormula = function (_pastedVal, _modelVal, _pastedFormula, _modelFormula, _operation, isEmptyPasted, isEmptyModel) { var res, part1, part2; var _typePasted = _pastedVal && _pastedVal.value && !isEmptyPasted ? _pastedVal.value.type : null; var _typeModel = _modelVal && _modelVal.value && !isEmptyModel ? _modelVal.value.type : null; if (_pastedFormula && _modelFormula) { part2 = "(" + _pastedFormula + ")"; part1 = "(" + _modelFormula + ")"; res = _calculateSpecialOperation(part1, part2, _operation, true); } else if (_pastedFormula && _typeModel === CellValueType.Number) { part2 = "(" + _pastedFormula + ")"; part1 = _modelVal.value.number; res = _calculateSpecialOperation(part1, part2, _operation, true); } else if (_modelFormula && _typePasted === CellValueType.Number) { part2 = _pastedVal.value.number; part1 = "(" + _modelFormula + ")"; res = _calculateSpecialOperation(part1, part2, _operation, true); } else if (_pastedFormula && isEmptyModel) { part2 = "(" + _pastedFormula + ")"; part1 = 0; res = _calculateSpecialOperation(part1, part2, _operation, true); } else if (_modelFormula && isEmptyPasted) { part2 = 0; part1 = "(" + _modelFormula + ")"; res = _calculateSpecialOperation(part1, part2, _operation, true); } else if (_pastedFormula) { res = null; } else { res = _modelFormula; } return res; }; var getModelData = function () { var val = firstRange ? firstRange.getValueData() : range.getValueData(); var formula = firstRange ? firstRange.getFormula() : range.getFormula(); return {val: val, formula: formula}; }; //set formula - for paste from binary var calculateValueAndBinaryFormula = function (newVal, firstRange, range) { //operation special paste var needOperation = specialPasteProps && specialPasteProps.operation; if (needOperation === window['Asc'].c_oSpecialPasteOperation.none) { needOperation = null; } var modelVal, modelFormula; if (null !== needOperation) { var _modelData = getModelData(); modelVal = _modelData.val; modelFormula = _modelData.formula; } var isEmptyModel = firstRange ? firstRange.isNullText() : range.isNullText(); var isEmptyPasted = newVal.isNullText(); var cellValueData = specialPasteProps.cellStyle ? newVal.getValueData() : null; if (cellValueData) { var _setOperationVal = applySpecialOperation(cellValueData, modelVal, needOperation, isEmptyPasted, isEmptyModel); if (null !== _setOperationVal) { cellValueData = _setOperationVal; } } var cellValueDataDup = newVal.getValueData(); if (cellValueData && cellValueData.value) { if (!specialPasteProps.formula) { cellValueData.formula = null; } rangeStyle.cellValueData = cellValueData; } else if (cellValueData && cellValueData.formula && !specialPasteProps.formula) { cellValueData.formula = null; rangeStyle.cellValueData = cellValueData; } else { if (needOperation !== null) { var _tempValRes = applySpecialOperation(cellValueDataDup, modelVal, needOperation, isEmptyPasted, isEmptyModel); if (null === _tempValRes) { rangeStyle.val = ""; } else if (null !== _tempValRes.value.number) { rangeStyle.val = _tempValRes.value.number.toString(); } else if (null !== _tempValRes.value.multiText) { rangeStyle.val = _tempValRes.value.multiText; } else if (_tempValRes.value.text) { rangeStyle.val = _tempValRes.value.text; } } else { rangeStyle.val = newVal.getValue(); if (rangeStyle.val && newVal.getType() === CellValueType.Number) { rangeStyle.val = rangeStyle.val.replace(AscCommon.FormulaSeparators.digitSeparatorDef, AscCommon.FormulaSeparators.digitSeparator); } } } var _newVal = newVal; if (null !== needOperation && formulaProps.formulaArrayFirstCell) { _newVal = formulaProps.formulaArrayFirstCell; } var pastedFormula = _newVal.getFormula(); var sId = _newVal.getName(); if (pastedFormula || modelFormula) { let oFromCell = formulaProps.cell; //formula if (pastedFormula && !isOneMerge) { var offset, arrayOffset; var arrayFormulaRef = needOperation === null && formulaProps.cell && formulaProps.cell.formulaParsed ? formulaProps.cell.formulaParsed.getArrayFormulaRef() : null; var cellAddress = new AscCommon.CellAddress(sId); if (specialPasteProps.transpose && transposeRange) { //для transpose необходимо брать offset перевернутого range if (arrayFormulaRef) { offset = new AscCommon.CellBase(transposeRange.bbox.r1 - cellAddress.row + 1, transposeRange.bbox.c1 - cellAddress.col + 1); arrayOffset = new AscCommon.CellBase(transposeRange.bbox.r1 - cellAddress.row + 1, transposeRange.bbox.c1 - cellAddress.col + 1); } else { offset = new AscCommon.CellBase(transposeRange.bbox.r1 - cellAddress.row + 1, transposeRange.bbox.c1 - cellAddress.col + 1); } } else { if (arrayFormulaRef) { offset = new AscCommon.CellBase(range.bbox.r1 - arrayFormulaRef.r1, range.bbox.c1 - arrayFormulaRef.c1); arrayOffset = new AscCommon.CellBase(range.bbox.r1 - cellAddress.row + 1, range.bbox.c1 - cellAddress.col + 1); } else { offset = new AscCommon.CellBase(range.bbox.r1 - cellAddress.row + 1, range.bbox.c1 - cellAddress.col + 1); } } var assemb, _p_ = new AscCommonExcel.parserFormula(pastedFormula, null, ws.model); if (_p_.parse(null, null, null, null, null, tablesMap)) { //array-formula if (arrayFormulaRef) { arrayFormulaRef = arrayFormulaRef.clone(); if (!formulaProps.fromRange.containsRange(arrayFormulaRef)) { arrayFormulaRef = arrayFormulaRef.intersection(formulaProps.fromRange); } if (arrayFormulaRef) { if (specialPasteProps.transpose) { var diffCol1 = arrayFormulaRef.c1 - activeCellsPasteFragment.c1; var diffRow1 = arrayFormulaRef.r1 - activeCellsPasteFragment.r1; var diffCol2 = arrayFormulaRef.c2 - activeCellsPasteFragment.c1; var diffRow2 = arrayFormulaRef.r2 - activeCellsPasteFragment.r1; arrayFormulaRef.c1 = activeCellsPasteFragment.c1 + diffRow1; arrayFormulaRef.r1 = activeCellsPasteFragment.r1 + diffCol1; arrayFormulaRef.c2 = activeCellsPasteFragment.c1 + diffRow2; arrayFormulaRef.r2 = activeCellsPasteFragment.r1 + diffCol2; } arrayFormulaRef.setOffset(arrayOffset ? arrayOffset : offset); } } if (specialPasteProps.transpose) { //для transpose необходимо перевернуть все дипазоны в формулах _p_.transpose(activeCellsPasteFragment); } if (null !== tablesMap) { var renameParams = {}; renameParams.offset = offset; renameParams.tableNameMap = tablesMap; _p_.renameSheetCopy(renameParams); assemb = _p_.assemble(true) } else { assemb = _p_.changeOffset(offset, null, true).assemble(true); } if (needOperation !== null) { assemb = applySpecialOperationFormula(cellValueDataDup, modelVal, assemb, modelFormula, needOperation, isEmptyPasted, isEmptyModel); } if (assemb !== null) { rangeStyle.formula = { range: range, val: "=" + assemb, arrayRef: arrayFormulaRef, ca: oFromCell.getFormulaParsed().ca, oldValue: oFromCell.getNumberValue() }; } } } else if (modelFormula && needOperation !== null) { assemb = applySpecialOperationFormula(cellValueDataDup, modelVal, null, modelFormula, needOperation, isEmptyPasted, isEmptyModel); if (assemb !== null) { rangeStyle.formula = { range: range, val: "=" + assemb, arrayRef: arrayFormulaRef, ca: oFromCell.getFormulaParsed().ca, oldValue: oFromCell.getNumberValue() }; } } } }; var calculateFormulaFromHtml = function (sFormula) { if (sFormula) { //formula if (sFormula && !isOneMerge) { sFormula = sFormula.substr(1); var offset = new AscCommon.CellBase(0, 0); var assemb, _p_ = new AscCommonExcel.parserFormula(sFormula, null, ws.model); let parseResult = new AscCommonExcel.ParseResult(); if (_p_.parse(AscCommonExcel.oFormulaLocaleInfo.Parse, AscCommonExcel.oFormulaLocaleInfo.DigitSep, parseResult)) { if (parseResult.externalReferenesNeedAdd && ws && ws.model && ws.model.workbook) { ws.model.workbook.addExternalReferencesAfterParseFormulas(parseResult.externalReferenesNeedAdd); // we create the formula again and parse it to correctly obtain externalLink and elements in outStack _p_ = new AscCommonExcel.parserFormula(sFormula, null, ws.model); _p_.parse(AscCommonExcel.oFormulaLocaleInfo.Parse, AscCommonExcel.oFormulaLocaleInfo.DigitSep, parseResult) } assemb = _p_.changeOffset(offset, null, true).assemble(true); rangeStyle.formula = {range: range, val: "=" + assemb}; } else { rangeStyle.cellValueData = new AscCommonExcel.UndoRedoData_CellValueData(null, new AscCommonExcel.CCellValue({ text: "=" + sFormula, type: CellValueType.String })); } } } }; var searchRangeIntoFormulaArrays = function (arr, curRange) { var res = false; if (arr && curRange && curRange.bbox) { for (var i = 0; i < arr.length; i++) { var refArray = arr[i].arrayRef; if (refArray && refArray.intersection(curRange.bbox)) { res = true; break; } } } return res; }; if (specialPasteProps.format && range.getHyperlink()) { range.removeHyperlink(); } //column width var col = range.bbox.c1; if (specialPasteProps.width && rangeStyle.colsWidth[col]) { var widthProp = rangeStyle.colsWidth[col]; ws.model.setColWidth(widthProp.width, col, col); ws.model.setColHidden(widthProp.hd, col, col); ws.model.setColBestFit(widthProp.BestFit, widthProp.width, col, col); rangeStyle.colsWidth[col] = null; } //offsetLast if (rangeStyle.offsetLast && specialPasteProps.merge) { range.setOffsetLast(rangeStyle.offsetLast); range.merge(rangeStyle.merge); } //for formula if (formulaProps && formulaProps.fromBinary) { calculateValueAndBinaryFormula(newVal, firstRange, range); } else if (!specialPasteProps.advancedOptions && rangeStyle && rangeStyle.val && rangeStyle.val.charAt(0) === "=") { calculateFormulaFromHtml(rangeStyle.val); } //fontName if (rangeStyle.fontName && specialPasteProps.fontName) { range.setFontname(rangeStyle.fontName); } //cellStyle if (rangeStyle.cellStyle && specialPasteProps.cellStyle) { //сделал для того, чтобы не перетерались старые бордеры бордерами стиля в случае, если специальная вставка без бордеров var oldBorders = null; if (!specialPasteProps.borders) { oldBorders = range.getBorderFull(); if (oldBorders) { oldBorders = oldBorders.clone(); } } if (range.getStyleName() !== rangeStyle.cellStyle) { range.setCellStyle(rangeStyle.cellStyle); } if (oldBorders) { range.setBorder(null); range.setBorder(oldBorders); } } //если не вставляем форматированную таблицу, но формат необходимо вставить if (specialPasteProps.format && !specialPasteProps.formatTable && rangeStyle.tableDxf) { range.getLeftTopCell(function (firstCell) { if (firstCell) { firstCell.setStyle(rangeStyle.tableDxf); } }); } //numFormat if (rangeStyle.numFormat && specialPasteProps.numFormat) { if (range.getNumFormatStr() !== rangeStyle.numFormat) { range.setNumFormat(rangeStyle.numFormat); } } //font if (rangeStyle.font && specialPasteProps.font) { var font = rangeStyle.font; //если вставляем форматированную таблицу с параметров values + all formating if (specialPasteProps.format && !specialPasteProps.formatTable && rangeStyle.tableDxf && rangeStyle.tableDxf.font) { font = rangeStyle.tableDxf.font.merge(rangeStyle.font); } if (!font.isEqual(range.getFont())) { range.setFont(font); } } var propPaste = specialPasteProps.property; var pasteOnlyText = propPaste === Asc.c_oSpecialPasteProps.valueNumberFormat || propPaste === Asc.c_oSpecialPasteProps.pasteOnlyValues; //***value*** //если формула - добавляем в массив и обрабатываем уже в _pasteData if (rangeStyle.formula && specialPasteProps.formula) { arrFormula.push(rangeStyle.formula); } else if (specialPasteProps.formula && searchRangeIntoFormulaArrays(arrFormula, range)) { //если ячейка является частью формулы массива-> в этом случае не нужно делать setValueData } else if (rangeStyle.cellValueData2 && specialPasteProps.font && specialPasteProps.val) { ws.model._getCell(rangeStyle.cellValueData2.row, rangeStyle.cellValueData2.col, function (cell) { cell.setValueData(rangeStyle.cellValueData2.valueData); }); } else if (rangeStyle.value2 && specialPasteProps.font && specialPasteProps.val) { if (formulaProps && firstRange) { firstRange.setValue2(rangeStyle.value2); } else { range.setValue2(rangeStyle.value2); } } else if (rangeStyle.cellValueData && specialPasteProps.val) { if (formulaProps && firstRange) { firstRange.setValueData(rangeStyle.cellValueData); } else { range.setValueData(rangeStyle.cellValueData); } } else if (null != rangeStyle.val && specialPasteProps.val) { //TODO возможно стоит всегда вызывать setValueData и тип выставлять в зависимости от val if (rangeStyle.val[0] === "'") { range.setValueData(new AscCommonExcel.UndoRedoData_CellValueData(null, new AscCommonExcel.CCellValue({ text: rangeStyle.val, type: CellValueType.String }))); } else { range.setValue(rangeStyle.val, null, null, undefined, pasteOnlyText); } } let align = range.getAlign(); //alignVertical if (undefined !== rangeStyle.alignVertical && specialPasteProps.alignVertical) { if (!align || align.getAlignVertical() !== rangeStyle.alignVertical) { range.setAlignVertical(rangeStyle.alignVertical); } } //alignHorizontal if (undefined !== rangeStyle.alignHorizontal && specialPasteProps.alignHorizontal) { if (!align || align.getAlignHorizontal() !== rangeStyle.alignHorizontal) { range.setAlignHorizontal(rangeStyle.alignHorizontal); } } //readingOrder if (undefined !== rangeStyle.readingOrder && specialPasteProps.readingOrder) { if (!align || align.getReadingOrder() !== rangeStyle.readingOrder) { range.setReadingOrder(rangeStyle.readingOrder); } } //fontSize if (rangeStyle.fontSize && specialPasteProps.fontSize) { range.setFontsize(rangeStyle.fontSize); } //borders if (rangeStyle.borders && specialPasteProps.borders) { range.setBorderSrc(rangeStyle.borders); } //bordersFull if (rangeStyle.bordersFull && specialPasteProps.borders) { if (!rangeStyle.bordersFull.isEqual(range.getBorderFull())) { range.setBorder(rangeStyle.bordersFull); } } //wrap if (rangeStyle.wrap && specialPasteProps.wrap) { range.setWrap(rangeStyle.wrap); } //fill if (specialPasteProps.fill && undefined !== rangeStyle.fill) { range.setFill(rangeStyle.fill); } if (specialPasteProps.fill && undefined !== rangeStyle.fillColor) { range.setFillColor(rangeStyle.fillColor); } //angle if (undefined !== rangeStyle.angle && specialPasteProps.angle) { if (range.getAngle() !== rangeStyle.angle) { range.setAngle(rangeStyle.angle); } } if (rangeStyle.shrinkToFit && specialPasteProps.fontSize) { range.setShrinkToFit(rangeStyle.shrinkToFit); } if (rangeStyle.tableDxfLocal && specialPasteProps.format) { range.getLeftTopCell(function (firstCell) { if (firstCell) { firstCell.setStyle(rangeStyle.tableDxfLocal); } }); } //indent if (rangeStyle.indent && specialPasteProps.format && rangeStyle.indent > 0) { range.setIndent(rangeStyle.indent); } //locked if (rangeStyle.locked !== undefined && specialPasteProps.format) { if (range.getLocked() !== rangeStyle.locked) { range.setLocked(rangeStyle.locked); } } //hidden if (rangeStyle.hidden !== undefined && specialPasteProps.format) { range.setHiddenFormulas(rangeStyle.hidden); } //hyperLink if (rangeStyle.hyperLink && specialPasteProps.hyperlink) { var _link = rangeStyle.hyperLink.hyperLink; var newHyperlink = new AscCommonExcel.Hyperlink(); if (_link.search('#') === 0) { newHyperlink.setLocation(_link.replace('#', '')); } else { newHyperlink.Hyperlink = _link; } newHyperlink.Ref = range; newHyperlink.Tooltip = rangeStyle.hyperLink.toolTip; newHyperlink.Location = rangeStyle.hyperLink.location; range.setHyperlink(newHyperlink); } else if (rangeStyle.hyperlinkObj && specialPasteProps.hyperlink) { rangeStyle.hyperlinkObj.Ref = range; range.setHyperlink(rangeStyle.hyperlinkObj, true); } //todo try to change up all styles on one cellstyle /*if (rangeStyle._cellStyle) { range.setCellStyle(rangeStyle._cellStyle); }*/ }; CCellPasteHelper.prototype._pasteCellLink = function (range, fromRow, fromCol, arrFormula, sheetName, pasteLink) { var formulaRange = new Asc.Range(fromCol, fromRow, fromCol, fromRow); var sFromula; if (pasteLink != null) { sFromula = "[" + pasteLink + "]" + sheetName + "!" + formulaRange.getName(); } else { //вставляем в этот же документ if (sheetName) { sFromula = sheetName + "!" + formulaRange.getName(); } else { sFromula = formulaRange.getName(); } } if (sFromula) { arrFormula.push({range: range, val: "=" + sFromula}); } }; CCellPasteHelper.prototype.getPastedLinkInfo = function (pastedWb, pastedWs) { //0 - вставляем в эту же книгу и в этот же лист //1 - вставляем в эту же книгу и на другой лист //-1 - вставляем в другую книгу и сслыка на неё уже есть //-2 - вставляем в другую книгу и ссылки на неё ешё нет var ws = this.ws; let type = null; let index = null; let sheet = null; let relativePath; if (pastedWb) { //вставляем в этот же документ. но исходный лист уже мог измениться/удалиться и тп //TODO просмотреть все эти случаи, ms desktop и online ведут себя по-разному //сейчас сравниваю по имени //TODO обработать: при вставке из одного и того же документа(открытого разными юзерами) с листа, который ещё не был добавлен другим юзером в режиме строго совместного редактирования let sameDoc = AscCommonExcel.g_clipboardExcel && AscCommonExcel.g_clipboardExcel.pasteProcessor && AscCommonExcel.g_clipboardExcel.pasteProcessor._checkPastedInOriginalDoc(pastedWb, true); let sameSheet = sameDoc && pastedWs.sName === ws.model.sName; let externalSheetSameWb; if (!sameSheet && sameDoc) { let sName = pastedWs.sName; for (let i = 0; i < ws.model.workbook.aWorksheets.length; i++) { if (ws.model.workbook.aWorksheets[i].sName === sName) { externalSheetSameWb = sName; } } } if (sameSheet) { type = 0; } else if (externalSheetSameWb) { type = 1; sheet = externalSheetSameWb; } else { let externalReferenceIndex; if (window["AscDesktopEditor"] && window["AscDesktopEditor"]["IsLocalFile"]()) { let fromPath = pastedWb.Core.contentStatus; let thisPath = window["AscDesktopEditor"]["LocalFileGetSourcePath"](); relativePath = buildRelativePath(fromPath, thisPath); externalReferenceIndex = ws.model.workbook.getExternalLinkIndexByName(relativePath); } else { //first we look by additional information //fileId -> contentStatus, portalName -> category let referenceData; if (pastedWb && pastedWb.Core) { referenceData = {}; referenceData["fileKey"] = pastedWb.Core.contentStatus; referenceData["instanceId"] = pastedWb.Core.category; } /* get external link index by reference data */ externalReferenceIndex = referenceData && ws.model.workbook.getExternalReferenceByReferenceData(referenceData, true); if (null == externalReferenceIndex) { //потом пробуем по имени найти let tempER = pastedWb && pastedWb.Core && ws.model.workbook.getExternalLinkIndexByName(pastedWb.Core.title); if (tempER && !referenceData) { // if there is no data, but an existing link with the same name is found, we refer to the existing data without updating externalReferenceIndex = tempER; } // if there is data and it doesn't match, and we have a link with the same name, we write a new link (duplicated by name, but not by data) } } //if we still haven’t found the ER, then we add a new external reference if (!externalReferenceIndex) { type = -2; } else { type = -1; index = externalReferenceIndex; sheet = pastedWs.sName; } } } return type !== null ? {type: type, index: index, sheet: sheet, path: relativePath} : null; }; CCellPasteHelper.prototype.checkPastedRange = function (pastedInfo) { if (!pastedInfo) { return false; } return pastedInfo.fromBinary ? this.pasteFromBinary(pastedInfo.data, true) : this.pasteFromHTML(pastedInfo.data, true); }; CCellPasteHelper.prototype.isNeedLockedAllOnPaste = function (val) { if (!val) { return false; } let ws = this.ws; var specialPasteHelper = window['AscCommon'].g_specialPasteHelper; var specialPasteProps = specialPasteHelper.specialPasteProps; var allowedPasteTables = !specialPasteProps || specialPasteProps.formatTable; var pasteContent = val.data; //отдельный лок для этого не делаю, а лочу всё перед вставкой новой ссылки if (specialPasteProps && specialPasteProps.property === Asc.c_oSpecialPasteProps.link) { const workbook = pasteContent.workbook; var linkInfo = this.getPastedLinkInfo(workbook, workbook && workbook.aWorksheets[0]); if (linkInfo && linkInfo.type === -2) { return true; } } if (val.fromBinary && pasteContent && pasteContent.TableParts && pasteContent.TableParts.length && allowedPasteTables) { var arnToRange = ws.model.selectionRange.getLast(); var range, tablePartRange, tables = pasteContent.TableParts, diffRow, diffCol, curTable, bIsAddTable; var activeRange = AscCommonExcel.g_clipboardExcel.pasteProcessor.activeRange; var refInsertBinary = AscCommonExcel.g_oRangeCache.getAscRange(activeRange); var pasteRange = AscCommonExcel.g_clipboardExcel.pasteProcessor.activeRange; var activeCellsPasteFragment = typeof pasteRange === "string" ? AscCommonExcel.g_oRangeCache.getAscRange(pasteRange) : pasteRange; for (var i = 0; i < tables.length; i++) { curTable = tables[i]; tablePartRange = curTable.Ref; diffRow = tablePartRange.r1 - refInsertBinary.r1 + arnToRange.r1; diffCol = tablePartRange.c1 - refInsertBinary.c1 + arnToRange.c1; range = ws.model.getRange3(diffRow, diffCol, diffRow + (tablePartRange.r2 - tablePartRange.r1), diffCol + (tablePartRange.c2 - tablePartRange.c1)); //если в активную область при записи попала лишь часть таблицы if (activeCellsPasteFragment && !activeCellsPasteFragment.containsRange(tablePartRange)) { continue; } //если область вставки содержит форматированную таблицу, которая пересекается с вставляемой форматированной таблицей if (ws.model.autoFilters._intersectionRangeWithTableParts(range.bbox)) { continue; } return true; } } return false; }; CCellPasteHelper.prototype.specialPaste = function (props) { var api = window["Asc"]["editor"]; var t = this; let ws = this.ws; var specialPasteHelper = window['AscCommon'].g_specialPasteHelper; var specialPasteData = specialPasteHelper.specialPasteData; if (!specialPasteData) { return; } var isIntoShape = ws.objectRender.controller.getTargetDocContent(); var onSelectionCallback = function (isSuccess) { if (!isSuccess) { return false; } window['AscCommon'].g_specialPasteHelper.Paste_Process_Start(); window['AscCommon'].g_specialPasteHelper.Special_Paste_Start(); //для того, чтобы была возможность делать несколько математических операций подряд var doUndo = true; if (window['Asc'].c_oSpecialPasteOperation.none !== props.operation && null !== props.operation) { if (window['AscCommon'].g_specialPasteHelper.isAppliedOperation) { doUndo = false; } window['AscCommon'].g_specialPasteHelper.isAppliedOperation = true; //specialPasteHelper.selectionRange = null; } else { window['AscCommon'].g_specialPasteHelper.isAppliedOperation = false; } //тут нужно откатить селект if (doUndo) { api.asc_Undo(); } if (specialPasteHelper.selectionRange) { ws.model.selectionRange = specialPasteHelper.selectionRange.clone(); } let pastingData1 = specialPasteData.data1; let pastingData2 = specialPasteData.data2; let doPaste = function (isSuccess, _format) { if (!isSuccess) { return; } //транзакция закроется в end_paste History.Create_NewPoint(); History.StartTransaction(); //далее специальная вставка specialPasteHelper.specialPasteProps = props; //TODO пока для закрытия транзации выставляю флаг. пересмотреть! window['AscCommon'].g_specialPasteHelper.bIsEndTransaction = true; AscCommonExcel.g_clipboardExcel.pasteData(ws, _format != null ? _format : specialPasteData._format, pastingData1, pastingData2, specialPasteData.text_data, true); if (cPasteProps.none !== pasteProp && cPasteProps.link !== pasteProp && cPasteProps.picture !== pasteProp && cPasteProps.linkedPicture !== pasteProp) { ws.traceDependentsManager && ws.traceDependentsManager.clearAll(true); } }; const cPasteProps = Asc.c_oSpecialPasteProps; const pasteProp = props && props.property; if (cPasteProps.picture === pasteProp && specialPasteData.images) { if (specialPasteData.htmlImage && false) { pastingData1 = specialPasteData.htmlImage; doPaste(true); } else { var blob = specialPasteData.images[0]; var reader = new FileReader(); reader.onload = function(e) { let html = ""; AscCommon.g_clipboardBase.CommonIframe_PasteStart(html, null, function (oHtmlElem) { if (oHtmlElem) { pastingData1 = oHtmlElem; specialPasteData.htmlImage = oHtmlElem; doPaste(true, AscCommon.c_oAscClipboardDataFormat.HtmlElement); } }); }; reader.onabort = reader.onerror = function(e) { doPaste(false); }; try { reader.readAsDataURL(blob); } catch (err) { doPaste(false); } } } else { doPaste(true); } }; if (specialPasteData.activeRange && !isIntoShape) { ws._isLockedCells(specialPasteData.activeRange.ranges, /*subType*/null, props && props.width ? ws._isLockedAll(onSelectionCallback) : onSelectionCallback); } else { onSelectionCallback(true); } }; CCellPasteHelper.prototype.showSpecialPasteOptions = function (options/*, range, positionShapeContent*/) { var ws = this.ws; var specialPasteShowOptions = window['AscCommon'].g_specialPasteHelper.buttonInfo; var positionShapeContent = options.position; var range = options.range; var props = options.options; var showPasteSpecial = options.showPasteSpecial; var containTables = options.containTables; var cellCoord; if (!positionShapeContent) { window['AscCommon'].g_specialPasteHelper.CleanButtonInfo(); window['AscCommon'].g_specialPasteHelper.buttonInfo.setRange(range); var isVisible = null !== ws.getCellVisibleRange(range.c2, range.r2); cellCoord = this.getSpecialPasteCoords(range, isVisible); } else { //var isVisible = null !== ws.getCellVisibleRange(range.c2, range.r2); cellCoord = [new AscCommon.asc_CRect(positionShapeContent.x, positionShapeContent.y, 0, 0)]; } specialPasteShowOptions.asc_setOptions(props); specialPasteShowOptions.asc_setCellCoord(cellCoord); specialPasteShowOptions.asc_setShowPasteSpecial(showPasteSpecial); specialPasteShowOptions.asc_setContainTables(containTables); ws.handlers.trigger("showSpecialPasteOptions", specialPasteShowOptions); }; CCellPasteHelper.prototype.updateSpecialPasteButton = function () { var ws = this.ws; var specialPasteShowOptions, cellCoord; var isIntoShape = ws.objectRender.controller.getTargetDocContent(); if (window['AscCommon'].g_specialPasteHelper.showSpecialPasteButton && isIntoShape) { if (window['AscCommon'].g_specialPasteHelper.buttonInfo.shapeId === isIntoShape.Id) { var curShape = isIntoShape.Parent.parent; var mmToPx = asc_getcvt(3/*mm*/, 0/*px*/, ws._getPPIX()); var cursorPos = window['AscCommon'].g_specialPasteHelper.buttonInfo.range; var offsetX = ws._getOffsetX(); var offsetY = ws._getOffsetY(); var posX = curShape.transformText.TransformPointX(cursorPos.X, cursorPos.Y) * mmToPx - offsetX + ws.cellsLeft; var posY = curShape.transformText.TransformPointY(cursorPos.X, cursorPos.Y) * mmToPx - offsetY + ws.cellsTop; posX = AscCommon.AscBrowser.convertToRetinaValue(posX); posY = AscCommon.AscBrowser.convertToRetinaValue(posY); cellCoord = [new AscCommon.asc_CRect(posX, posY, 0, 0)]; } } else if (window['AscCommon'].g_specialPasteHelper.showSpecialPasteButton) { var range = window['AscCommon'].g_specialPasteHelper.buttonInfo.range; var isVisible = null !== ws.getCellVisibleRange(range.c2, range.r2); cellCoord = this.getSpecialPasteCoords(range, isVisible); } if (cellCoord) { specialPasteShowOptions = window['AscCommon'].g_specialPasteHelper.buttonInfo; specialPasteShowOptions.asc_setOptions(null); specialPasteShowOptions.asc_setCellCoord(cellCoord); ws.handlers.trigger("showSpecialPasteOptions", specialPasteShowOptions); } }; CCellPasteHelper.prototype.getSpecialPasteCoords = function (range, isVisible) { var disableCoords = function () { cellCoord._x = -1; cellCoord._y = -1; }; var ws = this.ws; //TODO пересмотреть когда иконка вылезает за пределы области видимости var cellCoord = ws.getCellCoord(range.c2, range.r2); if (window['AscCommon'].g_specialPasteHelper.buttonInfo.shapeId) { disableCoords(); cellCoord = [cellCoord]; } else { var visibleRange = ws.getVisibleRange(); var intersectionVisibleRange = visibleRange.intersection(range); if (!intersectionVisibleRange && ws.topLeftFrozenCell) { var cFrozen = ws.topLeftFrozenCell.getCol0(); var rFrozen = ws.topLeftFrozenCell.getRow0(); cFrozen -= 1; rFrozen -= 1; var frozenRange; if (0 <= cFrozen && 0 <= rFrozen) { frozenRange = new asc_Range(0, 0, cFrozen, rFrozen); intersectionVisibleRange = frozenRange.intersection(range); } if (!intersectionVisibleRange && 0 <= cFrozen) { frozenRange = new asc_Range(0, ws.visibleRange.r1, cFrozen, ws.visibleRange.r2); intersectionVisibleRange = frozenRange.intersection(range); } if (!intersectionVisibleRange && 0 <= rFrozen) { frozenRange = new asc_Range(ws.visibleRange.c1, 0, ws.visibleRange.c2, rFrozen); intersectionVisibleRange = frozenRange.intersection(range); } } if (intersectionVisibleRange) { cellCoord = []; cellCoord[0] = ws.getCellCoord(intersectionVisibleRange.c2, intersectionVisibleRange.r2); cellCoord[1] = ws.getCellCoord(range.c1, range.r1); } else { disableCoords(); cellCoord = [cellCoord]; } } if (cellCoord && ws.getRightToLeft()) { if (cellCoord[0]) { cellCoord[0]._width = Math.abs(cellCoord[0]._width); cellCoord[0]._x = cellCoord[0]._x - cellCoord[0]._width; } if (cellCoord[1]) { cellCoord[1]._width = Math.abs(cellCoord[1]._width); cellCoord[1]._x = cellCoord[1]._x - cellCoord[1]._width; } } return cellCoord; }; /** * Class for asynchronous cell text replacement using timer * @constructor */ function CReplaceCellTextManager() { AscCommon.CActionOnTimerBase.call(this); this.ws = null; this.replaceCells = []; this.options = null; this.lockDraw = false; this.callback = null; this.oneUser = false; this.needLockCell = false; this.isSC = false; this.FirstActionOnTimer = true; this.Index = 0; } CReplaceCellTextManager.prototype = Object.create(AscCommon.CActionOnTimerBase.prototype); CReplaceCellTextManager.prototype.constructor = CReplaceCellTextManager; CReplaceCellTextManager.prototype.OnBegin = function(ws, aReplaceCells, options, lockDraw, callback, oneUser) { this.ws = ws; this.replaceCells = aReplaceCells; this.options = options; this.lockDraw = lockDraw; this.callback = callback; this.oneUser = oneUser; this.needLockCell = !oneUser; this.isSC = options.isSpellCheck; this.Index = options.indexInArray || 0; }; CReplaceCellTextManager.prototype.OnEnd = function() { // After processing all cells, unlock calculation and draw this.ws.model.workbook.dependencyFormulas.unlockRecal(); this.ws.draw(this.lockDraw); if (this.callback) { this.callback(this.options); } }; CReplaceCellTextManager.prototype.IsContinue = function() { return (this.Index < this.replaceCells.length); }; CReplaceCellTextManager.prototype.DoAction = function() { const cell = this.replaceCells[this.Index]; const t = this.ws; const oThis = this; this.Index++; this.options.indexInArray = this.Index; // Check for protected ranges if (cell && t.model.isUserProtectedRangesIntersection(cell)) { t.model.workbook.handlers.trigger("asc_onError", c_oAscError.ID.ProtectedRangeByOtherUser, c_oAscError.Level.NoCritical); this.options.error = true; this.End(); return; } // Check cell locking or perform replacement const isSuccess = !this.needLockCell || t._isLockedCells(cell, /*subType*/null, function(){}); if (isSuccess) { const c = t._getVisibleCell(cell.c1, cell.r1); let cellValue = c.getValueForEdit(); let v, newValue; const oldCellValue = cellValue; // Replace text depending on the mode if (!this.isSC) { cellValue = cellValue.replace(this.options.findRegExp, function() { ++oThis.options.countReplace; return oThis.options.replaceWith; }); } else { cellValue = AscCommonExcel.replaceSpellCheckWords(cellValue, this.options); } const isNeedToSave = oldCellValue !== cellValue; if (isNeedToSave) { // Create new fragments with replaced text v = c.getValueForEdit2().slice(0, 1); newValue = []; newValue[0] = new AscCommonExcel.Fragment({text: cellValue, format: v[0].format.clone()}); // Save new value if (!t._saveCellValueAfterEdit(c, newValue, /*flags*/undefined, /*isNotHistory*/true, /*lockDraw*/true)) { this.options.error = true; this.End(); return; } // Update search elements if (t.workbook.SearchEngine) { t.workbook.SearchEngine.removeFromSearchElems(cell.c1, cell.r1, t.model); } } } else { // If cell locking failed, stop processing this.options.error = true; this.End(); } }; //------------------------------------------------------------export--------------------------------------------------- window['AscCommonExcel'] = window['AscCommonExcel'] || {}; window["AscCommonExcel"].CellFlags = CellFlags; window["AscCommonExcel"].WorksheetView = WorksheetView; window['AscCommonExcel'].getPivotButtonsForLoad = getPivotButtonsForLoad; window['AscCommonExcel'].buildRelativePath = buildRelativePath; window['AscCommonExcel'].isAllowPasteLink = isAllowPasteLink; })(window);