diff --git a/webapp/components/Editor/Editor.spec.js b/webapp/components/Editor/Editor.spec.js index 20041c741..b4d9510d9 100644 --- a/webapp/components/Editor/Editor.spec.js +++ b/webapp/components/Editor/Editor.spec.js @@ -31,15 +31,15 @@ describe('Editor.vue', () => { })) } - beforeEach(() => { - propsData = {} - mocks = { - $t: () => 'some cool placeholder', - } - wrapper = Wrapper() - }) - describe('mount', () => { + beforeEach(() => { + propsData = {} + mocks = { + $t: () => 'some cool placeholder', + } + wrapper = Wrapper() + }) + it('renders', () => { expect(Wrapper().is('div')).toBe(true) }) @@ -149,7 +149,7 @@ describe('Editor.vue', () => { }) describe(':autosave', () => { - const getFirst = () => { + const getFirstInStorage = () => { const storageKey = Object.keys(localStorage)[0] const value = localStorage[storageKey] return { @@ -165,9 +165,16 @@ describe('Editor.vue', () => { let routerWrapper beforeEach(() => { + propsData = {} + mocks = { + $t: (key) => key, + } router = new VueRouter({ routes: [{ path: 'post/create' }], }) + mocks = { + $t: (key) => key, + } router.push('/post/create') propsData.autosave = false routerWrapper = Wrapper() @@ -187,6 +194,10 @@ describe('Editor.vue', () => { const content = '
Post WIP
' beforeEach(async () => { + propsData = {} + mocks = { + $t: (key) => key, + } router = new VueRouter({ routes: [{ path: 'post/create' }], }) @@ -201,7 +212,7 @@ describe('Editor.vue', () => { }) it('saves editor content to localStorage on input', async () => { - const { storageKey, value } = getFirst() + const { storageKey, value } = getFirstInStorage() expect(storageKey.startsWith('draft:post:')).toBe(true) expect(value).toBe(content) }) @@ -212,6 +223,10 @@ describe('Editor.vue', () => { const content = 'Comment WIP
' beforeEach(async () => { + propsData = {} + mocks = { + $t: (key) => key, + } router = new VueRouter({ routes: [{ path: `/post/${postId}/foo-title-slug` }], }) @@ -221,15 +236,21 @@ describe('Editor.vue', () => { await jest.runAllTimers() }) - afterEach(() => { + afterAll(() => { localStorage.clear() }) it('saves editor content to localStorage on input', async () => { - const { storageKey, value } = getFirst() + const { storageKey, value } = getFirstInStorage() expect(storageKey).toBe(`draft:${postId}`) expect(value).toBe(content) }) + + it('loads an existing autosave', () => { + const { value: autoSaveHTML } = getFirstInStorage() + const _wrapper = Wrapper() + expect(_wrapper.vm.editor.getHTML()).toBe(autoSaveHTML) + }) }) }) }) diff --git a/webapp/components/Editor/Editor.vue b/webapp/components/Editor/Editor.vue index 1fbe49be6..93bb39c0f 100644 --- a/webapp/components/Editor/Editor.vue +++ b/webapp/components/Editor/Editor.vue @@ -29,6 +29,9 @@ import { replace, build } from 'xregexp/xregexp-all.js' import * as key from '../../constants/keycodes' import { HASHTAG, MENTION } from '../../constants/editor' import defaultExtensions from './defaultExtensions.js' + +import AutoSave from './plugins/autoSave.js' + import EventHandler from './plugins/eventHandler.js' import Hashtag from './nodes/Hashtag.js' import Mention from './nodes/Mention.js' @@ -50,9 +53,12 @@ export default { props: { users: { type: Array, default: () => null }, // If 'null', than the Mention extention is not assigned. hashtags: { type: Array, default: () => null }, // If 'null', than the Hashtag extention is not assigned. - value: { type: String, default: '' }, doc: { type: Object, default: () => {} }, autosave: { type: Boolean, default: true }, + value: { + type: String, + default: '', + }, }, data() { return { @@ -106,6 +112,9 @@ export default { } return extensions }, + autosaveContent() { + return this.autosave && this.$route ? AutoSave.load(this.$route.path) : '' + }, }, watch: { placeholder: { @@ -120,7 +129,7 @@ export default { }, mounted() { this.editor = new Editor({ - content: this.value || '', + content: this.value || this.autosaveContent || '', doc: this.doc, extensions: [ // Hashtags must come first, see diff --git a/webapp/components/Editor/plugins/autoSave.js b/webapp/components/Editor/plugins/autoSave.js index c25b8ebfe..3f13eafef 100644 --- a/webapp/components/Editor/plugins/autoSave.js +++ b/webapp/components/Editor/plugins/autoSave.js @@ -5,7 +5,6 @@ export default class AutoSave extends Extension { constructor({ $route }) { super() this.route = $route - this._postId = 'randomIdForPosts' } static toHTML(content, schema) { @@ -15,16 +14,22 @@ export default class AutoSave extends Extension { return container.innerHTML } - get name() { - return 'auto_save' + static load(path) { + const key = AutoSave.getStorageKey(path) + return key ? localStorage[key] : null } - get storageKey() { - if (this.route.path === '/post/create') { - return `draft:post:${this._postId}` + 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 = this.route.path.match(/^\/post\/([0-9a-f-]*)\/[\w-]*$/) + const commentMatch = path.match(/^\/post\/([0-9a-f-]*)\/[\w-]*$/) if (commentMatch) { const key = `draft:${commentMatch[1]}` return key @@ -33,12 +38,20 @@ export default class AutoSave extends Extension { return null } + get name() { + return 'auto_save' + } + + get storageKey() { + return AutoSave.getStorageKey(this.route.path) + } + get plugins() { return [ new Plugin({ key: new PluginKey('auto_save'), filterTransaction: (tr, editorState) => { - if (tr.docChanged) { + if (tr.docChanged && this.storageKey) { localStorage.setItem( this.storageKey, AutoSave.toHTML(tr.doc.content, editorState.config.schema),