mirror of
https://github.com/tenrok/vue-meta.git
synced 2026-06-24 07:40:35 +03:00
chore(release): 2.1.0
This commit is contained in:
@@ -2,6 +2,36 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||||
|
|
||||||
|
## [2.1.0](https://github.com/nuxt/vue-meta/compare/v2.0.3...v2.1.0) (2019-07-24)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add warning for v1 boolean attribute syntax ([bfeab17](https://github.com/nuxt/vue-meta/commit/bfeab17))
|
||||||
|
* also use ssrAppId for client update ([50c0509](https://github.com/nuxt/vue-meta/commit/50c0509))
|
||||||
|
* don't generate <title> tag if metaInfo.title is null or false ([#409](https://github.com/nuxt/vue-meta/issues/409)) ([39ef287](https://github.com/nuxt/vue-meta/commit/39ef287))
|
||||||
|
* dont change title when value is undefined (fix [#396](https://github.com/nuxt/vue-meta/issues/396)) ([90f9710](https://github.com/nuxt/vue-meta/commit/90f9710))
|
||||||
|
* dont update title on client with falsy value except empty string ([6efcdf1](https://github.com/nuxt/vue-meta/commit/6efcdf1))
|
||||||
|
* ensure hasAttribute exists on $root.$el ([f1511ac](https://github.com/nuxt/vue-meta/commit/f1511ac))
|
||||||
|
* only show boolean attrs with truthy value ([1d9072a](https://github.com/nuxt/vue-meta/commit/1d9072a))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add option for prepending (no)script to body ([#410](https://github.com/nuxt/vue-meta/issues/410)) ([05163a7](https://github.com/nuxt/vue-meta/commit/05163a7))
|
||||||
|
* auto add ssrAttribute to htmlAttrs ([9cf6d32](https://github.com/nuxt/vue-meta/commit/9cf6d32))
|
||||||
|
* enable onload callbacks ([#414](https://github.com/nuxt/vue-meta/issues/414)) ([fc71e1f](https://github.com/nuxt/vue-meta/commit/fc71e1f))
|
||||||
|
* make ssr app id configurable ([b0c85e5](https://github.com/nuxt/vue-meta/commit/b0c85e5))
|
||||||
|
* support json content (without disabling sanitizers) ([#415](https://github.com/nuxt/vue-meta/issues/415)) ([51fe6ea](https://github.com/nuxt/vue-meta/commit/51fe6ea))
|
||||||
|
|
||||||
|
|
||||||
|
### Tests
|
||||||
|
|
||||||
|
* enable all getMetaInfo tests again ([24d7fee](https://github.com/nuxt/vue-meta/commit/24d7fee))
|
||||||
|
* update browser config ([8c35863](https://github.com/nuxt/vue-meta/commit/8c35863))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### [2.0.5](https://github.com/nuxt/vue-meta/compare/v2.0.3...v2.0.5) (2019-07-11)
|
### [2.0.5](https://github.com/nuxt/vue-meta/compare/v2.0.3...v2.0.5) (2019-07-11)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Vendored
+766
-645
File diff suppressed because it is too large
Load Diff
Vendored
+307
-74
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* vue-meta v2.0.5
|
* vue-meta v2.1.0
|
||||||
* (c) 2019
|
* (c) 2019
|
||||||
* - Declan de Wet
|
* - Declan de Wet
|
||||||
* - Sébastien Chopin (@Atinux)
|
* - Sébastien Chopin (@Atinux)
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
import deepmerge from 'deepmerge';
|
import deepmerge from 'deepmerge';
|
||||||
|
|
||||||
var version = "2.0.5";
|
var version = "2.1.0";
|
||||||
|
|
||||||
// store an id to keep track of DOM updates
|
// store an id to keep track of DOM updates
|
||||||
let batchId = null;
|
let batchId = null;
|
||||||
@@ -62,6 +62,10 @@ function isObject (arg) {
|
|||||||
return typeof arg === 'object'
|
return typeof arg === 'object'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isPureObject (arg) {
|
||||||
|
return typeof arg === 'object' && arg !== null
|
||||||
|
}
|
||||||
|
|
||||||
function isFunction (arg) {
|
function isFunction (arg) {
|
||||||
return typeof arg === 'function'
|
return typeof arg === 'function'
|
||||||
}
|
}
|
||||||
@@ -122,6 +126,31 @@ function addNavGuards (vm) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hasGlobalWindowFn () {
|
||||||
|
try {
|
||||||
|
return !isUndefined(window)
|
||||||
|
} catch (e) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasGlobalWindow = hasGlobalWindowFn();
|
||||||
|
|
||||||
|
const _global = hasGlobalWindow ? window : global;
|
||||||
|
|
||||||
|
const console = (_global.console = _global.console || {});
|
||||||
|
|
||||||
|
function warn (...args) {
|
||||||
|
/* istanbul ignore next */
|
||||||
|
if (!console || !console.warn) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
console.warn(...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const showWarningNotSupported = () => warn('This vue app/component has no vue-meta configuration');
|
||||||
|
|
||||||
let appId = 1;
|
let appId = 1;
|
||||||
|
|
||||||
function createMixin (Vue, options) {
|
function createMixin (Vue, options) {
|
||||||
@@ -136,7 +165,7 @@ function createMixin (Vue, options) {
|
|||||||
get () {
|
get () {
|
||||||
// Show deprecation warning once when devtools enabled
|
// Show deprecation warning once when devtools enabled
|
||||||
if (Vue.config.devtools && !this.$root._vueMeta.hasMetaInfoDeprecationWarningShown) {
|
if (Vue.config.devtools && !this.$root._vueMeta.hasMetaInfoDeprecationWarningShown) {
|
||||||
console.warn('VueMeta DeprecationWarning: _hasMetaInfo has been deprecated and will be removed in a future version. Please use hasMetaInfo(vm) instead'); // eslint-disable-line no-console
|
warn('VueMeta DeprecationWarning: _hasMetaInfo has been deprecated and will be removed in a future version. Please use hasMetaInfo(vm) instead');
|
||||||
this.$root._vueMeta.hasMetaInfoDeprecationWarningShown = true;
|
this.$root._vueMeta.hasMetaInfoDeprecationWarningShown = true;
|
||||||
}
|
}
|
||||||
return hasMetaInfo(this)
|
return hasMetaInfo(this)
|
||||||
@@ -198,7 +227,7 @@ function createMixin (Vue, options) {
|
|||||||
// if this Vue-app was server rendered, set the appId to 'ssr'
|
// if this Vue-app was server rendered, set the appId to 'ssr'
|
||||||
// only one SSR app per page is supported
|
// only one SSR app per page is supported
|
||||||
if (this.$root.$el && this.$root.$el.hasAttribute && this.$root.$el.hasAttribute('data-server-rendered')) {
|
if (this.$root.$el && this.$root.$el.hasAttribute && this.$root.$el.hasAttribute('data-server-rendered')) {
|
||||||
this.$root._vueMeta.appId = 'ssr';
|
this.$root._vueMeta.appId = options.ssrAppId;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -320,13 +349,17 @@ const metaTemplateKeyName = 'template';
|
|||||||
// This is the key name for the content-holding property
|
// This is the key name for the content-holding property
|
||||||
const contentKeyName = 'content';
|
const contentKeyName = 'content';
|
||||||
|
|
||||||
|
// The id used for the ssr app
|
||||||
|
const ssrAppId = 'ssr';
|
||||||
|
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
keyName,
|
keyName,
|
||||||
attribute,
|
attribute,
|
||||||
ssrAttribute,
|
ssrAttribute,
|
||||||
tagIDKeyName,
|
tagIDKeyName,
|
||||||
contentKeyName,
|
contentKeyName,
|
||||||
metaTemplateKeyName
|
metaTemplateKeyName,
|
||||||
|
ssrAppId
|
||||||
};
|
};
|
||||||
|
|
||||||
// List of metaInfo property keys which are configuration options (and dont generate html)
|
// List of metaInfo property keys which are configuration options (and dont generate html)
|
||||||
@@ -351,6 +384,12 @@ const metaInfoAttributeKeys = [
|
|||||||
'bodyAttrs'
|
'bodyAttrs'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// HTML elements which support the onload event
|
||||||
|
const tagsSupportingOnload = ['link', 'style', 'script'];
|
||||||
|
|
||||||
|
// Attributes which should be added with data- prefix
|
||||||
|
const commonDataAttributes = ['body', 'pbody'];
|
||||||
|
|
||||||
// from: https://github.com/kangax/html-minifier/blob/gh-pages/src/htmlminifier.js#L202
|
// from: https://github.com/kangax/html-minifier/blob/gh-pages/src/htmlminifier.js#L202
|
||||||
const booleanHtmlAttributes = [
|
const booleanHtmlAttributes = [
|
||||||
'allowfullscreen',
|
'allowfullscreen',
|
||||||
@@ -397,9 +436,6 @@ const booleanHtmlAttributes = [
|
|||||||
'visible'
|
'visible'
|
||||||
];
|
];
|
||||||
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
const showWarningNotSupported = () => console.warn('This vue app/component has no vue-meta configuration');
|
|
||||||
|
|
||||||
function setOptions (options) {
|
function setOptions (options) {
|
||||||
// combine options
|
// combine options
|
||||||
options = isObject(options) ? options : {};
|
options = isObject(options) ? options : {};
|
||||||
@@ -489,7 +525,7 @@ const clientSequences = [
|
|||||||
// sanitizes potentially dangerous characters
|
// sanitizes potentially dangerous characters
|
||||||
function escape (info, options, escapeOptions) {
|
function escape (info, options, escapeOptions) {
|
||||||
const { tagIDKeyName } = options;
|
const { tagIDKeyName } = options;
|
||||||
const { doEscape = v => v } = escapeOptions;
|
const { doEscape = v => v, escapeKeys } = escapeOptions;
|
||||||
const escaped = {};
|
const escaped = {};
|
||||||
|
|
||||||
for (const key in info) {
|
for (const key in info) {
|
||||||
@@ -523,15 +559,25 @@ function escape (info, options, escapeOptions) {
|
|||||||
escaped[key] = doEscape(value);
|
escaped[key] = doEscape(value);
|
||||||
} else if (isArray(value)) {
|
} else if (isArray(value)) {
|
||||||
escaped[key] = value.map((v) => {
|
escaped[key] = value.map((v) => {
|
||||||
return isObject(v)
|
if (isPureObject(v)) {
|
||||||
? escape(v, options, escapeOptions)
|
return escape(v, options, { ...escapeOptions, escapeKeys: true })
|
||||||
: doEscape(v)
|
}
|
||||||
|
|
||||||
|
return doEscape(v)
|
||||||
});
|
});
|
||||||
} else if (isObject(value)) {
|
} else if (isPureObject(value)) {
|
||||||
escaped[key] = escape(value, options, escapeOptions);
|
escaped[key] = escape(value, options, { ...escapeOptions, escapeKeys: true });
|
||||||
} else {
|
} else {
|
||||||
escaped[key] = value;
|
escaped[key] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (escapeKeys) {
|
||||||
|
const escapedKey = doEscape(key);
|
||||||
|
if (key !== escapedKey) {
|
||||||
|
escaped[escapedKey] = escaped[key];
|
||||||
|
delete escaped[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return escaped
|
return escaped
|
||||||
@@ -614,9 +660,8 @@ function merge (target, source, options = {}) {
|
|||||||
|
|
||||||
for (const key in source[attrKey]) {
|
for (const key in source[attrKey]) {
|
||||||
if (source[attrKey].hasOwnProperty(key) && source[attrKey][key] === undefined) {
|
if (source[attrKey].hasOwnProperty(key) && source[attrKey][key] === undefined) {
|
||||||
if (booleanHtmlAttributes.includes(key)) {
|
if (includes(booleanHtmlAttributes, key)) {
|
||||||
// eslint-disable-next-line no-console
|
warn('VueMeta: Please note that since v2 the value undefined is not used to indicate boolean attributes anymore, see migration guide for details');
|
||||||
console.warn('VueMeta: Please note that since v2 the value undefined is not used to indicate boolean attributes anymore, see migration guide for details');
|
|
||||||
}
|
}
|
||||||
delete source[attrKey][key];
|
delete source[attrKey][key];
|
||||||
}
|
}
|
||||||
@@ -750,6 +795,141 @@ function getMetaInfo (options = {}, component, escapeSequences = []) {
|
|||||||
return info
|
return info
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getTag (tags, tag) {
|
||||||
|
if (!tags[tag]) {
|
||||||
|
tags[tag] = document.getElementsByTagName(tag)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return tags[tag]
|
||||||
|
}
|
||||||
|
|
||||||
|
function getElementsKey ({ body, pbody }) {
|
||||||
|
return body
|
||||||
|
? 'body'
|
||||||
|
: (pbody ? 'pbody' : 'head')
|
||||||
|
}
|
||||||
|
|
||||||
|
function queryElements (parentNode, { appId, attribute, type, tagIDKeyName }, attributes = {}) {
|
||||||
|
const queries = [
|
||||||
|
`${type}[${attribute}="${appId}"]`,
|
||||||
|
`${type}[data-${tagIDKeyName}]`
|
||||||
|
].map((query) => {
|
||||||
|
for (const key in attributes) {
|
||||||
|
const val = attributes[key];
|
||||||
|
const attributeValue = val && val !== true ? `="${val}"` : '';
|
||||||
|
query += `[data-${key}${attributeValue}]`;
|
||||||
|
}
|
||||||
|
return query
|
||||||
|
});
|
||||||
|
|
||||||
|
return toArray(parentNode.querySelectorAll(queries.join(', ')))
|
||||||
|
}
|
||||||
|
|
||||||
|
const callbacks = [];
|
||||||
|
|
||||||
|
function isDOMComplete (d = document) {
|
||||||
|
return d.readyState === 'complete'
|
||||||
|
}
|
||||||
|
|
||||||
|
function addCallback (query, callback) {
|
||||||
|
if (arguments.length === 1) {
|
||||||
|
callback = query;
|
||||||
|
query = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
callbacks.push([ query, callback ]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addCallbacks ({ tagIDKeyName }, type, tags, autoAddListeners) {
|
||||||
|
let hasAsyncCallback = false;
|
||||||
|
|
||||||
|
for (const tag of tags) {
|
||||||
|
if (!tag[tagIDKeyName] || !tag.callback) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
hasAsyncCallback = true;
|
||||||
|
addCallback(`${type}[data-${tagIDKeyName}="${tag[tagIDKeyName]}"]`, tag.callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!autoAddListeners || !hasAsyncCallback) {
|
||||||
|
return hasAsyncCallback
|
||||||
|
}
|
||||||
|
|
||||||
|
return addListeners()
|
||||||
|
}
|
||||||
|
|
||||||
|
function addListeners () {
|
||||||
|
if (isDOMComplete()) {
|
||||||
|
applyCallbacks();
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instead of using a MutationObserver, we just apply
|
||||||
|
/* istanbul ignore next */
|
||||||
|
document.onreadystatechange = () => {
|
||||||
|
applyCallbacks();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyCallbacks (matchElement) {
|
||||||
|
for (const [query, callback] of callbacks) {
|
||||||
|
const selector = `${query}[onload="this.__vm_l=1"]`;
|
||||||
|
|
||||||
|
let elements = [];
|
||||||
|
if (!matchElement) {
|
||||||
|
elements = toArray(document.querySelectorAll(selector));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matchElement && matchElement.matches(selector)) {
|
||||||
|
elements = [matchElement];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const element of elements) {
|
||||||
|
/* __vm_cb: whether the load callback has been called
|
||||||
|
* __vm_l: set by onload attribute, whether the element was loaded
|
||||||
|
* __vm_ev: whether the event listener was added or not
|
||||||
|
*/
|
||||||
|
if (element.__vm_cb) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const onload = () => {
|
||||||
|
/* Mark that the callback for this element has already been called,
|
||||||
|
* this prevents the callback to run twice in some (rare) conditions
|
||||||
|
*/
|
||||||
|
element.__vm_cb = true;
|
||||||
|
|
||||||
|
/* onload needs to be removed because we only need the
|
||||||
|
* attribute after ssr and if we dont remove it the node
|
||||||
|
* will fail isEqualNode on the client
|
||||||
|
*/
|
||||||
|
element.removeAttribute('onload');
|
||||||
|
|
||||||
|
callback(element);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* IE9 doesnt seem to load scripts synchronously,
|
||||||
|
* causing a script sometimes/often already to be loaded
|
||||||
|
* when we add the event listener below (thus adding an onload event
|
||||||
|
* listener has no use because it will never be triggered).
|
||||||
|
* Therefore we add the onload attribute during ssr, and
|
||||||
|
* check here if it was already loaded or not
|
||||||
|
*/
|
||||||
|
if (element.__vm_l) {
|
||||||
|
onload();
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!element.__vm_ev) {
|
||||||
|
element.__vm_ev = true;
|
||||||
|
|
||||||
|
element.addEventListener('load', onload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the document's html tag attributes
|
* Updates the document's html tag attributes
|
||||||
*
|
*
|
||||||
@@ -799,7 +979,7 @@ function updateAttribute ({ attribute } = {}, attrs, tag) {
|
|||||||
* @param {String} title - the new title of the document
|
* @param {String} title - the new title of the document
|
||||||
*/
|
*/
|
||||||
function updateTitle (title) {
|
function updateTitle (title) {
|
||||||
if (title === undefined) {
|
if (!title && title !== '') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -814,11 +994,18 @@ function updateTitle (title) {
|
|||||||
* @param {(Array<Object>|Object)} tags - an array of tag objects or a single object in case of base
|
* @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 {Object} - a representation of what tags changed
|
||||||
*/
|
*/
|
||||||
function updateTag (appId, { attribute, tagIDKeyName } = {}, type, tags, headTag, bodyTag) {
|
function updateTag (appId, options = {}, type, tags, head, body) {
|
||||||
const oldHeadTags = toArray(headTag.querySelectorAll(`${type}[${attribute}="${appId}"], ${type}[data-${tagIDKeyName}]`));
|
const { attribute, tagIDKeyName } = options;
|
||||||
const oldBodyTags = toArray(bodyTag.querySelectorAll(`${type}[${attribute}="${appId}"][data-body="true"], ${type}[data-${tagIDKeyName}][data-body="true"]`));
|
|
||||||
const dataAttributes = [tagIDKeyName, 'body'];
|
const dataAttributes = [tagIDKeyName, ...commonDataAttributes];
|
||||||
const newTags = [];
|
const newElements = [];
|
||||||
|
|
||||||
|
const queryOptions = { appId, attribute, type, tagIDKeyName };
|
||||||
|
const currentElements = {
|
||||||
|
head: queryElements(head, queryOptions),
|
||||||
|
pbody: queryElements(body, queryOptions, { pbody: true }),
|
||||||
|
body: queryElements(body, queryOptions, { body: true })
|
||||||
|
};
|
||||||
|
|
||||||
if (tags.length > 1) {
|
if (tags.length > 1) {
|
||||||
// remove duplicates that could have been found by merging tags
|
// remove duplicates that could have been found by merging tags
|
||||||
@@ -834,74 +1021,107 @@ function updateTag (appId, { attribute, tagIDKeyName } = {}, type, tags, headTag
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (tags.length) {
|
if (tags.length) {
|
||||||
tags.forEach((tag) => {
|
for (const tag of tags) {
|
||||||
const newElement = document.createElement(type);
|
if (tag.skip) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const newElement = document.createElement(type);
|
||||||
newElement.setAttribute(attribute, appId);
|
newElement.setAttribute(attribute, appId);
|
||||||
|
|
||||||
const oldTags = tag.body !== true ? oldHeadTags : oldBodyTags;
|
|
||||||
|
|
||||||
for (const attr in tag) {
|
for (const attr in tag) {
|
||||||
if (tag.hasOwnProperty(attr)) {
|
/* istanbul ignore next */
|
||||||
if (attr === 'innerHTML') {
|
if (!tag.hasOwnProperty(attr)) {
|
||||||
newElement.innerHTML = tag.innerHTML;
|
continue
|
||||||
} else if (attr === 'cssText') {
|
|
||||||
if (newElement.styleSheet) {
|
|
||||||
/* istanbul ignore next */
|
|
||||||
newElement.styleSheet.cssText = tag.cssText;
|
|
||||||
} else {
|
|
||||||
newElement.appendChild(document.createTextNode(tag.cssText));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const _attr = includes(dataAttributes, attr)
|
|
||||||
? `data-${attr}`
|
|
||||||
: attr;
|
|
||||||
|
|
||||||
const isBooleanAttribute = includes(booleanHtmlAttributes, attr);
|
|
||||||
if (isBooleanAttribute && !tag[attr]) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
const value = isBooleanAttribute ? '' : tag[attr];
|
|
||||||
newElement.setAttribute(_attr, value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (attr === 'innerHTML') {
|
||||||
|
newElement.innerHTML = tag.innerHTML;
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attr === 'json') {
|
||||||
|
newElement.innerHTML = JSON.stringify(tag.json);
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attr === 'cssText') {
|
||||||
|
if (newElement.styleSheet) {
|
||||||
|
/* istanbul ignore next */
|
||||||
|
newElement.styleSheet.cssText = tag.cssText;
|
||||||
|
} else {
|
||||||
|
newElement.appendChild(document.createTextNode(tag.cssText));
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attr === 'callback') {
|
||||||
|
newElement.onload = () => tag[attr](newElement);
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const _attr = includes(dataAttributes, attr)
|
||||||
|
? `data-${attr}`
|
||||||
|
: attr;
|
||||||
|
|
||||||
|
const isBooleanAttribute = includes(booleanHtmlAttributes, attr);
|
||||||
|
if (isBooleanAttribute && !tag[attr]) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const value = isBooleanAttribute ? '' : tag[attr];
|
||||||
|
newElement.setAttribute(_attr, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const oldElements = currentElements[getElementsKey(tag)];
|
||||||
|
|
||||||
// Remove a duplicate tag from domTagstoRemove, so it isn't cleared.
|
// Remove a duplicate tag from domTagstoRemove, so it isn't cleared.
|
||||||
let indexToDelete;
|
let indexToDelete;
|
||||||
const hasEqualElement = oldTags.some((existingTag, index) => {
|
const hasEqualElement = oldElements.some((existingTag, index) => {
|
||||||
indexToDelete = index;
|
indexToDelete = index;
|
||||||
return newElement.isEqualNode(existingTag)
|
return newElement.isEqualNode(existingTag)
|
||||||
});
|
});
|
||||||
|
|
||||||
if (hasEqualElement && (indexToDelete || indexToDelete === 0)) {
|
if (hasEqualElement && (indexToDelete || indexToDelete === 0)) {
|
||||||
oldTags.splice(indexToDelete, 1);
|
oldElements.splice(indexToDelete, 1);
|
||||||
} else {
|
} else {
|
||||||
newTags.push(newElement);
|
newElements.push(newElement);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const oldTags = oldHeadTags.concat(oldBodyTags);
|
|
||||||
oldTags.forEach(tag => tag.parentNode.removeChild(tag));
|
|
||||||
newTags.forEach((tag) => {
|
|
||||||
if (tag.getAttribute('data-body') === 'true') {
|
|
||||||
bodyTag.appendChild(tag);
|
|
||||||
} else {
|
|
||||||
headTag.appendChild(tag);
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
return { oldTags, newTags }
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTag (tags, tag) {
|
|
||||||
if (!tags[tag]) {
|
|
||||||
tags[tag] = document.getElementsByTagName(tag)[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return tags[tag]
|
let oldElements = [];
|
||||||
|
for (const current of Object.values(currentElements)) {
|
||||||
|
oldElements = [
|
||||||
|
...oldElements,
|
||||||
|
...current
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove old elements
|
||||||
|
for (const element of oldElements) {
|
||||||
|
element.parentNode.removeChild(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert new elements
|
||||||
|
for (const element of newElements) {
|
||||||
|
if (element.hasAttribute('data-body')) {
|
||||||
|
body.appendChild(element);
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element.hasAttribute('data-pbody')) {
|
||||||
|
body.insertBefore(element, body.firstChild);
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
head.appendChild(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
oldTags: oldElements,
|
||||||
|
newTags: newElements
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -910,7 +1130,7 @@ function getTag (tags, tag) {
|
|||||||
* @param {Object} newInfo - the meta info to update to
|
* @param {Object} newInfo - the meta info to update to
|
||||||
*/
|
*/
|
||||||
function updateClientMetaInfo (appId, options = {}, newInfo) {
|
function updateClientMetaInfo (appId, options = {}, newInfo) {
|
||||||
const { ssrAttribute } = options;
|
const { ssrAttribute, ssrAppId } = options;
|
||||||
|
|
||||||
// only cache tags for current update
|
// only cache tags for current update
|
||||||
const tags = {};
|
const tags = {};
|
||||||
@@ -918,9 +1138,22 @@ function updateClientMetaInfo (appId, options = {}, newInfo) {
|
|||||||
const htmlTag = getTag(tags, 'html');
|
const htmlTag = getTag(tags, 'html');
|
||||||
|
|
||||||
// if this is a server render, then dont update
|
// if this is a server render, then dont update
|
||||||
if (appId === 'ssr' && htmlTag.hasAttribute(ssrAttribute)) {
|
if (appId === ssrAppId && htmlTag.hasAttribute(ssrAttribute)) {
|
||||||
// remove the server render attribute so we can update on (next) changes
|
// remove the server render attribute so we can update on (next) changes
|
||||||
htmlTag.removeAttribute(ssrAttribute);
|
htmlTag.removeAttribute(ssrAttribute);
|
||||||
|
|
||||||
|
// add load callbacks if the
|
||||||
|
let addLoadListeners = false;
|
||||||
|
for (const type of tagsSupportingOnload) {
|
||||||
|
if (newInfo[type] && addCallbacks(options, type, newInfo[type])) {
|
||||||
|
addLoadListeners = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addLoadListeners) {
|
||||||
|
addListeners();
|
||||||
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+766
-645
File diff suppressed because it is too large
Load Diff
Vendored
+727
-621
File diff suppressed because it is too large
Load Diff
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "vue-meta",
|
"name": "vue-meta",
|
||||||
"version": "2.0.5",
|
"version": "2.1.0",
|
||||||
"description": "Manage HTML metadata in Vue.js components with ssr support",
|
"description": "Manage HTML metadata in Vue.js components with ssr support",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"attribute",
|
"attribute",
|
||||||
|
|||||||
Reference in New Issue
Block a user