[Libreoffice-commits] online.git: Branch 'distro/collabora/collabora-online-cd-4' - 2 commits - loleaflet/html loleaflet/js loleaflet/reference.html loleaflet/src test/data wsd/ClientSession.cpp wsd/DocumentBroker.cpp wsd/DocumentBroker.hpp wsd/Storage.cpp wsd/Storage.hpp

Ashod Nakashian (via logerrit) logerrit at kemper.freedesktop.org
Mon Jun 17 11:32:10 UTC 2019


 loleaflet/html/framed.doc.html            |   10 +++++
 loleaflet/js/toolbar.js                   |   13 +++++--
 loleaflet/reference.html                  |   52 ++++++++++++++++++++++++++++--
 loleaflet/src/control/Control.Menubar.js  |    9 ++++-
 loleaflet/src/control/Toolbar.js          |   14 +++++---
 loleaflet/src/layer/tile/TileLayer.js     |    6 ++-
 loleaflet/src/map/Map.js                  |    1 
 loleaflet/src/map/handler/Map.Keyboard.js |    9 +++--
 loleaflet/src/map/handler/Map.WOPI.js     |   16 ++++++++-
 test/data/empty.odt                       |binary
 wsd/ClientSession.cpp                     |    9 ++++-
 wsd/DocumentBroker.cpp                    |    4 +-
 wsd/DocumentBroker.hpp                    |    2 -
 wsd/Storage.cpp                           |    2 +
 wsd/Storage.hpp                           |    6 +++
 15 files changed, 132 insertions(+), 21 deletions(-)

New commits:
commit 04064878fc24d910435ca0162c2f37b68b493d58
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Sun Jun 16 13:16:20 2019 -0400
Commit:     Andras Timar <andras.timar at collabora.com>
CommitDate: Mon Jun 17 13:32:01 2019 +0200

    leaflet: support disabling default action
    
    Clients often need to handle certain commands themselves.
    This is especially true for Action_Save and Action_Close.
    
    A new postMessage command, Disable_Default_UIAction, is
    now available to support disabling/enabling the default
    action for certain commands (as of this patch, only
    Action_Save and Action_Close are supported).
    
    The actions in question issue a notification and,
    when the default handler is disabled, the client
    is expected to handle the notification for which
    they disabled the default handler and act as necessary.
    
    See reference.html for more details.
    
    Change-Id: Ia6ce4e2d7578f79cc2069097e0b968e6c4aeabd1
    Reviewed-on: https://gerrit.libreoffice.org/74136
    Reviewed-by: Andras Timar <andras.timar at collabora.com>
    Tested-by: Andras Timar <andras.timar at collabora.com>

diff --git a/loleaflet/html/framed.doc.html b/loleaflet/html/framed.doc.html
index 9a1838f67..d89a1a98f 100644
--- a/loleaflet/html/framed.doc.html
+++ b/loleaflet/html/framed.doc.html
@@ -76,6 +76,12 @@
             });
       }
 
+      function disable_default_uiaction(action, disable) {
+        post({'MessageId': 'Disable_Default_UIAction',
+              'Values': { 'action': action, 'disable': disable }
+            });
+      }
+
       // This function is invoked when the iframe posts a message back.
 
       function receiveMessage(event) {
@@ -115,6 +121,8 @@
       <button onclick="show_commands('save'); return false;">Show Save Commands</button></br>
       <button onclick="hide_commands('print'); return false;">Hide Print Commands</button>
       <button onclick="show_commands('print'); return false;">Show Print Commands</button></br></br>
+      <button onclick="disable_default_uiaction('UI_Save', true); return false;">Disable default save action</button></br>
+      <button onclick="disable_default_uiaction('UI_Save', false); return false;">Enable default save action</button></br></br>
     </form>
 
     <!-- The hostname and pathnames below are obviously specific to my
diff --git a/loleaflet/js/toolbar.js b/loleaflet/js/toolbar.js
index cce5b6991..2fe703d7e 100644
--- a/loleaflet/js/toolbar.js
+++ b/loleaflet/js/toolbar.js
@@ -137,7 +137,10 @@ function onClick(e, id, item, subItem) {
 		map.print();
 	}
 	else if (id === 'save') {
-		map.save(false /* An explicit save should terminate cell edit */, false /* An explicit save should save it again */);
+		map.fire('postMessage', {msgId: 'UI_Save'});
+		if (!map._disableDefaultAction['UI_Save']) {
+			map.save(false /* An explicit save should terminate cell edit */, false /* An explicit save should save it again */);
+		}
 	}
 	else if (id === 'repair') {
 		map._socket.sendMessage('commandvalues command=.uno:DocumentRepair');
@@ -296,7 +299,9 @@ function onClick(e, id, item, subItem) {
 			map.fire('postMessage', {msgId: 'close', args: {EverModified: map._everModified, Deprecated: true}});
 			map.fire('postMessage', {msgId: 'UI_Close', args: {EverModified: map._everModified}});
 		}
-		map.remove();
+		if (!map._disableDefaultAction['UI_Close']) {
+			map.remove();
+		}
 	}
 	else {
 		map.handleSigningClickEvent(id, item); // this handles a bunch of signing bar click events
@@ -2472,7 +2477,9 @@ $(document).ready(function() {
 	$('#closebutton').click(function() {
 		map.fire('postMessage', {msgId: 'close', args: {EverModified: map._everModified, Deprecated: true}});
 		map.fire('postMessage', {msgId: 'UI_Close', args: {EverModified: map._everModified}});
-		map.remove();
+		if (!map._disableDefaultAction['UI_Close']) {
+			map.remove();
+		}
 	});
 
 	// Attach insert file action
diff --git a/loleaflet/reference.html b/loleaflet/reference.html
index 37748066a..80366cc90 100644
--- a/loleaflet/reference.html
+++ b/loleaflet/reference.html
@@ -3183,6 +3183,47 @@ WOPI host to editor
 			<a href="https://opengrok.libreoffice.org/xref/online/loleaflet/src/control/Control.Menubar.js">loleaflet/src/control/Control.Menubar.js</a>.
 		</td>
 	</tr>
+	<tr>
+		<td><code><b>Disable_Default_UIAction</b></code></td>
+		<td>
+			<code><nobr>action: <string></nobr></code>
+			<code><nobr>disable: <Boolean></nobr></code>
+		</td>
+		<td>
+			Disable the default handler and action for a UI command.<br/>
+
+			<code>action</code> is the action name to enable/disable the
+			default action for.<br/>
+
+			<code>disable</code> controls whether to disable (true) or
+			enable (false) the default action.<br/>
+
+			When set to true, the given UI command will only issue a postMessage
+			without invoking the default action, leaving it up to the client
+			to intercept the postMessage event and handle as necessary.
+			Notice that some actions do not have any default handler to
+			begin with (such as UI_SaveAs and UI_Share) and therefore this
+			will have no effect on them; they only issue postMessage notification
+			anyway without taking any action beyond that.<br/>
+
+			For example, UI_Save will be issued for invoking the save
+			command (from the menu, toolbar, or keyboard shortcut) and no
+			action will take place if 'UI_Save' is disabled via
+			the Disable_Default_UIAction command. Clients who disable
+			UI_Save should then issue Action_Save themselves, when and
+			if they desire to save the document.
+			Similarly, when disabling UI_Close, the document will not
+			close upon invoking the UI_Close action, instead a postMessage
+			notification will be issued and it will be up to the client
+			to issue Action_Close when they desire.<br/>
+
+			Clients must be careful not to issue duplicate actions when
+			the default handler is enabled, instead, they should only
+			issue actions themselves when the default is disabled.
+
+			Note: currently only UI_Save and UI_Close are supported.<br/>
+		</td>
+	</tr>
 </table>
 Editor to WOPI host
 <table data-id='postmessage-misc-to-host'>
diff --git a/loleaflet/src/control/Control.Menubar.js b/loleaflet/src/control/Control.Menubar.js
index 1d03ac4b5..fa05f48b7 100644
--- a/loleaflet/src/control/Control.Menubar.js
+++ b/loleaflet/src/control/Control.Menubar.js
@@ -726,7 +726,10 @@ L.Control.Menubar = L.Control.extend({
 	_executeAction: function(item) {
 		var id = $(item).data('id');
 		if (id === 'save') {
-			this._map.save(true, true);
+			this._map.fire('postMessage', {msgId: 'UI_Save'});
+			if (!this._map._disableDefaultAction['UI_Save']) {
+				this._map.save(true, true);
+			}
 		} else if (id === 'saveas') {
 			this._map.fire('postMessage', {msgId: 'UI_SaveAs'});
 		} else if (id === 'shareas') {
@@ -787,7 +790,9 @@ L.Control.Menubar = L.Control.extend({
 				this._map.fire('postMessage', {msgId: 'close', args: {EverModified: this._map._everModified, Deprecated: true}});
 				this._map.fire('postMessage', {msgId: 'UI_Close', args: {EverModified: this._map._everModified}});
 			}
-			this._map.remove();
+			if (!this._map._disableDefaultAction['UI_Close']) {
+				this._map.remove();
+			}
 		} else if (id === 'repair') {
 			this._map._socket.sendMessage('commandvalues command=.uno:DocumentRepair');
 		}
diff --git a/loleaflet/src/layer/tile/TileLayer.js b/loleaflet/src/layer/tile/TileLayer.js
index 11f2995e7..2e280dbed 100644
--- a/loleaflet/src/layer/tile/TileLayer.js
+++ b/loleaflet/src/layer/tile/TileLayer.js
@@ -502,7 +502,9 @@ L.TileLayer = L.GridLayer.extend({
 			if (this._map._docLayer._viewId === viewId) {
 				this._map.fire('postMessage', {msgId: 'close', args: {EverModified: this._map._everModified, Deprecated: true}});
 				this._map.fire('postMessage', {msgId: 'UI_Close', args: {EverModified: this._map._everModified}});
-				this._map.remove();
+				if (!this._map._disableDefaultAction['UI_Close']) {
+					this._map.remove();
+				}
 			}
 		}
 	},
@@ -812,7 +814,7 @@ L.TileLayer = L.GridLayer.extend({
 		//first time document open, set last cursor position
 		if (this.lastCursorPos.lat === 0 && this.lastCursorPos.lng === 0)
 			this.lastCursorPos = cursorPos;
-		
+
 		var updateCursor = false;
 		if ((this.lastCursorPos.lat !== cursorPos.lat) || (this.lastCursorPos.lng !== cursorPos.lng)) {
 			updateCursor = true;
diff --git a/loleaflet/src/map/Map.js b/loleaflet/src/map/Map.js
index a02528ca0..c43f873d9 100644
--- a/loleaflet/src/map/Map.js
+++ b/loleaflet/src/map/Map.js
@@ -98,6 +98,7 @@ L.Map = L.Evented.extend({
 		this._serverRecycling = false;
 		this._documentIdle = false;
 		this._helpTarget = null; // help page that fits best the current context
+		this._disableDefaultAction = {}; // The events for which the default handler is disabled and only issues postMessage.
 
 		vex.dialogID = -1;
 
diff --git a/loleaflet/src/map/handler/Map.Keyboard.js b/loleaflet/src/map/handler/Map.Keyboard.js
index 9ef49f1b9..4b71a7605 100644
--- a/loleaflet/src/map/handler/Map.Keyboard.js
+++ b/loleaflet/src/map/handler/Map.Keyboard.js
@@ -185,7 +185,7 @@ L.Map.Keyboard = L.Handler.extend({
 	/*
 	 * 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 
+	 * 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) {
@@ -539,8 +539,11 @@ L.Map.Keyboard = L.Handler.extend({
 			this._map.print();
 			return true;
 		case 83: // s
-			this._map.save(false /* An explicit save should terminate cell edit */,
-			               false /* An explicit save should save it again */);
+			this._map.fire('postMessage', {msgId: 'UI_Save'});
+			if (!this._map._disableDefaultAction['UI_Save']) {
+				this._map.save(false /* An explicit save should terminate cell edit */,
+				               false /* An explicit save should save it again */);
+			}
 			return true;
 		case 86: // v
 		case 118: // v (Safari)
diff --git a/loleaflet/src/map/handler/Map.WOPI.js b/loleaflet/src/map/handler/Map.WOPI.js
index c5c0a7efc..ae83aaf17 100644
--- a/loleaflet/src/map/handler/Map.WOPI.js
+++ b/loleaflet/src/map/handler/Map.WOPI.js
@@ -217,6 +217,19 @@ L.Map.WOPI = L.Handler.extend({
 				}
 			}
 		}
+		else if (msg.MessageId === 'Disable_Default_UIAction') {
+			// Disable the default handler and action for a UI command.
+			// When set to true, the given UI command will issue a postmessage
+			// only. For example, UI_Save will be issued for invoking the save
+			// command (from the menu, toolbar, or keyboard shortcut) and no
+			// action will take place if 'UI_Save' is disabled via
+			// the Disable_Default_UIAction command.
+			if (msg.Values && msg.Values.action && msg.Values.disable !== undefined) {
+				this._map._disableDefaultAction[msg.Values.action] = msg.Values.disable;
+			}
+		}
+
+		// All following actions must be done after initialization is completed.
 		if (!window.WOPIPostmessageReady) {
 			return;
 		}
diff --git a/test/data/empty.odt b/test/data/empty.odt
index 6b0747507..208d2f874 100644
Binary files a/test/data/empty.odt and b/test/data/empty.odt differ
commit fcd70816f2d702d4243fa0a118d8b89db12d64a6
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Sun Jun 16 14:42:11 2019 -0400
Commit:     Andras Timar <andras.timar at collabora.com>
CommitDate: Mon Jun 17 13:31:50 2019 +0200

    Pass Extended Data in Action_Save from the client to the WOPI host
    
    Clients often need to communicate with their wopi hosts when
    invoking Action_Save to provide more context when storing the
    document in question. Action_Save now support passing arbitrary
    string as ExtendedData entry that can be used by client to
    pass any context or otherwise flags to the WOPI host, which
    will receive it via the X-LOOL-WOPI-ExtendedData custom header.
    
    See reference.html for more details.
    
    Change-Id: I1814d1f3d984a553ffa60cec13d23b014ba59eb3
    Reviewed-on: https://gerrit.libreoffice.org/74135
    Reviewed-by: Andras Timar <andras.timar at collabora.com>
    Tested-by: Andras Timar <andras.timar at collabora.com>

diff --git a/loleaflet/html/framed.doc.html b/loleaflet/html/framed.doc.html
index 28fb465c8..9a1838f67 100644
--- a/loleaflet/html/framed.doc.html
+++ b/loleaflet/html/framed.doc.html
@@ -48,7 +48,7 @@
 
       function save() {
         post({'MessageId': 'Action_Save',
-              'Values': { 'Notify': true, }
+              'Values': { 'Notify': true, 'ExtendedData': 'CustomFlag=CustomValue;AnotherFlag=AnotherValue' }
             });
       }
 
diff --git a/loleaflet/reference.html b/loleaflet/reference.html
index 41ae4ebe1..37748066a 100644
--- a/loleaflet/reference.html
+++ b/loleaflet/reference.html
@@ -2920,6 +2920,7 @@ WOPI host to editor
 		    <nobr>DontTerminateEdit: <boolean></nobr>
 		    <nobr>DontSaveIfUnmodified: <boolean></nobr>
 		    <nobr>Notify: <boolean></nobr>
+		    <nobr>ExtendedData: <String></nobr>
 		</code></td>
 		<td>Saves the document.<br/>
 		<code>DontTerminateEdit</code> is relevant for spreadsheets where saving
@@ -2928,10 +2929,16 @@ WOPI host to editor
 		user's editing session in spreadsheets.<br/>
 		<code>DontSaveIfUnmodified</code> prevents loolwsd to save the file back to storage if document is
 		unmodified (only cursor position changed etc.) but still saved. This can be helpful
-		to prevent creating unnecessary file revisions.
+		to prevent creating unnecessary file revisions.<br/>
 		<code>Notify</code> when present and set to true notifies the
 		host when document is saved. See <code>Action_Save_Resp</code>
-		for details.
+		for details.<br/>
+		<code>ExtendedData</code> optional data carried over to the WOPI host if provided
+		in the X-LOOL-WOPI-ExtendedData header. The contents are preserved as-is,
+		however, care must be taken to avoid using anything that HTTP headers do
+		not allow, also, special values such as new-line, null character, non-printable
+		characters, etc. are not allowed. The client can use this to pass multiple values
+		to the WOPI host which can then act on them.<br/>
 		</td>
 	</tr>
 	<tr>
diff --git a/loleaflet/src/control/Toolbar.js b/loleaflet/src/control/Toolbar.js
index a08642b2e..89b0f65e6 100644
--- a/loleaflet/src/control/Toolbar.js
+++ b/loleaflet/src/control/Toolbar.js
@@ -143,10 +143,16 @@ L.Map.include({
 		}
 	},
 
-	save: function(dontTerminateEdit, dontSaveIfUnmodified) {
-		this._socket.sendMessage('save' +
-		                         ' dontTerminateEdit=' + (dontTerminateEdit ? 1 : 0) +
-		                         ' dontSaveIfUnmodified=' + (dontSaveIfUnmodified ? 1 : 0));
+	save: function(dontTerminateEdit, dontSaveIfUnmodified, extendedData) {
+		var msg = 'save' +
+					' dontTerminateEdit=' + (dontTerminateEdit ? 1 : 0) +
+					' dontSaveIfUnmodified=' + (dontSaveIfUnmodified ? 1 : 0);
+
+		if (extendedData !== undefined) {
+			msg += ' extendedData=' + extendedData;
+		}
+
+		this._socket.sendMessage(msg);
 	},
 
 	sendUnoCommand: function (command, json) {
diff --git a/loleaflet/src/map/handler/Map.WOPI.js b/loleaflet/src/map/handler/Map.WOPI.js
index 8f470fbed..c5c0a7efc 100644
--- a/loleaflet/src/map/handler/Map.WOPI.js
+++ b/loleaflet/src/map/handler/Map.WOPI.js
@@ -268,9 +268,10 @@ L.Map.WOPI = L.Handler.extend({
 		else if (msg.MessageId === 'Action_Save') {
 			var dontTerminateEdit = msg.Values && msg.Values['DontTerminateEdit'];
 			var dontSaveIfUnmodified = msg.Values && msg.Values['DontSaveIfUnmodified'];
+			var extendedData = msg.Values && msg.Values['ExtendedData'];
 			this._notifySave = msg.Values && msg.Values['Notify'];
 
-			this._map.save(dontTerminateEdit, dontSaveIfUnmodified);
+			this._map.save(dontTerminateEdit, dontSaveIfUnmodified, extendedData);
 		}
 		else if (msg.MessageId === 'Action_Close') {
 			this._map.remove();
diff --git a/wsd/ClientSession.cpp b/wsd/ClientSession.cpp
index 22f1fd202..f3eeadf97 100644
--- a/wsd/ClientSession.cpp
+++ b/wsd/ClientSession.cpp
@@ -266,7 +266,14 @@ bool ClientSession::_handleInput(const char *buffer, int length)
         if (!isReadOnly() && tokens.size() > 2)
             getTokenInteger(tokens[2], "dontSaveIfUnmodified", dontSaveIfUnmodified);
 
-        docBroker->sendUnoSave(getId(), dontTerminateEdit != 0, dontSaveIfUnmodified != 0);
+        std::string extendedData;
+        if (tokens.size() > 3)
+            getTokenString(tokens[3], "extendedData", extendedData);
+
+        constexpr bool isAutosave = false;
+        constexpr bool isExitSave = false;
+        docBroker->sendUnoSave(getId(), dontTerminateEdit != 0, dontSaveIfUnmodified != 0,
+                                isAutosave, isExitSave, extendedData);
     }
     else if (tokens[0] == "savetostorage")
     {
diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp
index 253774249..c5e095ae4 100644
--- a/wsd/DocumentBroker.cpp
+++ b/wsd/DocumentBroker.cpp
@@ -1046,7 +1046,8 @@ bool DocumentBroker::autoSave(const bool force)
 }
 
 bool DocumentBroker::sendUnoSave(const std::string& sessionId, bool dontTerminateEdit,
-                                 bool dontSaveIfUnmodified, bool isAutosave, bool isExitSave)
+                                 bool dontSaveIfUnmodified, bool isAutosave, bool isExitSave,
+                                 const std::string& extendedData)
 {
     assertCorrectThread();
 
@@ -1090,6 +1091,7 @@ bool DocumentBroker::sendUnoSave(const std::string& sessionId, bool dontTerminat
         assert(_storage);
         _storage->setIsAutosave(isAutosave || UnitWSD::get().isAutosave());
         _storage->setIsExitSave(isExitSave);
+        _storage->setExtendedData(extendedData);
 
         const std::string saveArgs = oss.str();
         LOG_TRC(".uno:Save arguments: " << saveArgs);
diff --git a/wsd/DocumentBroker.hpp b/wsd/DocumentBroker.hpp
index 55216a0a9..693370507 100644
--- a/wsd/DocumentBroker.hpp
+++ b/wsd/DocumentBroker.hpp
@@ -349,7 +349,7 @@ public:
     /// Sends the .uno:Save command to LoKit.
     bool sendUnoSave(const std::string& sessionId, bool dontTerminateEdit = true,
                      bool dontSaveIfUnmodified = true, bool isAutosave = false,
-                     bool isExitSave = false);
+                     bool isExitSave = false, const std::string& extendedData = std::string());
 
     /// Sends a message to all sessions
     void broadcastMessage(const std::string& message);
diff --git a/wsd/Storage.cpp b/wsd/Storage.cpp
index 387a03b50..208218942 100644
--- a/wsd/Storage.cpp
+++ b/wsd/Storage.cpp
@@ -729,6 +729,8 @@ StorageBase::SaveResult WopiStorage::saveLocalFileToStorage(const Authorization&
             request.set("X-LOOL-WOPI-IsModifiedByUser", isUserModified()? "true": "false");
             request.set("X-LOOL-WOPI-IsAutosave", getIsAutosave()? "true": "false");
             request.set("X-LOOL-WOPI-IsExitSave", isExitSave()? "true": "false");
+            if (!getExtendedData().empty())
+                request.set("X-LOOL-WOPI-ExtendedData", getExtendedData());
 
             if (!getForceSave())
             {
diff --git a/wsd/Storage.hpp b/wsd/Storage.hpp
index 02539b8f1..ed1c69a69 100644
--- a/wsd/Storage.hpp
+++ b/wsd/Storage.hpp
@@ -179,6 +179,7 @@ public:
     bool getIsAutosave() const { return _isAutosave; }
     void setIsExitSave(bool exitSave) { _isExitSave = exitSave; }
     bool isExitSave() const { return _isExitSave; }
+    void setExtendedData(const std::string& extendedData) { _extendedData = extendedData; }
 
     void setFileInfo(const FileInfo& fileInfo) { _fileInfo = fileInfo; }
 
@@ -211,6 +212,9 @@ protected:
     /// Returns the root path of the jail directory of docs.
     std::string getLocalRootPath() const;
 
+    /// Returns the client-provided extended data to send to the WOPI host.
+    const std::string& getExtendedData() const { return _extendedData; }
+
 private:
     const Poco::URI _uri;
     std::string _localStorePath;
@@ -228,6 +232,8 @@ private:
     bool _isAutosave;
     /// Saving on exit (when the document is cleaned up from memory)
     bool _isExitSave;
+    /// The client-provided saving extended data to send to the WOPI host.
+    std::string _extendedData;
 
     static bool FilesystemEnabled;
     static bool WopiEnabled;


More information about the Libreoffice-commits mailing list