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: Gabriel Masei <gabriel.masei@1and1.ro>
Change-Id: I89f782cf65f2f104e12cf31ddc059c3481c4eb55
  • Loading branch information
gmasei11 committed Sep 16, 2024
1 parent 8522dfc commit 73ab47f
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 3 deletions.
9 changes: 9 additions & 0 deletions browser/css/toolbar.css
Original file line number Diff line number Diff line change
Expand Up @@ -1806,3 +1806,12 @@ menu-entry-with-icon.padding-left + menu-entry-icon.width */
font-size: var(--default-font-size);
color: var(--color-main-text);
}

#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;
white-space: nowrap;
}
1 change: 1 addition & 0 deletions browser/html/cool.html.m4
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ m4_ifelse(MOBILEAPP, [true],
data-enable-accessibility = "%ENABLE_ACCESSIBILITY%"
data-out-of-focus-timeout-secs = "%OUT_OF_FOCUS_TIMEOUT_SECS%"
data-idle-timeout-secs = "%IDLE_TIMEOUT_SECS%"
data-min-saved-message-timeout-secs = %MIN_SAVED_MESSAGE_TIMEOUT_SECS%;
data-protocol-debug = "%PROTOCOL_DEBUG%"
data-enable-debug = "%ENABLE_DEBUG%"
data-frame-ancestors = "%FRAME_ANCESTORS%"
Expand Down
1 change: 1 addition & 0 deletions browser/src/control/Control.StatusBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ class StatusBar extends JSDialog.Toolbar {
this._generateHtmlItem('permissionmode'), // spreadsheet, text, presentation
{type: 'toolitem', id: 'signstatus', command: '.uno:Signature', w2icon: '', text: _UNO('.uno:Signature'), visible: false},
{type: 'spacer', id: 'permissionspacer'},
{type: 'customtoolitem', id: 'documentstatus'},
{type: 'customtoolitem', id: 'prev', command: 'prev', text: _UNO('.uno:PageUp', 'text'), pressAndHold: true},
{type: 'customtoolitem', id: 'next', command: 'next', text: _UNO('.uno:PageDown', 'text'), pressAndHold: true},
{type: 'separator', id: 'prevnextbreak', orientation: 'vertical'},
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 @@ -327,6 +327,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
75 changes: 72 additions & 3 deletions browser/src/map/Map.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,10 @@ L.Map = L.Evented.extend({

// 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 @@ -347,6 +351,31 @@ L.Map = L.Evented.extend({

// end of A11y

// can be '', 'SAVING', 'MODIFIED' or 'SAVED'
setDocumentStatus: function(status) {
if (status === 'SAVING') {
this._docStatusSaved.style.display = 'none';
this._docStatusLastSaved.textContent = '';
this._docStatusText.style.display = 'inline';
this._docStatusUI.style.display = 'inline';
return;
}

if (status === 'MODIFIED') {
this._docStatusUI.style.display = 'none';
this._docStatusLastSaved.textContent = '';
return;
}

if (status === 'SAVED') {
this._docStatusLastSaved.textContent = '';
this._docStatusText.style.display = 'none';
this._docStatusSaved.style.display = 'inline';
this._docStatusUI.style.display = 'inline';
return;
}
},

loadDocument: function(socket) {
app.socket.connect(socket);
if (this._clip)
Expand Down Expand Up @@ -424,6 +453,37 @@ L.Map = L.Evented.extend({
},

initializeModificationIndicator: function() {
this._docStatusUI = document.getElementById('documentstatus');
if (this._docStatusUI !== null && this._docStatusUI !== undefined) {
this._docStatusUI.replaceChildren();

//
const div = document.createElement('div');
div.className = 'jsdialog ui-badge';
this._docStatusSaved = div;
this._docStatusUI.appendChild(div);

const lastSaved = document.createElement('span');
lastSaved.title = _('Your changes have been saved') + '.';
lastSaved.textContent = '';
div.appendChild(lastSaved);
this._docStatusLastSaved = lastSaved;

const savedStatus = document.createElement('span');
savedStatus.id = 'saved-status-label';
savedStatus.textContent = _('Document saved');
div.appendChild(savedStatus);

const textDiv = document.createElement('div');
textDiv.textContent = _('Saving...');
textDiv.className = 'jsdialog ui-badge';
this._docStatusText = textDiv;
this._docStatusUI.appendChild(textDiv);

this.updateModificationIndicator(this._lastmodtime);
}
this._docStatusUI.style.display = 'none';

var lastModButton = L.DomUtil.get('menu-last-mod');
if (lastModButton !== null && lastModButton !== undefined
&& lastModButton.firstChild.innerHTML !== null
Expand Down Expand Up @@ -458,13 +518,17 @@ L.Map = L.Evented.extend({

clearTimeout(this._modTimeout);

if (this.lastModIndicator !== null && this.lastModIndicator !== undefined) {
if ((this.lastModIndicator !== null && this.lastModIndicator !== undefined)
|| (this._docStatusLastSaved !== null && this._docStatusLastSaved !== undefined)) {
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 @@ -479,7 +543,12 @@ L.Map = L.Evented.extend({
timeout = 60000;
}

this.lastModIndicator.innerHTML = dateValue;
if (this.lastModIndicator !== null && this.lastModIndicator !== undefined) {
this.lastModIndicator.innerHTML = dateValue;
}
if (this._docStatusLastSaved !== null && this._docStatusLastSaved !== undefined) {
this._docStatusLastSaved.innerHTML = 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 @@ -83,6 +83,7 @@
<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 300 seconds." type="uint" default="300">300</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>
<custom_os_info desc="Custom string shown as OS version in About dialog, get from system if empty." type="string" default=""></custom_os_info>
<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 @@ -2115,6 +2115,7 @@ void COOLWSD::innerInitialize(Application& self)
{ "per_view.idle_timeout_secs", "900" },
{ "per_view.out_of_focus_timeout_secs", "120" },
{ "per_view.custom_os_info", "" },
{ "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 @@ -1310,6 +1310,8 @@ FileServerRequestHandler::ResourceAccessDetails FileServerRequestHandler::prepro
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 73ab47f

Please sign in to comment.