Files
cssd-back/node_modules/vue-meta/lib/vue-meta.js
T
2019-07-15 13:07:31 +04:30

1343 lines
42 KiB
JavaScript
Vendored

/**
* vue-meta v1.6.0
* (c) 2019 Declan de Wet & Sébastien Chopin (@Atinux)
* @license MIT
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = global || self, global.VueMeta = factory());
}(this, function () { 'use strict';
/*
object-assign
(c) Sindre Sorhus
@license MIT
*/
/* eslint-disable no-unused-vars */
var getOwnPropertySymbols = Object.getOwnPropertySymbols;
var hasOwnProperty = Object.prototype.hasOwnProperty;
var propIsEnumerable = Object.prototype.propertyIsEnumerable;
function toObject(val) {
if (val === null || val === undefined) {
throw new TypeError('Object.assign cannot be called with null or undefined');
}
return Object(val);
}
function shouldUseNative() {
try {
if (!Object.assign) {
return false;
}
// Detect buggy property enumeration order in older V8 versions.
// https://bugs.chromium.org/p/v8/issues/detail?id=4118
var test1 = new String('abc'); // eslint-disable-line no-new-wrappers
test1[5] = 'de';
if (Object.getOwnPropertyNames(test1)[0] === '5') {
return false;
}
// https://bugs.chromium.org/p/v8/issues/detail?id=3056
var test2 = {};
for (var i = 0; i < 10; i++) {
test2['_' + String.fromCharCode(i)] = i;
}
var order2 = Object.getOwnPropertyNames(test2).map(function (n) {
return test2[n];
});
if (order2.join('') !== '0123456789') {
return false;
}
// https://bugs.chromium.org/p/v8/issues/detail?id=3056
var test3 = {};
'abcdefghijklmnopqrst'.split('').forEach(function (letter) {
test3[letter] = letter;
});
if (Object.keys(Object.assign({}, test3)).join('') !==
'abcdefghijklmnopqrst') {
return false;
}
return true;
} catch (err) {
// We don't expect any of the above to throw, but better to be safe.
return false;
}
}
var objectAssign = shouldUseNative() ? Object.assign : function (target, source) {
var arguments$1 = arguments;
var from;
var to = toObject(target);
var symbols;
for (var s = 1; s < arguments.length; s++) {
from = Object(arguments$1[s]);
for (var key in from) {
if (hasOwnProperty.call(from, key)) {
to[key] = from[key];
}
}
if (getOwnPropertySymbols) {
symbols = getOwnPropertySymbols(from);
for (var i = 0; i < symbols.length; i++) {
if (propIsEnumerable.call(from, symbols[i])) {
to[symbols[i]] = from[symbols[i]];
}
}
}
}
return to;
};
var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
function createCommonjsModule(fn, module) {
return module = { exports: {} }, fn(module, module.exports), module.exports;
}
var umd = createCommonjsModule(function (module, exports) {
(function (global, factory) {
module.exports = factory();
}(commonjsGlobal, (function () {
var isMergeableObject = function isMergeableObject(value) {
return isNonNullObject(value)
&& !isSpecial(value)
};
function isNonNullObject(value) {
return !!value && typeof value === 'object'
}
function isSpecial(value) {
var stringValue = Object.prototype.toString.call(value);
return stringValue === '[object RegExp]'
|| stringValue === '[object Date]'
|| isReactElement(value)
}
// see https://github.com/facebook/react/blob/b5ac963fb791d1298e7f396236383bc955f916c1/src/isomorphic/classic/element/ReactElement.js#L21-L25
var canUseSymbol = typeof Symbol === 'function' && Symbol.for;
var REACT_ELEMENT_TYPE = canUseSymbol ? Symbol.for('react.element') : 0xeac7;
function isReactElement(value) {
return value.$$typeof === REACT_ELEMENT_TYPE
}
function emptyTarget(val) {
return Array.isArray(val) ? [] : {}
}
function cloneUnlessOtherwiseSpecified(value, options) {
return (options.clone !== false && options.isMergeableObject(value))
? deepmerge(emptyTarget(value), value, options)
: value
}
function defaultArrayMerge(target, source, options) {
return target.concat(source).map(function(element) {
return cloneUnlessOtherwiseSpecified(element, options)
})
}
function getMergeFunction(key, options) {
if (!options.customMerge) {
return deepmerge
}
var customMerge = options.customMerge(key);
return typeof customMerge === 'function' ? customMerge : deepmerge
}
function mergeObject(target, source, options) {
var destination = {};
if (options.isMergeableObject(target)) {
Object.keys(target).forEach(function(key) {
destination[key] = cloneUnlessOtherwiseSpecified(target[key], options);
});
}
Object.keys(source).forEach(function(key) {
if (!options.isMergeableObject(source[key]) || !target[key]) {
destination[key] = cloneUnlessOtherwiseSpecified(source[key], options);
} else {
destination[key] = getMergeFunction(key, options)(target[key], source[key], options);
}
});
return destination
}
function deepmerge(target, source, options) {
options = options || {};
options.arrayMerge = options.arrayMerge || defaultArrayMerge;
options.isMergeableObject = options.isMergeableObject || isMergeableObject;
var sourceIsArray = Array.isArray(source);
var targetIsArray = Array.isArray(target);
var sourceAndTargetTypesMatch = sourceIsArray === targetIsArray;
if (!sourceAndTargetTypesMatch) {
return cloneUnlessOtherwiseSpecified(source, options)
} else if (sourceIsArray) {
return options.arrayMerge(target, source, options)
} else {
return mergeObject(target, source, options)
}
}
deepmerge.all = function deepmergeAll(array, options) {
if (!Array.isArray(array)) {
throw new Error('first argument should be an array')
}
return array.reduce(function(prev, next) {
return deepmerge(prev, next, options)
}, {})
};
var deepmerge_1 = deepmerge;
return deepmerge_1;
})));
});
/**
* lodash (Custom Build) <https://lodash.com/>
* Build: `lodash modularize exports="npm" -o ./`
* Copyright jQuery Foundation and other contributors <https://jquery.org/>
* Released under MIT license <https://lodash.com/license>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
*/
/** `Object#toString` result references. */
var objectTag = '[object Object]';
/**
* Checks if `value` is a host object in IE < 9.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a host object, else `false`.
*/
function isHostObject(value) {
// Many host objects are `Object` objects that can coerce to strings
// despite having improperly defined `toString` methods.
var result = false;
if (value != null && typeof value.toString != 'function') {
try {
result = !!(value + '');
} catch (e) {}
}
return result;
}
/**
* Creates a unary function that invokes `func` with its argument transformed.
*
* @private
* @param {Function} func The function to wrap.
* @param {Function} transform The argument transform.
* @returns {Function} Returns the new function.
*/
function overArg(func, transform) {
return function(arg) {
return func(transform(arg));
};
}
/** Used for built-in method references. */
var funcProto = Function.prototype,
objectProto = Object.prototype;
/** Used to resolve the decompiled source of functions. */
var funcToString = funcProto.toString;
/** Used to check objects for own properties. */
var hasOwnProperty$1 = objectProto.hasOwnProperty;
/** Used to infer the `Object` constructor. */
var objectCtorString = funcToString.call(Object);
/**
* Used to resolve the
* [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
* of values.
*/
var objectToString = objectProto.toString;
/** Built-in value references. */
var getPrototype = overArg(Object.getPrototypeOf, Object);
/**
* Checks if `value` is object-like. A value is object-like if it's not `null`
* and has a `typeof` result of "object".
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is object-like, else `false`.
* @example
*
* _.isObjectLike({});
* // => true
*
* _.isObjectLike([1, 2, 3]);
* // => true
*
* _.isObjectLike(_.noop);
* // => false
*
* _.isObjectLike(null);
* // => false
*/
function isObjectLike(value) {
return !!value && typeof value == 'object';
}
/**
* Checks if `value` is a plain object, that is, an object created by the
* `Object` constructor or one with a `[[Prototype]]` of `null`.
*
* @static
* @memberOf _
* @since 0.8.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
* @example
*
* function Foo() {
* this.a = 1;
* }
*
* _.isPlainObject(new Foo);
* // => false
*
* _.isPlainObject([1, 2, 3]);
* // => false
*
* _.isPlainObject({ 'x': 0, 'y': 0 });
* // => true
*
* _.isPlainObject(Object.create(null));
* // => true
*/
function isPlainObject(value) {
if (!isObjectLike(value) ||
objectToString.call(value) != objectTag || isHostObject(value)) {
return false;
}
var proto = getPrototype(value);
if (proto === null) {
return true;
}
var Ctor = hasOwnProperty$1.call(proto, 'constructor') && proto.constructor;
return (typeof Ctor == 'function' &&
Ctor instanceof Ctor && funcToString.call(Ctor) == objectCtorString);
}
var lodash_isplainobject = isPlainObject;
/**
* checks if passed argument is an array
* @param {any} arr - the object to check
* @return {Boolean} - true if `arr` is an array
*/
function isArray (arr) {
return Array.isArray
? Array.isArray(arr)
: Object.prototype.toString.call(arr) === '[object Array]'
}
function uniqBy (inputArray, predicate) {
return inputArray
.filter(function (x, i, arr) { return i === arr.length - 1
? true
: predicate(x) !== predicate(arr[i + 1]); }
)
}
/**
* lodash (Custom Build) <https://lodash.com/>
* Build: `lodash modularize exports="npm" -o ./`
* Copyright jQuery Foundation and other contributors <https://jquery.org/>
* Released under MIT license <https://lodash.com/license>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
*/
/** Used as references for various `Number` constants. */
var INFINITY = 1 / 0;
/** `Object#toString` result references. */
var symbolTag = '[object Symbol]';
/** Detect free variable `global` from Node.js. */
var freeGlobal = typeof commonjsGlobal == 'object' && commonjsGlobal && commonjsGlobal.Object === Object && commonjsGlobal;
/** Detect free variable `self`. */
var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
/** Used as a reference to the global object. */
var root = freeGlobal || freeSelf || Function('return this')();
/** Used for built-in method references. */
var objectProto$1 = Object.prototype;
/** Used to generate unique IDs. */
var idCounter = 0;
/**
* Used to resolve the
* [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
* of values.
*/
var objectToString$1 = objectProto$1.toString;
/** Built-in value references. */
var Symbol$1 = root.Symbol;
/** Used to convert symbols to primitives and strings. */
var symbolProto = Symbol$1 ? Symbol$1.prototype : undefined,
symbolToString = symbolProto ? symbolProto.toString : undefined;
/**
* The base implementation of `_.toString` which doesn't convert nullish
* values to empty strings.
*
* @private
* @param {*} value The value to process.
* @returns {string} Returns the string.
*/
function baseToString(value) {
// Exit early for strings to avoid a performance hit in some environments.
if (typeof value == 'string') {
return value;
}
if (isSymbol(value)) {
return symbolToString ? symbolToString.call(value) : '';
}
var result = (value + '');
return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
}
/**
* Checks if `value` is object-like. A value is object-like if it's not `null`
* and has a `typeof` result of "object".
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is object-like, else `false`.
* @example
*
* _.isObjectLike({});
* // => true
*
* _.isObjectLike([1, 2, 3]);
* // => true
*
* _.isObjectLike(_.noop);
* // => false
*
* _.isObjectLike(null);
* // => false
*/
function isObjectLike$1(value) {
return !!value && typeof value == 'object';
}
/**
* Checks if `value` is classified as a `Symbol` primitive or object.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
* @example
*
* _.isSymbol(Symbol.iterator);
* // => true
*
* _.isSymbol('abc');
* // => false
*/
function isSymbol(value) {
return typeof value == 'symbol' ||
(isObjectLike$1(value) && objectToString$1.call(value) == symbolTag);
}
/**
* Converts `value` to a string. An empty string is returned for `null`
* and `undefined` values. The sign of `-0` is preserved.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to process.
* @returns {string} Returns the string.
* @example
*
* _.toString(null);
* // => ''
*
* _.toString(-0);
* // => '-0'
*
* _.toString([1, 2, 3]);
* // => '1,2,3'
*/
function toString(value) {
return value == null ? '' : baseToString(value);
}
/**
* Generates a unique ID. If `prefix` is given, the ID is appended to it.
*
* @static
* @since 0.1.0
* @memberOf _
* @category Util
* @param {string} [prefix=''] The value to prefix the ID with.
* @returns {string} Returns the unique ID.
* @example
*
* _.uniqueId('contact_');
* // => 'contact_104'
*
* _.uniqueId();
* // => '105'
*/
function uniqueId(prefix) {
var id = ++idCounter;
return toString(prefix) + id;
}
var lodash_uniqueid = uniqueId;
/**
* Returns the `opts.option` $option value of the given `opts.component`.
* If methods are encountered, they will be bound to the component context.
* If `opts.deep` is true, will recursively merge all child component
* `opts.option` $option values into the returned result.
*
* @param {Object} opts - options
* @param {Object} opts.component - Vue component to fetch option data from
* @param {String} opts.option - what option to look for
* @param {Boolean} opts.deep - look for data in child components as well?
* @param {Function} opts.arrayMerge - how should arrays be merged?
* @param {Object} [result={}] - result so far
* @return {Object} result - final aggregated result
*/
function getComponentOption (opts, result) {
if ( result === void 0 ) result = {};
var component = opts.component;
var option = opts.option;
var deep = opts.deep;
var arrayMerge = opts.arrayMerge;
var metaTemplateKeyName = opts.metaTemplateKeyName;
var tagIDKeyName = opts.tagIDKeyName;
var contentKeyName = opts.contentKeyName;
var $options = component.$options;
if (component._inactive) { return result }
// only collect option data if it exists
if (typeof $options[option] !== 'undefined' && $options[option] !== null) {
var 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 = umd(result, data, { arrayMerge: arrayMerge });
} else {
result = data;
}
}
// collect & aggregate child options if deep = true
if (deep && component.$children.length) {
component.$children.forEach(function (childComponent) {
result = getComponentOption({
component: childComponent,
option: option,
deep: deep,
arrayMerge: arrayMerge
}, result);
});
}
if (metaTemplateKeyName && result.hasOwnProperty('meta')) {
result.meta = Object.keys(result.meta).map(function (metaKey) {
var metaObject = result.meta[metaKey];
if (!metaObject.hasOwnProperty(metaTemplateKeyName) || !metaObject.hasOwnProperty(contentKeyName) || typeof metaObject[metaTemplateKeyName] === 'undefined') {
return result.meta[metaKey]
}
var template = metaObject[metaTemplateKeyName];
delete metaObject[metaTemplateKeyName];
if (template) {
metaObject.content = typeof template === 'function' ? template(metaObject.content) : template.replace(/%s/g, metaObject.content);
}
return metaObject
});
result.meta = uniqBy(
result.meta,
function (metaObject) { return metaObject.hasOwnProperty(tagIDKeyName) ? metaObject[tagIDKeyName] : lodash_uniqueid(); }
);
}
return result
}
var escapeHTML = function (str) { return typeof window === 'undefined'
// server-side escape sequence
? String(str)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#x27;')
// client-side escape sequence
: String(str)
.replace(/&/g, '\u0026')
.replace(/</g, '\u003c')
.replace(/>/g, '\u003e')
.replace(/"/g, '\u0022')
.replace(/'/g, '\u0027'); };
function _getMetaInfo (options) {
if ( options === void 0 ) options = {};
var keyName = options.keyName;
var tagIDKeyName = options.tagIDKeyName;
var metaTemplateKeyName = options.metaTemplateKeyName;
var contentKeyName = options.contentKeyName;
/**
* Returns the correct meta info for the given component
* (child components will overwrite parent meta info)
*
* @param {Object} component - the Vue instance to get meta info from
* @return {Object} - returned meta info
*/
return function getMetaInfo (component) {
// set some sane defaults
var defaultInfo = {
title: '',
titleChunk: '',
titleTemplate: '%s',
htmlAttrs: {},
bodyAttrs: {},
headAttrs: {},
meta: [],
base: [],
link: [],
style: [],
script: [],
noscript: [],
__dangerouslyDisableSanitizers: [],
__dangerouslyDisableSanitizersByTagID: {}
};
// collect & aggregate all metaInfo $options
var info = getComponentOption({
component: component,
option: keyName,
deep: true,
metaTemplateKeyName: metaTemplateKeyName,
tagIDKeyName: tagIDKeyName,
contentKeyName: contentKeyName,
arrayMerge: function arrayMerge (target, source) {
// we concat the arrays without merging objects contained in,
// but we check for a `vmid` property on each object in the array
// using an O(1) lookup associative array exploit
// note the use of "for in" - we are looping through arrays here, not
// plain objects
var destination = [];
for (var targetIndex in target) {
var targetItem = target[targetIndex];
var shared = false;
for (var sourceIndex in source) {
var sourceItem = source[sourceIndex];
if (targetItem[tagIDKeyName] && targetItem[tagIDKeyName] === sourceItem[tagIDKeyName]) {
var targetTemplate = targetItem[metaTemplateKeyName];
var sourceTemplate = sourceItem[metaTemplateKeyName];
if (targetTemplate && !sourceTemplate) {
sourceItem[contentKeyName] = applyTemplate(component)(targetTemplate)(sourceItem[contentKeyName]);
}
// If template defined in child but content in parent
if (targetTemplate && sourceTemplate && !sourceItem[contentKeyName]) {
sourceItem[contentKeyName] = applyTemplate(component)(sourceTemplate)(targetItem[contentKeyName]);
delete sourceItem[metaTemplateKeyName];
}
shared = true;
break
}
}
if (!shared) {
destination.push(targetItem);
}
}
return destination.concat(source)
}
});
// Remove all "template" tags from meta
// backup the title chunk in case user wants access to it
if (info.title) {
info.titleChunk = info.title;
}
// replace title with populated template
if (info.titleTemplate) {
info.title = applyTemplate(component)(info.titleTemplate)(info.titleChunk || '');
}
// convert base tag to an array so it can be handled the same way
// as the other tags
if (info.base) {
info.base = Object.keys(info.base).length ? [info.base] : [];
}
var ref = info.__dangerouslyDisableSanitizers;
var refByTagID = info.__dangerouslyDisableSanitizersByTagID;
// sanitizes potentially dangerous characters
var escape = function (info) { return Object.keys(info).reduce(function (escaped, key) {
var isDisabled = ref && ref.indexOf(key) > -1;
var tagID = info[tagIDKeyName];
if (!isDisabled && tagID) {
isDisabled = refByTagID && refByTagID[tagID] && refByTagID[tagID].indexOf(key) > -1;
}
var val = info[key];
escaped[key] = val;
if (key === '__dangerouslyDisableSanitizers' || key === '__dangerouslyDisableSanitizersByTagID') {
return escaped
}
if (!isDisabled) {
if (typeof val === 'string') {
escaped[key] = escapeHTML(val);
} else if (lodash_isplainobject(val)) {
escaped[key] = escape(val);
} else if (isArray(val)) {
escaped[key] = val.map(escape);
} else {
escaped[key] = val;
}
} else {
escaped[key] = val;
}
return escaped
}, {}); };
// merge with defaults
info = umd(defaultInfo, info);
// begin sanitization
info = escape(info);
return info
}
}
var applyTemplate = function (component) { return function (template) { return function (chunk) { return typeof template === 'function' ? template.call(component, chunk) : template.replace(/%s/g, chunk); }; }; };
function _titleGenerator (options) {
if ( options === void 0 ) options = {};
var attribute = options.attribute;
/**
* Generates title output for the server
*
* @param {'title'} type - the string "title"
* @param {String} data - the title text
* @return {Object} - the title generator
*/
return function titleGenerator (type, data) {
return {
text: function text () {
return String(data).trim() ? ("<" + type + " " + attribute + "=\"true\">" + data + "</" + type + ">") : ''
}
}
}
}
function _attrsGenerator (options) {
if ( options === void 0 ) options = {};
var attribute = options.attribute;
/**
* Generates tag attributes for use on the server.
*
* @param {('bodyAttrs'|'htmlAttrs'|'headAttrs')} type - the type of attributes to generate
* @param {Object} data - the attributes to generate
* @return {Object} - the attribute generator
*/
return function attrsGenerator (type, data) {
return {
text: function text () {
var attributeStr = '';
var watchedAttrs = [];
for (var attr in data) {
if (data.hasOwnProperty(attr)) {
watchedAttrs.push(attr);
attributeStr += (typeof data[attr] !== 'undefined'
? (attr + "=\"" + (data[attr]) + "\"")
: attr) + " ";
}
}
attributeStr += attribute + "=\"" + (watchedAttrs.join(',')) + "\"";
return attributeStr.trim()
}
}
}
}
function _tagGenerator (options) {
if ( options === void 0 ) options = {};
var attribute = options.attribute;
/**
* Generates meta, base, link, style, script, noscript tags for use on the server
*
* @param {('meta'|'base'|'link'|'style'|'script'|'noscript')} the name of the tag
* @param {(Array<Object>|Object)} tags - an array of tag objects or a single object in case of base
* @return {Object} - the tag generator
*/
return function tagGenerator (type, tags) {
return {
text: function text (ref) {
if ( ref === void 0 ) ref = {};
var body = ref.body; if ( body === void 0 ) body = false;
// build a string containing all tags of this type
return tags.reduce(function (tagsStr, tag) {
if (Object.keys(tag).length === 0) { return tagsStr } // Bail on empty tag object
if (!!tag.body !== body) { return tagsStr }
// build a string containing all attributes of this tag
var attrs = Object.keys(tag).reduce(function (attrsStr, attr) {
switch (attr) {
// these attributes are treated as children on the tag
case 'innerHTML':
case 'cssText':
case 'once':
return attrsStr
// these form the attribute list for this tag
default:
if ([options.tagIDKeyName, 'body'].indexOf(attr) !== -1) {
return (attrsStr + " data-" + attr + "=\"" + (tag[attr]) + "\"")
}
return typeof tag[attr] === 'undefined'
? (attrsStr + " " + attr)
: (attrsStr + " " + attr + "=\"" + (tag[attr]) + "\"")
}
}, '').trim();
// grab child content from one of these attributes, if possible
var content = tag.innerHTML || tag.cssText || '';
// generate tag exactly without any other redundant attribute
var observeTag = tag.once
? ''
: (attribute + "=\"true\" ");
// these tags have no end tag
var hasEndTag = ['base', 'meta', 'link'].indexOf(type) === -1;
// these tag types will have content inserted
var hasContent = hasEndTag && ['noscript', 'script', 'style'].indexOf(type) > -1;
// the final string for this specific tag
return !hasContent
? (tagsStr + "<" + type + " " + observeTag + attrs + (hasEndTag ? '/' : '') + ">")
: (tagsStr + "<" + type + " " + observeTag + attrs + ">" + content + "</" + type + ">")
}, '')
}
}
}
}
function _generateServerInjector (options) {
if ( options === void 0 ) options = {};
/**
* Converts a meta info property to one that can be stringified on the server
*
* @param {String} type - the type of data to convert
* @param {(String|Object|Array<Object>)} data - the data value
* @return {Object} - the new injector
*/
return function generateServerInjector (type, data) {
switch (type) {
case 'title':
return _titleGenerator(options)(type, data)
case 'htmlAttrs':
case 'bodyAttrs':
case 'headAttrs':
return _attrsGenerator(options)(type, data)
default:
return _tagGenerator(options)(type, data)
}
}
}
function _inject (options) {
if ( options === void 0 ) options = {};
/**
* Converts the state of the meta info object such that each item
* can be compiled to a tag string on the server
*
* @this {Object} - Vue instance - ideally the root component
* @return {Object} - server meta info with `toString` methods
*/
return function inject () {
// get meta info with sensible defaults
var info = _getMetaInfo(options)(this.$root);
// generate server injectors
for (var key in info) {
if (info.hasOwnProperty(key) && key !== 'titleTemplate' && key !== 'titleChunk') {
info[key] = _generateServerInjector(options)(key, info[key]);
}
}
return info
}
}
function _updateTitle () {
/**
* Updates the document title
*
* @param {String} title - the new title of the document
*/
return function updateTitle (title) {
if ( title === void 0 ) title = document.title;
document.title = title;
}
}
function _updateTagAttributes (options) {
if ( options === void 0 ) options = {};
var attribute = options.attribute;
/**
* Updates the document's html tag attributes
*
* @param {Object} attrs - the new document html attributes
* @param {HTMLElement} tag - the HTMLElement tag to update with new attrs
*/
return function updateTagAttributes (attrs, tag) {
var vueMetaAttrString = tag.getAttribute(attribute);
var vueMetaAttrs = vueMetaAttrString ? vueMetaAttrString.split(',') : [];
var toRemove = [].concat(vueMetaAttrs);
for (var attr in attrs) {
if (attrs.hasOwnProperty(attr)) {
var val = attrs[attr] || '';
tag.setAttribute(attr, val);
if (vueMetaAttrs.indexOf(attr) === -1) {
vueMetaAttrs.push(attr);
}
var saveIndex = toRemove.indexOf(attr);
if (saveIndex !== -1) {
toRemove.splice(saveIndex, 1);
}
}
}
var i = toRemove.length - 1;
for (; i >= 0; i--) {
tag.removeAttribute(toRemove[i]);
}
if (vueMetaAttrs.length === toRemove.length) {
tag.removeAttribute(attribute);
} else {
tag.setAttribute(attribute, vueMetaAttrs.join(','));
}
}
}
// borrow the slice method
var toArray = Function.prototype.call.bind(Array.prototype.slice);
function _updateTags (options) {
if ( options === void 0 ) options = {};
var attribute = options.attribute;
/**
* Updates meta tags inside <head> and <body> on the client. Borrowed from `react-helmet`:
* https://github.com/nfl/react-helmet/blob/004d448f8de5f823d10f838b02317521180f34da/src/Helmet.js#L195-L245
*
* @param {('meta'|'base'|'link'|'style'|'script'|'noscript')} type - the name of the tag
* @param {(Array<Object>|Object)} tags - an array of tag objects or a single object in case of base
* @return {Object} - a representation of what tags changed
*/
return function updateTags (type, tags, headTag, bodyTag) {
var oldHeadTags = toArray(headTag.querySelectorAll((type + "[" + attribute + "]")));
var oldBodyTags = toArray(bodyTag.querySelectorAll((type + "[" + attribute + "][data-body=\"true\"]")));
var newTags = [];
var indexToDelete;
if (tags.length > 1) {
// remove duplicates that could have been found by merging tags
// which include a mixin with metaInfo and that mixin is used
// by multiple components on the same page
var found = [];
tags = tags.map(function (x) {
var k = JSON.stringify(x);
if (found.indexOf(k) < 0) {
found.push(k);
return x
}
}).filter(function (x) { return x; });
}
if (tags && tags.length) {
tags.forEach(function (tag) {
var newElement = document.createElement(type);
var oldTags = tag.body !== true ? oldHeadTags : oldBodyTags;
for (var attr in tag) {
if (tag.hasOwnProperty(attr)) {
if (attr === 'innerHTML') {
newElement.innerHTML = tag.innerHTML;
} else if (attr === 'cssText') {
if (newElement.styleSheet) {
newElement.styleSheet.cssText = tag.cssText;
} else {
newElement.appendChild(document.createTextNode(tag.cssText));
}
} else if ([options.tagIDKeyName, 'body'].indexOf(attr) !== -1) {
var _attr = "data-" + attr;
var value = (typeof tag[attr] === 'undefined') ? '' : tag[attr];
newElement.setAttribute(_attr, value);
} else {
var value$1 = (typeof tag[attr] === 'undefined') ? '' : tag[attr];
newElement.setAttribute(attr, value$1);
}
}
}
newElement.setAttribute(attribute, 'true');
// Remove a duplicate tag from domTagstoRemove, so it isn't cleared.
if (oldTags.some(function (existingTag, index) {
indexToDelete = index;
return newElement.isEqualNode(existingTag)
})) {
oldTags.splice(indexToDelete, 1);
} else {
newTags.push(newElement);
}
});
}
var oldTags = oldHeadTags.concat(oldBodyTags);
oldTags.forEach(function (tag) { return tag.parentNode.removeChild(tag); });
newTags.forEach(function (tag) {
if (tag.getAttribute('data-body') === 'true') {
bodyTag.appendChild(tag);
} else {
headTag.appendChild(tag);
}
});
return { oldTags: oldTags, newTags: newTags }
}
}
function _updateClientMetaInfo (options) {
if ( options === void 0 ) options = {};
var ssrAttribute = options.ssrAttribute;
/**
* Performs client-side updates when new meta info is received
*
* @param {Object} newInfo - the meta info to update to
*/
return function updateClientMetaInfo (newInfo) {
var htmlTag = document.getElementsByTagName('html')[0];
// if this is not a server render, then update
if (htmlTag.getAttribute(ssrAttribute) === null) {
// initialize tracked changes
var addedTags = {};
var removedTags = {};
Object.keys(newInfo).forEach(function (key) {
switch (key) {
// update the title
case 'title':
_updateTitle(options)(newInfo.title);
break
// update attributes
case 'htmlAttrs':
_updateTagAttributes(options)(newInfo[key], htmlTag);
break
case 'bodyAttrs':
_updateTagAttributes(options)(newInfo[key], document.getElementsByTagName('body')[0]);
break
case 'headAttrs':
_updateTagAttributes(options)(newInfo[key], document.getElementsByTagName('head')[0]);
break
// ignore these
case 'titleChunk':
case 'titleTemplate':
case 'changed':
case '__dangerouslyDisableSanitizers':
break
// catch-all update tags
default:
var headTag = document.getElementsByTagName('head')[0];
var bodyTag = document.getElementsByTagName('body')[0];
var ref = _updateTags(options)(key, newInfo[key], headTag, bodyTag);
var oldTags = ref.oldTags;
var newTags = ref.newTags;
if (newTags.length) {
addedTags[key] = newTags;
removedTags[key] = oldTags;
}
}
});
// emit "event" with new info
if (typeof newInfo.changed === 'function') {
newInfo.changed.call(this, newInfo, addedTags, removedTags);
}
} else {
// remove the server render attribute so we can update on changes
htmlTag.removeAttribute(ssrAttribute);
}
}
}
function _refresh (options) {
if ( options === void 0 ) options = {};
/**
* When called, will update the current meta info with new meta info.
* Useful when updating meta info as the result of an asynchronous
* action that resolves after the initial render takes place.
*
* Credit to [Sébastien Chopin](https://github.com/Atinux) for the suggestion
* to implement this method.
*
* @return {Object} - new meta info
*/
return function refresh () {
var info = _getMetaInfo(options)(this.$root);
_updateClientMetaInfo(options).call(this, info);
return info
}
}
function _$meta (options) {
if ( options === void 0 ) options = {};
/**
* Returns an injector for server-side rendering.
* @this {Object} - the Vue instance (a root component)
* @return {Object} - injector
*/
return function $meta () {
return {
inject: _inject(options).bind(this),
refresh: _refresh(options).bind(this)
}
}
}
// fallback to timers if rAF not present
var stopUpdate = (typeof window !== 'undefined' ? window.cancelAnimationFrame : null) || clearTimeout;
var startUpdate = (typeof window !== 'undefined' ? window.requestAnimationFrame : null) || (function (cb) { return setTimeout(cb, 0); });
/**
* Performs a batched update. Uses requestAnimationFrame to prevent
* calling a function too many times in quick succession.
* You need to pass it an ID (which can initially be `null`),
* but be sure to overwrite that ID with the return value of batchUpdate.
*
* @param {(null|Number)} id - the ID of this update
* @param {Function} callback - the update to perform
* @return {Number} id - a new ID
*/
function batchUpdate (id, callback) {
stopUpdate(id);
return startUpdate(function () {
id = null;
callback();
})
}
/**
* These are constant variables used throughout the application.
*/
// This is the name of the component option that contains all the information that
// gets converted to the various meta tags & attributes for the page.
var VUE_META_KEY_NAME = 'metaInfo';
// This is the attribute vue-meta augments on elements to know which it should
// manage and which it should ignore.
var VUE_META_ATTRIBUTE = 'data-vue-meta';
// This is the attribute that goes on the `html` tag to inform `vue-meta`
// that the server has already generated the meta tags for the initial render.
var VUE_META_SERVER_RENDERED_ATTRIBUTE = 'data-vue-meta-server-rendered';
// This is the property that tells vue-meta to overwrite (instead of append)
// an item in a tag list. For example, if you have two `meta` tag list items
// that both have `vmid` of "description", then vue-meta will overwrite the
// shallowest one with the deepest one.
var VUE_META_TAG_LIST_ID_KEY_NAME = 'vmid';
// This is the key name for possible meta templates
var VUE_META_TEMPLATE_KEY_NAME = 'template';
// This is the key name for the content-holding property
var VUE_META_CONTENT_KEY = 'content';
// automatic install
if (typeof window !== 'undefined' && typeof window.Vue !== 'undefined') {
Vue.use(VueMeta);
}
/**
* Plugin install function.
* @param {Function} Vue - the Vue constructor.
*/
function VueMeta (Vue, options) {
if ( options === void 0 ) options = {};
// set some default options
var defaultOptions = {
keyName: VUE_META_KEY_NAME,
contentKeyName: VUE_META_CONTENT_KEY,
metaTemplateKeyName: VUE_META_TEMPLATE_KEY_NAME,
attribute: VUE_META_ATTRIBUTE,
ssrAttribute: VUE_META_SERVER_RENDERED_ATTRIBUTE,
tagIDKeyName: VUE_META_TAG_LIST_ID_KEY_NAME
};
// combine options
options = objectAssign(defaultOptions, options);
// bind the $meta method to this component instance
Vue.prototype.$meta = _$meta(options);
// store an id to keep track of DOM updates
var batchID = null;
// watch for client side component updates
Vue.mixin({
beforeCreate: function beforeCreate () {
// Add a marker to know if it uses metaInfo
// _vnode is used to know that it's attached to a real component
// useful if we use some mixin to add some meta tags (like nuxt-i18n)
if (typeof this.$options[options.keyName] !== 'undefined') {
this._hasMetaInfo = true;
}
// coerce function-style metaInfo to a computed prop so we can observe
// it on creation
if (typeof this.$options[options.keyName] === 'function') {
if (typeof this.$options.computed === 'undefined') {
this.$options.computed = {};
}
this.$options.computed.$metaInfo = this.$options[options.keyName];
}
},
created: function created () {
var this$1 = this;
// if computed $metaInfo exists, watch it for updates & trigger a refresh
// when it changes (i.e. automatically handle async actions that affect metaInfo)
// credit for this suggestion goes to [Sébastien Chopin](https://github.com/Atinux)
if (!this.$isServer && this.$metaInfo) {
this.$watch('$metaInfo', function () {
// batch potential DOM updates to prevent extraneous re-rendering
batchID = batchUpdate(batchID, function () { return this$1.$meta().refresh(); });
});
}
},
activated: function activated () {
var this$1 = this;
if (this._hasMetaInfo) {
// batch potential DOM updates to prevent extraneous re-rendering
batchID = batchUpdate(batchID, function () { return this$1.$meta().refresh(); });
}
},
deactivated: function deactivated () {
var this$1 = this;
if (this._hasMetaInfo) {
// batch potential DOM updates to prevent extraneous re-rendering
batchID = batchUpdate(batchID, function () { return this$1.$meta().refresh(); });
}
},
beforeMount: function beforeMount () {
var this$1 = this;
// batch potential DOM updates to prevent extraneous re-rendering
if (this._hasMetaInfo) {
batchID = batchUpdate(batchID, function () { return this$1.$meta().refresh(); });
}
},
destroyed: function destroyed () {
var this$1 = this;
// do not trigger refresh on the server side
if (this.$isServer) { return }
// re-render meta data when returning from a child component to parent
if (this._hasMetaInfo) {
// Wait that element is hidden before refreshing meta tags (to support animations)
var interval = setInterval(function () {
if (this$1.$el && this$1.$el.offsetParent !== null) { return }
clearInterval(interval);
if (!this$1.$parent) { return }
batchID = batchUpdate(batchID, function () { return this$1.$meta().refresh(); });
}, 50);
}
}
});
}
var version = "1.6.0";
VueMeta.version = version;
return VueMeta;
}));