diff --git a/developer/src/server/src/site/chargrid.js b/developer/src/server/src/site/chargrid.js
index e3c78fd437a..1ce9206bae5 100644
--- a/developer/src/server/src/site/chargrid.js
+++ b/developer/src/server/src/site/chargrid.js
@@ -75,7 +75,7 @@
if(keyman.isPositionSynthesized()) { // this is an internal function
// For touch devices, we need to ask KMW
- selStart = ta1.kmw_ip ? ta1.kmw_ip.getTextBeforeCaret().length : 0;
+ selStart = 0;
selLength = 0;
selDirection = 'forward';
} else {
diff --git a/web/source/dom/domDefaultOutput.ts b/web/source/dom/domDefaultOutput.ts
index 694a4f2fb3b..9e66451da15 100644
--- a/web/source/dom/domDefaultOutput.ts
+++ b/web/source/dom/domDefaultOutput.ts
@@ -28,27 +28,14 @@ namespace com.keyman.dom {
let code = DefaultOutput.codeForEvent(Lkc);
let domManager = com.keyman.singleton.domManager;
- let hideCaret: () => void;
- if(outputTarget instanceof com.keyman.dom.targets.TouchAlias) {
- hideCaret = function() {
- let target = outputTarget as com.keyman.dom.targets.TouchAlias;
- target.root.hideCaret();
- }
- } else {
- hideCaret = function() {};
- }
-
switch(code) {
case Codes.keyCodes['K_TAB']:
- hideCaret();
domManager.moveToNext((Lkc.Lmodifiers & text.Codes.modifierCodes['SHIFT']) != 0);
break;
case Codes.keyCodes['K_TABBACK']:
- hideCaret();
domManager.moveToNext(true);
break;
case Codes.keyCodes['K_TABFWD']:
- hideCaret();
domManager.moveToNext(false);
break;
}
diff --git a/web/source/dom/domEventHandlers.ts b/web/source/dom/domEventHandlers.ts
index 83b37a1bf9d..f692a2dc661 100644
--- a/web/source/dom/domEventHandlers.ts
+++ b/web/source/dom/domEventHandlers.ts
@@ -1,4 +1,3 @@
-///
///
namespace com.keyman.dom {
@@ -51,20 +50,6 @@ namespace com.keyman.dom {
this.keyman = keyman;
}
- /**
- * Handle receiving focus by simulated input field
- */
- setFocus: (e?: TouchEvent) => void = function(e?: TouchEvent): void {
- // Touch-only handler.
- }.bind(this);
-
- /**
- * Handles touch-based loss of focus events.
- */
- setBlur: (e: FocusEvent) => void = function(e: FocusEvent) {
- // Touch-only handler.
- }.bind(this);
-
// End of I3363 (Build 301) additions
// Universal DOM event handlers (both desktop + touch)
@@ -75,7 +60,6 @@ namespace com.keyman.dom {
*/
_ControlFocus: (e: FocusEvent) => boolean = function(this: DOMEventHandlers, e: FocusEvent): boolean {
var Ltarg: HTMLElement;
- var device = this.keyman.util.device;
Ltarg = this.keyman.util.eventTarget(e) as HTMLElement;
if (Ltarg == null) {
@@ -86,23 +70,12 @@ namespace com.keyman.dom {
Ltarg = Ltarg['body']; // Occurs in Firefox for design-mode iframes.
}
- // Prevent any action if a protected input field
- if(device.touchable && (Ltarg.className == null || Ltarg.className.indexOf('keymanweb-input') < 0)) {
- return true;
- }
-
// Or if not a remappable input field
- var en=Ltarg.nodeName.toLowerCase();
if(Ltarg.ownerDocument && Ltarg instanceof Ltarg.ownerDocument.defaultView.HTMLInputElement) {
var et=Ltarg.type.toLowerCase();
if(!(et == 'text' || et == 'search')) {
return true;
}
- } else if(Ltarg.ownerDocument && Ltarg.ownerDocument.designMode == 'on') {
- // continue; don't block this one!
- } else if((device.touchable || !Ltarg.isContentEditable)
- && !(Ltarg.ownerDocument && Ltarg instanceof Ltarg.ownerDocument.defaultView.HTMLTextAreaElement)) {
- return true;
}
// We condition on 'priorElement' below as a check to allow KMW to set a default active keyboard.
@@ -114,13 +87,6 @@ namespace com.keyman.dom {
var LfocusTarg = Ltarg;
- // Ensure that focussed element is visible above the keyboard
- if(Ltarg.className == null || Ltarg.className.indexOf('keymanweb-input') < 0) {
- if(this instanceof DOMTouchHandlers) {
- (this as DOMTouchHandlers).scrollBody(Ltarg);
- }
- }
-
if(Ltarg.ownerDocument && Ltarg instanceof Ltarg.ownerDocument.defaultView.HTMLIFrameElement) { //**TODO: check case reference
this.keyman.domManager._AttachToIframe(Ltarg as HTMLIFrameElement);
Ltarg=Ltarg.contentWindow.document.body;
@@ -182,16 +148,6 @@ namespace com.keyman.dom {
Ltarg = Ltarg['body']; // Occurs in Firefox for design-mode iframes.
}
- // Makes sure we properly detect the TouchAliasElement root,
- // rather than one of its constituent children.
- if(this.keyman.util.device.touchable) {
- Ltarg = findTouchAliasTarget(Ltarg);
-
- if(!Ltarg) {
- return true;
- }
- }
-
if(DOMEventHandlers.states._IgnoreNextSelChange) {
// If a keyboard calls saveFocus() (KSF), then ignore the
// next selection change
@@ -208,12 +164,6 @@ namespace com.keyman.dom {
return true;
}
- // Hide the touch device input caret, if applicable I3363 (Build 301)
- if(dom.Utils.instanceof(this.keyman.domManager.activeElement, "TouchAliasElement")) {
- let lastAlias = this.keyman.domManager.activeElement;
- lastAlias.hideCaret();
- }
-
if (Ltarg.nodeType == 3) { // defeat Safari bug
Ltarg = Ltarg.parentNode as HTMLElement;
}
@@ -337,6 +287,13 @@ namespace com.keyman.dom {
const outputTarget = dom.Utils.getOutputTarget(target);
+ // Ensure that focused element is visible above the keyboard
+ if(keyman.util.device.touchable && outputTarget) {
+ if(this instanceof DOMTouchHandlers) {
+ (this as DOMTouchHandlers).scrollBody(target);
+ }
+ }
+
let activeKeyboard = keyman.core.activeKeyboard;
if(!uiManager.justActivated) {
if(target && outputTarget) {
@@ -405,11 +362,6 @@ namespace com.keyman.dom {
doChangeEvent(_target: HTMLElement) {
if(DOMEventHandlers.states.changed) {
let event = new Event('change', {"bubbles": true, "cancelable": false});
-
- // Ensure that touch-aliased elements fire as if from the aliased element.
- if(_target['base'] && _target['base']['kmw_ip']) {
- _target = _target['base'];
- }
_target.dispatchEvent(event);
}
@@ -502,163 +454,6 @@ namespace com.keyman.dom {
super(keyman);
}
- private static selectTouch(e: TouchEvent): Touch {
- /*
- * During multi-touch events, it's possible for one or more touches of said multi-touch
- * to be against irrelevant parts of the page. We only want to consider touches against
- * valid OutputTargets - against elements of the page that KMW can attach to.
- * With touch active... that's a TouchAliasElement.
- */
- let isValidTouch = function(touch: Touch, target: EventTarget): boolean {
- return e.target == target && !!(findTouchAliasTarget(touch.target as HTMLElement));
- }
-
- // The event at least tells us the event's target, which can be used to help check
- // whether or not individual `Touch`es may be related to this specific event for
- // an ongoing multitouch scenario.
- let target = e.target;
-
- // Find the first touch affected by this event that matches the current target.
- for(let i=0; i < e.changedTouches.length; i++) {
- if(isValidTouch(e.changedTouches[i], target)) {
- return e.changedTouches[i];
- }
- }
-
- // Shouldn't be possible. Just in case, we'd prefer a silent failure that allows
- // callers to silently abort.
- throw new Error("Could not select valid Touch for event.");
- }
-
- /**
- * Handle receiving focus by simulated input field
- */
- setFocus: (e?: TouchEvent) => void = function(this: DOMTouchHandlers, e?: TouchEvent): void {
- DOMEventHandlers.states.setFocusTimer();
-
- var tEvent: {
- pageX: number;
- pageY: number;
- target?: EventTarget;
- };
-
- if(e && dom.Utils.instanceof(e, "TouchEvent")) {
- try {
- tEvent=DOMTouchHandlers.selectTouch(e as TouchEvent);
- } catch(err) {
- console.warn(err);
- return;
- }
- } else { // Allow external code to set focus and thus display the OSK on touch devices if required (KMEW-123)
- tEvent={pageX:0, pageY:0}
-
- // Will usually be called from setActiveElement, which should define DOMEventHandlers.states.lastActiveElement
- if(this.keyman.domManager.lastActiveElement) {
- tEvent.target = this.keyman.domManager.lastActiveElement;
- // Shouldn't happen, but... just in case. Implemented late in 14.0 beta, so
- // this detail was kept, though it's likely safe to eliminate.
- if(tEvent.target['kmw_ip']) {
- tEvent.target = tEvent.target['kmw_ip'];
- }
- // but will default to first input or text area on page if DOMEventHandlers.states.lastActiveElement is null
- } else {
- tEvent.target = this.keyman.domManager.sortedInputs[0]['kmw_ip'];
- }
- }
-
- this.setFocusWithTouch(tEvent);
- }.bind(this);
-
- // Also handles initial touch responses.
- setFocusWithTouch(tEvent: {pageX: number, pageY: number, target?: EventTarget}) {
- var touchX=tEvent.pageX,touchY=tEvent.pageY;
-
- // Some specifics rely upon which child of the TouchAliasElement received the actual event.
- let tTarg=tEvent.target as HTMLElement;
-
- // Determines the actual TouchAliasElement - the part tied to an OutputTarget.
- let target = findTouchAliasTarget(tTarg);
-
- if(!target) {
- return;
- }
-
- // Some parts rely upon the scroller element.
- let scroller = target.firstChild as HTMLElement;
-
- // Move the caret and refocus if necessary
- if(this.keyman.domManager.activeElement != target) {
- // Hide the KMW caret
- let prevTarget = this.keyman.domManager.activeElement;
-
- // We're not 100% sure whether or not the next line can occur,
- // but it's a decent failsafe regardless.
- if(prevTarget && prevTarget['kmw_ip']) {
- prevTarget = prevTarget['kmw_ip'] as TouchAliasElement;
- }
-
- // Make sure that we have the right type so that the expected method exists.
- if(prevTarget && dom.Utils.instanceof(prevTarget, "TouchAliasElement")) {
- prevTarget.hideCaret();
- }
-
- this.keyman.domManager.activeElement = target;
- // The issue here is that touching a DIV does not actually set the focus for iOS, even when enabled to accept focus (by setting tabIndex=0)
- // We must explicitly set the focus in order to remove focus from any non-KMW input
- target.focus(); //Android native browsers may not like this, but it is needed for Chrome, Safari
- }
-
- // Correct element directionality if required
- this.keyman.domManager._SetTargDir(target);
-
- // If clicked on DIV on the main element, rather than any part of the text representation,
- // set caret to end of text
- if(tTarg && tTarg == target) {
- let cp: number;
- let x=dom.Utils.getAbsoluteX(scroller.firstChild as HTMLElement);
- if(target.dir == 'rtl') {
- x += (scroller.firstChild as HTMLElement).offsetWidth;
- cp=(touchX > x ? 0 : 100000);
- } else {
- cp=(touchX void = function(this: DOMTouchHandlers, e: FocusEvent) {
- // This works OK for iOS, but may need something else for other platforms
- var elem: HTMLElement;
-
- if(('relatedTarget' in e) && e.relatedTarget) {
- elem = e.relatedTarget as HTMLElement;
- }
-
- this.executeBlur(elem);
- }.bind(this);
-
- executeBlur(elem: HTMLElement) {
- this.keyman['resetContext']();
-
- if(elem) {
- this.doChangeEvent(elem);
- if(elem.nodeName != 'DIV' || elem.className.indexOf('keymanweb-input') == -1) {
- this.cancelInput();
- return;
- }
- }
-
- //Hide the OSK
- if(!DOMEventHandlers.states.focusing && !this.keyman.uiManager.justActivated) {
- this.cancelInput();
- }
- }
-
- /**
- * Display and position a scrollbar in the input field if needed
- *
- * @param {Object} e input DIV element (copy of INPUT or TEXTAREA)
- */
- setScrollBar(e: HTMLElement) {
- // Display the scrollbar if necessary. Added TEXTAREA condition to correct rotation issue KMW-5. Fixed for 310 beta.
- var scroller=e.childNodes[0], sbs=(e.childNodes[1]).style;
- if((scroller.offsetWidth > e.offsetWidth || scroller.offsetLeft < 0) && (e.base.nodeName != 'TEXTAREA')) {
- sbs.height='4px';
- sbs.width=100*(e.offsetWidth/scroller.offsetWidth)+'%';
- sbs.left=100*(-scroller.offsetLeft/scroller.offsetWidth)+'%';
- sbs.top='0';
- sbs.visibility='visible';
- } else if(scroller.offsetHeight > e.offsetHeight || scroller.offsetTop < 0) {
- sbs.width='4px';
- sbs.height=100*(e.offsetHeight/scroller.offsetHeight)+'%';
- sbs.top=100*(-scroller.offsetTop/scroller.offsetHeight)+'%';
- sbs.left='0';
- sbs.visibility='visible';
- } else {
- sbs.visibility='hidden';
- }
- }
-
/**
* Handle the touch end event for an input element
*/
@@ -732,101 +471,26 @@ namespace com.keyman.dom {
this.firstTouch = null;
}.bind(this);
- /**
- * Handle the touch move event for an input element
- */
- dragInput: (e: TouchEvent) => void = function(this: DOMTouchHandlers, e: TouchEvent) {
- // Prevent dragging window
- if(e.cancelable) {
- // If a touch-alias element is scrolling, this may be false.
- // Tends to result in a spam of console errors when e.cancelable == false.
- e.preventDefault();
- }
- e.stopPropagation();
-
- // Identify the target from the touch list or the event argument (IE 10 only)
- var target: HTMLElement;
- let touch: Touch;
-
- if(dom.Utils.instanceof(e, "TouchEvent")) {
- try {
- touch=DOMTouchHandlers.selectTouch(e as TouchEvent);
- } catch(err) {
- console.warn(err);
- return;
- }
- target = touch.target as HTMLElement;
- } else {
- target = e.target as HTMLElement;
- }
- if(target == null) {
- return;
- }
-
- // Identify the input element from the touch event target (touched element may be contained by input)
- target = findTouchAliasTarget(target);
-
- if(!target) {
- return;
- }
-
- const x = touch.screenX;
- const y = touch.screenY;
-
- // Allow content of input elements to be dragged horizontally or vertically
- if(typeof this.firstTouch == 'undefined' || this.firstTouch == null) {
- this.firstTouch={x:x,y:y};
- } else {
- var x0=this.firstTouch.x,y0=this.firstTouch.y,
- scroller=target.firstChild as HTMLElement,dx,dy,x1;
-
- if(target.base.nodeName == 'TEXTAREA') {
- var yOffset=parseInt(scroller.style.top,10);
- if(isNaN(yOffset)) yOffset=0;
- dy=y0-y;
- if(dy < -4 || dy > 4) {
- scroller.style.top=(yOffset 4)
- {
- // Limit dragging beyond the defined text (to avoid dragging the text completely out of view)
- var xMin=0, xMax= dom.Utils.getAbsoluteX(target)+target.offsetWidth-scroller.offsetWidth-32;
- if(target.base.dir == 'rtl')xMin=16; else xMax=xMax-24;
- x1=xOffset-dx;
- if(x1 > xMin) x1=xMin;
- if(x1 < xMax) x1=xMax;
- scroller.style.left=x1+'px';
- this.firstTouch.x=x;
- }
- }
- }
- // Should refactor to use TouchAliasElement's version; target is an instance of the class.
- this.setScrollBar(target);
- }.bind(this);
-
/**
* Scroll the document body vertically to bring the active input into view
*
- * @param {Object} e simulated input field object being focussed
+ * @param {Object} e input field object being focussed
*/
scrollBody(e: HTMLElement): void {
var osk = this.keyman.osk;
- if(!e || e.className == null || e.className.indexOf('keymanweb-input') < 0 || !osk) {
+ if(!e || !osk) {
return;
}
// Get the absolute position of the caret
- var s2=e.firstChild.childNodes[1], y=dom.Utils.getAbsoluteY(s2), t=window.pageYOffset,dy=0;
+ const y = dom.Utils.getAbsoluteY(e);
+ const t = window.pageYOffset;
+ let dy = 0;
if(y < t) {
dy=y-t;
} else {
- dy=y-t-(window.innerHeight-osk._Box.offsetHeight-s2.offsetHeight-2);
+ dy=y-t-(window.innerHeight-osk._Box.offsetHeight-e.offsetHeight-2);
if(dy < 0) dy=0;
}
// Hide OSK, then scroll, then re-anchor OSK with absolute position (on end of scroll event)
diff --git a/web/source/dom/domManager.ts b/web/source/dom/domManager.ts
index aeeb1b01307..2ecefe30c0a 100644
--- a/web/source/dom/domManager.ts
+++ b/web/source/dom/domManager.ts
@@ -8,8 +8,6 @@
///
// References other DOM-specific web-core overrides.
///
-// Defines the touch-alias element structure used for mobile devices.
-///
// Defines per-element-type OutputTarget element wrapping.
///
// Defines cookie-based variable store serialization
@@ -219,11 +217,6 @@ namespace com.keyman.dom {
* Also ensures the element is registered on keymanweb's internal input list.
*/
enableTouchElement(Pelem: HTMLElement) {
- // Touch doesn't worry about iframes.
- if(Pelem.tagName.toLowerCase() == 'iframe') {
- return false;
- }
-
if(this.isKMWDisabled(Pelem)) {
this.setupNonKMWTouchElement(Pelem);
return false;
@@ -238,34 +231,13 @@ namespace com.keyman.dom {
// Remove any handlers for "NonKMWTouch" elements, since we're enabling it here.
Pelem.removeEventListener('touchstart', this.nonKMWTouchHandler);
- /*
- * Does this element already have a simulated touch element established? If so,
- * just reuse it - if it isn't still in the input list!
- */
- if(Pelem['kmw_ip']) {
-
- if(this.inputList.indexOf(Pelem['kmw_ip']) != -1) {
- return false;
- }
-
- this.inputList.push(Pelem['kmw_ip']);
-
- console.log("Unexpected state - this element's simulated input DIV should have been removed from the page!");
-
- return true; // May need setup elsewhere since it's just been re-added!
- }
-
- // The simulated touch element doesn't already exist? Time to initialize it.
- let x=dom.constructTouchAlias(Pelem);
- if(this.isAttached(x)) {
- x._kmwAttachment.interface = dom.targets.wrapElement(x);
- } else {
- this.setupElementAttachment(x); // The touch-alias should have its own wrapper.
+ if(!this.isAttached(Pelem)) {
+ this.setupElementAttachment(Pelem);
+ Pelem.inputMode = 'none';
}
- Pelem._kmwAttachment = x._kmwAttachment; // It's an object reference we need to alias.
// Set font for base element
- this.enableInputElement(x, true);
+ this.enableInputElement(Pelem, false);
// Superimpose custom input fields for each input or textarea, unless readonly or disabled
@@ -275,14 +247,12 @@ namespace com.keyman.dom {
// We know this to be the correct set of handlers because we're setting up a touch element.
var touchHandlers = this.touchHandlers;
- x.addEventListener('touchstart', touchHandlers.setFocus);
- x.addEventListener('touchend', touchHandlers.dragEnd, false);
-
- // Disable internal scroll when input element in focus
- x.addEventListener('touchmove', touchHandlers.dragInput, false);
-
- // Hide keyboard and caret when losing focus from simulated input field
- x.onblur=touchHandlers.setBlur;
+ Pelem.addEventListener('touchmove', (event) => {
+ // Prevent the base-page `touchMoveActivationHandler` from triggering if we're
+ // "scrolling" within a valid input-element type. That can be used for selection.
+ event.stopPropagation();
+ }, false);
+ Pelem.addEventListener('touchend', touchHandlers.dragEnd, false);
// Note that touchend event propagates and is processed by body touchend handler
// re-setting the first touch point for a drag
@@ -299,34 +269,7 @@ namespace com.keyman.dom {
*/
disableTouchElement(Pelem: HTMLElement) {
// Do not check for the element being officially disabled - it's also used for detachment.
-
- // Touch doesn't worry about iframes.
- if(Pelem.tagName.toLowerCase() == 'iframe') {
- return; // If/when we do support this, we'll need an iframe-level manager for it.
- }
-
- if(Pelem['kmw_ip']) {
- var index = this.inputList.indexOf(Pelem['kmw_ip']);
- if(index != -1) {
- this.inputList.splice(index, 1);
- }
-
- Pelem.style.visibility='visible'; // hide by default: KMW-3
- Pelem.disabled = false;
- Pelem.removeEventListener('resize', Pelem['kmw_ip']._kmwResizeHandler);
-
- // Disable touch-related handling code.
- this.disableInputElement(Pelem['kmw_ip']);
- Pelem._kmwAttachment.interface = dom.targets.wrapElement(Pelem);
-
- // We get weird repositioning errors if we don't remove our simulated input element - and permanently.
- if(Pelem.parentNode) {
- Pelem.parentNode.removeChild(Pelem['kmw_ip']);
- }
- delete Pelem['kmw_ip'];
- }
-
- this.setupNonKMWTouchElement(Pelem);
+ Pelem.inputMode = 'text';
}
/**
@@ -404,15 +347,14 @@ namespace com.keyman.dom {
return;
}
- var baseElement = isAlias ? Pelem['base'] : Pelem;
// Do NOT test for pre-disabledness - we also use this to fully detach without officially 'disabling' via kmw-disabled.
if((Pelem.ownerDocument.defaultView && Pelem instanceof Pelem.ownerDocument.defaultView.HTMLIFrameElement) ||
Pelem instanceof HTMLIFrameElement) {
this._DetachFromIframe(Pelem);
} else {
- var cnIndex = baseElement.className.indexOf('keymanweb-font');
- if(cnIndex > 0 && !isAlias) { // See note about the alias below.
- baseElement.className = baseElement.className.replace('keymanweb-font', '').trim();
+ let cnIndex = Pelem.className.indexOf('keymanweb-font');
+ if(cnIndex >= 0 && !isAlias) { // See note about the alias below.
+ Pelem.className = Pelem.className.replace('keymanweb-font', '').trim();
}
// Remove the element from our internal input tracking.
@@ -421,28 +363,17 @@ namespace com.keyman.dom {
this.inputList.splice(index, 1);
}
- if(!isAlias) { // See note about the alias below.
- this.keyman.util.detachDOMEvent(baseElement,'focus', this.getHandlers(Pelem)._ControlFocus);
- this.keyman.util.detachDOMEvent(baseElement,'blur', this.getHandlers(Pelem)._ControlBlur);
- this.keyman.util.detachDOMEvent(baseElement,'click', this.getHandlers(Pelem)._Click);
- }
- // These need to be on the actual input element, as otherwise the keyboard will disappear on touch.
+ this.keyman.util.detachDOMEvent(Pelem,'focus', this.getHandlers(Pelem)._ControlFocus);
+ this.keyman.util.detachDOMEvent(Pelem,'blur', this.getHandlers(Pelem)._ControlBlur);
+ this.keyman.util.detachDOMEvent(Pelem,'click', this.getHandlers(Pelem)._Click);
+
Pelem.onkeypress = null;
Pelem.onkeydown = null;
Pelem.onkeyup = null;
}
- // If we're disabling an alias, we should fully enable the base version. (Thinking ahead to toggleable-touch mode.)
- if(isAlias) {
- this.inputList.push(baseElement);
-
- baseElement.onkeypress = this.getHandlers(Pelem)._KeyPress;
- baseElement.onkeydown = this.getHandlers(Pelem)._KeyDown;
- baseElement.onkeyup = this.getHandlers(Pelem)._KeyUp;
- }
-
var lastElem = this.lastActiveElement;
- if(lastElem == Pelem || lastElem == Pelem['kmw_ip']) {
+ if(lastElem == Pelem) {
if(this.activeElement == lastElem) {
this.activeElement = null;
}
@@ -546,18 +477,21 @@ namespace com.keyman.dom {
* Also filters elements not supported for touch devices when device.touchable == true.
*/
isKMWInput(x: HTMLElement): boolean {
- var touchable = this.keyman.util.device.touchable;
-
if(x instanceof x.ownerDocument.defaultView.HTMLTextAreaElement) {
return true;
} else if(x instanceof x.ownerDocument.defaultView.HTMLInputElement) {
if (x.type == 'text' || x.type == 'search') {
return true;
}
- } else if(x instanceof x.ownerDocument.defaultView.HTMLIFrameElement && !touchable) { // Do not allow iframe attachment if in 'touch' mode.
+ } else if(x instanceof x.ownerDocument.defaultView.HTMLIFrameElement) {
try {
if(x.contentWindow) {
- if(x.contentWindow.document) { // Only allow attachment if the iframe's internal document is valid.
+ const iframeDoc = x.contentWindow.document;
+ if(iframeDoc) { // Only allow attachment if the iframe's internal document is valid.
+ // Do not allow design-mode iframe attachment if in 'touch' mode.
+ if(this.keyman.util.device.touchable && iframeDoc.designMode.toLowerCase() == 'on') {
+ return false;
+ }
return true;
}
} // else nothing?
@@ -567,7 +501,7 @@ namespace com.keyman.dom {
console.warn("Error during attachment to / detachment from iframe: ");
console.warn(err);
}
- } else if(x.isContentEditable && !touchable) { // Only allow contentEditable attachment outside of 'touch' mode.
+ } else if(x.isContentEditable) {
return true;
}
@@ -796,21 +730,13 @@ namespace com.keyman.dom {
var elDir=(activeKeyboard && activeKeyboard.isRTL) ? 'rtl' : 'ltr';
if(Ptarg) {
- if(this.keyman.util.device.touchable) {
- let alias = Ptarg;
- if(Ptarg.textContent.length == 0) {
- alias.base.dir=alias.dir=elDir;
- alias.setTextCaret(10000);
- }
- } else {
- if(Ptarg instanceof Ptarg.ownerDocument.defaultView.HTMLInputElement
- || Ptarg instanceof Ptarg.ownerDocument.defaultView.HTMLTextAreaElement) {
- if((Ptarg as HTMLInputElement|HTMLTextAreaElement).value.length == 0) {
- Ptarg.dir=elDir;
- }
- } else if(typeof Ptarg.textContent == "string" && Ptarg.textContent.length == 0) { // As with contenteditable DIVs, for example.
+ if(Ptarg instanceof Ptarg.ownerDocument.defaultView.HTMLInputElement
+ || Ptarg instanceof Ptarg.ownerDocument.defaultView.HTMLTextAreaElement) {
+ if((Ptarg as HTMLInputElement|HTMLTextAreaElement).value.length == 0) {
Ptarg.dir=elDir;
}
+ } else if(typeof Ptarg.textContent == "string" && Ptarg.textContent.length == 0) { // As with contenteditable DIVs, for example.
+ Ptarg.dir=elDir;
}
}
}
@@ -826,24 +752,9 @@ namespace com.keyman.dom {
if(this.isAttached(Pelem) || Pelem instanceof Pelem.ownerDocument.defaultView.HTMLIFrameElement) {
if(this.keyman.util.device.touchable) {
this.disableTouchElement(Pelem);
- this.setupNonKMWTouchElement(Pelem);
-
- var keyman = this.keyman;
-
- // If a touch alias was removed, chances are it's gonna mess up our touch-based layout scheme, so let's update the touch elements.
- window.setTimeout(function() {
- this.listInputs();
-
- for(var k = 0; k < this.sortedInputs.length; k++) {
- if(this.sortedInputs[k]['kmw_ip']) {
- this.sortedInputs[k]['kmw_ip'].updateInput(this.sortedInputs[k]['kmw_ip']);
- }
- }
- }.bind(this), 1);
- } else {
- this.listInputs(); // Fix up our internal input ordering scheme.
}
+ this.listInputs(); // Fix up our internal input ordering scheme.
this.disableInputElement(Pelem);
}
}
@@ -865,12 +776,6 @@ namespace com.keyman.dom {
// if we don't update the touch elements.
window.setTimeout(function() {
keyman.domManager.listInputs();
-
- for(var k = 0; k < this.sortedInputs.length; k++) {
- if(this.sortedInputs[k]['kmw_ip']) {
- this.sortedInputs[k]['kmw_ip'].updateInput(this.sortedInputs[k]['kmw_ip']);
- }
- }
}.bind(this), 1);
} else {
this.enableInputElement(Pelem);
@@ -1002,12 +907,6 @@ namespace com.keyman.dom {
var domManager = this;
window.setTimeout(function() {
domManager.listInputs();
-
- for(var k = 0; k < this.sortedInputs.length; k++) {
- if(this.sortedInputs[k]['kmw_ip']) {
- this.sortedInputs[k]['kmw_ip'].updateInput();
- }
- }
}.bind(this), 1);
}
}
@@ -1021,7 +920,7 @@ namespace com.keyman.dom {
*
*/
_MutationAdditionObserved = function(Pelem: HTMLElement) {
- if(Pelem instanceof Pelem.ownerDocument.defaultView.HTMLIFrameElement && !this.keyman.util.device.touchable) {
+ if(Pelem instanceof Pelem.ownerDocument.defaultView.HTMLIFrameElement) {
//Problem: the iframe is loaded asynchronously, and we must wait for it to load fully before hooking in.
var domManager = this;
@@ -1146,6 +1045,10 @@ namespace com.keyman.dom {
* Description Set default keyboard for the control
*/
setKeyboardForControl(Pelem: HTMLElement, Pkbd?: string, Plc?: string) {
+ if(!Pelem) {
+ return;
+ }
+
/* pass null for kbd to specify no default, or '' to specify the default system keyboard. */
if(Pkbd !== null && Pkbd !== undefined) {
var index = Pkbd.indexOf("Keyboard_");
@@ -1169,10 +1072,9 @@ namespace com.keyman.dom {
Pelem._kmwAttachment.languageCode = Plc;
// If Pelem is the focused element/active control, we should set the keyboard in place now.
- // 'kmw_ip' is the touch-alias for the original page's control.
var lastElem = this.lastActiveElement;
- if(lastElem && (lastElem == Pelem || lastElem == Pelem['kmw_ip'])) {
+ if(lastElem && (lastElem == Pelem)) {
if(Pkbd != null && Plc != null) { // Second part necessary for Closure.
this.keyman.keyboardManager.setActiveKeyboard(Pkbd, Plc);
@@ -1262,13 +1164,6 @@ namespace com.keyman.dom {
}
set activeElement(Pelem: HTMLElement) {
- // Ensure that a TouchAliasElement is hidden whenever it is deactivated for input.
- if(this.activeElement) {
- if(Utils.instanceof(this.keyman.domManager.activeElement, "TouchAliasElement")) {
- (this.keyman.domManager.activeElement as TouchAliasElement).hideCaret();
- }
- }
-
DOMEventHandlers.states._activeElement = Pelem;
var isActivating = this.keyman.uiManager.isActivating;
@@ -1308,10 +1203,6 @@ namespace com.keyman.dom {
return;
}
- // As this is an API function, someone may pass in the base of a touch element.
- // We need to respond appropriately.
- e = (e['kmw_ip'] ? e['kmw_ip'] : e) as HTMLElement;
-
// If we're changing controls, don't forget to properly manage the keyboard settings!
// It's only an issue on 'native' (non-embedded) code paths.
if(!this.keyman.isEmbedded) {
@@ -1330,18 +1221,7 @@ namespace com.keyman.dom {
// Allow external focusing KMEW-123
if(arguments.length > 1 && setFocus) {
- if(this.keyman.util.device.touchable) {
- var tEvent = {
- pageX: 0,
- pageY: 0,
- target: e as HTMLElement
- };
-
- // Kinda hacky, but gets the job done.
- (this.keyman.touchAliasing as DOMTouchHandlers).setFocusWithTouch(tEvent);
- } else {
- this.focusLastActiveElement();
- }
+ this.focusLastActiveElement();
}
// Let the keyboard do its initial group processing
@@ -1393,24 +1273,7 @@ namespace com.keyman.dom {
i = i < 0 ? i+t.length : i;
// Move to the selected element
- if(touchable) {
- // Set focusing flag to prevent OSK disappearing
- DOMEventHandlers.states.focusing=true;
- var target=t[i]['kmw_ip'];
-
- // Focus if next element is non-mapped
- if(typeof(target) == 'undefined') {
- t[i].focus();
- } else { // Or reposition the caret on the input DIV if mapped
- let alias = target;
- this.keyman.domManager.setActiveElement(target); // Handles both `lastActive` + `active`.
- alias.setTextCaret(10000); // Safe b/c touchable == true.
- alias.scrollInput(); // mousedown check
- target.focus();
- }
- } else { // Behaviour for desktop browsers
- t[i].focus();
- }
+ t[i].focus();
}
/**
@@ -1420,17 +1283,11 @@ namespace com.keyman.dom {
*
*/
moveToElement(e:string|HTMLElement) {
- var i;
-
if(typeof(e) == "string") { // Can't instanceof string, and String is a different type.
e=document.getElementById(e);
}
- if(this.keyman.util.device.touchable && e['kmw_ip']) {
- e['kmw_ip'].focus();
- } else {
- e.focus();
- }
+ e.focus();
}
/* ----------------------- Editable IFrame methods ------------------- */
@@ -1694,11 +1551,9 @@ namespace com.keyman.dom {
// The following tests are needed to prevent the OSK from being hidden during normal input!
let p=(e.target as HTMLElement).parentElement;
if(typeof(p) != 'undefined' && p != null) {
- if(p.className.indexOf('keymanweb-input') >= 0) return false;
if(p.className.indexOf('kmw-key-') >= 0) return false;
if(typeof(p.parentElement) != 'undefined' && p.parentElement != null) {
p=p.parentElement;
- if(p.className.indexOf('keymanweb-input') >= 0) return false;
if(p.className.indexOf('kmw-key-') >= 0) return false;
}
}
diff --git a/web/source/dom/targets/input.ts b/web/source/dom/targets/input.ts
index bde5b52c5fc..a3b2514480c 100644
--- a/web/source/dom/targets/input.ts
+++ b/web/source/dom/targets/input.ts
@@ -155,7 +155,7 @@ namespace com.keyman.dom.targets {
}
static newlineHandler(inputEle: HTMLInputElement) {
- // Can't occur for Mocks - just Input and TouchAlias types.
+ // Can't occur for Mocks - just Input types.
if (inputEle && (inputEle.type == 'search' || inputEle.type == 'submit')) {
inputEle.disabled=false;
inputEle.form.submit();
diff --git a/web/source/dom/targets/readme.md b/web/source/dom/targets/readme.md
index 8d62928033e..ee52947bc31 100644
--- a/web/source/dom/targets/readme.md
+++ b/web/source/dom/targets/readme.md
@@ -1,3 +1,3 @@
Please keep any code in this folder / namespace as free as possible from dependencies on other parts of KMW. Some of our unit tests wish to run against these types without requiring KMW to be active.
-Note that with a little work, we _could_ completely spin this into its own separate module - this could be useful for development and testing purposes... at least, save for the TouchAlias type.
\ No newline at end of file
+Note that with a little work, we _could_ completely spin this into its own separate module - this could be useful for development and testing purposes, especially now that we've dropped the old `TouchAlias` type that was a bit entangled with main engine code.
\ No newline at end of file
diff --git a/web/source/dom/targets/touchAlias.ts b/web/source/dom/targets/touchAlias.ts
deleted file mode 100644
index a152a4b4e63..00000000000
--- a/web/source/dom/targets/touchAlias.ts
+++ /dev/null
@@ -1,93 +0,0 @@
-// Defines the TouchAliasElement merged type.
-///
-
-namespace com.keyman.dom.targets {
- export class TouchAlias extends OutputTarget {
- root: TouchAliasElement;
-
- constructor(e: TouchAliasElement) {
- super();
- this.root = e;
- }
-
- getElement(): HTMLDivElement {
- return this.root;
- }
-
- clearSelection(): void {
- // Touch-alias elements do not currently support selections.
- return;
- }
-
- invalidateSelection(): void {
- // Touch-alias elements do not currently support selections.
- return;
- }
-
- isSelectionEmpty(): boolean {
- // Touch-alias elements do not currently support selections.
- return true;
- }
-
- hasSelection(): boolean {
- // Always has an internal caret position.
- return true;
- }
-
- getDeadkeyCaret(): number {
- return this.root.getTextCaret();
- }
-
- getTextBeforeCaret(): string {
- return this.root.getTextBeforeCaret();
- }
-
- getTextAfterCaret(): string {
- return this.root.getTextAfterCaret();
- }
-
- getText(): string {
- return this.root.getText();
- }
-
- deleteCharsBeforeCaret(dn: number): void {
- if(dn > 0) {
- let curText = this.getTextBeforeCaret();
- if(this.getDeadkeyCaret() < dn) {
- dn = this.getDeadkeyCaret();
- }
- this.adjustDeadkeys(-dn);
- this.root.setTextBeforeCaret(curText.kmwSubstring(0, this.root.getTextCaret() - dn));
- }
- }
-
- insertTextBeforeCaret(s: string): void {
- this.adjustDeadkeys(s._kmwLength());
- this.root.setTextBeforeCaret(this.root.getTextBeforeCaret() + s);
- }
-
- handleNewlineAtCaret(): void {
- // Insert new line in text area fields
- if(this.root.base.nodeName == 'TEXTAREA') {
- // As the TouchAliasElement was implemented long before OutputTargets, it already has
- // built-in newline handling.
- this.insertTextBeforeCaret('\n');
- } else if(dom.Utils.instanceof(this.root.base, "HTMLInputElement")) {
- // HTMLInputElements do not permit newlines; they instead have DOM-specific behaviors.
- this.root.hideCaret();
- Input.newlineHandler(this.root.base as HTMLInputElement);
- } else {
- console.warn("TouchAlias OutputTarget cannot output newlines for unexpected base element types!");
- }
- }
-
- protected setTextAfterCaret(s: string) {
- this.root.setText(this.getTextBeforeCaret() + s, this.getTextBeforeCaret()._kmwLength());
- }
-
- doInputEvent() {
- // Dispatch the event on the aliased element, not the TouchAliasElement itself.
- this.dispatchInputEventOn(this.root.base);
- }
- }
-}
\ No newline at end of file
diff --git a/web/source/dom/targets/wrapElement.ts b/web/source/dom/targets/wrapElement.ts
index 5f13fbbeb4c..01b1a2a2c75 100644
--- a/web/source/dom/targets/wrapElement.ts
+++ b/web/source/dom/targets/wrapElement.ts
@@ -7,8 +7,6 @@
///
// Defines a basic design-mode IFrame wrapper.
///
-// Defines a basic touch-alias element wrapper.
-///
namespace com.keyman.dom.targets {
export function wrapElement(e: HTMLElement): OutputTarget {
@@ -18,8 +16,6 @@ namespace com.keyman.dom.targets {
return new Input( e);
} else if(Utils.instanceof(e, "HTMLTextAreaElement")) {
return new TextArea( e);
- } else if(Utils.instanceof(e, "TouchAliasElement")) {
- return new TouchAlias( e);
} else if(Utils.instanceof(e, "HTMLIFrameElement")) {
let iframe = e;
@@ -34,7 +30,7 @@ namespace com.keyman.dom.targets {
} else if(e.isContentEditable) {
return new ContentEditable(e);
}
-
+
return null;
}
}
\ No newline at end of file
diff --git a/web/source/dom/touchAliasElement.ts b/web/source/dom/touchAliasElement.ts
deleted file mode 100644
index ee94e40e490..00000000000
--- a/web/source/dom/touchAliasElement.ts
+++ /dev/null
@@ -1,858 +0,0 @@
-// References extra HTML definitions not included by default in TS.
-///
-// References device-specific code checks (separable module from KMW)
-///
-// References common DOM utility functions (separate module from KMW)
-///
-
-namespace com.keyman.dom {
- /**
- * As our touch-alias elements have historically been based on
s, this
- * defines the root element of touch-aliases as a merger type with HTMLDivElements.
- *
- */
- export type TouchAliasElement = HTMLDivElement & TouchAliasData;
-
- // Many thanks to https://www.typescriptlang.org/docs/handbook/advanced-types.html for this.
- function link(elem: HTMLDivElement, data: TouchAliasData): TouchAliasElement {
- let e = elem;
-
- // Merges all properties and methods of KeyData onto the underlying HTMLDivElement, creating a merged class.
- for(let id in data) {
- if(!e.hasOwnProperty(id)) {
- (e)[id] = (data)[id];
- }
- }
-
- return e;
- }
-
- // If the specified HTMLElement is either a TouchAliasElement or one of its children elements,
- // this method will return the root TouchAliasElement.
- export function findTouchAliasTarget(target: HTMLElement): TouchAliasElement {
- // The scrollable container element for the before & after text spans & the caret.
- // Not to be confused with the simulated scrollbar.
- let scroller: HTMLElement;
-
- // Identify the scroller element
- if(target && dom.Utils.instanceof(target, "HTMLSpanElement")) {
- scroller=target.parentNode as HTMLElement;
- } else if(target && (target.className != null && target.className.indexOf('keymanweb-input') >= 0)) {
- scroller=target.firstChild as HTMLElement;
- } else if(target && dom.Utils.instanceof(target, "HTMLDivElement")) {
- // Three possibilities: the scroller, the scrollbar, & the blinking DIV of the caret.
- // A direct click CAN trigger events on the blinking element itself if well-timed.
- scroller=target;
-
- // Ensures we land on the scroller, not the caret.
- if(scroller.parentElement && scroller.parentElement.className.indexOf('keymanweb-input') < 0) {
- scroller = scroller.parentElement;
- }
-
- // scroller is now either the actual scroller or the scrollbar element.
- // We don't return either of these, and they both have the same parent element.
- } else if(target['kmw_ip']) { // In case it's called on a TouchAliasElement's base (aliased) element.
- return target['kmw_ip'] as TouchAliasElement;
- } else {
- // If it's not in any way related to a TouchAliasElement, simply return null.
- return null;
- }
-
- // And the actual target element
- let root = scroller.parentNode;
- if(root['base'] !== undefined) {
- return root as TouchAliasElement;
- } else {
- return null;
- }
- }
-
- export function constructTouchAlias(base?: HTMLElement): TouchAliasElement {
- let div = document.createElement("div");
- let ele = link(div, new TouchAliasData());
-
- if(base) {
- ele.initWithBase(base);
- } else {
- ele.init();
- }
-
- return ele;
- }
-
- /**
- * The core definition for touch-alias 'subclassing' of HTMLDivElement.
- * It's 'merged' with HTMLDivElement to avoid issues with DOM inheritance and DOM element creation.
- */
- class TouchAliasData {
- ['base']: HTMLElement = null; // NOT undefined; we can use this distinction for 'type-checking'.
- __preCaret: HTMLSpanElement;
- __postCaret: HTMLSpanElement;
- __scrollDiv: HTMLDivElement;
- __scrollBar: HTMLDivElement;
-
- __caretSpan: HTMLSpanElement;
- __caretDiv: HTMLDivElement;
- __caretTimerId: number;
- __activeCaret: boolean = false;
-
- __executingCaretSearch: boolean = false;
-
- __resizeHandler: () => void;
-
- // The number of pixels a touch may lie within the 'next' character before we
- // bump the caret AFTER that next character.
- static readonly X_SNAP_LENIENCY_PIXELS: number = 5;
-
- private static device: Device;
-
- private static getDevice(): Device {
- if(!TouchAliasData.device) {
- let device = new com.keyman.Device();
- device.detect();
-
- TouchAliasData.device = device;
- }
-
- return TouchAliasData.device;
- }
-
- private static getOS(): string {
- return this.getDevice().OS;
- }
-
- isMultiline(): boolean {
- return this['base'] && this['base'].nodeName == "TEXTAREA";
- }
-
- initCaret(): void {
- /**
- * Create a caret to be appended to the scroller of the focussed input field.
- * The caret is appended to the scroller so that it will automatically be clipped
- * when the user manually scrolls it outside the element boundaries.
- * It is positioned exactly over the hidden span (__caretSpan) that is inserted
- * between the text spans before and after the insertion point.
- */
- this.__caretDiv = document.createElement('DIV');
- var cs=this.__caretDiv.style;
- cs.position='absolute';
- cs.height='16px'; // default height, actual height set from element properties
- cs.width='2px';
- cs.backgroundColor='blue';
- cs.border='none';
- cs.left=cs.top='0px'; // actual position set relative to parent when displayed
- cs.display='block';
- cs.visibility='hidden';
- cs.zIndex='9998'; // immediately below the OSK
-
- // Start the caret flash timer
- this.__caretTimerId = window.setInterval(this.flashCaret.bind(this), 500);
- }
-
- init() {
- // Remember, this type exists to be merged into HTMLDivElements, so this will work.
- // We have to trick TS a bit to make it happy, though.
- let divThis = ( this);
- divThis.className='keymanweb-input';
-
- // Add a scrollable interior div
- let d = this.__scrollDiv = document.createElement<'div'>('div');
- let xs = divThis.style;
- xs.overflow='hidden';
- xs.position='absolute';
- //xs.border='1px solid gray';
- xs.border='hidden'; // hide when element empty - KMW-3
- xs.border='none';
- xs.borderRadius='5px';
-
- // Add a scroll bar (horizontal for INPUT elements, vertical for TEXTAREA elements)
- var sb = this.__scrollBar = document.createElement<'div'>('div'), sbs=sb.style;
- sbs.position='absolute';
- sbs.height=sbs.width='4px';
- sbs.left=sbs.top='0';
- sbs.display='block';
- sbs.visibility='hidden';
- sbs.backgroundColor='#808080';
- sbs.borderRadius='2px';
-
- // And add two spans for the text content before and after the caret, and a caret span
- this.__preCaret=document.createElement<'span'>('span');
- this.__postCaret=document.createElement<'span'>('span');
- this.__caretSpan=document.createElement<'span'>('span');
- this.__preCaret.innerHTML = this.__postCaret.innerHTML = this.__caretSpan.innerHTML='';
- this.__preCaret.className = this.__postCaret.className = this.__caretSpan.className='keymanweb-font';
-
- d.appendChild(this.__preCaret);
- d.appendChild(this.__caretSpan);
- d.appendChild(this.__postCaret);
- divThis.appendChild(d);
- divThis.appendChild(sb);
-
- let ds=d.style;
- ds.position='relative';
-
- let preCaretStyle = this.__preCaret.style;
- let postCaretStyle = this.__postCaret.style;
- let styleCaret = this.__caretSpan.style;
- preCaretStyle.border=postCaretStyle.border='none';
- //preCaretStyle.backgroundColor='rgb(220,220,255)';
- //postCaretStyle.backgroundColor='rgb(220,255,220)'; //only for testing
- preCaretStyle.height=postCaretStyle.height='100%';
-
- // The invisible caret-positioning span must have a border to ensure that
- // it remains in the layout, but colour doesn't matter, as it is never visible.
- // Span margins are adjusted to compensate for the border and maintain text positioning.
- styleCaret.border='1px solid red';
- styleCaret.visibility='hidden';
- styleCaret.marginLeft=styleCaret.marginRight='-1px';
-
- ds.left='0px';
- ds.top='0px';
- ds.padding='0';
- ds.border='none';
-
- // Set the outer element padding *after* appending the element,
- // otherwise Firefox misaligns the two elements
- xs.padding='8px';
-
- // Set the tabindex to 0 to allow a DIV to accept focus and keyboard input
- // c.f. http://www.w3.org/WAI/GL/WCAG20/WD-WCAG20-TECHS/SCR29.html
- divThis.tabIndex=0;
-
- ds.minWidth=xs.width;
- ds.height=xs.height;
-
- this.initCaret();
- }
-
- initWithBase(base: HTMLElement) {
- this['base'] = base;
- this.init();
-
- let divThis = ( this);
-
- // There's quite a bit of setup for touch-alias elements that only occurs if it has an associated base.
- this['base']['kmw_ip'] = divThis;
- base.disabled = true;
-
- let baseStyle = window.getComputedStyle(base, null);
- let scrollDivStyle = this.__scrollDiv.style;
- let preCaretStyle = this.__preCaret.style;
- let postCaretStyle = this.__postCaret.style;
-
- divThis.dir = base.dir;
-
- preCaretStyle.fontFamily = postCaretStyle.fontFamily = scrollDivStyle.fontFamily = baseStyle.fontFamily;
-
- // Set vertical centering for input elements
- if(base.nodeName.toLowerCase() == 'input') {
- if(!isNaN(parseInt(baseStyle.height,10))) {
- preCaretStyle.lineHeight = postCaretStyle.lineHeight = baseStyle.height;
- }
- }
-
- if(TouchAliasData.getOS() == 'Android' && baseStyle.backgroundColor == 'transparent') {
- scrollDivStyle.backgroundColor = '#fff';
- } else {
- scrollDivStyle.backgroundColor = baseStyle.backgroundColor;
- }
-
- if(divThis.base.nodeName.toLowerCase() == 'textarea') {
- preCaretStyle.whiteSpace=postCaretStyle.whiteSpace='pre-wrap'; //scroll vertically
- } else {
- preCaretStyle.whiteSpace=postCaretStyle.whiteSpace='pre'; //scroll horizontally
- }
-
- divThis.base.parentNode.appendChild(divThis);
- divThis.updateInput();
-
- let style = divThis.style;
- style.color=baseStyle.color;
- //style.backgroundColor=bs.backgroundColor;
- style.fontFamily=baseStyle.fontFamily;
- style.fontSize=baseStyle.fontSize;
- style.fontWeight=baseStyle.fontWeight;
- style.textDecoration=baseStyle.textDecoration;
- style.padding=baseStyle.padding;
- style.margin=baseStyle.margin;
- style.border=baseStyle.border;
- style.borderRadius=baseStyle.borderRadius;
-
- //xs.color='red'; //use only for checking alignment
-
- // Prevent highlighting of underlying element (Android)
- if('webkitTapHighlightColor' in style) {
- (style).webkitTapHighlightColor='rgba(0,0,0,0)';
- }
-
- if(base instanceof base.ownerDocument.defaultView.HTMLTextAreaElement) {
- // Correct rows value if defaulted and box height set by CSS
- // The rows value is used when setting the caret vertically
-
- if(base.rows == 2) { // 2 is default value
- var h=parseFloat(baseStyle.height)-parseFloat(baseStyle.paddingTop)-parseFloat(baseStyle.paddingBottom),
- dh=parseFloat(baseStyle.fontSize), calcRows=Math.round(h/dh);
- if(calcRows > base.rows+1) {
- base.rows=calcRows;
- }
- }
- scrollDivStyle.width=style.width;
- scrollDivStyle.minHeight=style.height;
- } else {
- scrollDivStyle.minWidth=style.width;
- scrollDivStyle.height=style.height;
- }
- base.style.visibility='hidden'; // hide by default: KMW-3
-
- // Add an explicit event listener to allow the duplicated input element
- // to be adjusted for any changes in base element location or size
- // This will be called for each element after any rotation, as well as after user-initiated changes
- // It has to be wrapped in an anonymous function to preserve scope and be applied to each element.
- (function(xx: TouchAliasElement){
- xx.__resizeHandler = function(){
- /* A timeout is needed to let the base element complete its resizing before our
- * simulated element can properly resize itself.
- *
- * Not doing this causes errors if the input elements are resized for whatever reason, such as
- * changing languages to a text with greater height.
- */
- window.setTimeout(function (){
- xx.updateInput();
- }, 1);
- };
-
- xx.base.addEventListener('resize', xx.__resizeHandler, false);
- xx.base.addEventListener('orientationchange', xx.__resizeHandler, false);
- })(divThis);
-
- var textValue: string;
-
- if(base instanceof base.ownerDocument.defaultView.HTMLTextAreaElement
- || base instanceof base.ownerDocument.defaultView.HTMLInputElement) {
- textValue = base.value;
- } else {
- textValue = base.textContent;
- }
-
- // And copy the text content
- this.setText(textValue, null);
- }
-
- setText(t?: string, cp?: number): void {
- var tLen=0;
- var t1: string, t2: string;
-
- // Read current text if null passed (for caret positioning)
- if(t === null) {
- t1 = this.__preCaret.textContent;
- t2 = this.__postCaret.textContent;
- t = t1 + t2;
- }
-
- if(cp < 0) {
- cp = 0; //if(typeof t._kmwLength == 'undefined') return;
- }
-
- tLen=t._kmwLength();
-
- if(cp === null || cp === undefined || cp > tLen) {
- cp=tLen;
- }
- t1=t._kmwSubstr(0,cp);
- t2=t._kmwSubstr(cp);
-
- this.__preCaret.textContent=t1;
- this.__postCaret.textContent=t2;
-
- // Disable if a caret search is operational; no need to alter page layout or scroll just yet.
- if(!this.__executingCaretSearch) {
- this.updateBaseElement(); // KMW-3, KMW-29
- }
- }
-
- getTextBeforeCaret() {
- return this.__preCaret.textContent;
- }
-
- getTextAfterCaret() {
- return this.__postCaret.textContent;
- }
-
- setTextBeforeCaret(t: string): void {
- var tLen=0;
-
- // Collapse (trailing) whitespace to a single space for INPUT fields (also prevents wrapping)
- if(!this.isMultiline()) {
- t=t.replace(/\s+$/,' ');
- }
- this.__preCaret.textContent=t;
- // Test total length in order to control base element visibility
- tLen=t.length;
- tLen=tLen+this.__postCaret.textContent.length;
-
- if(!this.__executingCaretSearch) {
- this.finalizeCaret();
- }
- }
-
- getTextCaret(): number {
- return this.getTextBeforeCaret()._kmwLength();
- }
-
- setTextCaret(cp: number): void {
- this.setText(null,cp);
- this.showCaret();
- }
-
- /**
- * An outer wrapper for the caret position update function. Disables unnecessary DOM-manipulation
- * (& layout-triggering) operations during the search while guaranteeing that normal caret updates
- * resume after the search, whether or not an error occurs.
- *
- * Some layout-triggering is still needed for the search to work, but the quantity is greatly reduced.
- * @param touchPageX The target .pageX value for the caret
- * @param touchPageY The target .pageY value for the caret
- */
- executeCaretSearch(touchPageX: number, touchPageY: number) {
- this.__executingCaretSearch = true;
- try {
- this.performCaretSearch(touchPageX, touchPageY);
- } finally {
- this.__executingCaretSearch = false;
- this.finalizeCaret();
- }
- }
-
- /**
- * The core functionality for efficiently determining the intended caret placement within
- * the text form of the context given the page coordinate of a `TouchEvent`. Takes great
- * care to remain O(log N); some layout-triggering operations are required, making O(N)
- * unacceptable.
- *
- * Even a few thousand characters is enough to become unacceptably laggy if O(N).
- * @param touchPageX The target .pageX value for the caret
- * @param touchPageY The target .pageY value for the caret
- */
- private performCaretSearch(touchX: number, touchY: number) {
- const dy=document.body.scrollTop;
- const contextLength = this.getText()._kmwLength();
- let cpMin=0;
- let cpMax=contextLength;
- let cp=this.getTextCaret();
-
- // Vertical scrolling
- // instanceof this.base.[...] in case the element lies within an iframe.
- if(this.base instanceof this.base.ownerDocument.defaultView.HTMLTextAreaElement) {
- // Approximates the height of a row.
- const yRow=Math.round(this.base.offsetHeight/(this.base as HTMLTextAreaElement).rows);
- const maxY = touchY;
- const minY = touchY - yRow;
-
- // Performs a binary search for a valid caret based on the y-position.
- // cp: the previously-set caret position.
-
- // Break the binary search if our final search window is extremely small.
- while(cpMax - cpMin > 1) {
-
- const y=dom.Utils.getAbsoluteY(this.__caretSpan)-dy; //top of caret
-
- if(y > maxY && cp > cpMin) {
- // If caret's prior placement is below (after) the touch's y-pos...
- cpMax=cp; // new max position
- cp=Math.round((cp+cpMin)/2); // guess the halfway mark
- } else if(y < minY && cp < cpMax) {
- // If caret's prior placement is above (before) the touch's y-pos - 1 row height...
- cpMin=cp; // new min posiiton
- cp=Math.round((cp+cpMax)/2); // guess the halfway mark
- } else {
- // Great guess: the y-position lines up, so cp is within the target row.
- // At this point, the only thing that matters is that we've found ONE caret
- // position that matches the target line.
- break;
- }
- // Actively set our caret to the determined matching y-position.
- this.setTextCaret(cp); // mutates `caret`'s position
- }
-
- // Tweak slightly if the caret position still falls out of bounds, but only enough to get in-bounds.
- // Since our final window is small, we only need single-position shifts here (if needed at all).
- if(dom.Utils.getAbsoluteY(this.__caretSpan)-dy > maxY && cp > cpMin) {
- this.setTextCaret(--cp); // mutates `caret`'s position
- }
-
- if(dom.Utils.getAbsoluteY(this.__caretSpan)-dy < minY && cp < cpMax) {
- this.setTextCaret(++cp); // mutates `caret`'s position
- }
-
- // Guarantees: cp is 'close' to both bounds, as it lies within the target row.
- // Therefore, it caps the search interval for the x-coordinate versions of both cpMin and cpMax.
- //
- // Now to meet the pre-condition for the x-coord search later in the function:
- // we need those bounds to be [cpMin, cpMax] === [start of row, end of row], both within the same line.
-
- // Determine minimum caret position on the target row; prep the x-coord cpMin.
- // cpMin is guaranteed to lie strictly before the target row unless at the start of the first row.
- // It is neither guaranteed to have changed since its initialization nor to be close to the target row.
- let minCpMin = cpMin;
- let maxCpMin = cp;
- while(maxCpMin != minCpMin) {
- // Our logic will auto-increment if too low, so favor the lower index.
- const searchPt = Math.floor((maxCpMin+minCpMin)/2);
- this.setTextCaret(searchPt);
-
- const y=dom.Utils.getAbsoluteY(this.__caretSpan)-dy; //top of caret
- if(y < minY) {
- // We already know it's not on this row, so the minimum possible index should be increased.
- cpMin = minCpMin = searchPt+1;
- } else {
- // Still in the same row, so the boundary can only be at or before this point.
- cpMin = maxCpMin = searchPt;
- }
- }
-
- // Determine maximum caret position on the target row; prep the x-coord cpMax.
- // cpMax is guaranteed to lie strictly after the target row unless at the end of the final row.
- // It is neither guaranteed to have changed since its initialization nor to be close to the target row.
- let minCpMax = cp;
- let maxCpMax = cpMax;
- while(maxCpMax != minCpMax) {
- // Our logic will auto-decrement if too high, so favor the higher index.
- const searchPt = Math.round((maxCpMax+minCpMax)/2);
- this.setTextCaret(searchPt);
-
- const y=dom.Utils.getAbsoluteY(this.__caretSpan)-dy; //top of caret
- if(y > maxY) {
- // We already know it's not on this row, so the maximum possible index should be decreased.
- cpMax = maxCpMax = searchPt-1;
- } else {
- // Still in the same row, so the boundary can only be at or after this point.
- cpMax = minCpMax = searchPt;
- }
- }
-
- // Set the potential caret in the middle of the range.
- cp = Math.round((cpMin + cpMax)/2);
- this.setTextCaret(cp);
- }
-
- // Caret repositioning for horizontal scrolling of RTL text
-
- // snapOrder - 'snaps' the touch location in a manner corresponding to the 'ltr' vs 'rtl' orientation.
- // Think of it as performing a floor() function, but the floor depends on the origin's direction.
- const isRTL = (this as unknown as HTMLElement).dir == 'rtl';
- const snapOrder = isRTL ? (a, b) => a < b : (a, b) => a > b;
-
- // Used to signify a few pixels of leniency in the 'rtl'-appropriate direction for final
- // caret placement.
- const snapLeniency = isRTL ? -TouchAliasData.X_SNAP_LENIENCY_PIXELS : TouchAliasData.X_SNAP_LENIENCY_PIXELS;
-
- // Now to binary-search the x-coordinate.
- // Pre-condition: [cpMin, cpMax] === [start of row, end of row], both within the same line.
- // Automatically met for `-based instances.
- // Break the binary search if our final search window is extremely small.
- while(cpMax - cpMin > 1) {
- const x=dom.Utils.getAbsoluteX(this.__caretSpan); //left of caret
-
- if(snapOrder(x, touchX) && cp > cpMin) {
- cpMax=cp;
- cp=Math.round((cp+cpMin)/2);
- } else if(!snapOrder(x, touchX) && cp < cpMax) {
- cpMin=cp;
- cp=Math.round((cp+cpMax)/2);
- } else {
- break;
- }
- this.setTextCaret(cp);
- }
-
- // LTR: if caret x-pos > touchPosition, push caret earlier.
- if(snapOrder(dom.Utils.getAbsoluteX(this.__caretSpan), touchX) && cp > cpMin) {
- this.setTextCaret(--cp);
- }
-
- // LTR: if caret x-pos + leniency <= touchPosition, push caret later.
- // Allows the touch to "bleed over" a couple pixels into the next char without
- // bumping it later.
- if(!snapOrder(dom.Utils.getAbsoluteX(this.__caretSpan) + snapLeniency, touchX) && cp < cpMax) {
- this.setTextCaret(++cp);
- }
- }
-
- private finalizeCaret() {
- // Update the base element then scroll into view if necessary
- this.updateBaseElement(); //KMW-3, KMW-29
- this.scrollInput();
- }
-
- /**
- * Set content, visibility, background and borders of input and base elements (KMW-3,KMW-29)
- */
- updateBaseElement() {
- let e = ( this);
-
- // Only proceed if we actually have a base element.
- if(!e['base']) {
- return;
- }
-
- var Ldv = e.base.ownerDocument.defaultView;
- if(e.base instanceof Ldv.HTMLInputElement || e.base instanceof Ldv.HTMLTextAreaElement) {
- e.base.value = this.getText(); //KMW-29
- } else {
- e.base.textContent = this.getText();
- }
-
- let n = this.getText()._kmwLength();
-
- e.style.backgroundColor = (n==0 ? 'transparent' : window.getComputedStyle(e.base, null).backgroundColor);
-
- if(TouchAliasData.getOS() == 'iOS') {
- e.base.style.visibility=(n==0?'visible':'hidden');
- }
- }
-
- flashCaret(): void {
- // Significant change - each element manages its own caret, and its activation is managed through show/hideCaret()
- // without referencing core KMW code. (KMW must thus check if the active element is a TouchAliasElement, then use these
- // methods as appropriate.)
- if(this.__activeCaret) {
- var cs=this.__caretDiv.style;
- cs.visibility = cs.visibility != 'visible' ? 'visible' : 'hidden';
- }
- };
-
- /**
- * Position the caret at the start of the second span within the scroller
- */
- showCaret() {
- var scroller=this.__scrollDiv, cs=this.__caretDiv.style, sp2=this.__caretSpan;
-
- // Attach the caret to this scroller and position it over the caret span
- if(this.__caretDiv.parentNode != scroller) {
- scroller.appendChild(this.__caretDiv);
- }
-
- cs.left=sp2.offsetLeft+'px';
- cs.top=sp2.offsetTop+'px';
- cs.height=(sp2.offsetHeight-1)+'px';
- cs.visibility='hidden'; // best to wait for timer to display caret
- this.__activeCaret = true;
-
- // Disable if a caret search is operational; no need to alter page layout or scroll just yet.
- if(!this.__executingCaretSearch) {
- // Scroll into view if required
- this.scrollBody();
-
- // Display and position the scrollbar if necessary
- this.setScrollBar();
- }
- }
-
- hideCaret() {
- var e= ( this);
-
- // Always copy text back to underlying field on blur
- if(e.base instanceof e.base.ownerDocument.defaultView.HTMLTextAreaElement
- || e.base instanceof e.base.ownerDocument.defaultView.HTMLInputElement) {
- e.base.value = this.getText();
- }
-
- // And set the scroller caret to the end of the element content (null preserves text)
- this.setText(null, 100000);
-
- // Set the element scroll to zero (or max for RTL INPUT)
- var ss=this.__scrollDiv.style;
- if(e.isMultiline()) {
- ss.top='0';
- } else {
- if(e.base.dir == 'rtl') {
- ss.left=(e.offsetWidth - this.__scrollDiv.offsetWidth-8)+'px';
- } else {
- ss.left='0';
- }
- }
-
-
- // And hide the caret and scrollbar
- if(this.__caretDiv.parentNode) {
- this.__caretDiv.parentNode.removeChild(this.__caretDiv);
- }
-
- this.__caretDiv.style.visibility='hidden';
- this.__scrollBar.style.visibility='hidden';
-
- this.__activeCaret = false;
- }
-
- getText(): string {
- return ( ( this)).textContent;
- }
-
- updateInput() {
- if(this['base']) {
- let divThis = ( ( this));
-
- var xs=divThis.style, b=divThis.base,
- s=window.getComputedStyle(b,null),
- mLeft=parseFloat(s.marginLeft),
- mTop=parseFloat(s.marginTop),
- x1=Utils.getAbsoluteX(b), y1=Utils.getAbsoluteY(b);
-
- var p=divThis.offsetParent as HTMLElement;
- if(p) {
- x1=x1-Utils.getAbsoluteX(p);
- y1=y1-Utils.getAbsoluteY(p);
- }
-
- if(isNaN(mLeft)) {
- mLeft=0;
- }
- if(isNaN(mTop)) {
- mTop=0;
- }
-
- xs.left=(x1-mLeft)+'px';
- xs.top=(y1-mTop)+'px';
-
- var w=b.offsetWidth, h=b.offsetHeight,
- pLeft=parseFloat(s.paddingLeft), pRight=parseFloat(s.paddingRight),
- pTop=parseFloat(s.paddingTop), pBottom=parseFloat(s.paddingBottom),
- bLeft=parseFloat(s.borderLeft), bRight=parseFloat(s.borderRight),
- bTop=parseFloat(s.borderTop), bBottom=parseFloat(s.borderBottom);
-
- // If using content-box model, must subtract the padding and border,
- // but *not* for border-box (as for WordPress PlugIn)
- var boxSizing='undefined';
- if(typeof(s.boxSizing) != 'undefined') {
- boxSizing=s.boxSizing;
- } else if(typeof(s.MozBoxSizing) != 'undefined') {
- boxSizing=s.MozBoxSizing;
- }
-
- if(boxSizing == 'content-box') {
- if(!isNaN(pLeft)) w -= pLeft;
- if(!isNaN(pRight)) w -= pRight;
- if(!isNaN(bLeft)) w -= bLeft;
- if(!isNaN(bRight)) w -= bRight;
-
- if(!isNaN(pTop)) h -= pTop;
- if(!isNaN(pBottom)) h -= pBottom;
- if(!isNaN(bTop)) h -= bTop;
- if(!isNaN(bBottom)) h -= bBottom;
- }
-
- if(TouchAliasData.getOS() == 'Android') {
- w++;
- h++;
- }
-
- xs.width=w+'px';
- xs.height=h+'px';
- }
- }
-
- /**
- * Scroll the input field horizontally (INPUT base element) or
- * vertically (TEXTAREA base element) to bring the caret into view
- * as text is entered or deleted form an element
- */
- scrollInput() {
- var scroller=this.__scrollDiv;
- let divThis = ( this);
-
- // Get the actual absolute position of the caret and the element
- var s2=this.__caretSpan,
- cx=dom.Utils.getAbsoluteX(s2),cy=dom.Utils.getAbsoluteY(s2),
- ex=dom.Utils.getAbsoluteX(divThis),ey=dom.Utils.getAbsoluteY(divThis),
- x=parseInt(scroller.style.left,10),
- y=parseInt(scroller.style.top,10),
- dx=0,dy=0;
-
- // Scroller offsets must default to zero
- if(isNaN(x)) x=0; if(isNaN(y)) y=0;
-
- // Scroll input field vertically if necessary
- if(divThis.isMultiline()) {
- var rowHeight=Math.round(divThis.offsetHeight/( divThis.base).rows);
- if(cy < ey) {
- dy=cy-ey;
- }
- if(cy > ey+divThis.offsetHeight-rowHeight) {
- dy=cy-ey-divThis.offsetHeight+rowHeight;
- }
- if(dy != 0){
- scroller.style.top=(y ex+divThis.offsetWidth-12) {
- dx=cx-ex-divThis.offsetWidth+12;
- }
- if(dx != 0) {
- scroller.style.left=(x ( this);
-
- // Display the scrollbar if necessary. Added isMultiline condition to correct rotation issue KMW-5. Fixed for 310 beta.
- var scroller=this.__scrollDiv, sbs=this.__scrollBar.style;
- if((scroller.offsetWidth > e.offsetWidth || scroller.offsetLeft < 0) && !e.isMultiline()) {
- sbs.height='4px';
- sbs.width=100*(e.offsetWidth/scroller.offsetWidth)+'%';
- sbs.left=100*(-scroller.offsetLeft/scroller.offsetWidth)+'%';
- sbs.top='0';
- sbs.visibility='visible';
- } else if(scroller.offsetHeight > e.offsetHeight || scroller.offsetTop < 0) {
- sbs.width='4px';
- sbs.height=100*(e.offsetHeight/scroller.offsetHeight)+'%';
- sbs.top=100*(-scroller.offsetTop/scroller.offsetHeight)+'%';
- sbs.left='0';
- sbs.visibility='visible';
- } else {
- sbs.visibility='hidden';
- }
- }
- }
-}
\ No newline at end of file
diff --git a/web/source/dom/utils.ts b/web/source/dom/utils.ts
index 2c16bede30e..8f7fc2673eb 100644
--- a/web/source/dom/utils.ts
+++ b/web/source/dom/utils.ts
@@ -13,7 +13,7 @@ namespace com.keyman.dom {
if(keyman) {
Lelem = keyman.domManager.lastActiveElement;
}
-
+
if(!Lelem) {
// If we're trying to find an active target but one doesn't exist, just return null.
return null;
@@ -27,12 +27,12 @@ namespace com.keyman.dom {
throw new Error("OSK could not find element output target data!");
}
}
-
+
/**
* Function getAbsoluteX
* Scope Public
* @param {Object} Pobj HTML element
- * @return {number}
+ * @return {number}
* Description Returns x-coordinate of Pobj element absolute position with respect to page
*/
static getAbsoluteX(Pobj: HTMLElement): number { // I1476 - Handle SELECT overlapping END
@@ -41,7 +41,7 @@ namespace com.keyman.dom {
if(!Pobj) {
return 0;
}
-
+
var Lcurleft = Pobj.offsetLeft ? Pobj.offsetLeft : 0;
Lobj = Pobj; // I2404 - Support for IFRAMEs
@@ -73,9 +73,9 @@ namespace com.keyman.dom {
* Function getAbsoluteY
* Scope Public
* @param {Object} Pobj HTML element
- * @return {number}
+ * @return {number}
* Description Returns y-coordinate of Pobj element absolute position with respect to page
- */
+ */
static getAbsoluteY(Pobj: HTMLElement): number {
var Lobj: HTMLElement
@@ -113,32 +113,20 @@ namespace com.keyman.dom {
/**
* Checks the type of an input DOM-related object while ensuring that it is checked against the correct prototype,
* as class prototypes are (by specification) scoped upon the owning Window.
- *
+ *
* See https://stackoverflow.com/questions/43587286/why-does-instanceof-return-false-on-chrome-safari-and-edge-and-true-on-firefox
* for more details.
- *
+ *
* @param {Element|Event} Pelem An element of the web page or one of its IFrame-based subdocuments.
* @param {string} className The plain-text name of the expected Element type.
* @return {boolean}
*/
static instanceof(Pelem: Event|EventTarget, className: string): boolean {
- // We must write special checks for our custom-defined element types!
- if(className == "TouchAliasElement") {
- if(this.instanceof(Pelem, "HTMLDivElement")) {
- let div = Pelem;
-
- // We should probably implement a slightly more robust check, but this should get us started well enough.
- return div['base'] !== undefined;
- } else {
- return false;
- }
- }
-
var scopedClass;
if(!Pelem) {
// If we're bothering to check something's type, null references don't match
- // what we're looking for.
+ // what we're looking for.
return false;
}
if (Pelem['Window']) { // Window objects contain the class definitions for types held within them. So, we can check for those.
@@ -151,7 +139,7 @@ namespace com.keyman.dom {
var event = Pelem as Event;
if(this.instanceof(event.target, 'Window')) {
- scopedClass = event.target[className];
+ scopedClass = event.target[className];
} else if(this.instanceof(event.target, 'Document')) {
scopedClass = (event.target as Document).defaultView[className];
} else if(this.instanceof(event.target, 'HTMLElement')) {
diff --git a/web/source/kmwbase.ts b/web/source/kmwbase.ts
index d1ccd15c6ad..6cb0407ab2d 100644
--- a/web/source/kmwbase.ts
+++ b/web/source/kmwbase.ts
@@ -114,6 +114,9 @@ namespace com.keyman {
KC_(n, ln, Pelem){return '';}
handleRotationEvents(){}
// Will serve as an API function for a workaround, in case of future touch-alignment issues.
+ /**
+ * This function is deprecated in 16.0, with plans for removal in 17.0.
+ */
['alignInputs'](eleList?: HTMLElement[]){}
hideInputs() {};
namespaceID(Pstub) {};
diff --git a/web/source/kmwnative.ts b/web/source/kmwnative.ts
index a2d04d109f3..0af29d2ae28 100644
--- a/web/source/kmwnative.ts
+++ b/web/source/kmwnative.ts
@@ -6,10 +6,10 @@
Copyright 2019 SIL International
***/
-// If KMW is already initialized, the KMW script has been loaded more than once. We wish to prevent resetting the
+// If KMW is already initialized, the KMW script has been loaded more than once. We wish to prevent resetting the
// KMW system, so we use the fact that 'initialized' is only 1 / true after all scripts are loaded for the initial
// load of KMW.
-if(!window['keyman']['initialized']) {
+if(!window['keyman']['initialized']) {
/*****************************************/
/* */
/* On-Screen (Visual) Keyboard Code */
@@ -37,7 +37,7 @@ if(!window['keyman']['initialized']) {
/**
* Customized wait display
- *
+ *
* @param {string|boolean} s displayed text (or false)
*/
util.wait = function(s) {
@@ -48,7 +48,7 @@ if(!window['keyman']['initialized']) {
if(typeof(bg) == 'undefined' || bg == null || keymanweb.warned) {
return;
}
-
+
var nn=bg.firstChild.childNodes;
if(s) {
bg.pending=true;
@@ -68,7 +68,7 @@ if(!window['keyman']['initialized']) {
}
}
}
-
+
// Get default style sheet path
keymanweb.getStyleSheetPath=function(ssName) {
var ssPath = util['getOption']('resources')+'osk/'+ssName;
@@ -80,86 +80,49 @@ if(!window['keyman']['initialized']) {
* KeymanWeb 2 revised keyboard location specification:
* (a) absolute URL (includes ':') - load from specified URL
* (b) relative URL (starts with /, ./, ../) - load with respect to current page
- * (c) filename only (anything else) - prepend keyboards option to URL
+ * (c) filename only (anything else) - prepend keyboards option to URL
* (e.g. default keyboards option will be set by Cloud)
- *
- * @param {string} Lfilename keyboard file name with optional prefix
- */
- keymanweb.getKeyboardPath=function(Lfilename) {
- var rx=RegExp('^(([\\.]/)|([\\.][\\.]/)|(/))|(:)');
+ *
+ * @param {string} Lfilename keyboard file name with optional prefix
+ */
+ keymanweb.getKeyboardPath=function(Lfilename) {
+ var rx=RegExp('^(([\\.]/)|([\\.][\\.]/)|(/))|(:)');
return (rx.test(Lfilename) ? '' : keymanweb.options['keyboards']) + Lfilename;
}
/**
* Align input fields (should not be needed with KMEI, KMEA), making them visible if previously hidden.
- *
+ *
* @param {object} eleList A list of specific elements to align. If nil, selects all elements.
- *
+ *
**/
keymanweb.alignInputs = function(eleList: HTMLElement[]) {
- if(device.touchable) {
- var domManager = keymanweb.domManager;
- var processList: HTMLElement[] = [];
-
- if(eleList) {
- // Did the user specify the actual element or the touch-alias?
- eleList.forEach(function(element: HTMLElement){
- if(element.base) {
- // It's a touch-alias element, which is what we wish to perform alignment on.
- processList.push(element);
- } else {
- // This retrieves an element's touch-alias, should it exist.
- let touchAlias = element['kmw_ip'] as HTMLDivElement;
- if(touchAlias) {
- processList.push(element['kmw_ip']);
- }
- }
- });
- } else {
- processList = domManager.inputList;
- }
-
- processList.forEach(function(element: HTMLElement) {
- if(dom.Utils.instanceof(element, "TouchAliasElement")) {
- (element as com.keyman.dom.TouchAliasElement).updateInput();
- }
- element.style.visibility = 'visible';
- if(element.base.textContent.length > 0) {
- element.base.style.visibility = 'hidden';
- }
- })
- }
+ // no-op
}
/**
- * Programatically hides all input fields with underlying elements. Restore with .alignInputs.
- *
+ * Programatically hides all input fields with underlying elements. Restore with .alignInputs.
+ *
* @param {boolean} align align and make visible, else hide
- *
+ *
**/
keymanweb.hideInputs = function() {
- var domManager = keymanweb.domManager;
- if(device.touchable) {
- for(var i=0; i= 0) {
keyman.uiManager.setActivatingUI(false);
oskManager.startHide(true);
- let active = keyman.domManager.activeElement;
- if (dom.Utils.instanceof(active, "TouchAliasElement")) {
- (active as dom.TouchAliasElement).hideCaret();
- }
keyman.domManager.lastActiveElement = null;
}
}
diff --git a/web/source/tsconfig.dev_resources.json b/web/source/tsconfig.dev_resources.json
index 164859fab1b..003689efd2f 100644
--- a/web/source/tsconfig.dev_resources.json
+++ b/web/source/tsconfig.dev_resources.json
@@ -16,9 +16,7 @@
"dom/targets/textarea.ts",
"dom/targets/contentEditable.ts",
"dom/targets/designIFrame.ts",
- "dom/targets/touchAlias.ts",
"dom/targets/outputTarget.ts",
- "dom/touchAliasElement.ts",
"kmwexthtml.ts",
"kmwdevice.ts",
"dom/utils.ts",
diff --git a/web/testing/attachment-api/index.html b/web/testing/attachment-api/index.html
index c02c66d3fd1..69fb497c152 100644
--- a/web/testing/attachment-api/index.html
+++ b/web/testing/attachment-api/index.html
@@ -93,9 +93,7 @@
KeymanWeb Sample Page - Attachment API Testing
Note: The iframe section should not actually attach/enable for touch devices
and does not support setKeyboardForControl.
-
contenteditable Elements:
-
Note: This section should not actually attach/enable for touch devices.