Skip to content

Commit 0282154

Browse files
authored
Merge pull request #7062 from nextcloud/backport/6798/stable31
[stable31] feat(session): Send save request via `sendBeacon` at `beforeunload`
2 parents b10b228 + c374fa8 commit 0282154

4 files changed

Lines changed: 48 additions & 14 deletions

File tree

src/components/Editor.vue

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,13 @@ export default {
344344
this.updateEditorWidth(newWidth)
345345
},
346346
},
347+
dirty(val) {
348+
if (val) {
349+
window.addEventListener('beforeunload', this.saveBeforeUnload)
350+
} else {
351+
window.removeEventListener('beforeunload', this.saveBeforeUnload)
352+
}
353+
},
347354
},
348355
mounted() {
349356
if (this.active && (this.hasDocumentParameters)) {
@@ -669,7 +676,7 @@ export default {
669676
this.emit('ready')
670677
}
671678
if (Object.prototype.hasOwnProperty.call(state, 'dirty')) {
672-
// ignore initial loading and other automated changes
679+
// ignore initial loading and other automated changes before first user change
673680
if (this.$editor
674681
&& (this.$editor.can().undo() || this.$editor.can().redo())
675682
) {
@@ -884,6 +891,10 @@ export default {
884891
updateEditorWidth(newWidth) {
885892
document.documentElement.style.setProperty('--text-editor-max-width', newWidth)
886893
},
894+
895+
saveBeforeUnload() {
896+
this.$syncService?.saveViaSendBeacon()
897+
},
887898
},
888899
}
889900
</script>

src/components/Editor/Status.vue

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,22 +89,19 @@ export default {
8989
return this.dirtyStateIndicator ? t('text', 'Saving …') : t('text', 'Saved')
9090
},
9191
dirtyStateIndicator() {
92-
return this.dirty || this.hasUnsavedChanges
92+
return this.dirty
9393
},
9494
lastSavedStatusTooltip() {
9595
let message = t('text', 'Last saved {lastSave}', { lastSave: this.lastSavedString })
9696
if (this.hasSyncCollission) {
9797
message = t('text', 'The document has been changed outside of the editor. The changes cannot be applied.')
9898
}
99-
if (this.dirty || this.hasUnsavedChanges) {
99+
if (this.dirty) {
100100
message += ' - ' + t('text', 'Unsaved changes')
101101
}
102102
return message
103103
},
104104
105-
hasUnsavedChanges() {
106-
return this.document && this.document.lastSavedVersion < this.document.currentVersion
107-
},
108105
hasSyncCollission() {
109106
return this.syncError && this.syncError.type === ERROR_TYPE.SAVE_COLLISSION
110107
},

src/services/SessionApi.js

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* SPDX-License-Identifier: AGPL-3.0-or-later
44
*/
55
import axios from '@nextcloud/axios'
6+
import { getRequestToken } from '@nextcloud/auth'
67
import { generateUrl } from '@nextcloud/router'
78

89
export class ConnectionClosedError extends Error {
@@ -106,17 +107,30 @@ export class Connection {
106107
})
107108
}
108109

109-
save({ version, autosaveContent, documentState, force, manualSave }) {
110-
return this.#post(this.#url(`session/${this.#document.id}/save`), {
110+
save(data) {
111+
const url = this.#url(`session/${this.#document.id}/save`)
112+
const postData = {
111113
...this.#defaultParams,
112114
filePath: this.#options.filePath,
113115
baseVersionEtag: this.#document.baseVersionEtag,
114-
version,
115-
autosaveContent,
116-
documentState,
117-
force,
118-
manualSave,
119-
})
116+
...data,
117+
}
118+
119+
return this.#post(url, postData)
120+
}
121+
122+
saveViaSendBeacon(data) {
123+
const url = this.#url(`session/${this.#document.id}/save`)
124+
const postData = {
125+
...this.#defaultParams,
126+
filePath: this.#options.filePath,
127+
baseVersionEtag: this.#document.baseVersionEtag,
128+
...data,
129+
requestToken: getRequestToken() ?? '',
130+
}
131+
132+
const blob = new Blob([JSON.stringify(postData)], { type: 'application/json' })
133+
return navigator.sendBeacon(url, blob)
120134
}
121135

122136
push({ steps, version, awareness }) {

src/services/SyncService.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ class SyncService {
218218
this.emit('error', { type: ERROR_TYPE.PUSH_FORBIDDEN, data: {} })
219219
}
220220
// TODO: does response.data ever have a document? maybe for errors?
221+
// TODO: `currentVersion` is always 0 nowadays. Check if this is still needed.
221222
// Only emit conflict event if we have synced until the latest version
222223
if (response.data.document?.currentVersion === this.version) {
223224
this.emit('error', { type: ERROR_TYPE.PUSH_FAILURE, data: {} })
@@ -299,6 +300,17 @@ class SyncService {
299300
}
300301
}
301302

303+
saveViaSendBeacon() {
304+
this.#connection.saveViaSendBeacon({
305+
version: this.version,
306+
autosaveContent: this._getContent(),
307+
documentState: this.getDocumentState(),
308+
force: false,
309+
manualSave: true,
310+
})
311+
logger.debug('[SyncService] saved using sendBeacon')
312+
}
313+
302314
forceSave() {
303315
return this.save({ force: true })
304316
}

0 commit comments

Comments
 (0)