Skip to content

Commit

Permalink
feat(cms): parse vue components in text elements (#744)
Browse files Browse the repository at this point in the history
* feat: (wip) adding capability to parse vue components inside text element in sw cms

* feat: (wip) adding capability to parse vue components inside text element in sw cms - refactor with html-to-vue library

* feat: (wip) Added entities-parser plugin to work with html-to-vue

* feat: (wip) Added entities-parser - moved 'he' dependency from default-theme to nuxt-module

* feat: fixed SSR of CmsElementText.vue, added SwButton and SfLink to extraComponentsMap

* feat: SfButtons from CmsElementText.vue now contains a proper SfLink.
  • Loading branch information
Rigo-m authored May 29, 2020
1 parent b2f2ee7 commit 3b6b5ac
Show file tree
Hide file tree
Showing 9 changed files with 181 additions and 16 deletions.
91 changes: 76 additions & 15 deletions packages/default-theme/cms/elements/CmsElementText.vue
Original file line number Diff line number Diff line change
@@ -1,35 +1,96 @@
<template>
<div v-show="rawHtml" class="cms-element-text">
<div class="cms-element-text__content" v-html="rawHtml"></div>
</div>
</template>

<script>
// import any extra components here
import { SfLink } from '@storefront-ui/vue'
import SwButton from '@shopware-pwa/default-theme/components/atoms/SwButton'
import { renderHtml } from 'html-to-vue'
export default {
components: {},
name: 'CmsElementText',
functional: true,
props: {
content: {
type: Object,
default: () => ({}),
},
},
computed: {
rawHtml() {
return this.content?.data?.content
},
verticalAlign() {
return this.content?.config?.verticalAlign?.value
},
render(h, context) {
const config = {
textTransformer: context.parent.$entitiesDecoder,
extraComponentsMap: {
link: {
conditions(node) {
return (
node.type === 'tag' &&
node.name === 'a' &&
!node.attrs?.class?.match(/btn\s?/)
)
},
renderer(node, children, createElement) {
return createElement(
SfLink,
{
class: node.attrs?.class,
attrs: {
target: node.attrs?.target,
},
props: {
link: node.attrs?.href,
},
},
[...children]
)
},
},
button: {
conditions(node) {
return (
node.type === 'tag' &&
node.name === 'a' &&
node.attrs?.class?.match(/btn\s?/)
)
},
renderer(node, children, createElement) {
const _class = node.attrs?.class.replace('btn-secondary', 'color-secondary').replace('btn-primary', 'color-primary')
return createElement(
SwButton,
{
class: _class,
attrs: {
target: node.attrs?.target,
},
props: {
link: node.attrs?.href,
},
},
[createElement(SfLink, {}, [...children])]
)
},
},
},
}
const rawHtml = context.props.content?.data?.content
return renderHtml(rawHtml, config, h, context)
},
}
</script>
<style lang="scss" scoped>
<style lang="scss">
@import '../settings.scss';
.cms-element-text {
@include sizing-mode-boxed;
padding: var(--spacer-xl);
}
.sf-button {
display: inline-block;
.sf-link {
text-decoration: none;
}
&.btn-sm {
--button-padding: 0.5rem;
}
}
</style>
2 changes: 2 additions & 0 deletions packages/default-theme/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"@storefront-ui/vue": "0.7.16",
"currency.js": "^1.2.2",
"dayjs": "^1.8.25",
"html-to-vue": "^1.2.0",
"node-sass": "^4.14.1",
"nuxt": "^2.12.2",
"sass-loader": "^8.0.2",
Expand All @@ -40,6 +41,7 @@
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-nuxt": ">=0.5.2",
"eslint-plugin-prettier": "^3.1.3",
"husky": "^4.2.5",
"jest": "^25.4.0",
"lint-staged": "^10.1.7",
"prettier": "^2.0.5",
Expand Down
34 changes: 34 additions & 0 deletions packages/nuxt-module/__tests__/module.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,40 @@ describe("nuxt-module - ShopwarePWAModule runModule", () => {
});
});

it("should add entities-parser client plugin", () => {
runModule(moduleObject, {});
const pathForEntitiesParserClientPlugin = path.join(
__dirname,
"..",
"plugins",
"entities-parser",
"entities-parser.csr.js"
);
expect(moduleObject.addPlugin).toBeCalledWith({
fileName: "entities-parser.csr.js",
mode: "client",
options: {},
src: pathForEntitiesParserClientPlugin,
});
});

it("should add entities-parser server plugin", () => {
runModule(moduleObject, {});
const pathForEntitiesParserServerPlugin = path.join(
__dirname,
"..",
"plugins",
"entities-parser",
"entities-parser.ssr.js"
);
expect(moduleObject.addPlugin).toBeCalledWith({
fileName: "entities-parser.ssr.js",
mode: "server",
options: {},
src: pathForEntitiesParserServerPlugin,
});
});

it("should show console error when shopwareEndpoint contains api endpoint instead of just domain", () => {
jest.resetAllMocks();

Expand Down
1 change: 1 addition & 0 deletions packages/nuxt-module/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"@nuxt/utils": "^2.12.2",
"cookie-universal": "^2.1.3",
"fs-jetpack": "^2.2.3",
"he": "^1.2.0",
"path": "^0.12.7",
"snyk": "^1.316.1",
"universal-analytics": "^0.4.20",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import Vue from "vue";

let decoder;
Vue.prototype.$entitiesDecoder = (text) => {
decoder = decoder || document.createElement("div");
decoder.innerHTML = text;
return decoder.textContent;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { decode } from "he";
import Vue from "vue";

Vue.prototype.$entitiesDecoder = (html) => decode(html);
export default ({ app }, inject) => {
// Set the function directly on the context.app object
app.$entitiesDecoder = (html) => decode(html);
};
7 changes: 6 additions & 1 deletion packages/nuxt-module/src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@ export interface NuxtModuleOptions extends ModuleThis {
};
};
addLayout: (options: { src: string }, templateName: string) => void;
addPlugin: (options: { src: string; fileName: string; options: {} }) => void;
addPlugin: (options: {
src: string;
fileName: string;
mode?: string;
options: {};
}) => void;
extendRoutes: (method: Function) => void;
extendBuild: (method: Function) => void;
nuxt: any;
Expand Down
27 changes: 27 additions & 0 deletions packages/nuxt-module/src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,38 @@ export function runModule(moduleObject: NuxtModuleOptions, moduleOptions: {}) {
options: moduleOptions,
});

moduleObject.addPlugin({
src: path.join(
__dirname,
"..",
"plugins",
"entities-parser",
"entities-parser.csr.js"
),
fileName: "entities-parser.csr.js",
mode: "client",
options: moduleOptions,
});

moduleObject.addPlugin({
src: path.join(
__dirname,
"..",
"plugins",
"entities-parser",
"entities-parser.ssr.js"
),
fileName: "entities-parser.ssr.js",
mode: "server",
options: {},
});

moduleObject.addPlugin({
src: path.join(__dirname, "..", "plugins", "composition-api.js"),
fileName: "composition-api.js",
options: moduleOptions,
});

// fixes problem with multiple composition-api instances
moduleObject.extendBuild((config: WebpackConfig) => {
config.resolve.alias["@vue/composition-api"] = path.resolve(
Expand Down
19 changes: 19 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8896,11 +8896,25 @@ html-minifier@^4.0.0:
relateurl "^0.2.7"
uglify-js "^3.5.1"

html-parse-stringify2@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/html-parse-stringify2/-/html-parse-stringify2-2.0.1.tgz#dc5670b7292ca158b7bc916c9a6735ac8872834a"
integrity sha1-3FZwtyksoVi3vJFsmmc1rIhyg0o=
dependencies:
void-elements "^2.0.1"

html-tags@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-2.0.0.tgz#10b30a386085f43cede353cc8fa7cb0deeea668b"
integrity sha1-ELMKOGCF9Dzt41PMj6fLDe7qZos=

html-to-vue@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/html-to-vue/-/html-to-vue-1.2.0.tgz#d123f37f78cc944d67161bc5610bb8563dedbf22"
integrity sha512-x0rcwxsv+Vqz3bUYYw4fwsfzFB25xSH8/LcRQyInVwqXcdmxx3ak3ckX3FW//pDwublPBWVfkjnBWzcfNird4Q==
dependencies:
html-parse-stringify2 "^2.0.1"

html-webpack-plugin@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz#b01abbd723acaaa7b37b6af4492ebda03d9dd37b"
Expand Down Expand Up @@ -17119,6 +17133,11 @@ vm-browserify@^1.0.1:
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==

void-elements@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec"
integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=

vscode-languageserver-types@^3.5.0:
version "3.15.1"
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.15.1.tgz#17be71d78d2f6236d414f0001ce1ef4d23e6b6de"
Expand Down

1 comment on commit 3b6b5ac

@vercel
Copy link

@vercel vercel bot commented on 3b6b5ac May 29, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.