From 667b30146d59c1f4a06c6a683ef9526902aa9bfa Mon Sep 17 00:00:00 2001 From: Leos Literak Date: Tue, 1 Feb 2022 19:49:52 +0100 Subject: [PATCH] #249 #273 - unified snippet structure; finish html snippet --- backend/doc/database/snippets.md | 12 ++-- backend/src/handlers/items/snippets.js | 9 ++- backend/test/snippets.int.test.js | 6 +- spa/src/locales/cs.json | 3 + spa/src/locales/en.json | 3 + spa/src/modules/vuex/items.js | 7 +++ spa/src/views/item/Article.vue | 33 ++++------- spa/src/views/item/EditSnippets.vue | 78 +++++++++++++++----------- 8 files changed, 84 insertions(+), 67 deletions(-) diff --git a/backend/doc/database/snippets.md b/backend/doc/database/snippets.md index a17059a6..7dd8bd25 100644 --- a/backend/doc/database/snippets.md +++ b/backend/doc/database/snippets.md @@ -2,27 +2,29 @@ * code: unique identifier within the item; required * type: type of the object; values: html, link, meta, script, style; required * date: timestamp; required +* user: identification of the last user who made a change; required +* object: one of meta, html, link, script or style object -## Meta optional section +## Meta object * name: value of meta attribute; optional * property: value of property attribute; optional * content: value of content attribute; optional -## Html optional section +## Html object * innerHTML: content to be rendered; required -## Link optional section +## Link object * rel: value of rel attribute; optional * href: value of href attribute; optional -## Script optional section +## Script object * url: value of src attribute; optional * type: value of type attribute; optional * innerHTML: content to be rendered inside script tag; optional * async: boolean value; optional * defer: boolean value; optional -## Style optional section +## Style object * type: value of type attribute; optional * cssText: content to be rendered inside style tag; optional diff --git a/backend/src/handlers/items/snippets.js b/backend/src/handlers/items/snippets.js index 6f5c0a93..169d1756 100644 --- a/backend/src/handlers/items/snippets.js +++ b/backend/src/handlers/items/snippets.js @@ -93,8 +93,7 @@ module.exports = (app) => { } const user = auth.getIdentity(req.identity); - const snippet = { code: code.toLowerCase(), type: type.toLowerCase(), date: new Date(), user }; - snippet[snippet.type] = object; + const snippet = { code: code.toLowerCase(), type: type.toLowerCase(), date: new Date(), user, object }; snippets.push(snippet); const result = await dbClient.db().collection('items').updateOne({ _id: itemId }, { $set: { snippets } }); @@ -149,14 +148,14 @@ module.exports = (app) => { async function insertItem(dbClient, itemId, code, type, user, object) { const snippet = { code, + type, + date: new Date(), user: { nickname: user.nickname, id: user.userId, }, - type, - date: new Date(), + object, }; - snippet[type] = object; const result = await dbClient.db().collection('items').updateOne({ _id: itemId }, { $push: {snippets: snippet } }); if (result.modifiedCount === 1) { diff --git a/backend/test/snippets.int.test.js b/backend/test/snippets.int.test.js index 5cc96f5a..c4f9dbcd 100644 --- a/backend/test/snippets.int.test.js +++ b/backend/test/snippets.int.test.js @@ -45,7 +45,7 @@ test('Item snippets', async () => { const snippetABody = { code: 'set_a', type: 'html', - object: { content: 'a=1' }, + object: { innerHTML: 'a=1' }, }; // create snippet A as Jiri - forbidden (missing role editor in chief) @@ -76,6 +76,7 @@ test('Item snippets', async () => { expect(response.data.length).toBe(2); expect(response.data[0].code).toBe(snippetABody.code); expect(response.data[1].code).toBe(snippetCBody.code); + expect(response.data[1].object.content).toBe(snippetCBody.object.content); response = await api(`content/${blog.data.info.slug}`).json(); expect(response.success).toBe(true); @@ -93,8 +94,7 @@ test('Item snippets', async () => { expect(response.success).toBe(true); expect(response.data.code).toBe(snippetBBody.code); expect(response.data.type).toBe(snippetBBody.type); - expect(response.data.meta).toBeUndefined(); - expect(response.data.link).toStrictEqual(snippetBBody.object); + expect(response.data.object).toStrictEqual(snippetBBody.object); const snippetDBody = { code: 'set_d', diff --git a/spa/src/locales/cs.json b/spa/src/locales/cs.json index d41ccd08..4260a265 100644 --- a/spa/src/locales/cs.json +++ b/spa/src/locales/cs.json @@ -49,6 +49,7 @@ "edit-html-button": "Upravit HTML", "edit-snippets-button": "Upravit úryvky", "save-button": "Uložit", + "insert-button": "Přidat", "delete-button": "Smazat", "reset-button": "Reset", "reset-tooltip": "Reset", @@ -324,6 +325,8 @@ "cms": { "snippets": { "type": "Typ", + "code": "Kód", + "content": "Obsah", "add-label": "Vložit snippet" } }, diff --git a/spa/src/locales/en.json b/spa/src/locales/en.json index 1e36a7f0..b4c2f494 100644 --- a/spa/src/locales/en.json +++ b/spa/src/locales/en.json @@ -49,6 +49,7 @@ "edit-html-button": "Edit HTML", "edit-snippets-button": "Edit snippets", "save-button": "Save", + "insert-button": "Insert", "delete-button": "Delete", "reset-button": "Reset", "reset-tooltip": "Reset", @@ -320,6 +321,8 @@ "cms": { "snippets": { "type": "Type", + "code": "Code", + "content": "Content", "add-label": "Add new snippet" } }, diff --git a/spa/src/modules/vuex/items.js b/spa/src/modules/vuex/items.js index 1e2ee4fa..cd9c9f87 100644 --- a/spa/src/modules/vuex/items.js +++ b/spa/src/modules/vuex/items.js @@ -211,5 +211,12 @@ export default { await patch('API', `/posts/${content._id}/hidden`, payload, context); Vue.set(content.info, 'state', hidden ? 'hidden' : 'published'); }, + ADD_SNIPPET: async (context, payload) => { + Vue.$log.debug('ADD_SNIPPET'); + const { itemId } = payload; + const response = await post('API', `/items/${itemId}/snippets`, payload, context); + context.commit('CLEAR_CONTENT'); + return response; + }, }, }; diff --git a/spa/src/views/item/Article.vue b/spa/src/views/item/Article.vue index 317365ee..794789d4 100644 --- a/spa/src/views/item/Article.vue +++ b/spa/src/views/item/Article.vue @@ -93,7 +93,7 @@ export default { }, metaInfo () { return { - title: this.article ? this.article.info.caption : '', + title: this.title, link: [], meta: [], script: [], @@ -112,11 +112,10 @@ export default { return this.$store.getters.CONTENT; }, title() { - let txt = ''; if (this.article !== null) { - txt = this.article.info.caption; + return this.article.info.caption; } - return txt; + return ''; }, canEdit() { if (!this.$store.getters.IS_AUTHORIZED) { @@ -151,31 +150,23 @@ export default { return this.article.data.content; } - let htmlSnippets = []; + let content = this.article.data.content; this.article.snippets.forEach(snippet => { if (snippet.type === 'meta') { - this.metaInfo.meta.push(snippet.meta); + this.metaInfo.meta.push(snippet.object); } else if (snippet.type === 'html') { - htmlSnippets.push(snippet); + const replacer = `[code="${snippet.code}"]`; + const position = content.indexOf(replacer); + content = content.substring(0, position) + `\n${snippet.object.innerHTML}\n` + content.substring(position + replacer.length); } else if (snippet.type === 'style') { - this.metaInfo.style.push(snippet.style); + this.metaInfo.style.push(snippet.object); } else if (snippet.type === 'script') { - this.metaInfo.script.push(snippet.script); + this.metaInfo.script.push(snippet.object); } else if (snippet.type === 'link') { - this.metaInfo.link.push(snippet.link); + this.metaInfo.link.push(snippet.object); } }); - - if (htmlSnippets.length > 0) { - const replacer = (match, foundCode) => { - const snippet = htmlSnippets.find(({ code }) => code === foundCode); - return snippet.html.innerHTML; - }; - const html = this.article.data.content; - return html.replace(/\[code="([\w]+)"\]/gm, replacer); - } else { - return this.article.data.content; - } + return content; }, async toComments() { this.$scrollTo(document.getElementById('comments'), 500, { easing: 'ease' }); diff --git a/spa/src/views/item/EditSnippets.vue b/spa/src/views/item/EditSnippets.vue index b8c61851..31721d55 100644 --- a/spa/src/views/item/EditSnippets.vue +++ b/spa/src/views/item/EditSnippets.vue @@ -2,24 +2,16 @@

{{ $t('page-title.snippets') }}

- - - - {{ $t("generic.save-button") }} - +
+
+ +
-
- {{ errors[0] }} +
+ +
-

{{ $t('cms.snippets.add-label') }}

-
@@ -59,14 +51,38 @@
+
+
+ +
+ +
+ +
+
+ + + + {{ $t("generic.insert-button") }} + + +
+ {{ errors[0] }} +
+