[Libreoffice-commits] online.git: 78 commits - bundled/include kit/ChildSession.cpp kit/ChildSession.hpp loleaflet/build loleaflet/src loolwsd.xml.in wsd/ClientSession.cpp wsd/LOOLWSD.cpp
Henry Castro (via logerrit)
logerrit at kemper.freedesktop.org
Thu Oct 3 13:50:42 UTC 2019
bundled/include/LibreOfficeKit/LibreOfficeKit.h | 6
bundled/include/LibreOfficeKit/LibreOfficeKit.hxx | 13
kit/ChildSession.cpp | 28
kit/ChildSession.hpp | 1
loleaflet/build/deps.js | 7
loleaflet/src/control/Control.LokDialog.js | 120 ---
loleaflet/src/control/Control.MobileInput.js | 343 -----------
loleaflet/src/control/Control.Toolbar.js | 2
loleaflet/src/core/Browser.js | 4
loleaflet/src/core/Socket.js | 7
loleaflet/src/layer/marker/ClipboardContainer.js | 666 ++++++++++++++++++----
loleaflet/src/layer/tile/TileLayer.js | 63 +-
loleaflet/src/map/Map.js | 81 ++
loleaflet/src/map/handler/Map.Keyboard.js | 229 +++----
loleaflet/src/map/handler/Map.TouchGesture.js | 5
loolwsd.xml.in | 2
wsd/ClientSession.cpp | 3
wsd/LOOLWSD.cpp | 2
18 files changed, 854 insertions(+), 728 deletions(-)
New commits:
commit 974d02fcca70d96cb09b71fc1e33c0950ae50b29
Author: Henry Castro <hcastro at collabora.com>
AuthorDate: Wed Aug 28 21:26:46 2019 -0400
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 14:50:17 2019 +0100
loleaflet: mobile: fix the first typed character after opening the document
calling the function setSelectionRange is an implicit keyboard focus.
Only enable when the text area has the focus
Change-Id: Ic58abd3fc555ad9a0a08a01041f7aeb5367d271b
diff --git a/loleaflet/src/layer/marker/ClipboardContainer.js b/loleaflet/src/layer/marker/ClipboardContainer.js
index 643e00567..4d996ffb8 100644
--- a/loleaflet/src/layer/marker/ClipboardContainer.js
+++ b/loleaflet/src/layer/marker/ClipboardContainer.js
@@ -507,7 +507,7 @@ L.ClipboardContainer = L.Layer.extend({
// always catch deleteContentBackward/deleteContentForward input events
// (some combination of browser + input method don't fire those on an
// empty contenteditable).
- _emptyArea: function _emptyArea() {
+ _emptyArea: function _emptyArea(noSelect) {
this._fancyLog('empty-area');
this._ignoreInputCount++;
@@ -524,7 +524,7 @@ L.ClipboardContainer = L.Layer.extend({
this._textArea.value = this._preSpaceChar + this._postSpaceChar;
// avoid setting the focus keyboard
- if (document.activeElement === this._textArea) {
+ if (!noSelect) {
this._textArea.setSelectionRange(1, 1);
if (this._hasWorkingSelectionStart === undefined)
@@ -566,7 +566,7 @@ L.ClipboardContainer = L.Layer.extend({
this._fancyLog('abort-composition', ev.type);
if (this._isComposing)
this._isComposing = false;
- this._emptyArea();
+ this._emptyArea(document.activeElement !== this._textArea);
},
_onKeyDown: function _onKeyDown(ev) {
commit e33fc028766ab3d3d321019aa33d09debfa38009
Author: Henry Castro <hcastro at collabora.com>
AuthorDate: Mon Aug 19 07:52:33 2019 -0400
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 14:50:17 2019 +0100
loleaflet: mobile: removes keyboard focus when the graphic is selected
Change-Id: Iced49475ebf9af5508059f5d6e223e99d1187649
diff --git a/loleaflet/src/layer/marker/ClipboardContainer.js b/loleaflet/src/layer/marker/ClipboardContainer.js
index e7f7a2ed7..643e00567 100644
--- a/loleaflet/src/layer/marker/ClipboardContainer.js
+++ b/loleaflet/src/layer/marker/ClipboardContainer.js
@@ -522,9 +522,14 @@ L.ClipboardContainer = L.Layer.extend({
this._lastContent = [];
this._textArea.value = this._preSpaceChar + this._postSpaceChar;
- this._textArea.setSelectionRange(1, 1);
- if (this._hasWorkingSelectionStart === undefined)
- this._hasWorkingSelectionStart = (this._textArea.selectionStart === 1);
+
+ // avoid setting the focus keyboard
+ if (document.activeElement === this._textArea) {
+ this._textArea.setSelectionRange(1, 1);
+
+ if (this._hasWorkingSelectionStart === undefined)
+ this._hasWorkingSelectionStart = (this._textArea.selectionStart === 1);
+ }
this._fancyLog('empty-area-end');
diff --git a/loleaflet/src/map/handler/Map.TouchGesture.js b/loleaflet/src/map/handler/Map.TouchGesture.js
index fcdab2bd4..ae35507fa 100644
--- a/loleaflet/src/map/handler/Map.TouchGesture.js
+++ b/loleaflet/src/map/handler/Map.TouchGesture.js
@@ -239,7 +239,9 @@ L.Map.TouchGesture = L.Handler.extend({
this._map._docLayer._postMouseEvent('buttondown', mousePos.x, mousePos.y, 1, 1, 0);
this._map._docLayer._postMouseEvent('buttonup', mousePos.x, mousePos.y, 1, 1, 0);
- if (!this._map.hasFocus()) {
+ if (this._state === L.Map.TouchGesture.MARKER || this._state === L.Map.TouchGesture.GRAPHIC) {
+ this._map._clipboardContainer.blur();
+ } else {
this._map.focus();
}
},
commit 1240da475fae851668a8103f2461910d99a829ce
Author: Henry Castro <hcastro at collabora.com>
AuthorDate: Thu Aug 15 16:29:24 2019 -0400
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 14:50:17 2019 +0100
loleaflet: mobile: hide the cursor marker when exists text selection
Change-Id: Ib0a5c74567e1a0a71c53d741aa6c44a09b6b0fe2
diff --git a/loleaflet/src/layer/marker/ClipboardContainer.js b/loleaflet/src/layer/marker/ClipboardContainer.js
index ee90597d1..e7f7a2ed7 100644
--- a/loleaflet/src/layer/marker/ClipboardContainer.js
+++ b/loleaflet/src/layer/marker/ClipboardContainer.js
@@ -242,7 +242,11 @@ L.ClipboardContainer = L.Layer.extend({
// Move and display under-caret marker
if (L.Browser.touch) {
- this._cursorHandler.setLatLng(bottom).addTo(this._map);
+ if (this._map._docLayer._selections.getLayers().length === 0) {
+ this._cursorHandler.setLatLng(bottom).addTo(this._map);
+ } else {
+ this._map.removeLayer(this._cursorHandler);
+ }
}
// Move the hidden text area with the cursor
commit e39fb629b48a4675608103d87ea9ba3af008337b
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Thu Oct 3 14:19:59 2019 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 14:50:17 2019 +0100
Remove obsolete and unhelpful method.
Fixes up 8440e286c merge.
Change-Id: I27f16d36d135feae10de6d1db732259f81afd1fc
diff --git a/loleaflet/src/layer/marker/ClipboardContainer.js b/loleaflet/src/layer/marker/ClipboardContainer.js
index 7239126e3..ee90597d1 100644
--- a/loleaflet/src/layer/marker/ClipboardContainer.js
+++ b/loleaflet/src/layer/marker/ClipboardContainer.js
@@ -157,17 +157,6 @@ L.ClipboardContainer = L.Layer.extend({
return arr;
},
- setValue: function(val) {
- // console.log('clipboard setValue: ', val);
- if (this._legacyArea) {
- var tmp = document.createElement('div');
- tmp.innerHTML = val;
- this._textArea.value = tmp.innerText || tmp.textContent || '';
- } else {
- this._textArea.innerHTML = val;
- }
- },
-
update: function() {
if (this._container && this._map && this._latlng) {
var position = this._map.latLngToLayerPoint(this._latlng).round();
diff --git a/loleaflet/src/layer/tile/TileLayer.js b/loleaflet/src/layer/tile/TileLayer.js
index dd923df61..db2da511d 100644
--- a/loleaflet/src/layer/tile/TileLayer.js
+++ b/loleaflet/src/layer/tile/TileLayer.js
@@ -655,10 +655,6 @@ L.TileLayer = L.GridLayer.extend({
// messages during text composition, and resetting the contents
// of the clipboard container mid-composition will easily break it.
var formula = textMsg.substring(13);
- if (!this._map['wopi'].DisableCopy) {
- this._map._clipboardContainer.setValue(formula);
- this._map._clipboardContainer.select();
- }
this._lastFormula = formula;
this._map.fire('cellformula', {formula: formula});
},
commit 2210fddb2d89ed96ed425671423fdef1eebbf6a0
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Thu Oct 3 14:09:03 2019 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 14:50:17 2019 +0100
Remove unused code.
Change-Id: I7d75cd570411a3e9b596b853da9ebc77b703ee03
diff --git a/loleaflet/src/layer/marker/ClipboardContainer.js b/loleaflet/src/layer/marker/ClipboardContainer.js
index 17c420397..7239126e3 100644
--- a/loleaflet/src/layer/marker/ClipboardContainer.js
+++ b/loleaflet/src/layer/marker/ClipboardContainer.js
@@ -131,16 +131,6 @@ L.ClipboardContainer = L.Layer.extend({
this._textArea.select();
},
- warnCopyPaste: function() {
- var self = this;
- vex.dialog.alert({
- unsafeMessage: _('<p>Your browser has very limited access to the clipboard, so use these keyboard shortcuts:<ul><li><b>Ctrl+C</b>: For copying.</li><li><b>Ctrl+X</b>: For cutting.</li><li><b>Ctrl+V</b>: For pasting.</li></ul></p>'),
- callback: function () {
- self._map.focus();
- }
- });
- },
-
getValue: function() {
var value = this._textArea.value;
return value;
commit 3783e29db574a9e4e2c49e0bf3db581301603fc2
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 14:50:17 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 c41f0772f..b00ff806d 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 917c357d7e3009ed42876761119467b863471462
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 14:50:17 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 b7a842ef4..c41f0772f 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 51779f9f002bfe4645afebc31227e8d8e2bf297c
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 14:50:17 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 20e20cb65..17c420397 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;
@@ -358,19 +363,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;
}
}
},
@@ -393,19 +402,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();
@@ -416,9 +430,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)
@@ -525,7 +538,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 f850d01d2641d3ed769367619f7608f44265e2bc
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 14:50:17 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 b589683f3..20e20cb65 100644
--- a/loleaflet/src/layer/marker/ClipboardContainer.js
+++ b/loleaflet/src/layer/marker/ClipboardContainer.js
@@ -481,14 +481,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 a78551ce02cfa67eab2b5baa6b4c6c6eaecd9301
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 14:50:17 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 631456867..b589683f3 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 = ' ';
@@ -310,6 +311,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;
@@ -357,14 +359,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;
}
}
},
@@ -409,7 +415,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 103a039fd21d27222d6a9c66e8eff33fc157820c
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 14:50:17 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 f9f5ccade..631456867 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 = ' ';
@@ -91,6 +91,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);
@@ -308,6 +309,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;
@@ -351,6 +353,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();
@@ -436,7 +454,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));
@@ -503,9 +520,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 f68d56735c280923a17b7ba972876e2976cada0a
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 14:50:17 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 ed6f3bbbc..f9f5ccade 100644
--- a/loleaflet/src/layer/marker/ClipboardContainer.js
+++ b/loleaflet/src/layer/marker/ClipboardContainer.js
@@ -389,10 +389,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 67eafba6b7a5ed06acea69da94e1df5bb933b654
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 14:50:17 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 1d9cbcaba..ed6f3bbbc 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;
@@ -86,6 +94,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);
@@ -127,8 +136,6 @@ L.ClipboardContainer = L.Layer.extend({
getValue: function() {
var value = this._textArea.value;
- // kill unwanted entities
- value = value.replace(/ /g, ' ');
return value;
},
@@ -303,6 +310,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)
@@ -328,6 +338,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 ',
@@ -340,7 +352,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) {
@@ -348,22 +360,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);
@@ -377,18 +411,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)
@@ -439,15 +492,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--;
},
@@ -485,66 +541,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 73839f0dffe4c9c31c782cf3a634e0b824446a47
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 14:50:17 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 b1ccda130..1d9cbcaba 100644
--- a/loleaflet/src/layer/marker/ClipboardContainer.js
+++ b/loleaflet/src/layer/marker/ClipboardContainer.js
@@ -185,6 +185,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 8a2e7d8c8a6c0a0981cf6d8b8e5673e168a0e6be
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 14:50:17 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..b1ccda130 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,62 +70,29 @@ L.ClipboardContainer = L.Layer.extend({
},
_onFocusBlur: function(ev) {
-// console.log(ev.type, performance.now(), ev);
-
- if (this.dontBlur && ev.type == 'blur') {
- this._map.focus();
- this.dontBlur = false;
- return;
- }
-
- if (this.dontBlur && ev.type == 'blur') {
- this._map.focus();
- this.dontBlur = false;
- return;
- }
+ this._fancyLog(ev.type, '');
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 +112,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 +126,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 +178,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 +186,8 @@ L.ClipboardContainer = L.Layer.extend({
this._textArea.setAttribute('spellcheck', 'false');
this._setupStyles();
+
+ this._emptyArea();
},
_setupStyles: function() {
@@ -346,42 +264,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 +294,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 +334,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);
- // 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);
+ this._lastContent = content;
+
+ 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 +393,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 +428,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));
-
- }
- } 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.');
- }
- }
- },
-
- // 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);
- }
- }
+ this._fancyLog('empty-area');
- // 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._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.
- _queueInput: function _queueInput(text) {
- this._map.notifyActive();
+ console.log('Set old/lastContent to empty');
+ this._lastContent = [];
- 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;
- }
+ this._textArea.value = '\xa0 ';
+ /// TODO: Check that this selection method works with MSIE11
+ this._textArea.setSelectionRange(1, 1);
- //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 +463,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 +474,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 +557,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 +576,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 +588,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 586e8159a131f2860b7b632cc62994d1d989169e
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 14:50:17 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 8741339064da810cfaa7af6a98b06a0da7de2932
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 14:50:17 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..7425e4fac 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(getLock());
+ 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 1f80d99a7e373685bc52f4218d7a94b12b4aec25
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 14:50:17 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 2ba1e6a6ae2decdec82280f8cb41d448143507c7
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 14:50:17 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.
commit e97e3e6a7785ff135e6b9db1500dce4ba5527ea2
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Wed Jun 19 09:36:14 2019 -0400
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 14:50:17 2019 +0100
leaflet: correctly handle backspace in dialogs
The workaround for handling backspace caused
double-deletes in dialogs.
Change-Id: I85f1e1e89b7b802c24960b6f9b7b7e1e60af90a9
diff --git a/loleaflet/src/layer/marker/ClipboardContainer.js b/loleaflet/src/layer/marker/ClipboardContainer.js
index 2a575bf66..0c7735df1 100644
--- a/loleaflet/src/layer/marker/ClipboardContainer.js
+++ b/loleaflet/src/layer/marker/ClipboardContainer.js
@@ -680,9 +680,8 @@ L.ClipboardContainer = L.Layer.extend({
// 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.
- // NOTE: Ideally this should never happen, as the textarea/contenteditable
- // is initialized with two non-breaking spaces when "emptied".
- if (!this._hasInputType || (this._lastRangesString() === '0-0')) {
+ 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') {
commit ae22aa322fbf3b418877d987630e3b17860b7c6c
Author: Szymon Kłos <szymon.klos at collabora.com>
AuthorDate: Tue Jun 18 23:49:01 2019 +0200
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 14:50:17 2019 +0100
Do not blur just before focus to keep keyboard
This also reverts: 80768f782d867bf03f49a028c876b647a05d8662
(timeouts for focus and blur events)
Change-Id: Ib98af7bd397954987e411473f611935a7e336ce6
diff --git a/loleaflet/src/layer/marker/ClipboardContainer.js b/loleaflet/src/layer/marker/ClipboardContainer.js
index b34853b88..2a575bf66 100644
--- a/loleaflet/src/layer/marker/ClipboardContainer.js
+++ b/loleaflet/src/layer/marker/ClipboardContainer.js
@@ -76,6 +76,14 @@ 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;
},
onAdd: function() {
@@ -121,6 +129,12 @@ L.ClipboardContainer = L.Layer.extend({
return;
}
+ if (this.dontBlur && ev.type == 'blur') {
+ this._map.focus();
+ this.dontBlur = false;
+ return;
+ }
+
var onoff = (ev.type == 'focus' ? L.DomEvent.on : L.DomEvent.off).bind(L.DomEvent);
onoff(this._textArea, 'compositionstart', this._onCompositionStart, this);
@@ -172,13 +186,11 @@ L.ClipboardContainer = L.Layer.extend({
console.log('EPIC HORRORS HERE');
return;
}
- var that = this;
- setTimeout(function() { that._textArea.focus(); }, 10);
+ this._textArea.focus();
},
blur: function() {
- var that = this;
- setTimeout(function() { that._textArea.blur(); }, 10);
+ this._textArea.blur();
},
// Marks the content of the textarea/contenteditable as selected,
commit b7be199357f2d02ec0096fa7eb1b2ba65a15aa41
Author: Iván Sánchez Ortega <ivan.sanchez at collabora.com>
AuthorDate: Wed Jun 19 14:26:55 2019 +0200
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 14:50:17 2019 +0100
loleaflet: ClipboardContainer: Re-enable range fetching on 'beforeinput' events
Change-Id: I1d7d18b36a2152e91fe8c9db21fa7a2e9f4dc935
diff --git a/loleaflet/src/layer/marker/ClipboardContainer.js b/loleaflet/src/layer/marker/ClipboardContainer.js
index f076d98b1..b34853b88 100644
--- a/loleaflet/src/layer/marker/ClipboardContainer.js
+++ b/loleaflet/src/layer/marker/ClipboardContainer.js
@@ -651,8 +651,10 @@ L.ClipboardContainer = L.Layer.extend({
// particularly when the textarea/contenteditable is empty, but
// only in some configurations.
_onBeforeInput: function _onBeforeInput(ev) {
- var selection = window.getSelection().toString();
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;
commit ae350549a811a103c1a61af79d2abd05c902eff9
Author: Iván Sánchez Ortega <ivan.sanchez at collabora.com>
AuthorDate: Wed Jun 19 12:53:05 2019 +0200
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 14:50:17 2019 +0100
loleaflet: ClipboardContainer should behave the same in Chrome/ium...
...than in webkit-like Android WebView
Change-Id: I0063e1b67a5a705eb54d6bd5e977e36c8969b71d
diff --git a/loleaflet/src/layer/marker/ClipboardContainer.js b/loleaflet/src/layer/marker/ClipboardContainer.js
index 0eb4400c9..f076d98b1 100644
--- a/loleaflet/src/layer/marker/ClipboardContainer.js
+++ b/loleaflet/src/layer/marker/ClipboardContainer.js
@@ -727,13 +727,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) {
- this._map.notifyActive();
// 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 && !L.Browser.gecko)
- ) {
+ 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);
commit 0dc71cd79980783ad4a89b4ef90ba666fa9e42b7
Author: Iván Sánchez Ortega <ivan.sanchez at collabora.com>
AuthorDate: Wed Jun 19 12:01:23 2019 +0200
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 14:50:17 2019 +0100
loleaflet: ClipboardContainer fix innerHTML syntax
Change-Id: I3aa81d690d4b4ea3627525f5f5e53ffeecfe9b81
diff --git a/loleaflet/src/layer/marker/ClipboardContainer.js b/loleaflet/src/layer/marker/ClipboardContainer.js
index bb1c072aa..0eb4400c9 100644
--- a/loleaflet/src/layer/marker/ClipboardContainer.js
+++ b/loleaflet/src/layer/marker/ClipboardContainer.js
@@ -411,7 +411,7 @@ L.ClipboardContainer = L.Layer.extend({
} else {
if (
this._textArea.textContent.length === 0 &&
- this._textArea.textContent.innerHTML.indexOf('<br>') !== -1
+ 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
commit ff3a5a18474b03602ac8dc6305761031f01b352e
Author: Iván Sánchez Ortega <ivan.sanchez at collabora.com>
AuthorDate: Wed Jun 19 11:22:06 2019 +0200
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 14:50:17 2019 +0100
loleaflet: ClipboardContainer hack for pressing enter on Android WebView
Change-Id: I735fb1a856fdd1de1dc77044bb169216df6ba64f
diff --git a/loleaflet/src/layer/marker/ClipboardContainer.js b/loleaflet/src/layer/marker/ClipboardContainer.js
index 5c16c9ec3..bb1c072aa 100644
--- a/loleaflet/src/layer/marker/ClipboardContainer.js
+++ b/loleaflet/src/layer/marker/ClipboardContainer.js
@@ -404,12 +404,22 @@ L.ClipboardContainer = L.Layer.extend({
this._lastInputType = ev.inputType;
if (!('inputType' in ev)) {
- // Legacy MSIE or Android Webkit, just send the contents of the
+ // 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 {
- this._sendText(this._textArea.textContent);
+ if (
+ this._textArea.textContent.length === 0 &&
+ this._textArea.textContent.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') {
commit f0c5b6d1729806cd7137d2f1f4662ecf145cb906
Author: Iván Sánchez Ortega <ivan.sanchez at collabora.com>
AuthorDate: Wed Jun 19 11:02:13 2019 +0200
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 14:50:17 2019 +0100
loleaflet: ClipboardContainer handle composition mode for legacy input events
Change-Id: I3db3e790f75de90b126ea0e63771b6035f91b0b4
diff --git a/loleaflet/src/layer/marker/ClipboardContainer.js b/loleaflet/src/layer/marker/ClipboardContainer.js
index 785e6b0a7..5c16c9ec3 100644
--- a/loleaflet/src/layer/marker/ClipboardContainer.js
+++ b/loleaflet/src/layer/marker/ClipboardContainer.js
@@ -406,9 +406,12 @@ L.ClipboardContainer = L.Layer.extend({
if (!('inputType' in ev)) {
// Legacy MSIE or Android Webkit, just send the contents of the
// container and clear it.
- this._sendText(this._textArea.textContent);
- this._emptyArea();
-
+ if (this._isComposing) {
+ this._sendCompositionEvent('input', this._textArea.textContent);
+ } 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'
commit 4a20744c0c725ae3756981bec10a709d4b7ab1e6
Author: Iván Sánchez Ortega <ivan.sanchez at collabora.com>
AuthorDate: Wed Jun 19 10:28:20 2019 +0200
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 14:50:17 2019 +0100
loleaflet: ClipboardContainer: Assume legacy input events on Android Webkit as well
Change-Id: Iaa04f808940afaedc12c48b48c722673b3b406ab
diff --git a/loleaflet/src/layer/marker/ClipboardContainer.js b/loleaflet/src/layer/marker/ClipboardContainer.js
index 9f782e392..785e6b0a7 100644
--- a/loleaflet/src/layer/marker/ClipboardContainer.js
+++ b/loleaflet/src/layer/marker/ClipboardContainer.js
@@ -404,16 +404,11 @@ L.ClipboardContainer = L.Layer.extend({
this._lastInputType = ev.inputType;
if (!('inputType' in ev)) {
- if (this._isComposing) {
- this._sendCompositionEvent('input', this._textArea.textContent);
- } else {
- // Legacy MSIE, Android WebView or FFX < 66, just send the contents of the
- // container and clear it.
- if (this._textArea.textContent.length !== 0) {
- this._sendText(this._textArea.textContent);
- }
- this._emptyArea();
- }
+ // Legacy MSIE or Android Webkit, just send the contents of the
+ // container and clear it.
+ 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'
commit 1de1784942ba1cb857cde95546dddb2dbb11fa36
Author: Szymon Kłos <szymon.klos at collabora.com>
AuthorDate: Tue Jun 18 18:14:24 2019 +0200
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 14:50:17 2019 +0100
Set timeout for focus in focus events
This allows events to occur in order.
Change-Id: I30701dcdcb5758ea2d5f69a93203641679823d8c
diff --git a/loleaflet/src/layer/marker/ClipboardContainer.js b/loleaflet/src/layer/marker/ClipboardContainer.js
index 13d846781..9f782e392 100644
--- a/loleaflet/src/layer/marker/ClipboardContainer.js
+++ b/loleaflet/src/layer/marker/ClipboardContainer.js
@@ -172,11 +172,13 @@ L.ClipboardContainer = L.Layer.extend({
console.log('EPIC HORRORS HERE');
return;
}
- this._textArea.focus();
+ var that = this;
+ setTimeout(function() { that._textArea.focus(); }, 10);
},
blur: function() {
- this._textArea.blur();
+ var that = this;
+ setTimeout(function() { that._textArea.blur(); }, 10);
},
// Marks the content of the textarea/contenteditable as selected,
commit d525b4625690a86a86f451ac51a05778ff5c2002
Author: Iván Sánchez Ortega <ivan.sanchez at collabora.com>
AuthorDate: Tue Jun 18 15:20:02 2019 +0200
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 14:50:17 2019 +0100
loleaflet: Explicitly relay keyboard events from LokDialog to Keyboard handler
Change-Id: Icaa33537313c73286937bdeeef595bcd82037f95
diff --git a/loleaflet/src/map/handler/Map.Keyboard.js b/loleaflet/src/map/handler/Map.Keyboard.js
index 18ad2f5d7..0ef5d1a66 100644
--- a/loleaflet/src/map/handler/Map.Keyboard.js
+++ b/loleaflet/src/map/handler/Map.Keyboard.js
@@ -181,22 +181,13 @@ L.Map.Keyboard = L.Handler.extend({
L.DomEvent.off(this._map.getContainer(), 'keydown keyup keypress', this._onKeyDown, this);
},
- /*
- * Returns true whenever the key event shall be ignored.
- * This means shift+insert and shift+delete (or "insert or delete when holding
- * shift down"). Those events are handled elsewhere to trigger "cut" and
- * "paste" events, and need to be ignored in order to avoid double-handling them.
- */
- _ignoreKeyEvent: function(e) {
- var shift = e.originalEvent.shiftKey;
- if ('key' in e.originalEvent) {
- var key = e.originalEvent.key;
- return (shift && (key === 'Delete' || key === 'Insert'));
- } else {
- // keyCode is not reliable in AZERTY/DVORAK keyboard layouts, is used
- // only as a fallback for MSIE8.
- var keyCode = e.originalEvent.keyCode;
- return (shift && (keyCode === 45 || keyCode === 46));
+ _ignoreKeyEvent: function(ev) {
+ var shift = ev.shiftKey ? this.keyModifier.shift : 0;
+ if (shift && (ev.keyCode === 45 || ev.keyCode === 46)) {
+ // don't handle shift+insert, shift+delete
+ // These are converted to 'cut', 'paste' events which are
+ // automatically handled by us, so avoid double-handling
+ return true;
}
},
@@ -253,6 +244,7 @@ L.Map.Keyboard = L.Handler.extend({
// _handleKeyEvent - checks if the given keyboard event shall trigger
// a message to lowsd, and calls the given keyEventFn(type, charcode, keycode)
// callback if so.
+ // Called from private _onKeyDown
_handleKeyEvent: function (ev, keyEventFn) {
this._map.notifyActive();
if (this._map.slideShow && this._map.slideShow.fullscreen) {
commit 8b080fee2f86dbcc7d77b5eedeab468d1f8388f6
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Tue Jun 18 09:53:51 2019 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 14:50:17 2019 +0100
Avoid using the read-only / edit toggle as a show keyboard button.
Change-Id: I1c4e88c1824a8aef4aa2bb2e1e18943d95202bb0
diff --git a/loleaflet/src/layer/marker/ClipboardContainer.js b/loleaflet/src/layer/marker/ClipboardContainer.js
index a6631cccb..13d846781 100644
--- a/loleaflet/src/layer/marker/ClipboardContainer.js
+++ b/loleaflet/src/layer/marker/ClipboardContainer.js
@@ -156,10 +156,13 @@ L.ClipboardContainer = L.Layer.extend({
this._map.notifyActive();
- if (ev.type === 'blur' && this._isComposing) {
- /// TODO: Set this._compositionText
- this._queueInput(this._compositionText);
- this._abortComposition(ev);
+ if (ev.type === 'blur') {
+ if (this._isComposing) {
+ this._queueInput(this._compositionText);
+ }
+ this._abortComposition();
+ } else {
+ this._winId = 0;
}
},
commit 0c749e0f597509122913a9b4a08c6f07e8fda517
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Tue Jun 18 09:27:46 2019 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 14:50:17 2019 +0100
Default focus dialogs.
Change-Id: Idc37cdfbd84bbdcea90c96175091aff6d3026da6
diff --git a/loleaflet/src/control/Control.LokDialog.js b/loleaflet/src/control/Control.LokDialog.js
index b0404a593..b7a842ef4 100644
--- a/loleaflet/src/control/Control.LokDialog.js
+++ b/loleaflet/src/control/Control.LokDialog.js
@@ -399,8 +399,7 @@ L.Control.LokDialog = L.Control.extend({
focus: function(dlgId, force) {
if (!force && (!this._isOpen(dlgId) || !this._dialogs[dlgId].cursorVisible))
return;
- this._map.setWinId(dlgId);
- this._map.getClipboardContainer().focus();
+ this._dialogs[dlgId].input.focus();
},
_setCanvasWidthHeight: function(canvas, width, height) {
commit 7e38e8fc3cb00a26a02a45105bf6e534b381746c
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Tue Jul 2 22:41:57 2019 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 14:50:17 2019 +0100
input: avoid exceptions during logging.
Change-Id: I4dfc44688f7320c9294018904732e4343229de9b
diff --git a/loleaflet/src/layer/marker/ClipboardContainer.js b/loleaflet/src/layer/marker/ClipboardContainer.js
index c3f070932..a6631cccb 100644
--- a/loleaflet/src/layer/marker/ClipboardContainer.js
+++ b/loleaflet/src/layer/marker/ClipboardContainer.js
@@ -370,6 +370,12 @@ L.ClipboardContainer = L.Layer.extend({
},
_fancyLog: function _fancyLog(type, payload) {
+ // Avoid unhelpful exceptions
+ if (payload === undefined)
+ payload = 'undefined';
+ else if (payload === null)
+ payload = 'null';
+
// Save to downloadable log
L.Log.log(payload.toString(), 'INPUT');
commit 0c218028eb243919a66e1b3bcc42c47aa5ecde94
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Tue Jul 2 22:20:31 2019 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Thu Oct 3 14:50:17 2019 +0100
... etc. - the rest is truncated
More information about the Libreoffice-commits
mailing list