mirror of
https://github.com/docsifyjs/docsify.git
synced 2026-10-16 20:21:38 +08:00
update: render Vue templates by default when import vue resources. (#2327)
* update: render vue by default. --------- Co-authored-by: John Hildenbiddle <jhildenbiddle@users.noreply.github.com>
This commit is contained in:
+62
-58
@@ -90,6 +90,7 @@ export function Render(Base) {
|
|||||||
|
|
||||||
// Handle Vue content not mounted by markdown <script>
|
// Handle Vue content not mounted by markdown <script>
|
||||||
if ('Vue' in window) {
|
if ('Vue' in window) {
|
||||||
|
const vueGlobalOptions = docsifyConfig.vueGlobalOptions || {};
|
||||||
const vueMountData = [];
|
const vueMountData = [];
|
||||||
const vueComponentNames = Object.keys(
|
const vueComponentNames = Object.keys(
|
||||||
docsifyConfig.vueComponents || {}
|
docsifyConfig.vueComponents || {}
|
||||||
@@ -109,10 +110,10 @@ export function Render(Base) {
|
|||||||
// Store global data() return value as shared data object
|
// Store global data() return value as shared data object
|
||||||
if (
|
if (
|
||||||
!this.#vueGlobalData &&
|
!this.#vueGlobalData &&
|
||||||
docsifyConfig.vueGlobalOptions &&
|
vueGlobalOptions.data &&
|
||||||
typeof docsifyConfig.vueGlobalOptions.data === 'function'
|
typeof vueGlobalOptions.data === 'function'
|
||||||
) {
|
) {
|
||||||
this.#vueGlobalData = docsifyConfig.vueGlobalOptions.data();
|
this.#vueGlobalData = vueGlobalOptions.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
// vueMounts
|
// vueMounts
|
||||||
@@ -125,64 +126,67 @@ export function Render(Base) {
|
|||||||
.filter(([elm, vueConfig]) => elm)
|
.filter(([elm, vueConfig]) => elm)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Template syntax, vueComponents, vueGlobalOptions
|
// Template syntax, vueComponents, vueGlobalOptions ...
|
||||||
if (docsifyConfig.vueGlobalOptions || vueComponentNames.length) {
|
const reHasBraces = /{{2}[^{}]*}{2}/;
|
||||||
const reHasBraces = /{{2}[^{}]*}{2}/;
|
// Matches Vue full and shorthand syntax as attributes in HTML tags.
|
||||||
// Matches Vue full and shorthand syntax as attributes in HTML tags.
|
//
|
||||||
//
|
// Full syntax examples:
|
||||||
// Full syntax examples:
|
// v-foo, v-foo[bar], v-foo-bar, v-foo:bar-baz.prop
|
||||||
// v-foo, v-foo[bar], v-foo-bar, v-foo:bar-baz.prop
|
//
|
||||||
//
|
// Shorthand syntax examples:
|
||||||
// Shorthand syntax examples:
|
// @foo, @foo.bar, @foo.bar.baz, @[foo], :foo, :[foo]
|
||||||
// @foo, @foo.bar, @foo.bar.baz, @[foo], :foo, :[foo]
|
//
|
||||||
//
|
// Markup examples:
|
||||||
// Markup examples:
|
// <div v-html>{{ html }}</div>
|
||||||
// <div v-html>{{ html }}</div>
|
// <div v-text="msg"></div>
|
||||||
// <div v-text="msg"></div>
|
// <div v-bind:text-content.prop="text">
|
||||||
// <div v-bind:text-content.prop="text">
|
// <button v-on:click="doThis"></button>
|
||||||
// <button v-on:click="doThis"></button>
|
// <button v-on:click.once="doThis"></button>
|
||||||
// <button v-on:click.once="doThis"></button>
|
// <button v-on:[event]="doThis"></button>
|
||||||
// <button v-on:[event]="doThis"></button>
|
// <button @click.stop.prevent="doThis">
|
||||||
// <button @click.stop.prevent="doThis">
|
// <a :href="url">
|
||||||
// <a :href="url">
|
// <a :[key]="url">
|
||||||
// <a :[key]="url">
|
const reHasDirective = /<[^>/]+\s([@:]|v-)[\w-:.[\]]+[=>\s]/;
|
||||||
const reHasDirective = /<[^>/]+\s([@:]|v-)[\w-:.[\]]+[=>\s]/;
|
|
||||||
|
|
||||||
vueMountData.push(
|
vueMountData.push(
|
||||||
...dom
|
...dom
|
||||||
.findAll('.markdown-section > *')
|
.findAll('.markdown-section > *')
|
||||||
// Remove duplicates
|
// Remove duplicates
|
||||||
.filter(elm => !vueMountData.some(([e, c]) => e === elm))
|
.filter(elm => !vueMountData.some(([e, c]) => e === elm))
|
||||||
// Detect Vue content
|
// Detect Vue content
|
||||||
.filter(elm => {
|
.filter(elm => {
|
||||||
const isVueMount =
|
const isVueMount =
|
||||||
// is a component
|
// is a component
|
||||||
elm.tagName.toLowerCase() in
|
elm.tagName.toLowerCase() in
|
||||||
(docsifyConfig.vueComponents || {}) ||
|
(docsifyConfig.vueComponents || {}) ||
|
||||||
// has a component(s)
|
// has a component(s)
|
||||||
elm.querySelector(vueComponentNames.join(',') || null) ||
|
elm.querySelector(vueComponentNames.join(',') || null) ||
|
||||||
// has curly braces
|
// has curly braces
|
||||||
reHasBraces.test(elm.outerHTML) ||
|
reHasBraces.test(elm.outerHTML) ||
|
||||||
// has content directive
|
// has content directive
|
||||||
reHasDirective.test(elm.outerHTML);
|
reHasDirective.test(elm.outerHTML);
|
||||||
|
|
||||||
return isVueMount;
|
return isVueMount;
|
||||||
})
|
})
|
||||||
.map(elm => {
|
.map(elm => {
|
||||||
// Clone global configuration
|
// Clone global configuration
|
||||||
const vueConfig = {
|
const vueConfig = {
|
||||||
...docsifyConfig.vueGlobalOptions,
|
...vueGlobalOptions,
|
||||||
};
|
};
|
||||||
// Replace vueGlobalOptions data() return value with shared data object.
|
// Replace vueGlobalOptions data() return value with shared data object.
|
||||||
// This provides a global store for all Vue instances that receive
|
// This provides a global store for all Vue instances that receive
|
||||||
// vueGlobalOptions as their configuration.
|
// vueGlobalOptions as their configuration.
|
||||||
if (this.#vueGlobalData) {
|
if (this.#vueGlobalData) {
|
||||||
vueConfig.data = () => this.#vueGlobalData;
|
vueConfig.data = () => this.#vueGlobalData;
|
||||||
}
|
}
|
||||||
|
|
||||||
return [elm, vueConfig];
|
return [elm, vueConfig];
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Not found mounts but import Vue resource
|
||||||
|
if (vueMountData.length === 0) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mount
|
// Mount
|
||||||
|
|||||||
+17
-18
@@ -96,6 +96,23 @@ test.describe('Vue.js Compatibility', () => {
|
|||||||
const vueVersion = Number(vueURL.match(/vue(\d+)/)[1]); // 2|3
|
const vueVersion = Number(vueURL.match(/vue(\d+)/)[1]); // 2|3
|
||||||
|
|
||||||
test.describe(`Vue v${vueVersion}`, () => {
|
test.describe(`Vue v${vueVersion}`, () => {
|
||||||
|
test(`Parse templates and render content when import Vue v${vueVersion} resources`, async ({
|
||||||
|
page,
|
||||||
|
}) => {
|
||||||
|
const docsifyInitConfig = {
|
||||||
|
config: {},
|
||||||
|
markdown: {
|
||||||
|
homepage: stripIndent`
|
||||||
|
<div id="vuefor"><span v-for="i in 5">{{ i }}</span></div>
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
docsifyInitConfig.scriptURLs = vueURL;
|
||||||
|
|
||||||
|
await docsifyInit(docsifyInitConfig);
|
||||||
|
await expect(page.locator('#vuefor')).toHaveText('12345');
|
||||||
|
});
|
||||||
for (const executeScript of [true, undefined]) {
|
for (const executeScript of [true, undefined]) {
|
||||||
test(`renders content when executeScript is ${executeScript}`, async ({
|
test(`renders content when executeScript is ${executeScript}`, async ({
|
||||||
page,
|
page,
|
||||||
@@ -147,24 +164,6 @@ test.describe('Vue.js Compatibility', () => {
|
|||||||
await expect(page.locator('#vuescript p')).toHaveText('---');
|
await expect(page.locator('#vuescript p')).toHaveText('---');
|
||||||
});
|
});
|
||||||
|
|
||||||
test(`ignores content when vueComponents, vueMounts, and vueGlobalOptions are undefined`, async ({
|
|
||||||
page,
|
|
||||||
}) => {
|
|
||||||
const docsifyInitConfig = getSharedConfig();
|
|
||||||
|
|
||||||
docsifyInitConfig.config.vueComponents = undefined;
|
|
||||||
docsifyInitConfig.config.vueGlobalOptions = undefined;
|
|
||||||
docsifyInitConfig.config.vueMounts = undefined;
|
|
||||||
docsifyInitConfig.scriptURLs = vueURL;
|
|
||||||
|
|
||||||
await docsifyInit(docsifyInitConfig);
|
|
||||||
await expect(page.locator('#vuefor')).toHaveText('{{ i }}');
|
|
||||||
await expect(page.locator('#vuecomponent')).toHaveText('---');
|
|
||||||
await expect(page.locator('#vueglobaloptions p')).toHaveText('---');
|
|
||||||
await expect(page.locator('#vuemounts p')).toHaveText('---');
|
|
||||||
await expect(page.locator('#vuescript p')).toHaveText('vuescript');
|
|
||||||
});
|
|
||||||
|
|
||||||
test(`ignores content when vueGlobalOptions is undefined`, async ({
|
test(`ignores content when vueGlobalOptions is undefined`, async ({
|
||||||
page,
|
page,
|
||||||
}) => {
|
}) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user