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);
|