Skip to content

Commit

Permalink
browser: add last modification and document status at the bottom
Browse files Browse the repository at this point in the history
Signed-off-by: Alexandru Vlăduţu <alexandru.vladutu@1and1.ro>
Change-Id: I04891ce23e0f250243d9453bfecb0570683cae7a

- adds a last modification setting as well in coolwsd.xml so that it
displays the last modified after a certain delay
- moves the last modification text to the bottom as well as adds a new
text related to the document status (if saved)

Change-Id: I3b21274ed7557b37789f63751e0b9db583469355
  • Loading branch information
alessioalex-1and1 authored and gmasei11 committed Apr 4, 2022
1 parent c550a20 commit b233469
Show file tree
Hide file tree
Showing 9 changed files with 108 additions and 41 deletions.
11 changes: 11 additions & 0 deletions browser/css/cool.css
Original file line number Diff line number Diff line change
Expand Up @@ -900,3 +900,14 @@ nav.spreadsheet-color-indicator ~ #sidebar-dock-wrapper {
#about-dialog-info {
flex-direction: column;
}

#tb_actionbar_item_right {
text-align: right;
}
#saved-status-label {
background-image: url("data:image/svg+xml,%3Csvg id='Icons' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill:%235cb82a;%7D.cls-2%7Bfill:%23fff;%7D%3C/style%3E%3C/defs%3E%3Ctitle%3E_%3C/title%3E%3Cg id='Funktions-Icons_24' data-name='Funktions-Icons 24'%3E%3Ccircle class='cls-1' cx='10' cy='10' r='10'/%3E%3Crect class='cls-2' x='3.36' y='10.52' width='6.75' height='2.5' rx='0.5' ry='0.5' transform='translate(10.29 -1.31) rotate(45)'/%3E%3Crect class='cls-2' x='5.63' y='8.75' width='11.75' height='2.5' rx='0.5' ry='0.5' transform='translate(-3.7 11.06) rotate(-45)'/%3E%3C/g%3E%3C/svg%3E");
background-position: left center;
background-repeat: no-repeat;
padding-left: 18px;
margin-left: 15px;
}
11 changes: 0 additions & 11 deletions browser/css/menubar.css
Original file line number Diff line number Diff line change
Expand Up @@ -313,17 +313,6 @@
background-position: center;
}

#menu-last-mod a {
color: var(--color-text-lighter);
padding: 8px 15px 7px;
z-index: 400;
border: 1px solid transparent;
}

#menu-last-mod a:hover {
color: var(--color-text-darker);
}

/* For classic mode */
#main-menu .locking-disabled, #menu-nb-hamburger .locking-disabled {
color: var(--color-text-lighter) !important;
Expand Down
1 change: 1 addition & 0 deletions browser/html/cool.html.m4
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,7 @@ m4_ifelse(MOBILEAPP,[true],
window.enableMacrosExecution = '%ENABLE_MACROS_EXECUTION%';
window.outOfFocusTimeoutSecs = %OUT_OF_FOCUS_TIMEOUT_SECS%;
window.idleTimeoutSecs = %IDLE_TIMEOUT_SECS%;
window.minSavedMessageTimeoutSecs = %MIN_SAVED_MESSAGE_TIMEOUT_SECS%;
window.protocolDebug = %PROTOCOL_DEBUG%;
window.frameAncestors = decodeURIComponent('%FRAME_ANCESTORS%');
window.socketProxy = %SOCKET_PROXY%;
Expand Down
12 changes: 4 additions & 8 deletions browser/src/control/Control.Menubar.js
Original file line number Diff line number Diff line change
Expand Up @@ -310,8 +310,7 @@ L.Control.Menubar = L.Control.extend({
{name: _('Latest Updates'), id: 'latestupdates', type: 'action', iosapp: false},
{name: _('Send Feedback'), id: 'feedback', type: 'action'},
{name: _('About'), id: 'about', type: 'action'}]
},
{name: _('Last modification'), id: 'last-mod', type: 'action', tablet: false}
}
],

presentation: [
Expand Down Expand Up @@ -442,8 +441,7 @@ L.Control.Menubar = L.Control.extend({
{name: _('Latest Updates'), id: 'latestupdates', type: 'action', iosapp: false},
{name: _('Send Feedback'), id: 'feedback', type: 'action'},
{name: _('About'), id: 'about', type: 'action'}]
},
{name: _('Last modification'), id: 'last-mod', type: 'action', tablet: false}
}
],

drawing: [
Expand Down Expand Up @@ -554,8 +552,7 @@ L.Control.Menubar = L.Control.extend({
{name: _('Latest Updates'), id: 'latestupdates', type: 'action', iosapp: false},
{name: _('Send Feedback'), id: 'feedback', type: 'action'},
{name: _('About'), id: 'about', type: 'action'}]
},
{name: _('Last modification'), id: 'last-mod', type: 'action', tablet: false}
}
],

spreadsheet: [
Expand Down Expand Up @@ -770,8 +767,7 @@ L.Control.Menubar = L.Control.extend({
{name: _('Latest Updates'), id: 'latestupdates', type: 'action', iosapp: false},
{name: _('Send Feedback'), id: 'feedback', type: 'action'},
{name: _('About'), id: 'about', type: 'action'}]
},
{name: _('Last modification'), id: 'last-mod', type: 'action', tablet: false}
}
],

mobiletext: [
Expand Down
2 changes: 2 additions & 0 deletions browser/src/control/Toolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,8 @@ L.Map.include({
},

save: function(dontTerminateEdit, dontSaveIfUnmodified, extendedData) {
this.setDocumentStatus('SAVING');

var msg = 'save' +
' dontTerminateEdit=' + (dontTerminateEdit ? 1 : 0) +
' dontSaveIfUnmodified=' + (dontSaveIfUnmodified ? 1 : 0);
Expand Down
108 changes: 86 additions & 22 deletions browser/src/map/Map.js
Original file line number Diff line number Diff line change
Expand Up @@ -262,12 +262,19 @@ L.Map = L.Evented.extend({

this._isNotebookbarLoadedOnCore = false;

// can be '', 'SAVING', 'MODIFIED' or 'SAVED'
this._docStatus = '';

this.on('commandstatechanged', function(e) {
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' }});

if (this._everModified) {
this.setDocumentStatus(e.state === 'true' ? 'MODIFIED' : 'SAVED');
}
}
}, this);

Expand Down Expand Up @@ -306,6 +313,44 @@ L.Map = L.Evented.extend({
}, this);
},


// can be '', 'SAVING', 'MODIFIED' or 'SAVED'
setDocumentStatus: function(status) {
this._docStatus = status;

if (this._docStatus === 'SAVING' && this.lastModElement) {
this.lastModElement.textContent = _('Saving...');
this.toggleDocumentSavedMsg(false);
return;
}

if (this._docStatus === 'MODIFIED') {
this.lastModElement.textContent = '';
this.toggleDocumentSavedMsg(false);
return;
}

if (this._docStatus === 'SAVED') {
this.toggleDocumentSavedMsg(true);
return;
}
},

toggleDocumentSavedMsg: function(shouldShow) {
var savedStatusElId = 'saved-status-label';
var savedStatusEl = document.getElementById(savedStatusElId);

if (!savedStatusEl) {
savedStatusEl = document.createElement('span');
savedStatusEl.id = savedStatusElId;
savedStatusEl.textContent = _('Document saved');

document.getElementById('tb_actionbar_item_right').appendChild(savedStatusEl);
}

savedStatusEl.style.display = (shouldShow === false) ? 'none' : 'inline';
},

loadDocument: function(socket) {
app.socket.connect(socket);
if (this._clip)
Expand Down Expand Up @@ -378,29 +423,44 @@ L.Map = L.Evented.extend({
},

initializeModificationIndicator: function() {
var lastModButton = L.DomUtil.get('menu-last-mod');
if (lastModButton !== null && lastModButton !== undefined
&& lastModButton.firstChild.innerHTML !== null
&& lastModButton.firstChild.childElementCount == 0) {
if (this._lastmodtime == null) {
// No modification time -> hide the indicator
L.DomUtil.setStyle(lastModButton, 'display', 'none');
return;
}
var mainSpan = document.createElement('span');
this.lastModIndicator = document.createElement('span');
mainSpan.appendChild(this.lastModIndicator);
var lastModElementId = 'last-mod';
if (document.getElementById(lastModElementId)) {
return;
}

this.updateModificationIndicator(this._lastmodtime);
var lastModElement = document.createElement('span');
lastModElement.id = lastModElementId;
lastModElement.setAttribute('title', _('Your changes have been saved') + '.');
var actionBarItemRightElement = document.getElementById('tb_actionbar_item_right');
actionBarItemRightElement.appendChild(lastModElement);

// Replace menu button body with new content
lastModButton.firstChild.innerHTML = '';
lastModButton.firstChild.appendChild(mainSpan);
var that = this;
var timeout = null;

if (L.Params.revHistoryEnabled) {
L.DomUtil.setStyle(lastModButton, 'cursor', 'pointer');
}
// Create an observer that will look for mutations of the container element.
// After the bottom toolbar is beeing initialized it should be ok.
var observer = new MutationObserver(function() {
observer.disconnect();

clearTimeout(timeout);
timeout = setTimeout(function() {
if (!document.getElementById(lastModElementId)) {
that.initializeModificationIndicator();
}
}, 0);
});

observer.observe(actionBarItemRightElement, { attributes: true, childList: true, subtree: true });

this.lastModElement = lastModElement;

if (this._lastmodtime === null) {
// No modification time -> hide the indicator
L.DomUtil.setStyle(lastModElement, 'display', 'none');
return;
}

this.updateModificationIndicator(this._lastmodtime);
},

updateModificationIndicator: function(newModificationTime) {
Expand All @@ -412,13 +472,17 @@ L.Map = L.Evented.extend({

clearTimeout(this._modTimeout);

if (this.lastModIndicator !== null && this.lastModIndicator !== undefined) {
if (this.lastModElement) {
var dateTime = new Date(this._lastmodtime.replace(/,.*/, 'Z'));
var dateValue;

var elapsed = Date.now() - dateTime;
var rtf1 = new Intl.RelativeTimeFormat(String.locale, { style: 'narrow' });
if (elapsed < 60000) {

if (('minSavedMessageTimeoutSecs' in window) && (elapsed < (window.minSavedMessageTimeoutSecs * 1000))) {
timeout = window.minSavedMessageTimeoutSecs * 1000;
dateValue = '';
} else if (elapsed < 60000) {
dateValue = _('Last saved:') + ' ' + rtf1.format(-Math.round(elapsed / 1000), 'second');
timeout = 6000;
} else if (elapsed < 3600000) {
Expand All @@ -433,7 +497,7 @@ L.Map = L.Evented.extend({
timeout = 60000;
}

this.lastModIndicator.innerHTML = dateValue;
this.lastModElement.textContent = dateValue;

if (timeout) {
this._modTimeout = setTimeout(L.bind(this.updateModificationIndicator, this, -1), timeout);
Expand Down
1 change: 1 addition & 0 deletions coolwsd.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
<group_download_as desc="If set to true, groups download as icons into a dropdown for the notebookbar view." type="bool" default="false">false</group_download_as>
<out_of_focus_timeout_secs desc="The maximum number of seconds before dimming and stopping updates when the browser tab is no longer in focus. Defaults to 120 seconds." type="uint" default="120">120</out_of_focus_timeout_secs>
<idle_timeout_secs desc="The maximum number of seconds before dimming and stopping updates when the user is no longer active (even if the browser is in focus). Defaults to 15 minutes." type="uint" default="900">900</idle_timeout_secs>
<min_saved_message_timeout_secs type="uint" desc="The minimum number of seconds before the last modified message is being displayed." default="6">6</min_saved_message_timeout_secs>
</per_view>

<ver_suffix desc="Appended to etags to allow easy refresh of changed files during development" type="string" default=""></ver_suffix>
Expand Down
1 change: 1 addition & 0 deletions wsd/COOLWSD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1456,6 +1456,7 @@ void COOLWSD::innerInitialize(Application& self)
{ "per_view.group_download_as", "false" },
{ "per_view.idle_timeout_secs", "900" },
{ "per_view.out_of_focus_timeout_secs", "120" },
{ "per_view.min_saved_message_timeout_secs", "0"},
{ "security.capabilities", "true" },
{ "security.seccomp", "true" },
{ "security.jwt_expiry_secs", "1800" },
Expand Down
2 changes: 2 additions & 0 deletions wsd/FileServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -995,6 +995,8 @@ void FileServerRequestHandler::preprocessFile(const HTTPRequest& request,
Poco::replaceInPlace(preprocess, std::string("%OUT_OF_FOCUS_TIMEOUT_SECS%"), std::to_string(outOfFocusTimeoutSecs));
const unsigned int idleTimeoutSecs = config.getUInt("per_view.idle_timeout_secs", 900);
Poco::replaceInPlace(preprocess, std::string("%IDLE_TIMEOUT_SECS%"), std::to_string(idleTimeoutSecs));
const unsigned int minSavedMessTimeoutSecs = config.getUInt("per_view.min_saved_message_timeout_secs", 0);
Poco::replaceInPlace(preprocess, std::string("%MIN_SAVED_MESSAGE_TIMEOUT_SECS%"), std::to_string(minSavedMessTimeoutSecs));

#if ENABLE_WELCOME_MESSAGE
std::string enableWelcomeMessage = "true";
Expand Down

0 comments on commit b233469

Please sign in to comment.