1547 lines
41 KiB
JavaScript
1547 lines
41 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";
|
||
|
||
(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(" "))
|
||
newValue = newValue.split(" ").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);
|