mirror of
https://github.com/tenrok/vue-meta.git
synced 2026-06-17 01:50:33 +03:00
@@ -1,4 +1,5 @@
|
|||||||
import deepmerge from 'deepmerge'
|
import deepmerge from 'deepmerge'
|
||||||
|
import isArray from './isArray'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the `opts.option` $option value of the given `opts.component`.
|
* Returns the `opts.option` $option value of the given `opts.component`.
|
||||||
@@ -24,16 +25,10 @@ export default function getComponentOption (opts, result = {}) {
|
|||||||
if (typeof $options[option] !== 'undefined' && $options[option] !== null) {
|
if (typeof $options[option] !== 'undefined' && $options[option] !== null) {
|
||||||
let data = $options[option]
|
let data = $options[option]
|
||||||
|
|
||||||
// if option is a function, replace it with it's result
|
if (isArray(data)) {
|
||||||
if (typeof data === 'function') {
|
result = data.reduce((result, dataItem) => mergeDataInResult(dataItem, result, component, arrayMerge), result)
|
||||||
data = data.call(component)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof data === 'object') {
|
|
||||||
// merge with existing options
|
|
||||||
result = deepmerge(result, data, { arrayMerge })
|
|
||||||
} else {
|
} else {
|
||||||
result = data
|
result = mergeDataInResult(data, result, component, arrayMerge)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,3 +62,17 @@ export default function getComponentOption (opts, result = {}) {
|
|||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mergeDataInResult (data, result, component, arrayMerge) {
|
||||||
|
// if option is a function, replace it with it's result
|
||||||
|
if (typeof data === 'function') {
|
||||||
|
data = data.call(component)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof data === 'object') {
|
||||||
|
// merge with existing options
|
||||||
|
return deepmerge(result, data, { arrayMerge })
|
||||||
|
} else {
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -35,6 +35,9 @@ export default function VueMeta (Vue, options = {}) {
|
|||||||
// bind the $meta method to this component instance
|
// bind the $meta method to this component instance
|
||||||
Vue.prototype.$meta = $meta(options)
|
Vue.prototype.$meta = $meta(options)
|
||||||
|
|
||||||
|
// define optionMergeStrategies for the keyName
|
||||||
|
Vue.config.optionMergeStrategies[options.keyName] = Vue.config.optionMergeStrategies.created
|
||||||
|
|
||||||
// store an id to keep track of DOM updates
|
// store an id to keep track of DOM updates
|
||||||
let batchID = null
|
let batchID = null
|
||||||
|
|
||||||
|
|||||||
@@ -43,19 +43,23 @@ describe('getComponentOption', () => {
|
|||||||
expect(mergedOption).to.eql({ bar: 'baz', fizz: 'buzz' })
|
expect(mergedOption).to.eql({ bar: 'baz', fizz: 'buzz' })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('allows for a custom array merge strategy', () => {
|
it('allows for a custom array merge strategy in object literal', () => {
|
||||||
Vue.component('array-child', {
|
Vue.component('array-child', {
|
||||||
template: '<div></div>',
|
template: '<div></div>',
|
||||||
foo: [
|
foo: {
|
||||||
{ name: 'flower', content: 'rose' }
|
flowers: [
|
||||||
]
|
{ name: 'flower', content: 'rose' }
|
||||||
|
]
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
component = new Vue({
|
component = new Vue({
|
||||||
render: (h) => h('div', null, [h('array-child')]),
|
render: (h) => h('div', null, [h('array-child')]),
|
||||||
foo: [
|
foo: {
|
||||||
{ name: 'flower', content: 'tulip' }
|
flowers: [
|
||||||
],
|
{ name: 'flower', content: 'tulip' }
|
||||||
|
]
|
||||||
|
},
|
||||||
el: container
|
el: container
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -68,9 +72,64 @@ describe('getComponentOption', () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(mergedOption).to.eql([
|
expect(mergedOption).to.eql({
|
||||||
{ name: 'flower', content: 'tulip' },
|
flowers: [
|
||||||
{ name: 'flower', content: 'rose' }
|
{ name: 'flower', content: 'tulip' },
|
||||||
])
|
{ name: 'flower', content: 'rose' }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('merges arrays of objects literal options', () => {
|
||||||
|
component = new Vue({ someOption: [{ foo: 'hello' }, { bar: 'there' }] })
|
||||||
|
|
||||||
|
const mergedOption = getComponentOption({ component, option: 'someOption' })
|
||||||
|
expect(mergedOption).to.eql({ foo: 'hello', bar: 'there' })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('merges arrays of mixed object literals and functions', () => {
|
||||||
|
component = new Vue({
|
||||||
|
cake: 'good',
|
||||||
|
desserts: [
|
||||||
|
{ yogurt: 'meh' },
|
||||||
|
function someFunction () {
|
||||||
|
return { cake: this.$options.cake }
|
||||||
|
},
|
||||||
|
function someOtherFunction () {
|
||||||
|
return { pineapple: 'not bad' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
const mergedOption = getComponentOption({ component, option: 'desserts' })
|
||||||
|
expect(mergedOption).to.eql({ yogurt: 'meh', cake: 'good', pineapple: 'not bad' })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('uses custom array merge strategy when merging arrays in arrays of options', () => {
|
||||||
|
component = new Vue({
|
||||||
|
template: '<div></div>',
|
||||||
|
foo: [
|
||||||
|
{ cars: [{ brand: 'renault', color: 'red' }] },
|
||||||
|
function someFunction () {
|
||||||
|
return { cars: [{ brand: 'peugeot', color: 'blue' }] }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
const mergedOption = getComponentOption({
|
||||||
|
component,
|
||||||
|
option: 'foo',
|
||||||
|
deep: true,
|
||||||
|
arrayMerge (target, source) {
|
||||||
|
return target.concat(source)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(mergedOption).to.eql({
|
||||||
|
cars: [
|
||||||
|
{ brand: 'renault', color: 'red' },
|
||||||
|
{ brand: 'peugeot', color: 'blue' }
|
||||||
|
]
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ const defaultOptions = {
|
|||||||
|
|
||||||
const getMetaInfo = _getMetaInfo(defaultOptions)
|
const getMetaInfo = _getMetaInfo(defaultOptions)
|
||||||
|
|
||||||
|
// define optionMergeStrategies for the keyName
|
||||||
|
Vue.config.optionMergeStrategies[VUE_META_KEY_NAME] = Vue.config.optionMergeStrategies.created
|
||||||
|
|
||||||
describe('getMetaInfo', () => {
|
describe('getMetaInfo', () => {
|
||||||
// const container = document.createElement('div')
|
// const container = document.createElement('div')
|
||||||
let component
|
let component
|
||||||
@@ -530,4 +533,92 @@ describe('getMetaInfo', () => {
|
|||||||
__dangerouslyDisableSanitizersByTagID: {}
|
__dangerouslyDisableSanitizersByTagID: {}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('properly merges mixins options', () => {
|
||||||
|
const mixin1 = {
|
||||||
|
metaInfo: function () {
|
||||||
|
return {
|
||||||
|
title: 'This title will be overridden',
|
||||||
|
meta: [
|
||||||
|
{
|
||||||
|
vmid: 'og:title',
|
||||||
|
property: 'og:title',
|
||||||
|
content: 'This title will be overridden'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
vmid: 'og:fromMixin1',
|
||||||
|
property: 'og:fromMixin1',
|
||||||
|
content: 'This is from mixin1'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const mixin2 = {
|
||||||
|
metaInfo: {
|
||||||
|
meta: [
|
||||||
|
{
|
||||||
|
vmid: 'og:fromMixin2',
|
||||||
|
property: 'og:fromMixin2',
|
||||||
|
content: 'This is from mixin2'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const component = new Vue({
|
||||||
|
mixins: [mixin1, mixin2],
|
||||||
|
metaInfo: {
|
||||||
|
title: 'New Title',
|
||||||
|
meta: [
|
||||||
|
{
|
||||||
|
vmid: 'og:title',
|
||||||
|
property: 'og:title',
|
||||||
|
content: 'New Title! - My page'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
vmid: 'og:description',
|
||||||
|
property: 'og:description',
|
||||||
|
content: 'Some Description'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
expect(getMetaInfo(component)).to.eql({
|
||||||
|
title: 'New Title',
|
||||||
|
titleChunk: 'New Title',
|
||||||
|
titleTemplate: '%s',
|
||||||
|
htmlAttrs: {},
|
||||||
|
headAttrs: {},
|
||||||
|
bodyAttrs: {},
|
||||||
|
meta: [
|
||||||
|
{
|
||||||
|
vmid: 'og:fromMixin1',
|
||||||
|
property: 'og:fromMixin1',
|
||||||
|
content: 'This is from mixin1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
vmid: 'og:fromMixin2',
|
||||||
|
property: 'og:fromMixin2',
|
||||||
|
content: 'This is from mixin2'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
vmid: 'og:title',
|
||||||
|
property: 'og:title',
|
||||||
|
content: 'New Title! - My page'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
vmid: 'og:description',
|
||||||
|
property: 'og:description',
|
||||||
|
content: 'Some Description'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
base: [],
|
||||||
|
link: [],
|
||||||
|
style: [],
|
||||||
|
script: [],
|
||||||
|
noscript: [],
|
||||||
|
__dangerouslyDisableSanitizers: [],
|
||||||
|
__dangerouslyDisableSanitizersByTagID: {}
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -30,4 +30,9 @@ describe('plugin', () => {
|
|||||||
const vm = new Vue(Component).$mount()
|
const vm = new Vue(Component).$mount()
|
||||||
expect(vm._hasMetaInfo).to.equal(true)
|
expect(vm._hasMetaInfo).to.equal(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('setup optionMergeStrategies for the keyName', () => {
|
||||||
|
const strats = Vue.config.optionMergeStrategies
|
||||||
|
expect(strats[VUE_META_KEY_NAME]).to.equal(strats.created)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user