mirror of
https://github.com/tenrok/vue-meta.git
synced 2026-05-17 20:39:37 +03:00
@@ -1,4 +1,5 @@
|
||||
import deepmerge from 'deepmerge'
|
||||
import isArray from './isArray'
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
let data = $options[option]
|
||||
|
||||
// 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
|
||||
result = deepmerge(result, data, { arrayMerge })
|
||||
if (isArray(data)) {
|
||||
result = data.reduce((result, dataItem) => mergeDataInResult(dataItem, result, component, arrayMerge), result)
|
||||
} else {
|
||||
result = data
|
||||
result = mergeDataInResult(data, result, component, arrayMerge)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,3 +62,17 @@ export default function getComponentOption (opts, 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
|
||||
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
|
||||
let batchID = null
|
||||
|
||||
|
||||
@@ -43,19 +43,23 @@ describe('getComponentOption', () => {
|
||||
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', {
|
||||
template: '<div></div>',
|
||||
foo: [
|
||||
{ name: 'flower', content: 'rose' }
|
||||
]
|
||||
foo: {
|
||||
flowers: [
|
||||
{ name: 'flower', content: 'rose' }
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
component = new Vue({
|
||||
render: (h) => h('div', null, [h('array-child')]),
|
||||
foo: [
|
||||
{ name: 'flower', content: 'tulip' }
|
||||
],
|
||||
foo: {
|
||||
flowers: [
|
||||
{ name: 'flower', content: 'tulip' }
|
||||
]
|
||||
},
|
||||
el: container
|
||||
})
|
||||
|
||||
@@ -68,9 +72,64 @@ describe('getComponentOption', () => {
|
||||
}
|
||||
})
|
||||
|
||||
expect(mergedOption).to.eql([
|
||||
{ name: 'flower', content: 'tulip' },
|
||||
{ name: 'flower', content: 'rose' }
|
||||
])
|
||||
expect(mergedOption).to.eql({
|
||||
flowers: [
|
||||
{ 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)
|
||||
|
||||
// define optionMergeStrategies for the keyName
|
||||
Vue.config.optionMergeStrategies[VUE_META_KEY_NAME] = Vue.config.optionMergeStrategies.created
|
||||
|
||||
describe('getMetaInfo', () => {
|
||||
// const container = document.createElement('div')
|
||||
let component
|
||||
@@ -530,4 +533,92 @@ describe('getMetaInfo', () => {
|
||||
__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()
|
||||
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