[Libreoffice-commits] online.git: 91 commits - common/Session.cpp kit/ChildSession.cpp kit/ChildSession.hpp kit/Kit.cpp loleaflet/css loleaflet/debug loleaflet/html loleaflet/images loleaflet/Makefile.am loleaflet/README loleaflet/reference.html loleaflet/src net/Socket.cpp wsd/ClientSession.cpp wsd/DocumentBroker.cpp wsd/DocumentBroker.hpp wsd/FileServer.cpp wsd/Storage.cpp wsd/Storage.hpp

Ashod Nakashian (via logerrit) logerrit at kemper.freedesktop.org
Tue Sep 3 05:55:46 UTC 2019


 common/Session.cpp                         |    1 
 kit/ChildSession.cpp                       |   42 +++
 kit/ChildSession.hpp                       |    3 
 kit/Kit.cpp                                |    5 
 loleaflet/Makefile.am                      |    1 
 loleaflet/README                           |   23 ++
 loleaflet/css/leaflet.css                  |    5 
 loleaflet/css/loleaflet.css                |   46 ++++
 loleaflet/css/partsPreviewControl.css      |    4 
 loleaflet/css/sidebar.css                  |    3 
 loleaflet/css/toolbar.css                  |    1 
 loleaflet/debug/document/loleaflet.html    |    2 
 loleaflet/html/framed.doc.html             |  114 ++++++++--
 loleaflet/html/loleaflet.html.m4           |    4 
 loleaflet/images/lc_formproperties.svg     |    1 
 loleaflet/reference.html                   |  125 +++++++++++
 loleaflet/src/control/Control.LokDialog.js |  312 ++++++++++++++++++++++++++---
 loleaflet/src/control/Control.Menubar.js   |   75 ++++++
 loleaflet/src/control/Control.Toolbar.js   |   43 +++
 loleaflet/src/control/Parts.js             |    1 
 loleaflet/src/control/Toolbar.js           |   14 -
 loleaflet/src/core/Socket.js               |    6 
 loleaflet/src/layer/tile/TileLayer.js      |    4 
 loleaflet/src/main.js                      |    4 
 loleaflet/src/map/Map.js                   |   72 ++++++
 loleaflet/src/map/handler/Map.Keyboard.js  |   12 -
 loleaflet/src/map/handler/Map.WOPI.js      |  170 +++++++++------
 net/Socket.cpp                             |    1 
 wsd/ClientSession.cpp                      |   21 +
 wsd/DocumentBroker.cpp                     |    4 
 wsd/DocumentBroker.hpp                     |    2 
 wsd/FileServer.cpp                         |    5 
 wsd/Storage.cpp                            |    3 
 wsd/Storage.hpp                            |    6 
 34 files changed, 979 insertions(+), 156 deletions(-)

New commits:
commit 8deb0fbcbd2b6095b5ceda65215e7c9b32ae91ed
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Tue Sep 3 00:47:27 2019 -0400
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    leaflet: minor cleanup of sidebar
    
    Change-Id: I0c3e9e0a35a093f529346ea3b3afbd44ed875570

diff --git a/loleaflet/src/control/Control.LokDialog.js b/loleaflet/src/control/Control.LokDialog.js
index a5cfb01f2..e71e0c256 100644
--- a/loleaflet/src/control/Control.LokDialog.js
+++ b/loleaflet/src/control/Control.LokDialog.js
@@ -168,12 +168,12 @@ L.Control.LokDialog = L.Control.extend({
 	},
 
 	_isOpen: function(id) {
-		return this._dialogs[id] &&
+		return (id in this._dialogs) && this._dialogs[id] &&
 			$('#' + this._toStrId(id)).length > 0;
 	},
 
 	_isSidebar: function(id) {
-		return this._dialogs[id].isSidebar;
+		return (id in this._dialogs) && this._dialogs[id].isSidebar;
 	},
 
 	// Given a prefixed dialog id like 'lokdialog-323', gives a raw id, 323.
@@ -253,6 +253,7 @@ L.Control.LokDialog = L.Control.extend({
 	},
 
 	_onDialogMsg: function(e) {
+		console.log('onDialogMsg: id: ' + e.id + ', winType: ' + e.winType + ', action: ' + e.action + ', size: ' + e.size + ', rectangle: ' + e.rectangle);
 		if (e.winType != undefined && e.winType !== 'dialog' && e.winType !== 'child' && e.winType !== 'deck') {
 			return;
 		}
@@ -659,7 +660,7 @@ L.Control.LokDialog = L.Control.extend({
 			// 'mousedown' -> 'buttondown'
 			var lokEventType = e.type.replace('mouse', 'button');
 			this._postWindowMouseEvent(lokEventType, id, e.offsetX, e.offsetY, 1, buttons, 0);
-			this.focus(id, !this._dialogs[id].isSidebar);
+			this.focus(id, !this._isSidebar(id));
 			// Keep map active while user is playing with sidebar/dialog.
 			this._map.lastActiveTime = Date.now();
 		}, this);
@@ -806,12 +807,6 @@ L.Control.LokDialog = L.Control.extend({
 	},
 
 	_onSidebarClose: function(dialogId) {
-		this._resizeSidebar(dialogId, 0);
-		$('#' + this._currentDeck.strId).remove();
-		this._map.focus();
-		delete this._dialogs[dialogId];
-		this._currentDeck = null;
-
 		//play slide animation to right if this is a mobile or tablet
 		if (L.Browser.mobile) {
 			var sidebar = $('#sidebar-dock-wrapper');
@@ -827,6 +822,14 @@ L.Control.LokDialog = L.Control.extend({
 				$('#toolbar-down').show();
 			});
 		}
+
+		this._resizeSidebar(dialogId, 0);
+		$('#' + this._currentDeck.strId).remove();
+		this._map.focus();
+		delete this._dialogs[dialogId];
+		this._currentDeck = null;
+
+		$('#sidebar-dock-wrapper').css({display: ''});
 	},
 
 	_onDialogClose: function(dialogId, notifyBackend) {
@@ -843,25 +846,24 @@ L.Control.LokDialog = L.Control.extend({
 	},
 
 	_onClosePopups: function() {
-		for (var dialog in this._dialogs) {
-			if (this._dialogs[dialog].isSidebar != true) {
-				this._onDialogClose(this._dialogs[dialog].id, true);
+		for (var dialogId in this._dialogs) {
+			if (!this._isSidebar(dialogId)) {
+				this._onDialogClose(dialogId, true);
 			}
 		}
 	},
 
 	onCloseCurrentPopUp: function() {
 		// for title-less dialog only (context menu, pop-up)
-		if (!this._currentId || !this._isOpen(this._currentId) ||
-			this._dialogs[this._currentId].title || this._isSidebar(this._currentId))
-			return;
-		this._onDialogClose(this._currentId, true);
+		if (this._currentId && this._isOpen(this._currentId) &&
+			this._dialogs[this._currentId].title && !this._isSidebar(this._currentId))
+			this._onDialogClose(this._currentId, true);
 	},
 
 	_closeSidebar: function() {
-		for (var dialog in this._dialogs) {
-			if (this._dialogs[dialog].isSidebar == true) {
-				this._onSidebarClose(dialog);
+		for (var dialogId in this._dialogs) {
+			if (this._isSidebar(dialogId)) {
+				this._onSidebarClose(dialogId);
 			}
 		}
 		$('#sidebar-dock-wrapper').css({display: ''});
commit 2dbb7e23d98afca6b454ab3b79e43f98bc18bac1
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Mon Sep 2 13:46:02 2019 -0400
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    leaflet: support creating size_changed on sidebars too
    
    Change-Id: Iee13732838ac2c5b80256c1d2c2e8ece720244dc

diff --git a/loleaflet/src/control/Control.LokDialog.js b/loleaflet/src/control/Control.LokDialog.js
index 4d97cb80f..a5cfb01f2 100644
--- a/loleaflet/src/control/Control.LokDialog.js
+++ b/loleaflet/src/control/Control.LokDialog.js
@@ -329,7 +329,10 @@ L.Control.LokDialog = L.Control.extend({
 			// FIXME: we don't really have to destroy and launch the dialog again but do it for
 			// now because the size sent to us previously in 'created' cb is not correct
 			$('#' + strId).remove();
-			this._launchDialog(e.id, null, null, width, height, this._dialogs[parseInt(e.id)].title);
+			if (e.winType  === 'deck' || this._isSidebar(e.id))
+				this._launchSidebar(e.id, width, height);
+			else
+				this._launchDialog(e.id, null, null, width, height, this._dialogs[parseInt(e.id)].title);
 		} else if (e.action === 'cursor_invalidate') {
 			if (this._isOpen(e.id) && !!e.rectangle) {
 				rectangle = e.rectangle.split(',');
commit 53bd11c8e74f9242b91771dd7c2da183e0a62dc6
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Sun Sep 1 22:13:58 2019 -0400
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    leaflet: Sidebar is not a popup window
    
    Change-Id: Ib786a4038bfb55ee71e7e66a0e195fd43c9603af

diff --git a/loleaflet/src/control/Control.LokDialog.js b/loleaflet/src/control/Control.LokDialog.js
index 0dd42476b..4d97cb80f 100644
--- a/loleaflet/src/control/Control.LokDialog.js
+++ b/loleaflet/src/control/Control.LokDialog.js
@@ -849,7 +849,8 @@ L.Control.LokDialog = L.Control.extend({
 
 	onCloseCurrentPopUp: function() {
 		// for title-less dialog only (context menu, pop-up)
-		if (!this._currentId || !this._isOpen(this._currentId) || this._dialogs[this._currentId].title)
+		if (!this._currentId || !this._isOpen(this._currentId) ||
+			this._dialogs[this._currentId].title || this._isSidebar(this._currentId))
 			return;
 		this._onDialogClose(this._currentId, true);
 	},
commit 97a7b1f170e14c3fbbaed795ba8591a10831fa4e
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Wed Aug 28 21:18:53 2019 -0400
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    wsd: sanitize url when error reporting
    
    (cherry picked from commit 2b35ae713943abd5f51de383fb2d26ab96f73988)
    
    Change-Id: I7937429f2f987212beaeb9a97b48bfedb0a7ac58

diff --git a/wsd/FileServer.cpp b/wsd/FileServer.cpp
index bfde038c9..01e73cb79 100644
--- a/wsd/FileServer.cpp
+++ b/wsd/FileServer.cpp
@@ -460,8 +460,10 @@ void FileServerRequestHandler::sendError(int errorCode, const Poco::Net::HTTPReq
         << "\r\n";
     if (!shortMessage.empty())
     {
+        std::string pathSanitized;
+        Poco::URI::encode(path, "", pathSanitized);
         oss << "<h1>Error: " << shortMessage << "</h1>"
-            "<p>" << longMessage << " " << path << "</p>"
+            "<p>" << longMessage << ' ' << pathSanitized << "</p>"
             "<p>Please contact your system administrator.</p>";
     }
     socket->send(oss.str());
@@ -740,6 +742,7 @@ void FileServerRequestHandler::preprocessFile(const HTTPRequest& request, Poco::
         LOG_TRC("Denied all frame ancestors");
         cspOss << "img-src 'self' data: none;";
     }
+
     cspOss << "\r\n";
     // Append CSP to response headers too
     oss << cspOss.str();
commit 5772bbd8c9de6bb38d7c341b93b6757ab0c63dd7
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Sat Aug 17 11:13:57 2019 -0400
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    leaflet: save only when not read-only
    
    Change-Id: I0cff68d2a2e8354b8c5a6888faa9fa823295c98e

diff --git a/loleaflet/src/control/Control.Menubar.js b/loleaflet/src/control/Control.Menubar.js
index ba3fe0b98..9ac0e8fb2 100644
--- a/loleaflet/src/control/Control.Menubar.js
+++ b/loleaflet/src/control/Control.Menubar.js
@@ -767,9 +767,12 @@ L.Control.Menubar = L.Control.extend({
 	_executeAction: function(item) {
 		var id = $(item).data('id');
 		if (id === 'save') {
-			this._map.fire('postMessage', {msgId: 'UI_Save'});
-			if (!this._map._disableDefaultAction['UI_Save']) {
-				this._map.save(true, true);
+			// Save only when not read-only.
+			if (map._permission !== 'readonly') {
+				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'});
diff --git a/loleaflet/src/control/Control.Toolbar.js b/loleaflet/src/control/Control.Toolbar.js
index 7b3343156..e7af7aa81 100644
--- a/loleaflet/src/control/Control.Toolbar.js
+++ b/loleaflet/src/control/Control.Toolbar.js
@@ -141,9 +141,12 @@ function onClick(e, id, item, subItem) {
 		map.print();
 	}
 	else if (id === 'save') {
-		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 */);
+		// Save only when not read-only.
+		if (map._permission !== 'readonly') {
+			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') {
diff --git a/loleaflet/src/map/handler/Map.Keyboard.js b/loleaflet/src/map/handler/Map.Keyboard.js
index b9456b9fa..968a8c8ba 100644
--- a/loleaflet/src/map/handler/Map.Keyboard.js
+++ b/loleaflet/src/map/handler/Map.Keyboard.js
@@ -539,10 +539,13 @@ L.Map.Keyboard = L.Handler.extend({
 			this._map.print();
 			return true;
 		case 83: // s
-			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 */);
+			// Save only when not read-only.
+			if (this._map._permission !== 'readonly') {
+				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
commit ee0f9c8d5348e48f4d7da851447370c71845cb15
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Tue Jul 30 00:01:24 2019 -0400
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    leaflet: add id to Format menu
    
    Change-Id: I16569eadefde1d4bd9d841688cbb5a2a43c25f44
    (cherry picked from commit 78ad91b92348dd56388c3cb7512cb67edc0688cb)

diff --git a/loleaflet/src/control/Control.Menubar.js b/loleaflet/src/control/Control.Menubar.js
index 46ab7543b..ba3fe0b98 100644
--- a/loleaflet/src/control/Control.Menubar.js
+++ b/loleaflet/src/control/Control.Menubar.js
@@ -113,7 +113,7 @@ L.Control.Menubar = L.Control.extend({
 					{uno: '.uno:InsertIndexesEntry'},
 					{uno: '.uno:InsertAuthoritiesEntry'}]},
 			]},
-			{name: _UNO('.uno:FormatMenu', 'text'), type: 'menu', menu: [
+			{name: _UNO('.uno:FormatMenu', 'text'), id: 'format', type: 'menu', menu: [
 				{name: _UNO('.uno:FormatTextMenu', 'text'), type: 'menu', menu: [
 					{uno: '.uno:Bold'},
 					{uno: '.uno:Italic'},
commit ae9c1a67c9bbecd6915af8a00d31638c7fe12d2c
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Fri Jul 12 19:14:21 2019 -0400
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    leaflet: support show/hide of Insert>Section menu entry
    
    Change-Id: I89ccfcb7f9e091b26f1f67ec889556bfc07295a3
    (cherry picked from commit ca7246a05639572d5c1ff133ca7dd6847ca8c7b0)

diff --git a/loleaflet/src/control/Control.Menubar.js b/loleaflet/src/control/Control.Menubar.js
index bb5eb8b6c..46ab7543b 100644
--- a/loleaflet/src/control/Control.Menubar.js
+++ b/loleaflet/src/control/Control.Menubar.js
@@ -77,7 +77,7 @@ L.Control.Menubar = L.Control.extend({
 				{name: _UNO('.uno:InsertAnnotation', 'text'), id: 'insertcomment', type: 'action'},
 				{uno: '.uno:InsertObjectChart'},
 				{type: 'separator'},
-                               {uno: '.uno:InsertSection'},
+				{uno: '.uno:InsertSection', id: 'insertsection'},
 				{name: _UNO('.uno:InsertField', 'text'), type: 'menu', menu: [
 					{uno: '.uno:InsertPageNumberField'},
 					{uno: '.uno:InsertPageCountField'},
commit 22993464b835810db7eb089394cb82c39f8fbc61
Author:     Jan Holesovsky <kendy at collabora.com>
AuthorDate: Wed Jul 10 16:08:39 2019 +0200
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    android: Needs the same treatment of .uno:Sidebar as iOS.
    
    And when at that, do that actually at the same place as where it is
    handled for browser on desktop.
    
    Reviewed-on: https://gerrit.libreoffice.org/75361
    Reviewed-by: Jan Holesovsky <kendy at collabora.com>
    Tested-by: Jan Holesovsky <kendy at collabora.com>
    (cherry picked from commit fa50758a782348f031750c643cd512433c9e7aff)
    
    Change-Id: I41612e29d15de0fdc9c0e4013f6375ffcb4c3ae4

diff --git a/loleaflet/src/control/Control.Menubar.js b/loleaflet/src/control/Control.Menubar.js
index 735857bf7..bb5eb8b6c 100644
--- a/loleaflet/src/control/Control.Menubar.js
+++ b/loleaflet/src/control/Control.Menubar.js
@@ -547,18 +547,8 @@ L.Control.Menubar = L.Control.extend({
 		var docType = this._map.getDocType();
 		if (docType === 'text') {
 			this._initializeMenu(this.options.text);
-			if (window.ThisIsTheiOSApp) {
-				// The sidebar initially thinks it is visible but actually it isn't,
-				// so to make its internal state match its visible state, toggle it
-				// to be non-visible.
-				this._map.sendUnoCommand('.uno:Sidebar')
-			}
 		} else if (docType === 'spreadsheet') {
 			this._initializeMenu(this.options.spreadsheet);
-			if (window.ThisIsTheiOSApp) {
-				// As above.
-				this._map.sendUnoCommand('.uno:Sidebar');
-			}
 		} else if (docType === 'presentation' || docType === 'drawing') {
 			this._initializeMenu(this.options.presentation);
 		}
diff --git a/loleaflet/src/map/Map.js b/loleaflet/src/map/Map.js
index f2dc469e1..118e74833 100644
--- a/loleaflet/src/map/Map.js
+++ b/loleaflet/src/map/Map.js
@@ -265,7 +265,7 @@ L.Map = L.Evented.extend({
 			this.initializeModificationIndicator();
 
 			// Show sidebar.
-			if (this._docLayer && !this._docLoadedOnce && !window.mode.isMobile() && !window.mode.isTablet() &&
+			if (this._docLayer && !this._docLoadedOnce &&
 				(this._docLayer._docType === 'spreadsheet' || this._docLayer._docType === 'text')) {
 				// Let the first page finish loading then load the sidebar.
 				var map = this;
@@ -274,7 +274,15 @@ L.Map = L.Evented.extend({
                     // be loaded and show rather quickly on first use.
                     // Also, triggers sidebar window creation in the client.
 					map._socket.sendMessage('uno .uno:Sidebar');
-					map._socket.sendMessage('uno .uno:Sidebar');
+
+					// HACK: The initial state of sidebar is that the core
+					// thinks it is shown, so the command has to be triggered
+					// once again for it to be visible on the desktop
+					// (because the first .uno:Sidebar has actually hidden
+					// that)
+					if (!window.mode.isMobile() && !window.mode.isTablet() && !window.ThisIsAMobileApp) {
+						map._socket.sendMessage('uno .uno:Sidebar');
+					}
 				}, 200);
 			}
 
commit a0ca9120850836a0cca4e27f5073b55f44a8fcb4
Author:     Tor Lillqvist <tml at collabora.com>
AuthorDate: Wed Jul 10 13:38:57 2019 +0300
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    Show the View menu in the iOS app for Calc docs
    
    Also sync the sidebar state on initialization, as for Writer docs.
    
    We want View > Sidebar to show up and work also for Calc docs in the
    iOS app.
    
    Change-Id: Iaf50d03a50940a0d414b512ad55419c52c87943e
    Reviewed-on: https://gerrit.libreoffice.org/75345
    Reviewed-by: Tor Lillqvist <tml at collabora.com>
    Tested-by: Tor Lillqvist <tml at collabora.com>
    (cherry picked from commit 9c900398f3f1c95f9e30f9714c748a9d464ffb95)

diff --git a/loleaflet/src/control/Control.Menubar.js b/loleaflet/src/control/Control.Menubar.js
index 0b079ada4..735857bf7 100644
--- a/loleaflet/src/control/Control.Menubar.js
+++ b/loleaflet/src/control/Control.Menubar.js
@@ -358,9 +358,9 @@ L.Control.Menubar = L.Control.extend({
 				{type: 'separator'},
 				{uno: '.uno:SearchDialog'}
 			]},
-			{name: _UNO('.uno:ViewMenu', 'spreadsheet'), id: 'view', type: 'menu', mobileapp: false, menu: [
-				{name: _UNO('.uno:FullScreen', 'spreadsheet'), id: 'fullscreen', type: 'action'},
-				{type: 'separator'},
+			{name: _UNO('.uno:ViewMenu', 'spreadsheet'), id: 'view', type: 'menu', menu: [
+				{name: _UNO('.uno:FullScreen', 'spreadsheet'), id: 'fullscreen', type: 'action', mobileapp: false},
+				{type: 'separator', mobileapp: false},
 				{uno: '.uno:Sidebar'}
 			]},
 			{name: _UNO('.uno:InsertMenu', 'spreadsheet'), type: 'menu', menu: [
@@ -555,6 +555,10 @@ L.Control.Menubar = L.Control.extend({
 			}
 		} else if (docType === 'spreadsheet') {
 			this._initializeMenu(this.options.spreadsheet);
+			if (window.ThisIsTheiOSApp) {
+				// As above.
+				this._map.sendUnoCommand('.uno:Sidebar');
+			}
 		} else if (docType === 'presentation' || docType === 'drawing') {
 			this._initializeMenu(this.options.presentation);
 		}
commit a93c89d66616e64da597035b93b66980214d593b
Author:     Tor Lillqvist <tml at collabora.com>
AuthorDate: Tue Jul 9 17:51:52 2019 +0300
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    Sync the initial internal and apparent state of the sidebar in the iOS app
    
    Avoids having to use View > Sidebar twice for it to show up.
    
    I am told that the sidebar initially thinks it is visible, but it
    actually isn't, so the first View > Sidebar invocation caused it to
    become internally non-visible, and then the second View > Sidebar
    caused it to become visible for real, too.
    
    Now the first View > Sidebar invocation is enough for it to become
    visible.
    
    Change-Id: I4bc88f5b4d488e5fb12d89106bbd113f34347dfd
    Reviewed-on: https://gerrit.libreoffice.org/75310
    Reviewed-by: Tor Lillqvist <tml at collabora.com>
    Tested-by: Tor Lillqvist <tml at collabora.com>
    (cherry picked from commit 23df55ca8f0f145b5c0eb819f2f87a6d909d7f91)

diff --git a/loleaflet/src/control/Control.Menubar.js b/loleaflet/src/control/Control.Menubar.js
index 3c4296565..0b079ada4 100644
--- a/loleaflet/src/control/Control.Menubar.js
+++ b/loleaflet/src/control/Control.Menubar.js
@@ -547,6 +547,12 @@ L.Control.Menubar = L.Control.extend({
 		var docType = this._map.getDocType();
 		if (docType === 'text') {
 			this._initializeMenu(this.options.text);
+			if (window.ThisIsTheiOSApp) {
+				// The sidebar initially thinks it is visible but actually it isn't,
+				// so to make its internal state match its visible state, toggle it
+				// to be non-visible.
+				this._map.sendUnoCommand('.uno:Sidebar')
+			}
 		} else if (docType === 'spreadsheet') {
 			this._initializeMenu(this.options.spreadsheet);
 		} else if (docType === 'presentation' || docType === 'drawing') {
commit 8f312862ca1e3d472820b70c852ff5c7afa62ddc
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Sat Jun 29 10:52:11 2019 -0400
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    leaflet: fire Doc_ModifiedStatus with modified state of the document
    
    When .uno:ModifiedStatus is received, now Doc_ModifiedStatus
    is fired to inform the client of the modified state of the document.
    
    This is useful in case the integration needs to prompt the user to save
    before closing the document (which they can catch with the onunload or
    onbeforeunload events in the browser, as well as with our
    UI_Close when the default handler is disabled).
    
    Includes working sample and documentation.
    
    Change-Id: Ief30483e2f078b0aa9f3c006a1ecb4093375174c
    Reviewed-on: https://gerrit.libreoffice.org/74891
    Reviewed-by: Jan Holesovsky <kendy at collabora.com>
    Tested-by: Jan Holesovsky <kendy at collabora.com>

diff --git a/loleaflet/html/framed.doc.html b/loleaflet/html/framed.doc.html
index d89a1a98f..80f842c40 100644
--- a/loleaflet/html/framed.doc.html
+++ b/loleaflet/html/framed.doc.html
@@ -87,12 +87,30 @@
       function receiveMessage(event) {
         console.log('==== framed.doc.html receiveMessage: ' + event.data);
         var msg = JSON.parse(event.data);
-        if (msg && msg.MessageId == 'App_LoadingStatus') {
+        if (!msg) {
+          return;
+        }
+        if (msg.MessageId == 'App_LoadingStatus') {
           if (msg.Values) {
             if (msg.Values.Status == 'Document_Loaded') {
               window.frames[0].postMessage(JSON.stringify({'MessageId': 'Host_PostmessageReady'}), '*');
             }
           }
+        } else if (msg.MessageId == 'Doc_ModifiedStatus') {
+          if (msg.Values) {
+            if (msg.Values.Modified == true) {
+              document.getElementById("ModifiedStatus").innerHTML = "Modified";
+            }
+            else {
+              document.getElementById("ModifiedStatus").innerHTML = "Saved";
+            }
+          }
+        } else if (msg.MessageId == 'Action_Save_Resp') {
+          if (msg.Values) {
+            if (msg.Values.success == true) {
+              document.getElementById("ModifiedStatus").innerHTML = "Saved";
+            }
+          }
         }
       }
 
@@ -125,6 +143,10 @@
       <button onclick="disable_default_uiaction('UI_Save', false); return false;">Enable default save action</button></br></br>
     </form>
 
+    <p>Modified Status:
+    <span id="ModifiedStatus">Saved</span>
+    </p>
+
     <!-- The hostname and pathnames below are obviously specific to my
     personal environment and need to be changed appropriately. Also
     the hex string needs to be changed of course, to the right one as
diff --git a/loleaflet/reference.html b/loleaflet/reference.html
index 3e47008f2..f472d46f7 100644
--- a/loleaflet/reference.html
+++ b/loleaflet/reference.html
@@ -3395,6 +3395,21 @@ Note that they usually don't change but there is no guarantee that they are stab
 		Response to this query is sent via <code>Action_SaveAs</code> message.
 		</td>
 	</tr>
+	<tr>
+		<td><code><b>Doc_ModifiedStatus</b></code></td>
+		<td></td>
+		<td>
+		Notification to update the modified status of the document.
+		Values.Modified will be true, if the document has been modified
+		since the last save, otherwise, it will be false if the document
+		has been saved.
+
+		Note that this notification may be published without a change
+		from the prior value, so care must be taken to check the Values.Modified
+		value and not assume the notifiaction itself implies the
+		modified state of the document on its own.
+		</td>
+	</tr>
 </table>
 
 <h3 id='loleaflet-postmessage-python'>Calling Python scripts</h3>
diff --git a/loleaflet/src/map/Map.js b/loleaflet/src/map/Map.js
index 0b8a00c3b..f2dc469e1 100644
--- a/loleaflet/src/map/Map.js
+++ b/loleaflet/src/map/Map.js
@@ -239,8 +239,12 @@ L.Map = L.Evented.extend({
 		this._docLoadedOnce = false;
 
 		this.on('commandstatechanged', function(e) {
-			if (e.commandName === '.uno:ModifiedStatus')
+			if (e.commandName === '.uno:ModifiedStatus') {
 				this._everModified = this._everModified || (e.state === 'true');
+
+				// Fire an event to let the client know whether the document needs saving or not.
+				this.fire('postMessage', {msgId: 'Doc_ModifiedStatus', args: { Modified: e.state === 'true' }});
+			}
 		}, this);
 
 		this.on('docloaded', function(e) {
diff --git a/test/data/empty.odt b/test/data/empty.odt
index 208d2f874..6b0747507 100644
Binary files a/test/data/empty.odt and b/test/data/empty.odt differ
commit 3dcc68e6f12a1b0d2e1c586a6d4c8ccdfeb8a15b
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Sun Jun 16 14:42:11 2019 -0400
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    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 bd62fddeb..d89a1a98f 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 0dc2286c5..3e47008f2 100644
--- a/loleaflet/reference.html
+++ b/loleaflet/reference.html
@@ -2938,6 +2938,7 @@ Editor to WOPI host
 		    <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
@@ -2946,10 +2947,16 @@ Editor to WOPI host
 		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 f4ffa86f3..b57bb7dc4 100644
--- a/loleaflet/src/control/Toolbar.js
+++ b/loleaflet/src/control/Toolbar.js
@@ -144,10 +144,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 cd3a5ace0..8891866de 100644
--- a/loleaflet/src/map/handler/Map.WOPI.js
+++ b/loleaflet/src/map/handler/Map.WOPI.js
@@ -320,9 +320,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 c1f84ffee..baaa177d9 100644
--- a/wsd/ClientSession.cpp
+++ b/wsd/ClientSession.cpp
@@ -521,7 +521,14 @@ bool ClientSession::_handleInput(const char *buffer, int length)
             if (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")
@@ -749,7 +756,7 @@ bool ClientSession::loadDocument(const char* /*buffer*/, int /*length*/,
         {
             std::string encodedUserExtraInfo;
             Poco::URI::encode(getUserExtraInfo(), "", encodedUserExtraInfo);
-            oss << " authorextrainfo=" << encodedUserExtraInfo; //TODO: could this include user-data?
+            oss << " authorextrainfo=" << encodedUserExtraInfo; //TODO: could this include PII?
         }
 
         oss << " readonly=" << isReadOnly();
diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp
index 046f916cb..dffe5ea7f 100644
--- a/wsd/DocumentBroker.cpp
+++ b/wsd/DocumentBroker.cpp
@@ -1101,7 +1101,8 @@ bool DocumentBroker::autoSave(const bool force, const bool dontSaveIfUnmodified)
 }
 
 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();
 
@@ -1145,6 +1146,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 d3bdaa6d9..576906d9e 100644
--- a/wsd/DocumentBroker.hpp
+++ b/wsd/DocumentBroker.hpp
@@ -363,7 +363,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 e4b4e1029..db82d913a 100644
--- a/wsd/Storage.cpp
+++ b/wsd/Storage.cpp
@@ -720,6 +720,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 06887c657..21eee8dab 100644
--- a/wsd/Storage.hpp
+++ b/wsd/Storage.hpp
@@ -180,6 +180,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; }
 
@@ -212,6 +213,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;
@@ -229,6 +233,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;
commit 5ff0a42b94bc06723a2e592b649c28717c88512f
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Sun Jun 16 14:16:06 2019 -0400
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    leaflet: Support notifying the client on Action_SaveAs completion
    
    Clients expect a consistent notification API for Action_Save
    and Action_SaveAs. Unfortunately, Action_SaveAs didn't
    support notifying the client as Action_Save does.
    
    Now, when Notify is set to true in the Action_SaveAs
    message, the client will be notified with Action_Save_Resp.
    
    Change-Id: Ib8eb946c3bc642cfd46124e1190e931c21f88de0
    Reviewed-on: https://gerrit.libreoffice.org/74134
    Reviewed-by: Andras Timar <andras.timar at collabora.com>
    Tested-by: Andras Timar <andras.timar at collabora.com>

diff --git a/loleaflet/reference.html b/loleaflet/reference.html
index 2d797b10a..0dc2286c5 100644
--- a/loleaflet/reference.html
+++ b/loleaflet/reference.html
@@ -2956,9 +2956,13 @@ Editor to WOPI host
 		<td><code><b>Action_SaveAs</b></code></td>
 		<td><code>
 		    <nobr>Filename: <String></nobr>
+		    <nobr>Notify: <boolean></nobr>
 		</code></td>
 		<td>Creates copy of the document with given Filename.<br/>
 		<code>Filename</code> is the requested filename for the new file.<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.
 		</td>
 	</tr>
 	<tr>
diff --git a/loleaflet/src/core/Socket.js b/loleaflet/src/core/Socket.js
index c4ba559d1..2b24ab49d 100644
--- a/loleaflet/src/core/Socket.js
+++ b/loleaflet/src/core/Socket.js
@@ -680,6 +680,12 @@ L.Socket = L.Class.extend({
 						}
 					});
 				}
+
+				// Issue the save response to be consistent with normal save.
+				var postMessageObj = {
+					success: true
+				};
+				this._map.fire('postMessage', {msgId: 'Action_Save_Resp', args: postMessageObj});
 			}
 			// var name = command.name; - ignored, we get the new name via the wopi's BaseFileName
 		}
diff --git a/loleaflet/src/map/handler/Map.WOPI.js b/loleaflet/src/map/handler/Map.WOPI.js
index 200730c30..cd3a5ace0 100644
--- a/loleaflet/src/map/handler/Map.WOPI.js
+++ b/loleaflet/src/map/handler/Map.WOPI.js
@@ -366,6 +366,7 @@ L.Map.WOPI = L.Handler.extend({
 		else if (msg.MessageId === 'Action_SaveAs') {
 			if (msg.Values) {
 				if (msg.Values.Filename !== null && msg.Values.Filename !== undefined) {
+					this._notifySave = msg.Values['Notify'];
 					this._map.showBusy(_('Creating copy...'), false);
 					this._map.saveAs(msg.Values.Filename);
 				}
commit d80fdefcbeafd28e22b3256281d9ec54bbeac93d
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Sun Jun 16 14:05:33 2019 -0400
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    wsd: don't use DocBrokers marked to be destroyed
    
    There are cases when we do get client-requests
    while we are about to unload and destroy
    the DocBroker. This protects against the use
    of partially-destroyed DocBroker (specifically,
    when TileCache is already destroyed).
    
    Change-Id: I963f2239fd62280e70b1938d3c6f653e8af91b1e
    Reviewed-on: https://gerrit.libreoffice.org/74132
    Reviewed-by: Andras Timar <andras.timar at collabora.com>
    Tested-by: Andras Timar <andras.timar at collabora.com>

diff --git a/wsd/ClientSession.cpp b/wsd/ClientSession.cpp
index 2623f3585..c1f84ffee 100644
--- a/wsd/ClientSession.cpp
+++ b/wsd/ClientSession.cpp
@@ -316,9 +316,9 @@ bool ClientSession::_handleInput(const char *buffer, int length)
     const std::vector<std::string> tokens = LOOLProtocol::tokenize(firstLine.data(), firstLine.size());
 
     std::shared_ptr<DocumentBroker> docBroker = getDocumentBroker();
-    if (!docBroker)
+    if (!docBroker || docBroker->isMarkedToDestroy())
     {
-        LOG_ERR("No DocBroker found. Terminating session " << getName());
+        LOG_ERR("No DocBroker found, or DocBroker marked to be destroyed. Terminating session " << getName());
         return false;
     }
 
commit 4dc312f5492c75d4afdc6e333dd4d85079e84dfc
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Sun Jun 16 13:28:58 2019 -0400
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    Cleanup framed.doc.html sample
    
    Now Host_PostmessageReady is automatically issued
    upon loading and the postMessage calls are more modular,
    allowing for expansion with more functionality.
    
    Change-Id: I22b50f7228e0fd32c4cb880f4981c1a455038d48
    Reviewed-on: https://gerrit.libreoffice.org/74129
    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 1dfe7f27b..bd62fddeb 100644
--- a/loleaflet/html/framed.doc.html
+++ b/loleaflet/html/framed.doc.html
@@ -10,9 +10,9 @@
 
      To test this, do 'make run', and then in your browser open the
      equivalent of
-     http://snorken.local:9980/loleaflet/3304e9093/framed.html if the
+     http://snorken.local:9980/loleaflet/3304e9093/framed.doc.html if the
      browser is running on a different machine, or
-     http://localhost:9980/loleaflet/3304e9093/framed.html if running
+     http://localhost:9980/loleaflet/3304e9093/framed.doc.html if running
      on the same machine.
 
 -->
@@ -24,26 +24,26 @@
 
     <script>
 
+      function post(msg) {
+        window.frames[0].postMessage(JSON.stringify(msg), '*');
+      }
+
       function insertText(text) {
-        window.frames[0].postMessage(JSON.stringify({'MessageId': 'Host_PostmessageReady'}), '*');
-        window.frames[0].postMessage(JSON.stringify({'MessageId': 'CallPythonScript',
-                                                     'SendTime': Date.now(),
-                                                     'ScriptFile': 'InsertText.py',
-                                                     'Function': 'InsertText',
-                                                     'Values': { 'text': {'type': 'string', 'value': text}}
-                                                     }),
-                                     '*');
+        post({'MessageId': 'CallPythonScript',
+              'SendTime': Date.now(),
+              'ScriptFile': 'InsertText.py',
+              'Function': 'InsertText',
+              'Values': { 'text': {'type': 'string', 'value': text}}
+            });
       }
 
       function capitalize() {
-        window.frames[0].postMessage(JSON.stringify({'MessageId': 'Host_PostmessageReady'}), '*');
-        window.frames[0].postMessage(JSON.stringify({'MessageId': 'CallPythonScript',
-                                                     'SendTime': Date.now(),
-                                                     'ScriptFile': 'Capitalise.py',
-                                                     'Function': 'capitalisePython',
-                                                     'Values': null
-                                                     }),
-                                     '*');
+        post({'MessageId': 'CallPythonScript',
+              'SendTime': Date.now(),
+              'ScriptFile': 'Capitalise.py',
+              'Function': 'capitalisePython',
+              'Values': null
+            });
       }
 
       function save() {
@@ -85,9 +85,15 @@
       // This function is invoked when the iframe posts a message back.
 
       function receiveMessage(event) {
+        console.log('==== framed.doc.html receiveMessage: ' + event.data);
         var msg = JSON.parse(event.data);
-        console.log('==== framed.html receiveMessage: ' + event.data);
-        console.log('                                 ' + msg);
+        if (msg && msg.MessageId == 'App_LoadingStatus') {
+          if (msg.Values) {
+            if (msg.Values.Status == 'Document_Loaded') {
+              window.frames[0].postMessage(JSON.stringify({'MessageId': 'Host_PostmessageReady'}), '*');
+            }
+          }
+        }
       }
 
       // 'main' code of this <script> block, run when page is being
commit df6cc01c325f215ba90afe7665365d269c582fd1
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Sun Jun 16 13:16:20 2019 -0400
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    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 5501d5df6..1dfe7f27b 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) {
@@ -109,6 +115,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/reference.html b/loleaflet/reference.html
index e6a0b448f..2d797b10a 100644
--- a/loleaflet/reference.html
+++ b/loleaflet/reference.html
@@ -3277,6 +3277,47 @@ Editor to WOPI host
 			<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>
 
 <h5><a name="toolbar-button-ids">Finding toolbar button IDs</a></h5>
diff --git a/loleaflet/src/control/Control.Menubar.js b/loleaflet/src/control/Control.Menubar.js
index f711e5aec..3c4296565 100644
--- a/loleaflet/src/control/Control.Menubar.js
+++ b/loleaflet/src/control/Control.Menubar.js
@@ -767,7 +767,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') {
@@ -832,7 +835,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');
 		} else if (!window.ThisIsAMobileApp && id === 'warn-copy-paste') {
diff --git a/loleaflet/src/control/Control.Toolbar.js b/loleaflet/src/control/Control.Toolbar.js
index de4b5fcb1..7b3343156 100644
--- a/loleaflet/src/control/Control.Toolbar.js
+++ b/loleaflet/src/control/Control.Toolbar.js
@@ -141,7 +141,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');
@@ -303,7 +306,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
@@ -2295,7 +2300,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/src/layer/tile/TileLayer.js b/loleaflet/src/layer/tile/TileLayer.js
index 95b489b84..6851333c5 100644
--- a/loleaflet/src/layer/tile/TileLayer.js
+++ b/loleaflet/src/layer/tile/TileLayer.js
@@ -540,7 +540,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();
+				}
 			}
 		}
 	},
diff --git a/loleaflet/src/map/Map.js b/loleaflet/src/map/Map.js
index e176e0d10..0b8a00c3b 100644
--- a/loleaflet/src/map/Map.js
+++ b/loleaflet/src/map/Map.js
@@ -107,6 +107,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.
 
 		this.callInitHooks();
 
diff --git a/loleaflet/src/map/handler/Map.Keyboard.js b/loleaflet/src/map/handler/Map.Keyboard.js
index 8097f9c74..b9456b9fa 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 7cc9f7241..200730c30 100644
--- a/loleaflet/src/map/handler/Map.WOPI.js
+++ b/loleaflet/src/map/handler/Map.WOPI.js
@@ -269,6 +269,17 @@ 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) {
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 0852f62f5650f6c07e6fbd90040bf5b9176e6cb3
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Sat Jun 15 20:58:49 2019 -0400
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    leaflet: support Action_Close
    
    This allows for clients to issue a document
    close programmatically, which is useful when they
    have custom buttons or commands, or external
    events/triggers, that might result in cleanly
    closing the document.
    
    A demo of how to use it is included in framed.doc.html.
    
    Change-Id: Ib889bb01bbcaaa91fd0f341c989aeb1a6fceec28
    Reviewed-on: https://gerrit.libreoffice.org/74131
    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 93c606cdc..5501d5df6 100644
--- a/loleaflet/html/framed.doc.html
+++ b/loleaflet/html/framed.doc.html
@@ -52,6 +52,12 @@
             });
       }
 
+      function closeDocument() {
+        post({'MessageId': 'Action_Close',
+              'Values': null
+            });
+      }
+
       function hide_commands(id) {
         post({'MessageId': 'Hide_Menu_Item',
               'Values': { 'id': id, }
@@ -97,7 +103,8 @@
 
     <form id="insert-text-form">
       Click <button onclick="capitalize(); return false;">here</button> to capitalize selected text in the document.</br></br>
-      <button onclick="save(); return false;">Save</button></br></br>
+      <button onclick="save(); return false;">Save</button>
+      <button onclick="closeDocument(); return false;">Close</button></br></br>
       <button onclick="hide_commands('save'); return false;">Hide Save Commands</button>
       <button onclick="show_commands('save'); return false;">Show Save Commands</button></br>
       <button onclick="hide_commands('print'); return false;">Hide Print Commands</button>
diff --git a/loleaflet/reference.html b/loleaflet/reference.html
index 686c2854b..e6a0b448f 100644
--- a/loleaflet/reference.html
+++ b/loleaflet/reference.html
@@ -2973,6 +2973,14 @@ Editor to WOPI host
 		</td>
 	</tr>
 	<tr>
+		<td><code><b>Action_Close</b></code></td>
+		<td><code>
+		</code></td>
+		<td>
+		Closes the document.
+		</td>
+	</tr>
+	<tr>
 		<td><code><b>Action_Print</b></code></td>
 		<td><code>
 		</code></td>
diff --git a/loleaflet/src/map/handler/Map.WOPI.js b/loleaflet/src/map/handler/Map.WOPI.js
index e8c591b9f..7cc9f7241 100644
--- a/loleaflet/src/map/handler/Map.WOPI.js
+++ b/loleaflet/src/map/handler/Map.WOPI.js
@@ -313,6 +313,9 @@ L.Map.WOPI = L.Handler.extend({
 
 			this._map.save(dontTerminateEdit, dontSaveIfUnmodified);
 		}
+		else if (msg.MessageId === 'Action_Close') {
+			this._map.remove();
+		}
 		else if (msg.MessageId === 'Action_Print') {
 			this._map.print();
 		}
commit 89ae4278e849cd950f7df984e69715649dc724fb
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Sat Jun 15 20:56:28 2019 -0400
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    leaflet: show/hide commands demo
    
    This demonstrates the use of show and hide
    functionality via Show/Hide_Button and
    Show/Hide_Menu_Item postMessage events.
    
    Save and Print buttons and menu items are
    controlled in the demo.
    
    Change-Id: I81dfea816765da50a1c20699b460765ae35f60a6
    Reviewed-on: https://gerrit.libreoffice.org/74130
    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 8fa875db4..93c606cdc 100644
--- a/loleaflet/html/framed.doc.html
+++ b/loleaflet/html/framed.doc.html
@@ -46,6 +46,30 @@
                                      '*');
       }
 
+      function save() {
+        post({'MessageId': 'Action_Save',
+              'Values': { 'Notify': true, }
+            });
+      }
+
+      function hide_commands(id) {
+        post({'MessageId': 'Hide_Menu_Item',
+              'Values': { 'id': id, }
+            });
+        post({'MessageId': 'Hide_Button',
+              'Values': { 'id': id, }
+            });
+      }
+
+      function show_commands(id) {
+        post({'MessageId': 'Show_Menu_Item',
+              'Values': { 'id': id, }
+            });
+        post({'MessageId': 'Show_Button',
+              'Values': { 'id': id, }
+            });
+      }
+
       // This function is invoked when the iframe posts a message back.
 
       function receiveMessage(event) {
@@ -72,7 +96,12 @@
     </form>
 
     <form id="insert-text-form">
-      Click <button onclick="capitalize(); return false;">here</button> to capitalize selected text in the document:
+      Click <button onclick="capitalize(); return false;">here</button> to capitalize selected text in the document.</br></br>
+      <button onclick="save(); return false;">Save</button></br></br>
+      <button onclick="hide_commands('save'); return false;">Hide Save Commands</button>
+      <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>
     </form>
 
     <!-- The hostname and pathnames below are obviously specific to my
commit f454b240ec26cd117e4a96212a493d05768e394b
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Fri Jun 14 06:05:46 2019 -0400
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    Alow to modify UI before WOPIPostmessageReady
    
    Since UI customization doesn't depend on
    the document being fully loaded, while at
    the same time we wouldn't want to display
    misleading/incomplete UI while the document
    loads, only to change it right after.
    
    Change-Id: Ib8178a1d0033659cbeb79bd4827b528e13890095
    Reviewed-on: https://gerrit.libreoffice.org/74133
    Reviewed-by: Andras Timar <andras.timar at collabora.com>
    Tested-by: Andras Timar <andras.timar at collabora.com>

diff --git a/loleaflet/src/map/handler/Map.WOPI.js b/loleaflet/src/map/handler/Map.WOPI.js
index c2783b2f7..e8c591b9f 100644
--- a/loleaflet/src/map/handler/Map.WOPI.js
+++ b/loleaflet/src/map/handler/Map.WOPI.js
@@ -142,7 +142,7 @@ L.Map.WOPI = L.Handler.extend({
 	},
 
 	_postMessageListener: function(e) {
-		if (!window.WOPIPostmessageReady || (e.origin !== window.parent.origin)) {
+		if (e.origin !== window.parent.origin) {
 			return;
 		}
 
@@ -154,29 +154,81 @@ L.Map.WOPI = L.Handler.extend({
 			return;
 		}
 
-		if (msg.MessageId === 'Host_PostmessageReady') {
-			// We already have a listener for this in loleaflet.html, so ignore it here
-			return;
-		}
-
-		if (msg.MessageId === 'Grab_Focus') {
-			this._map.makeActive();
-			return;
-		}
-
 		// allow closing documents before they are completely loaded
 		if (msg.MessageId === 'Close_Session') {
 			this._map._socket.sendMessage('closedocument');
 			return;
 		}
 
-		// For all other messages, warn if trying to interact before we are completely loaded
-		if (!this._appLoaded) {
-			console.error('LibreOffice Online not loaded yet. Listen for App_LoadingStatus (Document_Loaded) event before using PostMessage API. Ignoring post message \'' + msg.MessageId + '\'.');
-			return;
+		// Exception: UI modification can be done before WOPIPostmessageReady was fullfiled
+		if (msg.MessageId === 'Show_Button' || msg.MessageId === 'Hide_Button' || msg.MessageId === 'Remove_Button') {
+			if (!msg.Values) {
+				console.error('Property "Values" not set');
+				return;
+			}
+			if (!msg.Values.id) {
+				console.error('Property "Values.id" not set');
+				return;
+			}
+			var toolbar = w2ui['editbar'];
+			if (!toolbar || !toolbar.get(msg.Values.id)) {
+				console.error('Toolbar button with id "' + msg.Values.id + '" not found.');
+				return;
+			}
+			if (msg.MessageId === 'Show_Button') {
+				toolbar.show(msg.Values.id);
+			} else {
+				toolbar.hide(msg.Values.id);
+			}
+		}
+		else if (msg.MessageId === 'Remove_Statusbar_Element') {
+			if (!msg.Values) {
+				console.error('Property "Values" not set');
+				return;
+			}
+			if (!msg.Values.id) {
+				console.error('Property "Values.id" not set');
+				return;
+			}
+			if (!w2ui['actionbar'].get(msg.Values.id)) {
+				console.error('Statusbar element with id "' + msg.Values.id + '" not found.');
+				return;
+			}
+			w2ui['actionbar'].remove(msg.Values.id);
+		}
+		else if (msg.MessageId === 'Show_Menubar') {
+			this._map.showMenubar();
+		}
+		else if (msg.MessageId === 'Hide_Menubar') {
+			this._map.hideMenubar();
+		}
+		else if (msg.MessageId === 'Show_Ruler') {
+			this._map.showRuler();
 		}
+		else if (msg.MessageId === 'Hide_Ruler') {
+			this._map.hideRuler();
+		}
+		else if (msg.MessageId === 'Show_Menu_Item' || msg.MessageId === 'Hide_Menu_Item') {
+			if (!msg.Values) {
+				console.error('Property "Values" not set');
+				return;
+			}
+			if (!msg.Values.id) {
+				console.error('Property "Values.id" not set');
+				return;
+			}
+			if (!this._map.menubar || !this._map.menubar.hasItem(msg.Values.id)) {
+				console.error('Menu item with id "' + msg.Values.id + '" not found.');
+				return;
+			}
 
-		if (msg.MessageId === 'Insert_Button') {
+			if (msg.MessageId === 'Show_Menu_Item') {
+				this._map.menubar.showItem(msg.Values.id);
+			} else {
+				this._map.menubar.hideItem(msg.Values.id);
+			}
+		}
+		else if (msg.MessageId === 'Insert_Button') {
 			if (msg.Values) {
 				if (msg.Values.id && !w2ui['editbar'].get(msg.Values.id)
 				    && msg.Values.imgurl) {
@@ -217,59 +269,35 @@ L.Map.WOPI = L.Handler.extend({
 				}
 			}
 		}
-		if (msg.MessageId === 'Show_Button' || msg.MessageId === 'Hide_Button' || msg.MessageId === 'Remove_Button') {
-			if (!msg.Values) {
-				console.error('Property "Values" not set');
-				return;
-			}
-			if (!msg.Values.id) {
-				console.error('Property "Values.id" not set');
-				return;
-			}
-			if (this._map._permission !== 'edit') {
-				console.log('No toolbar in readonly mode - ignoring request.');
-				return;
-			}
-			if (!w2ui['editbar'].get(msg.Values.id)) {
-				console.error('Toolbar button with id "' + msg.Values.id + '" not found.');
-				return;
-			}
-			if (msg.MessageId === 'Show_Button') {
-				w2ui['editbar'].show(msg.Values.id);
-			} else if (msg.MessageId === 'Hide_Button') {
-				w2ui['editbar'].hide(msg.Values.id);
-			} else {
-				w2ui['editbar'].remove(msg.Values.id);
-			}
-		}
-		if (msg.MessageId === 'Remove_Statusbar_Element') {
-			if (!msg.Values) {
-				console.error('Property "Values" not set');
-				return;
-			}
-			if (!msg.Values.id) {
-				console.error('Property "Values.id" not set');
-				return;
-			}
-			if (!w2ui['actionbar'].get(msg.Values.id)) {
-				console.error('Statusbar element with id "' + msg.Values.id + '" not found.');
-				return;
-			}
-			w2ui['actionbar'].remove(msg.Values.id);
+
+		// All following actions must be done after initialization is completed.
+		if (!window.WOPIPostmessageReady) {
+			return;
 		}
-		else if (msg.MessageId === 'Show_Menubar') {
-			this._map.showMenubar();
+
+		if (msg.MessageId === 'Host_PostmessageReady') {
+			// We already have a listener for this in loleaflet.html, so ignore it here
+			return;
 		}
-		else if (msg.MessageId === 'Hide_Menubar') {
-			this._map.hideMenubar();
+
+		if (msg.MessageId === 'Grab_Focus') {
+			this._map.makeActive();
+			return;
 		}
-		else if (msg.MessageId === 'Show_Ruler') {
-			this._map.showRuler();
+
+		// allow closing documents before they are completely loaded
+		if (msg.MessageId === 'Close_Session') {
+			this._map._socket.sendMessage('closedocument');
+			return;
 		}
-		else if (msg.MessageId === 'Hide_Ruler') {
-			this._map.hideRuler();
+
+		// For all other messages, warn if trying to interact before we are completely loaded
+		if (!this._appLoaded) {
+			console.error('LibreOffice Online not loaded yet. Listen for App_LoadingStatus (Document_Loaded) event before using PostMessage API. Ignoring post message \'' + msg.MessageId + '\'.');
+			return;
 		}
-		else if (msg.MessageId === 'Set_Settings') {
+
+		if (msg.MessageId === 'Set_Settings') {
 			if (msg.Values) {
 				var alwaysActive = msg.Values.AlwaysActive;
 				this._map.options.alwaysActive = !!alwaysActive;
commit 7b86174eb85a9cda82247895d026a39c3013e8cd
Author:     Szymon Kłos <szymon.klos at collabora.com>
AuthorDate: Thu Jun 6 17:51:48 2019 +0200
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    Add API to remove menu items
    
    Reviewed-on: https://gerrit.libreoffice.org/74128
    Reviewed-by: Andras Timar <andras.timar at collabora.com>
    Tested-by: Andras Timar <andras.timar at collabora.com>
    (cherry picked from commit 16ba97e7ae4a06932bdd63dbf32dd9e09b6b227e)
    Reviewed-on: https://gerrit.libreoffice.org/75228
    (cherry picked from commit 5105f3b95117c88d91a882fb4fef5356b5e45e68)
    
    Change-Id: I59f2e3e1ed467f58bcd56db945e0d4807c1cff6e

diff --git a/loleaflet/reference.html b/loleaflet/reference.html
index 4b3b9a53a..686c2854b 100644
--- a/loleaflet/reference.html
+++ b/loleaflet/reference.html
@@ -3241,12 +3241,34 @@ Editor to WOPI host
 			<code><nobr>id: <string></nobr></code>
 		</td>
 		<td>
-			Hides a button from the toolbar.<br/>
+			Shows a button from the toolbar.<br/>
 			<code>id</code> is the button ID as defined in the
 			<a href="https://opengrok.libreoffice.org/search?project=online&q=&defs=createToolbar">createToolbar</a>
 			function in <a href="https://opengrok.libreoffice.org/xref/online/loleaflet/js/toolbar.js">loleaflet/js/toolbar.js</a>.
 		</td>
 	</tr>
+	<tr>
+		<td><code><b>Hide_Menu_Item</b></code></td>
+		<td>
+			<code><nobr>id: <string></nobr></code>
+		</td>
+		<td>
+			Hides an item from the menu.<br/>
+			<code>id</code> is the item ID as defined in the
+			<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>Show_Menu_Item</b></code></td>
+		<td>
+			<code><nobr>id: <string></nobr></code>
+		</td>
+		<td>
+			Shows an item from the menu.<br/>
+			<code>id</code> is the item ID as defined in the
+			<a href="https://opengrok.libreoffice.org/xref/online/loleaflet/src/control/Control.Menubar.js">loleaflet/src/control/Control.Menubar.js</a>.
+		</td>
+	</tr>
 </table>
 
 <h5><a name="toolbar-button-ids">Finding toolbar button IDs</a></h5>
diff --git a/loleaflet/src/control/Control.Menubar.js b/loleaflet/src/control/Control.Menubar.js
index 3057f5d95..f711e5aec 100644
--- a/loleaflet/src/control/Control.Menubar.js
+++ b/loleaflet/src/control/Control.Menubar.js
@@ -1062,6 +1062,39 @@ L.Control.Menubar = L.Control.extend({
 		return itemList;
 	},
 
+	_getItems: function() {
+		return $(this._menubarCont).children().children('ul').children('li').add($(this._menubarCont).children('li'));
+	},
+
+	_getItem: function(targetId) {
+		var items = this._getItems();
+		var found = $(items).filter(function() {
+			var item = this;
+			var id = $(item).attr('id');
+			if (id && id == 'menu-' + targetId) {
+				return true;
+			}
+			return false
+		});
+		return found.length ? found : null;
+	},
+
+	hasItem: function(targetId) {
+		return this._getItem(targetId) != null;
+	},
+
+	hideItem: function(targetId) {
+		var item = this._getItem(targetId);
+		if (item)
+			$(item).css('display', 'none');
+	},
+
+	showItem: function(targetId) {
+		var item = this._getItem(targetId);
+		if (item)
+			$(item).css('display', '');
+	},
+
 	_initializeMenu: function(menu) {
 		var menuHtml = this._createMenu(menu);
 		for (var i in menuHtml) {
diff --git a/loleaflet/src/main.js b/loleaflet/src/main.js
index 7e59effb5..1b847bb5e 100644
--- a/loleaflet/src/main.js
+++ b/loleaflet/src/main.js
@@ -72,7 +72,9 @@ var map = L.map('map', {
 });
 
 ////// Controls /////
-map.addControl(L.control.menubar());
+var menubar = L.control.menubar();
+map.menubar = menubar;
+map.addControl(menubar);
 setupToolbar(map);
 map.addControl(L.control.scroll());
 map.addControl(L.control.alertDialog());
commit 9783d70520d4ee9e83b402771c9caacf4d9cd96c
Author:     Jan Holesovsky <kendy at collabora.com>
AuthorDate: Mon Jun 3 14:25:30 2019 +0200
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    Show the state of the Delete Slide.
    
    When there is only one slide, it cannot be deleted.  Use the information
    from the core to enable or disable the state of the "Delete Slide"
    button in the slide sorter and the menu entry.
    
    Reviewed-on: https://gerrit.libreoffice.org/73383
    Reviewed-by: Szymon Kłos <szymon.klos at collabora.com>
    Tested-by: Szymon Kłos <szymon.klos at collabora.com>
    (cherry picked from commit 3a1f68dc84dddf252cdd222ab14b2a4635f39251)
    Reviewed-on: https://gerrit.libreoffice.org/73863
    Reviewed-by: Andras Timar <andras.timar at collabora.com>
    Tested-by: Andras Timar <andras.timar at collabora.com>
    
    Change-Id: I549d4c09b6fd999b14e281976320d1b6f63d64b7

diff --git a/loleaflet/src/control/Control.Menubar.js b/loleaflet/src/control/Control.Menubar.js
index 2e0f2e348..3057f5d95 100644
--- a/loleaflet/src/control/Control.Menubar.js
+++ b/loleaflet/src/control/Control.Menubar.js
@@ -725,6 +725,20 @@ L.Control.Menubar = L.Control.extend({
 						} else {
 							$(aItem).removeClass(constChecked);
 						}
+
+					} else if (self._map.getDocType() === 'presentation' && (id === 'deletepage' || id === 'insertpage' || id === 'duplicatepage')) {
+						if (id === 'deletepage') {
+							itemState = self._map['stateChangeHandler'].getItemValue('.uno:DeletePage');
+						} else if (id === 'insertpage') {
+							itemState = self._map['stateChangeHandler'].getItemValue('.uno:InsertPage');
+						} else {
+							itemState = self._map['stateChangeHandler'].getItemValue('.uno:DuplicatePage');
+						}
+						if (itemState === 'disabled') {
+							$(aItem).addClass('disabled');
+						} else {
+							$(aItem).removeClass('disabled');
+						}
 					} else {
 						$(aItem).removeClass('disabled');
 					}
diff --git a/loleaflet/src/control/Control.Toolbar.js b/loleaflet/src/control/Control.Toolbar.js
index 948b85b0d..de4b5fcb1 100644
--- a/loleaflet/src/control/Control.Toolbar.js
+++ b/loleaflet/src/control/Control.Toolbar.js
@@ -1732,6 +1732,9 @@ function onCommandStateChanged(e) {
 		if (_inMobileMode()) {
 			toolbarUp = statusbar;
 		}
+		if (map.getDocType() === 'presentation' && (id === 'deletepage' || id === 'insertpage' || id === 'duplicatepage')) {
+			toolbarUp = w2ui['presentation-toolbar'];
+		}
 		if (state === 'enabled') {
 			toolbarUp.enable(id);
 		} else {
@@ -1998,6 +2001,24 @@ function onUpdatePermission(e) {
 			});
 		}
 
+		presentationButtons.forEach(function(id) {
+			if (id === 'deletepage') {
+				var itemState = map['stateChangeHandler'].getItemValue('.uno:DeletePage');
+			} else if (id === 'insertpage') {
+				itemState = map['stateChangeHandler'].getItemValue('.uno:InsertPage');
+			} else if (id === 'duplicatepage') {
+				itemState = map['stateChangeHandler'].getItemValue('.uno:DuplicatePage');
+			} else {
+				itemState = 'enabled';
+			}
+
+			if (itemState === 'enabled') {
+				toolbar.enable(id);
+			} else {
+				toolbar.disable(id);
+			}
+		});
+
 		toolbar = w2ui['actionbar'];
 		if (toolbar) {
 			toolbarDownButtons.forEach(function(id) {
commit 11f5154432eef8e067efb140e329dba0a47afd3d
Author:     Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>
AuthorDate: Thu Nov 29 09:32:56 2018 +0100
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    Add postMessage methods to show/hide toolbar buttons
    
    (cherry picked from commit c0d0ad736839260667c98aa0cf08feb5630e0b87)
    
    Change-Id: Ib5ecde5a53aa0aae2346e360423e72025edade3a

diff --git a/loleaflet/reference.html b/loleaflet/reference.html
index 1d8b8ba83..4b3b9a53a 100644
--- a/loleaflet/reference.html
+++ b/loleaflet/reference.html
@@ -3223,6 +3223,30 @@ Editor to WOPI host
 			Shows the horizontal document ruler (Writer only)
 		</td>
 	</tr>
+	<tr>
+		<td><code><b>Hide_Button</b></code></td>
+		<td>
+			<code><nobr>id: <string></nobr></code>
+		</td>
+		<td>
+			Hides a button from the toolbar.<br/>
+		    <code>id</code> is the button ID as defined in the
+		    <a href="https://opengrok.libreoffice.org/search?project=online&q=&defs=createToolbar">createToolbar</a>
+		    function in <a href="https://opengrok.libreoffice.org/xref/online/loleaflet/js/toolbar.js">loleaflet/js/toolbar.js</a>.
+		</td>
+	</tr>
+	<tr>
+		<td><code><b>Show_Button</b></code></td>
+		<td>
+			<code><nobr>id: <string></nobr></code>
+		</td>
+		<td>
+			Hides a button from the toolbar.<br/>
+			<code>id</code> is the button ID as defined in the
+			<a href="https://opengrok.libreoffice.org/search?project=online&q=&defs=createToolbar">createToolbar</a>
+			function in <a href="https://opengrok.libreoffice.org/xref/online/loleaflet/js/toolbar.js">loleaflet/js/toolbar.js</a>.
+		</td>
+	</tr>
 </table>
 
 <h5><a name="toolbar-button-ids">Finding toolbar button IDs</a></h5>
commit 30cc128690119114e4b2b92c83f69d6e133623b7
Author:     Florin Ciornei <florin.ciornei at collabora.com>
AuthorDate: Tue May 14 16:13:08 2019 +0200
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    Open/close sidebar on swipe
    
    Change-Id: I91e3889375b833c656cf81f2dc4094b1d3f13ea5
    Reviewed-on: https://gerrit.libreoffice.org/72354
    Reviewed-by: Jan Holesovsky <kendy at collabora.com>
    Tested-by: Jan Holesovsky <kendy at collabora.com>
    (cherry picked from commit 0fb53bb1a8487171acba1b08c720c5cdb75855c3)

diff --git a/loleaflet/src/control/Control.LokDialog.js b/loleaflet/src/control/Control.LokDialog.js
index 4e363f2fc..0dd42476b 100644
--- a/loleaflet/src/control/Control.LokDialog.js
+++ b/loleaflet/src/control/Control.LokDialog.js
@@ -127,6 +127,25 @@ L.Control.LokDialog = L.Control.extend({
 		map.on('closesidebar', this._closeSidebar, this);
 		map.on('editorgotfocus', this._onEditorGotFocus, this);
 		L.DomEvent.on(document, 'mouseup', this.onCloseCurrentPopUp, this);
+
+		this.slideAnimationDuration = 250;//sidebar open animation duration
+
+		//open sidebar on left swipe on document view
+		var documentContainerHammer = new Hammer(document.getElementById('document-container'));
+		documentContainerHammer.on('swipeleft', function (e) {
+			var startX = e.changedPointers[0].clientX - e.deltaX;
+			if (startX < window.screen.width * 0.7)//detect open swipes only near screen edge
+				return;
+			map._socket.sendMessage('uno .uno:Sidebar');
+		})
+
+		//close sidebar on right swipe on sidebar panel, also on document view(for tablets)
+		var sidebarPanelHammer = new Hammer(document.getElementById('sidebar-panel'));
+		[sidebarPanelHammer, documentContainerHammer].forEach(function (hammerElement) {
+			hammerElement.on('swiperight', function () {
+				map._socket.sendMessage('uno .uno:Sidebar');
+			})
+		})
 	},
 
 	_dialogs: {},
@@ -602,6 +621,19 @@ L.Control.LokDialog = L.Control.extend({
 
 		// Render window.
 		this._sendPaintWindowRect(id);
+
+		//play slide from right animation on mobile and tablets
+		if (L.Browser.mobile) {
+			var sidebar = $('#sidebar-dock-wrapper');
+			var bottomBar = $('#toolbar-down');
+			sidebar.css('bottom', '0px');//to take the space occupied by the bottom menu
+			sidebar.css('position', 'fixed');//fixed position in order to prevent scrollbars to appear while opening/closing
+			bottomBar.animate({ 'opacity': 0 }, this.slideAnimationDuration);
+			sidebar.css('margin-right', -width * ratio + 'px').animate({ 'margin-right': '0px' }, this.slideAnimationDuration, function () {
+				$('#toolbar-down').hide();
+				sidebar.css('position', '');
+			});
+		}
 	},
 
 	_setupWindowEvents: function(id, canvas, dlgInput) {
@@ -776,6 +808,22 @@ L.Control.LokDialog = L.Control.extend({
 		this._map.focus();
 		delete this._dialogs[dialogId];
 		this._currentDeck = null;
+
+		//play slide animation to right if this is a mobile or tablet
+		if (L.Browser.mobile) {
+			var sidebar = $('#sidebar-dock-wrapper');
+			var bottomBar = $('#toolbar-down');
+			var sidebarWidth = $('#sidebar-dock-wrapper').width();
+			bottomBar.animate({ 'opacity': 1 }, this.slideAnimationDuration);
+			sidebar.css('position', 'fixed');//fixed position in order to prevent scrollbars to appear while opening/closing
+			sidebar.animate({ 'margin-right': -sidebarWidth + 'px' }, this.slideAnimationDuration, function () {
+				//remove artifacts from the animation
+				sidebar.css('margin-right', '');
+				sidebar.css('display', '');
+				sidebar.css('position', '');
+				$('#toolbar-down').show();
+			});
+		}
 	},
 
 	_onDialogClose: function(dialogId, notifyBackend) {
commit 4df0548d264f09c440c30bfae75785045e51cca7
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Mon May 13 06:50:32 2019 -0400
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    leaflet: update the cursor when the editor gets focus back
    
    After closing dialog that had its own cursor, the editor
    loses the cursor until the user types, which forces a
    cursor invalidation from Core. This is to make sure that
    the editor always updates the visibility of its cursor
    when the editor get focus back.
    
    Change-Id: Icba5e6c2c94da7488131269749fc96e185dec6a2
    (cherry picked from commit 72025d21cb127aadeb092e564da8acc884188032)

diff --git a/loleaflet/src/map/Map.js b/loleaflet/src/map/Map.js
index b1607a7f8..e176e0d10 100644
--- a/loleaflet/src/map/Map.js
+++ b/loleaflet/src/map/Map.js
@@ -862,6 +862,7 @@ L.Map = L.Evented.extend({
 
 	focus: function () {
 		this._clipboardContainer.focus();
+		this._onEditorGotFocus();
 	},
 
 	hasFocus: function () {
commit 6a99e313ec3f348e5af8b5a19ac191d791b3483f
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Sun May 12 16:52:35 2019 -0400
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    leaflet: initialize the sidebar only once
    
    Calc tends to issue document size change very
    frequently (after certain operations), and this
    results in the status: message to be generated.
    Unfortunately, this message signals finishing
    document loading, which means it also triggers
    post-loading events.
    
    This fix is to hold a new flag in map to track
    the true first laod event, to avoid triggering
    post-load handlers.
    
    Ideally, we will get a different and unambiguous
    message for document loading, vs. generic status
    updates.
    
    Change-Id: Ib8b59c04a770cbfcaf443608c418557671ed207b
    (cherry picked from commit c97defd5f65a1bbc69247f74a943b224111f2ca2)

diff --git a/loleaflet/src/map/Map.js b/loleaflet/src/map/Map.js
index ece3a6b37..b1607a7f8 100644
--- a/loleaflet/src/map/Map.js
+++ b/loleaflet/src/map/Map.js
@@ -230,9 +230,13 @@ L.Map = L.Evented.extend({
 		// This becomes true if document was ever modified by the user
 		this._everModified = false;
 
-		// Document is completely loaded or not
+		// Document is completely loaded or not.
 		this._docLoaded = false;
 
+		// Unlike _docLoaded, this is flagged only once,
+		// after we receive status for the first time.
+		this._docLoadedOnce = false;
+
 		this.on('commandstatechanged', function(e) {
 			if (e.commandName === '.uno:ModifiedStatus')
 				this._everModified = this._everModified || (e.state === 'true');
@@ -256,7 +260,7 @@ L.Map = L.Evented.extend({
 			this.initializeModificationIndicator();
 
 			// Show sidebar.
-			if (this._docLayer && !window.mode.isMobile() && !window.mode.isTablet() &&
+			if (this._docLayer && !this._docLoadedOnce && !window.mode.isMobile() && !window.mode.isTablet() &&
 				(this._docLayer._docType === 'spreadsheet' || this._docLayer._docType === 'text')) {
 				// Let the first page finish loading then load the sidebar.
 				var map = this;
@@ -268,6 +272,11 @@ L.Map = L.Evented.extend({
 					map._socket.sendMessage('uno .uno:Sidebar');
 				}, 200);
 			}
+
+			// We have loaded.
+			if (!this._docLoadedOnce) {
+				this._docLoadedOnce = this._docLoaded;
+			}
 		}, this);
 	},
 
commit 5e84467f62fdc35a6a7c72db9fcc75dd63684fbd
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Thu May 9 08:15:14 2019 -0400
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    leaflet: Keep active even in windows and child windows
    
    Change-Id: I7e72b21d9276e96e94852916f9e6a8e04d73c222
    (cherry picked from commit 977858b8720516d50a4e0365dce5d486939427b1)

diff --git a/loleaflet/src/control/Control.LokDialog.js b/loleaflet/src/control/Control.LokDialog.js
index 96af0de39..4e363f2fc 100644
--- a/loleaflet/src/control/Control.LokDialog.js
+++ b/loleaflet/src/control/Control.LokDialog.js
@@ -607,7 +607,6 @@ L.Control.LokDialog = L.Control.extend({
 	_setupWindowEvents: function(id, canvas, dlgInput) {
 		L.DomEvent.on(canvas, 'contextmenu', L.DomEvent.preventDefault);
 		L.DomEvent.on(canvas, 'mousemove', function(e) {
-			this._map.lastActiveTime = Date.now();
 			this._postWindowMouseEvent('move', id, e.offsetX, e.offsetY, 1, 0, 0);
 			// Keep map active while user is playing with sidebar/dialog.
 			this._map.lastActiveTime = Date.now();
@@ -744,23 +743,31 @@ L.Control.LokDialog = L.Control.extend({
 
 	_postWindowCompositionEvent: function(winid, type, text) {
 		this._map._docLayer._postCompositionEvent(winid, type, text);
+		// Keep map active while user is playing with sidebar/dialog.
+		this._map.lastActiveTime = Date.now();
 	},
 
 	_postWindowMouseEvent: function(type, winid, x, y, count, buttons, modifier) {
 		this._map._socket.sendMessage('windowmouse id=' + winid +  ' type=' + type +
 		                              ' x=' + x + ' y=' + y + ' count=' + count +
 		                              ' buttons=' + buttons + ' modifier=' + modifier);
+		// Keep map active while user is playing with sidebar/dialog.
+		this._map.lastActiveTime = Date.now();
 	},
 
 	_postWindowGestureEvent: function(winid, type, x, y, offset) {
 		console.log('x ' + x + ' y ' + y + ' o ' + offset);
 		this._map._socket.sendMessage('windowgesture id=' + winid +  ' type=' + type +
 		                              ' x=' + x + ' y=' + y + ' offset=' + offset);
+		// Keep map active while user is playing with sidebar/dialog.
+		this._map.lastActiveTime = Date.now();
 	},
 
 	_postWindowKeyboardEvent: function(winid, type, charcode, keycode) {
 		this._map._socket.sendMessage('windowkey id=' + winid + ' type=' + type +
 		                              ' char=' + charcode + ' key=' + keycode);
+		// Keep map active while user is playing with sidebar/dialog.
+		this._map.lastActiveTime = Date.now();
 	},
 
 	_onSidebarClose: function(dialogId) {
@@ -992,7 +999,6 @@ L.Control.LokDialog = L.Control.extend({
 				}
 				firstTouchPositionX = null;
 				firstTouchPositionY = null;
-
 			}
 			else if (e.type === 'touchmove')
 			{
commit 076bbc80fa4bc65559937fc03421ac7f4c6537c3
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Tue May 7 20:59:13 2019 -0400
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    leaflet: show message box dialogs centered
    
    Change-Id: Ic55f48067c918aac2bdcfe998c8d4b5cbbcc008d
    (cherry picked from commit 2f0e39b39cc16e4bc3c6157de3ba4b32dba7abf4)

diff --git a/loleaflet/src/control/Control.LokDialog.js b/loleaflet/src/control/Control.LokDialog.js
index 3552d4f0b..96af0de39 100644
--- a/loleaflet/src/control/Control.LokDialog.js
+++ b/loleaflet/src/control/Control.LokDialog.js
@@ -248,8 +248,8 @@ L.Control.LokDialog = L.Control.extend({
 			height = parseInt(e.size.split(',')[1]);
 		}
 
-		var left = 0;
-		var top = 0;
+		var left;
+		var top;
 		if (e.position) {
 			left = parseInt(e.position.split(',')[0]);
 			top = parseInt(e.position.split(',')[1]);
@@ -257,14 +257,19 @@ L.Control.LokDialog = L.Control.extend({
 
 		if (e.action === 'created') {
 			if (e.winType === 'dialog') {
+				// When left/top are invalid, the dialog shows in the center.
 				this._launchDialog(e.id, left, top, width, height, e.title);
 			} else if (e.winType === 'deck') {
-				this._launchSidebar(e.id, left, top, width, height);
+				this._launchSidebar(e.id, width, height);
 			} else if (e.winType === 'child') {
 				var parentId = parseInt(e.parentId);
 				if (!this._isOpen(parentId))
 					return;
 
+				if (!left)
+					left = 0;
+				if (!top)
+					top = 0;
 				this._removeDialogChild(parentId);
 				this._dialogs[parentId].childid = e.id;
 				this._dialogs[parentId].childwidth = width;
@@ -501,12 +506,7 @@ L.Control.LokDialog = L.Control.extend({
 		this._sendPaintWindow(id, this._createRectStr(id));
 	},
 
-	_launchSidebar: function(id, left, top, width, height) {
-
-		if (!left)
-			left = 0;
-		if (!top)
-			top = 0;
+	_launchSidebar: function(id, width, height) {
 
 		if ((window.mode.isMobile() || window.mode.isTablet())
 		    && this._map._permission != 'edit')
@@ -571,8 +571,8 @@ L.Control.LokDialog = L.Control.extend({
 			id: id,
 			strId: strId,
 			isSidebar: true,
-			left: left,
-			top: top,
+			left: 0,
+			top: 0,
 			width: width,
 			height: height,
 			cursor: null,
commit 5fcd8f38beddf0f3c4f13169cf67e9c77e4fa173
Author:     Jan Holesovsky <kendy at collabora.com>
AuthorDate: Tue May 14 14:02:12 2019 +0200
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    Fix build.
    
    Change-Id: Ibfe0d09ca156540f5ec535c6a5da5e9cd339b16d
    (cherry picked from commit b52dd6b14e63ff160524a0f6fe2d3d4e2361d547)

diff --git a/kit/ChildSession.hpp b/kit/ChildSession.hpp
index cbaaba54b..3e32f311d 100644
--- a/kit/ChildSession.hpp
+++ b/kit/ChildSession.hpp
@@ -36,6 +36,8 @@ enum class LokEventTargetEnum
 class DocumentManagerInterface
 {
 public:
+    virtual ~DocumentManagerInterface()  {}
+
     /// Reqest loading a document, or a new view, if one exists.
     virtual bool onLoad(const std::string& sessionId,
                         const std::string& uriAnonym,
commit 7edfa725c19d80e7a54d2aed7b8d694dcbfada7d
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Sat May 4 15:30:11 2019 -0400
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    leaflet: Add sidebar commands in toolbar and menu
    
    Reviewed-on: https://gerrit.libreoffice.org/71840
    Reviewed-by: Jan Holesovsky <kendy at collabora.com>
    Tested-by: Jan Holesovsky <kendy at collabora.com>
    (cherry picked from commit 212290a35dc4e87439e5d4d41b16224281c8d27d)
    
    Change-Id: Icac459849196a70b62ac0e2a558882d8cc199e6c

diff --git a/loleaflet/css/toolbar.css b/loleaflet/css/toolbar.css
index 3ae37ad54..5e63e4140 100644
--- a/loleaflet/css/toolbar.css
+++ b/loleaflet/css/toolbar.css
@@ -617,6 +617,7 @@ button.leaflet-control-search-next
 .w2ui-icon.fullscreen{ background: url('images/lc_fullscreen.svg') no-repeat center !important; }
 .w2ui-icon.closemobile{ background: url('images/lc_closedocmobile.svg') no-repeat center !important; }
 .w2ui-icon.closetoolbar{ background: url('images/close_toolbar.svg') no-repeat center !important; }
+.w2ui-icon.sidebar_modify_page{ background: url('images/lc_formproperties.svg') no-repeat center !important; }
 
 .w2ui-icon.vereign{ background: url('images/vereign.png') no-repeat center !important; }
 
diff --git a/loleaflet/images/lc_formproperties.svg b/loleaflet/images/lc_formproperties.svg
new file mode 100644
index 000000000..75c2b7b52
--- /dev/null
+++ b/loleaflet/images/lc_formproperties.svg
@@ -0,0 +1 @@
+<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m3 6h18v15h-18z" fill="#fff"/><path d="m3 2c-.554 0-1 .446-1 1v18c0 .554.446 1 1 1h18c.554 0 1-.446 1-1v-18c0-.554-.446-1-1-1zm0 4h18v15h-18z" fill="#808080"/><rect fill="#808080" height="1" ry=".5" width="12" x="6" y="11"/><rect fill="#4d82b8" height="1" ry=".5" width="4" x="6" y="15"/><path d="m10.5 14a1.5 1.5 0 0 0 -1.5 1.5 1.5 1.5 0 0 0 1.5 1.5 1.5 1.5 0 0 0 1.5-1.5 1.5 1.5 0 0 0 -1.5-1.5zm0 1a.5.5 0 0 1 .5.5.5.5 0 0 1 -.5.5.5.5 0 0 1 -.5-.5.5.5 0 0 1 .5-.5z" fill="#4d82b8"/><path d="m13.5 10c-.828427 0-1.5.671573-1.5 1.5s.671573 1.5 1.5 1.5 1.5-.671573 1.5-1.5-.671573-1.5-1.5-1.5z" fill="#808080"/><rect fill="#4d82b8" height="1" ry=".491011" width="7" x="11" y="15"/><g fill="#808080"><rect height="1" ry=".5" width="4" x="6" y="15"/><path d="m10.5 14a1.5 1.5 0 0 0 -1.5 1.5 1.5 1.5 0 0 0 1.5 1.5 1.5 1.5 0 0 0 1.5-1.5 1.5 1.5 0 0 0 -1.5-1.5zm0 1a.5.5 0 0 1 .5.5.5.5 0 0 1 -.5.5.5.5 0 0 1 -.5-.5.5.5 0 0 1 .5-.5z"/>
 <rect height="1" ry=".491011" width="7" x="11" y="15"/></g></svg>
\ No newline at end of file
diff --git a/loleaflet/src/control/Control.Menubar.js b/loleaflet/src/control/Control.Menubar.js
index 6d9fcb33b..2e0f2e348 100644
--- a/loleaflet/src/control/Control.Menubar.js
+++ b/loleaflet/src/control/Control.Menubar.js
@@ -66,7 +66,9 @@ L.Control.Menubar = L.Control.extend({
 				{type: 'separator'},
 				{uno: '.uno:ControlCodes'},
 				{type: 'separator'},
-				{name: _UNO('.uno:ShowResolvedAnnotations', 'text'), id: 'showresolved', type: 'action'}
+				{name: _UNO('.uno:ShowResolvedAnnotations', 'text'), id: 'showresolved', type: 'action'},
+				{type: 'separator'},
+				{uno: '.uno:Sidebar'}
 			]
 			},
 			{name: _UNO('.uno:InsertMenu', 'text'), type: 'menu', menu: [
@@ -357,7 +359,9 @@ L.Control.Menubar = L.Control.extend({
 				{uno: '.uno:SearchDialog'}
 			]},
 			{name: _UNO('.uno:ViewMenu', 'spreadsheet'), id: 'view', type: 'menu', mobileapp: false, menu: [
-				{name: _UNO('.uno:FullScreen', 'spreadsheet'), id: 'fullscreen', type: 'action'}
+				{name: _UNO('.uno:FullScreen', 'spreadsheet'), id: 'fullscreen', type: 'action'},
+				{type: 'separator'},
+				{uno: '.uno:Sidebar'}
 			]},
 			{name: _UNO('.uno:InsertMenu', 'spreadsheet'), type: 'menu', menu: [
 				{name: _('Local Image...'), id: 'insertgraphic', type: 'action'},
diff --git a/loleaflet/src/control/Control.Toolbar.js b/loleaflet/src/control/Control.Toolbar.js
index 29e5c2590..948b85b0d 100644
--- a/loleaflet/src/control/Control.Toolbar.js
+++ b/loleaflet/src/control/Control.Toolbar.js
@@ -824,6 +824,8 @@ function initNormalToolbar() {
 		{type: 'button',  id: 'insertsymbol', img: 'insertsymbol', hint: _UNO('.uno:InsertSymbol', '', true), uno: 'InsertSymbol'},
 		{type: 'spacer'},
 		{type: 'button',  id: 'edit',  img: 'edit'},
+		{type: 'button',  id: 'sidebar', img: 'sidebar_modify_page', hint: _UNO('.uno:Sidebar', '', true), uno: '.uno:Sidebar', hidden: true},
+		{type: 'break', id: 'breaksidebar', hidden: true},
 		{type: 'button',  id: 'fold',  img: 'fold', desktop: true, mobile: false, hidden: true},
 		{type: 'button',  id: 'hamburger-tablet',  img: 'hamburger', desktop: false, mobile: false, tablet: true, iosapptablet: false, hidden: true}
 	];
@@ -1350,7 +1352,7 @@ function onDocLayerInit() {
 		toolbarUp.show('textalign', 'wraptext', 'breakspacing', 'insertannotation', 'conditionalformaticonset',
 			'numberformatcurrency', 'numberformatpercent',
 			'numberformatincdecimals', 'numberformatdecdecimals', 'break-number', 'togglemergecells', 'breakmergecells',
-			'setborderstyle', 'sortascending', 'sortdescending', 'breaksorting', 'backgroundcolor');
+			'setborderstyle', 'sortascending', 'sortdescending', 'breaksorting', 'backgroundcolor', 'breaksidebar', 'sidebar');
 		toolbarUp.remove('styles');
 
 		statusbar.remove('prev', 'next', 'prevnextbreak');
@@ -1416,7 +1418,7 @@ function onDocLayerInit() {
 	case 'text':
 		toolbarUp.show('leftpara', 'centerpara', 'rightpara', 'justifypara', 'breakpara', 'linespacing',
 			'breakspacing', 'defaultbullet', 'defaultnumbering', 'breakbullet', 'incrementindent', 'decrementindent',
-			'breakindent', 'inserttable', 'insertannotation', 'backcolor');
+			'breakindent', 'inserttable', 'insertannotation', 'backcolor', 'breaksidebar', 'sidebar');
 
 		if (!_inMobileMode()) {
 			statusbar.insert('left', [
diff --git a/loleaflet/src/map/Map.js b/loleaflet/src/map/Map.js
index 6513f40ac..ece3a6b37 100644
--- a/loleaflet/src/map/Map.js
+++ b/loleaflet/src/map/Map.js
@@ -264,7 +264,7 @@ L.Map = L.Evented.extend({
                     // This triggers all sidebar decks, so they would
                     // be loaded and show rather quickly on first use.
                     // Also, triggers sidebar window creation in the client.
-					map._socket.sendMessage('uno .uno:ViewSidebarStyles');
+					map._socket.sendMessage('uno .uno:Sidebar');
 					map._socket.sendMessage('uno .uno:Sidebar');
 				}, 200);
 			}
commit 3d4f148a56324ceafb1a1688bb4dee8ef7591d61
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Thu May 2 23:28:04 2019 -0400
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    leaflet: Enable sidebar in writer and calc
    
    Does not actually show the sidebar yet...
    
    Change-Id: Iadddba04bbdb96159e84ffd1498a0845b32e1590
    (cherry picked from commit b999c6fe6d080131f96dec34b11075164ae1d9e1)

diff --git a/loleaflet/src/map/Map.js b/loleaflet/src/map/Map.js
index 1828fabb7..6513f40ac 100644
--- a/loleaflet/src/map/Map.js
+++ b/loleaflet/src/map/Map.js
@@ -257,17 +257,15 @@ L.Map = L.Evented.extend({
 
 			// Show sidebar.
 			if (this._docLayer && !window.mode.isMobile() && !window.mode.isTablet() &&
-				(this._docLayer._docType === 'spreadsheet' || this._docType === 'text')) {
+				(this._docLayer._docType === 'spreadsheet' || this._docLayer._docType === 'text')) {
 				// Let the first page finish loading then load the sidebar.
 				var map = this;
 				setTimeout(function () {
                     // This triggers all sidebar decks, so they would
                     // be loaded and show rather quickly on first use.
                     // Also, triggers sidebar window creation in the client.
-					map._socket.sendMessage('uno .uno:MasterSlidesPanel');
-					map._socket.sendMessage('uno .uno:CustomAnimation');
-					map._socket.sendMessage('uno .uno:SlideChangeWindow');
-					map._socket.sendMessage('uno .uno:ModifyPage');
+					map._socket.sendMessage('uno .uno:ViewSidebarStyles');
+					map._socket.sendMessage('uno .uno:Sidebar');
 				}, 200);
 			}
 		}, this);
commit 652ae5c68f7d494293bc486ecae56c30f2f971c8
Author:     Szymon Kłos <szymon.klos at collabora.com>
AuthorDate: Mon Mar 25 20:19:09 2019 +0100
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    Sidebar: don't show border and placeholder if not visible
    
    Change-Id: I689fa47b0dcb034688ec73c0d338c99423b10a38
    (cherry picked from commit 9b31ab7d44894dda87276eae6bb852bbbc692e1e)

diff --git a/loleaflet/css/loleaflet.css b/loleaflet/css/loleaflet.css
index 0cf5e2b0c..1941b78d5 100644
--- a/loleaflet/css/loleaflet.css
+++ b/loleaflet/css/loleaflet.css
@@ -117,6 +117,7 @@ body {
 }
 
 #sidebar-dock-wrapper {
+	display: none;
 	background: #fff;
 	position: absolute;
 	top: 77px;
diff --git a/loleaflet/src/control/Control.LokDialog.js b/loleaflet/src/control/Control.LokDialog.js
index 9d3721f78..3552d4f0b 100644
--- a/loleaflet/src/control/Control.LokDialog.js
+++ b/loleaflet/src/control/Control.LokDialog.js
@@ -512,6 +512,8 @@ L.Control.LokDialog = L.Control.extend({
 		    && this._map._permission != 'edit')
 			return;
 
+		$('#sidebar-dock-wrapper').css('display', 'block');
+
 		var ratio = 1.0;
 		if (width > window.screen.width) {
 			ratio = window.screen.width / width;
@@ -890,7 +892,10 @@ L.Control.LokDialog = L.Control.extend({
 
 	_resizeSidebar: function(strId, width) {
 		this._currentDeck.width = width;
-		width = width + 15;
+		if (width > 1) {
+			// Add extra space for scrollbar only when visible
+			width = width + 15;
+		}
 		var sidebar = L.DomUtil.get(strId);
 		if (sidebar) {
 			sidebar.width = width;
commit d5b906f3d5294414227669d586baed5c8a6159f2
Author:     Szymon Kłos <szymon.klos at collabora.com>
AuthorDate: Thu Feb 7 15:17:21 2019 +0100
Commit:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
CommitDate: Tue Sep 3 01:53:12 2019 -0400

    Z-index doc, sidebar under menu
    
    Change-Id: Ic9c0dbb326d45c205746e50018906030f7a6fd27
    (cherry picked from commit 0d7b28daf8a8bf6f2adc33bbe3d7d5f7f72d6659)

diff --git a/loleaflet/README b/loleaflet/README
index ad67073bd..5e93024f9 100644
--- a/loleaflet/README
+++ b/loleaflet/README
@@ -377,3 +377,26 @@ are independent of the map's div, thus enabling us to link them to the map as ne
 When the user scrolls, the map is panned by the same amount as it would've been scrolled.
 Also, some custom jquery scrollbars are used, to trigger the same scroll events across
 browsers.
+
+Z-index values:
+-------------------------------------------
+		leaflet
+-------------------------------------------
+10			map
+11			ruler
+-------------------------------------------
+		under menu
+-------------------------------------------
+990			sidebar
+999			toolbar-up
+-------------------------------------------
+		menu items
+-------------------------------------------
+1000			menu, toolbar-down
+1050			closebuttonwrapper
+-------------------------------------------
+		on the top
+-------------------------------------------
+1105			dialogs
+2000			mobile-edit-button
+-------------------------------------------
diff --git a/loleaflet/css/loleaflet.css b/loleaflet/css/loleaflet.css

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list