1
0
mirror of https://github.com/ONLYOFFICE/sdkjs.git synced 2025-09-16 17:03:31 +03:00
Files
sdkjs/common/text_input.js
2024-04-23 19:18:31 +03:00

1735 lines
44 KiB
JavaScript
Raw Permalink 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)
///
function CKeyboardEventWrapper(e)
{
// emulate
this.altKey = e.altKey;
this.ctrlKey = e.ctrlKey;
this.metaKey = e.metaKey;
this.shiftKey = e.shiftKey;
this.charCode = e.charCode;
this.keyCode = e.keyCode;
this.which = e.which;
this.code = e.code;
this.key = e.key;
this.srcElement = e.srcElement;
this.target = e.target;
// work
this._isDefaultPrevented = false;
}
CKeyboardEventWrapper.prototype =
{
preventDefault : function()
{
this._isDefaultPrevented = true;
},
stopPropagation : function()
{
// nothing
}
};
function CTextInput(api)
{
this.Api = api;
this.TargetId = null; // id caret
this.HtmlDiv = null; // для незаметной реализации одной textarea недостаточно
this.TextArea_Not_ContentEditableDiv = true;
this.HtmlArea = null;
this.HtmlAreaOffset = 50; // height in pix
this.HtmlAreaWidth = 200;
this.LockerTargetTimer = -1;
this.KeyDownFlag = false;
this.KeyPressFlag = false;
this.IsLockTargetMode = false;
this.nativeFocusElement = null;
this.nativeFocusElementNoRemoveOnElementFocus = false;
this.InterfaceEnableKeyEvents = true;
this.debugTexBoxMaxW = 100;
this.debugTexBoxMaxH = 20;
this.isDebug = false;
this.isSystem = false;
this.isShow = false;
// chrome element for left/top
this.FixedPosCheckElementX = 0;
this.FixedPosCheckElementY = 0;
this.virtualKeyboardClickTimeout = -1;
this.virtualKeyboardClickPrevent = false;
// current text info
this.TextBeforeComposition = "";
this.Text = "";
this.Target = 0;
this.CompositionStart = 0;
this.CompositionEnd = 0;
this.IsComposition = false;
this.ApiIsComposition = false;
// Notes offset for slides
this.TargetOffsetY = 0;
// editor_sdk div sizes (for visible textarea)
this.editorSdkW = 0;
this.editorSdkH = 0;
this.ReadOnlyCounter = 0;
this.LastReplaceText = [];
this.IsLastReplaceFlag = false;
this.isNoClearOnFocus = false;
this.keyPressInput = "";
this.isInputHelpersPresent = false;
this.isInputHelpers = {};
this.isKeyPressOnUp = AscCommon.AscBrowser.isAppleDevices; // keyPress может приходить ДО oncompositionstart, а это проблема.
this.keyPressOnUpCodes = [];
this.isKeyPressOnUpStackedMode = this.isKeyPressOnUp;
this.isHardCheckKeyboard = AscCommon.AscBrowser.isSailfish;
}
CTextInput.prototype =
{
log : function(_val)
{
//console.log(_val);
},
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)
this.HtmlDiv.style.position = "fixed";
else
this.HtmlDiv.style.position = "absolute";
this.HtmlDiv.style.zIndex = 10;
this.HtmlDiv.style.width = "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.TextArea_Not_ContentEditableDiv)
{
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 = ("left:-" + (this.HtmlAreaWidth >> 1) + "px;top:" + (-this.HtmlAreaOffset) + "px;");
_style += ("background:transparent;border:none;position:absolute;text-shadow:0 0 0 #000;outline:none;color:transparent;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;color:transparent;caret-color:transparent;";
_style += AscCommon.AscBrowser.isAppleDevices ? "font-size:0px;" : "font-size:8px;"
this.HtmlArea.setAttribute("style", _style);
this.HtmlArea.setAttribute("spellcheck", false);
this.HtmlArea.setAttribute("autocapitalize", "none");
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);
};
this.HtmlArea.addEventListener("input", function(e)
{
return oThis.onInput(e);
}, false);
this.HtmlArea.addEventListener("compositionstart", function(e)
{
return oThis.onCompositionStart(e);
}, false);
this.HtmlArea.addEventListener("compositionupdate", function(e)
{
return oThis.onCompositionUpdate(e);
}, false);
this.HtmlArea.addEventListener("compositionend", function(e)
{
return oThis.onCompositionEnd(e);
}, false);
this.show();
this.Api.Input_UpdatePos();
if (AscCommon.AscBrowser.isAndroid)
{
this.HtmlArea.onclick = function (e)
{
var _this = AscCommon.g_inputContext;
if (-1 != _this.virtualKeyboardClickTimeout)
{
clearTimeout(_this.virtualKeyboardClickTimeout);
_this.virtualKeyboardClickTimeout = -1;
}
_this.apiCompositeEnd();
if (!_this.virtualKeyboardClickPrevent)
return;
_this.setReadOnlyWrapper(true);
_this.virtualKeyboardClickPrevent = false;
AscCommon.stopEvent(e);
_this.virtualKeyboardClickTimeout = setTimeout(function ()
{
_this.setReadOnlyWrapper(false);
_this.virtualKeyboardClickTimeout = -1;
}, 1);
return false;
};
}
},
appendInputToCanvas: function (parent_id) {
var oHtmlParent = null;
var oHtmlTarget = document.getElementById(this.TargetId);
if (undefined == parent_id)
oHtmlParent = oHtmlTarget.parentNode;
else
oHtmlParent = document.getElementById(parent_id);
// нужен еще один родитель. чтобы скроллился он, а не oHtmlParent
var oHtmlDivScrollable = document.createElement("div");
oHtmlDivScrollable.id = "area_id_main";
oHtmlDivScrollable.setAttribute("style", "background:transparent;border:none;position:absolute;padding:0px;margin:0px;z-index:0;pointer-events:none;");
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);
},
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 = _elemSrc.getBoundingClientRect();
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.isMobileVersion)
{
var _elem1 = document.getElementById("area_id_parent");
var _elem2 = document.getElementById("area_id");
_elem1.parentNode.style.pointerEvents = "";
_elem1.style.left = "0px";
_elem1.style.top = "-1000px";
_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;
},
checkFocus : function()
{
if (this.Api.asc_IsFocus() && !AscCommon.g_clipboardBase.IsFocus() && !AscCommon.g_clipboardBase.IsWorking())
{
if (document.activeElement != this.HtmlArea)
focusHtmlElement(this.HtmlArea);
}
},
move : function(x, y)
{
if (this.Api.isMobileVersion)
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.isDebug && !this.isSystem)
{
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);
}
else
{
// this.HtmlAreaOffset - не сдвигаем, курсор должен быть виден
this.debugCalculatePlace(xPos + this.FixedPosCheckElementX, yPos + this.FixedPosCheckElementY + this.TargetOffsetY);
}
if (window.g_asc_plugins)
window.g_asc_plugins.onPluginEvent("onTargetPositionChanged");
},
emulateKeyDownApi : function(code)
{
var _e = {
altKey : false,
ctrlKey : false,
shiftKey : false,
target : null,
charCode : 0,
which : code,
keyCode : code,
code : "",
emulated: true,
preventDefault : function() {},
stopPropagation : function() {}
};
this.Api.onKeyDown(_e);
this.Api.onKeyUp(_e);
},
clear : function(isFromFocus)
{
if (!this.TextArea_Not_ContentEditableDiv)
{
this.HtmlArea.innerHTML = "";
}
else
{
this.HtmlArea.value = "";
}
if (isFromFocus !== true)
focusHtmlElement(this.HtmlArea);
this.TextBeforeComposition = "";
this.Text = "";
this.Target = 0;
this.CompositionStart = 0;
this.CompositionEnd = 0;
this.IsComposition = false;
this.keyPressInput = "";
if (window.g_asc_plugins)
window.g_asc_plugins.onPluginEvent("onInputHelperClear");
},
getAreaValue : function()
{
return this.TextArea_Not_ContentEditableDiv ? this.HtmlArea.value : this.HtmlArea.innerText;
},
setReadOnly : function(isLock)
{
if (isLock)
this.ReadOnlyCounter++;
else
this.ReadOnlyCounter--;
// при синхронной загрузке шрифтов (десктоп)
// может вызываться и в обратном порядке (setReadOnly(false), setReadOnly(true))
// поэтому сравнение с нулем неверно. отрицательные значение могут быть.
this.setReadOnlyWrapper((0 >= this.ReadOnlyCounter) ? false : true);
},
setReadOnlyWrapper : function(val)
{
this.HtmlArea.readOnly = this.Api.isViewMode ? true : val;
},
show : function()
{
if (this.isDebug || this.isSystem)
{
this.log("ti: show");
document.getElementById("area_id_main").style.zIndex = 10;
this.HtmlArea.style.top = "0px";
this.HtmlArea.style.width = "100%";
this.HtmlArea.style.height = "100%";
this.HtmlArea.style.background = "#FFFFFF";
this.HtmlArea.style.color = "black";
this.HtmlDiv.style.zIndex = 90;
this.HtmlDiv.style.border = "2px solid #4363A4";
this.isShow = true;
}
},
unshow : function(isAttack)
{
if (this.isDebug || this.isSystem || (true == isAttack))
{
this.log("ti: unshow");
document.getElementById("area_id_main").style.zIndex = 0;
this.HtmlArea.style.top = ((-this.HtmlAreaOffset) + "px");
this.HtmlArea.style.width = "1000px";
this.HtmlArea.style.height = "50px";
this.HtmlArea.style.background = "transparent";
this.HtmlArea.style.color = "transparent";
this.HtmlDiv.style.zIndex = 0;
this.HtmlDiv.style.border = "none";
this.isShow = false;
}
},
debugCalculatePlace : function(x, y)
{
var _left = x;
var _top = y;
if (undefined == _left)
_left = parseInt(this.HtmlDiv.style.left);
if (undefined == _top)
_top = parseInt(this.HtmlDiv.style.top);
var _r_max = this.editorSdkW;
var _b_max = this.editorSdkH;
_r_max -= 60;
if ((_r_max - _left) > 50)
{
this.debugTexBoxMaxW = _r_max - _left;
}
else
{
_left = _r_max - 50;
this.debugTexBoxMaxW = 50;
}
_b_max -= 40;
if ((_b_max - _top) > 50)
{
this.debugTexBoxMaxH = _b_max - _top;
}
else
{
_top = _b_max - 50;
this.debugTexBoxMaxH = 50;
}
if (AscCommon.AscBrowser.isSafari && AscCommon.AscBrowser.isMobile)
_left = -100;
this.HtmlDiv.style.left = _left + "px";
this.HtmlDiv.style.top = _top + "px";
var _height = 22;
var _t = this.getAreaValue();
if (0 != _t.length)
{
var _editorSdk = document.getElementById("editor_sdk");
// теперь нужно расчитать ширину/высоту текстбокса
var _p = document.createElement('p');
_p.style.zIndex = "-1";
_p.style.position = "absolute";
_p.style.fontFamily = "arial";
_p.style.fontSize = "12pt";
_p.style.left = "0px";
_p.style.width = this.debugTexBoxMaxW + "px";
_editorSdk.appendChild(_p);
_t = _t.replace(/ /g, " ");
_p.innerHTML = "<span>" + _t + "</span>";
var _width = _p.firstChild.offsetWidth;
_width = Math.min(_width + 20, this.debugTexBoxMaxW);
if (AscCommon.AscBrowser.isIE)
_width += 10;
var area = document.createElement('textarea');
area.style.zIndex = "-1";
area.id = "area2_id";
area.rows = 1;
area.setAttribute("style", "font-family:arial;font-size:12pt;position:absolute;resize:none;padding:0px;margin:0px;font-weight:normal;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;");
area.style.overflow = "hidden";
area.style.width = _width + "px";
_editorSdk.appendChild(area);
area.value = this.getAreaValue();
_height = area.clientHeight;
if (area.scrollHeight > _height)
_height = area.scrollHeight;
_editorSdk.removeChild(_p);
_editorSdk.removeChild(area);
}
if (_height > this.debugTexBoxMaxH)
_height = this.debugTexBoxMaxH;
this.HtmlDiv.style.width = _width + "px";
this.HtmlDiv.style.height = _height + "px";
// вот такая заглушка под firefox если этого не делать, то будет плохо перерисовываться border)
var oldZindex = parseInt(this.HtmlDiv.style.zIndex);
var newZindex = (oldZindex == 90) ? "89" : "90";
this.HtmlDiv.style.zIndex = newZindex;
},
onInput : function(e, isFromCompositionUpdate)
{
if (this.Api.isLongAction() || this.Api.isViewMode)
{
AscCommon.stopEvent(e);
return false;
}
if (this.isSystem)
{
if (!this.isShow)
this.show();
this.debugCalculatePlace(undefined, undefined);
return;
}
if (this.isKeyPressOnUp && this.keyPressOnUpCodes.length > 0)
{
// clear light
if (!this.TextArea_Not_ContentEditableDiv)
{
this.HtmlArea.innerHTML = "";
}
else
{
this.HtmlArea.value = "";
}
this.TextBeforeComposition = "";
this.Text = "";
AscCommon.stopEvent(e);
return false;
}
this.log("ti: onInput");
// current text value
this.Text = this.getAreaValue();
this.Text = this.Text.split("&nbsp;").join(" ");
var codes = [];
if (this.IsComposition || this.ApiIsComposition)
{
var ieStart = -1;
var ieEnd = -1;
if (true)
{
var target = e.target;
if (target["msGetInputContext"])
{
var ctx = target["msGetInputContext"]();
if (ctx)
{
ieStart = ctx["compositionStartOffset"];
ieEnd = ctx["compositionEndOffset"];
}
}
}
this.CompositionEnd = this.Text.length;
this.CompositionStart = this.TextBeforeComposition.length;
var textReplace = this.Text.substr(this.CompositionStart);
var iter;
for (iter = textReplace.getUnicodeIterator(); iter.check(); iter.next())
{
codes.push(iter.value());
}
var isAsync = AscFonts.FontPickerByCharacter.checkTextLight(codes, true);
if (!isAsync)
{
// ie/edge могут не присылать onCompositeEnd. И тогда ориентир - дополнительный селект
if (ieStart > this.CompositionStart)
{
textReplace = textReplace.substr(0, ieStart - this.CompositionStart);
codes = [];
for (iter = textReplace.getUnicodeIterator(); iter.check(); iter.next())
{
codes.push(iter.value());
}
this.apiCompositeReplace(codes);
this.apiCompositeEnd();
this.TextBeforeComposition = this.Text.substr(0, ieStart);
this.apiCompositeStart();
this.CompositionStart = ieStart;
codes = [];
textReplace = this.Text.substr(this.CompositionStart);
for (iter = textReplace.getUnicodeIterator(); iter.check(); iter.next())
{
codes.push(iter.value());
}
this.apiCompositeReplace(codes);
}
else
{
this.apiCompositeReplace(codes);
}
if (!this.IsComposition)
{
this.apiCompositeEnd();
this.TextBeforeComposition = this.Text;
}
}
else
{
AscFonts.FontPickerByCharacter.loadFonts(this, function ()
{
this.apiCompositeReplace(codes);
this.apiCompositeEnd();
this.clear();
this.setReadOnly(false);
});
AscCommon.stopEvent(e);
this.setReadOnly(true);
return false;
}
}
else
{
var textToApi = this.Text.substr(this.TextBeforeComposition.length);
for (var iter = textToApi.getUnicodeIterator(); iter.check(); iter.next())
{
codes.push(iter.value());
}
if (codes.length > 0)
{
this.apiInputText(codes);
}
this.TextBeforeComposition = this.Text;
}
if (!this.IsComposition)
{
if (this.Text.length > 0)
{
var _lastCode = this.Text.charCodeAt(this.Text.length - 1);
if (_lastCode == 12290 || _lastCode == 46)
{
// китайская точка
AscCommon.stopEvent(e);
if (AscCommon.AscBrowser.isIE && !AscCommon.AscBrowser.isIeEdge)
{
// ie тепряет фокус
setTimeout(function(){
window['AscCommon'].g_inputContext.clear();
focusHtmlElement(window['AscCommon'].g_inputContext.HtmlArea);
}, 0);
}
else
{
this.clear();
}
return false;
}
}
}
},
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;
},
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;
},
systemInputEnable : function(isEnabled)
{
if (this.isSystem == isEnabled)
return;
this.isSystem = isEnabled;
this.HtmlArea.style.left = this.isSystem ? "0px" : ("-" + (this.HtmlAreaWidth >> 1) + "px");
this.clear();
if (this.isShow)
this.unshow(true);
if (this.Api.WordControl && this.Api.WordControl.m_oLogicDocument && this.Api.WordControl.m_oLogicDocument.Document_UpdateSelectionState)
this.Api.WordControl.m_oLogicDocument.Document_UpdateSelectionState();
},
debugInputEnable : function(isEnabled)
{
if (this.isDebug == isEnabled)
return;
this.isDebug = isEnabled;
this.HtmlArea.style.left = this.isDebug ? "0px" : ("-" + (this.HtmlAreaWidth >> 1) + "px");
},
apiInputText : function(codes)
{
var isAsync = AscFonts.FontPickerByCharacter.checkTextLight(codes, true);
if (!isAsync)
{
this.apiCompositeStart();
this.apiCompositeReplace(codes);
this.apiCompositeEnd();
}
else
{
AscFonts.FontPickerByCharacter.loadFonts(this, function ()
{
this.apiCompositeStart();
this.apiCompositeReplace(codes);
this.apiCompositeEnd();
this.setReadOnly(false);
});
this.setReadOnly(true);
return false;
}
},
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 }, this.isInputHelpers);
AscCommon.stopEvent(e);
return false;
}
case 32:
{
// send, but not prevent
//window.g_asc_plugins.onPluginEvent2("onKeyDown", { "keyCode" : e.keyCode }, this.isInputHelpers);
//теперь пробел - на keyPress - и добавится там
//this.keyPressInput += " ";
if (window.g_asc_plugins)
window.g_asc_plugins.onPluginEvent("onInputHelperInput", { "text" : this.keyPressInput });
}
default:
break;
}
}
else if (32 == e.keyCode)
{
//теперь пробел - на keyPress - и добавится там
//this.keyPressInput += " ";
}
if (this.isSystem && this.isShow)
{
// нужно проверить на enter
// вся остальная обработка - в текстбоксе
if (e.keyCode == 13)
{
var text = this.getAreaValue();
var codes = [];
for (var iter = text.getUnicodeIterator(); iter.check(); iter.next())
{
codes.push(iter.value());
}
this.apiInputText(codes);
this.clear();
this.unshow();
AscCommon.stopEvent(e);
return false;
}
else if (e.keyCode == 27)
{
this.clear();
this.unshow();
AscCommon.stopEvent(e);
return false;
}
// вся обработка - в текстбоксе
return;
}
if (null != this.nativeFocusElement)
{
if (this.emulateNativeKeyDown(e))
{
e.preventDefault();
return false;
}
}
// некоторые рукописные вводы не присылают keyUp
var _code = e.keyCode;
if (_code != 8 && _code != 46)
this.KeyDownFlag = true;
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);
});
AscCommon.stopEvent(e);
this.setReadOnly(true);
return false;
}
var ret = this.Api.onKeyDown(e);
switch (e.keyCode)
{
case 8: // backspace
{
var oldKeyPressInput = this.keyPressInput;
this.clear();
if (oldKeyPressInput.length > 1)
{
this.keyPressInput = oldKeyPressInput.substr(0, oldKeyPressInput.length - 1);
if (window.g_asc_plugins)
window.g_asc_plugins.onPluginEvent("onInputHelperInput", { "text" : this.keyPressInput });
}
return 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
{
this.clear();
return false;
}
case 46: // delete
case 45: // insert
{
if (!AscCommon.global_keyboardEvent.CtrlKey && !AscCommon.global_keyboardEvent.ShiftKey) // copy/cut/paste
{
// заканчиваем "непрерывный" ввод => очищаем текстбокс
this.clear();
return false;
}
}
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;
},
onKeyPress : function(e)
{
if (this.Api.isLongAction() || !this.Api.asc_IsFocus() || this.Api.isViewMode)
{
AscCommon.stopEvent(e);
return false;
}
if (this.isSystem)
return;
if (this.KeyDownFlag)
this.KeyPressFlag = true;
if (this.IsComposition)
return;
if ((e.which == 13 && e.keyCode == 13) || (e.which == 10 && e.keyCode == 10))
{
AscCommon.stopEvent(e);
return false;
}
var c = e.which || e.keyCode;
var isAsync = (c >= 0x20) ? AscFonts.FontPickerByCharacter.checkTextLight([c], true) : false;
if (isAsync)
{
AscFonts.FontPickerByCharacter.loadFonts(this, function ()
{
this.apiCompositeStart();
this.apiCompositeReplace([c]);
this.apiCompositeEnd();
this.setReadOnly(false);
});
AscCommon.stopEvent(e);
this.setReadOnly(true);
return false;
}
if (this.isKeyPressOnUp)
{
var isSaveCode = true;
switch (e.which)
{
case 46: // delete
{
isSaveCode = false;
break;
}
default:
break;
}
if (isSaveCode)
{
if (this.isKeyPressOnUpStackedMode)
{
this.keyPressOnUpCodes.push({
which: e.which,
charCode: e.charCode,
keyCode: e.keyCode,
shiftKey: e.shiftKey,
ctrlKey: e.ctrlKey,
metaKey: e.metaKey,
altKey: e.altKey,
preventDefault: function () {
}
});
}
return;
}
}
var ret = this.Api.onKeyPress(e);
if (e.key === "Delete" || e.code === "Delete") {
switch (e.which)
{
case 46: // delete
{
AscCommon.stopEvent(e);
this.clear();
return false;
}
default:
break;
}
}
this.keyPressInput += String.fromCharCode(e.which);
if (window.g_asc_plugins)
window.g_asc_plugins.onPluginEvent("onInputHelperInput", { "text" : this.keyPressInput });
AscCommon.stopEvent(e);
return ret;
},
onKeyUp : function(e)
{
if (this.Api.isLongAction())
{
AscCommon.stopEvent(e);
return false;
}
if (this.isSystem && this.isShow)
return;
if (this.isKeyPressOnUp && this.keyPressOnUpCodes.length > 0)
{
this.isKeyPressOnUp = false;
for (var i = 0; i < this.keyPressOnUpCodes.length; i++)
{
this.onKeyPress(this.keyPressOnUpCodes[i]);
}
this.isKeyPressOnUp = true;
this.keyPressOnUpCodes = [];
}
this.KeyDownFlag = false;
this.KeyPressFlag = false;
AscCommon.global_keyboardEvent.Up();
this.Api.onKeyUp(e);
},
getAreaPos : function()
{
var _offset = 0;
if (this.TextArea_Not_ContentEditableDiv)
{
_offset = this.HtmlArea.selectionEnd;
}
else
{
var sel = window.getSelection();
if (sel.rangeCount > 0)
{
var range = sel.getRangeAt(0);
_offset = range.endOffset;
}
}
return _offset;
},
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();
},
lockTarget : function()
{
if (!this.IsLockTargetMode)
return;
if (-1 != this.LockerTargetTimer)
clearTimeout(this.LockerTargetTimer);
this.Api.asc_LockTargetUpdate(true);
var oThis = this;
this.LockerTargetTimer = setTimeout(function()
{
oThis.unlockTarget();
}, 1000);
},
unlockTarget : function()
{
if (!this.IsLockTargetMode)
return;
if (-1 != this.LockerTargetTimer)
clearTimeout(this.LockerTargetTimer);
this.LockerTargetTimer = -1;
this.Api.asc_LockTargetUpdate(false);
},
clearLastCompositeText : function()
{
this.LastReplaceText = [];
this.IsLastReplaceFlag = false;
},
apiCompositeStart : function()
{
},
apiCompositeReplace : function(_value)
{
if (this.Api.isLongAction())
return false;
if (!this.ApiIsComposition)
{
this.Api.Begin_CompositeInput();
this.clearLastCompositeText();
}
this.ApiIsComposition = true;
if (this.IsLastReplaceFlag)
{
// check _value == this.LastReplaceText
if (_value.length == this.LastReplaceText.length)
{
var isEqual = true;
for (var nC = 0; nC < _value.length; nC++)
{
if (_value[nC] != this.LastReplaceText[nC])
{
isEqual = false;
break;
}
}
if (isEqual)
return; // не посылаем одинаковые замены!
}
}
this.Api.Replace_CompositeText(_value);
if (window.g_asc_plugins)
{
this.keyPressInput = String.fromCodePoint.apply(this, _value);
window.g_asc_plugins.onPluginEvent("onInputHelperInput", {"text": this.keyPressInput});
}
this.LastReplaceText = _value.slice();
this.IsLastReplaceFlag = true;
},
apiCompositeEnd : function()
{
if (!this.ApiIsComposition)
return;
this.ApiIsComposition = false;
this.Api.End_CompositeInput();
this.clearLastCompositeText();
},
onCompositionStart : function(e)
{
if (this.isSystem)
return;
this.IsComposition = true;
this.keyPressOnUpCodes = [];
},
onCompositionUpdate : function(e)
{
if (this.isSystem)
return;
this.IsComposition = true;
this.keyPressOnUpCodes = [];
this.onInput(e, true);
},
onCompositionEnd : function(e)
{
if (this.isSystem)
return;
this.IsComposition = false;
this.onInput(e, true);
},
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;
}
focusHtmlElement(this.HtmlArea);
}
},
externalEndCompositeInput : function()
{
this.clear();
},
externalChangeFocus : function()
{
if (!this.IsComposition)
return false;
setTimeout(function() {
window['AscCommon'].g_inputContext.clear();
}, 10);
return true;
},
isCompositionProcess : function()
{
return this.IsComposition;
},
preventVirtualKeyboard : function(e)
{
if (this.isHardCheckKeyboard)
return;
//AscCommon.stopEvent(e);
if (AscCommon.AscBrowser.isAndroid)
{
this.setReadOnlyWrapper(true);
this.virtualKeyboardClickPrevent = true;
this.virtualKeyboardClickTimeout = setTimeout(function ()
{
window['AscCommon'].g_inputContext.setReadOnlyWrapper(false);
window['AscCommon'].g_inputContext.virtualKeyboardClickTimeout = -1;
}, 1);
}
},
enableVirtualKeyboard : function()
{
if (this.isHardCheckKeyboard)
return;
if (AscCommon.AscBrowser.isAndroid)
{
if (-1 != this.virtualKeyboardClickTimeout)
{
clearTimeout(this.virtualKeyboardClickTimeout);
this.virtualKeyboardClickTimeout = -1;
}
this.setReadOnlyWrapper(false);
this.virtualKeyboardClickPrevent = false;
}
},
preventVirtualKeyboard_Hard : function()
{
this.setReadOnlyWrapper(true);
},
enableVirtualKeyboard_Hard : function()
{
this.setReadOnlyWrapper(false);
}
};
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 = CTextInput;
window['AscCommon'].InitBrowserInputContext = function(api, target_id, parent_id)
{
if (window['AscCommon'].g_inputContext)
return;
window['AscCommon'].g_inputContext = new CTextInput(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;
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;
if (t.IsComposition)
{
t.apiCompositeEnd();
t.externalEndCompositeInput();
}
if (!t.isSystem && !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.HtmlArea.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.HtmlArea); }, 0) : focusHtmlElement(t.HtmlArea);
t.nativeFocusElement = _elem;
t.Api.asc_enableKeyEvents(true, true);
}, true);
// send focus
if (!api.isMobileVersion && !api.isEmbedVersion)
focusHtmlElement(window['AscCommon'].g_inputContext.HtmlArea);
};
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);