[Libreoffice-commits] online.git: Branch 'feature/mobile-input' - 14 commits - bundled/include kit/ChildSession.cpp kit/ChildSession.hpp loleaflet/src wsd/ClientSession.cpp
Iván Sánchez Ortega (via logerrit)
logerrit at kemper.freedesktop.org
Thu Oct 3 12:57:43 UTC 2019
bundled/include/LibreOfficeKit/LibreOfficeKit.h | 6
bundled/include/LibreOfficeKit/LibreOfficeKit.hxx | 13
kit/ChildSession.cpp | 28
kit/ChildSession.hpp | 1
loleaflet/src/control/Control.LokDialog.js | 9
loleaflet/src/layer/marker/ClipboardContainer.js | 795 +++++++---------------
loleaflet/src/map/handler/Map.Keyboard.js | 6
wsd/ClientSession.cpp | 3
8 files changed, 336 insertions(+), 525 deletions(-)
New commits:
commit 6b783bcfd6223a4fef31411dbc2917c624cc55c6
Author: Iván Sánchez Ortega <ivan.sanchez at collabora.com>
AuthorDate: Mon Jul 29 17:46:42 2019 +0200
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 13:56:08 2019 +0100
loleaflet: preventDefault() on lokDialog clicks to avoid focus changes.
Change-Id: I95c3f94562cbfd0de71cd7330fa0b1baf1562a21
diff --git a/loleaflet/src/control/Control.LokDialog.js b/loleaflet/src/control/Control.LokDialog.js
index 1b65b1086..b2fd267a2 100644
--- a/loleaflet/src/control/Control.LokDialog.js
+++ b/loleaflet/src/control/Control.LokDialog.js
@@ -615,7 +615,7 @@ L.Control.LokDialog = L.Control.extend({
}, this);
L.DomEvent.on(canvas, 'mousedown mouseup', function(e) {
- L.DomEvent.stopPropagation(e);
+ L.DomEvent.stop(e);
var buttons = 0;
if (this._map['mouse']) {
buttons |= e.button === this._map['mouse'].JSButtons.left ? this._map['mouse'].LOButtons.left : 0;
@@ -629,6 +629,12 @@ L.Control.LokDialog = L.Control.extend({
this._postWindowMouseEvent(lokEventType, id, e.offsetX, e.offsetY, 1, buttons, 0);
//dlgInput.focus();
}, this);
+
+ L.DomEvent.on(canvas, 'click', function(ev) {
+ // Clicking on the dialog's canvas shall not trigger any
+ // focus change - therefore the event is stopped and preventDefault()ed.
+ L.DomEvent.stop(ev);
+ });
},
_setupGestures: function(dialogContainer, id, canvas) {
commit 6fc7686ff8b7340f2c0ba675a8b34dd8205b3471
Author: Marco Cecchetti <mrcekets at gmail.com>
AuthorDate: Tue Jul 23 21:50:55 2019 +0200
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 13:55:08 2019 +0100
android-chrome: keyboard disappears when tapping on current input field
Change-Id: I76145a4c4eeba6f1cb9ae3f05784d426ea298ccc
diff --git a/loleaflet/src/control/Control.LokDialog.js b/loleaflet/src/control/Control.LokDialog.js
index 5047e03db..1b65b1086 100644
--- a/loleaflet/src/control/Control.LokDialog.js
+++ b/loleaflet/src/control/Control.LokDialog.js
@@ -386,6 +386,7 @@ L.Control.LokDialog = L.Control.extend({
// set the position of the cursor container element
L.DomUtil.setStyle(this._dialogs[dlgId].cursor, 'left', x + 'px');
L.DomUtil.setStyle(this._dialogs[dlgId].cursor, 'top', y + 'px');
+ this._map.getClipboardContainer().focus();
},
_createDialogCursor: function(dialogId) {
commit 3dfd05f9c171d47ae3663b2ba9d116c5f9f0b708
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Tue Jul 23 20:41:16 2019 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 13:54:56 2019 +0100
input: use pre-pended non-blanking space & handle GBoard better.
GBoard's unwelcome & unwanted movement of our cursor does not
necessarily mean backspace - so special case detect that.
Also use pre-pended on Android, apparently it stops GBoard
capitalizing everything, hmm.
Change-Id: Idfbc696c3e45f173895ed0f26abaea3a32ad86c0
diff --git a/loleaflet/src/layer/marker/ClipboardContainer.js b/loleaflet/src/layer/marker/ClipboardContainer.js
index 3e16778ef..7e048af14 100644
--- a/loleaflet/src/layer/marker/ClipboardContainer.js
+++ b/loleaflet/src/layer/marker/ClipboardContainer.js
@@ -25,8 +25,13 @@ L.ClipboardContainer = L.Layer.extend({
this._hasWorkingSelectionStart = undefined; // does it work ?
this._ignoreNextBackspace = false;
+ this._preSpaceChar = ' ';
// Might need to be \xa0 in some legacy browsers ?
- this._spaceChar = ' ';
+ if (L.Browser.android && L.Browser.webkit) {
+ // fool GBoard into not auto-capitalizing constantly
+ this._preSpaceChar = '\xa0';
+ }
+ this._postSpaceChar = ' ';
// Debug flag, used in fancyLog(). See the debug() method.
// this._isDebugOn = true;
@@ -370,19 +375,23 @@ L.ClipboardContainer = L.Layer.extend({
// Backspaces and deletes at the beginning / end are filtered out, so
// we get a beforeinput, but no input for them. Sometimes we can end up
// in a state where we lost our leading / terminal chars and can't recover
- _onBeforeInput: function _onBeforeInput(/* ev */) {
+ _onBeforeInput: function _onBeforeInput(ev) {
this._ignoreNextBackspace = false;
if (this._hasWorkingSelectionStart) {
var value = this._textArea.value;
- if (value.length == 2 && value === this._spaceChar + this._spaceChar &&
+ if (value.length == 2 && value === this._preSpaceChar + this._postSpaceChar &&
this._textArea.selectionStart === 0)
{
// It seems some inputs eg. GBoard can magically move the cursor from " | " to "| "
console.log('Oh dear, gboard sabotaged our cursor position, fixing');
- this._removeTextContent(1, 0);
+ // But when we detect the problem only emit a delete when we have one.
+ if (ev.inputType && ev.inputType === 'deleteContentBackward')
+ {
+ this._removeTextContent(1, 0);
+ // Having mended it we now get a real backspace on input (sometimes)
+ this._ignoreNextBackspace = true;
+ }
this._emptyArea();
- // Having mended it we now get a real backspace on input (sometimes)
- this._ignoreNextBackspace = true;
}
}
},
@@ -405,19 +414,24 @@ L.ClipboardContainer = L.Layer.extend({
this._deleteHint = '';
}
+ var ignoreBackspace = this._ignoreNextBackspace;
+ this._ignoreNextBackspace = false;
+
var content = this.getValueAsCodePoints();
- var spaceChar = this._spaceChar.charCodeAt(0);
+ var preSpaceChar = this._preSpaceChar.charCodeAt(0);
+ var postSpaceChar = this._postSpaceChar.charCodeAt(0);
// We use a different leading and terminal space character
// to differentiate backspace from delete, then replace the character.
- if (content.length < 1 || content[0] !== spaceChar) { // missing initial space
+ if (content.length < 1 || content[0] !== preSpaceChar) { // missing initial space
console.log('Sending backspace');
- this._removeTextContent(1, 0);
+ if (!ignoreBackspace)
+ this._removeTextContent(1, 0);
this._emptyArea();
return;
}
- if (content[content.length-1] !== spaceChar) { // missing trailing space.
+ if (content[content.length-1] !== postSpaceChar) { // missing trailing space.
console.log('Sending delete');
this._removeTextContent(0, 1);
this._emptyArea();
@@ -428,9 +442,8 @@ L.ClipboardContainer = L.Layer.extend({
if (this._deleteHint == 'backspace' ||
this._textArea.selectionStart === 0)
{
- if (!this._ignoreNextBackspace)
+ if (!ignoreBackspace)
this._removeTextContent(1, 0);
- this._ignoreNextBackspace = false;
}
else if (this._deleteHint == 'delete' ||
this._textArea.selectionStart === 1)
@@ -537,7 +550,7 @@ L.ClipboardContainer = L.Layer.extend({
console.log('Set old/lastContent to empty');
this._lastContent = [];
- this._textArea.value = this._spaceChar + this._spaceChar;
+ this._textArea.value = this._preSpaceChar + this._postSpaceChar;
this._textArea.setSelectionRange(1, 1);
if (this._hasWorkingSelectionStart === undefined)
this._hasWorkingSelectionStart = (this._textArea.selectionStart === 1);
commit 390ece4d59e08cf28f48d1dd52aa84d116cc6a7d
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Tue Jul 23 18:19:40 2019 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 13:54:51 2019 +0100
input: remove Gecko special-case breaking new-line input.
Seems we can unify this, and let the textarea handle enters.
Change-Id: I4ff020993ba562fb95899c3ff113dfc835f7b419
diff --git a/loleaflet/src/layer/marker/ClipboardContainer.js b/loleaflet/src/layer/marker/ClipboardContainer.js
index f24720858..3e16778ef 100644
--- a/loleaflet/src/layer/marker/ClipboardContainer.js
+++ b/loleaflet/src/layer/marker/ClipboardContainer.js
@@ -493,14 +493,10 @@ L.ClipboardContainer = L.Layer.extend({
// MSIE/Edge cannot compare a string to "\n" for whatever reason,
// so compare charcode as well
if (text === '\n' || (text.length === 1 && text.charCodeAt(0) === 13)) {
- // we get a duplicate key-event on Gecko, oddly so drop it.
- if (!L.Browser.gecko)
- {
- // The composition messages doesn't play well with just a line break,
- // therefore send a keystroke.
- this._sendKeyEvent(13, 1280);
- this._emptyArea();
- }
+ // The composition messages doesn't play well with just a line break,
+ // therefore send a keystroke.
+ this._sendKeyEvent(13, 1280);
+ this._emptyArea();
} else {
// The composition messages doesn't play well with line breaks inside
// the composed word (e.g. word and a newline are queued client-side
diff --git a/loleaflet/src/map/handler/Map.Keyboard.js b/loleaflet/src/map/handler/Map.Keyboard.js
index 1e5299ef7..fb0f8954f 100644
--- a/loleaflet/src/map/handler/Map.Keyboard.js
+++ b/loleaflet/src/map/handler/Map.Keyboard.js
@@ -338,10 +338,10 @@ L.Map.Keyboard = L.Handler.extend({
}
}
else if ((ev.type === 'keypress') && (!this.handleOnKeyDownKeys[keyCode] || charCode !== 0)) {
- if (keyCode === 8 || keyCode === 46)
+ if (keyCode === 8 || keyCode === 46 || keyCode === 13)
{
// handled generically in ClipboardContainer.js
- console.log('Ignore backspace/delete keypress');
+ console.log('Ignore backspace/delete/enter keypress');
return;
}
if (charCode === keyCode && charCode !== 13) {
commit 005bc16a48b10de38fe6d8418d290f634627ccdf
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Tue Jul 23 17:59:43 2019 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 13:54:47 2019 +0100
input: ensure we emit a backspace as we repair for gboard.
But don't let ourselves emit another one with in an input call later.
Change-Id: Ic4443b5e6d5a5dbb1ac5381328134af98739b299
diff --git a/loleaflet/src/layer/marker/ClipboardContainer.js b/loleaflet/src/layer/marker/ClipboardContainer.js
index e2c0e7602..f24720858 100644
--- a/loleaflet/src/layer/marker/ClipboardContainer.js
+++ b/loleaflet/src/layer/marker/ClipboardContainer.js
@@ -23,6 +23,7 @@ L.ClipboardContainer = L.Layer.extend({
// Content
this._lastContent = []; // unicode characters
this._hasWorkingSelectionStart = undefined; // does it work ?
+ this._ignoreNextBackspace = false;
// Might need to be \xa0 in some legacy browsers ?
this._spaceChar = ' ';
@@ -322,6 +323,7 @@ L.ClipboardContainer = L.Layer.extend({
if (this._isDebugOn) {
var state = this._isComposing ? 'C' : 'N';
state += this._hasWorkingSelectionStart ? 'S' : '-';
+ state += this._ignoreNextBackspace ? 'I' : '-';
state += ' ';
var textSel = this._textArea.selectionStart + '!' + this._textArea.selectionEnd;
@@ -369,14 +371,18 @@ L.ClipboardContainer = L.Layer.extend({
// we get a beforeinput, but no input for them. Sometimes we can end up
// in a state where we lost our leading / terminal chars and can't recover
_onBeforeInput: function _onBeforeInput(/* ev */) {
+ this._ignoreNextBackspace = false;
if (this._hasWorkingSelectionStart) {
- if (this._textArea.length == 2 &&
- this._textArea.value === this._spaceChar + this._spaceChar &&
+ var value = this._textArea.value;
+ if (value.length == 2 && value === this._spaceChar + this._spaceChar &&
this._textArea.selectionStart === 0)
{
// It seems some inputs eg. GBoard can magically move the cursor from " | " to "| "
console.log('Oh dear, gboard sabotaged our cursor position, fixing');
+ this._removeTextContent(1, 0);
this._emptyArea();
+ // Having mended it we now get a real backspace on input (sometimes)
+ this._ignoreNextBackspace = true;
}
}
},
@@ -421,7 +427,11 @@ L.ClipboardContainer = L.Layer.extend({
console.log('Missing terminal nodes: ' + this._deleteHint);
if (this._deleteHint == 'backspace' ||
this._textArea.selectionStart === 0)
- this._removeTextContent(1, 0);
+ {
+ if (!this._ignoreNextBackspace)
+ this._removeTextContent(1, 0);
+ this._ignoreNextBackspace = false;
+ }
else if (this._deleteHint == 'delete' ||
this._textArea.selectionStart === 1)
this._removeTextContent(0, 1);
commit 4e8b529604c9feb9948f278fc0a903624dceaebc
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Tue Jul 23 17:35:50 2019 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 13:54:43 2019 +0100
input: track if we have a working selectionStart & correct problems.
It -seems- that GBoard can move the cursor selection in some cases.
Adding the test code to fetch the cursor position seems to avoid it
being called, possibly timing sensitive.
Change-Id: I97a3bceec2169e8c15b8157a3c3eca1005a69172
diff --git a/loleaflet/src/layer/marker/ClipboardContainer.js b/loleaflet/src/layer/marker/ClipboardContainer.js
index e244e2495..e2c0e7602 100644
--- a/loleaflet/src/layer/marker/ClipboardContainer.js
+++ b/loleaflet/src/layer/marker/ClipboardContainer.js
@@ -22,7 +22,7 @@ L.ClipboardContainer = L.Layer.extend({
// Content
this._lastContent = []; // unicode characters
- this._lastCursor = 1; // last cursor position.
+ this._hasWorkingSelectionStart = undefined; // does it work ?
// Might need to be \xa0 in some legacy browsers ?
this._spaceChar = ' ';
@@ -103,6 +103,7 @@ L.ClipboardContainer = L.Layer.extend({
);
onoff(this._textArea, 'input', this._onInput, this);
+ onoff(this._textArea, 'beforeinput', this._onBeforeInput, this);
onoff(this._textArea, 'compositionstart', this._onCompositionStart, this);
onoff(this._textArea, 'compositionupdate', this._onCompositionUpdate, this);
onoff(this._textArea, 'compositionend', this._onCompositionEnd, this);
@@ -320,6 +321,7 @@ L.ClipboardContainer = L.Layer.extend({
// Pretty-print on console (but only if "tile layer debug mode" is active)
if (this._isDebugOn) {
var state = this._isComposing ? 'C' : 'N';
+ state += this._hasWorkingSelectionStart ? 'S' : '-';
state += ' ';
var textSel = this._textArea.selectionStart + '!' + this._textArea.selectionEnd;
@@ -363,6 +365,22 @@ L.ClipboardContainer = L.Layer.extend({
}
},
+ // Backspaces and deletes at the beginning / end are filtered out, so
+ // we get a beforeinput, but no input for them. Sometimes we can end up
+ // in a state where we lost our leading / terminal chars and can't recover
+ _onBeforeInput: function _onBeforeInput(/* ev */) {
+ if (this._hasWorkingSelectionStart) {
+ if (this._textArea.length == 2 &&
+ this._textArea.value === this._spaceChar + this._spaceChar &&
+ this._textArea.selectionStart === 0)
+ {
+ // It seems some inputs eg. GBoard can magically move the cursor from " | " to "| "
+ console.log('Oh dear, gboard sabotaged our cursor position, fixing');
+ this._emptyArea();
+ }
+ }
+ },
+
// Fired when text has been inputed, *during* and after composing/spellchecking
_onInput: function _onInput(ev) {
this._map.notifyActive();
@@ -448,7 +466,6 @@ L.ClipboardContainer = L.Layer.extend({
newText = newText.slice(matchTo);
this._lastContent = content;
- this._lastCursor = this._textArea.selectionStart;
if (newText.length > 0)
this._sendText(String.fromCharCode.apply(null, newText));
@@ -515,9 +532,11 @@ L.ClipboardContainer = L.Layer.extend({
this._lastContent = [];
this._textArea.value = this._spaceChar + this._spaceChar;
- /// TODO: Check that this selection method works with MSIE11
this._textArea.setSelectionRange(1, 1);
- this._lastCursor = 1;
+ if (this._hasWorkingSelectionStart === undefined)
+ this._hasWorkingSelectionStart = (this._textArea.selectionStart === 1);
+
+ this._fancyLog('empty-area-end');
this._ignoreInputCount--;
},
commit cdb2ab1437034f94789e1517ad64752149a6edb7
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Tue Jul 23 15:43:41 2019 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 13:54:38 2019 +0100
input: handle backspace on android/gboard more robustly.
We get no direction hint in this case - so use cursor position.
Change-Id: Ic69f075507fe619ccac84f3d5a595bf6cd413a41
diff --git a/loleaflet/src/layer/marker/ClipboardContainer.js b/loleaflet/src/layer/marker/ClipboardContainer.js
index 71567ae78..e244e2495 100644
--- a/loleaflet/src/layer/marker/ClipboardContainer.js
+++ b/loleaflet/src/layer/marker/ClipboardContainer.js
@@ -401,10 +401,12 @@ L.ClipboardContainer = L.Layer.extend({
}
if (content.length < 2) {
console.log('Missing terminal nodes: ' + this._deleteHint);
- if (this._deleteHint == 'delete')
- this._removeTextContent(0, 1);
- else if (this._deleteHint == 'backspace')
+ if (this._deleteHint == 'backspace' ||
+ this._textArea.selectionStart === 0)
this._removeTextContent(1, 0);
+ else if (this._deleteHint == 'delete' ||
+ this._textArea.selectionStart === 1)
+ this._removeTextContent(0, 1);
else
console.log('Cant detect delete or backspace');
this._emptyArea();
commit 26dc90887fe44d86b83569e3d44039a9dfb2fb4e
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Mon Jul 22 20:46:46 2019 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 13:54:24 2019 +0100
Enable firefox, IE11, Edge, etc.
Ignore backspace keypress to avoid duplicate deletion in firefox.
Handle distinguishing <space><delete> from <backspace>.
Change-Id: Ia279aab929977b3522452adcbfac0c4aad189771
diff --git a/loleaflet/src/layer/marker/ClipboardContainer.js b/loleaflet/src/layer/marker/ClipboardContainer.js
index 709045824..71567ae78 100644
--- a/loleaflet/src/layer/marker/ClipboardContainer.js
+++ b/loleaflet/src/layer/marker/ClipboardContainer.js
@@ -13,11 +13,19 @@ L.ClipboardContainer = L.Layer.extend({
// compositionstart/compositionend events; unused
this._isComposing = false;
+ // We need to detect whether delete or backspace was
+ // pressed sometimes - consider ' foo' -> ' foo'
+ this._deleteHint = ''; // or 'delete' or 'backspace'
+
// Clearing the area can generate input events
this._ignoreInputCount = 0;
// Content
this._lastContent = []; // unicode characters
+ this._lastCursor = 1; // last cursor position.
+
+ // Might need to be \xa0 in some legacy browsers ?
+ this._spaceChar = ' ';
// Debug flag, used in fancyLog(). See the debug() method.
// this._isDebugOn = true;
@@ -98,6 +106,7 @@ L.ClipboardContainer = L.Layer.extend({
onoff(this._textArea, 'compositionstart', this._onCompositionStart, this);
onoff(this._textArea, 'compositionupdate', this._onCompositionUpdate, this);
onoff(this._textArea, 'compositionend', this._onCompositionEnd, this);
+ onoff(this._textArea, 'keydown', this._onKeyDown, this);
onoff(this._textArea, 'keyup', this._onKeyUp, this);
onoff(this._textArea, 'copy cut paste', this._map._handleDOMEvent, this._map);
@@ -139,8 +148,6 @@ L.ClipboardContainer = L.Layer.extend({
getValue: function() {
var value = this._textArea.value;
- // kill unwanted entities
- value = value.replace(/ /g, ' ');
return value;
},
@@ -315,6 +322,9 @@ L.ClipboardContainer = L.Layer.extend({
var state = this._isComposing ? 'C' : 'N';
state += ' ';
+ var textSel = this._textArea.selectionStart + '!' + this._textArea.selectionEnd;
+ state += textSel + ' ';
+
var sel = window.getSelection();
var content = this.getValue();
if (sel === null)
@@ -340,6 +350,8 @@ L.ClipboardContainer = L.Layer.extend({
content = content.slice(0, cursorPos) + '|' + content.slice(cursorPos);
}
+ state += '[' + this._deleteHint + '] ';
+
console.log2(
+ new Date() + ' %cINPUT%c: ' + state
+ '"' + content + '" ' + type + '%c ',
@@ -352,7 +364,7 @@ L.ClipboardContainer = L.Layer.extend({
},
// Fired when text has been inputed, *during* and after composing/spellchecking
- _onInput: function _onInput(/* ev */) {
+ _onInput: function _onInput(ev) {
this._map.notifyActive();
if (this._ignoreInputCount > 0) {
@@ -360,22 +372,44 @@ L.ClipboardContainer = L.Layer.extend({
return;
}
+ if (ev.inputType) {
+ if (ev.inputType == 'deleteContentForward')
+ this._deleteHint = 'delete';
+ else if (ev.inputType == 'deleteContentBackward')
+ this._deleteHint = 'backspace';
+ else
+ this._deleteHint = '';
+ }
+
var content = this.getValueAsCodePoints();
+ var spaceChar = this._spaceChar.charCodeAt(0);
+
// We use a different leading and terminal space character
// to differentiate backspace from delete, then replace the character.
- if (content[0] !== 16*10) { // missing initial non-breaking space.
+ if (content.length < 1 || content[0] !== spaceChar) { // missing initial space
console.log('Sending backspace');
this._removeTextContent(1, 0);
this._emptyArea();
return;
}
- if (content[content.length-1] !== 32) { // missing trailing space.
+ if (content[content.length-1] !== spaceChar) { // missing trailing space.
console.log('Sending delete');
this._removeTextContent(0, 1);
this._emptyArea();
return;
}
+ if (content.length < 2) {
+ console.log('Missing terminal nodes: ' + this._deleteHint);
+ if (this._deleteHint == 'delete')
+ this._removeTextContent(0, 1);
+ else if (this._deleteHint == 'backspace')
+ this._removeTextContent(1, 0);
+ else
+ console.log('Cant detect delete or backspace');
+ this._emptyArea();
+ return;
+ }
// remove leading & tailing spaces.
content = content.slice(1, -1);
@@ -389,18 +423,37 @@ L.ClipboardContainer = L.Layer.extend({
'\tnew "' + String.fromCharCode.apply(null, content) + '" (' + content.length + ')' + '\n' +
'\told "' + String.fromCharCode.apply(null, this._lastContent) + '" (' + this._lastContent.length + ')');
- var remove = this._lastContent.length - matchTo;
- if (remove > 0)
- this._removeTextContent(remove, 0);
+ var removeBefore = this._lastContent.length - matchTo;
+ var removeAfter = 0;
+
+ if (this._lastContent.length > content.length)
+ {
+ // Pressing '<space><delete>' can delete our terminal space
+ // such that subsequent deletes will do nothing; need to
+ // detect and reset in this case.
+ if (this._deleteHint === 'delete')
+ {
+ removeBefore--;
+ removeAfter++;
+ }
+ }
+
+ if (removeBefore > 0 || removeAfter > 0)
+ this._removeTextContent(removeBefore, removeAfter);
var newText = content;
if (matchTo > 0)
newText = newText.slice(matchTo);
this._lastContent = content;
+ this._lastCursor = this._textArea.selectionStart;
if (newText.length > 0)
this._sendText(String.fromCharCode.apply(null, newText));
+
+ // was a 'delete' and we need to reset world.
+ if (removeAfter > 0)
+ this._emptyArea();
},
// Sends the given (UTF-8) string of text to lowsd, as IME (text composition)
@@ -451,15 +504,18 @@ L.ClipboardContainer = L.Layer.extend({
this._ignoreInputCount++;
// Note: 0xA0 is 160, which is the character code for non-breaking space:
// https://www.fileformat.info/info/unicode/char/00a0/index.htm
+
// Using normal spaces would make FFX/Gecko collapse them into an
// empty string.
+ // FIXME: is that true !? ...
console.log('Set old/lastContent to empty');
this._lastContent = [];
- this._textArea.value = '\xa0 ';
+ this._textArea.value = this._spaceChar + this._spaceChar;
/// TODO: Check that this selection method works with MSIE11
this._textArea.setSelectionRange(1, 1);
+ this._lastCursor = 1;
this._ignoreInputCount--;
},
@@ -497,66 +553,13 @@ L.ClipboardContainer = L.Layer.extend({
this._emptyArea();
},
- // Override the system default for pasting into the textarea/contenteditable,
- // and paste into the document instead.
- _onPaste: function _onPaste(ev) {
- // Prevent the event's default - in this case, prevent the clipboard contents
- // from being added to the hidden textarea and firing 'input'/'textInput' events.
- ev.preventDefault();
-
- // TODO: handle internal selection here (compare pasted plaintext with the
- // last copied/cut plaintext, send a UNO 'paste' command over websockets if so.
- // if (this._lastClipboardText === ...etc...
-
- var pasteString;
- if (ev.clipboardData) {
- pasteString = ev.clipboardData.getData('text/plain'); // non-IE11
- } else if (window.clipboardData) {
- pasteString = window.clipboardData.getData('Text'); // IE 11
- }
-
- if (pasteString && pasteString === this._lastClipboardText) {
- // If the pasted text is the same as the last copied/cut text,
- // let lowsd use LOK's clipboard instead. This is done in order
- // to keep formatting and non-text bits.
- this._map._socket.sendMessage('uno .uno:Paste');
- return;
- }
-
- // Let the TileLayer functionality take care of sending the
- // DataTransfer from the event to lowsd.
- this._map._docLayer._dataTransferToDocument(
- ev.clipboardData || window.clipboardData /* IE11 */
- );
-
- this._abortComposition();
- },
-
- // Override the system default for cut & copy - ensure that the system clipboard
- // receives *plain text* (instead of HTML/RTF), and save internal state.
- // TODO: Change the 'gettextselection' command, so that it can fetch the HTML
- // version of the copied text **maintaining typefaces**.
- _onCutCopy: function _onCutCopy(ev) {
- var plaintext = document.getSelection().toString();
-
- this._lastClipboardText = plaintext;
-
- if (ev.type === 'copy') {
- this._map._socket.sendMessage('uno .uno:Copy');
- } else if (ev.type === 'cut') {
- this._map._socket.sendMessage('uno .uno:Cut');
- }
-
- if (event.clipboardData) {
- event.clipboardData.setData('text/plain', plaintext); // non-IE11
- } else if (window.clipboardData) {
- window.clipboardData.setData('Text', plaintext); // IE 11
- } else {
- console.warn('Could not set the clipboard contents to plain text.');
- return;
- }
-
- event.preventDefault();
+ _onKeyDown: function _onKeyDown(ev) {
+ if (ev.keyCode == 8)
+ this._deleteHint = 'backspace';
+ else if (ev.keyCode == 46)
+ this._deleteHint = 'delete';
+ else
+ this._deleteHint = '';
},
// Check arrow keys on 'keyup' event; using 'ArrowLeft' or 'ArrowRight'
diff --git a/loleaflet/src/map/handler/Map.Keyboard.js b/loleaflet/src/map/handler/Map.Keyboard.js
index 0ef5d1a66..1e5299ef7 100644
--- a/loleaflet/src/map/handler/Map.Keyboard.js
+++ b/loleaflet/src/map/handler/Map.Keyboard.js
@@ -338,6 +338,12 @@ L.Map.Keyboard = L.Handler.extend({
}
}
else if ((ev.type === 'keypress') && (!this.handleOnKeyDownKeys[keyCode] || charCode !== 0)) {
+ if (keyCode === 8 || keyCode === 46)
+ {
+ // handled generically in ClipboardContainer.js
+ console.log('Ignore backspace/delete keypress');
+ return;
+ }
if (charCode === keyCode && charCode !== 13) {
// Chrome sets keyCode = charCode for printable keys
// while LO requires it to be 0
commit 54251f39e7ed4380c58d9a6b9bd702d689ded0e4
Author: Iván Sánchez Ortega <ivan.sanchez at collabora.com>
AuthorDate: Mon Jul 22 17:06:55 2019 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 13:53:04 2019 +0100
Prevent automatic line breaks in the textarea.
Change-Id: I6040f2f2e0285d6872686c7db2edfc08df4522bc
diff --git a/loleaflet/src/layer/marker/ClipboardContainer.js b/loleaflet/src/layer/marker/ClipboardContainer.js
index c18a7ebe9..709045824 100644
--- a/loleaflet/src/layer/marker/ClipboardContainer.js
+++ b/loleaflet/src/layer/marker/ClipboardContainer.js
@@ -197,6 +197,12 @@ L.ClipboardContainer = L.Layer.extend({
this._textArea.setAttribute('autocomplete', 'off');
this._textArea.setAttribute('spellcheck', 'false');
+ // Prevent automatic line breaks in the textarea. Without this,
+ // chromium/blink will trigger input/insertLineBreak events by
+ // just adding whitespace.
+ // See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea#attr-wrap
+ this._textArea.setAttribute('wrap', 'off');
+
this._setupStyles();
this._emptyArea();
commit 6f9508863fcc21b50197f24f8d00d308686aa2e0
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Mon Jul 22 17:01:03 2019 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 13:52:36 2019 +0100
input: start again - switch to using textarea and diffing it's content.
A much simpler, and more robust approach.
Change-Id: I855818e69845212523848464a4ab07d22a762dba
diff --git a/loleaflet/src/layer/marker/ClipboardContainer.js b/loleaflet/src/layer/marker/ClipboardContainer.js
index d89c7fa9a..c18a7ebe9 100644
--- a/loleaflet/src/layer/marker/ClipboardContainer.js
+++ b/loleaflet/src/layer/marker/ClipboardContainer.js
@@ -2,68 +2,25 @@
/*
* L.ClipboardContainer is the hidden textarea, which handles text
* input events and clipboard selection.
+ *
*/
/* global */
L.ClipboardContainer = L.Layer.extend({
initialize: function() {
- // Queued input - this shall be sent to lowsd after a short timeout,
- // and might be canceled in the event of a 'deleteContentBackward'
- // input event, to account for predictive keyboard behaviour.
- this._queuedInput = '';
- this._queueTimer = undefined;
-
- // Flag to denote the composing state, derived from compositionstart/compositionend events.
- // Needed for a edge case in Chrome+AOSP where an
- // "input/deleteContentBackward" event is fired with "isComposing" set
- // to false even though it happens *before* a "compositionend" event.
- // Also for some cases in desktop Safari when an InputEvent doesn't have a "isComposing"
- // property (and therefore evaluates to "undefined")
+ // Flag to denote the composing state, derived from
+ // compositionstart/compositionend events; unused
this._isComposing = false;
- // Stores the range(s) of the last 'beforeinput' event, so that the input event
- // can access it.
- this._lastRanges = [];
-
- // Stores the data of the last 'compositionstart' event. Needed to abort
- // composition when going back to spellcheck a word in FFX/Gecko + GBoard.
- // this._lastCompositionStartData = [];
-
- // Stores the type of the last 'input' event. Needed to abort composition
- // when going back to spellcheck a word in FFX/Gecko + AnySoftKeyboard and
- // some other scenarios.
- this._lastInputType = '';
-
- // Length of the document's selection when the last 'beforeinput' event was
- // handled. Needed to catch and handle an edge case in Chrome where hitting
- // either delete or backspace with active selection sends messages for both
- // the input event and the keystrokes.
- this._selectionLengthAtBeforeInput = 0;
-
- // Idem to _lastInputType. Needed to handle the right keystroke on the edge case
- // that this._selectionLengthAtBeforeInput helps catch.
- this._lastBeforeInputType = '';
-
- // Capability check.
- this._hasInputType = window.InputEvent && 'inputType' in window.InputEvent.prototype;
-
- // The "normal" order of composition events is:
- // - compositionstart
- // - compositionupdate
- // - input/insertCompositionText
- // But if the user goes back to a previous word for spellchecking, the browser
- // might fire a compositionupdate *without* a corresponding input event later.
- // In that case, the composition has to be aborted. Because of the order of
- // the events, a timer is needed to check for the right conditions.
- this._abortCompositionTimeout = undefined;
-
- // Defines whether to use a <input type=textarea> (when true) or a
- // <div contenteditable> (when false)
- this._legacyArea = L.Browser.safari;
+ // Clearing the area can generate input events
+ this._ignoreInputCount = 0;
+
+ // Content
+ this._lastContent = []; // unicode characters
// Debug flag, used in fancyLog(). See the debug() method.
-// this._isDebugOn = true;
+// this._isDebugOn = true;
this._isDebugOn = false;
this._initLayout();
@@ -77,13 +34,8 @@ L.ClipboardContainer = L.Layer.extend({
draggable: true
}).on('dragend', this._onCursorHandlerDragEnd, this);
- // Used for internal cut/copy/paste in the same document - to tell
- // lowsd whether to use its internal clipboard state (rich text) or to send
- // the browser contents (plaintext)
- this._lastClipboardText = undefined;
-
- // This variable prevents from hiding the keyboard just before focus call
- this.dontBlur = false;
+ var that = this;
+ this._selectionHandler = function(ev) { that._onEvent(ev); }
},
onAdd: function() {
@@ -104,9 +56,6 @@ L.ClipboardContainer = L.Layer.extend({
}
L.DomEvent.on(this._map.getContainer(), 'mousedown touchstart', this._abortComposition, this);
- // L.DomEvent.on(this._map.getContainer(), 'mousedown touchstart', function(ev) {
- // this._fancyLog(ev.type);
- // }, this);
},
onRemove: function() {
@@ -121,7 +70,7 @@ L.ClipboardContainer = L.Layer.extend({
},
_onFocusBlur: function(ev) {
-// console.log(ev.type, performance.now(), ev);
+ this._fancyLog(ev.type, '');
if (this.dontBlur && ev.type == 'blur') {
this._map.focus();
@@ -137,46 +86,25 @@ L.ClipboardContainer = L.Layer.extend({
var onoff = (ev.type == 'focus' ? L.DomEvent.on : L.DomEvent.off).bind(L.DomEvent);
- onoff(this._textArea, 'compositionstart', this._onCompositionStart, this);
- onoff(this._textArea, 'compositionend', this._onCompositionEnd, this);
- onoff(this._textArea, 'beforeinput', this._onBeforeInput, this);
- onoff(this._textArea, 'cut copy', this._onCutCopy, this);
- onoff(this._textArea, 'paste', this._onPaste, this);
- onoff(this._textArea, 'input', this._onInput, this);
- onoff(this._textArea, 'keyup', this._onKeyUp, this);
-
- if (L.Browser.ie) {
- onoff(this._textArea, 'textinput', this._onMSIETextInput, this);
- onoff(this._textArea, 'keydown', this._onMSIEKeyDown, this);
- }
- if (L.Browser.edge) {
- onoff(this._textArea, 'keydown', this._onEdgeKeyDown, this);
- }
-
- // Stock android browsers (using an embedded WebView) wihout an InputEvent
- // implementation behave similar to MSIE in regards to "enter" & "delete"
- // keypresses
- if (L.Browser.android && L.Browser.mobileWebkit3d && !('InputEvent' in window)) {
- onoff(this._textArea, 'keydown', this._onMSIEKeyDown, this);
- }
-
- // Debug
+ // Debug - connect first for saner logging.
onoff(
this._textArea,
- 'copy cut compositionstart compositionupdate compositionend select selectionstart selectionchange keydown keypress keyup beforeinput textInput textinput input',
+ 'copy cut compositionstart compositionupdate compositionend select keydown keypress keyup beforeinput textInput textinput input',
this._onEvent,
this
);
+ onoff(this._textArea, 'input', this._onInput, this);
+ onoff(this._textArea, 'compositionstart', this._onCompositionStart, this);
+ onoff(this._textArea, 'compositionupdate', this._onCompositionUpdate, this);
+ onoff(this._textArea, 'compositionend', this._onCompositionEnd, this);
+ onoff(this._textArea, 'keyup', this._onKeyUp, this);
+ onoff(this._textArea, 'copy cut paste', this._map._handleDOMEvent, this._map);
+
this._map.notifyActive();
- if (ev.type === 'blur') {
- if (this._isComposing) {
- this._queueInput(this._compositionText);
- }
- this._abortComposition();
- } else {
- this._winId = 0;
+ if (ev.type === 'blur' && this._isComposing) {
+ this._abortComposition(ev);
}
},
@@ -196,16 +124,7 @@ L.ClipboardContainer = L.Layer.extend({
// Marks the content of the textarea/contenteditable as selected,
// for system clipboard interaction.
select: function select() {
- if (this._legacyArea) {
- this._textArea.select();
- } else {
- // As per https://stackoverflow.com/a/6150060/4768502
- var range = document.createRange();
- range.selectNodeContents(this._textArea);
- var sel = window.getSelection();
- sel.removeAllRanges();
- sel.addRange(range);
- }
+ this._textArea.select();
},
warnCopyPaste: function() {
@@ -219,11 +138,31 @@ L.ClipboardContainer = L.Layer.extend({
},
getValue: function() {
- if (this._legacyArea) {
- return this._textArea.value;
- } else {
- return this._textArea.textContent;
+ var value = this._textArea.value;
+ // kill unwanted entities
+ value = value.replace(/ /g, ' ');
+ return value;
+ },
+
+ getValueAsCodePoints: function() {
+ var value = this.getValue();
+ var arr = [];
+ var code;
+ for (var i = 0; i < value.length; ++i)
+ {
+ code = value.charCodeAt(i);
+
+ // if it were not for IE11: "for (code of value)" does the job.
+ if (code >= 0xd800 && code <= 0xdbff) // handle UTF16 pairs.
+ {
+ // TESTME: harder ...
+ var high = (code - 0xd800) << 10;
+ code = value.charCodeAt(++i);
+ code = high + code - 0xdc00 + 0x100000;
+ }
+ arr.push(code);
}
+ return arr;
},
setValue: function(val) {
@@ -251,18 +190,7 @@ L.ClipboardContainer = L.Layer.extend({
// The textarea allows the keyboard to pop up and so on.
// Note that the contents of the textarea are NOT deleted on each composed
// word, in order to make
-
- if (this._legacyArea) {
- // Force a textarea on Safari. This is two-fold: Safari doesn't fire
- // input/insertParagraph events on an empty&focused contenteditable,
- // but does fire input/insertLineBreak on an empty&focused textarea;
- // Safari on iPad would show bold/italic/underline native controls
- // which cannot be handled with the current implementation.
- this._textArea = L.DomUtil.create('textarea', 'clipboard', this._container);
- } else {
- this._textArea = L.DomUtil.create('div', 'clipboard', this._container);
- this._textArea.setAttribute('contenteditable', 'true');
- }
+ this._textArea = L.DomUtil.create('textarea', 'clipboard', this._container);
this._textArea.setAttribute('autocapitalize', 'off');
this._textArea.setAttribute('autofocus', 'true');
this._textArea.setAttribute('autocorrect', 'off');
@@ -270,6 +198,8 @@ L.ClipboardContainer = L.Layer.extend({
this._textArea.setAttribute('spellcheck', 'false');
this._setupStyles();
+
+ this._emptyArea();
},
_setupStyles: function() {
@@ -346,42 +276,21 @@ L.ClipboardContainer = L.Layer.extend({
L.DomUtil.setPosition(this._container, pos);
},
- // Return the content of _lastRanges as a string.
- _lastRangesString: function() {
- if (
- this._lastRanges[0] &&
- 'startOffset' in this._lastRanges[0] &&
- 'endOffset' in this._lastRanges[0]
- ) {
- return this._lastRanges[0].startOffset + '-' + this._lastRanges[0].endOffset;
- }
-
- return undefined;
- },
-
// Generic handle attached to most text area events, just for debugging purposes.
_onEvent: function _onEvent(ev) {
var msg = {
- type: ev.type,
inputType: ev.inputType,
data: ev.data,
key: ev.key,
isComposing: ev.isComposing
};
- msg.lastRanges = this._lastRangesString();
-
- if (ev.type === 'input') {
- msg.inputType = ev.inputType;
- }
-
if ('key' in ev) {
msg.key = ev.key;
msg.keyCode = ev.keyCode;
msg.code = ev.code;
msg.which = ev.which;
}
-
this._fancyLog(ev.type, msg);
},
@@ -397,8 +306,37 @@ L.ClipboardContainer = L.Layer.extend({
// Pretty-print on console (but only if "tile layer debug mode" is active)
if (this._isDebugOn) {
+ var state = this._isComposing ? 'C' : 'N';
+ state += ' ';
+
+ var sel = window.getSelection();
+ var content = this.getValue();
+ if (sel === null)
+ state += '-1';
+ else
+ {
+ state += sel.rangeCount;
+
+ state += ' ';
+ var cursorPos = -1;
+ for (var i = 0; i < sel.rangeCount; ++i)
+ {
+ var range = sel.getRangeAt(i);
+ state += range.startOffset + '-' + range.endOffset + ' ';
+ if (cursorPos < 0)
+ cursorPos = range.startOffset;
+ }
+ if (sel.toString() !== '')
+ state += ': "' + sel.toString() + '" ';
+
+ // inject probable cursor
+ if (cursorPos >= 0)
+ content = content.slice(0, cursorPos) + '|' + content.slice(cursorPos);
+ }
+
console.log2(
- +new Date() + ' %cINPUT%c: ' + type + '%c',
+ + new Date() + ' %cINPUT%c: ' + state
+ + '"' + content + '" ' + type + '%c ',
'background:#bfb;color:black',
'color:green',
'color:black',
@@ -408,153 +346,55 @@ L.ClipboardContainer = L.Layer.extend({
},
// Fired when text has been inputed, *during* and after composing/spellchecking
- _onInput: function _onInput(ev) {
+ _onInput: function _onInput(/* ev */) {
this._map.notifyActive();
- var previousInputType = this._lastInputType;
- this._lastInputType = ev.inputType;
-
- if (!('inputType' in ev)) {
- // Legacy MSIE or Android WebView, just send the contents of the
- // container and clear it.
- if (this._isComposing) {
- this._sendCompositionEvent('input', this._textArea.textContent);
- } else {
- if (
- this._textArea.textContent.length === 0 &&
- this._textArea.innerHTML.indexOf('<br>') !== -1
- ) {
- // WebView-specific hack: when the user presses enter, textContent
- // is empty instead of "\n", but a <br> is added to the
- // contenteditable.
- this._sendText('\n');
- } else {
- this._sendText(this._textArea.textContent);
- }
- this._emptyArea();
- }
- } else if (ev.inputType === 'insertCompositionText') {
- // The text being composed has changed.
- // This is diferent from a 'compositionupdate' event: a 'compositionupdate'
- // event might be fired when going back to spellcheck a word, but an
- // 'input/insertCompositionText' happens only when the user is adding to a
- // composition.
-
- // Abort composition when going back for spellchecking, FFX/Gecko
- if (L.Browser.gecko && previousInputType === 'deleteContentBackward') {
- return;
- }
-
- clearTimeout(this._abortCompositionTimeout);
-
- if (!this._isComposing) {
- // FFX/Gecko: Regardless of on-screen keyboard, there is a
- // input/insertCompositionText with isComposing=false *after*
- // the compositionend event.
- this._queueInput(ev.data);
- } else {
- // Flush the queue
- if (this._queuedInput !== '') {
- this._sendQueued();
- }
+ if (this._ignoreInputCount > 0) {
+ console.log('ignoring synthetic input ' + this._ignoreInputCount);
+ return;
+ }
- // Tell lowsd about the current text being composed
- this._sendCompositionEvent('input', ev.data);
- }
- } else if (ev.inputType === 'insertText') {
- // Non-composed text has been added to the text area.
-
- // FFX+AOSP / FFX+AnySoftKeyboard edge case: Autocompleting a
- // one-letter word will fire a input/insertText with that word
- // right after a compositionend + input/insertCompositionText.
- // In that case, ignore the
- if (
- L.Browser.gecko &&
- ev.data.length === 1 &&
- previousInputType === 'insertCompositionText' &&
- ev.data === this._queuedInput
- ) {
- return;
- }
+ var content = this.getValueAsCodePoints();
- if (!this._isComposing) {
- this._queueInput(ev.data);
- }
- } else if (ev.inputType === 'insertParagraph') {
- // Happens on non-Safari on the contenteditable div.
- this._queueInput('\n');
+ // We use a different leading and terminal space character
+ // to differentiate backspace from delete, then replace the character.
+ if (content[0] !== 16*10) { // missing initial non-breaking space.
+ console.log('Sending backspace');
+ this._removeTextContent(1, 0);
this._emptyArea();
- } else if (ev.inputType === 'insertLineBreak') {
- // Happens on Safari on the textarea.
- this._queueInput('\n');
+ return;
+ }
+ if (content[content.length-1] !== 32) { // missing trailing space.
+ console.log('Sending delete');
+ this._removeTextContent(0, 1);
this._emptyArea();
- } else if (ev.inputType === 'deleteContentBackward') {
- if (this._isComposing) {
- // deletion refers to the text being composed, noop
- return;
- }
+ return;
+ }
- // Delete text backwards - as many characters as indicated in the previous
- // 'beforeinput' event
+ // remove leading & tailing spaces.
+ content = content.slice(1, -1);
- // These are sent e.g. by the GBoard keyboard when autocorrecting, meaning
- // "I'm about to send another textInput event with the right word".
+ var matchTo = 0;
+ var sharedLength = Math.min(content.length, this._lastContent.length);
+ while (matchTo < sharedLength && content[matchTo] === this._lastContent[matchTo])
+ matchTo++;
- var count = 1;
- if (this._lastRanges[0]) {
- count = this._lastRanges[0].endOffset - this._lastRanges[0].startOffset;
- }
+ console.log('Comparison matchAt ' + matchTo + '\n' +
+ '\tnew "' + String.fromCharCode.apply(null, content) + '" (' + content.length + ')' + '\n' +
+ '\told "' + String.fromCharCode.apply(null, this._lastContent) + '" (' + this._lastContent.length + ')');
- // If there is queued input, cancel that first. This prevents race conditions
- // in lowsd (compose-backspace-compose messages are handled as
- // compose-compose-backspace).
- // Deleting queued input happens when accepting an autocorrect suggestion;
- // emptying the area in that case would break text composition workflow.
- var l = this._queuedInput.length;
- if (l >= count) {
- this._queuedInput = this._queuedInput.substring(0, l - count);
- } else {
- this._removeTextContext(count, 0);
- this._emptyArea();
- }
+ var remove = this._lastContent.length - matchTo;
+ if (remove > 0)
+ this._removeTextContent(remove, 0);
- L.DomEvent.stop(ev);
- } else if (ev.inputType === 'deleteContentForward') {
- // Send a UNO 'delete' keystroke
- this._sendKeyEvent(46, 1286);
- this._emptyArea();
- } else if (ev.inputType === 'insertReplacementText') {
- // Happens only in Safari (both iOS and OS X) with autocorrect/spellcheck
- // FIXME: It doesn't provide any info about how much to replace!
- // This is currently disabled by means of using a <input type=textarea
- // autocorrect=off> in Safari.
- /// TODO: Send a specific message to lowsd to find the last word and
- /// replace it with the given one.
- } else if (ev.inputType === 'deleteCompositionText') {
- // Safari on OS X is extra nice about composition - it notifies the
- // browser whenever the composition text should be deleted.
- } else if (ev.inputType === 'insertFromComposition') {
- // Observed only on desktop Safari just before a "compositionend"
- // TODO: Check if the
- this._queueInput(ev.data);
- } else if (ev.inputType === 'deleteByCut') {
- // Called when Ctrl+X'ing
- this._abortComposition(ev);
- } else {
- console.error('Unhandled type of input event!!', ev.inputType, ev);
- throw new Error('Unhandled type of input event!');
- }
- },
+ var newText = content;
+ if (matchTo > 0)
+ newText = newText.slice(matchTo);
+
+ this._lastContent = content;
- // Chrome and MSIE (from 9 all the way up to Edge) send the non-standard
- // "textInput" DOM event.
- // In Chrome, this is fired *just before* the compositionend event, and *before*
- // any other "input" events which would add text to the area (e.g. "insertText")
- // "textInput" events are used in MSIE, since the "input" events do not hold
- // information about the text added to the area.
- // In MSIE11, the event is "textinput" (all lowercase).
- _onMSIETextInput: function _onInput(ev) {
- this._queueInput(ev.data);
+ if (newText.length > 0)
+ this._sendText(String.fromCharCode.apply(null, newText));
},
// Sends the given (UTF-8) string of text to lowsd, as IME (text composition)
@@ -565,10 +405,14 @@ L.ClipboardContainer = L.Layer.extend({
// MSIE/Edge cannot compare a string to "\n" for whatever reason,
// so compare charcode as well
if (text === '\n' || (text.length === 1 && text.charCodeAt(0) === 13)) {
- // The composition messages doesn't play well with just a line break,
- // therefore send a keystroke.
- this._sendKeyEvent(13, 1280);
- this._emptyArea();
+ // we get a duplicate key-event on Gecko, oddly so drop it.
+ if (!L.Browser.gecko)
+ {
+ // The composition messages doesn't play well with just a line break,
+ // therefore send a keystroke.
+ this._sendKeyEvent(13, 1280);
+ this._emptyArea();
+ }
} else {
// The composition messages doesn't play well with line breaks inside
// the composed word (e.g. word and a newline are queued client-side
@@ -596,161 +440,34 @@ L.ClipboardContainer = L.Layer.extend({
// (some combination of browser + input method don't fire those on an
// empty contenteditable).
_emptyArea: function _emptyArea() {
- if (this._hasInputType) {
- // Note: 0xA0 is 160, which is the character code for non-breaking space:
- // https://www.fileformat.info/info/unicode/char/00a0/index.htm
- // Using normal spaces would make FFX/Gecko collapse them into an
- // empty string.
- if (this._legacyArea) {
- this._textArea.value = '\xa0\xa0';
- /// TODO: Check that this selection method works with MSIE11
- ///
- this._textArea.setSelectionRange(1, 1);
- } else {
- // The strategy for a contenteditable is to add a space, select it,
- // collapse the selection, then add two text nodes after and before
- // the text node with the selection but with a delay of one frame.
- // The frame delay is done in order to avoid the AOSP on-screen keyboard
- // from moving the cursor caret around. On delete/backspace, AOSP
- // keyboard would somehow ignore the selection ranges and move the caret
- // before/after the empty spaces.
-
- /// FIXME: The aforementioned strategy makes Android + GBoard + Firefox fail:
- /// trying to press the "ArrowLeft" or "ArrowUp" keys in the
- this._textArea.innerText = '\xa0';
-
- var range = document.createRange();
- range.selectNodeContents(this._textArea);
- var sel = window.getSelection();
- sel.removeAllRanges();
- sel.addRange(range);
- sel.collapse(this._textArea.childNodes[0]);
-
- L.Util.requestAnimFrame(function() {
- this._textArea.prepend('\xa0');
- this._textArea.append('\xa0');
- }.bind(this));
+ this._fancyLog('empty-area');
- }
- } else if (this._legacyArea) {
- this._textArea.value = '';
- } else {
- // In order to empty a contenteditable when the two-spaces-hack is not
- // in place, access its first text node child and empty it.
- if (this._textArea.childNodes.length === 1) {
- this._textArea.childNodes[0].data = '';
- } else if (this._textArea.childNodes.length > 1) {
- this._textArea.innerText = '';
- this._textArea.innerHTML = '';
- // Sanity check, should never be reached.
- // True - but for now - lets not kill the world in this case ...
-// throw new Error('Unexpected: more than one text node inside the contenteditable.');
- }
- }
- },
+ this._ignoreInputCount++;
+ // Note: 0xA0 is 160, which is the character code for non-breaking space:
+ // https://www.fileformat.info/info/unicode/char/00a0/index.htm
+ // Using normal spaces would make FFX/Gecko collapse them into an
+ // empty string.
- // The getTargetRanges() method usually returns an empty array,
- // since the ranges are only valid at the "beforeinput" stage.
- // Fetching this info for later is important, especially
- // for Chrome+"input/deleteContentBackward" events.
- // Also, some deleteContentBackward/Forward input types
- // only happen at 'beforeinput' and not at 'input' events,
- // particularly when the textarea/contenteditable is empty, but
- // only in some configurations.
- _onBeforeInput: function _onBeforeInput(ev) {
- this._lastRanges = ev.getTargetRanges();
- // console.log('onBeforeInput range: ', ev.inputType, ranges,
- // ranges[0] && ranges[0].startOffset,
- // ranges[0] && ranges[0].endOffset);
-
- this._lastBeforeInputType = ev.inputType;
- this._selectionLengthAtBeforeInput = selection.length;
-
- this._fancyLog('beforeinput selection', window.getSelection().toString());
- this._fancyLog('beforeinput range', this._lastRangesString());
-
- // FIXME: a hack - this assumes that nothing changed / no auto-correction inside the Kit.
- // FIXME: only mobile for now to reduce risk ...
- if (window.mode.isMobile() || window.mode.isTablet())
- {
- var seltext = window.getSelection();
- if (!this._isComposing && seltext && seltext.toString() && seltext.toString().length > 0)
- {
- var len = seltext.toString().length;
- this._fancyLog('selection overtype', seltext.toString() + ' len ' + len + ' chars "' + this._queuedInput + '"');
- if (this._queuedInput)
- {
- var size = this._queuedInput.length;
- var redux = Math.min(size, len);
- this._queuedInput = this._queuedInput.slice(0,-redux);
- len -= redux;
- console.log2('queue overtype', 'removed ' + redux + ' from queued input to "' + this._queuedInput + '"');
- }
- // FIXME: this is the more hacky bit - if the Kit changed under us.
- for (var i = 0; i < len; ++i)
- this._sendKeyEvent(8, 1283);
- }
- }
+ console.log('Set old/lastContent to empty');
+ this._lastContent = [];
- // When trying to delete (i.e. backspace) on an empty textarea, the input event
- // won't be fired afterwards. Handle backspace here instead.
-
- // Chrome + AOSP does *not* send any "beforeinput" events when the
- // textarea is empty. In that case, a 'keydown'+'keypress'+'keyup' sequence
- // for charCode=8 is fired, and handled by the Map.Keyboard.js.
- if ((this._winId === 0 && this._textArea.textContent.length === 0) ||
- ev.findMyTextContentAre.length == 0) {
- if (ev.inputType === 'deleteContentBackward') {
- this._sendKeyEvent(8, 1283);
- } else if (ev.inputType === 'deleteContentForward') {
- this._sendKeyEvent(46, 1286);
- }
- }
- },
+ this._textArea.value = '\xa0 ';
+ /// TODO: Check that this selection method works with MSIE11
+ this._textArea.setSelectionRange(1, 1);
- _queueInput: function _queueInput(text) {
- this._map.notifyActive();
-
- if (text === null) {
- // Chrome sends a input/insertText with 'null' event data when
- // typing a newline quickly after typing text.
- console.warn('Tried to queue null text! Maybe a lost newline?');
- this._queuedInput += '\n';
- clearTimeout(this._queueTimer);
- }
- else if (this._queuedInput !== '') {
- console.warn(
- 'Text input already queued - recieving composition end events too fast!'
- );
- this._queuedInput += text;
- clearTimeout(this._queueTimer);
- } else {
- this._queuedInput = text;
- }
-
- //console.log('_queueInput', text, ' queue is now:', {text: this._queuedInput});
- this._queueTimer = setTimeout(this._sendQueued.bind(this), 50);
- },
-
- _clearQueued: function _clearQueued() {
- // console.log('Cleared queued:', { text: this._queuedInput });
- clearTimeout(this._queueTimer);
- this._queuedInput = '';
- },
-
- _sendQueued: function _sendQueued() {
- // console.log('Sending to lowsd (queued): ', {text: this._queuedInput});
- this._sendText(this._queuedInput);
- this._clearQueued();
+ this._ignoreInputCount--;
},
_onCompositionStart: function _onCompositionStart(/*ev*/) {
this._isComposing = true;
},
- // _onCompositionUpdate: function _onCompositionUpdate(ev) {
- // // Noop - handled at input/insertCompositionText instead.
- // },
+ // Handled only in legacy situations ('input' events with an inputType
+ // property are preferred).
+ _onCompositionUpdate: function _onCompositionUpdate(ev) {
+ this._map.notifyActive();
+ this._onInput(ev);
+ },
// Chrome doesn't fire any "input/insertCompositionText" with "isComposing" set to false.
// Instead , it fires non-standard "textInput" events, but those can be tricky
@@ -758,37 +475,9 @@ L.ClipboardContainer = L.Layer.extend({
// The approach here is to use "compositionend" events *only in Chrome* to mark
// the composing text as committed to the text area.
_onCompositionEnd: function _onCompositionEnd(ev) {
- // Check for standard chrome, and check heuristically for embedded Android
- // WebView (without chrome user-agent string)
- if (L.Browser.chrome || (L.Browser.android && L.Browser.webkit3d && !L.Browser.webkit)) {
- if (this._lastInputType === 'insertCompositionText') {
-// console.log('Queuing input because android webview');
- this._queueInput(ev.data);
- } else {
- // Ended a composition without user input, abort.
- // This happens on Chrome+GBoard when autocompleting a word
- // then entering a punctuation mark.
- this._abortComposition(ev);
- }
- }
-
- // Check for Safari; it fires composition events on typing diacritics with dead keys.
- if (L.Browser.Safari) {
- if (this._lastInputType === 'insertFromComposition') {
- this._queueInput(ev.data);
- } else {
- this._abortComposition(ev);
- }
- }
-
- // Tell lowsd to exit composition mode when the composition is empty
- // This happens when deleting the whole word being composed, e.g.
- // swipe a word then press backspace.
- if (ev.data === '') {
- this._sendCompositionEvent('input', '');
- }
-
+ this._map.notifyActive();
this._isComposing = false;
+ this._onInput(ev);
},
// Called when the user goes back to a word to spellcheck or replace it,
@@ -797,11 +486,8 @@ L.ClipboardContainer = L.Layer.extend({
// empty the text area.
_abortComposition: function _abortComposition(ev) {
this._fancyLog('abort-composition', ev.type);
- if (this._isComposing) {
- this._sendCompositionEvent('input', '');
- this._sendCompositionEvent('end', '');
+ if (this._isComposing)
this._isComposing = false;
- }
this._emptyArea();
},
@@ -883,33 +569,14 @@ L.ClipboardContainer = L.Layer.extend({
}
},
- // MSIE11 doesn't send any "textinput" events on enter, delete or backspace.
- // (Idem for old-ish stock android browsers which do not implement InputEvents)
- // To handle those, an event handler is added to the "keydown" event (which repeats)
- _onMSIEKeyDown: function _onMSIEKeyDown(ev) {
- if (!ev.shiftKey && !ev.ctrlKey && !ev.altKey && !ev.metaKey) {
- if (ev.key === 'Delete' || ev.key === 'Del') {
- this._sendKeyEvent(46, 1286);
- this._emptyArea();
- } else if (ev.key === 'Backspace') {
- this._sendKeyEvent(8, 1283);
- this._emptyArea();
- } else if (ev.key === 'Enter') {
- this._queueInput('\n');
- this._emptyArea();
- }
- }
- },
-
- // Edge18 doesn't send any "input" events on delete or backspace
- // To handle those, an event handler is added to the "keydown" event (which repeats)
- _onEdgeKeyDown: function _onEdgeKeyDown(ev) {
- // FIXME: we need enter too - share with above method ?
- this._onMSIEKeyDown(ev);
- },
+ // Used in the deleteContentBackward for deleting multiple characters with a single
+ // message.
+ // Will remove characters from the queue first, if there are any.
+ _removeTextContent: function _removeTextContent(before, after) {
+ console.log('Remove ' + before + ' before, and ' + after + ' after');
- // Used in the deleteContentBackward for deleting multiple characters with a single message.
- _removeTextContext: function _removeTextContext(before, after) {
+ /// TODO: rename the event to 'removetextcontent' as soon as lowsd supports it
+ /// TODO: Ask Marco about it
this._map._socket.sendMessage(
'removetextcontext id=' +
this._map.getWinId() +
@@ -921,6 +588,7 @@ L.ClipboardContainer = L.Layer.extend({
// Tiny helper - encapsulates sending a 'textinput' websocket message.
// "type" is either "input" for updates or "end" for commits.
_sendCompositionEvent: function _sendCompositionEvent(type, text) {
+ console.log('sending to lowsd: ', type, text);
this._map._socket.sendMessage(
'textinput id=' +
this._map.getWinId() +
@@ -932,16 +600,22 @@ L.ClipboardContainer = L.Layer.extend({
},
// Tiny helper - encapsulates sending a 'key' or 'windowkey' websocket message
- _sendKeyEvent: function _sendKeyEvent(charCode, unoKeyCode) {
+ // "type" can be "input" (default) or "up"
+ _sendKeyEvent: function _sendKeyEvent(charCode, unoKeyCode, type) {
+ if (!type) {
+ type = 'input';
+ }
if (this._map.getWinId() === 0) {
this._map._socket.sendMessage(
- 'key type=input char=' + charCode + ' key=' + unoKeyCode + '\n'
+ 'key type=' + type + ' char=' + charCode + ' key=' + unoKeyCode + '\n'
);
} else {
this._map._socket.sendMessage(
'windowkey id=' +
this._map.getWinId() +
- ' type=input char=' +
+ ' type=' +
+ type +
+ ' char=' +
charCode +
' key=' +
unoKeyCode +
commit 0e86094f1c6d6f50d945bcee9908ecd496a2c594
Author: Iván Sánchez Ortega <ivan.sanchez at collabora.com>
AuthorDate: Thu Jul 4 15:53:23 2019 +0200
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 13:47:19 2019 +0100
loleaflet: Unconditionally apply autocapitalize=false to ClipboardContainer
Change-Id: Ib875caac26920a3ed18a7ca53fbba587cebc89b5
diff --git a/loleaflet/src/layer/marker/ClipboardContainer.js b/loleaflet/src/layer/marker/ClipboardContainer.js
index 68e27d4d8..d89c7fa9a 100644
--- a/loleaflet/src/layer/marker/ClipboardContainer.js
+++ b/loleaflet/src/layer/marker/ClipboardContainer.js
@@ -259,16 +259,15 @@ L.ClipboardContainer = L.Layer.extend({
// Safari on iPad would show bold/italic/underline native controls
// which cannot be handled with the current implementation.
this._textArea = L.DomUtil.create('textarea', 'clipboard', this._container);
- this._textArea.setAttribute('autocorrect', 'off');
- this._textArea.setAttribute('autocapitalize', 'off');
- this._textArea.setAttribute('autocomplete', 'off');
- this._textArea.setAttribute('spellcheck', 'false');
- this._textArea.setAttribute('autofocus', 'true');
} else {
this._textArea = L.DomUtil.create('div', 'clipboard', this._container);
this._textArea.setAttribute('contenteditable', 'true');
- this._textArea.setAttribute('autofocus', 'true');
}
+ this._textArea.setAttribute('autocapitalize', 'off');
+ this._textArea.setAttribute('autofocus', 'true');
+ this._textArea.setAttribute('autocorrect', 'off');
+ this._textArea.setAttribute('autocomplete', 'off');
+ this._textArea.setAttribute('spellcheck', 'false');
this._setupStyles();
},
commit 17c90f8910f5418af2a81665bb3546aca1c101fb
Author: Marco Cecchetti <mrcekets at gmail.com>
AuthorDate: Wed Jul 10 10:29:50 2019 +0200
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 13:46:10 2019 +0100
single msg for deleting multiple characters
Change-Id: I589dbc933e4450d5dbcf35e99b1a55598d3dee76
diff --git a/bundled/include/LibreOfficeKit/LibreOfficeKit.h b/bundled/include/LibreOfficeKit/LibreOfficeKit.h
index 93b430f5d..6060b015b 100644
--- a/bundled/include/LibreOfficeKit/LibreOfficeKit.h
+++ b/bundled/include/LibreOfficeKit/LibreOfficeKit.h
@@ -408,6 +408,12 @@ struct _LibreOfficeKitDocumentClass
/// @see lok::Document::getSelectionType
int (*getSelectionType) (LibreOfficeKitDocument* pThis);
+ /// @see lok::Document::removeTextContext
+ void (*removeTextContext) (LibreOfficeKitDocument* pThis,
+ unsigned nWindowId,
+ int nBefore,
+ int nAfter);
+
#endif // defined LOK_USE_UNSTABLE_API || defined LIBO_INTERNAL_ONLY
};
diff --git a/bundled/include/LibreOfficeKit/LibreOfficeKit.hxx b/bundled/include/LibreOfficeKit/LibreOfficeKit.hxx
index 517a38a50..a695c4113 100644
--- a/bundled/include/LibreOfficeKit/LibreOfficeKit.hxx
+++ b/bundled/include/LibreOfficeKit/LibreOfficeKit.hxx
@@ -728,6 +728,19 @@ public:
return mpDoc->pClass->resizeWindow(mpDoc, nWindowId, width, height);
}
+ /**
+ * For deleting many characters all at once
+ *
+ * @param nWindowId Specify the window id to post the input event to. If
+ * nWindow is 0, the event is posted into the document
+ * @param nBefore The characters to be deleted before the cursor position
+ * @param nAfter The characters to be deleted after the cursor position
+ */
+ void removeTextContext(unsigned nWindowId, int nBefore, int nAfter)
+ {
+ mpDoc->pClass->removeTextContext(mpDoc, nWindowId, nBefore, nAfter);
+ }
+
#endif // defined LOK_USE_UNSTABLE_API || defined LIBO_INTERNAL_ONLY
};
diff --git a/kit/ChildSession.cpp b/kit/ChildSession.cpp
index 2880e73d0..5dce1f5db 100644
--- a/kit/ChildSession.cpp
+++ b/kit/ChildSession.cpp
@@ -294,7 +294,8 @@ bool ChildSession::_handleInput(const char *buffer, int length)
tokens[0] == "signdocument" ||
tokens[0] == "uploadsigneddocument" ||
tokens[0] == "exportsignanduploaddocument" ||
- tokens[0] == "rendershapeselection");
+ tokens[0] == "rendershapeselection" ||
+ tokens[0] == "removetextcontext");
if (tokens[0] == "clientzoom")
{
@@ -414,6 +415,10 @@ bool ChildSession::_handleInput(const char *buffer, int length)
{
return renderShapeSelection(buffer, length, tokens);
}
+ else if (tokens[0] == "removetextcontext")
+ {
+ return removeTextContext(buffer, length, tokens);
+ }
else
{
assert(false && "Unknown command token.");
@@ -2094,6 +2099,27 @@ bool ChildSession::renderShapeSelection(const char* /*buffer*/, int /*length*/,
return true;
}
+bool ChildSession::removeTextContext(const char* /*buffer*/, int /*length*/,
+ const std::vector<std::string>& tokens)
+{
+ int id, before, after;
+ std::string text;
+ if (tokens.size() < 4 ||
+ !getTokenInteger(tokens[1], "id", id) || id < 0 ||
+ !getTokenInteger(tokens[2], "before", before) ||
+ !getTokenInteger(tokens[3], "after", after))
+ {
+ sendTextFrame("error: cmd=" + std::string(tokens[0]) + " kind=syntax");
+ return false;
+ }
+
+ std::unique_lock<std::mutex> lock(_docManager.getDocumentMutex());
+ getLOKitDocument()->setView(_viewId);
+ getLOKitDocument()->removeTextContext(id, before, after);
+
+ return true;
+}
+
/* If the user is inactive we have to remember important events so that when
* the user becomes active again, we can replay the events.
*/
diff --git a/kit/ChildSession.hpp b/kit/ChildSession.hpp
index 3e32f311d..88166a0c4 100644
--- a/kit/ChildSession.hpp
+++ b/kit/ChildSession.hpp
@@ -276,6 +276,7 @@ private:
bool uploadSignedDocument(const char* buffer, int length, const std::vector<std::string>& tokens);
bool exportSignAndUploadDocument(const char* buffer, int length, const std::vector<std::string>& tokens);
bool renderShapeSelection(const char* buffer, int length, const std::vector<std::string>& tokens);
+ bool removeTextContext(const char* /*buffer*/, int /*length*/, const std::vector<std::string>& tokens);
void rememberEventsForInactiveUser(const int type, const std::string& payload);
diff --git a/loleaflet/src/layer/marker/ClipboardContainer.js b/loleaflet/src/layer/marker/ClipboardContainer.js
index 68068abf9..68e27d4d8 100644
--- a/loleaflet/src/layer/marker/ClipboardContainer.js
+++ b/loleaflet/src/layer/marker/ClipboardContainer.js
@@ -515,11 +515,7 @@ L.ClipboardContainer = L.Layer.extend({
if (l >= count) {
this._queuedInput = this._queuedInput.substring(0, l - count);
} else {
- for (var i = 0; i < count; i++) {
- // Send a UNO backspace keystroke per glyph to be deleted
- this._sendKeyEvent(8, 1283);
- }
-
+ this._removeTextContext(count, 0);
this._emptyArea();
}
@@ -913,6 +909,16 @@ L.ClipboardContainer = L.Layer.extend({
this._onMSIEKeyDown(ev);
},
+ // Used in the deleteContentBackward for deleting multiple characters with a single message.
+ _removeTextContext: function _removeTextContext(before, after) {
+ this._map._socket.sendMessage(
+ 'removetextcontext id=' +
+ this._map.getWinId() +
+ ' before=' + before +
+ ' after=' + after
+ );
+ },
+
// Tiny helper - encapsulates sending a 'textinput' websocket message.
// "type" is either "input" for updates or "end" for commits.
_sendCompositionEvent: function _sendCompositionEvent(type, text) {
diff --git a/wsd/ClientSession.cpp b/wsd/ClientSession.cpp
index 85469f6ec..f7c1d35ca 100644
--- a/wsd/ClientSession.cpp
+++ b/wsd/ClientSession.cpp
@@ -426,7 +426,8 @@ bool ClientSession::_handleInput(const char *buffer, int length)
tokens[0] != "rendershapeselection" &&
tokens[0] != "removesession" &&
tokens[0] != "renamefile" &&
- tokens[0] != "resizewindow")
+ tokens[0] != "resizewindow" &&
+ tokens[0] != "removetextcontext")
{
LOG_ERR("Session [" << getId() << "] got unknown command [" << tokens[0] << "].");
sendTextFrame("error: cmd=" + tokens[0] + " kind=unknown");
commit a06f77ca3a3b1cb2af5490061f2abb9b9282a977
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Wed Jul 3 20:58:04 2019 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 13:41:50 2019 +0100
Cleanup the fix - and reduce risk by special-casing for iOS / Android.
Change-Id: I3a86cfcfaa2ce0664aaeccf2c2fb5bd7e980de19
diff --git a/loleaflet/src/layer/marker/ClipboardContainer.js b/loleaflet/src/layer/marker/ClipboardContainer.js
index 1bcb3a226..68068abf9 100644
--- a/loleaflet/src/layer/marker/ClipboardContainer.js
+++ b/loleaflet/src/layer/marker/ClipboardContainer.js
@@ -675,22 +675,26 @@ L.ClipboardContainer = L.Layer.extend({
this._fancyLog('beforeinput range', this._lastRangesString());
// FIXME: a hack - this assumes that nothing changed / no auto-correction inside the Kit.
- var seltext = window.getSelection();
- if (!this._isComposing && seltext && seltext.toString() && seltext.toString().length)
+ // FIXME: only mobile for now to reduce risk ...
+ if (window.mode.isMobile() || window.mode.isTablet())
{
- var len = seltext.toString().length;
- console.log2('Horror meeks3 hack - delete ' + len + ' chars "' + this._queudInput + '"');
- if (this._queuedInput)
+ var seltext = window.getSelection();
+ if (!this._isComposing && seltext && seltext.toString() && seltext.toString().length > 0)
{
- var size = this._queuedInput.length;
- var redux = Math.min(size, len);
- this._queuedInput = this._queuedInput.slice(0,-redux);
- len -= redux;
- console.log2('Horror meeks3 hack - removed ' + redux + ' from queued input to "' + this._queuedInput + '"');
+ var len = seltext.toString().length;
+ this._fancyLog('selection overtype', seltext.toString() + ' len ' + len + ' chars "' + this._queuedInput + '"');
+ if (this._queuedInput)
+ {
+ var size = this._queuedInput.length;
+ var redux = Math.min(size, len);
+ this._queuedInput = this._queuedInput.slice(0,-redux);
+ len -= redux;
+ console.log2('queue overtype', 'removed ' + redux + ' from queued input to "' + this._queuedInput + '"');
+ }
+ // FIXME: this is the more hacky bit - if the Kit changed under us.
+ for (var i = 0; i < len; ++i)
+ this._sendKeyEvent(8, 1283);
}
- // FIXME: this is the more hacky bit - if the Kit changed under us.
- for (var i = 0; i < len; ++i)
- this._sendKeyEvent(8, 1283);
}
// When trying to delete (i.e. backspace) on an empty textarea, the input event
commit 1fb662f06cb22d9360921ac13536bbc42bfed045
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Wed Jul 3 17:12:00 2019 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 13:41:45 2019 +0100
Delete selection hack for testing.
This is pretty grim, but - apparently semi-working.
Change-Id: Ie14c7b0ff9927ecd7eb81716a9b347fa2230146c
diff --git a/loleaflet/src/layer/marker/ClipboardContainer.js b/loleaflet/src/layer/marker/ClipboardContainer.js
index 0c7735df1..1bcb3a226 100644
--- a/loleaflet/src/layer/marker/ClipboardContainer.js
+++ b/loleaflet/src/layer/marker/ClipboardContainer.js
@@ -674,6 +674,25 @@ L.ClipboardContainer = L.Layer.extend({
this._fancyLog('beforeinput selection', window.getSelection().toString());
this._fancyLog('beforeinput range', this._lastRangesString());
+ // FIXME: a hack - this assumes that nothing changed / no auto-correction inside the Kit.
+ var seltext = window.getSelection();
+ if (!this._isComposing && seltext && seltext.toString() && seltext.toString().length)
+ {
+ var len = seltext.toString().length;
+ console.log2('Horror meeks3 hack - delete ' + len + ' chars "' + this._queudInput + '"');
+ if (this._queuedInput)
+ {
+ var size = this._queuedInput.length;
+ var redux = Math.min(size, len);
+ this._queuedInput = this._queuedInput.slice(0,-redux);
+ len -= redux;
+ console.log2('Horror meeks3 hack - removed ' + redux + ' from queued input to "' + this._queuedInput + '"');
+ }
+ // FIXME: this is the more hacky bit - if the Kit changed under us.
+ for (var i = 0; i < len; ++i)
+ this._sendKeyEvent(8, 1283);
+ }
+
// When trying to delete (i.e. backspace) on an empty textarea, the input event
// won't be fired afterwards. Handle backspace here instead.
More information about the Libreoffice-commits
mailing list