/* * (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 asc = window["Asc"]; var AscBrowser = AscCommon.AscBrowser; var cElementType = AscCommonExcel.cElementType; var c_oAscCellEditorSelectState = AscCommonExcel.c_oAscCellEditorSelectState; var c_oAscCellEditorState = asc.c_oAscCellEditorState; var Fragment = AscCommonExcel.Fragment; var asc_getcvt = asc.getCvtRatio; var asc_round = asc.round; var asc_search = asc.search; var asc_lastidx = asc.lastIndexOf; var asc_HL = AscCommonExcel.HandlersList; var asc_incDecFonSize = asc.incDecFonSize; /** @const */ var kBeginOfLine = -1; /** @const */ var kBeginOfText = -2; /** @const */ var kEndOfLine = -3; /** @const */ var kEndOfText = -4; /** @const */ var kNextChar = -5; /** @const */ var kNextWord = -6; /** @const */ var kNextLine = -7; /** @const */ var kPrevChar = -8; /** @const */ var kPrevWord = -9; /** @const */ var kPrevLine = -10; /** @const */ var kPosition = -11; /** @const */ var kPositionLength = -12; /** @const */ var codeNewLine = 0x00A; var codeEqually = 0x3D; var codeUnarPlus = 0x2B; var codeUnarMinus = 0x2D; /** * CellEditor widget * ----------------------------------------------------------------------------- * @constructor * @param {Element} elem * @param {Element} input * @param {Array} fmgrGraphics * @param {AscCommonExcel.Font} oFont * @param {HandlersList} handlers * @param {Number} padding * @param {Boolean} menuEditor */ function CellEditor(elem, input, fmgrGraphics, oFont, handlers, padding, menuEditor) { this.element = elem; this.input = input; this.handlers = new asc_HL(handlers); this.options = {}; this.sides = undefined; this.menuEditor = menuEditor; //---declaration--- this.canvasOuter = undefined; this.canvasOuterStyle = undefined; this.canvas = undefined; this.canvasOverlay = undefined; this.cursor = undefined; this.cursorStyle = undefined; this.cursorTID = undefined; this.cursorPos = 0; this.beginCompositePos = -1; this.compositeLength = 0; this.topLineIndex = 0; this.m_oFont = oFont; this.fmgrGraphics = fmgrGraphics; this.drawingCtx = undefined; this.overlayCtx = undefined; this.textRender = undefined; this.textFlags = undefined; this.kx = 1; this.ky = 1; this.skipKeyPress = undefined; this.undoList = []; this.redoList = []; this.undoMode = false; this.noUpdateMode = false; this.selectionBegin = -1; this.selectionEnd = -1; this.isSelectMode = c_oAscCellEditorSelectState.no; this.hasCursor = false; this.hasFocus = false; this.newTextFormat = null; this.selectionTimer = undefined; this.enableKeyEvents = true; this.isTopLineActive = false; this.openFromTopLine = false; this.skipTLUpdate = true; this.loadFonts = false; this.isOpened = false; this.callTopLineMouseup = false; this.m_nEditorState = c_oAscCellEditorState.editEnd; // Editor's status // Features that we will disable this.fKeyMouseUp = null; this.fKeyMouseMove = null; //----------------- this.objAutoComplete = new Map(); this.sAutoComplete = null; this.eventListeners = []; /** @type RegExp */ this.rangeChars = ["=", "-", "+", "*", "/", "(", "{", "<", ">", "^", "!", "&", ":", " ", "."]; this.reNotFormula = new XRegExp("[^\\p{L}\\\\_\\#\\]\\[\\p{N}\\.\"\@]", "i"); this.reFormula = new XRegExp("^([\\p{L}\\\\_\\]\\[][\\p{L}\\\\_\\#\\]\\[\\p{N}\\.@]*)", "i"); this.defaults = { padding: padding, selectColor: new AscCommon.CColor(190, 190, 255, 0.5), canvasZIndex: 500, blinkInterval: 500, cursorShape: "text" }; this._formula = null; this._parseResult = null; this.needFindFirstFunction = null; this.lastRangePos = null; this.lastRangeLength = null; // Click handler this.clickCounter = new AscFormat.ClickCounter(); //temporary - for safari rendering. remove after fixed this._originalCanvasWidth = null; this._init(); return this; } CellEditor.prototype._init = function () { var t = this; var z = t.defaults.canvasZIndex; this.sAutoComplete = null; if (null != this.element) { var ceMenuEditor = this.getMenuEditorMode() ? '-menu' : '' var ceCanvasOuterId = "ce-canvas-outer" + ceMenuEditor; var ceCanvasId = "ce-canvas" + ceMenuEditor; var ceCanvasOverlay = "ce-canvas-overlay" + ceMenuEditor; var ceCursor = "ce-cursor" + ceMenuEditor; var canvasOuterEl = document.getElementById(ceCanvasOuterId); if (canvasOuterEl) { var parentNode = canvasOuterEl.parentNode; parentNode.removeChild(canvasOuterEl); } t.canvasOuter = document.createElement('div'); t.canvasOuter.id = ceCanvasOuterId; t.canvasOuter.style.position = "absolute"; t.canvasOuter.style.display = "none"; t.canvasOuter.style.zIndex = z; var innerHTML = ''; innerHTML += ''; innerHTML += '
'; t.canvasOuter.innerHTML = innerHTML; this.element.appendChild(t.canvasOuter); t.canvasOuterStyle = t.canvasOuter.style; t.canvas = document.getElementById(ceCanvasId); t.canvasOverlay = document.getElementById(ceCanvasOverlay); t.cursor = document.getElementById(ceCursor); t.cursorStyle = t.cursor.style; } // create text render t.drawingCtx = new asc.DrawingContext({ canvas: t.canvas, units: 0/*px*/, fmgrGraphics: this.fmgrGraphics, font: this.m_oFont }); t.overlayCtx = new asc.DrawingContext({ canvas: t.canvasOverlay, units: 0/*px*/, fmgrGraphics: this.fmgrGraphics, font: this.m_oFont }); t.textRender = new AscCommonExcel.CellTextRender(t.drawingCtx); // bind event handlers if (t.canvasOuter && t.canvasOuter.addEventListener) { var eventInfo = new AscCommon.CEventListenerInfo(t.canvasOuter, AscCommon.getPtrEvtName("down"), function () { return t._onMouseDown.apply(t, arguments); }, false); t.eventListeners.push(eventInfo); eventInfo = new AscCommon.CEventListenerInfo(t.canvasOuter, AscCommon.getPtrEvtName("up"), function () { return t._onMouseUp.apply(t, arguments); }, false); t.eventListeners.push(eventInfo); eventInfo = new AscCommon.CEventListenerInfo(t.canvasOuter, AscCommon.getPtrEvtName("move"), function () { return t._onMouseMove.apply(t, arguments); }, false); t.eventListeners.push(eventInfo); eventInfo = new AscCommon.CEventListenerInfo(t.canvasOuter, AscCommon.getPtrEvtName("leave"), function () { return t._onMouseLeave.apply(t, arguments); }, false); t.eventListeners.push(eventInfo); } // check input, it may have zero len, for mobile version if (t.input && t.input.addEventListener) { eventInfo = new AscCommon.CEventListenerInfo(t.input, "focus", function () { return t.isOpened ? t._topLineGotFocus.apply(t, arguments) : true; }, false); t.eventListeners.push(eventInfo); eventInfo = new AscCommon.CEventListenerInfo(t.input, AscCommon.getPtrEvtName("down"), function () { return t.isOpened ? (t.callTopLineMouseup = true) : true; }, false); t.eventListeners.push(eventInfo); eventInfo = new AscCommon.CEventListenerInfo(t.input, AscCommon.getPtrEvtName("up"), function () { return t.isOpened ? t._topLineMouseUp.apply(t, arguments) : true; }, false); t.eventListeners.push(eventInfo); eventInfo = new AscCommon.CEventListenerInfo(t.input, "input", function () { return t._onInputTextArea.apply(t, arguments); }, false); t.eventListeners.push(eventInfo); // We do not support drop to the top line eventInfo = new AscCommon.CEventListenerInfo(t.input, "drop", function (e) { e.preventDefault(); return false; }, false); t.eventListeners.push(eventInfo); } this.fKeyMouseUp = function () { return t._onWindowMouseUp.apply(t, arguments); }; this.fKeyMouseMove = function () { return t._onWindowMouseMove.apply(t, arguments); }; t.addEventListeners(); }; CellEditor.prototype.destroy = function () { }; CellEditor.prototype.removeEventListeners = function () { this.eventListeners.forEach(function (eventInfo) { eventInfo.listeningElement.removeEventListener(eventInfo.eventName, eventInfo.listener); }); }; CellEditor.prototype.addEventListeners = function () { this.eventListeners.forEach(function (eventInfo) { eventInfo.listeningElement.addEventListener(eventInfo.eventName, eventInfo.listener, eventInfo.useCapture); }); }; /** * @param {Object} options * fragments - text fragments * flags - text flags (wrapText, textAlign) * font * background * saveValueCallback */ CellEditor.prototype.open = function (options) { this._setEditorState(c_oAscCellEditorState.editStart); var b = this.input.selectionStart; this.isOpened = true; if (window.addEventListener) { window.addEventListener(AscCommon.getPtrEvtName("up"), this.fKeyMouseUp, false); window.addEventListener(AscCommon.getPtrEvtName("move"), this.fKeyMouseMove, false); } this._setOptions(options); this._cleanLastRangeInfo(); this._updateTopLineActive(true === this.input.isFocused, true); this._updateEditorState(); this._draw(); if (null !== options.enterOptions.newText) { this._selectChars(kEndOfText); this._addChars(options.enterOptions.newText); } if (this.isTopLineActive && typeof b !== "undefined") { if (this.cursorPos !== b) { this._moveCursor(kPosition, b); } } else if (options.enterOptions.cursorPos) { this._moveCursor(kPosition, options.enterOptions.cursorPos); } else if (options.enterOptions.eventPos) { this._onMouseDown(options.enterOptions.eventPos); this._onMouseUp(options.enterOptions.eventPos); } else { this._moveCursor(kEndOfText); } /* * Set focus when opening * When clicking a symbol, do not set focus * When F2 sets focus in the editor * When dbl clicking, set focus depending on the presence of text in the cell */ this.setFocus(this.isTopLineActive ? true : (null === options.enterOptions.focus) ? this._haveTextInEdit() : options.enterOptions.focus); this._updateUndoRedoChanged(); AscCommon.StartIntervalDrawText(true); this.openAction(); }; CellEditor.prototype.close = function (saveValue, callback) { var opt = this.options; var t = this; let externalSelectionController = this.handlers.trigger("getExternalSelectionController"); if (externalSelectionController && externalSelectionController.getExternalFormulaEditMode()) { if (!externalSelectionController.supportVisibilityChangeOption) { externalSelectionController.sendExternalCloseEditor(saveValue); saveValue = false; } else { callback && callback(false); return; } } var api = window["Asc"]["editor"]; if (api && !api.canUndoRedoByRestrictions()) { saveValue = false; } var localSaveValueCallback = function (isSuccess) { if (!isSuccess) { t.setFocus(true); t.cleanSelectRange(); if (callback) { callback(false); } return false; } t.isOpened = false; t._formula = null; t._parseResult = null; if (!window['IS_NATIVE_EDITOR']) { if (window.removeEventListener) { window.removeEventListener(AscCommon.getPtrEvtName("up"), t.fKeyMouseUp, false); window.removeEventListener(AscCommon.getPtrEvtName("move"), t.fKeyMouseMove, false); } if (api && api.isMobileVersion) { t.input.blur(); } t._blur(); t._updateTopLineActive(false); t.input.isFocused = false; t._updateCursor(); // hide t._hideCanvas(); } // delete autoComplete t.objAutoComplete.clear(); // Reset editor state t._setEditorState(c_oAscCellEditorState.editEnd); t.handlers.trigger("closed"); t.closeAction(); if (callback) { callback(true); } else { return true; } }; if (this.isStartCompositeInput()) { this.End_CompositeInput(); } if (saveValue) { // We always recalculate for a non-empty cell or if there were changes. http://bugzilla.onlyoffice.com/show_bug.cgi?id=34864 if (0 < this.undoList.length || 0 < AscCommonExcel.getFragmentsCharCodesLength(this.options.fragments)) { var isFormula = this.isFormula(); // We replace the text with auto-completion if there is a select and the text matches completely. if (this.sAutoComplete && !isFormula) { this.selectionBegin = this.textRender.getBeginOfText(); this.cursorPos = this.selectionEnd = this.textRender.getEndOfText(); this.noUpdateMode = true; this._addChars(this.sAutoComplete); this.noUpdateMode = false; } for (var i = 0; i < opt.fragments.length; i++) { opt.fragments[i].initText(); } return opt.saveValueCallback(opt.fragments, this.textFlags, localSaveValueCallback); } } this.isOpened = false; this._formula = null; this._parseResult = null; if (!window['IS_NATIVE_EDITOR']) { if (window.removeEventListener) { window.removeEventListener(AscCommon.getPtrEvtName("up"), this.fKeyMouseUp, false); window.removeEventListener(AscCommon.getPtrEvtName("move"), this.fKeyMouseMove, false); } this._blur(); this._updateTopLineActive(false); this.input.isFocused = false; this._updateCursor(); // hide this._hideCanvas(); } // delete autoComplete this.objAutoComplete.clear(); // Reset editor state this._setEditorState(c_oAscCellEditorState.editEnd); this.handlers.trigger("closed"); t.closeAction(); if (callback) { callback(true); } return true; }; CellEditor.prototype._blur = function () { this.handlers.trigger("doEditorFocus"); }; CellEditor.prototype.setTextStyle = function (prop, val) { if (this.isFormula()) { return; } if (!this.options.fragments) { return; } this.startAction(); var t = this, opt = t.options, begin, end, i, first, last; if (t.selectionBegin !== t.selectionEnd) { begin = Math.min(t.selectionBegin, t.selectionEnd); end = Math.max(t.selectionBegin, t.selectionEnd); // save info to undo/redo if (end - begin < 2) { t.undoList.push({fn: t._addChars, args: [t.textRender.getChars(begin, 1), begin]}); } else { t.undoList.push({fn: t._addFragments, args: [t._getFragments(begin, end - begin), begin]}); } t._extractFragments(begin, end - begin); first = t._findFragment(begin); last = t._findFragment(end - 1); if (first && last) { for (i = first.index; i <= last.index; ++i) { var valTmp = t._setFormatProperty(opt.fragments[i].format, prop, val); // For hotkeys only if (null === val) { val = valTmp; } } // merge fragments with equal formats t._mergeFragments(); t._update(); // Refreshing the selection t._cleanSelection(); t._drawSelection(); // save info to undo/redo t.undoList.push({fn: t._removeChars, args: [begin, end - begin]}); t.redoList = []; } } else { first = t._findFragmentToInsertInto(t.cursorPos); if (first) { if (!t.newTextFormat) { t.newTextFormat = opt.fragments[first.index].format.clone(); } t._setFormatProperty(t.newTextFormat, prop, val); t._update(); } } this.endAction(); }; CellEditor.prototype.changeTextCase = function (val) { if (this.isFormula()) { return; } if (!this.options.fragments) { return; } var t = this, opt = t.options; if (t.selectionBegin !== t.selectionEnd) { let begin = Math.min(t.selectionBegin, t.selectionEnd); let end = Math.max(t.selectionBegin, t.selectionEnd); let oNewText = AscCommonExcel.changeTextCase(opt.fragments, val, begin, end); if (oNewText && oNewText.fragmentsMap) { this._changeFragments(oNewText.fragmentsMap); } } }; CellEditor.prototype._changeFragments = function (fragmentsMap) { let opt = this.options; if (!opt.fragments) { return; } this.startAction(); if (fragmentsMap) { let _undoFragments = {}; for (let i in fragmentsMap) { if (fragmentsMap.hasOwnProperty(i)) { _undoFragments[i] = opt.fragments[i].clone(); opt.fragments[i] = fragmentsMap[i]; } } if (!this.undoMode) { // save info to undo/redo this.undoList.push({fn: this._changeFragments, args: [_undoFragments]}); } this._update(); // Refreshing the selection this._cleanSelection(); this._drawSelection(); } this.endAction(); }; CellEditor.prototype.empty = function (options) { // Clean for editing only All if (Asc.c_oAscCleanOptions.All !== options) { return; } // We delete only the selection this._removeChars(); }; CellEditor.prototype.undo = function () { var api = window["Asc"]["editor"]; if (api && !api.canUndoRedoByRestrictions()) { return; } api.sendEvent("asc_onBeforeUndoRedo"); this._performAction(this.undoList, this.redoList); api.sendEvent("asc_onUndoRedo"); }; CellEditor.prototype.redo = function () { var api = window["Asc"]["editor"]; if (api && !api.canUndoRedoByRestrictions()) { return; } api.sendEvent("asc_onBeforeUndoRedo"); this._performAction(this.redoList, this.undoList); api.sendEvent("asc_onUndoRedo"); }; CellEditor.prototype.getZoom = function () { return this.drawingCtx.getZoom(); }; CellEditor.prototype.changeZoom = function (factor) { this.drawingCtx.changeZoom(factor); this.overlayCtx.changeZoom(factor); }; CellEditor.prototype.canEnterCellRange = function () { if (this.lastRangePos !== null || this.handlers.trigger('getWizard')) { return true; } var res = false; var isSelection = this.selectionBegin !== this.selectionEnd; var curPos = isSelection ? (this.selectionBegin < this.selectionEnd ? this.selectionBegin : this.selectionEnd) : this.cursorPos; var prevChar = this.textRender.getChars(curPos - 1, 1); if (this.checkSymbolBeforeRange(prevChar)) { this.lastRangePos = curPos; if (isSelection) { this.lastRangeLength = Math.abs(this.selectionEnd - this.selectionBegin); } res = true; } return res; }; CellEditor.prototype.checkSymbolBeforeRange = function (char) { if (char && !char.trim) { char = AscCommon.convertUnicodeToUTF16(char); } return (this.rangeChars && this.rangeChars.indexOf(char) >= 0) || char === AscCommon.FormulaSeparators.functionArgumentSeparator; }; CellEditor.prototype.changeCellRange = function (range, moveEndOfText) { this.skipTLUpdate = false; this._moveCursor(kPosition, range.cursorePos); this._selectChars(kPositionLength, range.formulaRangeLength); this._addChars(range.getName(), undefined, /*isRange*/true); if (moveEndOfText) { this._moveCursor(kEndOfText); } this.skipTLUpdate = true; }; CellEditor.prototype.changeCellText = function (str) { this.skipTLUpdate = false; this._moveCursor(kPosition, this.lastRangePos); if (this.lastRangeLength) { this._selectChars(kPositionLength, this.lastRangeLength); } this._addChars(str, undefined, /*isRange*/true); this.lastRangeLength = str.length; this.skipTLUpdate = true; let externalSelectionController = this.handlers.trigger("getExternalSelectionController"); externalSelectionController && externalSelectionController.sendExternalChangeSelection(); }; CellEditor.prototype.insertFormula = function (functionName, isDefName, sRange) { this.skipTLUpdate = false; // ToDo check selection formula in wizard for delete if (this.selectionBegin !== this.selectionEnd) { this._removeChars(undefined, undefined, true); } var addText = ''; var text = AscCommonExcel.getFragmentsText(this.options.fragments); if (!this.isFormula() && 0 === this.cursorPos) { addText = '='; } else if (functionName && !this.checkSymbolBeforeRange(text[this.cursorPos - 1])) { addText = '+'; } if (functionName) { addText += functionName; if (!isDefName) { addText += sRange ? '(' + sRange + ')' : '()'; } } if (addText) { this._addChars(addText); if (functionName && !isDefName) { this._moveCursor(kPosition, this.cursorPos - 1); // ToDo move this code to moveCursor this.lastRangePos = this._parseResult && this._parseResult.argPosArr && this._parseResult.argPosArr.length ? this._parseResult.argPosArr[0].start : this.cursorPos; this.lastRangeLength = this._parseResult && this._parseResult.argPosArr && this._parseResult.argPosArr.length ? this._parseResult.argPosArr[this._parseResult.argPosArr.length - 1].end - this._parseResult.argPosArr[0].start : 0; } } this.skipTLUpdate = true; }; CellEditor.prototype.updateWizardMode = function (mode) { this._updateCursorStyle(mode ? AscCommon.Cursors.CellCur : this.defaults.cursorShape); }; CellEditor.prototype.move = function () { if (!this.isOpened) { return; } if (this.handlers.trigger('isActive') && this.options.checkVisible()) { this.textFlags.wrapOnlyCE = false; this.sides = this.options.getSides(); this.left = this.sides.cellX; this.top = this.sides.cellY; this.right = this.sides.r[this.sides.ri]; this.bottom = this.sides.b[this.sides.bi]; this._expand(); this._adjustCanvas(); this._showCanvas(); this._calculateCanvasSize(); this._renderText(); this.topLineIndex = 0; this._updateCursorPosition(); this._updateCursor(); this._drawSelection(); } else { // hide this._hideCanvas(); } }; CellEditor.prototype.setFocus = function (hasFocus) { this.hasFocus = !!hasFocus; this.handlers.trigger("gotFocus", this.hasFocus); }; CellEditor.prototype.restoreFocus = function () { if (this.isTopLineActive) { this.input.focus(); } }; CellEditor.prototype.copySelection = function () { var t = this; var res = null; if (t.selectionBegin !== t.selectionEnd) { var start = t.selectionBegin; var end = t.selectionEnd; if (start > end) { var temp = start; start = end; end = temp; } res = t._getFragments(start, end - start); } return res; }; CellEditor.prototype.cutSelection = function () { var t = this; var f = null; if (t.selectionBegin !== t.selectionEnd) { var start = t.selectionBegin; var end = t.selectionEnd; if (start > end) { var temp = start; start = end; end = temp; } f = t._getFragments(start, end - start); t._removeChars(); } return f; }; CellEditor.prototype.pasteText = function (text) { text = text.replace(/\t/g, " "); text = text.replace(/\r/g, ""); text = text.replace(/^\n+|\n+$/g, ""); if (0 === text.length) { return; } this._addChars(text); }; CellEditor.prototype.paste = function (fragments, cursorPos) { if (!(fragments.length > 0)) { return; } this.startAction(); var noUpdateMode = this.noUpdateMode; this.noUpdateMode = true; if (this.selectionBegin !== this.selectionEnd) { this._removeChars(); } // limit count characters var length = AscCommonExcel.getFragmentsLength(fragments); var excess = this._checkMaxCellLength(length); if (excess) { length -= excess; if (0 === length) { this.noUpdateMode = noUpdateMode; return false; } this._extractFragments(0, length, fragments); } this._cleanFragments(fragments); // save info to undo/redo this.undoList.push({fn: this._removeChars, args: [this.cursorPos, length]}); this.redoList = []; this.noUpdateMode = noUpdateMode; this._addFragments(fragments, this.cursorPos); // Made only for inserting a formula into a cell (when the editor is not open) if (undefined !== cursorPos) { this._moveCursor(kPosition, cursorPos); } this.endAction(); }; /** @param flag {Boolean} */ CellEditor.prototype.enableKeyEventsHandler = function (flag) { var oldValue = this.enableKeyEvents; this.enableKeyEvents = !!flag; if (this.isOpened && oldValue !== this.enableKeyEvents) { this._updateCursor(); } }; CellEditor.prototype._isFormula = function () { let fragments = this.options.fragments; if (fragments && fragments.length > 0 && fragments[0].getCharCodesLength() > 0) { let firstSymbolCode = fragments[0].getCharCode(0); let isEqualSign = firstSymbolCode === codeEqually; let unarSign = isEqualSign ? false : (firstSymbolCode === codeUnarPlus || firstSymbolCode === codeUnarMinus); return isEqualSign || unarSign; } return false; }; CellEditor.prototype.isFormula = function () { return c_oAscCellEditorState.editFormula === this.m_nEditorState; }; CellEditor.prototype._updateTextAlign = function () { this.textFlags.textAlign = (this.options.flags.textAlign === AscCommon.align_Justify || this.isFormula()) ? AscCommon.align_Left : this.options.flags.textAlign; }; CellEditor.prototype.replaceText = function (pos, len, newText) { this._moveCursor(kPosition, pos); this._selectChars(kPosition, pos + len); return this._addChars(newText); }; CellEditor.prototype.setFontRenderingMode = function () { if (this.isOpened) { this._draw(); } }; CellEditor.prototype.cleanSelectRange = function () { this._cleanLastRangeInfo(); this.handlers.trigger("cleanSelectRange"); this.handlers.trigger("onSelectionEnd"); }; // Private CellEditor.prototype._setOptions = function (options) { var opt = this.options = options; var ctx = this.drawingCtx; var u = ctx.getUnits(); this.textFlags = opt.flags.clone(); this._updateTextAlign(); this.textFlags.shrinkToFit = false; this._cleanFragments(opt.fragments); this.textRender.setString(opt.fragments, this.textFlags); this.newTextFormat = null; if (opt.zoom > 0) { this.overlayCtx.setFont(this.drawingCtx.getFont()); this.changeZoom(opt.zoom); } this.kx = asc_getcvt(u, 0/*px*/, ctx.getPPIX()); this.ky = asc_getcvt(u, 0/*px*/, ctx.getPPIY()); this.sides = opt.getSides(); this.left = this.sides.cellX; this.top = this.sides.cellY; this.right = this.sides.r[this.sides.ri]; this.bottom = this.sides.b[this.sides.bi]; this.cursorPos = 0; this.topLineIndex = 0; this.selectionBegin = -1; this.selectionEnd = -1; this.isSelectMode = c_oAscCellEditorSelectState.no; this.hasCursor = false; this.undoList = []; this.redoList = []; this.undoMode = false; this._setSkipKeyPress(false); this.updateWizardMode(false); }; CellEditor.prototype._parseRangeStr = function (s) { var range = AscCommonExcel.g_oRangeCache.getAscRange(s); return range ? range.clone() : null; }; CellEditor.prototype._parseFormulaRanges = function () { //I get a string without double-byte characters var s = this.options.fragments.reduce(function (pv, cv) { return pv + AscCommonExcel.convertUnicodeToSimpleString(cv.getCharCodes()); }, ""); var ws = this.handlers.trigger("getActiveWS"); var bbox = this.options.bbox; this._parseResult = new AscCommonExcel.ParseResult([], []); this._parseResult.cursorPos = this.needFindFirstFunction ? undefined : this.cursorPos - 1; var cellWithFormula = new window['AscCommonExcel'].CCellWithFormula(ws, bbox.r1, bbox.c1); this._formula = new AscCommonExcel.parserFormula(s.substr(1), cellWithFormula, ws); this._formula.parse(true, true, this._parseResult, true); if (this.needFindFirstFunction) { this.argPosArr = this._parseResult.argPosArr; this.needFindFirstFunction = null; } var r, oper, wsName = null, bboxOper, range, isName = false; var oSelectionRange = new AscCommonExcel.SelectionRange(ws); // ToDo change create SelectionRange oSelectionRange.ranges = []; if (this._parseResult.refPos && this._parseResult.refPos.length > 0) { for (var index = 0; index < this._parseResult.refPos.length; index++) { wsName = null; isName = false; bboxOper = null; r = this._parseResult.refPos[index]; oper = r.oper; if ((cElementType.table === oper.type || cElementType.name === oper.type || cElementType.name3D === oper.type) && oper.externalLink == null) { oper = r.oper.toRef(bbox); if (oper instanceof AscCommonExcel.cError) { continue; } isName = true; } if ((cElementType.cell === oper.type || cElementType.cellsRange === oper.type || cElementType.cell3D === oper.type) && oper.externalLink == null) { wsName = oper.getWS().getName(); bboxOper = oper.getBBox0(); } else if ((cElementType.cellsRange3D === oper.type) && oper.externalLink == null) { if (oper.isSingleSheet()) { wsName = oper.getWS().getName(); bboxOper = oper.getBBox0NoCheck(); } else if (oper.isBetweenSheet(ws)) { wsName = ws.getName(); bboxOper = oper.getBBox0NoCheck(); } } if (bboxOper) { if (wsName && ws && ws.getName() !== wsName) { continue; } oSelectionRange.addRange(); range = oSelectionRange.getLast(); if (bboxOper.isOneCell()) { var isMerged = ws.getMergedByCell(bboxOper.r1, bboxOper.c1); if (isMerged) { bboxOper.r2 = isMerged.r2; bboxOper.c2 = isMerged.c2; } } range.assign2(bboxOper); range.cursorePos = range.colorRangePos = r.start + 1; range.formulaRangeLength = r.end - r.start; range.isName = isName; } } } this.handlers.trigger("newRanges", 0 !== oSelectionRange.ranges.length ? oSelectionRange : null); }; CellEditor.prototype._findRangeUnderCursor = function () { // Get character string let s = this.textRender.getChars(0, this.textRender.getCharsCount()); s = AscCommonExcel.convertUnicodeToSimpleString(s); let arrFR = this.handlers.trigger("getFormulaRanges"); // Check cached formula ranges first if (arrFR) { let ranges = arrFR.ranges; // Check if cursor is over any existing ranges before re-parsing formula // Needed for cases like sumnas2:K2 where sumnas2 is invalid reference for (let i = 0, l = ranges.length; i < l; ++i) { let a = ranges[i]; if (this.cursorPos >= a.cursorePos && this.cursorPos <= a.cursorePos + a.formulaRangeLength) { let range = a.clone(true); range.isName = a.isName; range.formulaRangeLength = a.formulaRangeLength; range.cursorePos = a.cursorePos; return {range: range}; } } } // No ranges found under cursor, parse formula let r, offset, _e, _s, wsName = null, ret = false, refStr, isName = false; let _sColorPos, localStrObj; let ws = this.handlers.trigger("getActiveWS"); let bbox = this.options.bbox; this._parseResult = new AscCommonExcel.ParseResult([], []); let cellWithFormula = new window['AscCommonExcel'].CCellWithFormula(ws, bbox.r1, bbox.c1); this._formula = new AscCommonExcel.parserFormula(s.substr(1), cellWithFormula, ws); this._formula.parse(true, true, this._parseResult, bbox); let range; if (this._parseResult.refPos && this._parseResult.refPos.length > 0) { for (let index = 0; index < this._parseResult.refPos.length; index++) { wsName = null; r = this._parseResult.refPos[index]; offset = r.end; _e = r.end; _sColorPos = _s = r.start; switch (r.oper.type) { case cElementType.cell: { wsName = ws.getName(); refStr = r.oper.toLocaleString(); ret = true; break; } case cElementType.cell3D: { localStrObj = r.oper.toLocaleStringObj(); refStr = localStrObj[1]; ret = true; wsName = r.oper.getWS().getName(); _s = _e - localStrObj[1].length + 1; _sColorPos = _e - localStrObj[0].length; break; } case cElementType.cellsRange: { wsName = ws.getName(); refStr = r.oper.toLocaleString(); ret = true; break; } case cElementType.cellsRange3D: { if (!r.oper.isSingleSheet()) { continue; } ret = true; localStrObj = r.oper.toLocaleStringObj(); refStr = localStrObj[1]; wsName = r.oper.getWS().getName(); _s = _e - localStrObj[1].length + 1; break; } case cElementType.table: case cElementType.name: case cElementType.name3D: { let nameRef = r.oper.toRef(bbox); if (nameRef instanceof AscCommonExcel.cError) { continue; } switch (nameRef.type) { case cElementType.cellsRange3D: { if (!nameRef.isSingleSheet()) { continue; } } case cElementType.cellsRange: case cElementType.cell3D: { ret = true; localStrObj = nameRef.toLocaleStringObj(); refStr = localStrObj[1]; wsName = nameRef.getWS().getName(); _s = _e - localStrObj[1].length; break; } } isName = true; break; } default: continue; } if (ret && this.cursorPos > _s && this.cursorPos <= _s + refStr.length) { range = this._parseRangeStr(refStr); if (range) { range.isName = isName; range.formulaRangeLength = refStr.length; range.cursorePos = _s; return {range: range, wsName: wsName}; } } } } range ? range.isName = isName : null; range ? range.formulaRangeLength = r.oper.value.length : null; range ? range.cursorePos = _s : null; return !range ? {range: null} : {range: range, wsName: wsName}; }; CellEditor.prototype._updateTopLineActive = function (state, isOpening) { if (state !== this.isTopLineActive) { this.isTopLineActive = state; this.openFromTopLine = isOpening && state; this.handlers.trigger("updateTopLine", this.isTopLineActive ? c_oAscCellEditorState.editInFormulaBar : c_oAscCellEditorState.editInCell); } }; CellEditor.prototype._updateEditorState = function () { if (this.getMenuEditorMode()) { return; } var isFormula = this._isFormula(); var editorState = isFormula ? c_oAscCellEditorState.editFormula : "" === AscCommonExcel.getFragmentsText(this.options.fragments) ? c_oAscCellEditorState.editEmptyCell : c_oAscCellEditorState.editText; this._setEditorState(editorState); this.handlers.trigger("updateFormulaEditMod", isFormula); if (isFormula) { this._parseFormulaRanges(); } }; CellEditor.prototype._cleanLastRangeInfo = function () { this.lastRangeLength = null; this.lastRangePos = null; }; // Update Undo/Redo state CellEditor.prototype._updateUndoRedoChanged = function () { this.handlers.trigger("updateUndoRedoChanged", 0 < this.undoList.length, 0 < this.redoList.length); }; CellEditor.prototype._haveTextInEdit = function () { var fragments = this.options.fragments; return fragments.length > 0 && fragments[0].getCharCodesLength() > 0; }; CellEditor.prototype._setEditorState = function (editorState) { if (this.m_nEditorState !== editorState) { this.m_nEditorState = editorState; this.handlers.trigger("updateEditorState", this.m_nEditorState); } }; CellEditor.prototype._getRenderFragments = function () { var opt = this.options, fragments = opt.fragments, i, k, l, first, last, val, lengthColors, tmpColors, colorIndex, uniqueColorIndex; if (this.isFormula()) { var ranges = this.handlers.trigger("getFormulaRanges"); if (ranges) { fragments = []; for (i = 0; i < opt.fragments.length; ++i) { fragments.push(opt.fragments[i].clone()); } lengthColors = AscCommonExcel.c_oAscFormulaRangeBorderColor.length; tmpColors = []; uniqueColorIndex = 0; ranges = ranges.ranges; for (i = 0, l = ranges.length; i < l; ++i) { val = ranges[i]; colorIndex = asc.getUniqueRangeColor(ranges, i, tmpColors); if (null == colorIndex) { colorIndex = uniqueColorIndex++; } tmpColors.push(colorIndex); this._extractFragments(val.cursorePos, val.formulaRangeLength, fragments); first = this._findFragment(val.cursorePos, fragments); last = this._findFragment(val.cursorePos + val.formulaRangeLength - 1, fragments); if (first && last) { for (k = first.index; k <= last.index; ++k) { fragments[k].format.setColor(AscCommonExcel.c_oAscFormulaRangeBorderColor[colorIndex % lengthColors]); } } } } } return fragments; }; // Rendering CellEditor.prototype._draw = function () { if (!this.options || !this.options.fragments) { return; } this._expand(); this._cleanText(); let externalSelectionController = this.handlers.trigger("getExternalSelectionController"); if (!externalSelectionController || !externalSelectionController.getExternalFormulaEditMode()) { this._cleanSelection(); this._adjustCanvas(); this._showCanvas(); this._calculateCanvasSize(); this._renderText(); } if (!this.getMenuEditorMode()) { for (var i = 0; i < this.options.fragments.length; i++) { this.options.fragments[i].initText(); } this.input.value = AscCommonExcel.getFragmentsText((this.options.fragments)); } this._updateCursorPosition(); this._updateCursor(); }; CellEditor.prototype._update = function () { this._updateEditorState(); let isExpand = this._expand(); if (isExpand) { this._adjustCanvas(); this._calculateCanvasSize(); } // the call is needed to update the text of the top line, before updating the cursor position this.textRender.initStartX(0, this.textRender.lines[0], this._getContentLeft(), this._getContentWidth(), true); if (!this.getMenuEditorMode()) { this._fireUpdated(); } this._updateCursorPosition(true, isExpand, null, true); this._updateCursor(); this._updateUndoRedoChanged(); if (window['IS_NATIVE_EDITOR']) { window['native']['onCellEditorChangeText'](AscCommonExcel.getFragmentsText(this.options.fragments)); } }; CellEditor.prototype._fireUpdated = function () { //TODO I save the text! var s = AscCommonExcel.getFragmentsText(this.options.fragments); var isFormula = -1 === this.beginCompositePos && (s.charAt(0) === "=" || s.charAt(0) === "+" || s.charAt(0) === "-"); var api = window["Asc"]["editor"]; var fPos, fName, match, fCurrent; if (!this.isTopLineActive || !this.skipTLUpdate || this.undoMode) { this.input.value = s; } //get a string without double-byte characters and pass it to the regular expression //positions of all functions must match //the question remains with arguments that can contain double-byte characters s = this.options.fragments ? this.options.fragments.reduce(function (pv, cv) { return pv + AscCommonExcel.convertUnicodeToSimpleString(cv.getCharCodes()); }, "") : ""; if (isFormula) { let obj = this._getFunctionByString(this.cursorPos, s); fPos = obj.fPos; fName = obj.fName; fCurrent = this._getEditableFunction(this._parseResult).func; } else { this._parseResult = null; } this.handlers.trigger("updated", s, this.cursorPos, fPos, fName); let functionInfo = null; if (this._parseResult && this._parseResult.argPos && fCurrent) { functionInfo = new AscCommonExcel.CFunctionInfo(AscCommonExcel.cFormulaFunctionToLocale ? AscCommonExcel.cFormulaFunctionToLocale[fCurrent] : fCurrent); functionInfo.activeArgPos = this._parseResult.argPos; functionInfo.activeArgsCount = this._parseResult.argPosArr && this._parseResult.argPosArr.length; } this.handlers.trigger("updatedEditableFunction", fCurrent, fPos !== undefined ? this.calculateOffset(fPos) : null, functionInfo); if (api && api.isMobileVersion) { this.restoreFocus(); } }; CellEditor.prototype._getFunctionByString = function (cursorPos, s) { let isInString = false; let isEscaped = false; if ('"' === s[cursorPos - 1]) { return {fPos: undefined, fName: undefined}; } for (let i = 0; i < cursorPos; i++) { if (s[i] === '"') { if (!isEscaped) { isInString = !isInString; } } } if (isInString) { return {fPos: undefined, fName: undefined}; } let fPos = asc_lastidx(s, this.reNotFormula, cursorPos) + 1; let match; if (fPos > 0) { match = s.slice(fPos, cursorPos).match(this.reFormula); } let fName; if (match) { fName = match[1]; } else { fPos = undefined; fName = undefined; } return {fPos: fPos, fName: fName}; }; CellEditor.prototype._getEditableFunction = function (parseResult, bEndCurPos) { //TODO I save the text! var findOpenFunc = [], editableFunction = null, level = -1; if (!parseResult) { //in this case, I start parsing the formula up to the current position //I get a string without double-byte characters var s = this.options.fragments.reduce(function (pv, cv) { return pv + AscCommonExcel.convertUnicodeToSimpleString(cv.getCharCodes()); }, ""); var isFormula = -1 === this.beginCompositePos && s.charAt(0) === "="; if (isFormula) { var pos = this.cursorPos; var ws = this.handlers.trigger("getActiveWS"); var bbox = this.options.bbox; var endPos = pos; if (!bEndCurPos) { for (var n = pos; n < s.length; n++) { if ("(" === s[n]) { endPos = n; } } } var formulaStr = s.substring(1, endPos); parseResult = new AscCommonExcel.ParseResult([], []); var cellWithFormula = new window['AscCommonExcel'].CCellWithFormula(ws, bbox.r1, bbox.c1); var tempFormula = new AscCommonExcel.parserFormula(formulaStr, cellWithFormula, ws); tempFormula.parse(true, true, parseResult, true); } } var elements = parseResult ? parseResult.elems : null; if (elements) { for (var i = 0; i < elements.length; i++) { if (cElementType.func === elements[i].type && elements[i + 1] && "(" === elements[i + 1].name) { level++; findOpenFunc[level] = {elem: elements[i], counter: 1}; i++; } else if (-1 !== level) { if ("(" === elements[i].name) { findOpenFunc[level].counter++; } else if (")" === elements[i].name) { findOpenFunc[level].counter--; } } if (level > -1 && findOpenFunc[level].counter === 0) { findOpenFunc.splice(level, 1); level--; } } } if (findOpenFunc) { for (var j = findOpenFunc.length - 1; j >= 0; j--) { if (findOpenFunc[j].counter > 0 && !(findOpenFunc[j].elem instanceof window['AscCommonExcel'].cUnknownFunction)) { editableFunction = findOpenFunc[j].elem.name; break; } } } return {func: editableFunction, argPos: parseResult ? parseResult.argPos : null}; }; CellEditor.prototype._expand = function () { var bottom, tm; var doAdjust = false, fragments = this._getRenderFragments(); if (fragments && 0 < fragments.length) { bottom = this.bottom; this.bottom = this.sides.b[this.sides.bi]; this._updateTextAlign(); tm = this.textRender.measureString(fragments, this.textFlags, this._getContentWidth()); if (!this.textFlags.wrapText && !this.textFlags.wrapOnlyCE) { while (tm.width > this._getContentWidth()) { if (!this._expandWidth()) { this.textFlags.wrapOnlyCE = true; tm = this.textRender.measureString(fragments, this.textFlags, this._getContentWidth()); break; } doAdjust = true; } } while (tm.height > this._getContentHeight() && this._expandHeight()) { } if (bottom !== this.bottom) { if (bottom > this.bottom) { // Clear index when reduce size this.topLineIndex = 0; } doAdjust = true; // ToDo move this to _adjustCanvas if (this.getMenuEditorMode) { this.handlers.trigger("resizeEditorHeight"); } } } return doAdjust; }; CellEditor.prototype._expandWidth = function () { var i, l = -1, r = -1; if (AscCommon.align_Left === this.textFlags.textAlign || AscCommon.align_Center === this.textFlags.textAlign) { var rightSide = this.sides.r; for (i = 0; i < rightSide.length; ++i) { if (rightSide[i] > this.right) { r = rightSide[i]; break; } } } if (AscCommon.align_Right === this.textFlags.textAlign || AscCommon.align_Center === this.textFlags.textAlign) { var leftSide = this.sides.l; for (i = 0; i < leftSide.length; ++i) { if (leftSide[i] < this.left) { l = leftSide[i]; break; } } } if (AscCommon.align_Center === this.textFlags.textAlign) { if (-1 !== l && -1 !== r) { var min = Math.min(this.left - l, r - this.right); this.left -= min; this.right += min; return true; } } else { if (-1 !== l) { this.left = l; return true; } else if (-1 !== r) { this.right = r; return true; } } return false; }; CellEditor.prototype._expandHeight = function () { var t = this, bottomSide = this.sides.b, i = asc_search(bottomSide, function (v) { return v > t.bottom; }); if (i >= 0) { t.bottom = bottomSide[i]; return true; } var val = bottomSide[bottomSide.length - 1]; if (Math.abs(t.bottom - val) > 0.000001) { // bottom !== bottomSide[len-1] t.bottom = val; } return false; }; CellEditor.prototype._cleanText = function () { this.drawingCtx.clear(); }; CellEditor.prototype._showCanvas = function () { this.canvasOuterStyle.display = 'block'; }; CellEditor.prototype._hideCanvas = function () { this.canvasOuterStyle.display = 'none'; }; CellEditor.prototype._adjustCanvas = function () { var z = this.defaults.canvasZIndex; var borderSize = AscBrowser.retinaPixelRatio === 1.5 ? 1 : AscCommon.AscBrowser.convertToRetinaValue(1, true); var left = this.left * this.kx; var top = this.top * this.ky; var width, height, widthStyle, heightStyle; width = widthStyle = (this.right - this.left) * this.kx - borderSize; height = heightStyle = (this.bottom - this.top) * this.ky - borderSize; left = AscCommon.AscBrowser.convertToRetinaValue(left); top = AscCommon.AscBrowser.convertToRetinaValue(top); widthStyle = AscCommon.AscBrowser.convertToRetinaValue(widthStyle); heightStyle = AscCommon.AscBrowser.convertToRetinaValue(heightStyle); // in safari with hardware acceleration enabled, there is a bug when entering text. // apparently they cache textures in a special way that are (w*h<5000) in size // the formula is accurate. not a pixel less. more - you can have as much as you like. // you need to check every safari update - and when they fix it - remove this stub // canvases are transparent and their increased size does not affect the result. // // in the new version of safari, we increase not only the canvases, but also the div. if (AscCommon.AscBrowser.isSafariMacOs) { if ((widthStyle * heightStyle) < 5000) { this._originalCanvasWidth = width; widthStyle = ((5000 / heightStyle) >> 0) + 1; } else { this._originalCanvasWidth = null; } } // Calculate canvas offset inside container let ws = this.handlers.trigger("getActiveWSView"); let canvasTop = 0; let cellsTop = ws && AscCommon.AscBrowser.convertToRetinaValue(ws.cellsTop); if (ws && top < cellsTop) { // If editor position is above data area canvasTop = top < 0 ? -(cellsTop + Math.abs(top)) : top - cellsTop; // Fix container at headers level top = cellsTop; } this.canvasOuterStyle.left = left + 'px'; this.canvasOuterStyle.top = top + 'px'; this.canvasOuterStyle.width = widthStyle + 'px'; this.canvasOuterStyle.height = heightStyle + 'px'; if (!this.getMenuEditorMode()) { this.canvasOuterStyle.zIndex = /*this.top < 0 ? -1 :*/ z; } this.canvas.style.width = this.canvasOverlay.style.width = widthStyle + 'px'; this.canvas.style.height = this.canvasOverlay.style.height = heightStyle + 'px'; this.canvas.style.top = this.canvasOverlay.style.top = canvasTop + 'px'; }; CellEditor.prototype._calculateCanvasSize = function () { //this code is called after showCanvas because inside calculateCanvasSize getBoundingClientRect is used //if canvas has display = 'none' then the sizes will be returned as zero if (this.canvas) { AscCommon.calculateCanvasSize(this.canvas); } if (this.canvasOverlay) { AscCommon.calculateCanvasSize(this.canvasOverlay); } }; CellEditor.prototype._renderText = function (dy, forceRender) { if (window.LOCK_DRAW && !forceRender) { this.textRender.initStartX(0, null, this._getContentLeft(), this._getContentWidth(), true); window.TEXT_DRAW_INSTANCE = this; window.TEXT_DRAW_INSTANCE_POS = dy; return; } if (forceRender) { window.TEXT_DRAW_INSTANCE = undefined; } var t = this, opt = t.options, ctx = t.drawingCtx; if (!window['IS_NATIVE_EDITOR']) { let _width = this._originalCanvasWidth ? this._originalCanvasWidth : ctx.getWidth(); if (opt.background) { ctx.setFillStyle(opt.background); } ctx.fillRect(0, 0, _width, ctx.getHeight()); } if (opt.fragments && opt.fragments.length > 0) { t.textRender.render(undefined, t._getContentLeft(), dy || 0, t._getContentWidth(), opt.font.getColor()); } }; CellEditor.prototype._cleanSelection = function () { this.overlayCtx.clear(); }; CellEditor.prototype._drawSelection = function () { var ctx = this.overlayCtx; var zoom = this.getZoom(); var begPos, endPos, top, topLine, begInfo, endInfo, line, i, y, h, selection = []; function drawRect(x, y, w, h) { if (window['IS_NATIVE_EDITOR']) { selection.push([x, y, w, h]); } else { ctx.fillRect(x, y, w, h); } } begPos = this.selectionBegin; endPos = this.selectionEnd; if (!window['IS_NATIVE_EDITOR']) { ctx.setFillStyle(this.defaults.selectColor).clear(); } if (begPos !== endPos && !this.isTopLineActive) { top = this.textRender.calcLineOffset(this.topLineIndex); begInfo = this.textRender.calcCharOffset(Math.min(begPos, endPos)); line = this.textRender.getLineInfo(begInfo.lineIndex); topLine = this.textRender.calcLineOffset(begInfo.lineIndex); endInfo = this.textRender.calcCharOffset(Math.max(begPos, endPos)); h = asc_round(line.th * zoom); y = topLine - top; if (begInfo.lineIndex === endInfo.lineIndex) { drawRect(begInfo.left, y, endInfo.left - begInfo.left, h); } else { drawRect(begInfo.left, y, line.tw - begInfo.left + line.startX, h); for (i = begInfo.lineIndex + 1, y += h; i < endInfo.lineIndex; ++i, y += h) { line = this.textRender.getLineInfo(i); h = asc_round(line.th * zoom); drawRect(line.startX, y, line.tw, h); } line = this.textRender.getLineInfo(endInfo.lineIndex); topLine = this.textRender.calcLineOffset(endInfo.lineIndex); if (line) { drawRect(line.startX, topLine - top, endInfo.left - line.startX, asc_round(line.th * zoom)); } } } if (!this.isSelectMode) { this.handlers.trigger("onSelectionEnd"); } let externalSelectionController = this.handlers.trigger("getExternalSelectionController"); externalSelectionController && externalSelectionController.sendExternalChangeSelection(); return selection; }; CellEditor.prototype.calculateOffset = function (pos) { var left = 0; var top = 0; if (pos != null && this.textRender) { var _top = this.textRender.calcLineOffset(this.topLineIndex); var _begInfo = this.textRender.calcCharOffset(pos); var _topLine = _begInfo ? this.textRender.calcLineOffset(_begInfo.lineIndex) : null; left = _begInfo && _begInfo.left ? AscCommon.AscBrowser.convertToRetinaValue(_begInfo.left) : 0; top = _topLine != null && _top != null ? AscCommon.AscBrowser.convertToRetinaValue(_topLine - _top) : 0; } return [left, top]; }; // Cursor CellEditor.prototype._updateCursorStyle = function (cursor) { var newHtmlCursor = AscCommon.g_oHtmlCursor.value(cursor); if (this.canvasOverlay.style.cursor !== newHtmlCursor) { this.canvasOverlay.style.cursor = newHtmlCursor; } }; CellEditor.prototype._updateCursor = function () { if (window['IS_NATIVE_EDITOR']) { return; } if (!this.isOpened || this.options.enterOptions.hideCursor || this.isTopLineActive || !this.enableKeyEvents || this.handlers.trigger('getWizard')) { this._hideCursor(); } else { this._showCursor(); } }; CellEditor.prototype.showCursor = function () { this.options.enterOptions.hideCursor = false; this._updateCursor(); }; CellEditor.prototype._showCursor = function () { var t = this; window.clearInterval(t.cursorTID); t.cursorStyle.display = "block"; t.cursorTID = window.setInterval(function () { t.cursorStyle.display = ("none" === t.cursorStyle.display) ? "block" : "none"; }, t.defaults.blinkInterval); }; CellEditor.prototype._hideCursor = function () { window.clearInterval(this.cursorTID); this.cursorStyle.display = "none"; }; CellEditor.prototype._updateCursorPosition = function (redrawText, isExpand, lineIndex, opt_not_formulas_update) { // ToDo should forward this function let h = this.canvas.height; let y = -this.textRender.calcLineOffset(this.topLineIndex); let cur = this.textRender.calcCharOffset(this.cursorPos, lineIndex); let charsCount = this.textRender.getCharsCount(); let textAlign = this.textFlags && this.textFlags.textAlign; let curLeft = asc_round( ((AscCommon.align_Right !== textAlign || this.cursorPos !== charsCount) && cur !== null && cur.left !== null ? cur.left : this._getContentPosition()) * this.kx); let curTop = asc_round(((cur !== null ? cur.top : 0) + y) * this.ky); let curHeight = asc_round((cur !== null ? cur.height : this._getContentHeight()) * this.ky); let i, dy, nCount = this.textRender.getLinesCount(); let zoom = this.getZoom(); while (1 < nCount) { if (curTop + curHeight - 1 > h) { i = i === undefined ? 0 : i + 1; if (i === nCount) { break; } dy = asc_round(this.textRender.getLineInfo(i).th * zoom); y -= dy; curTop -= asc_round(dy * this.ky); ++this.topLineIndex; continue; } if (curTop < 0) { --this.topLineIndex; if (this.textRender.lines && this.textRender.lines.length && this.topLineIndex >= this.textRender.lines.length) { this.topLineIndex = this.textRender.lines.length - 1; } dy = asc_round(this.textRender.getLineInfo(this.topLineIndex).th * zoom); y += dy; curTop += asc_round(dy * this.ky); continue; } break; } if (dy !== undefined || redrawText) { this._renderText(y, isExpand); } curLeft = AscCommon.AscBrowser.convertToRetinaValue(curLeft); curTop = AscCommon.AscBrowser.convertToRetinaValue(curTop); curHeight = AscCommon.AscBrowser.convertToRetinaValue(curHeight); this.curLeft = curLeft; this.curTop = curTop; this.curHeight = curHeight; if (!window['IS_NATIVE_EDITOR']) { // update cursor position let scrollDiff = parseFloat(this.canvas.style.top); this.cursorStyle.left = curLeft + "px"; this.cursorStyle.top = curTop + scrollDiff + "px"; this.cursorStyle.width = (((2 * AscCommon.AscBrowser.retinaPixelRatio) >> 0) / AscCommon.AscBrowser.retinaPixelRatio) + "px"; this.cursorStyle.height = curHeight + "px"; } if (AscCommon.g_inputContext) { AscCommon.g_inputContext.moveAccurate(this.left * this.kx + curLeft, this.top * this.ky + curTop); } if (cur) { this.input.scrollTop = this.input.clientHeight * cur.lineIndex; } if (this.isTopLineActive && !this.skipTLUpdate) { this._updateTopLineCurPos(); } var s = AscCommonExcel.getFragmentsText(this.options.fragments); var isFormula = -1 === this.beginCompositePos && (s.charAt(0) === "=" || s.charAt(0) === "+" || s.charAt(0) === "-"); var fPos, fName, fCurrent, argPos = null; if (!opt_not_formulas_update && isFormula && this._parseResult && this._parseResult.allFunctionsPos && this.cursorPos) { let activeFunction = this._parseResult.getActiveFunction(this.cursorPos, this.cursorPos, true); let argPos = activeFunction && activeFunction.argPos; fCurrent = activeFunction && activeFunction.func ? activeFunction.func.name : null; fPos = activeFunction && activeFunction.start; let functionInfo = null; if (fCurrent) { functionInfo = new AscCommonExcel.CFunctionInfo(AscCommonExcel.cFormulaFunctionToLocale ? AscCommonExcel.cFormulaFunctionToLocale[fCurrent] : fCurrent); functionInfo.activeArgPos = argPos != null ? argPos + 1 : null; functionInfo.activeArgsCount = activeFunction && activeFunction.args ? activeFunction.args.length : 0; } this.handlers.trigger("updatedEditableFunction", fCurrent, fPos !== undefined ? this.calculateOffset(fPos) : null, functionInfo); } if (this.getMenuEditorMode()) { this.handlers.trigger("updateMenuEditorCursorPosition", curTop, curHeight); } //let fCurrent = this._getEditableFunction(null, true); //console.log("func: " + fCurrent.func + " arg: " + fCurrent.argPos); this._updateSelectionInfo(); }; CellEditor.prototype._moveCursor = function (kind, pos, lineIndex) { this.newTextFormat = null; var t = this; this.sAutoComplete = null; switch (kind) { case kPrevChar: t.cursorPos = t.textRender.getPrevChar(t.cursorPos); break; case kNextChar: t.cursorPos = t.textRender.getNextChar(t.cursorPos); break; case kPrevWord: t.cursorPos = t.textRender.getPrevWord(t.cursorPos); break; case kNextWord: t.cursorPos = t.textRender.getNextWord(t.cursorPos); break; case kBeginOfLine: t.cursorPos = t.textRender.getBeginOfLine(t.cursorPos); break; case kEndOfLine: t.cursorPos = t.textRender.getEndOfLine(t.cursorPos); break; case kBeginOfText: t.cursorPos = t.textRender.getBeginOfText(t.cursorPos); break; case kEndOfText: t.cursorPos = t.textRender.getEndOfText(t.cursorPos); break; case kPrevLine: t.cursorPos = t.textRender.getPrevLine(t.cursorPos); break; case kNextLine: t.cursorPos = t.textRender.getNextLine(t.cursorPos); break; case kPosition: t.cursorPos = pos; break; case kPositionLength: t.cursorPos += pos; break; default: return; } if (t.selectionBegin !== t.selectionEnd) { t.selectionBegin = t.selectionEnd = -1; t._cleanSelection(); } t._updateCursorPosition(null, null, lineIndex); t._updateCursor(); }; CellEditor.prototype._findCursorPosition = function (coord) { return this.textRender.getCharPosByXY(coord.x, coord.y, this.topLineIndex, this.getZoom()); }; CellEditor.prototype._findLineIndex = function (coord) { return this.textRender.getLineByY(coord.y, this.topLineIndex, this.getZoom()); }; CellEditor.prototype._updateTopLineCurPos = function () { if (this.loadFonts) { return; } var isSelected = this.selectionBegin !== this.selectionEnd; var b = isSelected ? this.selectionBegin : this.cursorPos; var e = isSelected ? this.selectionEnd : this.cursorPos; if (this.input.setSelectionRange) { this.input.setSelectionRange(Math.min(b, e), Math.max(b, e)); } }; CellEditor.prototype._topLineGotFocus = function () { this._updateTopLineActive(true); this.input.isFocused = true; this.setFocus(true); this._updateCursor(); this._cleanSelection(); }; CellEditor.prototype._topLineMouseUp = function () { this.callTopLineMouseup = false; // with this combination ctrl+a, click, ctrl+a, click selectionStart is not updated // therefore we perform processing after the system handler this._delayedUpdateCursorByTopLine(); }; CellEditor.prototype._delayedUpdateCursorByTopLine = function () { var t = this; setTimeout(function () { t._updateCursorByTopLine(); }); }; CellEditor.prototype._updateCursorByTopLine = function () { var b = this.input.selectionStart; var e = this.input.selectionEnd; // ToDo replace code to input.selectionDirection after updating closure-compiler to version 20200719 if ('backward' === this.input["selectionDirection"]) { var tmp = b; b = e; e = tmp; } if (typeof b !== "undefined") { if (this.cursorPos !== b || this.selectionBegin !== this.selectionEnd) { this._moveCursor(kPosition, b); } if (b !== e) { this._selectChars(kPosition, e); } //onSelectionEnd - used in plugins. It is needed to track the change of select. if (!this.isSelectMode) { this.handlers.trigger("onSelectionEnd"); } } }; CellEditor.prototype._syncEditors = function () { var t = this; var s1 = AscCommonExcel.getFragmentsCharCodes(t.options.fragments); var s2 = AscCommon.convertUTF16toUnicode(t.input.value); var l = Math.min(s1.length, s2.length); var i1 = 0, i2; while (i1 < l && s1[i1] === s2[i1]) { ++i1; } i2 = i1 + 1; if (i2 >= l) { i2 = Math.max(s1.length, s2.length); } else { while (i2 < l && s1[i1] !== s2[i2]) { ++i2; } } t._addChars(s2.slice(i1, i2), i1); }; // Content CellEditor.prototype.getText = function () { return AscCommonExcel.getFragmentsText(this.options.fragments); }; CellEditor.prototype._getContentLeft = function () { return this.defaults.padding; }; CellEditor.prototype._getContentWidth = function () { //remove 1 px offset. without cell editor no 1 px offset return this.right - this.left - 2 * this.defaults.padding /*+ 1*//*px*/; }; CellEditor.prototype._getContentHeight = function () { var t = this; return t.bottom - t.top; }; CellEditor.prototype._getContentPosition = function () { if (!this.textFlags) { return this.defaults.padding; } switch (this.textFlags.textAlign) { case AscCommon.align_Right: return this.right - this.left - this.defaults.padding - 1; case AscCommon.align_Center: return 0.5 * (this.right - this.left); } return this.defaults.padding; }; CellEditor.prototype._wrapText = function () { this.textFlags.wrapOnlyNL = true; }; CellEditor.prototype._addCharCodes = function (arrCharCodes) { return this._addChars(arrCharCodes); }; CellEditor.prototype._addChars = function (str, pos, isRange) { if (!isRange) { this.cleanSelectRange(); } this.startAction(); var opt = this.options, f, l, s; var noUpdateMode = this.noUpdateMode; this.noUpdateMode = true; this.sAutoComplete = null; if (!opt.fragments) { return; } if (this.selectionBegin !== this.selectionEnd) { var copyFragment = this._findFragmentToInsertInto(Math.min(this.selectionBegin, this.selectionEnd) + 1); if (copyFragment && !this.newTextFormat) { this.newTextFormat = opt.fragments[copyFragment.index].format.clone(); } this._removeChars(undefined, undefined, isRange); } if (str.trim) { str = AscCommon.convertUTF16toUnicode(str); } var length = str.length; if (0 !== length) { // limit count characters var excess = this._checkMaxCellLength(length); if (excess) { length -= excess; if (0 === length) { this.noUpdateMode = noUpdateMode; return length; } str = str.slice(0, length); } if (pos === undefined) { pos = this.cursorPos; } if (!this.undoMode) { // save info to undo/redo this.undoList.push({fn: this._removeChars, args: [pos, length], isRange: isRange}); this.redoList = []; } if (this.newTextFormat) { var oNewObj = new Fragment({format: this.newTextFormat, charCodes: str}); this._addFragments([oNewObj], pos); this.newTextFormat = null; } else { f = this._findFragmentToInsertInto(pos); if (f) { l = pos - f.begin; s = opt.fragments[f.index].getCharCodes(); opt.fragments[f.index].setCharCodes(s.slice(0, l).concat(str).concat(s.slice(l))); s = opt.fragments[f.index].getCharCodes(); } } this.cursorPos = pos + str.length; if (-1 !== window["Asc"].search(str, function (val) { return val === codeNewLine })) { this._wrapText(); } } this.noUpdateMode = noUpdateMode; if (!this.noUpdateMode) { this._update(); } this.endAction(); return length; }; CellEditor.prototype._addNewLine = function () { this._wrapText(); let sNewLine = "\n"; this._addChars( /*codeNewLine*/sNewLine); }; CellEditor.prototype._removeChars = function (pos, length, isRange) { var t = this, opt = t.options, b, e, l, first, last; if (!isRange) { this.cleanSelectRange(); } this.sAutoComplete = null; if (t.selectionBegin !== t.selectionEnd) { b = Math.min(t.selectionBegin, t.selectionEnd); e = Math.max(t.selectionBegin, t.selectionEnd); t.selectionBegin = t.selectionEnd = -1; t._cleanSelection(); } else if (length === undefined) { switch (pos) { case kPrevChar: b = t.textRender.getPrevChar(t.cursorPos, false); e = t.cursorPos; break; case kNextChar: b = t.cursorPos; e = t.textRender.getNextChar(t.cursorPos); break; case kPrevWord: b = t.textRender.getPrevWord(t.cursorPos); e = t.cursorPos; break; case kNextWord: b = t.cursorPos; e = t.textRender.getNextWord(t.cursorPos); break; default: return; } } else { b = pos; e = pos + length; } if (b === e) { return; } if (!opt.fragments) { return; } this.startAction(); // search for begin and end positions first = t._findFragment(b); last = t._findFragment(e - 1); if (!t.undoMode) { // save info to undo/redo if (e - b < 2 && opt.fragments[first.index].getCharCodesLength() > 1) { t.undoList.push({fn: t._addChars, args: [t.textRender.getChars(b, 1), b], isRange: isRange}); } else { t.undoList.push({fn: t._addFragments, args: [t._getFragments(b, e - b), b], isRange: isRange}); } t.redoList = []; } if (first && last) { // remove chars if (first.index === last.index) { l = opt.fragments[first.index].getCharCodes(); opt.fragments[first.index].setCharCodes(l.slice(0, b - first.begin).concat(l.slice(e - first.begin))); } else { opt.fragments[first.index].setCharCodes(opt.fragments[first.index].getCharCodes().slice(0, b - first.begin)); opt.fragments[last.index].setCharCodes(opt.fragments[last.index].getCharCodes().slice(e - last.begin)); l = last.index - first.index; if (l > 1) { opt.fragments.splice(first.index + 1, l - 1); } } // merge fragments with equal formats t._mergeFragments(); } t.cursorPos = b; if (!t.noUpdateMode) { t._update(); } this.endAction(); }; CellEditor.prototype._selectChars = function (kind, pos) { var t = this; var begPos, endPos; this.sAutoComplete = null; begPos = t.selectionBegin === t.selectionEnd ? t.cursorPos : t.selectionBegin; t._moveCursor(kind, pos); endPos = t.cursorPos; t.selectionBegin = begPos; t.selectionEnd = endPos; t._drawSelection(); if (t.isTopLineActive && !t.skipTLUpdate) { t._updateTopLineCurPos(); } }; CellEditor.prototype._changeSelection = function (coord) { var t = this; function doChangeSelection(coordTmp) { // ToDo implement for the word. if (c_oAscCellEditorSelectState.word === t.isSelectMode) { return; } var pos = t._findCursorPosition(coordTmp); if (pos !== undefined) { pos >= 0 ? t._selectChars(kPosition, pos) : t._selectChars(pos); } } if (window['IS_NATIVE_EDITOR']) { doChangeSelection(coord); } else { window.clearTimeout(t.selectionTimer); t.selectionTimer = window.setTimeout(function () { doChangeSelection(coord); }, 0); } }; CellEditor.prototype._findFragment = function (pos, fragments) { var i, begin, end; if (!fragments) { fragments = this.options.fragments; } if (!fragments) { return; } for (i = 0, begin = 0; i < fragments.length; ++i) { end = begin + fragments[i].getCharCodesLength(); if (pos >= begin && pos < end) { return {index: i, begin: begin, end: end}; } if (i < fragments.length - 1) { begin = end; } } return pos === end ? {index: i - 1, begin: begin, end: end} : undefined; }; CellEditor.prototype._findFragmentToInsertInto = function (pos, fragments) { var i, begin, end; if (!fragments) { fragments = this.options.fragments; } if (!fragments) { return; } for (i = 0, begin = 0; i < fragments.length; ++i) { end = begin + fragments[i].getCharCodesLength(); if (pos >= begin && pos <= end) { return {index: i, begin: begin, end: end}; } if (i < fragments.length - 1) { begin = end; } } return undefined; }; CellEditor.prototype._isWholeFragment = function (pos, len) { var fr = this._findFragment(pos); return fr && pos === fr.begin && len === fr.end - fr.begin; }; CellEditor.prototype._splitFragment = function (f, pos, fragments) { var fr; if (!fragments) { fragments = this.options.fragments; } if (!fragments) { return; } if (pos > f.begin && pos < f.end) { fr = fragments[f.index]; Array.prototype.splice.apply(fragments, [f.index, 1].concat([new Fragment({ format: fr.format.clone(), charCodes: fr.getCharCodes().slice(0, pos - f.begin) }), new Fragment({format: fr.format.clone(), charCodes: fr.getCharCodes().slice(pos - f.begin)})])); } }; CellEditor.prototype._getFragments = function (startPos, length) { var t = this, opt = t.options, endPos = startPos + length - 1, res = [], fr, i; var first = t._findFragment(startPos); var last = t._findFragment(endPos); if (!first || !last) { throw new Error("Can not extract fragment of text"); } if (first.index === last.index) { fr = opt.fragments[first.index].clone(); fr.charCodes = fr.getCharCodes().slice(startPos - first.begin, endPos - first.begin + 1); res.push(fr); } else { fr = opt.fragments[first.index].clone(); fr.charCodes = fr.getCharCodes().slice(startPos - first.begin); res.push(fr); for (i = first.index + 1; i < last.index; ++i) { fr = opt.fragments[i].clone(); res.push(fr); } fr = opt.fragments[last.index].clone(); fr.charCodes = fr.getCharCodes().slice(0, endPos - last.begin + 1); res.push(fr); } return res; }; CellEditor.prototype._extractFragments = function (startPos, length, fragments) { var fr; fr = this._findFragment(startPos, fragments); if (!fr) { throw new Error("Can not extract fragment of text"); } this._splitFragment(fr, startPos, fragments); fr = this._findFragment(startPos + length, fragments); if (!fr) { throw new Error("Can not extract fragment of text"); } this._splitFragment(fr, startPos + length, fragments); }; CellEditor.prototype._addFragments = function (f, pos) { var t = this, opt = t.options, fr; if (!opt.fragments) { return; } fr = t._findFragment(pos); if (fr && pos < fr.end) { t._splitFragment(fr, pos); fr = t._findFragment(pos); Array.prototype.splice.apply(opt.fragments, [fr.index, 0].concat(f)); } else { opt.fragments = opt.fragments.concat(f); } // merge fragments with equal formats t._mergeFragments(); t.cursorPos = pos + AscCommonExcel.getFragmentsLength(f); if (!t.noUpdateMode) { t._update(); } }; CellEditor.prototype._mergeFragments = function (fragments) { var i; if (!fragments) { fragments = this.options.fragments; } if (!fragments) { return; } for (i = 0; i < fragments.length;) { if (fragments[i].getCharCodesLength() < 1 && fragments.length > 1) { fragments.splice(i, 1); continue; } if (i < fragments.length - 1) { var fr = fragments[i]; var nextFr = fragments[i + 1]; if (fr.format.isEqual(nextFr.format)) { fragments.splice(i, 2, new Fragment({ format: fr.format, charCodes: fr.getCharCodes().concat(nextFr.getCharCodes()) })); continue; } } ++i; } }; CellEditor.prototype._cleanFragments = function (fr) { var t = this, i, s, f, wrap = t.textFlags.wrapText || t.textFlags.wrapOnlyNL; if (!fr) { return; } for (i = 0; i < fr.length; ++i) { s = fr[i].getCharCodes(); if (!wrap && -1 !== window["Asc"].search(s, function (val) { return val === codeNewLine })) { this._wrapText(); } fr[i].setCharCodes(s); f = fr[i].format; if (f.getName() === "") { f.setName(t.options.font.getName()); } if (f.getSize() === 0) { f.setSize(t.options.font.getSize()); } } }; CellEditor.prototype._setFormatProperty = function (format, prop, val) { switch (prop) { case "fn": format.setName(val); format.setScheme(null); break; case "fs": format.setSize(val); break; case "b": var bold = format.getBold(); val = (null === val) ? ((bold) ? !bold : true) : val; format.setBold(val); break; case "i": var italic = format.getItalic(); val = (null === val) ? ((italic) ? !italic : true) : val; format.setItalic(val); break; case "u": var underline = format.getUnderline(); val = (null === val) ? ((Asc.EUnderline.underlineNone === underline) ? Asc.EUnderline.underlineSingle : Asc.EUnderline.underlineNone) : val; format.setUnderline(val); break; case "s": var strikeout = format.getStrikeout(); val = (null === val) ? ((strikeout) ? !strikeout : true) : val; format.setStrikeout(val); break; case "fa": format.setVerticalAlign(val); break; case "c": format.setColor(val); break; case "changeFontSize": var newFontSize = asc_incDecFonSize(val, format.getSize()); if (null !== newFontSize) { format.setSize(newFontSize); } break; } return val; }; CellEditor.prototype._performAction = function (list1, list2) { var t = this, action, str, pos, len; if (list1.length < 1) { return; } action = list1.pop(); if (action.fn === t._removeChars) { pos = action.args[0]; len = action.args[1]; if (len < 2 && !t._isWholeFragment(pos, len)) { list2.push({fn: t._addChars, args: [t.textRender.getChars(pos, len), pos], isRange: action.isRange}); } else { list2.push({fn: t._addFragments, args: [t._getFragments(pos, len), pos], isRange: action.isRange}); } } else if (action.fn === t._addChars) { str = action.args[0]; pos = action.args[1]; list2.push({fn: t._removeChars, args: [pos, str.length], isRange: action.isRange}); } else if (action.fn === t._addFragments) { pos = action.args[1]; len = AscCommonExcel.getFragmentsLength(action.args[0]); list2.push({fn: t._removeChars, args: [pos, len], isRange: action.isRange}); } else if (action.fn === t._changeFragments) { let _fragments = action.args[0]; let _redoFragments = {}; for (let i in _fragments) { if (_fragments.hasOwnProperty(i)) { if (this.options.fragments && this.options.fragments[i]) { _redoFragments[i] = this.options.fragments[i].clone(); } } } list2.push({fn: t._changeFragments, args: [_redoFragments]}); } else { return; } t.undoMode = true; if (t.selectionBegin !== t.selectionEnd) { t.selectionBegin = t.selectionEnd = -1; t._cleanSelection(); } action.fn.apply(t, action.args); t.undoMode = false; }; CellEditor.prototype._tryCloseEditor = function (event) { var t = this; let nRetValue = keydownresult_PreventNothing; var callback = function (success) { // for the case when the user presses ctrl+shift+enter/crtl+enter the transition to a new line is not performed var applyByArray = t.textFlags && t.textFlags.ctrlKey; if (!applyByArray && success) { nRetValue = t.handlers.trigger("applyCloseEvent", event); AscCommon.StartIntervalDrawText(false); } }; this.close(true, callback); return nRetValue; }; CellEditor.prototype._getAutoComplete = function (str) { // ToDo can be sped up by searching each time not in a large array, but in a smaller one (by previous characters) //TODO I save the text! var oLastResult = this.objAutoComplete.get(str); if (oLastResult) { return oLastResult; } var arrAutoComplete = this.options.autoComplete; var arrAutoCompleteLC = this.options.autoCompleteLC; var i, length, arrResult = []; for (i = 0, length = arrAutoCompleteLC.length; i < length; ++i) { if (arrAutoCompleteLC[i].length !== str.length && 0 === arrAutoCompleteLC[i].indexOf(str)) { arrResult.push(arrAutoComplete[i]); } } this.objAutoComplete.set(str, arrResult); return arrResult; }; CellEditor.prototype._updateSelectionInfo = function () { var f = this._findFragmentToInsertInto(this.cursorPos); if (!f) { return; } var xfs = new AscCommonExcel.CellXfs(); xfs.setFont(this.newTextFormat || (this.options.fragments && this.options.fragments[f.index].format)); this.handlers.trigger("updateEditorSelectionInfo", xfs); }; CellEditor.prototype._checkMaxCellLength = function (length) { //TODO question, measure text length or number of characters var count = AscCommonExcel.getFragmentsCharCodesLength(this.options.fragments) + length - Asc.c_oAscMaxCellOrCommentLength; return 0 > count ? 0 : count; }; // Event handlers CellEditor.prototype.executeShortcut = function(nShortcutAction) { let oResult = {keyResult: keydownresult_PreventAll}; const oApi = window["Asc"]["editor"]; const bHieroglyph = this.isTopLineActive && AscCommonExcel.getFragmentsLength(this.options.fragments) !== this.input.value.length; switch (nShortcutAction) { case Asc.c_oAscSpreadsheetShortcutType.Strikeout: { if (bHieroglyph) { this._syncEditors(); } this.setTextStyle("s", null); break; } case Asc.c_oAscSpreadsheetShortcutType.Bold: { if (bHieroglyph) { this._syncEditors(); } this.setTextStyle("b", null); break; } case Asc.c_oAscSpreadsheetShortcutType.Italic: { if (bHieroglyph) { this._syncEditors(); } this.setTextStyle("i", null); break; } case Asc.c_oAscSpreadsheetShortcutType.Underline: { if (bHieroglyph) { this._syncEditors(); } this.setTextStyle("u", null); break; } case Asc.c_oAscSpreadsheetShortcutType.EditSelectAll: { if (!this.hasFocus) { this.setFocus(true); } if (this.isTopLineActive) { oResult.keyResult = keydownresult_PreventNothing; } this._moveCursor(kBeginOfText); this._selectChars(kEndOfText); break; } case Asc.c_oAscSpreadsheetShortcutType.EditUndo: { this.undo(); break; } case Asc.c_oAscSpreadsheetShortcutType.EditRedo: { this.redo(); break; } case Asc.c_oAscSpreadsheetShortcutType.CellInsertTime: { const oDate = new Asc.cDate(); this._addChars(oDate.getTimeString(oApi)); break; } case Asc.c_oAscSpreadsheetShortcutType.CellInsertDate: { const oDate = new Asc.cDate(); this._addChars(oDate.getDateString(oApi, true)); break; } case Asc.c_oAscSpreadsheetShortcutType.PrintPreviewAndPrint: { break; } case Asc.c_oAscSpreadsheetShortcutType.EditOpenCellEditor: { if (!AscBrowser.isOpera) { oResult.keyResult = keydownresult_PreventNothing; } break; } case Asc.c_oAscSpreadsheetShortcutType.CellAddSeparator: { this._addChars(oApi.asc_getDecimalSeparator()); break; } case Asc.c_oAscSpreadsheetShortcutType.CellEditorSwitchReference: { const oRes = this._findRangeUnderCursor(); if (oRes.range) { oRes.range.switchReference(); // ToDo add change ref to other sheet this.changeCellRange(oRes.range); } break; } case Asc.c_oAscSpreadsheetShortcutType.IncreaseFontSize: case Asc.c_oAscSpreadsheetShortcutType.DecreaseFontSize: { if (bHieroglyph) { this._syncEditors(); } this.setTextStyle("changeFontSize", nShortcutAction === Asc.c_oAscSpreadsheetShortcutType.IncreaseFontSize); break; } default: { const oCustom = oApi.getCustomShortcutAction(nShortcutAction); if (oCustom) { if (AscCommon.c_oAscCustomShortcutType.Symbol === oCustom.Type) { oApi["asc_insertSymbol"](oCustom.Font, oCustom.CharCode); } } else { oResult = null; } break; } } return oResult; }; /** * * @param oEvent {AscCommon.CKeyboardEvent} * @returns {number} */ CellEditor.prototype._onWindowKeyDown = function (oEvent) { const oThis = this; const oApi = window["Asc"]["editor"]; let nRetValue = keydownresult_PreventNothing; if (this.handlers.trigger('getWizard') || !oThis.isOpened) { return nRetValue; } oThis._setSkipKeyPress(false); oThis.skipTLUpdate = false; // hieroglyph input definition const bHieroglyph = oThis.isTopLineActive && AscCommonExcel.getFragmentsLength(oThis.options.fragments) !== oThis.input.value.length; nRetValue = keydownresult_PreventKeyPress; const nShortcutAction = oApi.getShortcut(oEvent); const oShortcutRes = oThis.executeShortcut(nShortcutAction); if (oShortcutRes) { nRetValue = oShortcutRes.keyResult; } else { const bIsMacOs = AscCommon.AscBrowser.isMacOs; const bIsWordRemove = bIsMacOs ? oEvent.IsAlt() : oEvent.CtrlKey; switch (oEvent.GetKeyCode()) { case 27: { // "esc" if (oThis.handlers.trigger("isGlobalLockEditCell") || this.getMenuEditorMode()) { break; } oThis.close(); nRetValue = keydownresult_PreventAll; break; } case 13: { // "enter" if (window['IS_NATIVE_EDITOR']) { oThis._addNewLine(); } else { if (!(oEvent.IsAlt() && oEvent.IsShift())) { if (oEvent.IsAlt()) { oThis._addNewLine(); } else if (this.getMenuEditorMode()) { oThis._addNewLine(); } else { if (false === oThis.handlers.trigger("isGlobalLockEditCell")) { if (oThis.textFlags) { oThis.textFlags.ctrlKey = oEvent.CtrlKey; oThis.textFlags.shiftKey = oEvent.IsShift(); } oThis._tryCloseEditor(oEvent); } } } } nRetValue = keydownresult_PreventAll; break; } case 9: { // tab if (bHieroglyph) { oThis._syncEditors(); } if (false === oThis.handlers.trigger("isGlobalLockEditCell")) { nRetValue = oThis._tryCloseEditor(oEvent); } break; } case 8: { // "backspace" if (!this.enableKeyEvents) { break; } if (!window['IS_NATIVE_EDITOR']) { // Disable the browser's standard handling of pressing backspace nRetValue = keydownresult_PreventAll; if (bHieroglyph) { oThis._syncEditors(); } } oThis._removeChars(bIsWordRemove ? kPrevWord : kPrevChar); break; } case 35: { // "end" if (!this.enableKeyEvents) { break; } // Disable the browser's standard handling of pressing end nRetValue = keydownresult_PreventAll; if (!oThis.hasFocus) { break; } if (bHieroglyph) { oThis._syncEditors(); } const nKind = oEvent.CtrlKey ? kEndOfText : kEndOfLine; oEvent.IsShift() ? oThis._selectChars(nKind) : oThis._moveCursor(nKind); break; } case 36: { // "home" if (!this.enableKeyEvents) { break; } // Disable the browser's standard handling of pressing home nRetValue = keydownresult_PreventAll; if (!oThis.hasFocus) { break; } if (bHieroglyph) { oThis._syncEditors(); } const nKind = oEvent.CtrlKey ? kBeginOfText : kBeginOfLine; oEvent.IsShift() ? oThis._selectChars(nKind) : oThis._moveCursor(nKind); break; } case 37: { // "left" if (!this.enableKeyEvents) { this._delayedUpdateCursorByTopLine(); break; } nRetValue = keydownresult_PreventAll; if (!oThis.hasFocus) { break; } if (bHieroglyph) { oThis._syncEditors(); } if (bIsMacOs && oEvent.CtrlKey) { oEvent.IsShift() ? oThis._selectChars(kBeginOfLine) : oThis._moveCursor(kBeginOfLine); } else { const bWord = bIsMacOs ? oEvent.IsAlt() : oEvent.CtrlKey; const nKind = bWord ? kPrevWord : kPrevChar; oEvent.IsShift() ? oThis._selectChars(nKind) : oThis._moveCursor(nKind); } break; } case 38: {// "up" if (!this.enableKeyEvents) { this._delayedUpdateCursorByTopLine(); break; } nRetValue = keydownresult_PreventAll; if (!oThis.hasFocus) { break; } if (bHieroglyph) { oThis._syncEditors(); } oEvent.IsShift() ? oThis._selectChars(kPrevLine) : oThis._moveCursor(kPrevLine); break; } case 39: {// "right" if (!this.enableKeyEvents) { this._delayedUpdateCursorByTopLine(); break; } nRetValue = keydownresult_PreventAll; if (!oThis.hasFocus) { break; } if (bHieroglyph) { oThis._syncEditors(); } if (bIsMacOs && oEvent.CtrlKey) { oEvent.IsShift() ? oThis._selectChars(kEndOfLine) : oThis._moveCursor(kEndOfLine); } else { const bWord = bIsMacOs ? oEvent.IsAlt() : oEvent.CtrlKey; const nKind = bWord ? kNextWord : kNextChar; oEvent.IsShift() ? oThis._selectChars(nKind) : oThis._moveCursor(nKind); } break; } case 40: { // "down" if (!this.enableKeyEvents) { this._delayedUpdateCursorByTopLine(); break; } nRetValue = keydownresult_PreventAll; if (!oThis.hasFocus) { break; } if (bHieroglyph) { oThis._syncEditors(); } oEvent.IsShift() ? oThis._selectChars(kNextLine) : oThis._moveCursor(kNextLine); break; } case 46: {// "del" if (!this.enableKeyEvents || oEvent.IsShift()) { break; } if (bHieroglyph) { oThis._syncEditors(); } nRetValue = keydownresult_PreventAll; oThis._removeChars(bIsWordRemove ? kNextWord : kNextChar); break; } case 144://Num Lock case 145: {//Scroll Lock if (AscBrowser.isOpera) { nRetValue = keydownresult_PreventAll; } break; } default: { nRetValue = keydownresult_PreventNothing; break; } } } if (nRetValue & keydownresult_PreventKeyPress) { oThis._setSkipKeyPress(true); } oThis.skipTLUpdate = true; return nRetValue; }; /** @param event {KeyboardEvent} */ CellEditor.prototype._onWindowKeyPress = function (event) { var t = this; if (!window['IS_NATIVE_EDITOR']) { if (event.KeyCode < 32 || t.skipKeyPress) { t._setSkipKeyPress(true); return true; } } let Code; if (null != event.Which) { Code = event.Which; } else if (event.KeyCode) { Code = event.KeyCode; } else { Code = 0; } return this.EnterText(Code); }; CellEditor.prototype.EnterText = function (codePoints) { var t = this; if (!window['IS_NATIVE_EDITOR']) { if (!t.isOpened || !t.enableKeyEvents || this.handlers.trigger('getWizard')) { return true; } // hieroglyph input definition if (t.isTopLineActive && AscCommonExcel.getFragmentsLength(t.options.fragments) !== t.input.value.length) { t._syncEditors(); } } t._setSkipKeyPress(false); //TODO Translation from code to symbols! var newChar; if (Array.isArray(codePoints)) { for (let nIdx = 0; nIdx < codePoints.length; ++nIdx) { newChar = String.fromCharCode(codePoints[nIdx]); t._addChars(newChar); } } else { newChar = String.fromCharCode(codePoints); t._addChars(newChar); } //TODO in case of adding an array - check - perhaps the part needs to be called every time after _addChars var tmpCursorPos; // The first time we enter quickly, we should add percentages at the end (for percentage format and only for numbers) if (t.options.isAddPersentFormat && AscCommon.isNumber(newChar)) { t.options.isAddPersentFormat = false; tmpCursorPos = t.cursorPos; t.undoMode = true; // add the percentage only to the line without a formula if (!t._formula) { t._addChars("%"); } t.cursorPos = tmpCursorPos; t.undoMode = false; t._updateCursorPosition(); } if (t.textRender.getEndOfText() === t.cursorPos && !t.isFormula()) { var s = AscCommonExcel.getFragmentsText(t.options.fragments); if (!AscCommon.isNumber(s) && s.length !== 0) { var arrAutoComplete = t._getAutoComplete(s.toLowerCase()); var lengthInput = s.length; if (1 === arrAutoComplete.length) { var newValue = arrAutoComplete[0]; tmpCursorPos = t.cursorPos; t._addChars(newValue.substring(lengthInput)); t.selectionBegin = tmpCursorPos; t._selectChars(kEndOfText); this.sAutoComplete = newValue; } } } return t.isTopLineActive; // prevent event bubbling }; /** @param event {KeyboardEvent} */ CellEditor.prototype._onWindowKeyUp = function (event) { }; /** @param event {MouseEvent} */ CellEditor.prototype._onWindowMouseUp = function (event) { AscCommon.global_mouseEvent.UnLockMouse(); if (c_oAscCellEditorSelectState.no !== this.isSelectMode) { this.cleanSelectRange(); } this.isSelectMode = c_oAscCellEditorSelectState.no; if (this.callTopLineMouseup) { this._topLineMouseUp(); } return true; }; /** @param event {MouseEvent} */ CellEditor.prototype._onWindowMouseMove = function (event) { if (c_oAscCellEditorSelectState.no !== this.isSelectMode && !this.hasCursor) { this._changeSelection(this._getCoordinates(event)); } return true; }; /** @param event {MouseEvent} */ CellEditor.prototype._onMouseDown = function (event) { if (AscCommon.g_inputContext && AscCommon.g_inputContext.externalChangeFocus()) { return; } if (this.handlers.trigger('getWizard')) { return this.handlers.trigger('onMouseDown', event); } AscCommon.global_mouseEvent.LockMouse(); var pos; var button = AscCommon.getMouseButton(event); var coord = this._getCoordinates(event); if (!window['IS_NATIVE_EDITOR']) { this.clickCounter.mouseDownEvent(coord.x, coord.y, button); } this.setFocus(true); this._updateTopLineActive(false); this.input.isFocused = false; if (0 === button) { if (1 === this.clickCounter.getClickCount() % 2) { this.isSelectMode = c_oAscCellEditorSelectState.char; if (!event.shiftKey) { this._updateCursor(); pos = this._findCursorPosition(coord); if (pos !== undefined) { pos >= 0 ? this._moveCursor(kPosition, pos, this._findLineIndex(coord)) : this._moveCursor(pos, null, this._findLineIndex(coord)); } } else { this._changeSelection(coord); } } else { // Dbl click this.isSelectMode = c_oAscCellEditorSelectState.word; let endWord, startWord; let fullString = AscCommonExcel.convertUnicodeToSimpleString(this.textRender.chars); let isNum = AscCommon.g_oFormatParser.isLocaleNumber(fullString); if (isNum) { // if we encounter a current numberDecimalSeparator in a number, we return the entire string as selection let splitIndex = fullString.indexOf(AscCommon.g_oDefaultCultureInfo.NumberDecimalSeparator); if (splitIndex !== -1) { endWord = fullString.length; startWord = 0; } } // End of the word endWord = endWord === undefined ? this.textRender.getNextWord(this.cursorPos) : endWord; // The beginning of the word (we look for the end, because we could get into a space) startWord = startWord === undefined ? this.textRender.getPrevWord(endWord) : startWord; this._moveCursor(kPosition, startWord); this._selectChars(kPosition, endWord); } } else if (2 === button) { this.handlers.trigger('onContextMenu', event); } return true; }; /** @param event {MouseEvent} */ CellEditor.prototype._onMouseUp = function (event) { var button = AscCommon.getMouseButton(event); AscCommon.global_mouseEvent.UnLockMouse(); if (2 === button) { return true; } if (c_oAscCellEditorSelectState.no !== this.isSelectMode) { this.cleanSelectRange(); } this.isSelectMode = c_oAscCellEditorSelectState.no; return true; }; /** @param event {MouseEvent} */ CellEditor.prototype._onMouseMove = function (event) { var coord = this._getCoordinates(event); this.clickCounter.mouseMoveEvent(coord.x, coord.y); this.hasCursor = true; if (c_oAscCellEditorSelectState.no !== this.isSelectMode) { this._changeSelection(coord); } return true; }; /** @param event {MouseEvent} */ CellEditor.prototype._onMouseLeave = function (event) { this.hasCursor = false; return true; }; /** @param event {jQuery.Event} */ CellEditor.prototype._onInputTextArea = function (event) { //TODO save the text! var t = this; if (!this.handlers.trigger("canEdit") || this.loadFonts) { return true; } if (this.handlers.trigger("isUserProtectActiveCell")) { this.handlers.trigger("asc_onError", Asc.c_oAscError.ID.ProtectedRangeByOtherUser, c_oAscError.Level.NoCritical); return true; } if (this.handlers.trigger("isProtectActiveCell")) { return true; } this.loadFonts = true; let checkedText = this.input.value.replace(/[\r\n]+/g, ''); AscFonts.FontPickerByCharacter.checkText(checkedText, this, function () { t.loadFonts = false; t.skipTLUpdate = true; var length = t.replaceText(0, t.textRender.getEndOfText(), t.input.value); t._updateCursorByTopLine(); if (length !== t.input.value.length) { t.input.value = AscCommonExcel.getFragmentsText((t.options.fragments)); t._updateTopLineCurPos(); } }); return true; }; /** @param event {MouseEvent} */ CellEditor.prototype._getCoordinates = function (event) { if (window['IS_NATIVE_EDITOR']) { return {x: event.pageX, y: event.pageY}; } var offs = AscCommon.UI.getBoundingClientRect(this.canvasOverlay); var x = (((event.pageX * AscBrowser.zoom) >> 0) - offs.left) / this.kx; var y = (((event.pageY * AscBrowser.zoom) >> 0) - offs.top) / this.ky; x *= AscCommon.AscBrowser.retinaPixelRatio; y *= AscCommon.AscBrowser.retinaPixelRatio; return {x: x, y: y}; }; CellEditor.prototype.getTextFromCharCodes = function (arrCharCodes) { //TODO save the text! var code, codePt, newText = ''; for (var i = 0; i < arrCharCodes.length; ++i) { code = arrCharCodes[i]; if (code < 0x10000) { newText += String.fromCharCode(code); } else { codePt = code - 0x10000; newText += String.fromCharCode(0xD800 + (codePt >> 10), 0xDC00 + (codePt & 0x3FF)); } } return newText; }; CellEditor.prototype.Begin_CompositeInput = function () { if (this.selectionBegin === this.selectionEnd) { this.beginCompositePos = this.cursorPos; this.compositeLength = 0; } else { this.beginCompositePos = Math.min(this.selectionBegin, this.selectionEnd); this.compositeLength = Math.max(this.selectionBegin, this.selectionEnd) - this.beginCompositePos; } this.setTextStyle('u', Asc.EUnderline.underlineSingle); }; CellEditor.prototype.Replace_CompositeText = function (arrCharCodes) { if (!this.isOpened) { return; } var newText = this.getTextFromCharCodes(arrCharCodes); this.compositeLength = this.replaceText(this.beginCompositePos, this.compositeLength, newText); var tmpBegin = this.selectionBegin, tmpEnd = this.selectionEnd; this.selectionBegin = this.beginCompositePos; this.selectionEnd = this.beginCompositePos + this.compositeLength; this.setTextStyle('u', Asc.EUnderline.underlineSingle); this.selectionBegin = tmpBegin; this.selectionEnd = tmpEnd; // Refreshing the selection this._cleanSelection(); this._drawSelection(); }; CellEditor.prototype.End_CompositeInput = function () { var tmpBegin = this.selectionBegin, tmpEnd = this.selectionEnd; //TODO linux(popOs + portuguese lang.) composite input - doesn't come Replace_CompositeText on remove chars let checkFragments = this._findFragment(this.beginCompositePos) && this._findFragment(this.beginCompositePos + this.compositeLength); if (checkFragments) { this.selectionBegin = this.beginCompositePos; this.selectionEnd = this.beginCompositePos + this.compositeLength; } this.setTextStyle('u', Asc.EUnderline.underlineNone); this.beginCompositePos = -1; this.compositeLength = 0; this.selectionBegin = tmpBegin; this.selectionEnd = tmpEnd; // Refreshing the selection this._cleanSelection(); this._drawSelection(); }; CellEditor.prototype.isStartCompositeInput = function () { return this.beginCompositePos !== -1 && this.compositeLength !== 0; }; CellEditor.prototype.Set_CursorPosInCompositeText = function (nPos) { if (-1 !== this.beginCompositePos) { nPos = Math.min(nPos, this.compositeLength); this._moveCursor(kPosition, this.beginCompositePos + nPos); } }; CellEditor.prototype.Get_CursorPosInCompositeText = function () { return this.cursorPos - this.beginCompositePos; }; CellEditor.prototype.Get_MaxCursorPosInCompositeText = function () { return this.compositeLength; }; CellEditor.prototype.getMenuEditorMode = function () { return this.menuEditor; }; CellEditor.prototype.selectAll = function () { //t.skipKeyPress var tmp = this.skipTLUpdate; this.skipTLUpdate = false; this._moveCursor(kBeginOfText); this._selectChars(kEndOfText); this.skipTLUpdate = tmp; }; CellEditor.prototype._setSkipKeyPress = function (val) { this.skipKeyPress = val; }; CellEditor.prototype.getText = function (start, len) { if (start == null) { start = 0; } if (len == null) { len = this.textRender.getCharsCount(); } let chars = this.textRender.getChars(start, len); let res = ""; for (let i in chars) { if (chars.hasOwnProperty(i)) { res += AscCommon.encodeSurrogateChar(chars[i]); } } return res; }; CellEditor.prototype.getSelectionState = function () { return {start: this.selectionBegin, end: this.selectionEnd, cursor: this.cursorPos}; }; CellEditor.prototype.getSpeechDescription = function (prevState, curState, action) { if (curState.start === prevState.start && curState.end === prevState.end && prevState.cursor === curState.cursor) { return null; } let type = null, text = null, t = this; let compareSelection = function () { let _begin = Math.min(curState.start, curState.end); let _end = Math.max(curState.start, curState.end); let _start, _len; if (_end === _begin) { text = t.getText(t.cursorPos, 1); type = AscCommon.SpeechWorkerCommands.Text; return; } if (_end < prevState.start || prevState.end < _begin) { //no intersection //speech new select _start = _begin; _len = _end - _begin; type = AscCommon.SpeechWorkerCommands.Text; } else { if (_end !== prevState.end) { //changed end of text if (_end > prevState.end) { //added by select _start = prevState.end; _len = _end - prevState.end; type = AscCommon.SpeechWorkerCommands.TextSelected; } else { //deleted from select _start = _end; _len = prevState.end - _end; type = AscCommon.SpeechWorkerCommands.TextUnselected; } } else { if (_begin < prevState.start) { //added by select _start = _begin; _len = prevState.start - _begin; type = AscCommon.SpeechWorkerCommands.TextSelected; } else { //deleted from select _start = prevState.start; _len = _begin - prevState.start; type = AscCommon.SpeechWorkerCommands.TextUnselected; } } } text = t.getText(_start, _len); }; let getWord = function () { let _cursorPos = t.cursorPos; type = AscCommon.SpeechWorkerCommands.Text; let _cursorPosNextWord = t.textRender.getNextWord(_cursorPos); text = t.getText(_cursorPos, _cursorPosNextWord - _cursorPos); }; if (action) { let bWord = false; if (action.type !== AscCommon.SpeakerActionType.keyDown || action.event.KeyCode < 35 || action.event.KeyCode > 40) { return null; } if (!this.enableKeyEvents || !t.hasFocus) { return null; } let event = action.event; let isWizard = this.handlers.trigger('getWizard'); if (!action.event || isWizard || !t.isOpened) { return null; } const bIsMacOs = AscCommon.AscBrowser.isMacOs; switch (event.GetKeyCode()) { case 8: // "backspace" /*const bIsWord = bIsMacOs ? event.altKey : ctrlKey; t._removeChars(bIsWord ? kPrevWord : kPrevChar);*/ break; case 35: // "end" /*kind = ctrlKey ? kEndOfText : kEndOfLine; event.shiftKey ? t._selectChars(kind) : t._moveCursor(kind); return false;*/ break; case 36: // "home" /*kind = ctrlKey ? kBeginOfText : kBeginOfLine; event.shiftKey ? t._selectChars(kind) : t._moveCursor(kind);*/ break; case 37: // "left" if (bIsMacOs && event.CtrlKey) { //event.shiftKey ? t._selectChars(kBeginOfLine) : t._moveCursor(kBeginOfLine); } else { bWord = bIsMacOs ? event.AltKey : event.CtrlKey; /*kind = bWord ? kPrevWord : kPrevChar; event.shiftKey ? t._selectChars(kind) : t._moveCursor(kind);*/ } break; case 38: // "up" //event.shiftKey ? t._selectChars(kPrevLine) : t._moveCursor(kPrevLine); break; case 39: // "right" if (bIsMacOs && event.CtrlKey) { //event.shiftKey ? t._selectChars(kEndOfLine) : t._moveCursor(kEndOfLine); } else { bWord = bIsMacOs ? event.AltKey : event.CtrlKey; /*kind = bWord ? kNextWord : kNextChar; event.shiftKey ? t._selectChars(kind) : t._moveCursor(kind);*/ } break; case 40: // "down" //event.shiftKey ? t._selectChars(kNextLine) : t._moveCursor(kNextLine); break; } if (bWord) { getWord(); } else { compareSelection(); } } else { compareSelection(); } return type !== null ? {type: type, obj: {text: text}} : null; }; CellEditor.prototype.setSelectionState = function (obj) { if (!obj) { return; } this.selectionBegin = obj.selectionBegin; this.selectionEnd = obj.selectionEnd; this.lastRangePos = obj.lastRangePos; this.lastRangeLength = obj.lastRangeLength; this.cursorPos = obj.cursorPos; }; CellEditor.prototype.startAction = function () { var api = window["Asc"]["editor"]; if (!api) { return; } api.sendEvent('asc_onUserActionStart'); }; CellEditor.prototype.endAction = function () { var api = window["Asc"]["editor"]; if (!api) { return; } api.sendEvent('asc_onUserActionEnd'); }; CellEditor.prototype.openAction = function () { var api = window["Asc"]["editor"]; if (!api) { return; } api.sendEvent('onOpenCellEditor'); }; CellEditor.prototype.closeAction = function () { var api = window["Asc"]["editor"]; if (!api) { return; } api.sendEvent('onCloseCellEditor'); }; //------------------------------------------------------------export--------------------------------------------------- window['AscCommonExcel'] = window['AscCommonExcel'] || {}; window["AscCommonExcel"].CellEditor = CellEditor; })(window);