Files
DocumentServer-v-9.2.0/sdkjs/cell/view/CellEditorView.js
Yajbir Singh f1b860b25c
Some checks failed
check / markdownlint (push) Has been cancelled
check / spellchecker (push) Has been cancelled
updated
2025-12-11 19:03:17 +05:30

3486 lines
102 KiB
JavaScript

/*
* (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 = '<canvas id=' + ceCanvasId + ' style="z-index: ' + (z + 1) + '"></canvas>';
innerHTML += '<canvas id=' + ceCanvasOverlay + ' style="z-index: ' + (z + 2) + '; cursor: ' + t.defaults.cursorShape +
'"></canvas>';
innerHTML += '<div id=' + ceCursor + ' style="display: none; z-index: ' + (z + 3) + '"></div>';
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);