Makefile.am | 1 loleaflet/html/loleaflet.html.m4 | 6 + loleaflet/src/control/Control.Menubar.js | 13 +++ loleaflet/src/control/Control.StatusBar.js | 12 +++ loleaflet/src/control/Control.UIManager.js | 39 ++++++++++ loleaflet/src/control/Ruler.js | 9 ++ test/Makefile.am | 1 test/WhiteBoxTests.cpp | 15 ++++ wsd/FileServer.cpp | 3 wsd/FileServer.hpp | 8 ++ wsd/FileServerUtil.cpp | 104 +++++++++++++++++++++++++++++ wsd/reference.md | 21 +++++ 12 files changed, 226 insertions(+), 6 deletions(-)
New commits: commit 2e28b9bb655ac7ebc5b580fabb5636b629dd7f85 Author: mert <mert.tu...@collabora.com> AuthorDate: Wed Jun 3 21:16:31 2020 +0300 Commit: Mert Tumer <mert.tu...@collabora.com> CommitDate: Mon Sep 28 11:53:23 2020 +0200 Change Show/Hide Ruler & Statusbar by default on first load Change-Id: If0bcf08f005b8461ed559d197b49dc11448344d3 Signed-off-by: mert <mert.tu...@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/c/online/+/96489 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> diff --git a/loleaflet/src/control/Control.Menubar.js b/loleaflet/src/control/Control.Menubar.js index e53958f14..d3e3988a7 100644 --- a/loleaflet/src/control/Control.Menubar.js +++ b/loleaflet/src/control/Control.Menubar.js @@ -64,6 +64,7 @@ L.Control.Menubar = L.Control.extend({ {name: _UNO('.uno:ZoomMinus', 'text'), id: 'zoomout', type: 'action',}, {name: _('Reset zoom'), id: 'zoomreset', type: 'action'}, {name: _('Show Ruler'), id: 'showruler', type: 'action'}, + {name: _('Show Status Bar'), id: 'showstatusbar', type: 'action'}, {type: 'separator'}, ]).concat([ {uno: '.uno:ControlCodes'}, @@ -294,7 +295,8 @@ L.Control.Menubar = L.Control.extend({ {uno: '.uno:CustomAnimation', drawing: false}, {uno: '.uno:MasterSlidesPanel', drawing: false}, {type: 'separator', drawing: false}, - {uno: '.uno:Sidebar', drawing: false}] + {uno: '.uno:Sidebar', drawing: false}, + {name: _('Show Status Bar'), id: 'showstatusbar', type: 'action'}] }, {name: _UNO('.uno:InsertMenu', 'presentation'), id: 'insert', type: 'menu', menu: [ {name: _('Local Image...'), id: 'insertgraphic', type: 'action'}, @@ -1082,6 +1084,13 @@ L.Control.Menubar = L.Control.extend({ $(aItem).removeClass(constChecked); } + } else if (id === 'showstatusbar') { + if (self._map.uiManager.isStatusBarVisible()) { + $(aItem).addClass(constChecked); + } 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'); @@ -1215,6 +1224,8 @@ L.Control.Menubar = L.Control.extend({ L.toggleFullScreen(); } else if (id === 'showruler') { this._map.uiManager.toggleRuler(); + } else if (id === 'showstatusbar') { + this._map.uiManager.toggleStatusBar(); } else if (id === 'fullscreen-presentation' && this._map.getDocType() === 'presentation') { this._map.fire('fullscreen'); } else if (id === 'presentation-currentslide' && this._map.getDocType() === 'presentation') { diff --git a/loleaflet/src/control/Control.StatusBar.js b/loleaflet/src/control/Control.StatusBar.js index 29a844e9f..62f368403 100644 --- a/loleaflet/src/control/Control.StatusBar.js +++ b/loleaflet/src/control/Control.StatusBar.js @@ -240,7 +240,6 @@ L.Control.StatusBar = L.Control.extend({ }); if (window.mode.isDesktop()) toolbar.tooltip(); - toolbar.show(); } toolbar.bind('touchstart', function() { @@ -397,6 +396,17 @@ L.Control.StatusBar = L.Control.extend({ if (statusbar) statusbar.refresh(); + + var showStatusbar = true; + if (window.uiDefaults) { + if (window.uiDefaults[docType]) { + showStatusbar = window.uiDefaults[docType].ShowStatusbar !== false; + } + } + if (showStatusbar) + $('#toolbar-down').show(); + else + this.map.uiManager.hideStatusBar(true); }, _cancelSearch: function() { diff --git a/loleaflet/src/control/Control.UIManager.js b/loleaflet/src/control/Control.UIManager.js index 8f603eadd..edc0472e6 100644 --- a/loleaflet/src/control/Control.UIManager.js +++ b/loleaflet/src/control/Control.UIManager.js @@ -114,8 +114,14 @@ L.Control.UIManager = L.Control.extend({ L.DomUtil.remove(L.DomUtil.get('presentation-controls-wrapper')); if ((window.mode.isTablet() || window.mode.isDesktop())) { + var showRuler = true; + if (window.uiDefaults) { + if (window.uiDefaults[docType]) { + showRuler = window.uiDefaults[docType].ShowRuler || false; + } + } var interactiveRuler = this.map.isPermissionEdit(); - L.control.ruler({position:'topleft', interactive:interactiveRuler}).addTo(this.map); + L.control.ruler({position:'topleft', interactive:interactiveRuler, showruler: showRuler}).addTo(this.map); } } @@ -260,6 +266,37 @@ L.Control.UIManager = L.Control.extend({ return $('#document-container').hasClass('tabs-collapsed'); }, + // UI Defaults functions + + showStatusBar: function() { + $('#document-container').css('bottom', this.documentBottom); + $('#presentation-controls-wrapper').css('bottom', this.presentationControlBottom); + $('#toolbar-down').show(); + this.map.invalidateSize(); + }, + + hideStatusBar: function(firstStart) { + if (!firstStart && !this.isStatusBarVisible()) + return; + + this.documentBottom = $('#document-container').css('bottom'); + this.presentationControlBottom = $('#presentation-controls-wrapper').css('bottom'); + $('#document-container').css('bottom', '0px'); + $('#presentation-controls-wrapper').css('bottom','33px'); + $('#toolbar-down').hide(); + }, + + toggleStatusBar: function() { + if (this.isStatusBarVisible()) + this.hideStatusBar(); + else + this.showStatusBar(); + }, + + isStatusBarVisible: function() { + return $('#toolbar-down').is(':visible'); + }, + // Event handlers onUpdatePermission: function(e) { diff --git a/loleaflet/src/control/Ruler.js b/loleaflet/src/control/Ruler.js index f9b4a913e..7df9def3d 100644 --- a/loleaflet/src/control/Ruler.js +++ b/loleaflet/src/control/Ruler.js @@ -19,7 +19,8 @@ L.Control.Ruler = L.Control.extend({ tabs: [], unit: null, DraggableConvertRatio: null, - timer: null + timer: null, + showruler: true }, onAdd: function(map) { @@ -149,6 +150,12 @@ L.Control.Ruler = L.Control.extend({ _initLayout: function() { this._rWrapper = L.DomUtil.create('div', 'loleaflet-ruler leaflet-bar leaflet-control leaflet-control-custom'); + // We start it hidden rather than not initialzing at all. + // It is due to rulerupdate command that comes from LOK. + // If we delay its initialization, we can't calculate its margins and have to wait for another rulerupdate message to arrive. + if (!this.options.showruler) { + L.DomUtil.setStyle(this._rWrapper, 'display', 'none'); + } this._rFace = L.DomUtil.create('div', 'loleaflet-ruler-face', this._rWrapper); this._rMarginWrapper = L.DomUtil.create('div', 'loleaflet-ruler-marginwrapper', this._rFace); // BP => Break Points commit 4ad8773821f73fa0df665f4d2d4682237a7af677 Author: Jan Holesovsky <ke...@collabora.com> AuthorDate: Wed Jun 3 19:46:42 2020 +0300 Commit: Mert Tumer <mert.tu...@collabora.com> CommitDate: Mon Sep 28 11:53:16 2020 +0200 Make various bits of the UI configurable. This adds the infrastructure to be able to pass the info which elements like the statusbar / ruler / sidebar are supposed to be shown or hidden on startup of the editor. Change-Id: I188264dec6961074444934ff5fd7088e23b170d4 Reviewed-on: https://gerrit.libreoffice.org/c/online/+/103169 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Mert Tumer <mert.tu...@collabora.com> diff --git a/Makefile.am b/Makefile.am index e50b68022..1ab2f733b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -118,6 +118,7 @@ loolwsd_sources = common/Crypto.cpp \ wsd/LOOLWSD.cpp \ wsd/ClientSession.cpp \ wsd/FileServer.cpp \ + wsd/FileServerUtil.cpp \ wsd/RequestDetails.cpp \ wsd/Storage.cpp \ wsd/TileCache.cpp \ diff --git a/loleaflet/html/loleaflet.html.m4 b/loleaflet/html/loleaflet.html.m4 index 7abe51f18..d180165e7 100644 --- a/loleaflet/html/loleaflet.html.m4 +++ b/loleaflet/html/loleaflet.html.m4 @@ -260,7 +260,8 @@ m4_ifelse(MOBILEAPP,[true], window.protocolDebug = false; window.frameAncestors = ''; window.socketProxy = false; - window.tileSize = 256;], + window.tileSize = 256; + window.uiDefaults = {};], [window.host = '%HOST%'; window.serviceRoot = '%SERVICE_ROOT%'; window.versionPath = '%VERSION%'; @@ -277,7 +278,8 @@ m4_ifelse(MOBILEAPP,[true], window.protocolDebug = %PROTOCOL_DEBUG%; window.frameAncestors = '%FRAME_ANCESTORS%'; window.socketProxy = %SOCKET_PROXY%; - window.tileSize = 256;]) + window.tileSize = 256; + window.uiDefaults = %UI_DEFAULTS%;]) m4_syscmd([cat ]GLOBAL_JS)m4_dnl // Dynamically load the appropriate *-mobile.css, *-tablet.css or *-desktop.css diff --git a/test/Makefile.am b/test/Makefile.am index 967143b3e..1b1bcb28a 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -67,6 +67,7 @@ wsd_sources = \ ../common/Authorization.cpp \ ../kit/Kit.cpp \ ../kit/TestStubs.cpp \ + ../wsd/FileServerUtil.cpp \ ../wsd/RequestDetails.cpp \ ../wsd/TileCache.cpp \ ../wsd/ProofKey.cpp diff --git a/test/WhiteBoxTests.cpp b/test/WhiteBoxTests.cpp index 445a7134a..8f53c32ef 100644 --- a/test/WhiteBoxTests.cpp +++ b/test/WhiteBoxTests.cpp @@ -23,6 +23,7 @@ #include <RequestDetails.hpp> #include <common/Authorization.hpp> +#include <wsd/FileServer.hpp> /// WhiteBox unit-tests. class WhiteBoxTests : public CPPUNIT_NS::TestFixture @@ -48,6 +49,7 @@ class WhiteBoxTests : public CPPUNIT_NS::TestFixture CPPUNIT_TEST(testRequestDetails_loleafletURI); CPPUNIT_TEST(testRequestDetails_local); CPPUNIT_TEST(testRequestDetails); + CPPUNIT_TEST(testUIDefaults); CPPUNIT_TEST_SUITE_END(); @@ -70,6 +72,7 @@ class WhiteBoxTests : public CPPUNIT_NS::TestFixture void testRequestDetails_loleafletURI(); void testRequestDetails_local(); void testRequestDetails(); + void testUIDefaults(); }; void WhiteBoxTests::testLOOLProtocolFunctions() @@ -1563,6 +1566,18 @@ void WhiteBoxTests::testRequestDetails() } } +void WhiteBoxTests::testUIDefaults() +{ + LOK_ASSERT_EQUAL(std::string("{\"uiMode\":\"classic\"}"), + FileServerRequestHandler::uiDefaultsToJSON("UIMode=classic;huh=bleh;")); + + LOK_ASSERT_EQUAL(std::string("{\"spreadsheet\":{\"ShowSidebar\":false},\"text\":{\"ShowRuler\":true}}"), + FileServerRequestHandler::uiDefaultsToJSON("TextRuler=true;SpreadsheetSidebar=false")); + + LOK_ASSERT_EQUAL(std::string("{\"presentation\":{\"ShowStatusbar\":false},\"spreadsheet\":{\"ShowSidebar\":false},\"text\":{\"ShowRuler\":true},\"uiMode\":\"notebookbar\"}"), + FileServerRequestHandler::uiDefaultsToJSON(";;UIMode=notebookbar;;PresentationStatusbar=false;;TextRuler=true;;bah=ugh;;SpreadsheetSidebar=false")); +} + CPPUNIT_TEST_SUITE_REGISTRATION(WhiteBoxTests); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/wsd/FileServer.cpp b/wsd/FileServer.cpp index fcf853173..56ff49801 100644 --- a/wsd/FileServer.cpp +++ b/wsd/FileServer.cpp @@ -677,6 +677,8 @@ void FileServerRequestHandler::preprocessFile(const HTTPRequest& request, LOG_TRC("access_token=" << accessToken << ", access_token_ttl=" << accessTokenTtl); const std::string accessHeader = form.get("access_header", ""); LOG_TRC("access_header=" << accessHeader); + const std::string uiDefaults = form.get("ui_defaults", ""); + LOG_TRC("ui_defaults=" << uiDefaults); // Escape bad characters in access token. // This is placed directly in javascript in loleaflet.html, we need to make sure @@ -718,6 +720,7 @@ void FileServerRequestHandler::preprocessFile(const HTTPRequest& request, Poco::replaceInPlace(preprocess, std::string("%HOST%"), cnxDetails.getWebSocketUrl()); Poco::replaceInPlace(preprocess, std::string("%VERSION%"), std::string(LOOLWSD_VERSION_HASH)); Poco::replaceInPlace(preprocess, std::string("%SERVICE_ROOT%"), responseRoot); + Poco::replaceInPlace(preprocess, std::string("%UI_DEFAULTS%"), uiDefaultsToJSON(uiDefaults)); const auto& config = Application::instance().config(); std::string protocolDebug = "false"; diff --git a/wsd/FileServer.hpp b/wsd/FileServer.hpp index 58cbb0b28..1cad001fb 100644 --- a/wsd/FileServer.hpp +++ b/wsd/FileServer.hpp @@ -18,6 +18,8 @@ class RequestDetails; /// Handles file requests over HTTP(S). class FileServerRequestHandler { + friend class WhiteBoxTests; // for unit testing + static std::string getRequestPathname(const Poco::Net::HTTPRequest& request); static void preprocessFile(const Poco::Net::HTTPRequest& request, @@ -27,6 +29,12 @@ class FileServerRequestHandler static void preprocessAdminFile(const Poco::Net::HTTPRequest& request, const RequestDetails &requestDetails, const std::shared_ptr<StreamSocket>& socket); + + /// Construct a JSON to be accepted by the loleflet.html from a list like + /// UIMode=classic;TextRuler=true;PresentationStatusbar=false + /// that is passed as "ui_defaults" hidden input during the iframe setup. + static std::string uiDefaultsToJSON(const std::string& uiDefaults); + public: /// Evaluate if the cookie exists, and if not, ask for the credentials. static bool isAdminLoggedIn(const Poco::Net::HTTPRequest& request, Poco::Net::HTTPResponse& response); diff --git a/wsd/FileServerUtil.cpp b/wsd/FileServerUtil.cpp new file mode 100644 index 000000000..dbbc90028 --- /dev/null +++ b/wsd/FileServerUtil.cpp @@ -0,0 +1,104 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <config.h> + +#include <Poco/JSON/Object.h> + +#include "FileServer.hpp" + +std::string FileServerRequestHandler::uiDefaultsToJSON(const std::string& uiDefaults) +{ + static std::string previousUIDefaults; + static std::string previousJSON("{}"); + + // early exit if we are serving the same thing + if (uiDefaults == previousUIDefaults) + return previousJSON; + + Poco::JSON::Object json; + Poco::JSON::Object textDefs; + Poco::JSON::Object spreadsheetDefs; + Poco::JSON::Object presentationDefs; + + StringVector tokens(Util::tokenize(uiDefaults, ';')); + for (const auto& token : tokens) + { + StringVector keyValue(Util::tokenize(tokens.getParam(token), '=')); + Poco::JSON::Object* currentDef = nullptr; + std::string key; + + // detect the UIMode or component + if (keyValue[0] == "UIMode") + { + if (keyValue[1] == "classic" || keyValue[1] == "notebookbar") + json.set("uiMode", keyValue[1]); + else + LOG_WRN("unknown UIMode value " << keyValue[1]); + + continue; + } + else if (Util::startsWith(keyValue[0], "Text")) + { + currentDef = &textDefs; + key = keyValue[0].substr(4); + } + else if (Util::startsWith(keyValue[0], "Spreadsheet")) + { + currentDef = &spreadsheetDefs; + key = keyValue[0].substr(11); + } + else if (Util::startsWith(keyValue[0], "Presentation")) + { + currentDef = &presentationDefs; + key = keyValue[0].substr(12); + } + else + { + LOG_WRN("unknown UI default's component " << keyValue[0]); + continue; + } + + assert(currentDef); + + // detect the actual UI widget we want to hide or show + if (key == "Ruler" || key == "Sidebar" || key == "Statusbar") + { + bool value(true); + if (keyValue[1] == "false" || keyValue[1] == "False" || keyValue[1] == "0") + value = false; + + currentDef->set("Show" + key, value); + } + else + { + LOG_WRN("unknown UI default " << keyValue[0]); + continue; + } + } + + if (textDefs.size() > 0) + json.set("text", textDefs); + + if (spreadsheetDefs.size() > 0) + json.set("spreadsheet", spreadsheetDefs); + + if (presentationDefs.size() > 0) + json.set("presentation", presentationDefs); + + std::ostringstream oss; + Poco::JSON::Stringifier::stringify(json, oss); + + previousUIDefaults = uiDefaults; + previousJSON = oss.str(); + + return previousJSON; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/wsd/reference.md b/wsd/reference.md index e8798debc..0c987f9eb 100644 --- a/wsd/reference.md +++ b/wsd/reference.md @@ -128,6 +128,27 @@ PostMessage extensions ### App_LoadingStatus Was extended with field 'Status' with 'Document_Loaded' value when document was loaded successfully and 'Failed' in other case. +User Interface modifications +---------------------------- + +Some parts of the user interface can be hidden or shown based or what the +integration needs. This is controlled by: + + <input name="ui_defaults" value="VALUES" type="hidden"/>' + +during sending the form when the iframe is being set up (similarly as the +access_token). The VALUES can have a form like: + + UIMode=notebookbar;TextRuler=false;PresentationStatusbar=false;SpreadsheetSidebar=false + +where the: + +* UIMode specifies the general mode of operatior (classic or notebookbar) + +* Text, Presentation or Spreadsheet - are prefixes to identify the component + +* Ruler, Statusbar, Sidebar - are the UI parts that can be affected by this. + Alternative authentication possibility -------------------------------------- _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits