From d07d2ba5b3bbeb1aa72158d6dc607b0604e42b7a Mon Sep 17 00:00:00 2001 From: Raphael Beer Date: Sun, 12 Apr 2020 04:01:16 +0200 Subject: [PATCH] Add: temporary post id for /create/post --- webapp/components/Editor/Editor.spec.js | 17 ++++++-- webapp/components/Editor/plugins/autoSave.js | 45 +++++++++++--------- webapp/package.json | 1 + webapp/yarn.lock | 2 +- 4 files changed, 41 insertions(+), 24 deletions(-) diff --git a/webapp/components/Editor/Editor.spec.js b/webapp/components/Editor/Editor.spec.js index 976c6bd93..ceb6ddc3e 100644 --- a/webapp/components/Editor/Editor.spec.js +++ b/webapp/components/Editor/Editor.spec.js @@ -208,15 +208,24 @@ describe('Editor.vue', () => { await jest.runAllTimers() }) - afterEach(() => { + afterAll(() => { localStorage.clear() }) it('saves editor content to localStorage on input', async () => { - const { storageKey, value } = getFirstInStorage() - expect(storageKey.startsWith('draft:post:')).toBe(true) + const { value } = getFirstInStorage() expect(value).toBe(content) }) + + it('generates a temporary id for the post', () => { + const { storageKey } = getFirstInStorage() + expect(storageKey).toMatch(/^autosave:post:[a-f\d]{8}$/) + }) + + it('stores temporary id of last edit', () => { + const lastEditedId = localStorage.getItem('autosave:post:last') + expect(lastEditedId).toMatch(/^[a-f\d]{8}$/) + }) }) describe('when editing a comment', () => { @@ -242,7 +251,7 @@ describe('Editor.vue', () => { it('saves editor content to localStorage on input', async () => { const { storageKey, value } = getFirstInStorage() - expect(storageKey).toBe(`draft:${postId}`) + expect(storageKey).toMatch(/autosave:comment:[a-f\d]{8}/) expect(value).toBe(content) }) diff --git a/webapp/components/Editor/plugins/autoSave.js b/webapp/components/Editor/plugins/autoSave.js index 3f13eafef..409638e5f 100644 --- a/webapp/components/Editor/plugins/autoSave.js +++ b/webapp/components/Editor/plugins/autoSave.js @@ -1,10 +1,28 @@ import { Extension, Plugin, PluginKey } from 'tiptap' import { DOMSerializer } from 'prosemirror-model' +import { h32 as hash } from 'xxhashjs' export default class AutoSave extends Extension { constructor({ $route }) { super() + this.route = $route + const { id, editorType } = AutoSave.for(this.route.path) + this.id = id + this.editorType = editorType + } + + static for(path) { + if (path === '/post/create') { + return { editorType: 'post', id: hash(Date.now().toString(), 0xb0b).toString(16) } + } + + const commentMatch = path.match(/^\/post\/([0-9a-f-]*)\/[\w-]*$/) + if (commentMatch) { + return { editorType: 'comment', id: hash(commentMatch[1], 0xb0b).toString(16) } + } + + return null } static toHTML(content, schema) { @@ -15,27 +33,13 @@ export default class AutoSave extends Extension { } static load(path) { - const key = AutoSave.getStorageKey(path) + const { id, editorType } = AutoSave.for(path) + const key = AutoSave.getStorageKey(id, editorType) return key ? localStorage[key] : null } - static getStorageKey(path) { - if (path === '/post/create') { - // find a way to keep invisible random ids - // for posts. - // Once a draft is sent, the storage item - // is deleted. - const _postId = 'randomPostId' - return `draft:post:${_postId}` - } - - const commentMatch = path.match(/^\/post\/([0-9a-f-]*)\/[\w-]*$/) - if (commentMatch) { - const key = `draft:${commentMatch[1]}` - return key - } - - return null + static getStorageKey(id, editorType) { + return `autosave:${editorType}:${id}` } get name() { @@ -43,7 +47,7 @@ export default class AutoSave extends Extension { } get storageKey() { - return AutoSave.getStorageKey(this.route.path) + return AutoSave.getStorageKey(this.id, this.editorType) } get plugins() { @@ -56,6 +60,9 @@ export default class AutoSave extends Extension { this.storageKey, AutoSave.toHTML(tr.doc.content, editorState.config.schema), ) + if (this.editorType === 'post') { + localStorage.setItem('autosave:post:last', this.id) + } } return tr }, diff --git a/webapp/package.json b/webapp/package.json index 15489fc83..ab88b4130 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -94,6 +94,7 @@ "vue-sweetalert-icons": "~4.2.0", "vuex-i18n": "~1.13.1", "xregexp": "^4.3.0", + "xxhashjs": "^0.2.2", "zxcvbn": "^4.4.2" }, "devDependencies": { diff --git a/webapp/yarn.lock b/webapp/yarn.lock index eba52d9cc..58c305e56 100644 --- a/webapp/yarn.lock +++ b/webapp/yarn.lock @@ -17450,7 +17450,7 @@ xtend@^4.0.1: resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== -xxhashjs@^0.2.1: +xxhashjs@^0.2.1, xxhashjs@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/xxhashjs/-/xxhashjs-0.2.2.tgz#8a6251567621a1c46a5ae204da0249c7f8caa9d8" integrity sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==