Files
DocumentServer-v-9.2.0/sdkjs/common/text_input2.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

1547 lines
41 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* (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";
(function(window, undefined)
{
window["AscInputMethod"] = window["AscInputMethod"] || {};
///
// такие методы нужны в апи
// baseEditorsApi.prototype.Begin_CompositeInput = function()
// baseEditorsApi.prototype.Replace_CompositeText = function(arrCharCodes)
// baseEditorsApi.prototype.Set_CursorPosInCompositeText = function(nPos)
// baseEditorsApi.prototype.Get_CursorPosInCompositeText = function()
// baseEditorsApi.prototype.End_CompositeInput = function()
// baseEditorsApi.prototype.Get_MaxCursorPosInCompositeText = function()
// baseEditorsApi.prototype.onKeyDown = function(e)
// baseEditorsApi.prototype.onKeyPress = function(e)
// baseEditorsApi.prototype.onKeyUp = function(e)
///
window['AscCommon'] = window['AscCommon'] || {};
window['AscCommon'].inputMethodAddInitEvent = function(callback)
{
AscCommon.g_inputContext_create_events = AscCommon.g_inputContext_create_events || [];
AscCommon.g_inputContext_create_events.push(callback);
};
window['AscCommon'].inputMethodCheckInitEvents = function()
{
if (!AscCommon.g_inputContext_create_events)
return;
for (let i = 0, len = AscCommon.g_inputContext_create_events.length; i < len; i++)
AscCommon.g_inputContext_create_events[i]();
delete AscCommon.g_inputContext_create_events;
};
var InputTextElementType = {
TextArea : 0,
ContentEditableDiv : 1
};
function CTextInput2(api)
{
this.Api = api;
this.TargetId = null; // id caret
this.HtmlDiv = null; // для незаметной реализации одной textarea недостаточно. parent для HtmlArea
this.HtmlArea = null; // HtmlArea - элемент для ввода
this.ElementType = InputTextElementType.TextArea;
// ---------------------------------------------------------------
// chrome element for left/top
this.FixedPosCheckElementX = 0;
this.FixedPosCheckElementY = 0;
// Notes offset for slides
this.TargetOffsetY = 0;
this.HtmlAreaOffset = 50; // height in pix
this.HtmlAreaWidth = 200;
// ---------------------------------------------------------------
// информация о текущем состоянии текста -------------------------
// текущее значение в textarea
this.Text = "";
// текст до того, как пришли сообщения onCompositeStart/onCompositeUpdate
// т.е. текст, который пришел на onInput/onTextInput, и когда мы не внутри onComposite[Begin-End]
this.TextBeforeComposition = "";
// в каком состоянии апи (композитный ли ввод сейчас)
this.IsComposition = false;
// ---------------------------------------------------------------
// не обрабатывать keyPress после keyDown
this.IsDisableKeyPress = false;
this.nativeFocusElement = null;
this.nativeFocusElementNoRemoveOnElementFocus = false;
this.InterfaceEnableKeyEvents = true;
this.isNoClearOnFocus = false;
this.isGlobalDisableFocus = false;
this.ReadOnlyCounter = 0;
this.keyPressInput = "";
this.isInputHelpersPresent = false;
this.isInputHelpers = {};
// параметры для показа/скрытия виртуальной клавиатуры.
this.isHardCheckKeyboard = AscCommon.AscBrowser.isSailfish;
this.virtualKeyboardClickTimeout = -1;
this.virtualKeyboardReadOnly_ShowKeyboard = AscCommon.AscBrowser.isAndroid && AscCommon.AscBrowser.isMozilla;
// для сброса текста при фокусе
this.checkClearTextOnFocusTimerId = -1;
this.isDisableKeyboard = false;
this.moveAccurateInfo = {
id : -1,
x : 0,
y : 0
};
}
var CTextInputPrototype = CTextInput2.prototype;
const TEXT_INPUT_DEBUG = false;
CTextInputPrototype.log = function(value)
{
if (TEXT_INPUT_DEBUG)
console.log(value);
};
// для совместимости. убрал системный ввод
CTextInputPrototype.systemInputEnable = function()
{
};
// input common
CTextInputPrototype.isSpaceSymbol = function(e)
{
if (e.keyCode == 32)
return true;
if ((e.keyCode == 229) && ((e.code == "space") || (e.code == "Space") || (e.key == "Spacebar")))
return true;
return false;
};
CTextInputPrototype.isCompositionProcess = function()
{
return this.IsComposition;
};
// input
CTextInputPrototype.onKeyDown = function(e)
{
if (this.Api.isLongAction())
{
AscCommon.stopEvent(e);
return false;
}
// проверим - может это навигация в окне хэлпера
if (this.isInputHelpersPresent)
{
switch (e.keyCode)
{
case 9: // tab
case 13: // enter
case 38: // top
case 40: // bottom
case 33: // pageup
case 34: // pagedown
case 35: // end
case 36: // home
case 27: // escape
{
window.g_asc_plugins.onPluginEvent2("onKeyDown", {
"keyCode" : e.keyCode,
"key" : e.key,
"code" : e.code,
"altKey" : e.altKey,
"ctrlKey" : e.ctrlKey,
"metaKey" : e.metaKey,
"shiftKey" : e.shiftKey
}, this.isInputHelpers);
AscCommon.stopEvent(e);
return false;
}
default:
break;
}
}
else
{
window.g_asc_plugins.onPluginEvent("onKeyDown", {
"keyCode" : e.keyCode,
"key" : e.key,
"code" : e.code,
"altKey" : e.altKey,
"ctrlKey" : e.ctrlKey,
"metaKey" : e.metaKey,
"shiftKey" : e.shiftKey
});
}
if (null != this.nativeFocusElement)
{
if (this.emulateNativeKeyDown(e))
{
e.preventDefault();
return false;
}
}
AscCommon.check_KeyboardEvent(e);
var arrCodes = this.Api.getAddedTextOnKeyDown(AscCommon.global_keyboardEvent);
var isAsync = AscFonts.FontPickerByCharacter.checkTextLight(arrCodes, true);
if (isAsync)
{
AscFonts.FontPickerByCharacter.loadFonts(this, function ()
{
this.onKeyDown(e);
this.onKeyUp(e);
this.setReadOnly(false);
});
this.setReadOnly(true);
AscCommon.stopEvent(e);
return false;
}
let isSpaceAsText = (32 === e.keyCode);
if (isSpaceAsText)
{
// hotkeys
if (AscCommon.global_keyboardEvent.AltKey ||
AscCommon.global_keyboardEvent.CtrlKey ||
AscCommon.global_keyboardEvent.MacCmdKey)
{
isSpaceAsText = false;
}
if (isSpaceAsText)
{
switch (this.Api.editorId)
{
case AscCommon.c_oEditorId.Spreadsheet:
{
if (AscCommon.global_keyboardEvent.ShiftKey)
isSpaceAsText = false;
break;
}
case AscCommon.c_oEditorId.Presentation:
{
if (this.Api.WordControl && this.Api.WordControl.DemonstrationManager && this.Api.WordControl.DemonstrationManager.Mode)
isSpaceAsText = false;
break;
}
default:
break;
}
}
}
// ios копирование и вырезка через клавиатуру внешнюю - требует селекта в фокусном textarea
// но если селектить - его видно. да и куча проблем. попробуем сэмулировать
if (this.Api.isMobileVersion && AscCommon.AscBrowser.isAppleDevices)
{
if (e.metaKey)
{
if (e.keyCode === 67)
{
AscCommon.g_clipboardBase.Button_Copy();
return;
}
else if (e.keyCode === 88)
{
AscCommon.g_clipboardBase.Button_Cut();
return;
}
}
else if (e.ctrlKey)
{
// safari send code 13 on ctrl + c. disable it
if (e.keyCode === 13 && e.code === "KeyC")
return;
}
}
let ret = undefined;
if (!isSpaceAsText)
ret = this.Api.onKeyDown(e);
let isSpecialClearInComposition = true;
switch (e.keyCode)
{
case 8: // backspace
isSpecialClearInComposition = false;
case 9: // tab
case 13: // enter
case 37: // left
case 38: // top
case 39: // right
case 40: // bottom
case 33: // pageup
case 34: // pagedown
case 35: // end
case 36: // home
case 46: // delete
{
if (!this.IsComposition || isSpecialClearInComposition)
this.clear();
}
default:
break;
}
if (e.keyCode === 32 && AscCommon.global_keyboardEvent.CtrlKey && !AscCommon.global_keyboardEvent.ShiftKey)
{
if (window.g_asc_plugins)
window.g_asc_plugins.onPluginEvent("onClick");
}
return ret;
};
CTextInputPrototype.onKeyPress = function(e)
{
if (this.Api.isLongAction() || !this.Api.asc_IsFocus() || this.Api.isViewMode)
{
AscCommon.stopEvent(e);
return false;
}
// вся обработка - в onInput
};
CTextInputPrototype.onKeyUp = function(e)
{
if (this.Api.isLongAction())
{
AscCommon.stopEvent(e);
return false;
}
AscCommon.global_keyboardEvent.Up();
this.Api.onKeyUp(e);
};
CTextInputPrototype.onFocusInputText = function()
{
this.onFocusInputTextEnd();
this.checkClearTextOnFocusTimerId = setTimeout(function(){
let _t = AscCommon.g_inputContext;
if (!_t.IsComposition)
_t.clear(true);
}, 500);
};
CTextInputPrototype.onFocusInputTextEnd = function()
{
if (-1 !== this.checkClearTextOnFocusTimerId)
{
clearTimeout(this.checkClearTextOnFocusTimerId);
this.checkClearTextOnFocusTimerId = -1;
}
};
CTextInputPrototype.onInput = function(e)
{
if (this.Api.isLongAction())
{
AscCommon.stopEvent(e);
return false;
}
this.onFocusInputTextEnd();
let type = (e.type ? ("" + e.type) : "undefined");
type = type.toLowerCase()
let newValue = this.getAreaValue();
this.log("onInput: " + newValue);
if (-1 !== newValue.indexOf("&nbsp;"))
newValue = newValue.split("&nbsp;").join(" ");
if (("compositionstart" === type) && this.IsComposition)
{
// не пришел end - пришлем сами
this.compositeEnd();
}
if (("compositionstart" === type || "compositionupdate" === type) && !this.IsComposition)
{
// начался композитный ввод
this.TextBeforeComposition = this.Text;
this.log("compositionStart: " + this.TextBeforeComposition);
this.compositeStart();
}
let lastSymbol = 0;
let newTextLength = 0;
let isAsyncInput = false;
if (this.IsComposition)
{
if (newValue.length >= this.TextBeforeComposition.length)
{
let newText = newValue.substr(this.TextBeforeComposition.length);
this.log("compositionText: " + newText);
let codes = [];
for (let iter = newText.getUnicodeIterator(); iter.check(); iter.next())
codes.push(iter.value());
newTextLength = codes.length;
if (newTextLength > 0)
lastSymbol = codes[newTextLength - 1];
isAsyncInput = this.checkTextInput(codes);
}
}
else
{
// текст может не только добавиться, но и замениться (например на маке зажать i - и выбрать вариант)
let codesOld = [];
for (let iter = this.Text.getUnicodeIterator(); iter.check(); iter.next())
codesOld.push(iter.value());
let codesNew = [];
for (let iter = newValue.getUnicodeIterator(); iter.check(); iter.next())
codesNew.push(iter.value());
let oldLen = codesOld.length;
let newLen = codesNew.length;
let savedLen = (oldLen < newLen) ? oldLen : newLen;
let equalsLen = 0;
for (let i = 0; i < savedLen; i++)
{
if (codesOld[i] !== codesNew[i])
break;
++equalsLen;
}
newTextLength = newLen;
// удаляем то, чего уже нет
let codesRemove = undefined;
if (oldLen > equalsLen)
codesRemove = codesOld.slice(equalsLen);
// удаляем старые из массива
if (0 !== equalsLen)
codesNew.splice(0, equalsLen);
if (codesNew.length > 0)
lastSymbol = codesNew[codesNew.length - 1];
if (10 === lastSymbol)
{
// заглушка на интерфейс (если там enter был нажат - и сначала blur(), и только затем применение).
this.clear();
return;
}
// добавляем новые
isAsyncInput = this.checkTextInput(codesNew, codesRemove);
}
if (("compositionend" === type) && this.IsComposition)
{
// закончился композитный ввод
this.compositeEnd();
this.log("compositionEnd: " + newValue);
}
if (!isAsyncInput)
{
// если асинхронно - то на коллбеке придет onInput - и текст добавится позже
this.Text = newValue;
}
if (window.g_asc_plugins)
window.g_asc_plugins.onPluginEvent("onInputHelperInput", { "text" : this.Text });
if (!this.IsComposition && lastSymbol !== 0 && !isAsyncInput)
{
let isClear = false;
switch (lastSymbol)
{
case 32: // пробел
case 46: // точка
case 44: // запятая
//case 12290: // азиатская точка
//case 65292: // азиатская запятая
{
isClear = true;
break;
}
default:
{
// надеемся, что при вводе все-таки будут точки/пробелы/запятые
// если нет - то не даем копить до бесконечности.
let currentTextLenMax = this.Api.isMobileVersion ? 20 : 100;
if (newTextLength > currentTextLenMax)
isClear = true;
break;
}
}
if (isClear)
this.clear();
}
};
CTextInputPrototype.addText = function(text)
{
this.setAreaValue(this.getAreaValue() + text);
this.onInput({
type : "input",
preventDefault : function() {},
stopPropagation : function() {}
});
};
CTextInputPrototype.compositeStart = function()
{
if (this.IsComposition)
return;
this.IsComposition = true;
this.Api.Begin_CompositeInput();
};
CTextInputPrototype.compositeReplace = function(codes)
{
this.Api.Replace_CompositeText(codes);
};
CTextInputPrototype.compositeEnd = function()
{
if (!this.IsComposition)
return;
this.IsComposition = false;
this.Api.End_CompositeInput();
this.TextBeforeComposition = "";
};
CTextInputPrototype.apiCompositeEnd = function()
{
if (!this.IsComposition)
return;
this.compositeEnd();
this.clear();
};
CTextInputPrototype.checkTextInput = function(codes, codesRemove)
{
var isAsync = AscFonts.FontPickerByCharacter.checkTextLight(codes, true);
if (!isAsync)
{
window.LOCK_DRAW = true;
if (this.IsComposition)
{
this.compositeReplace(codes);
}
else
{
this.addTextCodes(codes, codesRemove);
}
}
else
{
AscFonts.FontPickerByCharacter.loadFonts(this, function ()
{
this.onInput({
type : this.IsComposition ? "compositionupdate" : "input",
preventDefault : function() {},
stopPropagation : function() {}
});
//this.setReadOnly(false);
});
//this.setReadOnly(true);
}
return isAsync;
};
CTextInputPrototype.addTextCodes = function(codes, codesRemove)
{
if (codesRemove && codesRemove.length !== 0)
{
// old version (cells??).
//this.removeText(codesRemove.length);
let resultCorrection = this.Api.asc_correctEnterText(codesRemove, codes);
if (true !== resultCorrection)
this.Api.asc_enterText(codes);
}
else
{
this.Api.asc_enterText(codes);
}
};
/* Old version
CTextInputPrototype.addTextCodes = function(codes)
{
for (let i = 0, len = codes.length; i < len; i++)
{
this.addTextCode(codes[i]);
}
};
CTextInputPrototype.addTextCode = function(code)
{
if (code === 32)
{
if (!this.isSpaceOnKeyDown)
{
// иначе пробел добавился на onKeyDown
let keyObject = this.getKeyboardEventObject(code);
this.Api.onKeyDown(keyObject);
this.Api.onKeyUp(keyObject);
}
return;
}
else
{
// TODO: отдельный метод в апи
// пока имитируем через keyCode - для keyDown/Up - сделаем такой код,
// который ни на что не влияет. код для буквы 'a' - 65
let keyObject = this.getKeyboardEventObject(code);
let keyObjectUpDown = this.getKeyboardEventObject(65);
this.Api.onKeyDown(keyObjectUpDown);
this.Api.onKeyPress(keyObject);
this.Api.onKeyUp(keyObjectUpDown);
}
};
*/
CTextInputPrototype.removeText = function(length)
{
for (let i = 0; i < length; i++)
{
// backspace
let keyObject = this.getKeyboardEventObject(8);
this.Api.onKeyDown(keyObject);
this.Api.onKeyUp(keyObject);
}
};
CTextInputPrototype.emulateKeyDownApi = function(code)
{
let keyObject = this.getKeyboardEventObject(code);
this.Api.onKeyDown(keyObject);
this.Api.onKeyUp(keyObject);
};
// keyboard
CTextInputPrototype.getKeyboardEventObject = function(code)
{
return {
altKey : false,
ctrlKey : false,
shiftKey : false,
target : null,
charCode : 0,
which : code,
keyCode : code,
code : "",
emulated: true,
preventDefault : function() {},
stopPropagation : function() {}
};
};
CTextInputPrototype.emulateNativeKeyDown = function(e, target)
{
var oEvent = document.createEvent('KeyboardEvent');
/*
var _event = new KeyboardEvent("keydown", {
bubbles : true,
cancelable : true,
char : e.charCode,
shiftKey : e.shiftKey,
ctrlKey : e.ctrlKey,
metaKey : e.metaKey,
altKey : e.altKey,
keyCode : e.keyCode,
which : e.which,
key : e.key
});
*/
// Chromium Hack
Object.defineProperty(oEvent, 'keyCode', {
get : function()
{
return this.keyCodeVal;
}
});
Object.defineProperty(oEvent, 'which', {
get : function()
{
return this.keyCodeVal;
}
});
Object.defineProperty(oEvent, 'shiftKey', {
get : function()
{
return this.shiftKeyVal;
}
});
Object.defineProperty(oEvent, 'altKey', {
get : function()
{
return this.altKeyVal;
}
});
Object.defineProperty(oEvent, 'metaKey', {
get : function()
{
return this.metaKeyVal;
}
});
Object.defineProperty(oEvent, 'ctrlKey', {
get : function()
{
return this.ctrlKeyVal;
}
});
if (AscCommon.AscBrowser.isIE)
{
oEvent.preventDefault = function ()
{
try
{
Object.defineProperty(this, "defaultPrevented", {
get: function ()
{
return true;
}
});
}
catch(err)
{
}
};
}
var k = e.keyCode;
if (oEvent.initKeyboardEvent)
{
oEvent.initKeyboardEvent("keydown", true, true, window, false, false, false, false, k, k);
}
else
{
oEvent.initKeyEvent("keydown", true, true, window, false, false, false, false, k, 0);
}
oEvent.keyCodeVal = k;
oEvent.shiftKeyVal = e.shiftKey;
oEvent.altKeyVal = e.altKey;
oEvent.metaKeyVal = e.metaKey;
oEvent.ctrlKeyVal = e.ctrlKey;
var _elem = target ? target : _getElementKeyboardDown(this.nativeFocusElement, 3);
_elem.dispatchEvent(oEvent);
return oEvent.defaultPrevented;
};
//
CTextInputPrototype.getAreaPos = function()
{
var _offset = 0;
if (this.ElementType === InputTextElementType.TextArea)
{
_offset = this.HtmlArea.selectionEnd;
}
else
{
var sel = window.getSelection();
if (sel.rangeCount > 0)
{
var range = sel.getRangeAt(0);
_offset = range.endOffset;
}
}
return _offset;
};
CTextInputPrototype.checkTargetPosition = function(isCorrect)
{
var _offset = this.getAreaPos();
if (false !== isCorrect)
{
var _value = this.getAreaValue();
_offset -= (_value.length - this.compositionValue.length);
}
if (!this.IsLockTargetMode)
{
// никакого смысла прыгать курсором туда-сюда
if (_offset == 0 && this.compositionValue.length == 1)
_offset = 1;
}
this.Api.Set_CursorPosInCompositeText(_offset);
this.unlockTarget();
};
CTextInputPrototype.clear = function(isFromFocus)
{
this.log("clear");
this.TextBeforeComposition = "";
this.Text = "";
this.compositeEnd();
this.clearAreaValue();
if (isFromFocus !== true)
focusHtmlElement(this.getFocusElement());
if (window.g_asc_plugins)
window.g_asc_plugins.onPluginEvent("onInputHelperClear");
};
CTextInputPrototype.getAreaValue = function()
{
return (this.ElementType === InputTextElementType.TextArea) ? this.HtmlArea.value : this.HtmlArea.innerText;
};
CTextInputPrototype.clearAreaValue = function()
{
if (this.ElementType === InputTextElementType.TextArea)
this.HtmlArea.value = "";
else
this.HtmlArea.innerHTML = "";
};
CTextInputPrototype.setAreaValue = function(value)
{
if (this.ElementType === InputTextElementType.TextArea)
this.HtmlArea.value = value;
else
this.HtmlArea.innerHTML = value;
};
CTextInputPrototype.setReadOnly = function(isLock)
{
if (isLock)
this.ReadOnlyCounter++;
else
this.ReadOnlyCounter--;
// при синхронной загрузке шрифтов (десктоп)
// может вызываться и в обратном порядке (setReadOnly(false), setReadOnly(true))
// поэтому сравнение с нулем неверно. отрицательные значение могут быть.
this.setReadOnlyWrapper((0 >= this.ReadOnlyCounter) ? false : true);
};
CTextInputPrototype.setReadOnlyWrapper = function(val)
{
this.HtmlArea.readOnly = this.isDisableKeyboard ? true : val;
};
CTextInputPrototype.setInterfaceEnableKeyEvents = function(value)
{
this.InterfaceEnableKeyEvents = value;
if (true === this.InterfaceEnableKeyEvents)
{
if (document.activeElement)
{
var _id = document.activeElement.id;
if (_id == "area_id" || (window.g_asc_plugins && window.g_asc_plugins.checkRunnedFrameId(_id)))
return;
}
if (!this.isGlobalDisableFocus)
focusHtmlElement(this.getFocusElement());
}
};
CTextInputPrototype.externalEndCompositeInput = function()
{
this.clear();
};
CTextInputPrototype.externalChangeFocus = function()
{
return;
if (!this.IsComposition)
return false;
setTimeout(function() {
window['AscCommon'].g_inputContext.clear();
}, 10);
return true;
};
// html element
CTextInputPrototype.init = function(target_id, parent_id)
{
this.TargetId = target_id;
this.HtmlDiv = document.createElement("div");
this.HtmlDiv.id = "area_id_parent";
this.HtmlDiv.style.background = "transparent";
this.HtmlDiv.style.border = "none";
// в хроме скроллируется редактор, когда курсор текстового поля выходит за пределы окна
if (AscCommon.AscBrowser.isChrome && !TEXT_INPUT_DEBUG)
this.HtmlDiv.style.position = "fixed";
else
this.HtmlDiv.style.position = "absolute";
this.HtmlDiv.style.zIndex = 10;
this.HtmlDiv.style.width = TEXT_INPUT_DEBUG ? "200px" : "20px";
this.HtmlDiv.style.height = "50px";
this.HtmlDiv.style.overflow = "hidden";
this.HtmlDiv.style.boxSizing = "content-box";
this.HtmlDiv.style.webkitBoxSizing = "content-box";
this.HtmlDiv.style.MozBoxSizing = "content-box";
if (this.ElementType === InputTextElementType.TextArea)
{
this.HtmlArea = document.createElement("textarea");
}
else
{
this.HtmlArea = document.createElement("div");
this.HtmlArea.setAttribute("contentEditable", true);
}
this.HtmlArea.id = "area_id";
if (this.Api.isViewMode && this.Api.isMobileVersion)
this.setReadOnlyWrapper(true);
var _style = "";
if (!TEXT_INPUT_DEBUG)
{
_style = ("left:-" + (this.HtmlAreaWidth >> 1) + "px;top:" + (-this.HtmlAreaOffset) + "px;");
_style += "color:transparent;caret-color:transparent;background:transparent;";
if (this.Api.isUseOldMobileVersion())
_style += (AscCommon.AscBrowser.isAppleDevices && !AscCommon.AscBrowser.isTelegramWebView && (AscCommon.AscBrowser.maxTouchPoints > 0)) ? "font-size:0px;" : "font-size:8px;";
else
_style += "font-size:8px;";
}
else
{
_style = "left:0px;top:0px;color:black;caret-color:black;font-size:16px;background:transparent;";
}
_style += ("border:none;position:absolute;text-shadow:0 0 0 #000;outline:none;width:" + this.HtmlAreaWidth + "px;height:50px;");
_style += "overflow:hidden;padding:0px;margin:0px;font-family:arial;resize:none;font-weight:normal;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;";
_style += "touch-action: none;-webkit-touch-callout: none;";
this.HtmlArea.setAttribute("style", _style);
this.HtmlArea.setAttribute("spellcheck", false);
this.HtmlArea.setAttribute("autocapitalize", "none");
if(AscCommon.AscBrowser.isChrome)
{
//Bug in Chrome. Autofill does not respect autocomplete="off"
//https://bugs.chromium.org/p/chromium/issues/detail?id=914451
this.HtmlArea.setAttribute("autocomplete", "extremely_off");
}
else
{
this.HtmlArea.setAttribute("autocomplete", "off");
}
this.HtmlArea.setAttribute("autocorrect", "off");
this.HtmlDiv.appendChild(this.HtmlArea);
this.appendInputToCanvas(parent_id);
// events:
var oThis = this;
this.HtmlArea["onkeydown"] = function(e)
{
if (AscCommon.AscBrowser.isSafariMacOs)
{
var cmdButton = (e.ctrlKey || e.metaKey) ? true : false;
var buttonCode = ((e.keyCode == 67) || (e.keyCode == 88) || (e.keyCode == 86));
if (cmdButton && buttonCode)
oThis.IsDisableKeyPress = true;
else
oThis.IsDisableKeyPress = false;
}
return oThis.onKeyDown(e);
};
this.HtmlArea["onkeypress"] = function(e)
{
if (oThis.IsDisableKeyPress == true)
{
// macOS Sierra send keypress before copy event
oThis.IsDisableKeyPress = false;
var cmdButton = (e.ctrlKey || e.metaKey) ? true : false;
if (cmdButton)
return;
}
return oThis.onKeyPress(e);
};
this.HtmlArea["onkeyup"] = function(e)
{
oThis.IsDisableKeyPress = false;
return oThis.onKeyUp(e);
};
var inputEvents = ["input", /*"textInput", */"compositionstart", "compositionupdate", "compositionend"];
for (let i = 0, len = inputEvents.length; i < len; i++)
{
this.HtmlArea.addEventListener(inputEvents[i], function(e)
{
return oThis.onInput(e);
}, false);
}
this.Api.Input_UpdatePos();
this.checkViewMode();
};
CTextInputPrototype.appendInputToCanvas = function(parent_id)
{
let oHtmlParent;
if (undefined === parent_id)
oHtmlParent = document.getElementById(this.TargetId).parentNode;
else
oHtmlParent = document.getElementById(parent_id);
// нужен еще один родитель. чтобы скроллился он, а не oHtmlParent
var oHtmlDivScrollable = document.createElement("div");
oHtmlDivScrollable.id = "area_id_main";
let styleZIndex = TEXT_INPUT_DEBUG ? "z-index:50;" : "z-index:0;";
oHtmlDivScrollable.setAttribute("style", "background:transparent;border:none;position:absolute;padding:0px;margin:0px;pointer-events:none;" + styleZIndex);
var parentStyle = getComputedStyle(oHtmlParent);
oHtmlDivScrollable.style.left = parentStyle.left;
oHtmlDivScrollable.style.top = parentStyle.top;
oHtmlDivScrollable.style.width = parentStyle.width;
oHtmlDivScrollable.style.height = parentStyle.height;
oHtmlDivScrollable.style.overflow = "hidden";
oHtmlDivScrollable.appendChild(this.HtmlDiv);
oHtmlParent.parentNode.appendChild(oHtmlDivScrollable);
};
CTextInputPrototype.onResize = function(editorContainerId)
{
var _elem = document.getElementById("area_id_main");
var _elemSrc = document.getElementById(editorContainerId);
if (!_elem || !_elemSrc)
return;
if (AscCommon.AscBrowser.isChrome)
{
var rectObject = AscCommon.UI.getBoundingClientRect(_elemSrc);
this.FixedPosCheckElementX = rectObject.left;
this.FixedPosCheckElementY = rectObject.top;
}
var _width = _elemSrc.style.width;
if ((null == _width || "" == _width) && window.getComputedStyle)
{
var _s = window.getComputedStyle(_elemSrc);
_elem.style.left = _s.left;
_elem.style.top = _s.top;
_elem.style.width = _s.width;
_elem.style.height = _s.height;
}
else
{
_elem.style.left = _elemSrc.style.left;
_elem.style.top = _elemSrc.style.top;
_elem.style.width = _width;
_elem.style.height = _elemSrc.style.height;
}
if (this.Api.isUseOldMobileVersion())
{
var _elem1 = document.getElementById("area_id_parent");
var _elem2 = document.getElementById("area_id");
_elem1.parentNode.style.pointerEvents = "";
_elem1.style.left = "0px";
let topStyle = "-1000px";
if (AscCommon.AscBrowser.isTelegramWebView)
{
if (!AscCommon.AscBrowser.isAndroid && !AscCommon.AscBrowser.isAppleDevices)
topStyle = "0px";
else if (AscCommon.AscBrowser.isAppleDevices && navigator.maxTouchPoints === 0)
topStyle = "0px";
}
_elem1.style.top = topStyle;
_elem1.style.right = "0px";
_elem1.style.bottom = "-100px";
_elem1.style.width = "auto";
_elem1.style.height = "auto";
_elem2.style.left = "0px";
_elem2.style.top = "0px";
_elem2.style.right = "0px";
_elem2.style.bottom = "0px";
_elem2.style.width = "100%";
_elem2.style.height = "100%";
if (AscCommon.AscBrowser.isIE)
{
document.body.style["msTouchAction"] = "none";
document.body.style["touchAction"] = "none";
}
}
var _editorSdk = document.getElementById("editor_sdk");
this.editorSdkW = _editorSdk.clientWidth;
this.editorSdkH = _editorSdk.clientHeight;
};
CTextInputPrototype.checkFocus = function()
{
if (this.Api.asc_IsFocus() && !AscCommon.g_clipboardBase.IsFocus() && !AscCommon.g_clipboardBase.IsWorking())
{
if (document.activeElement != this.getFocusElement())
focusHtmlElement(this.getFocusElement());
}
};
CTextInputPrototype.moveAccurate = function(x, y)
{
if (!this.moveAccurateFunc)
{
this.moveAccurateFunc = function() {
let ctx = AscCommon.g_inputContext;
ctx.move(ctx.moveAccurateInfo.x, ctx.moveAccurateInfo.y);
ctx.moveAccurateInfo.id = -1;
};
}
if (-1 !== this.moveAccurateInfo.id)
clearTimeout(this.moveAccurateInfo.id);
this.moveAccurateInfo.x = x;
this.moveAccurateInfo.y = y;
this.moveAccurateInfo.id = setTimeout(this.moveAccurateFunc, 20);
};
CTextInputPrototype.move = function(x, y)
{
if (this.Api.isUseOldMobileVersion())
return;
var oTarget = document.getElementById(this.TargetId);
if (!oTarget)
return;
var xPos = x ? x : parseInt(oTarget.style.left);
var yPos = (y ? y : parseInt(oTarget.style.top)) + parseInt(oTarget.style.height);
if (AscCommon.AscBrowser.isSafari && AscCommon.AscBrowser.isMobile)
xPos = -100;
if (this.Api.editorId === AscCommon.c_oEditorId.Presentation)
{
let offset = this.Api.getTextInputOffset();
xPos += offset.X;
yPos += offset.Y;
}
this.HtmlDiv.style.left = xPos + this.FixedPosCheckElementX + "px";
this.HtmlDiv.style.top = yPos + this.FixedPosCheckElementY + this.TargetOffsetY + this.HtmlAreaOffset + "px";
this.HtmlArea.scrollTop = this.HtmlArea.scrollHeight;
//this.log("" + this.HtmlArea.scrollTop + ", " + this.HtmlArea.scrollHeight);
if (window.g_asc_plugins)
window.g_asc_plugins.onPluginEvent("onTargetPositionChanged");
};
// virtual keyboard
CTextInputPrototype.preventVirtualKeyboard = function(e)
{
if (this.isHardCheckKeyboard)
return;
//AscCommon.stopEvent(e);
if (AscCommon.AscBrowser.isAndroid)
{
this.setReadOnlyWrapper(true);
if (this.virtualKeyboardReadOnly_ShowKeyboard)
return;
this.virtualKeyboardClickTimeout = setTimeout(function ()
{
window['AscCommon'].g_inputContext.setReadOnlyWrapper(false);
window['AscCommon'].g_inputContext.virtualKeyboardClickTimeout = -1;
}, 1);
}
};
CTextInputPrototype.enableVirtualKeyboard = function()
{
if (this.isHardCheckKeyboard)
return;
if (AscCommon.AscBrowser.isAndroid)
{
if (this.virtualKeyboardReadOnly_ShowKeyboard)
return;
if (-1 != this.virtualKeyboardClickTimeout)
{
clearTimeout(this.virtualKeyboardClickTimeout);
this.virtualKeyboardClickTimeout = -1;
}
this.setReadOnlyWrapper(false);
}
};
CTextInputPrototype.preventVirtualKeyboard_Hard = function()
{
this.setReadOnlyWrapper(true);
};
CTextInputPrototype.enableVirtualKeyboard_Hard = function()
{
this.setReadOnlyWrapper(false);
};
CTextInputPrototype.showKeyboard = function()
{
if (this.virtualKeyboardReadOnly_ShowKeyboard)
{
if (this.HtmlArea.readOnly === true)
{
this.setReadOnlyWrapper(false);
}
}
if (!this.Api.asc_IsFocus())
this.Api.asc_enableKeyEvents(true);
else
focusHtmlElement(this.getFocusElement());
}
CTextInputPrototype.checkViewMode = function()
{
let oldDisableKeyboard = this.isDisableKeyboard;
this.isDisableKeyboard = this.Api.isViewMode;
if (!this.isDisableKeyboard)
{
switch (this.Api.editorId)
{
case AscCommon.c_oEditorId.Word:
{
// use canEnterText instead this
break;
}
case AscCommon.c_oEditorId.Presentation:
case AscCommon.c_oEditorId.Spreadsheet:
{
if (this.Api.isRestrictionView() && !this.Api.isRestrictionForms())
this.isDisableKeyboard = true;
break;
}
default:
break;
}
}
if (oldDisableKeyboard !== this.isDisableKeyboard)
{
this.setReadOnlyWrapper(false);
}
};
CTextInputPrototype.getFocusElement = function()
{
return this.Api.getFocusElement();
};
function _getAttirbute(_elem, _attr, _depth)
{
var _elemTest = _elem;
for (var _level = 0; _elemTest && (_level < _depth); ++_level, _elemTest = _elemTest.parentNode)
{
var _res = _elemTest.getAttribute ? _elemTest.getAttribute(_attr) : null;
if (null != _res)
return _res;
}
return null;
}
function _getElementKeyboardDown(_elem, _depth)
{
var _elemTest = _elem;
for (var _level = 0; _elemTest && (_level < _depth); ++_level, _elemTest = _elemTest.parentNode)
{
var _res = _elemTest.getAttribute ? _elemTest.getAttribute("oo_editor_keyboard") : null;
if (null != _res)
return _elemTest;
}
return null;
}
function _getDefaultKeyboardInput(_elem, _depth)
{
var _elemTest = _elem;
for (var _level = 0; _elemTest && (_level < _depth); ++_level, _elemTest = _elemTest.parentNode)
{
var _name = " " + _elemTest.className + " ";
if (_name.indexOf(" dropdown-menu" ) > -1 ||
_name.indexOf(" dropdown-toggle ") > -1 ||
_name.indexOf(" dropdown-submenu ") > -1 ||
_name.indexOf(" canfocused ") > -1)
{
return "true";
}
}
return null;
}
window['AscCommon'] = window['AscCommon'] || {};
window['AscCommon'].CTextInput = CTextInput2;
window['AscCommon'].InitBrowserInputContext = function(api, target_id, parent_id)
{
if (window['AscCommon'].g_inputContext)
return;
window['AscCommon'].g_inputContext = new CTextInput2(api);
window['AscCommon'].g_inputContext.init(target_id, parent_id);
window['AscCommon'].g_clipboardBase.Init(api);
window['AscCommon'].g_clipboardBase.inputContext = window['AscCommon'].g_inputContext;
window['AscCommon'].inputMethodCheckInitEvents();
if (window['AscCommon'].TextBoxInputMode === true)
{
window['AscCommon'].g_inputContext.systemInputEnable(true);
}
//window["SetInputDebugMode"]();
document.addEventListener("focus", function(e)
{
var t = window['AscCommon'].g_inputContext;
var _oldNativeFE = t.nativeFocusElement;
t.nativeFocusElement = e.target;
t.log("focus");
if (t.IsComposition)
{
t.compositeEnd();
t.externalEndCompositeInput();
}
t.onFocusInputText();
/*
if (!t.isNoClearOnFocus)
t.clear(true);
t.isNoClearOnFocus = false;
*/
t.Api.isBlurEditor = false;
var _nativeFocusElementNoRemoveOnElementFocus = t.nativeFocusElementNoRemoveOnElementFocus;
t.nativeFocusElementNoRemoveOnElementFocus = false;
if (t.InterfaceEnableKeyEvents == false)
{
t.nativeFocusElement = null;
return;
}
if (t.nativeFocusElement && (t.nativeFocusElement.id == t.getFocusElement().id))
{
t.Api.asc_enableKeyEvents(true, true);
if (_nativeFocusElementNoRemoveOnElementFocus)
t.nativeFocusElement = _oldNativeFE;
else
t.nativeFocusElement = null;
return;
}
if (t.nativeFocusElement && (t.nativeFocusElement.id == window['AscCommon'].g_clipboardBase.CommonDivId))
{
t.nativeFocusElement = null;
return;
}
t.nativeFocusElementNoRemoveOnElementFocus = false;
var _isElementEditable = false;
if (t.nativeFocusElement)
{
// detect _isElementEditable
var _name = t.nativeFocusElement.nodeName;
if (_name)
_name = _name.toUpperCase();
if ("INPUT" == _name || "TEXTAREA" == _name)
_isElementEditable = true;
else if ("DIV" == _name)
{
if (t.nativeFocusElement.getAttribute("contenteditable") == "true")
_isElementEditable = true;
}
}
if ("IFRAME" == _name)
{
// перехват клавиатуры
t.Api.asc_enableKeyEvents(false, true);
t.nativeFocusElement = null;
return;
}
// перехватывает ли элемент ввод
var _oo_editor_input = _getAttirbute(t.nativeFocusElement, "oo_editor_input", 3);
// нужно ли прокидывать нажатие клавиш элементу (ТОЛЬКО keyDown)
var _oo_editor_keyboard = _getAttirbute(t.nativeFocusElement, "oo_editor_keyboard", 3);
if (!_oo_editor_input && !_oo_editor_keyboard)
_oo_editor_input = _getDefaultKeyboardInput(t.nativeFocusElement, 3);
if (_oo_editor_keyboard == "true")
_oo_editor_input = undefined;
if (_oo_editor_input == "true")
{
// перехват клавиатуры
t.Api.asc_enableKeyEvents(false, true);
t.nativeFocusElement = null;
return;
}
if (_isElementEditable && (_oo_editor_input != "false"))
{
// перехват клавиатуры
t.Api.asc_enableKeyEvents(false, true);
t.nativeFocusElement = null;
return;
}
// итак, ввод у нас. теперь определяем, нужна ли клавиатура элементу
if (_oo_editor_keyboard != "true")
t.nativeFocusElement = null;
var _elem = t.nativeFocusElement;
t.nativeFocusElementNoRemoveOnElementFocus = true; // ie focus async
AscCommon.AscBrowser.isMozilla ? setTimeout(function(){ focusHtmlElement(t.getFocusElement()); }, 0) : focusHtmlElement(t.getFocusElement());
t.nativeFocusElement = _elem;
t.Api.asc_enableKeyEvents(true, true);
}, true);
// send focus
if (!api.isMobileVersion && !api.isEmbedVersion)
focusHtmlElement(api.getFocusElement());
};
function focusHtmlElement(element)
{
element.focus();
/*
var api = window['AscCommon'].g_inputContext.Api;
if (api.isMobileVersion)
element.focus();
else
element.focus({ "preventScroll" : true });
*/
};
window["SetInputDebugMode"] = function()
{
if (!window['AscCommon'].g_inputContext)
return;
window['AscCommon'].g_inputContext.debugInputEnable(true);
window['AscCommon'].g_inputContext.show();
};
window['AscCommon'].StartIntervalDrawText = function (isStart) {
if (isStart) {
window.renderIntervalId = setInterval(function(){
window.LOCK_DRAW = false;
if (undefined !== window.TEXT_DRAW_INSTANCE)
window.TEXT_DRAW_INSTANCE._renderText(window.TEXT_DRAW_INSTANCE_POS);
window.TEXT_DRAW_INSTANCE = undefined;
window.TEXT_DRAW_INSTANCE_POS = 0;
}, 20);
} else {
clearInterval(window.renderIntervalId);
}
};
/*
UNCOMMENT FOR DETECT FOCUS INITIALIZER
{
focusHtmlElement = function(element)
{
window.disableFocusDebugger = true;
element.focus();
delete window.disableFocusDebugger;
}
const originalFocus = HTMLElement.prototype.focus;
HTMLElement.prototype.focus = function(...args)
{
if (!window.disableFocusDebugger)
debugger;
console.log("FOCUS:", this);
originalFocus.apply(this, args);
};
}
*/
})(window);