From 27aaf4744a97a0f26688106e20772be73f0c117e Mon Sep 17 00:00:00 2001 From: pimlie Date: Sun, 26 Jul 2020 00:11:28 +0200 Subject: [PATCH] test: add render tests fix: webpack dev server chore: use eslint not prettier unfeat: remove support for comments (its brokenn in Vue, maybe later) --- .eslintignore | 2 + .eslintrc | 18 + .prettierignore | 5 - .prettierrc | 6 - babel.config.js | 15 +- dist/vue-meta.common.js | 1924 ----- dist/vue-meta.esm.browser.js | 1550 ---- dist/vue-meta.esm.browser.min.js | 10 - dist/vue-meta.esm.js | 1920 ----- dist/vue-meta.js | 1643 ----- dist/vue-meta.min.js | 10 - examples/_static/user-1.js | 8 +- examples/_static/user-2.js | 8 +- examples/_static/user-3.js | 8 +- examples/_static/user-4.js | 8 +- examples/async-callback/app.js | 32 +- examples/basic-render/app.js | 20 +- examples/basic/app.js | 14 +- examples/keep-alive/app.js | 14 +- examples/meta-loader.js | 8 +- examples/multiple-apps/app.js | 28 +- examples/server.js | 6 +- examples/ssr/App.js | 62 +- examples/ssr/server.js | 10 +- examples/vue-router/about.vue | 2 - examples/vue-router/app.js | 102 +- examples/vuex-async/router.js | 4 +- examples/vuex-async/store.js | 34 +- examples/vuex/router.js | 4 +- examples/vuex/store.js | 30 +- examples/webpack.config.js | 96 + jest.config.js | 10 +- package.json | 60 +- src/Metainfo.ts | 39 +- src/config.ts | 45 +- src/config/tags.ts | 36 +- src/global.d.ts | 2 +- src/info/remove.ts | 4 +- src/info/resolve.ts | 2 +- src/info/set.ts | 12 +- src/info/update.ts | 4 +- src/install.ts | 2 +- src/manager.ts | 14 +- src/proxy.ts | 19 +- src/render.ts | 104 +- src/resolvers/deepest.ts | 8 +- src/useApi.ts | 15 +- src/utils/clone.ts | 2 +- test/{ => old}/components/changed.vue | 0 test/{ => old}/components/goodbye-world.vue | 0 test/{ => old}/components/hello-world.vue | 0 test/{ => old}/components/keep-alive.vue | 0 test/{ => old}/e2e/browser.test.js | 0 test/{ => old}/e2e/ssr.test.js | 0 test/{ => old}/fixtures/app.template.html | 0 test/{ => old}/fixtures/basic/App.vue | 0 test/{ => old}/fixtures/basic/client.js | 0 test/{ => old}/fixtures/basic/router.js | 0 test/{ => old}/fixtures/basic/server.js | 0 .../fixtures/basic/static/load-test.js | 0 test/{ => old}/fixtures/basic/views/about.vue | 0 test/{ => old}/fixtures/basic/views/home.vue | 0 test/{ => old}/unit/components.test.js | 0 test/{ => old}/unit/escaping.test.js | 0 test/{ => old}/unit/generators.test.js | 0 .../unit/getComponentOptions.test.js | 0 test/{ => old}/unit/getMetaInfo.test.js | 0 test/{ => old}/unit/load.test.js | 0 test/{ => old}/unit/plugin.test.js | 0 test/{ => old}/unit/shared.test.js | 0 test/{ => old}/unit/updaters.test.js | 0 test/{ => old}/unit/utils.test.js | 0 test/{ => old}/utils/build.js | 0 test/{ => old}/utils/index.js | 0 test/{ => old}/utils/meta-info-data.js | 0 test/old/utils/setup.js | 4 + test/unit/render.test.js | 432 ++ test/utils/setup.js | 4 - webpack.config.js | 98 - yarn.lock | 6377 +++++------------ 80 files changed, 2785 insertions(+), 12109 deletions(-) create mode 100644 .eslintignore create mode 100644 .eslintrc delete mode 100644 .prettierignore delete mode 100644 .prettierrc delete mode 100644 dist/vue-meta.common.js delete mode 100644 dist/vue-meta.esm.browser.js delete mode 100644 dist/vue-meta.esm.browser.min.js delete mode 100644 dist/vue-meta.esm.js delete mode 100644 dist/vue-meta.js delete mode 100644 dist/vue-meta.min.js create mode 100644 examples/webpack.config.js rename test/{ => old}/components/changed.vue (100%) rename test/{ => old}/components/goodbye-world.vue (100%) rename test/{ => old}/components/hello-world.vue (100%) rename test/{ => old}/components/keep-alive.vue (100%) rename test/{ => old}/e2e/browser.test.js (100%) rename test/{ => old}/e2e/ssr.test.js (100%) rename test/{ => old}/fixtures/app.template.html (100%) rename test/{ => old}/fixtures/basic/App.vue (100%) rename test/{ => old}/fixtures/basic/client.js (100%) rename test/{ => old}/fixtures/basic/router.js (100%) rename test/{ => old}/fixtures/basic/server.js (100%) rename test/{ => old}/fixtures/basic/static/load-test.js (100%) rename test/{ => old}/fixtures/basic/views/about.vue (100%) rename test/{ => old}/fixtures/basic/views/home.vue (100%) rename test/{ => old}/unit/components.test.js (100%) rename test/{ => old}/unit/escaping.test.js (100%) rename test/{ => old}/unit/generators.test.js (100%) rename test/{ => old}/unit/getComponentOptions.test.js (100%) rename test/{ => old}/unit/getMetaInfo.test.js (100%) rename test/{ => old}/unit/load.test.js (100%) rename test/{ => old}/unit/plugin.test.js (100%) rename test/{ => old}/unit/shared.test.js (100%) rename test/{ => old}/unit/updaters.test.js (100%) rename test/{ => old}/unit/utils.test.js (100%) rename test/{ => old}/utils/build.js (100%) rename test/{ => old}/utils/index.js (100%) rename test/{ => old}/utils/meta-info-data.js (100%) create mode 100644 test/old/utils/setup.js create mode 100644 test/unit/render.test.js delete mode 100644 webpack.config.js diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..b2b2512 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +test/old +__build__ diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..9078c4a --- /dev/null +++ b/.eslintrc @@ -0,0 +1,18 @@ +{ + "extends": [ + "@nuxtjs/eslint-config-typescript" + ], + "globals": { + "__DEV__": true + }, + "overrides": [ + { + "files": [ + "examples/**" + ], + "rules": { + "no-console": "off", + } + } + ] +} diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index f416a49..0000000 --- a/.prettierignore +++ /dev/null @@ -1,5 +0,0 @@ -node_modules -__build__ -dist -.vue-meta -_old diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index 12911d3..0000000 --- a/.prettierrc +++ /dev/null @@ -1,6 +0,0 @@ -{ - "semi": false, - "trailingComma": "es5", - "singleQuote": true, - "arrowParens": "avoid" -} diff --git a/babel.config.js b/babel.config.js index 39599a2..fb10d30 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,4 +1,16 @@ module.exports = { + presets: [ + ["@babel/preset-env", { + useBuiltIns: 'usage', + corejs: 3, + targets: { + ie: 9 + } + }] + ], + plugins: [ + "dynamic-import-node" + ], env: { test: { plugins: [ @@ -10,7 +22,8 @@ module.exports = { targets: { node: 'current' } - }] + }], + '@babel/preset-typescript' ], } } diff --git a/dist/vue-meta.common.js b/dist/vue-meta.common.js deleted file mode 100644 index 148b34a..0000000 --- a/dist/vue-meta.common.js +++ /dev/null @@ -1,1924 +0,0 @@ -/** - * vue-meta v2.3.3 - * (c) 2020 - * - Declan de Wet - * - Sébastien Chopin (@Atinux) - * - Pim (@pimlie) - * - All the amazing contributors - * @license MIT - */ - -'use strict'; - -function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } - -var deepmerge = _interopDefault(require('deepmerge')); - -var version = "2.3.3"; - -function _typeof(obj) { - "@babel/helpers - typeof"; - - if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { - _typeof = function (obj) { - return typeof obj; - }; - } else { - _typeof = function (obj) { - return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; - }; - } - - return _typeof(obj); -} - -function _defineProperty(obj, key, value) { - if (key in obj) { - Object.defineProperty(obj, key, { - value: value, - enumerable: true, - configurable: true, - writable: true - }); - } else { - obj[key] = value; - } - - return obj; -} - -function ownKeys(object, enumerableOnly) { - var keys = Object.keys(object); - - if (Object.getOwnPropertySymbols) { - var symbols = Object.getOwnPropertySymbols(object); - if (enumerableOnly) symbols = symbols.filter(function (sym) { - return Object.getOwnPropertyDescriptor(object, sym).enumerable; - }); - keys.push.apply(keys, symbols); - } - - return keys; -} - -function _objectSpread2(target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i] != null ? arguments[i] : {}; - - if (i % 2) { - ownKeys(Object(source), true).forEach(function (key) { - _defineProperty(target, key, source[key]); - }); - } else if (Object.getOwnPropertyDescriptors) { - Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); - } else { - ownKeys(Object(source)).forEach(function (key) { - Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); - }); - } - } - - return target; -} - -function _toConsumableArray(arr) { - return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); -} - -function _arrayWithoutHoles(arr) { - if (Array.isArray(arr)) { - for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; - - return arr2; - } -} - -function _iterableToArray(iter) { - if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); -} - -function _nonIterableSpread() { - throw new TypeError("Invalid attempt to spread non-iterable instance"); -} - -/** - * checks if passed argument is an array - * @param {any} arg - the object to check - * @return {Boolean} - true if `arg` is an array - */ -function isArray(arg) { - return Array.isArray(arg); -} -function isUndefined(arg) { - return typeof arg === 'undefined'; -} -function isObject(arg) { - return _typeof(arg) === 'object'; -} -function isPureObject(arg) { - return _typeof(arg) === 'object' && arg !== null; -} -function isFunction(arg) { - return typeof arg === 'function'; -} -function isString(arg) { - return typeof arg === 'string'; -} - -function hasGlobalWindowFn() { - try { - return !isUndefined(window); - } catch (e) { - return false; - } -} -var hasGlobalWindow = hasGlobalWindowFn(); - -var _global = hasGlobalWindow ? window : global; - -var console = _global.console || {}; -function warn(str) { - /* istanbul ignore next */ - if (!console || !console.warn) { - return; - } - - console.warn(str); -} -var showWarningNotSupported = function showWarningNotSupported() { - return warn('This vue app/component has no vue-meta configuration'); -}; - -/** - * These are constant variables used throughout the application. - */ -// set some sane defaults -var defaultInfo = { - title: undefined, - titleChunk: '', - titleTemplate: '%s', - htmlAttrs: {}, - bodyAttrs: {}, - headAttrs: {}, - base: [], - link: [], - meta: [], - style: [], - script: [], - noscript: [], - __dangerouslyDisableSanitizers: [], - __dangerouslyDisableSanitizersByTagID: {} -}; -var rootConfigKey = '_vueMeta'; // 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 keyName = 'metaInfo'; // This is the attribute vue-meta arguments on elements to know which it should -// manage and which it should ignore. - -var 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 ssrAttribute = '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 tagIDKeyName = 'vmid'; // This is the key name for possible meta templates - -var metaTemplateKeyName = 'template'; // This is the key name for the content-holding property - -var contentKeyName = 'content'; // The id used for the ssr app - -var ssrAppId = 'ssr'; // How long meta update - -var debounceWait = 10; // How long meta update - -var waitOnDestroyed = true; -var defaultOptions = { - keyName: keyName, - attribute: attribute, - ssrAttribute: ssrAttribute, - tagIDKeyName: tagIDKeyName, - contentKeyName: contentKeyName, - metaTemplateKeyName: metaTemplateKeyName, - waitOnDestroyed: waitOnDestroyed, - debounceWait: debounceWait, - ssrAppId: ssrAppId -}; // might be a bit ugly, but minimizes the browser bundles a bit - -var defaultInfoKeys = Object.keys(defaultInfo); // The metaInfo property keys which are used to disable escaping - -var disableOptionKeys = [defaultInfoKeys[12], defaultInfoKeys[13]]; // List of metaInfo property keys which are configuration options (and dont generate html) - -var metaInfoOptionKeys = [defaultInfoKeys[1], defaultInfoKeys[2], 'changed'].concat(disableOptionKeys); // List of metaInfo property keys which only generates attributes and no tags - -var metaInfoAttributeKeys = [defaultInfoKeys[3], defaultInfoKeys[4], defaultInfoKeys[5]]; // HTML elements which support the onload event - -var tagsSupportingOnload = ['link', 'style', 'script']; // HTML elements which dont have a head tag (shortened to our needs) -// see: https://www.w3.org/TR/html52/document-metadata.html - -var tagsWithoutEndTag = ['base', 'meta', 'link']; // HTML elements which can have inner content (shortened to our needs) - -var tagsWithInnerContent = ['noscript', 'script', 'style']; // Attributes which are inserted as childNodes instead of HTMLAttribute - -var tagAttributeAsInnerContent = ['innerHTML', 'cssText', 'json']; -var tagProperties = ['once', 'skip', 'template']; // Attributes which should be added with data- prefix - -var commonDataAttributes = ['body', 'pbody']; // from: https://github.com/kangax/html-minifier/blob/gh-pages/src/htmlminifier.js#L202 - -var booleanHtmlAttributes = ['allowfullscreen', 'amp', 'async', 'autofocus', 'autoplay', 'checked', 'compact', 'controls', 'declare', 'default', 'defaultchecked', 'defaultmuted', 'defaultselected', 'defer', 'disabled', 'enabled', 'formnovalidate', 'hidden', 'indeterminate', 'inert', 'ismap', 'itemscope', 'loop', 'multiple', 'muted', 'nohref', 'noresize', 'noshade', 'novalidate', 'nowrap', 'open', 'pauseonexit', 'readonly', 'required', 'reversed', 'scoped', 'seamless', 'selected', 'sortable', 'truespeed', 'typemustmatch', 'visible']; - -var batchId = null; -function triggerUpdate(_ref, rootVm, hookName) { - var debounceWait = _ref.debounceWait; - - // if an update was triggered during initialization or when an update was triggered by the - // metaInfo watcher, set initialized to null - // then we keep falsy value but know we need to run a triggerUpdate after initialization - if (!rootVm[rootConfigKey].initialized && (rootVm[rootConfigKey].initializing || hookName === 'watcher')) { - rootVm[rootConfigKey].initialized = null; - } - - if (rootVm[rootConfigKey].initialized && !rootVm[rootConfigKey].pausing) { - // batch potential DOM updates to prevent extraneous re-rendering - // eslint-disable-next-line no-void - batchUpdate(function () { - return void rootVm.$meta().refresh(); - }, debounceWait); - } -} -/** - * Performs a batched update. - * - * @param {(null|Number)} id - the ID of this update - * @param {Function} callback - the update to perform - * @return {Number} id - a new ID - */ - -function batchUpdate(callback, timeout) { - timeout = timeout === undefined ? 10 : timeout; - - if (!timeout) { - callback(); - return; - } - - clearTimeout(batchId); - batchId = setTimeout(function () { - callback(); - }, timeout); - return batchId; -} - -/* - * To reduce build size, this file provides simple polyfills without - * overly excessive type checking and without modifying - * the global Array.prototype - * The polyfills are automatically removed in the commonjs build - * Also, only files in client/ & shared/ should use these functions - * files in server/ still use normal js function - */ -function find(array, predicate, thisArg) { - if ( !Array.prototype.find) { - // idx needs to be a Number, for..in returns string - for (var idx = 0; idx < array.length; idx++) { - if (predicate.call(thisArg, array[idx], idx, array)) { - return array[idx]; - } - } - - return; - } - - return array.find(predicate, thisArg); -} -function findIndex(array, predicate, thisArg) { - if ( !Array.prototype.findIndex) { - // idx needs to be a Number, for..in returns string - for (var idx = 0; idx < array.length; idx++) { - if (predicate.call(thisArg, array[idx], idx, array)) { - return idx; - } - } - - return -1; - } - - return array.findIndex(predicate, thisArg); -} -function toArray(arg) { - if ( !Array.from) { - return Array.prototype.slice.call(arg); - } - - return Array.from(arg); -} -function includes(array, value) { - if ( !Array.prototype.includes) { - for (var idx in array) { - if (array[idx] === value) { - return true; - } - } - - return false; - } - - return array.includes(value); -} - -function hasMetaInfo(vm) { - vm = vm || this; - return vm && (vm[rootConfigKey] === true || isObject(vm[rootConfigKey])); -} // a component is in a metaInfo branch when itself has meta info or one of its (grand-)children has - -function inMetaInfoBranch(vm) { - vm = vm || this; - return vm && !isUndefined(vm[rootConfigKey]); -} - -function pause(rootVm, refresh) { - rootVm[rootConfigKey].pausing = true; - return function () { - return resume(rootVm, refresh); - }; -} -function resume(rootVm, refresh) { - rootVm[rootConfigKey].pausing = false; - - if (refresh || refresh === undefined) { - return rootVm.$meta().refresh(); - } -} - -function addNavGuards(rootVm) { - var router = rootVm.$router; // return when nav guards already added or no router exists - - if (rootVm[rootConfigKey].navGuards || !router) { - /* istanbul ignore next */ - return; - } - - rootVm[rootConfigKey].navGuards = true; - router.beforeEach(function (to, from, next) { - pause(rootVm); - next(); - }); - router.afterEach(function () { - rootVm.$nextTick(function () { - var _resume = resume(rootVm), - metaInfo = _resume.metaInfo; - - if (metaInfo && isFunction(metaInfo.afterNavigation)) { - metaInfo.afterNavigation(metaInfo); - } - }); - }); -} - -var appId = 1; -function createMixin(Vue, options) { - // for which Vue lifecycle hooks should the metaInfo be refreshed - var updateOnLifecycleHook = ['activated', 'deactivated', 'beforeMount']; // watch for client side component updates - - return { - beforeCreate: function beforeCreate() { - var _this2 = this; - - var rootKey = '$root'; - var $root = this[rootKey]; - var $options = this.$options; - var devtoolsEnabled = Vue.config.devtools; - Object.defineProperty(this, '_hasMetaInfo', { - configurable: true, - get: function get() { - // Show deprecation warning once when devtools enabled - if (devtoolsEnabled && !$root[rootConfigKey].deprecationWarningShown) { - warn('VueMeta DeprecationWarning: _hasMetaInfo has been deprecated and will be removed in a future version. Please use hasMetaInfo(vm) instead'); - $root[rootConfigKey].deprecationWarningShown = true; - } - - return hasMetaInfo(this); - } - }); // 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 (isUndefined($options[options.keyName]) || $options[options.keyName] === null) { - return; - } - - if (!$root[rootConfigKey]) { - $root[rootConfigKey] = { - appId: appId - }; - appId++; - - if (devtoolsEnabled && $root.$options[options.keyName]) { - // use nextTick so the children should be added to $root - this.$nextTick(function () { - // find the first child that lists fnOptions - var child = find($root.$children, function (c) { - return c.$vnode && c.$vnode.fnOptions; - }); - - if (child && child.$vnode.fnOptions[options.keyName]) { - warn("VueMeta has detected a possible global mixin which adds a ".concat(options.keyName, " property to all Vue components on the page. This could cause severe performance issues. If possible, use $meta().addApp to add meta information instead")); - } - }); - } - } // to speed up updates we keep track of branches which have a component with vue-meta info defined - // if _vueMeta = true it has info, if _vueMeta = false a child has info - - - if (!this[rootConfigKey]) { - this[rootConfigKey] = true; - var parent = this.$parent; - - while (parent && parent !== $root) { - if (isUndefined(parent[rootConfigKey])) { - parent[rootConfigKey] = false; - } - - parent = parent.$parent; - } - } // coerce function-style metaInfo to a computed prop so we can observe - // it on creation - - - if (isFunction($options[options.keyName])) { - $options.computed = $options.computed || {}; - $options.computed.$metaInfo = $options[options.keyName]; - - if (!this.$isServer) { - // 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) - this.$on('hook:created', function () { - this.$watch('$metaInfo', function () { - triggerUpdate(options, this[rootKey], 'watcher'); - }); - }); - } - } // force an initial refresh on page load and prevent other lifecycleHooks - // to triggerUpdate until this initial refresh is finished - // this is to make sure that when a page is opened in an inactive tab which - // has throttled rAF/timers we still immediately set the page title - - - if (isUndefined($root[rootConfigKey].initialized)) { - $root[rootConfigKey].initialized = this.$isServer; - - if (!$root[rootConfigKey].initialized) { - if (!$root[rootConfigKey].initializedSsr) { - $root[rootConfigKey].initializedSsr = true; - this.$on('hook:beforeMount', function () { - var $root = this; // if this Vue-app was server rendered, set the appId to 'ssr' - // only one SSR app per page is supported - - if ($root.$el && $root.$el.nodeType === 1 && $root.$el.hasAttribute('data-server-rendered')) { - $root[rootConfigKey].appId = options.ssrAppId; - } - }); - } // we use the mounted hook here as on page load - - - this.$on('hook:mounted', function () { - var $root = this[rootKey]; - - if (!$root[rootConfigKey].initialized) { - // used in triggerUpdate to check if a change was triggered - // during initialization - $root[rootConfigKey].initializing = true; // refresh meta in nextTick so all child components have loaded - - this.$nextTick(function () { - var _$root$$meta$refresh = $root.$meta().refresh(), - tags = _$root$$meta$refresh.tags, - metaInfo = _$root$$meta$refresh.metaInfo; // After ssr hydration (identifier by tags === false) check - // if initialized was set to null in triggerUpdate. That'd mean - // that during initilazation changes where triggered which need - // to be applied OR a metaInfo watcher was triggered before the - // current hook was called - // (during initialization all changes are blocked) - - - if (tags === false && $root[rootConfigKey].initialized === null) { - this.$nextTick(function () { - return triggerUpdate(options, $root, 'init'); - }); - } - - $root[rootConfigKey].initialized = true; - delete $root[rootConfigKey].initializing; // add the navigation guards if they havent been added yet - // they are needed for the afterNavigation callback - - if (!options.refreshOnceOnNavigation && metaInfo.afterNavigation) { - addNavGuards($root); - } - }); - } - }); // add the navigation guards if requested - - if (options.refreshOnceOnNavigation) { - addNavGuards($root); - } - } - } - - this.$on('hook:destroyed', function () { - var _this = this; - - // do not trigger refresh: - // - when user configured to not wait for transitions on destroyed - // - when the component doesnt have a parent - // - doesnt have metaInfo defined - if (!this.$parent || !hasMetaInfo(this)) { - return; - } - - delete this._hasMetaInfo; - this.$nextTick(function () { - if (!options.waitOnDestroyed || !_this.$el || !_this.$el.offsetParent) { - triggerUpdate(options, _this.$root, 'destroyed'); - return; - } // Wait that element is hidden before refreshing meta tags (to support animations) - - - var interval = setInterval(function () { - if (_this.$el && _this.$el.offsetParent !== null) { - /* istanbul ignore next line */ - return; - } - - clearInterval(interval); - triggerUpdate(options, _this.$root, 'destroyed'); - }, 50); - }); - }); // do not trigger refresh on the server side - - if (this.$isServer) { - /* istanbul ignore next */ - return; - } // no need to add this hooks on server side - - - updateOnLifecycleHook.forEach(function (lifecycleHook) { - _this2.$on("hook:".concat(lifecycleHook), function () { - triggerUpdate(options, this[rootKey], lifecycleHook); - }); - }); - } - }; -} - -function setOptions(options) { - // combine options - options = isObject(options) ? options : {}; // The options are set like this so they can - // be minified by terser while keeping the - // user api intact - // terser --mangle-properties keep_quoted=strict - - /* eslint-disable dot-notation */ - - return { - keyName: options['keyName'] || defaultOptions.keyName, - attribute: options['attribute'] || defaultOptions.attribute, - ssrAttribute: options['ssrAttribute'] || defaultOptions.ssrAttribute, - tagIDKeyName: options['tagIDKeyName'] || defaultOptions.tagIDKeyName, - contentKeyName: options['contentKeyName'] || defaultOptions.contentKeyName, - metaTemplateKeyName: options['metaTemplateKeyName'] || defaultOptions.metaTemplateKeyName, - debounceWait: isUndefined(options['debounceWait']) ? defaultOptions.debounceWait : options['debounceWait'], - waitOnDestroyed: isUndefined(options['waitOnDestroyed']) ? defaultOptions.waitOnDestroyed : options['waitOnDestroyed'], - ssrAppId: options['ssrAppId'] || defaultOptions.ssrAppId, - refreshOnceOnNavigation: !!options['refreshOnceOnNavigation'] - }; - /* eslint-enable dot-notation */ -} -function getOptions(options) { - var optionsCopy = {}; - - for (var key in options) { - optionsCopy[key] = options[key]; - } - - return optionsCopy; -} - -function ensureIsArray(arg, key) { - if (!key || !isObject(arg)) { - return isArray(arg) ? arg : []; - } - - if (!isArray(arg[key])) { - arg[key] = []; - } - - return arg; -} - -var serverSequences = [[/&/g, '&'], [//g, '>'], [/"/g, '"'], [/'/g, ''']]; -var clientSequences = [[/&/g, "&"], [//g, ">"], [/"/g, "\""], [/'/g, "'"]]; // sanitizes potentially dangerous characters - -function escape(info, options, escapeOptions, escapeKeys) { - var tagIDKeyName = options.tagIDKeyName; - var _escapeOptions$doEsca = escapeOptions.doEscape, - doEscape = _escapeOptions$doEsca === void 0 ? function (v) { - return v; - } : _escapeOptions$doEsca; - var escaped = {}; - - for (var key in info) { - var value = info[key]; // no need to escape configuration options - - if (includes(metaInfoOptionKeys, key)) { - escaped[key] = value; - continue; - } // do not use destructuring for disableOptionKeys, it increases transpiled size - // due to var checks while we are guaranteed the structure of the cb - - - var disableKey = disableOptionKeys[0]; - - if (escapeOptions[disableKey] && includes(escapeOptions[disableKey], key)) { - // this info[key] doesnt need to escaped if the option is listed in __dangerouslyDisableSanitizers - escaped[key] = value; - continue; - } - - var tagId = info[tagIDKeyName]; - - if (tagId) { - disableKey = disableOptionKeys[1]; // keys which are listed in __dangerouslyDisableSanitizersByTagID for the current vmid do not need to be escaped - - if (escapeOptions[disableKey] && escapeOptions[disableKey][tagId] && includes(escapeOptions[disableKey][tagId], key)) { - escaped[key] = value; - continue; - } - } - - if (isString(value)) { - escaped[key] = doEscape(value); - } else if (isArray(value)) { - escaped[key] = value.map(function (v) { - if (isPureObject(v)) { - return escape(v, options, escapeOptions, true); - } - - return doEscape(v); - }); - } else if (isPureObject(value)) { - escaped[key] = escape(value, options, escapeOptions, true); - } else { - escaped[key] = value; - } - - if (escapeKeys) { - var escapedKey = doEscape(key); - - if (key !== escapedKey) { - escaped[escapedKey] = escaped[key]; - delete escaped[key]; - } - } - } - - return escaped; -} -function escapeMetaInfo(options, info, escapeSequences) { - escapeSequences = escapeSequences || []; // do not use destructuring for seq, it increases transpiled size - // due to var checks while we are guaranteed the structure of the cb - - var escapeOptions = { - doEscape: function doEscape(value) { - return escapeSequences.reduce(function (val, seq) { - return val.replace(seq[0], seq[1]); - }, value); - } - }; - disableOptionKeys.forEach(function (disableKey, index) { - if (index === 0) { - ensureIsArray(info, disableKey); - } else if (index === 1) { - for (var key in info[disableKey]) { - ensureIsArray(info[disableKey], key); - } - } - - escapeOptions[disableKey] = info[disableKey]; - }); // begin sanitization - - return escape(info, options, escapeOptions); -} - -function applyTemplate(_ref, headObject, template, chunk) { - var component = _ref.component, - metaTemplateKeyName = _ref.metaTemplateKeyName, - contentKeyName = _ref.contentKeyName; - - if (template === true || headObject[metaTemplateKeyName] === true) { - // abort, template was already applied - return false; - } - - if (isUndefined(template) && headObject[metaTemplateKeyName]) { - template = headObject[metaTemplateKeyName]; - headObject[metaTemplateKeyName] = true; - } // return early if no template defined - - - if (!template) { - // cleanup faulty template properties - delete headObject[metaTemplateKeyName]; - return false; - } - - if (isUndefined(chunk)) { - chunk = headObject[contentKeyName]; - } - - headObject[contentKeyName] = isFunction(template) ? template.call(component, chunk) : template.replace(/%s/g, chunk); - return true; -} - -function _arrayMerge(_ref, target, source) { - var component = _ref.component, - tagIDKeyName = _ref.tagIDKeyName, - metaTemplateKeyName = _ref.metaTemplateKeyName, - contentKeyName = _ref.contentKeyName; - // 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 - var destination = []; - - if (!target.length && !source.length) { - return destination; - } - - target.forEach(function (targetItem, targetIndex) { - // no tagID so no need to check for duplicity - if (!targetItem[tagIDKeyName]) { - destination.push(targetItem); - return; - } - - var sourceIndex = findIndex(source, function (item) { - return item[tagIDKeyName] === targetItem[tagIDKeyName]; - }); - var sourceItem = source[sourceIndex]; // source doesnt contain any duplicate vmid's, we can keep targetItem - - if (sourceIndex === -1) { - destination.push(targetItem); - return; - } // when sourceItem explictly defines contentKeyName or innerHTML as undefined, its - // an indication that we need to skip the default behaviour or child has preference over parent - // which means we keep the targetItem and ignore/remove the sourceItem - - - if (contentKeyName in sourceItem && sourceItem[contentKeyName] === undefined || 'innerHTML' in sourceItem && sourceItem.innerHTML === undefined) { - destination.push(targetItem); // remove current index from source array so its not concatenated to destination below - - source.splice(sourceIndex, 1); - return; - } // we now know that targetItem is a duplicate and we should ignore it in favor of sourceItem - // if source specifies null as content then ignore both the target as the source - - - if (sourceItem[contentKeyName] === null || sourceItem.innerHTML === null) { - // remove current index from source array so its not concatenated to destination below - source.splice(sourceIndex, 1); - return; - } // now we only need to check if the target has a template to combine it with the source - - - var targetTemplate = targetItem[metaTemplateKeyName]; - - if (!targetTemplate) { - return; - } - - var sourceTemplate = sourceItem[metaTemplateKeyName]; - - if (!sourceTemplate) { - // use parent template and child content - applyTemplate({ - component: component, - metaTemplateKeyName: metaTemplateKeyName, - contentKeyName: contentKeyName - }, sourceItem, targetTemplate); // set template to true to indicate template was already applied - - sourceItem.template = true; - return; - } - - if (!sourceItem[contentKeyName]) { - // use parent content and child template - applyTemplate({ - component: component, - metaTemplateKeyName: metaTemplateKeyName, - contentKeyName: contentKeyName - }, sourceItem, undefined, targetItem[contentKeyName]); - } - }); - return destination.concat(source); -} -var warningShown = false; -function merge(target, source, options) { - options = options || {}; // remove properties explicitly set to false so child components can - // optionally _not_ overwrite the parents content - // (for array properties this is checked in arrayMerge) - - if (source.title === undefined) { - delete source.title; - } - - metaInfoAttributeKeys.forEach(function (attrKey) { - if (!source[attrKey]) { - return; - } - - for (var key in source[attrKey]) { - if (key in source[attrKey] && source[attrKey][key] === undefined) { - if (includes(booleanHtmlAttributes, key) && !warningShown) { - warn('VueMeta: Please note that since v2 the value undefined is not used to indicate boolean attributes anymore, see migration guide for details'); - warningShown = true; - } - - delete source[attrKey][key]; - } - } - }); - return deepmerge(target, source, { - arrayMerge: function arrayMerge(t, s) { - return _arrayMerge(options, t, s); - } - }); -} - -function getComponentMetaInfo(options, component) { - return getComponentOption(options || {}, component, defaultInfo); -} -/** - * 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 {Boolean} opts.deep - look for data in child components as well? - * @param {Function} opts.arrayMerge - how should arrays be merged? - * @param {String} opts.keyName - the name of the option to look for - * @param {Object} [result={}] - result so far - * @return {Object} result - final aggregated result - */ - -function getComponentOption(options, component, result) { - result = result || {}; - - if (component._inactive) { - return result; - } - - options = options || {}; - var _options = options, - keyName = _options.keyName; - var $metaInfo = component.$metaInfo, - $options = component.$options, - $children = component.$children; // only collect option data if it exists - - if ($options[keyName]) { - // if $metaInfo exists then [keyName] was defined as a function - // and set to the computed prop $metaInfo in the mixin - // using the computed prop should be a small performance increase - // because Vue caches those internally - var data = $metaInfo || $options[keyName]; // only merge data with result when its an object - // eg it could be a function when metaInfo() returns undefined - // dueo to the or statement above - - if (isObject(data)) { - result = merge(result, data, options); - } - } // collect & aggregate child options if deep = true - - - if ($children.length) { - $children.forEach(function (childComponent) { - // check if the childComponent is in a branch - // return otherwise so we dont walk all component branches unnecessarily - if (!inMetaInfoBranch(childComponent)) { - return; - } - - result = getComponentOption(options, childComponent, result); - }); - } - - return result; -} - -var querySelector = function querySelector(arg, el) { - return (el || document).querySelectorAll(arg); -}; -function getTag(tags, tag) { - if (!tags[tag]) { - tags[tag] = document.getElementsByTagName(tag)[0]; - } - - return tags[tag]; -} -function getElementsKey(_ref) { - var body = _ref.body, - pbody = _ref.pbody; - return body ? 'body' : pbody ? 'pbody' : 'head'; -} -function queryElements(parentNode, _ref2, attributes) { - var appId = _ref2.appId, - attribute = _ref2.attribute, - type = _ref2.type, - tagIDKeyName = _ref2.tagIDKeyName; - attributes = attributes || {}; - var queries = ["".concat(type, "[").concat(attribute, "=\"").concat(appId, "\"]"), "".concat(type, "[data-").concat(tagIDKeyName, "]")].map(function (query) { - for (var key in attributes) { - var val = attributes[key]; - var attributeValue = val && val !== true ? "=\"".concat(val, "\"") : ''; - query += "[data-".concat(key).concat(attributeValue, "]"); - } - - return query; - }); - return toArray(querySelector(queries.join(', '), parentNode)); -} -function removeElementsByAppId(_ref3, appId) { - var attribute = _ref3.attribute; - toArray(querySelector("[".concat(attribute, "=\"").concat(appId, "\"]"))).map(function (el) { - return el.remove(); - }); -} -function removeAttribute(el, attributeName) { - el.removeAttribute(attributeName); -} - -var callbacks = []; -function isDOMComplete(d) { - return (d || document).readyState === 'complete'; -} -function addCallback(query, callback) { - if (arguments.length === 1) { - callback = query; - query = ''; - } - - callbacks.push([query, callback]); -} -function addCallbacks(_ref, type, tags, autoAddListeners) { - var tagIDKeyName = _ref.tagIDKeyName; - var hasAsyncCallback = false; - tags.forEach(function (tag) { - if (!tag[tagIDKeyName] || !tag.callback) { - return; - } - - hasAsyncCallback = true; - addCallback("".concat(type, "[data-").concat(tagIDKeyName, "=\"").concat(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 = function () { - applyCallbacks(); - }; -} -function applyCallbacks(matchElement) { - callbacks.forEach(function (args) { - // do not use destructuring for args, it increases transpiled size - // due to var checks while we are guaranteed the structure of the cb - var query = args[0]; - var callback = args[1]; - var selector = "".concat(query, "[onload=\"this.__vm_l=1\"]"); - var elements = []; - - if (!matchElement) { - elements = toArray(querySelector(selector)); - } - - if (matchElement && matchElement.matches(selector)) { - elements = [matchElement]; - } - - elements.forEach(function (element) { - /* __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) { - return; - } - - var onload = function 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 - */ - - removeAttribute(element, '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(); - return; - } - - if (!element.__vm_ev) { - element.__vm_ev = true; - element.addEventListener('load', onload); - } - }); - }); -} - -// instead of adding it to the html - -var attributeMap = {}; -/** - * 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 - */ - -function updateAttribute(appId, options, type, attrs, tag) { - var _ref = options || {}, - attribute = _ref.attribute; - - var vueMetaAttrString = tag.getAttribute(attribute); - - if (vueMetaAttrString) { - attributeMap[type] = JSON.parse(decodeURI(vueMetaAttrString)); - removeAttribute(tag, attribute); - } - - var data = attributeMap[type] || {}; - var toUpdate = []; // remove attributes from the map - // which have been removed for this appId - - for (var attr in data) { - if (data[attr] && appId in data[attr]) { - toUpdate.push(attr); - - if (!attrs[attr]) { - delete data[attr][appId]; - } - } - } - - for (var _attr in attrs) { - var attrData = data[_attr]; - - if (!attrData || attrData[appId] !== attrs[_attr]) { - toUpdate.push(_attr); - - if (attrs[_attr]) { - data[_attr] = data[_attr] || {}; - data[_attr][appId] = attrs[_attr]; - } - } - } - - for (var _i = 0, _toUpdate = toUpdate; _i < _toUpdate.length; _i++) { - var _attr2 = _toUpdate[_i]; - var _attrData = data[_attr2]; - var attrValues = []; - - for (var _appId in _attrData) { - Array.prototype.push.apply(attrValues, [].concat(_attrData[_appId])); - } - - if (attrValues.length) { - var attrValue = includes(booleanHtmlAttributes, _attr2) && attrValues.some(Boolean) ? '' : attrValues.filter(Boolean).join(' '); - tag.setAttribute(_attr2, attrValue); - } else { - removeAttribute(tag, _attr2); - } - } - - attributeMap[type] = data; -} - -/** - * Updates the document title - * - * @param {String} title - the new title of the document - */ -function updateTitle(title) { - if (!title && title !== '') { - return; - } - - document.title = title; -} - -/** - * Updates meta tags inside and 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)} tags - an array of tag objects or a single object in case of base - * @return {Object} - a representation of what tags changed - */ - -function updateTag(appId, options, type, tags, head, body) { - var _ref = options || {}, - attribute = _ref.attribute, - tagIDKeyName = _ref.tagIDKeyName; - - var dataAttributes = commonDataAttributes.slice(); - dataAttributes.push(tagIDKeyName); - var newElements = []; - var queryOptions = { - appId: appId, - attribute: attribute, - type: type, - tagIDKeyName: tagIDKeyName - }; - var currentElements = { - head: queryElements(head, queryOptions), - pbody: queryElements(body, queryOptions, { - pbody: true - }), - body: queryElements(body, queryOptions, { - body: true - }) - }; - - 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.filter(function (x) { - var k = JSON.stringify(x); - var res = !includes(found, k); - found.push(k); - return res; - }); - } - - tags.forEach(function (tag) { - if (tag.skip) { - return; - } - - var newElement = document.createElement(type); - - if (!tag.once) { - newElement.setAttribute(attribute, appId); - } - - Object.keys(tag).forEach(function (attr) { - /* istanbul ignore next */ - if (includes(tagProperties, attr)) { - return; - } - - if (attr === 'innerHTML') { - newElement.innerHTML = tag.innerHTML; - return; - } - - if (attr === 'json') { - newElement.innerHTML = JSON.stringify(tag.json); - return; - } - - if (attr === 'cssText') { - if (newElement.styleSheet) { - /* istanbul ignore next */ - newElement.styleSheet.cssText = tag.cssText; - } else { - newElement.appendChild(document.createTextNode(tag.cssText)); - } - - return; - } - - if (attr === 'callback') { - newElement.onload = function () { - return tag[attr](newElement); - }; - - return; - } - - var _attr = includes(dataAttributes, attr) ? "data-".concat(attr) : attr; - - var isBooleanAttribute = includes(booleanHtmlAttributes, attr); - - if (isBooleanAttribute && !tag[attr]) { - return; - } - - var value = isBooleanAttribute ? '' : tag[attr]; - newElement.setAttribute(_attr, value); - }); - var oldElements = currentElements[getElementsKey(tag)]; // Remove a duplicate tag from domTagstoRemove, so it isn't cleared. - - var indexToDelete; - var hasEqualElement = oldElements.some(function (existingTag, index) { - indexToDelete = index; - return newElement.isEqualNode(existingTag); - }); - - if (hasEqualElement && (indexToDelete || indexToDelete === 0)) { - oldElements.splice(indexToDelete, 1); - } else { - newElements.push(newElement); - } - }); - var oldElements = []; - - for (var _type in currentElements) { - Array.prototype.push.apply(oldElements, currentElements[_type]); - } // remove old elements - - - oldElements.forEach(function (element) { - element.parentNode.removeChild(element); - }); // insert new elements - - newElements.forEach(function (element) { - if (element.hasAttribute('data-body')) { - body.appendChild(element); - return; - } - - if (element.hasAttribute('data-pbody')) { - body.insertBefore(element, body.firstChild); - return; - } - - head.appendChild(element); - }); - return { - oldTags: oldElements, - newTags: newElements - }; -} - -/** - * Performs client-side updates when new meta info is received - * - * @param {Object} newInfo - the meta info to update to - */ - -function updateClientMetaInfo(appId, options, newInfo) { - options = options || {}; - var _options = options, - ssrAttribute = _options.ssrAttribute, - ssrAppId = _options.ssrAppId; // only cache tags for current update - - var tags = {}; - var htmlTag = getTag(tags, 'html'); // if this is a server render, then dont update - - if (appId === ssrAppId && htmlTag.hasAttribute(ssrAttribute)) { - // remove the server render attribute so we can update on (next) changes - removeAttribute(htmlTag, ssrAttribute); // add load callbacks if the - - var addLoadListeners = false; - tagsSupportingOnload.forEach(function (type) { - if (newInfo[type] && addCallbacks(options, type, newInfo[type])) { - addLoadListeners = true; - } - }); - - if (addLoadListeners) { - addListeners(); - } - - return false; - } // initialize tracked changes - - - var tagsAdded = {}; - var tagsRemoved = {}; - - for (var type in newInfo) { - // ignore these - if (includes(metaInfoOptionKeys, type)) { - continue; - } - - if (type === 'title') { - // update the title - updateTitle(newInfo.title); - continue; - } - - if (includes(metaInfoAttributeKeys, type)) { - var tagName = type.substr(0, 4); - updateAttribute(appId, options, type, newInfo[type], getTag(tags, tagName)); - continue; - } // tags should always be an array, ignore if it isnt - - - if (!isArray(newInfo[type])) { - continue; - } - - var _updateTag = updateTag(appId, options, type, newInfo[type], getTag(tags, 'head'), getTag(tags, 'body')), - oldTags = _updateTag.oldTags, - newTags = _updateTag.newTags; - - if (newTags.length) { - tagsAdded[type] = newTags; - tagsRemoved[type] = oldTags; - } - } - - return { - tagsAdded: tagsAdded, - tagsRemoved: tagsRemoved - }; -} - -var appsMetaInfo; -function addApp(rootVm, appId, options) { - return { - set: function set(metaInfo) { - return setMetaInfo(rootVm, appId, options, metaInfo); - }, - remove: function remove() { - return removeMetaInfo(rootVm, appId, options); - } - }; -} -function setMetaInfo(rootVm, appId, options, metaInfo) { - // if a vm exists _and_ its mounted then immediately update - if (rootVm && rootVm.$el) { - return updateClientMetaInfo(appId, options, metaInfo); - } // store for later, the info - // will be set on the first refresh - - - appsMetaInfo = appsMetaInfo || {}; - appsMetaInfo[appId] = metaInfo; -} -function removeMetaInfo(rootVm, appId, options) { - if (rootVm && rootVm.$el) { - var tags = {}; - var _iteratorNormalCompletion = true; - var _didIteratorError = false; - var _iteratorError = undefined; - - try { - for (var _iterator = metaInfoAttributeKeys[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { - var type = _step.value; - var tagName = type.substr(0, 4); - updateAttribute(appId, options, type, {}, getTag(tags, tagName)); - } - } catch (err) { - _didIteratorError = true; - _iteratorError = err; - } finally { - try { - if (!_iteratorNormalCompletion && _iterator.return != null) { - _iterator.return(); - } - } finally { - if (_didIteratorError) { - throw _iteratorError; - } - } - } - - return removeElementsByAppId(options, appId); - } - - if (appsMetaInfo[appId]) { - delete appsMetaInfo[appId]; - clearAppsMetaInfo(); - } -} -function getAppsMetaInfo() { - return appsMetaInfo; -} -function clearAppsMetaInfo(force) { - if (force || !Object.keys(appsMetaInfo).length) { - appsMetaInfo = undefined; - } -} - -/** - * 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 - */ - -function getMetaInfo(options, info, escapeSequences, component) { - options = options || {}; - escapeSequences = escapeSequences || []; - var _options = options, - tagIDKeyName = _options.tagIDKeyName; // 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.titleTemplate !== '%s') { - applyTemplate({ - component: component, - contentKeyName: 'title' - }, info, 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] : []; - } - - if (info.meta) { - // remove meta items with duplicate vmid's - info.meta = info.meta.filter(function (metaItem, index, arr) { - var hasVmid = !!metaItem[tagIDKeyName]; - - if (!hasVmid) { - return true; - } - - var isFirstItemForVmid = index === findIndex(arr, function (item) { - return item[tagIDKeyName] === metaItem[tagIDKeyName]; - }); - return isFirstItemForVmid; - }); // apply templates if needed - - info.meta.forEach(function (metaObject) { - return applyTemplate(options, metaObject); - }); - } - - return escapeMetaInfo(options, info, escapeSequences); -} - -/** - * 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 - */ - -function refresh(rootVm, options) { - options = options || {}; // make sure vue-meta was initiated - - if (!rootVm[rootConfigKey]) { - showWarningNotSupported(); - return {}; - } // collect & aggregate all metaInfo $options - - - var rawInfo = getComponentMetaInfo(options, rootVm); - var metaInfo = getMetaInfo(options, rawInfo, clientSequences, rootVm); - var appId = rootVm[rootConfigKey].appId; - var tags = updateClientMetaInfo(appId, options, metaInfo); // emit "event" with new info - - if (tags && isFunction(metaInfo.changed)) { - metaInfo.changed(metaInfo, tags.tagsAdded, tags.tagsRemoved); - tags = { - addedTags: tags.tagsAdded, - removedTags: tags.tagsRemoved - }; - } - - var appsMetaInfo = getAppsMetaInfo(); - - if (appsMetaInfo) { - for (var additionalAppId in appsMetaInfo) { - updateClientMetaInfo(additionalAppId, options, appsMetaInfo[additionalAppId]); - delete appsMetaInfo[additionalAppId]; - } - - clearAppsMetaInfo(true); - } - - return { - vm: rootVm, - metaInfo: metaInfo, - // eslint-disable-line object-shorthand - tags: tags - }; -} - -/** - * 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 - */ - -function attributeGenerator(options, type, data, addSrrAttribute) { - var _ref = options || {}, - attribute = _ref.attribute, - ssrAttribute = _ref.ssrAttribute; - - var attributeStr = ''; - - for (var attr in data) { - var attrData = data[attr]; - var attrValues = []; - - for (var appId in attrData) { - attrValues.push.apply(attrValues, _toConsumableArray([].concat(attrData[appId]))); - } - - if (attrValues.length) { - attributeStr += booleanHtmlAttributes.includes(attr) && attrValues.some(Boolean) ? "".concat(attr) : "".concat(attr, "=\"").concat(attrValues.join(' '), "\""); - attributeStr += ' '; - } - } - - if (attributeStr) { - attributeStr += "".concat(attribute, "=\"").concat(encodeURI(JSON.stringify(data)), "\""); - } - - if (type === 'htmlAttrs' && addSrrAttribute) { - return "".concat(ssrAttribute).concat(attributeStr ? ' ' : '').concat(attributeStr); - } - - return attributeStr; -} - -/** - * Generates title output for the server - * - * @param {'title'} type - the string "title" - * @param {String} data - the title text - * @return {Object} - the title generator - */ -function titleGenerator(options, type, data, generatorOptions) { - var _ref = generatorOptions || {}, - ln = _ref.ln; - - if (!data) { - return ''; - } - - return "<".concat(type, ">").concat(data, "").concat(ln ? '\n' : ''); -} - -/** - * 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)} tags - an array of tag objects or a single object in case of base - * @return {Object} - the tag generator - */ - -function tagGenerator(options, type, tags, generatorOptions) { - var _ref = options || {}, - ssrAppId = _ref.ssrAppId, - attribute = _ref.attribute, - tagIDKeyName = _ref.tagIDKeyName; - - var _ref2 = generatorOptions || {}, - appId = _ref2.appId, - _ref2$body = _ref2.body, - body = _ref2$body === void 0 ? false : _ref2$body, - _ref2$pbody = _ref2.pbody, - pbody = _ref2$pbody === void 0 ? false : _ref2$pbody, - _ref2$ln = _ref2.ln, - ln = _ref2$ln === void 0 ? false : _ref2$ln; - - var dataAttributes = [tagIDKeyName].concat(_toConsumableArray(commonDataAttributes)); - - if (!tags || !tags.length) { - return ''; - } // build a string containing all tags of this type - - - return tags.reduce(function (tagsStr, tag) { - if (tag.skip) { - return tagsStr; - } - - var tagKeys = Object.keys(tag); - - if (tagKeys.length === 0) { - return tagsStr; // Bail on empty tag object - } - - if (Boolean(tag.body) !== body || Boolean(tag.pbody) !== pbody) { - return tagsStr; - } - - var attrs = tag.once ? '' : " ".concat(attribute, "=\"").concat(appId || ssrAppId, "\""); // build a string containing all attributes of this tag - - for (var attr in tag) { - // these attributes are treated as children on the tag - if (tagAttributeAsInnerContent.includes(attr) || tagProperties.includes(attr)) { - continue; - } - - if (attr === 'callback') { - attrs += ' onload="this.__vm_l=1"'; - continue; - } // these form the attribute list for this tag - - - var prefix = ''; - - if (dataAttributes.includes(attr)) { - prefix = 'data-'; - } - - var isBooleanAttr = !prefix && booleanHtmlAttributes.includes(attr); - - if (isBooleanAttr && !tag[attr]) { - continue; - } - - attrs += " ".concat(prefix).concat(attr) + (isBooleanAttr ? '' : "=\"".concat(tag[attr], "\"")); - } - - var json = ''; - - if (tag.json) { - json = JSON.stringify(tag.json); - } // grab child content from one of these attributes, if possible - - - var content = tag.innerHTML || tag.cssText || json; // generate tag exactly without any other redundant attribute - // these tags have no end tag - - var hasEndTag = !tagsWithoutEndTag.includes(type); // these tag types will have content inserted - - var hasContent = hasEndTag && tagsWithInnerContent.includes(type); // the final string for this specific tag - - return "".concat(tagsStr, "<").concat(type).concat(attrs).concat(!hasContent && hasEndTag ? '/' : '', ">") + (hasContent ? "".concat(content, "") : '') + (ln ? '\n' : ''); - }, ''); -} - -/** - * 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)} data - the data value - * @return {Object} - the new injector - */ - -function generateServerInjector(options, metaInfo) { - var serverInjector = { - data: metaInfo, - extraData: undefined, - addInfo: function addInfo(appId, metaInfo) { - this.extraData = this.extraData || {}; - this.extraData[appId] = metaInfo; - }, - callInjectors: function callInjectors(opts) { - var m = this.injectors; // only call title for the head - - return (opts.body || opts.pbody ? '' : m.title.text(opts)) + m.meta.text(opts) + m.link.text(opts) + m.style.text(opts) + m.script.text(opts) + m.noscript.text(opts); - }, - injectors: { - head: function head(ln) { - return serverInjector.callInjectors({ - ln: ln - }); - }, - bodyPrepend: function bodyPrepend(ln) { - return serverInjector.callInjectors({ - ln: ln, - pbody: true - }); - }, - bodyAppend: function bodyAppend(ln) { - return serverInjector.callInjectors({ - ln: ln, - body: true - }); - } - } - }; - - var _loop = function _loop(type) { - if (metaInfoOptionKeys.includes(type)) { - return "continue"; - } - - serverInjector.injectors[type] = { - text: function text(arg) { - if (type === 'title') { - return titleGenerator(options, type, serverInjector.data[type], arg); - } - - if (metaInfoAttributeKeys.includes(type)) { - var attributeData = {}; - var data = serverInjector.data[type]; - - if (data) { - for (var attr in data) { - attributeData[attr] = _defineProperty({}, options.ssrAppId, data[attr]); - } - } - - if (serverInjector.extraData) { - for (var appId in serverInjector.extraData) { - var _data = serverInjector.extraData[appId][type]; - - if (_data) { - for (var _attr in _data) { - attributeData[_attr] = _objectSpread2({}, attributeData[_attr], _defineProperty({}, appId, _data[_attr])); - } - } - } - } - - return attributeGenerator(options, type, attributeData, arg); - } - - var str = tagGenerator(options, type, serverInjector.data[type], arg); - - if (serverInjector.extraData) { - for (var _appId in serverInjector.extraData) { - var _data2 = serverInjector.extraData[_appId][type]; - var extraStr = tagGenerator(options, type, _data2, _objectSpread2({ - appId: _appId - }, arg)); - str = "".concat(str).concat(extraStr); - } - } - - return str; - } - }; - }; - - for (var type in defaultInfo) { - var _ret = _loop(type); - - if (_ret === "continue") continue; - } - - return serverInjector; -} - -/** - * Converts the state of the meta info object such that each item - * can be compiled to a tag string on the server - * - * @vm {Object} - Vue instance - ideally the root component - * @return {Object} - server meta info with `toString` methods - */ - -function inject(rootVm, options) { - // make sure vue-meta was initiated - if (!rootVm[rootConfigKey]) { - showWarningNotSupported(); - return {}; - } // collect & aggregate all metaInfo $options - - - var rawInfo = getComponentMetaInfo(options, rootVm); - var metaInfo = getMetaInfo(options, rawInfo, serverSequences, rootVm); // generate server injector - - var serverInjector = generateServerInjector(options, metaInfo); // add meta info from additional apps - - var appsMetaInfo = getAppsMetaInfo(); - - if (appsMetaInfo) { - for (var additionalAppId in appsMetaInfo) { - serverInjector.addInfo(additionalAppId, appsMetaInfo[additionalAppId]); - delete appsMetaInfo[additionalAppId]; - } - - clearAppsMetaInfo(true); - } - - return serverInjector.injectors; -} - -function $meta(options) { - options = options || {}; - /** - * Returns an injector for server-side rendering. - * @this {Object} - the Vue instance (a root component) - * @return {Object} - injector - */ - - var $root = this.$root; - return { - getOptions: function getOptions$1() { - return getOptions(options); - }, - setOptions: function setOptions(newOptions) { - var refreshNavKey = 'refreshOnceOnNavigation'; - - if (newOptions && newOptions[refreshNavKey]) { - options.refreshOnceOnNavigation = !!newOptions[refreshNavKey]; - addNavGuards($root); - } - - var debounceWaitKey = 'debounceWait'; - - if (newOptions && debounceWaitKey in newOptions) { - var debounceWait = parseInt(newOptions[debounceWaitKey]); - - if (!isNaN(debounceWait)) { - options.debounceWait = debounceWait; - } - } - - var waitOnDestroyedKey = 'waitOnDestroyed'; - - if (newOptions && waitOnDestroyedKey in newOptions) { - options.waitOnDestroyed = !!newOptions[waitOnDestroyedKey]; - } - }, - refresh: function refresh$1() { - return refresh($root, options); - }, - inject: function inject$1() { - return inject($root, options) ; - }, - pause: function pause$1() { - return pause($root); - }, - resume: function resume$1() { - return resume($root); - }, - addApp: function addApp$1(appId) { - return addApp($root, appId, options); - } - }; -} - -function generate(rawInfo, options) { - options = setOptions(options); - var metaInfo = getMetaInfo(options, rawInfo, serverSequences); - var serverInjector = generateServerInjector(options, metaInfo); - return serverInjector.injectors; -} - -/** - * Plugin install function. - * @param {Function} Vue - the Vue constructor. - */ - -function install(Vue, options) { - if (Vue.__vuemeta_installed) { - return; - } - - Vue.__vuemeta_installed = true; - options = setOptions(options); - - Vue.prototype.$meta = function () { - return $meta.call(this, options); - }; - - Vue.mixin(createMixin(Vue, options)); -} - -var index = { - version: version, - install: install, - generate: function generate$1(metaInfo, options) { - return generate(metaInfo, options) ; - }, - hasMetaInfo: hasMetaInfo -}; - -module.exports = index; diff --git a/dist/vue-meta.esm.browser.js b/dist/vue-meta.esm.browser.js deleted file mode 100644 index 59e1acb..0000000 --- a/dist/vue-meta.esm.browser.js +++ /dev/null @@ -1,1550 +0,0 @@ -/** - * vue-meta v2.3.3 - * (c) 2020 - * - Declan de Wet - * - Sébastien Chopin (@Atinux) - * - Pim (@pimlie) - * - All the amazing contributors - * @license MIT - */ - -import deepmerge from 'deepmerge'; - -var version = "2.3.3"; - -function _typeof(obj) { - "@babel/helpers - typeof"; - - if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { - _typeof = function (obj) { - return typeof obj; - }; - } else { - _typeof = function (obj) { - return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; - }; - } - - return _typeof(obj); -} - -/** - * checks if passed argument is an array - * @param {any} arg - the object to check - * @return {Boolean} - true if `arg` is an array - */ -function isArray(arg) { - return Array.isArray(arg); -} -function isUndefined(arg) { - return typeof arg === 'undefined'; -} -function isObject(arg) { - return _typeof(arg) === 'object'; -} -function isPureObject(arg) { - return _typeof(arg) === 'object' && arg !== null; -} -function isFunction(arg) { - return typeof arg === 'function'; -} -function isString(arg) { - return typeof arg === 'string'; -} - -function hasGlobalWindowFn() { - try { - return !isUndefined(window); - } catch (e) { - return false; - } -} -var hasGlobalWindow = hasGlobalWindowFn(); - -var _global = hasGlobalWindow ? window : global; - -var console = _global.console || {}; -function warn(str) { - /* istanbul ignore next */ - if (!console || !console.warn) { - return; - } - - console.warn(str); -} -var showWarningNotSupportedInBrowserBundle = function showWarningNotSupportedInBrowserBundle(method) { - return warn("".concat(method, " is not supported in browser builds")); -}; -var showWarningNotSupported = function showWarningNotSupported() { - return warn('This vue app/component has no vue-meta configuration'); -}; - -/** - * These are constant variables used throughout the application. - */ -// set some sane defaults -var defaultInfo = { - title: undefined, - titleChunk: '', - titleTemplate: '%s', - htmlAttrs: {}, - bodyAttrs: {}, - headAttrs: {}, - base: [], - link: [], - meta: [], - style: [], - script: [], - noscript: [], - __dangerouslyDisableSanitizers: [], - __dangerouslyDisableSanitizersByTagID: {} -}; -var rootConfigKey = '_vueMeta'; // 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 keyName = 'metaInfo'; // This is the attribute vue-meta arguments on elements to know which it should -// manage and which it should ignore. - -var 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 ssrAttribute = '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 tagIDKeyName = 'vmid'; // This is the key name for possible meta templates - -var metaTemplateKeyName = 'template'; // This is the key name for the content-holding property - -var contentKeyName = 'content'; // The id used for the ssr app - -var ssrAppId = 'ssr'; // How long meta update - -var debounceWait = 10; // How long meta update - -var waitOnDestroyed = true; -var defaultOptions = { - keyName: keyName, - attribute: attribute, - ssrAttribute: ssrAttribute, - tagIDKeyName: tagIDKeyName, - contentKeyName: contentKeyName, - metaTemplateKeyName: metaTemplateKeyName, - waitOnDestroyed: waitOnDestroyed, - debounceWait: debounceWait, - ssrAppId: ssrAppId -}; // might be a bit ugly, but minimizes the browser bundles a bit - -var defaultInfoKeys = Object.keys(defaultInfo); // The metaInfo property keys which are used to disable escaping - -var disableOptionKeys = [defaultInfoKeys[12], defaultInfoKeys[13]]; // List of metaInfo property keys which are configuration options (and dont generate html) - -var metaInfoOptionKeys = [defaultInfoKeys[1], defaultInfoKeys[2], 'changed'].concat(disableOptionKeys); // List of metaInfo property keys which only generates attributes and no tags - -var metaInfoAttributeKeys = [defaultInfoKeys[3], defaultInfoKeys[4], defaultInfoKeys[5]]; // HTML elements which support the onload event - -var tagsSupportingOnload = ['link', 'style', 'script']; // HTML elements which dont have a head tag (shortened to our needs) -var tagProperties = ['once', 'skip', 'template']; // Attributes which should be added with data- prefix - -var commonDataAttributes = ['body', 'pbody']; // from: https://github.com/kangax/html-minifier/blob/gh-pages/src/htmlminifier.js#L202 - -var booleanHtmlAttributes = ['allowfullscreen', 'amp', 'async', 'autofocus', 'autoplay', 'checked', 'compact', 'controls', 'declare', 'default', 'defaultchecked', 'defaultmuted', 'defaultselected', 'defer', 'disabled', 'enabled', 'formnovalidate', 'hidden', 'indeterminate', 'inert', 'ismap', 'itemscope', 'loop', 'multiple', 'muted', 'nohref', 'noresize', 'noshade', 'novalidate', 'nowrap', 'open', 'pauseonexit', 'readonly', 'required', 'reversed', 'scoped', 'seamless', 'selected', 'sortable', 'truespeed', 'typemustmatch', 'visible']; - -var batchId = null; -function triggerUpdate(_ref, rootVm, hookName) { - var debounceWait = _ref.debounceWait; - - // if an update was triggered during initialization or when an update was triggered by the - // metaInfo watcher, set initialized to null - // then we keep falsy value but know we need to run a triggerUpdate after initialization - if (!rootVm[rootConfigKey].initialized && (rootVm[rootConfigKey].initializing || hookName === 'watcher')) { - rootVm[rootConfigKey].initialized = null; - } - - if (rootVm[rootConfigKey].initialized && !rootVm[rootConfigKey].pausing) { - // batch potential DOM updates to prevent extraneous re-rendering - // eslint-disable-next-line no-void - batchUpdate(function () { - return void rootVm.$meta().refresh(); - }, debounceWait); - } -} -/** - * Performs a batched update. - * - * @param {(null|Number)} id - the ID of this update - * @param {Function} callback - the update to perform - * @return {Number} id - a new ID - */ - -function batchUpdate(callback, timeout) { - timeout = timeout === undefined ? 10 : timeout; - - if (!timeout) { - callback(); - return; - } - - clearTimeout(batchId); - batchId = setTimeout(function () { - callback(); - }, timeout); - return batchId; -} - -/* - * To reduce build size, this file provides simple polyfills without - * overly excessive type checking and without modifying - * the global Array.prototype - * The polyfills are automatically removed in the commonjs build - * Also, only files in client/ & shared/ should use these functions - * files in server/ still use normal js function - */ -function find(array, predicate, thisArg) { - if ( !Array.prototype.find) { - // idx needs to be a Number, for..in returns string - for (var idx = 0; idx < array.length; idx++) { - if (predicate.call(thisArg, array[idx], idx, array)) { - return array[idx]; - } - } - - return; - } - - return array.find(predicate, thisArg); -} -function findIndex(array, predicate, thisArg) { - if ( !Array.prototype.findIndex) { - // idx needs to be a Number, for..in returns string - for (var idx = 0; idx < array.length; idx++) { - if (predicate.call(thisArg, array[idx], idx, array)) { - return idx; - } - } - - return -1; - } - - return array.findIndex(predicate, thisArg); -} -function toArray(arg) { - if ( !Array.from) { - return Array.prototype.slice.call(arg); - } - - return Array.from(arg); -} -function includes(array, value) { - if ( !Array.prototype.includes) { - for (var idx in array) { - if (array[idx] === value) { - return true; - } - } - - return false; - } - - return array.includes(value); -} - -function hasMetaInfo(vm) { - vm = vm || this; - return vm && (vm[rootConfigKey] === true || isObject(vm[rootConfigKey])); -} // a component is in a metaInfo branch when itself has meta info or one of its (grand-)children has - -function inMetaInfoBranch(vm) { - vm = vm || this; - return vm && !isUndefined(vm[rootConfigKey]); -} - -function pause(rootVm, refresh) { - rootVm[rootConfigKey].pausing = true; - return function () { - return resume(rootVm, refresh); - }; -} -function resume(rootVm, refresh) { - rootVm[rootConfigKey].pausing = false; - - if (refresh || refresh === undefined) { - return rootVm.$meta().refresh(); - } -} - -function addNavGuards(rootVm) { - var router = rootVm.$router; // return when nav guards already added or no router exists - - if (rootVm[rootConfigKey].navGuards || !router) { - /* istanbul ignore next */ - return; - } - - rootVm[rootConfigKey].navGuards = true; - router.beforeEach(function (to, from, next) { - pause(rootVm); - next(); - }); - router.afterEach(function () { - rootVm.$nextTick(function () { - var _resume = resume(rootVm), - metaInfo = _resume.metaInfo; - - if (metaInfo && isFunction(metaInfo.afterNavigation)) { - metaInfo.afterNavigation(metaInfo); - } - }); - }); -} - -var appId = 1; -function createMixin(Vue, options) { - // for which Vue lifecycle hooks should the metaInfo be refreshed - var updateOnLifecycleHook = ['activated', 'deactivated', 'beforeMount']; // watch for client side component updates - - return { - beforeCreate: function beforeCreate() { - var _this2 = this; - - var rootKey = '$root'; - var $root = this[rootKey]; - var $options = this.$options; - var devtoolsEnabled = Vue.config.devtools; - Object.defineProperty(this, '_hasMetaInfo', { - configurable: true, - get: function get() { - // Show deprecation warning once when devtools enabled - if (devtoolsEnabled && !$root[rootConfigKey].deprecationWarningShown) { - warn('VueMeta DeprecationWarning: _hasMetaInfo has been deprecated and will be removed in a future version. Please use hasMetaInfo(vm) instead'); - $root[rootConfigKey].deprecationWarningShown = true; - } - - return hasMetaInfo(this); - } - }); // 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 (isUndefined($options[options.keyName]) || $options[options.keyName] === null) { - return; - } - - if (!$root[rootConfigKey]) { - $root[rootConfigKey] = { - appId: appId - }; - appId++; - - if (devtoolsEnabled && $root.$options[options.keyName]) { - // use nextTick so the children should be added to $root - this.$nextTick(function () { - // find the first child that lists fnOptions - var child = find($root.$children, function (c) { - return c.$vnode && c.$vnode.fnOptions; - }); - - if (child && child.$vnode.fnOptions[options.keyName]) { - warn("VueMeta has detected a possible global mixin which adds a ".concat(options.keyName, " property to all Vue components on the page. This could cause severe performance issues. If possible, use $meta().addApp to add meta information instead")); - } - }); - } - } // to speed up updates we keep track of branches which have a component with vue-meta info defined - // if _vueMeta = true it has info, if _vueMeta = false a child has info - - - if (!this[rootConfigKey]) { - this[rootConfigKey] = true; - var parent = this.$parent; - - while (parent && parent !== $root) { - if (isUndefined(parent[rootConfigKey])) { - parent[rootConfigKey] = false; - } - - parent = parent.$parent; - } - } // coerce function-style metaInfo to a computed prop so we can observe - // it on creation - - - if (isFunction($options[options.keyName])) { - $options.computed = $options.computed || {}; - $options.computed.$metaInfo = $options[options.keyName]; - - if (!this.$isServer) { - // 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) - this.$on('hook:created', function () { - this.$watch('$metaInfo', function () { - triggerUpdate(options, this[rootKey], 'watcher'); - }); - }); - } - } // force an initial refresh on page load and prevent other lifecycleHooks - // to triggerUpdate until this initial refresh is finished - // this is to make sure that when a page is opened in an inactive tab which - // has throttled rAF/timers we still immediately set the page title - - - if (isUndefined($root[rootConfigKey].initialized)) { - $root[rootConfigKey].initialized = this.$isServer; - - if (!$root[rootConfigKey].initialized) { - if (!$root[rootConfigKey].initializedSsr) { - $root[rootConfigKey].initializedSsr = true; - this.$on('hook:beforeMount', function () { - var $root = this; // if this Vue-app was server rendered, set the appId to 'ssr' - // only one SSR app per page is supported - - if ($root.$el && $root.$el.nodeType === 1 && $root.$el.hasAttribute('data-server-rendered')) { - $root[rootConfigKey].appId = options.ssrAppId; - } - }); - } // we use the mounted hook here as on page load - - - this.$on('hook:mounted', function () { - var $root = this[rootKey]; - - if (!$root[rootConfigKey].initialized) { - // used in triggerUpdate to check if a change was triggered - // during initialization - $root[rootConfigKey].initializing = true; // refresh meta in nextTick so all child components have loaded - - this.$nextTick(function () { - var _$root$$meta$refresh = $root.$meta().refresh(), - tags = _$root$$meta$refresh.tags, - metaInfo = _$root$$meta$refresh.metaInfo; // After ssr hydration (identifier by tags === false) check - // if initialized was set to null in triggerUpdate. That'd mean - // that during initilazation changes where triggered which need - // to be applied OR a metaInfo watcher was triggered before the - // current hook was called - // (during initialization all changes are blocked) - - - if (tags === false && $root[rootConfigKey].initialized === null) { - this.$nextTick(function () { - return triggerUpdate(options, $root, 'init'); - }); - } - - $root[rootConfigKey].initialized = true; - delete $root[rootConfigKey].initializing; // add the navigation guards if they havent been added yet - // they are needed for the afterNavigation callback - - if (!options.refreshOnceOnNavigation && metaInfo.afterNavigation) { - addNavGuards($root); - } - }); - } - }); // add the navigation guards if requested - - if (options.refreshOnceOnNavigation) { - addNavGuards($root); - } - } - } - - this.$on('hook:destroyed', function () { - var _this = this; - - // do not trigger refresh: - // - when user configured to not wait for transitions on destroyed - // - when the component doesnt have a parent - // - doesnt have metaInfo defined - if (!this.$parent || !hasMetaInfo(this)) { - return; - } - - delete this._hasMetaInfo; - this.$nextTick(function () { - if (!options.waitOnDestroyed || !_this.$el || !_this.$el.offsetParent) { - triggerUpdate(options, _this.$root, 'destroyed'); - return; - } // Wait that element is hidden before refreshing meta tags (to support animations) - - - var interval = setInterval(function () { - if (_this.$el && _this.$el.offsetParent !== null) { - /* istanbul ignore next line */ - return; - } - - clearInterval(interval); - triggerUpdate(options, _this.$root, 'destroyed'); - }, 50); - }); - }); // do not trigger refresh on the server side - - if (this.$isServer) { - /* istanbul ignore next */ - return; - } // no need to add this hooks on server side - - - updateOnLifecycleHook.forEach(function (lifecycleHook) { - _this2.$on("hook:".concat(lifecycleHook), function () { - triggerUpdate(options, this[rootKey], lifecycleHook); - }); - }); - } - }; -} - -function setOptions(options) { - // combine options - options = isObject(options) ? options : {}; // The options are set like this so they can - // be minified by terser while keeping the - // user api intact - // terser --mangle-properties keep_quoted=strict - - /* eslint-disable dot-notation */ - - return { - keyName: options['keyName'] || defaultOptions.keyName, - attribute: options['attribute'] || defaultOptions.attribute, - ssrAttribute: options['ssrAttribute'] || defaultOptions.ssrAttribute, - tagIDKeyName: options['tagIDKeyName'] || defaultOptions.tagIDKeyName, - contentKeyName: options['contentKeyName'] || defaultOptions.contentKeyName, - metaTemplateKeyName: options['metaTemplateKeyName'] || defaultOptions.metaTemplateKeyName, - debounceWait: isUndefined(options['debounceWait']) ? defaultOptions.debounceWait : options['debounceWait'], - waitOnDestroyed: isUndefined(options['waitOnDestroyed']) ? defaultOptions.waitOnDestroyed : options['waitOnDestroyed'], - ssrAppId: options['ssrAppId'] || defaultOptions.ssrAppId, - refreshOnceOnNavigation: !!options['refreshOnceOnNavigation'] - }; - /* eslint-enable dot-notation */ -} -function getOptions(options) { - var optionsCopy = {}; - - for (var key in options) { - optionsCopy[key] = options[key]; - } - - return optionsCopy; -} - -function ensureIsArray(arg, key) { - if (!key || !isObject(arg)) { - return isArray(arg) ? arg : []; - } - - if (!isArray(arg[key])) { - arg[key] = []; - } - - return arg; -} - -var clientSequences = [[/&/g, "&"], [//g, ">"], [/"/g, "\""], [/'/g, "'"]]; // sanitizes potentially dangerous characters - -function escape(info, options, escapeOptions, escapeKeys) { - var tagIDKeyName = options.tagIDKeyName; - var _escapeOptions$doEsca = escapeOptions.doEscape, - doEscape = _escapeOptions$doEsca === void 0 ? function (v) { - return v; - } : _escapeOptions$doEsca; - var escaped = {}; - - for (var key in info) { - var value = info[key]; // no need to escape configuration options - - if (includes(metaInfoOptionKeys, key)) { - escaped[key] = value; - continue; - } // do not use destructuring for disableOptionKeys, it increases transpiled size - // due to var checks while we are guaranteed the structure of the cb - - - var disableKey = disableOptionKeys[0]; - - if (escapeOptions[disableKey] && includes(escapeOptions[disableKey], key)) { - // this info[key] doesnt need to escaped if the option is listed in __dangerouslyDisableSanitizers - escaped[key] = value; - continue; - } - - var tagId = info[tagIDKeyName]; - - if (tagId) { - disableKey = disableOptionKeys[1]; // keys which are listed in __dangerouslyDisableSanitizersByTagID for the current vmid do not need to be escaped - - if (escapeOptions[disableKey] && escapeOptions[disableKey][tagId] && includes(escapeOptions[disableKey][tagId], key)) { - escaped[key] = value; - continue; - } - } - - if (isString(value)) { - escaped[key] = doEscape(value); - } else if (isArray(value)) { - escaped[key] = value.map(function (v) { - if (isPureObject(v)) { - return escape(v, options, escapeOptions, true); - } - - return doEscape(v); - }); - } else if (isPureObject(value)) { - escaped[key] = escape(value, options, escapeOptions, true); - } else { - escaped[key] = value; - } - - if (escapeKeys) { - var escapedKey = doEscape(key); - - if (key !== escapedKey) { - escaped[escapedKey] = escaped[key]; - delete escaped[key]; - } - } - } - - return escaped; -} -function escapeMetaInfo(options, info, escapeSequences) { - escapeSequences = escapeSequences || []; // do not use destructuring for seq, it increases transpiled size - // due to var checks while we are guaranteed the structure of the cb - - var escapeOptions = { - doEscape: function doEscape(value) { - return escapeSequences.reduce(function (val, seq) { - return val.replace(seq[0], seq[1]); - }, value); - } - }; - disableOptionKeys.forEach(function (disableKey, index) { - if (index === 0) { - ensureIsArray(info, disableKey); - } else if (index === 1) { - for (var key in info[disableKey]) { - ensureIsArray(info[disableKey], key); - } - } - - escapeOptions[disableKey] = info[disableKey]; - }); // begin sanitization - - return escape(info, options, escapeOptions); -} - -function applyTemplate(_ref, headObject, template, chunk) { - var component = _ref.component, - metaTemplateKeyName = _ref.metaTemplateKeyName, - contentKeyName = _ref.contentKeyName; - - if (template === true || headObject[metaTemplateKeyName] === true) { - // abort, template was already applied - return false; - } - - if (isUndefined(template) && headObject[metaTemplateKeyName]) { - template = headObject[metaTemplateKeyName]; - headObject[metaTemplateKeyName] = true; - } // return early if no template defined - - - if (!template) { - // cleanup faulty template properties - delete headObject[metaTemplateKeyName]; - return false; - } - - if (isUndefined(chunk)) { - chunk = headObject[contentKeyName]; - } - - headObject[contentKeyName] = isFunction(template) ? template.call(component, chunk) : template.replace(/%s/g, chunk); - return true; -} - -function _arrayMerge(_ref, target, source) { - var component = _ref.component, - tagIDKeyName = _ref.tagIDKeyName, - metaTemplateKeyName = _ref.metaTemplateKeyName, - contentKeyName = _ref.contentKeyName; - // 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 - var destination = []; - - if (!target.length && !source.length) { - return destination; - } - - target.forEach(function (targetItem, targetIndex) { - // no tagID so no need to check for duplicity - if (!targetItem[tagIDKeyName]) { - destination.push(targetItem); - return; - } - - var sourceIndex = findIndex(source, function (item) { - return item[tagIDKeyName] === targetItem[tagIDKeyName]; - }); - var sourceItem = source[sourceIndex]; // source doesnt contain any duplicate vmid's, we can keep targetItem - - if (sourceIndex === -1) { - destination.push(targetItem); - return; - } // when sourceItem explictly defines contentKeyName or innerHTML as undefined, its - // an indication that we need to skip the default behaviour or child has preference over parent - // which means we keep the targetItem and ignore/remove the sourceItem - - - if (contentKeyName in sourceItem && sourceItem[contentKeyName] === undefined || 'innerHTML' in sourceItem && sourceItem.innerHTML === undefined) { - destination.push(targetItem); // remove current index from source array so its not concatenated to destination below - - source.splice(sourceIndex, 1); - return; - } // we now know that targetItem is a duplicate and we should ignore it in favor of sourceItem - // if source specifies null as content then ignore both the target as the source - - - if (sourceItem[contentKeyName] === null || sourceItem.innerHTML === null) { - // remove current index from source array so its not concatenated to destination below - source.splice(sourceIndex, 1); - return; - } // now we only need to check if the target has a template to combine it with the source - - - var targetTemplate = targetItem[metaTemplateKeyName]; - - if (!targetTemplate) { - return; - } - - var sourceTemplate = sourceItem[metaTemplateKeyName]; - - if (!sourceTemplate) { - // use parent template and child content - applyTemplate({ - component: component, - metaTemplateKeyName: metaTemplateKeyName, - contentKeyName: contentKeyName - }, sourceItem, targetTemplate); // set template to true to indicate template was already applied - - sourceItem.template = true; - return; - } - - if (!sourceItem[contentKeyName]) { - // use parent content and child template - applyTemplate({ - component: component, - metaTemplateKeyName: metaTemplateKeyName, - contentKeyName: contentKeyName - }, sourceItem, undefined, targetItem[contentKeyName]); - } - }); - return destination.concat(source); -} -var warningShown = false; -function merge(target, source, options) { - options = options || {}; // remove properties explicitly set to false so child components can - // optionally _not_ overwrite the parents content - // (for array properties this is checked in arrayMerge) - - if (source.title === undefined) { - delete source.title; - } - - metaInfoAttributeKeys.forEach(function (attrKey) { - if (!source[attrKey]) { - return; - } - - for (var key in source[attrKey]) { - if (key in source[attrKey] && source[attrKey][key] === undefined) { - if (includes(booleanHtmlAttributes, key) && !warningShown) { - warn('VueMeta: Please note that since v2 the value undefined is not used to indicate boolean attributes anymore, see migration guide for details'); - warningShown = true; - } - - delete source[attrKey][key]; - } - } - }); - return deepmerge(target, source, { - arrayMerge: function arrayMerge(t, s) { - return _arrayMerge(options, t, s); - } - }); -} - -function getComponentMetaInfo(options, component) { - return getComponentOption(options || {}, component, defaultInfo); -} -/** - * 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 {Boolean} opts.deep - look for data in child components as well? - * @param {Function} opts.arrayMerge - how should arrays be merged? - * @param {String} opts.keyName - the name of the option to look for - * @param {Object} [result={}] - result so far - * @return {Object} result - final aggregated result - */ - -function getComponentOption(options, component, result) { - result = result || {}; - - if (component._inactive) { - return result; - } - - options = options || {}; - var _options = options, - keyName = _options.keyName; - var $metaInfo = component.$metaInfo, - $options = component.$options, - $children = component.$children; // only collect option data if it exists - - if ($options[keyName]) { - // if $metaInfo exists then [keyName] was defined as a function - // and set to the computed prop $metaInfo in the mixin - // using the computed prop should be a small performance increase - // because Vue caches those internally - var data = $metaInfo || $options[keyName]; // only merge data with result when its an object - // eg it could be a function when metaInfo() returns undefined - // dueo to the or statement above - - if (isObject(data)) { - result = merge(result, data, options); - } - } // collect & aggregate child options if deep = true - - - if ($children.length) { - $children.forEach(function (childComponent) { - // check if the childComponent is in a branch - // return otherwise so we dont walk all component branches unnecessarily - if (!inMetaInfoBranch(childComponent)) { - return; - } - - result = getComponentOption(options, childComponent, result); - }); - } - - return result; -} - -var querySelector = function querySelector(arg, el) { - return (el || document).querySelectorAll(arg); -}; -function getTag(tags, tag) { - if (!tags[tag]) { - tags[tag] = document.getElementsByTagName(tag)[0]; - } - - return tags[tag]; -} -function getElementsKey(_ref) { - var body = _ref.body, - pbody = _ref.pbody; - return body ? 'body' : pbody ? 'pbody' : 'head'; -} -function queryElements(parentNode, _ref2, attributes) { - var appId = _ref2.appId, - attribute = _ref2.attribute, - type = _ref2.type, - tagIDKeyName = _ref2.tagIDKeyName; - attributes = attributes || {}; - var queries = ["".concat(type, "[").concat(attribute, "=\"").concat(appId, "\"]"), "".concat(type, "[data-").concat(tagIDKeyName, "]")].map(function (query) { - for (var key in attributes) { - var val = attributes[key]; - var attributeValue = val && val !== true ? "=\"".concat(val, "\"") : ''; - query += "[data-".concat(key).concat(attributeValue, "]"); - } - - return query; - }); - return toArray(querySelector(queries.join(', '), parentNode)); -} -function removeElementsByAppId(_ref3, appId) { - var attribute = _ref3.attribute; - toArray(querySelector("[".concat(attribute, "=\"").concat(appId, "\"]"))).map(function (el) { - return el.remove(); - }); -} -function removeAttribute(el, attributeName) { - el.removeAttribute(attributeName); -} - -var callbacks = []; -function isDOMComplete(d) { - return (d || document).readyState === 'complete'; -} -function addCallback(query, callback) { - if (arguments.length === 1) { - callback = query; - query = ''; - } - - callbacks.push([query, callback]); -} -function addCallbacks(_ref, type, tags, autoAddListeners) { - var tagIDKeyName = _ref.tagIDKeyName; - var hasAsyncCallback = false; - tags.forEach(function (tag) { - if (!tag[tagIDKeyName] || !tag.callback) { - return; - } - - hasAsyncCallback = true; - addCallback("".concat(type, "[data-").concat(tagIDKeyName, "=\"").concat(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 = function () { - applyCallbacks(); - }; -} -function applyCallbacks(matchElement) { - callbacks.forEach(function (args) { - // do not use destructuring for args, it increases transpiled size - // due to var checks while we are guaranteed the structure of the cb - var query = args[0]; - var callback = args[1]; - var selector = "".concat(query, "[onload=\"this.__vm_l=1\"]"); - var elements = []; - - if (!matchElement) { - elements = toArray(querySelector(selector)); - } - - if (matchElement && matchElement.matches(selector)) { - elements = [matchElement]; - } - - elements.forEach(function (element) { - /* __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) { - return; - } - - var onload = function 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 - */ - - removeAttribute(element, '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(); - return; - } - - if (!element.__vm_ev) { - element.__vm_ev = true; - element.addEventListener('load', onload); - } - }); - }); -} - -// instead of adding it to the html - -var attributeMap = {}; -/** - * 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 - */ - -function updateAttribute(appId, options, type, attrs, tag) { - var _ref = options || {}, - attribute = _ref.attribute; - - var vueMetaAttrString = tag.getAttribute(attribute); - - if (vueMetaAttrString) { - attributeMap[type] = JSON.parse(decodeURI(vueMetaAttrString)); - removeAttribute(tag, attribute); - } - - var data = attributeMap[type] || {}; - var toUpdate = []; // remove attributes from the map - // which have been removed for this appId - - for (var attr in data) { - if (data[attr] && appId in data[attr]) { - toUpdate.push(attr); - - if (!attrs[attr]) { - delete data[attr][appId]; - } - } - } - - for (var _attr in attrs) { - var attrData = data[_attr]; - - if (!attrData || attrData[appId] !== attrs[_attr]) { - toUpdate.push(_attr); - - if (attrs[_attr]) { - data[_attr] = data[_attr] || {}; - data[_attr][appId] = attrs[_attr]; - } - } - } - - for (var _i = 0, _toUpdate = toUpdate; _i < _toUpdate.length; _i++) { - var _attr2 = _toUpdate[_i]; - var _attrData = data[_attr2]; - var attrValues = []; - - for (var _appId in _attrData) { - Array.prototype.push.apply(attrValues, [].concat(_attrData[_appId])); - } - - if (attrValues.length) { - var attrValue = includes(booleanHtmlAttributes, _attr2) && attrValues.some(Boolean) ? '' : attrValues.filter(Boolean).join(' '); - tag.setAttribute(_attr2, attrValue); - } else { - removeAttribute(tag, _attr2); - } - } - - attributeMap[type] = data; -} - -/** - * Updates the document title - * - * @param {String} title - the new title of the document - */ -function updateTitle(title) { - if (!title && title !== '') { - return; - } - - document.title = title; -} - -/** - * Updates meta tags inside and 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)} tags - an array of tag objects or a single object in case of base - * @return {Object} - a representation of what tags changed - */ - -function updateTag(appId, options, type, tags, head, body) { - var _ref = options || {}, - attribute = _ref.attribute, - tagIDKeyName = _ref.tagIDKeyName; - - var dataAttributes = commonDataAttributes.slice(); - dataAttributes.push(tagIDKeyName); - var newElements = []; - var queryOptions = { - appId: appId, - attribute: attribute, - type: type, - tagIDKeyName: tagIDKeyName - }; - var currentElements = { - head: queryElements(head, queryOptions), - pbody: queryElements(body, queryOptions, { - pbody: true - }), - body: queryElements(body, queryOptions, { - body: true - }) - }; - - 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.filter(function (x) { - var k = JSON.stringify(x); - var res = !includes(found, k); - found.push(k); - return res; - }); - } - - tags.forEach(function (tag) { - if (tag.skip) { - return; - } - - var newElement = document.createElement(type); - - if (!tag.once) { - newElement.setAttribute(attribute, appId); - } - - Object.keys(tag).forEach(function (attr) { - /* istanbul ignore next */ - if (includes(tagProperties, attr)) { - return; - } - - if (attr === 'innerHTML') { - newElement.innerHTML = tag.innerHTML; - return; - } - - if (attr === 'json') { - newElement.innerHTML = JSON.stringify(tag.json); - return; - } - - if (attr === 'cssText') { - if (newElement.styleSheet) { - /* istanbul ignore next */ - newElement.styleSheet.cssText = tag.cssText; - } else { - newElement.appendChild(document.createTextNode(tag.cssText)); - } - - return; - } - - if (attr === 'callback') { - newElement.onload = function () { - return tag[attr](newElement); - }; - - return; - } - - var _attr = includes(dataAttributes, attr) ? "data-".concat(attr) : attr; - - var isBooleanAttribute = includes(booleanHtmlAttributes, attr); - - if (isBooleanAttribute && !tag[attr]) { - return; - } - - var value = isBooleanAttribute ? '' : tag[attr]; - newElement.setAttribute(_attr, value); - }); - var oldElements = currentElements[getElementsKey(tag)]; // Remove a duplicate tag from domTagstoRemove, so it isn't cleared. - - var indexToDelete; - var hasEqualElement = oldElements.some(function (existingTag, index) { - indexToDelete = index; - return newElement.isEqualNode(existingTag); - }); - - if (hasEqualElement && (indexToDelete || indexToDelete === 0)) { - oldElements.splice(indexToDelete, 1); - } else { - newElements.push(newElement); - } - }); - var oldElements = []; - - for (var _type in currentElements) { - Array.prototype.push.apply(oldElements, currentElements[_type]); - } // remove old elements - - - oldElements.forEach(function (element) { - element.parentNode.removeChild(element); - }); // insert new elements - - newElements.forEach(function (element) { - if (element.hasAttribute('data-body')) { - body.appendChild(element); - return; - } - - if (element.hasAttribute('data-pbody')) { - body.insertBefore(element, body.firstChild); - return; - } - - head.appendChild(element); - }); - return { - oldTags: oldElements, - newTags: newElements - }; -} - -/** - * Performs client-side updates when new meta info is received - * - * @param {Object} newInfo - the meta info to update to - */ - -function updateClientMetaInfo(appId, options, newInfo) { - options = options || {}; - var _options = options, - ssrAttribute = _options.ssrAttribute, - ssrAppId = _options.ssrAppId; // only cache tags for current update - - var tags = {}; - var htmlTag = getTag(tags, 'html'); // if this is a server render, then dont update - - if (appId === ssrAppId && htmlTag.hasAttribute(ssrAttribute)) { - // remove the server render attribute so we can update on (next) changes - removeAttribute(htmlTag, ssrAttribute); // add load callbacks if the - - var addLoadListeners = false; - tagsSupportingOnload.forEach(function (type) { - if (newInfo[type] && addCallbacks(options, type, newInfo[type])) { - addLoadListeners = true; - } - }); - - if (addLoadListeners) { - addListeners(); - } - - return false; - } // initialize tracked changes - - - var tagsAdded = {}; - var tagsRemoved = {}; - - for (var type in newInfo) { - // ignore these - if (includes(metaInfoOptionKeys, type)) { - continue; - } - - if (type === 'title') { - // update the title - updateTitle(newInfo.title); - continue; - } - - if (includes(metaInfoAttributeKeys, type)) { - var tagName = type.substr(0, 4); - updateAttribute(appId, options, type, newInfo[type], getTag(tags, tagName)); - continue; - } // tags should always be an array, ignore if it isnt - - - if (!isArray(newInfo[type])) { - continue; - } - - var _updateTag = updateTag(appId, options, type, newInfo[type], getTag(tags, 'head'), getTag(tags, 'body')), - oldTags = _updateTag.oldTags, - newTags = _updateTag.newTags; - - if (newTags.length) { - tagsAdded[type] = newTags; - tagsRemoved[type] = oldTags; - } - } - - return { - tagsAdded: tagsAdded, - tagsRemoved: tagsRemoved - }; -} - -var appsMetaInfo; -function addApp(rootVm, appId, options) { - return { - set: function set(metaInfo) { - return setMetaInfo(rootVm, appId, options, metaInfo); - }, - remove: function remove() { - return removeMetaInfo(rootVm, appId, options); - } - }; -} -function setMetaInfo(rootVm, appId, options, metaInfo) { - // if a vm exists _and_ its mounted then immediately update - if (rootVm && rootVm.$el) { - return updateClientMetaInfo(appId, options, metaInfo); - } // store for later, the info - // will be set on the first refresh - - - appsMetaInfo = appsMetaInfo || {}; - appsMetaInfo[appId] = metaInfo; -} -function removeMetaInfo(rootVm, appId, options) { - if (rootVm && rootVm.$el) { - var tags = {}; - var _iteratorNormalCompletion = true; - var _didIteratorError = false; - var _iteratorError = undefined; - - try { - for (var _iterator = metaInfoAttributeKeys[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { - var type = _step.value; - var tagName = type.substr(0, 4); - updateAttribute(appId, options, type, {}, getTag(tags, tagName)); - } - } catch (err) { - _didIteratorError = true; - _iteratorError = err; - } finally { - try { - if (!_iteratorNormalCompletion && _iterator.return != null) { - _iterator.return(); - } - } finally { - if (_didIteratorError) { - throw _iteratorError; - } - } - } - - return removeElementsByAppId(options, appId); - } - - if (appsMetaInfo[appId]) { - delete appsMetaInfo[appId]; - clearAppsMetaInfo(); - } -} -function getAppsMetaInfo() { - return appsMetaInfo; -} -function clearAppsMetaInfo(force) { - if (force || !Object.keys(appsMetaInfo).length) { - appsMetaInfo = undefined; - } -} - -/** - * 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 - */ - -function getMetaInfo(options, info, escapeSequences, component) { - options = options || {}; - escapeSequences = escapeSequences || []; - var _options = options, - tagIDKeyName = _options.tagIDKeyName; // 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.titleTemplate !== '%s') { - applyTemplate({ - component: component, - contentKeyName: 'title' - }, info, 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] : []; - } - - if (info.meta) { - // remove meta items with duplicate vmid's - info.meta = info.meta.filter(function (metaItem, index, arr) { - var hasVmid = !!metaItem[tagIDKeyName]; - - if (!hasVmid) { - return true; - } - - var isFirstItemForVmid = index === findIndex(arr, function (item) { - return item[tagIDKeyName] === metaItem[tagIDKeyName]; - }); - return isFirstItemForVmid; - }); // apply templates if needed - - info.meta.forEach(function (metaObject) { - return applyTemplate(options, metaObject); - }); - } - - return escapeMetaInfo(options, info, escapeSequences); -} - -/** - * 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 - */ - -function refresh(rootVm, options) { - options = options || {}; // make sure vue-meta was initiated - - if (!rootVm[rootConfigKey]) { - showWarningNotSupported(); - return {}; - } // collect & aggregate all metaInfo $options - - - var rawInfo = getComponentMetaInfo(options, rootVm); - var metaInfo = getMetaInfo(options, rawInfo, clientSequences, rootVm); - var appId = rootVm[rootConfigKey].appId; - var tags = updateClientMetaInfo(appId, options, metaInfo); // emit "event" with new info - - if (tags && isFunction(metaInfo.changed)) { - metaInfo.changed(metaInfo, tags.tagsAdded, tags.tagsRemoved); - tags = { - addedTags: tags.tagsAdded, - removedTags: tags.tagsRemoved - }; - } - - var appsMetaInfo = getAppsMetaInfo(); - - if (appsMetaInfo) { - for (var additionalAppId in appsMetaInfo) { - updateClientMetaInfo(additionalAppId, options, appsMetaInfo[additionalAppId]); - delete appsMetaInfo[additionalAppId]; - } - - clearAppsMetaInfo(true); - } - - return { - vm: rootVm, - metaInfo: metaInfo, - // eslint-disable-line object-shorthand - tags: tags - }; -} - -function $meta(options) { - options = options || {}; - /** - * Returns an injector for server-side rendering. - * @this {Object} - the Vue instance (a root component) - * @return {Object} - injector - */ - - var $root = this.$root; - return { - getOptions: function getOptions$1() { - return getOptions(options); - }, - setOptions: function setOptions(newOptions) { - var refreshNavKey = 'refreshOnceOnNavigation'; - - if (newOptions && newOptions[refreshNavKey]) { - options.refreshOnceOnNavigation = !!newOptions[refreshNavKey]; - addNavGuards($root); - } - - var debounceWaitKey = 'debounceWait'; - - if (newOptions && debounceWaitKey in newOptions) { - var debounceWait = parseInt(newOptions[debounceWaitKey]); - - if (!isNaN(debounceWait)) { - options.debounceWait = debounceWait; - } - } - - var waitOnDestroyedKey = 'waitOnDestroyed'; - - if (newOptions && waitOnDestroyedKey in newOptions) { - options.waitOnDestroyed = !!newOptions[waitOnDestroyedKey]; - } - }, - refresh: function refresh$1() { - return refresh($root, options); - }, - inject: function inject() { - return showWarningNotSupportedInBrowserBundle('inject'); - }, - pause: function pause$1() { - return pause($root); - }, - resume: function resume$1() { - return resume($root); - }, - addApp: function addApp$1(appId) { - return addApp($root, appId, options); - } - }; -} - -/** - * Plugin install function. - * @param {Function} Vue - the Vue constructor. - */ - -function install(Vue, options) { - if (Vue.__vuemeta_installed) { - return; - } - - Vue.__vuemeta_installed = true; - options = setOptions(options); - - Vue.prototype.$meta = function () { - return $meta.call(this, options); - }; - - Vue.mixin(createMixin(Vue, options)); -} - -var index = { - version: version, - install: install, - generate: function generate(metaInfo, options) { - return showWarningNotSupportedInBrowserBundle('generate'); - }, - hasMetaInfo: hasMetaInfo -}; - -export default index; diff --git a/dist/vue-meta.esm.browser.min.js b/dist/vue-meta.esm.browser.min.js deleted file mode 100644 index f5690e3..0000000 --- a/dist/vue-meta.esm.browser.min.js +++ /dev/null @@ -1,10 +0,0 @@ -/** - * vue-meta v2.3.3 - * (c) 2020 - * - Declan de Wet - * - Sébastien Chopin (@Atinux) - * - Pim (@pimlie) - * - All the amazing contributors - * @license MIT - */ -import n from"deepmerge";function t(n){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(n){return typeof n}:function(n){return n&&"function"==typeof Symbol&&n.constructor===Symbol&&n!==Symbol.prototype?"symbol":typeof n})(n)}function e(n){return Array.isArray(n)}function r(n){return void 0===n}function i(n){return"object"===t(n)}function o(n){return"object"===t(n)&&null!==n}function a(n){return"function"==typeof n}var u=(function(){try{return!r(window)}catch(n){return!1}}()?window:global).console||{};function f(n){u&&u.warn&&u.warn(n)}var c=function(n){return f("".concat(n," is not supported in browser builds"))},s={title:void 0,titleChunk:"",titleTemplate:"%s",htmlAttrs:{},bodyAttrs:{},headAttrs:{},base:[],link:[],meta:[],style:[],script:[],noscript:[],__dangerouslyDisableSanitizers:[],__dangerouslyDisableSanitizersByTagID:{}},d="metaInfo",l="data-vue-meta",v="data-vue-meta-server-rendered",m="vmid",h="content",p="template",y=!0,b=10,g="ssr",I=Object.keys(s),A=[I[12],I[13]],N=[I[1],I[2],"changed"].concat(A),T=[I[3],I[4],I[5]],w=["link","style","script"],O=["once","skip","template"],k=["body","pbody"],M=["allowfullscreen","amp","async","autofocus","autoplay","checked","compact","controls","declare","default","defaultchecked","defaultmuted","defaultselected","defer","disabled","enabled","formnovalidate","hidden","indeterminate","inert","ismap","itemscope","loop","multiple","muted","nohref","noresize","noshade","novalidate","nowrap","open","pauseonexit","readonly","required","reversed","scoped","seamless","selected","sortable","truespeed","typemustmatch","visible"],S=null;function j(n,t,e){var r=n.t;t._vueMeta.i||!t._vueMeta.o&&"watcher"!==e||(t._vueMeta.i=null),t._vueMeta.i&&!t._vueMeta.u&&function(n,t){if(!(t=void 0===t?10:t))return void n();clearTimeout(S),S=setTimeout((function(){n()}),t)}((function(){t.$meta().refresh()}),r)}function K(n,t,e){if(!Array.prototype.findIndex){for(var r=0;r/g,">"],[/"/g,'"'],[/'/g,"'"]];function L(n,t,r){r=r||[];var i={A:function(n){return r.reduce((function(n,t){return n.replace(t[0],t[1])}),n)}};return A.forEach((function(n,e){if(0===e)C(t,n);else if(1===e)for(var r in t[n])C(t[n],r);i[n]=t[n]})),function n(t,r,i,a){var u=r.j,f=i.A,c=void 0===f?function(n){return n}:f,s={};for(var d in t){var l=t[d];if(D(N,d))s[d]=l;else{var v=A[0];if(i[v]&&D(i[v],d))s[d]=l;else{var m=t[u];if(m&&(v=A[1],i[v]&&i[v][m]&&D(i[v][m],d)))s[d]=l;else if("string"==typeof l?s[d]=c(l):e(l)?s[d]=l.map((function(t){return o(t)?n(t,r,i,!0):c(t)})):o(l)?s[d]=n(l,r,i,!0):s[d]=l,a){var h=c(d);d!==h&&(s[h]=s[d],delete s[d])}}}}return s}(t,n,i)}function P(n,t,e,i){var o=n.component,u=n.N,f=n.T;return!0!==e&&!0!==t[u]&&(r(e)&&t[u]&&(e=t[u],t[u]=!0),e?(r(i)&&(i=t[f]),t[f]=a(e)?e.call(o,i):e.replace(/%s/g,i),!0):(delete t[u],!1))}var R=!1;function $(t,e,r){return r=r||{},void 0===e.title&&delete e.title,T.forEach((function(n){if(e[n])for(var t in e[n])t in e[n]&&void 0===e[n][t]&&(D(M,t)&&!R&&(f("VueMeta: Please note that since v2 the value undefined is not used to indicate boolean attributes anymore, see migration guide for details"),R=!0),delete e[n][t])})),n(t,e,{O:function(n,t){return function(n,t,e){var r=n.component,i=n.j,o=n.N,a=n.T,u=[];return t.length||e.length?(t.forEach((function(n,t){if(n[i]){var f=K(e,(function(t){return t[i]===n[i]})),c=e[f];if(-1!==f){if(a in c&&void 0===c[a]||"innerHTML"in c&&void 0===c.innerHTML)return u.push(n),void e.splice(f,1);if(null!==c[a]&&null!==c.innerHTML){var s=n[o];if(s){if(!c[o])return P({component:r,N:o,T:a},c,s),void(c.template=!0);c[a]||P({component:r,N:o,T:a},c,void 0,n[a])}}else e.splice(f,1)}else u.push(n)}else u.push(n)})),u.concat(e)):u}(r,n,t)}})}function q(n,t){return function n(t,e,o){if(o=o||{},e._inactive)return o;var a=(t=t||{}).v,u=e.$metaInfo,f=e.$options,c=e.$children;if(f[a]){var s=u||f[a];i(s)&&(o=$(o,s,t))}c.length&&c.forEach((function(e){(function(n){return(n=n||this)&&!r(n._vueMeta)})(e)&&(o=n(t,e,o))}));return o}(n||{},t,s)}var E=function(n,t){return(t||document).querySelectorAll(n)};function U(n,t){return n[t]||(n[t]=document.getElementsByTagName(t)[0]),n[t]}function F(n,t,e){var r=t.m,i=t.k,o=t.type,a=t.j;e=e||{};var u=["".concat(o,"[").concat(i,'="').concat(r,'"]'),"".concat(o,"[data-").concat(a,"]")].map((function(n){for(var t in e){var r=e[t],i=r&&!0!==r?'="'.concat(r,'"'):"";n+="[data-".concat(t).concat(i,"]")}return n}));return _(E(u.join(", "),n))}function G(n,t){n.removeAttribute(t)}var Q=[];function X(n,t,e,r){var i=n.j,o=!1;return e.forEach((function(n){n[i]&&n.callback&&(o=!0,function(n,t){1===arguments.length&&(t=n,n=""),Q.push([n,t])}("".concat(t,"[data-").concat(i,'="').concat(n[i],'"]'),n.callback))})),r&&o?Y():o}function Y(){var n;"complete"!==(n||document).readyState?document.onreadystatechange=function(){Z()}:Z()}function Z(n){Q.forEach((function(t){var e=t[0],r=t[1],i="".concat(e,'[onload="this.__vm_l=1"]'),o=[];n||(o=_(E(i))),n&&n.matches(i)&&(o=[n]),o.forEach((function(n){if(!n.__vm_cb){var t=function(){n.__vm_cb=!0,G(n,"onload"),r(n)};n.__vm_l?t():n.__vm_ev||(n.__vm_ev=!0,n.addEventListener("load",t))}}))}))}var nn,tn={};function en(n,t,e,r,i){var o=(t||{}).k,a=i.getAttribute(o);a&&(tn[e]=JSON.parse(decodeURI(a)),G(i,o));var u=tn[e]||{},f=[];for(var c in u)u[c]&&n in u[c]&&(f.push(c),r[c]||delete u[c][n]);for(var s in r){var d=u[s];d&&d[n]===r[s]||(f.push(s),r[s]&&(u[s]=u[s]||{},u[s][n]=r[s]))}for(var l=0,v=f;l1){var v=[];r=r.filter((function(n){var t=JSON.stringify(n),e=!D(v,t);return v.push(t),e}))}r.forEach((function(t){if(!t.skip){var r=document.createElement(e);t.once||r.setAttribute(u,n),Object.keys(t).forEach((function(n){if(!D(O,n))if("innerHTML"!==n)if("json"!==n)if("cssText"!==n)if("callback"!==n){var e=D(c,n)?"data-".concat(n):n,i=D(M,n);if(!i||t[n]){var o=i?"":t[n];r.setAttribute(e,o)}}else r.onload=function(){return t[n](r)};else r.styleSheet?r.styleSheet.cssText=t.cssText:r.appendChild(document.createTextNode(t.cssText));else r.innerHTML=JSON.stringify(t.json);else r.innerHTML=t.innerHTML}));var i,o=l[function(n){var t=n.body,e=n.pbody;return t?"body":e?"pbody":"head"}(t)];o.some((function(n,t){return i=t,r.isEqualNode(n)}))&&(i||0===i)?o.splice(i,1):s.push(r)}}));var m=[];for(var h in l)Array.prototype.push.apply(m,l[h]);return m.forEach((function(n){n.parentNode.removeChild(n)})),s.forEach((function(n){n.hasAttribute("data-body")?o.appendChild(n):n.hasAttribute("data-pbody")?o.insertBefore(n,o.firstChild):i.appendChild(n)})),{oldTags:m,newTags:s}}function on(n,t,r){var i=t=t||{},o=i.M,a=i.h,u={},f=U(u,"html");if(n===a&&f.hasAttribute(o)){G(f,o);var c=!1;return w.forEach((function(n){r[n]&&X(t,n,r[n])&&(c=!0)})),c&&Y(),!1}var s,d={},l={};for(var v in r)if(!D(N,v))if("title"!==v){if(D(T,v)){var m=v.substr(0,4);en(n,t,v,r[v],U(u,m))}else if(e(r[v])){var h=rn(n,t,v,r[v],U(u,"head"),U(u,"body")),p=h.oldTags,y=h.newTags;y.length&&(d[v]=y,l[v]=p)}}else((s=r.title)||""===s)&&(document.title=s);return{S:d,D:l}}function an(n,t,e){return{set:function(r){return function(n,t,e,r){if(n&&n.$el)return on(t,e,r);(nn=nn||{})[t]=r}(n,t,e,r)},remove:function(){return function(n,t,e){if(n&&n.$el){var r={},i=!0,o=!1,a=void 0;try{for(var u,f=T[Symbol.iterator]();!(i=(u=f.next()).done);i=!0){var c=u.value,s=c.substr(0,4);en(t,e,c,{},U(r,s))}}catch(n){o=!0,a=n}finally{try{i||null==f.return||f.return()}finally{if(o)throw a}}return function(n,t){var e=n.k;_(E("[".concat(e,'="').concat(t,'"]'))).map((function(n){return n.remove()}))}(e,t)}nn[t]&&(delete nn[t],fn())}(n,t,e)}}}function un(){return nn}function fn(n){!n&&Object.keys(nn).length||(nn=void 0)}function cn(n,t){if(t=t||{},!n._vueMeta)return f("This vue app/component has no vue-meta configuration"),{};var e=function(n,t,e,r){e=e||[];var i=(n=n||{}).j;return t.title&&(t.titleChunk=t.title),t.titleTemplate&&"%s"!==t.titleTemplate&&P({component:r,T:"title"},t,t.titleTemplate,t.titleChunk||""),t.base&&(t.base=Object.keys(t.base).length?[t.base]:[]),t.meta&&(t.meta=t.meta.filter((function(n,t,e){return!n[i]||t===K(e,(function(t){return t[i]===n[i]}))})),t.meta.forEach((function(t){return P(n,t)}))),L(n,t,e)}(t,q(t,n),H,n),r=on(n._vueMeta.m,t,e);r&&a(e.changed)&&(e.changed(e,r.S,r.D),r={addedTags:r.S,removedTags:r.D});var i=un();if(i){for(var o in i)on(o,t,i[o]),delete i[o];fn(!0)}return{vm:n,metaInfo:e,tags:r}}function sn(n){n=n||{};var t=this.$root;return{getOptions:function(){return function(n){var t={};for(var e in n)t[e]=n[e];return t}(n)},setOptions:function(e){e&&e.p&&(n.p=!!e.p,B(t));if(e&&"debounceWait"in e){var r=parseInt(e.t);isNaN(r)||(n.t=r)}e&&"waitOnDestroyed"in e&&(n.g=!!e.g)},refresh:function(){return cn(t,n)},inject:function(){return c("inject")},pause:function(){return V(t)},resume:function(){return z(t)},addApp:function(e){return an(t,e,n)}}}var dn={version:"2.3.3",install:function(n,t){n.__vuemeta_installed||(n.__vuemeta_installed=!0,t=function(n){return{v:(n=i(n)?n:{}).keyName||d,k:n.attribute||l,M:n.ssrAttribute||v,j:n.tagIDKeyName||m,T:n.contentKeyName||h,N:n.metaTemplateKeyName||p,t:r(n.debounceWait)?b:n.debounceWait,g:r(n.waitOnDestroyed)?y:n.waitOnDestroyed,h:n.ssrAppId||g,p:!!n.refreshOnceOnNavigation}}(t),n.prototype.$meta=function(){return sn.call(this,t)},n.mixin(W(n,t)))},generate:function(n,t){return c("generate")},hasMetaInfo:x};export default dn; diff --git a/dist/vue-meta.esm.js b/dist/vue-meta.esm.js deleted file mode 100644 index 7b24202..0000000 --- a/dist/vue-meta.esm.js +++ /dev/null @@ -1,1920 +0,0 @@ -/** - * vue-meta v2.3.3 - * (c) 2020 - * - Declan de Wet - * - Sébastien Chopin (@Atinux) - * - Pim (@pimlie) - * - All the amazing contributors - * @license MIT - */ - -import deepmerge from 'deepmerge'; - -var version = "2.3.3"; - -function _typeof(obj) { - "@babel/helpers - typeof"; - - if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { - _typeof = function (obj) { - return typeof obj; - }; - } else { - _typeof = function (obj) { - return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; - }; - } - - return _typeof(obj); -} - -function _defineProperty(obj, key, value) { - if (key in obj) { - Object.defineProperty(obj, key, { - value: value, - enumerable: true, - configurable: true, - writable: true - }); - } else { - obj[key] = value; - } - - return obj; -} - -function ownKeys(object, enumerableOnly) { - var keys = Object.keys(object); - - if (Object.getOwnPropertySymbols) { - var symbols = Object.getOwnPropertySymbols(object); - if (enumerableOnly) symbols = symbols.filter(function (sym) { - return Object.getOwnPropertyDescriptor(object, sym).enumerable; - }); - keys.push.apply(keys, symbols); - } - - return keys; -} - -function _objectSpread2(target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i] != null ? arguments[i] : {}; - - if (i % 2) { - ownKeys(Object(source), true).forEach(function (key) { - _defineProperty(target, key, source[key]); - }); - } else if (Object.getOwnPropertyDescriptors) { - Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); - } else { - ownKeys(Object(source)).forEach(function (key) { - Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); - }); - } - } - - return target; -} - -function _toConsumableArray(arr) { - return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); -} - -function _arrayWithoutHoles(arr) { - if (Array.isArray(arr)) { - for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; - - return arr2; - } -} - -function _iterableToArray(iter) { - if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); -} - -function _nonIterableSpread() { - throw new TypeError("Invalid attempt to spread non-iterable instance"); -} - -/** - * checks if passed argument is an array - * @param {any} arg - the object to check - * @return {Boolean} - true if `arg` is an array - */ -function isArray(arg) { - return Array.isArray(arg); -} -function isUndefined(arg) { - return typeof arg === 'undefined'; -} -function isObject(arg) { - return _typeof(arg) === 'object'; -} -function isPureObject(arg) { - return _typeof(arg) === 'object' && arg !== null; -} -function isFunction(arg) { - return typeof arg === 'function'; -} -function isString(arg) { - return typeof arg === 'string'; -} - -function hasGlobalWindowFn() { - try { - return !isUndefined(window); - } catch (e) { - return false; - } -} -var hasGlobalWindow = hasGlobalWindowFn(); - -var _global = hasGlobalWindow ? window : global; - -var console = _global.console || {}; -function warn(str) { - /* istanbul ignore next */ - if (!console || !console.warn) { - return; - } - - console.warn(str); -} -var showWarningNotSupported = function showWarningNotSupported() { - return warn('This vue app/component has no vue-meta configuration'); -}; - -/** - * These are constant variables used throughout the application. - */ -// set some sane defaults -var defaultInfo = { - title: undefined, - titleChunk: '', - titleTemplate: '%s', - htmlAttrs: {}, - bodyAttrs: {}, - headAttrs: {}, - base: [], - link: [], - meta: [], - style: [], - script: [], - noscript: [], - __dangerouslyDisableSanitizers: [], - __dangerouslyDisableSanitizersByTagID: {} -}; -var rootConfigKey = '_vueMeta'; // 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 keyName = 'metaInfo'; // This is the attribute vue-meta arguments on elements to know which it should -// manage and which it should ignore. - -var 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 ssrAttribute = '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 tagIDKeyName = 'vmid'; // This is the key name for possible meta templates - -var metaTemplateKeyName = 'template'; // This is the key name for the content-holding property - -var contentKeyName = 'content'; // The id used for the ssr app - -var ssrAppId = 'ssr'; // How long meta update - -var debounceWait = 10; // How long meta update - -var waitOnDestroyed = true; -var defaultOptions = { - keyName: keyName, - attribute: attribute, - ssrAttribute: ssrAttribute, - tagIDKeyName: tagIDKeyName, - contentKeyName: contentKeyName, - metaTemplateKeyName: metaTemplateKeyName, - waitOnDestroyed: waitOnDestroyed, - debounceWait: debounceWait, - ssrAppId: ssrAppId -}; // might be a bit ugly, but minimizes the browser bundles a bit - -var defaultInfoKeys = Object.keys(defaultInfo); // The metaInfo property keys which are used to disable escaping - -var disableOptionKeys = [defaultInfoKeys[12], defaultInfoKeys[13]]; // List of metaInfo property keys which are configuration options (and dont generate html) - -var metaInfoOptionKeys = [defaultInfoKeys[1], defaultInfoKeys[2], 'changed'].concat(disableOptionKeys); // List of metaInfo property keys which only generates attributes and no tags - -var metaInfoAttributeKeys = [defaultInfoKeys[3], defaultInfoKeys[4], defaultInfoKeys[5]]; // HTML elements which support the onload event - -var tagsSupportingOnload = ['link', 'style', 'script']; // HTML elements which dont have a head tag (shortened to our needs) -// see: https://www.w3.org/TR/html52/document-metadata.html - -var tagsWithoutEndTag = ['base', 'meta', 'link']; // HTML elements which can have inner content (shortened to our needs) - -var tagsWithInnerContent = ['noscript', 'script', 'style']; // Attributes which are inserted as childNodes instead of HTMLAttribute - -var tagAttributeAsInnerContent = ['innerHTML', 'cssText', 'json']; -var tagProperties = ['once', 'skip', 'template']; // Attributes which should be added with data- prefix - -var commonDataAttributes = ['body', 'pbody']; // from: https://github.com/kangax/html-minifier/blob/gh-pages/src/htmlminifier.js#L202 - -var booleanHtmlAttributes = ['allowfullscreen', 'amp', 'async', 'autofocus', 'autoplay', 'checked', 'compact', 'controls', 'declare', 'default', 'defaultchecked', 'defaultmuted', 'defaultselected', 'defer', 'disabled', 'enabled', 'formnovalidate', 'hidden', 'indeterminate', 'inert', 'ismap', 'itemscope', 'loop', 'multiple', 'muted', 'nohref', 'noresize', 'noshade', 'novalidate', 'nowrap', 'open', 'pauseonexit', 'readonly', 'required', 'reversed', 'scoped', 'seamless', 'selected', 'sortable', 'truespeed', 'typemustmatch', 'visible']; - -var batchId = null; -function triggerUpdate(_ref, rootVm, hookName) { - var debounceWait = _ref.debounceWait; - - // if an update was triggered during initialization or when an update was triggered by the - // metaInfo watcher, set initialized to null - // then we keep falsy value but know we need to run a triggerUpdate after initialization - if (!rootVm[rootConfigKey].initialized && (rootVm[rootConfigKey].initializing || hookName === 'watcher')) { - rootVm[rootConfigKey].initialized = null; - } - - if (rootVm[rootConfigKey].initialized && !rootVm[rootConfigKey].pausing) { - // batch potential DOM updates to prevent extraneous re-rendering - // eslint-disable-next-line no-void - batchUpdate(function () { - return void rootVm.$meta().refresh(); - }, debounceWait); - } -} -/** - * Performs a batched update. - * - * @param {(null|Number)} id - the ID of this update - * @param {Function} callback - the update to perform - * @return {Number} id - a new ID - */ - -function batchUpdate(callback, timeout) { - timeout = timeout === undefined ? 10 : timeout; - - if (!timeout) { - callback(); - return; - } - - clearTimeout(batchId); - batchId = setTimeout(function () { - callback(); - }, timeout); - return batchId; -} - -/* - * To reduce build size, this file provides simple polyfills without - * overly excessive type checking and without modifying - * the global Array.prototype - * The polyfills are automatically removed in the commonjs build - * Also, only files in client/ & shared/ should use these functions - * files in server/ still use normal js function - */ -function find(array, predicate, thisArg) { - if ( !Array.prototype.find) { - // idx needs to be a Number, for..in returns string - for (var idx = 0; idx < array.length; idx++) { - if (predicate.call(thisArg, array[idx], idx, array)) { - return array[idx]; - } - } - - return; - } - - return array.find(predicate, thisArg); -} -function findIndex(array, predicate, thisArg) { - if ( !Array.prototype.findIndex) { - // idx needs to be a Number, for..in returns string - for (var idx = 0; idx < array.length; idx++) { - if (predicate.call(thisArg, array[idx], idx, array)) { - return idx; - } - } - - return -1; - } - - return array.findIndex(predicate, thisArg); -} -function toArray(arg) { - if ( !Array.from) { - return Array.prototype.slice.call(arg); - } - - return Array.from(arg); -} -function includes(array, value) { - if ( !Array.prototype.includes) { - for (var idx in array) { - if (array[idx] === value) { - return true; - } - } - - return false; - } - - return array.includes(value); -} - -function hasMetaInfo(vm) { - vm = vm || this; - return vm && (vm[rootConfigKey] === true || isObject(vm[rootConfigKey])); -} // a component is in a metaInfo branch when itself has meta info or one of its (grand-)children has - -function inMetaInfoBranch(vm) { - vm = vm || this; - return vm && !isUndefined(vm[rootConfigKey]); -} - -function pause(rootVm, refresh) { - rootVm[rootConfigKey].pausing = true; - return function () { - return resume(rootVm, refresh); - }; -} -function resume(rootVm, refresh) { - rootVm[rootConfigKey].pausing = false; - - if (refresh || refresh === undefined) { - return rootVm.$meta().refresh(); - } -} - -function addNavGuards(rootVm) { - var router = rootVm.$router; // return when nav guards already added or no router exists - - if (rootVm[rootConfigKey].navGuards || !router) { - /* istanbul ignore next */ - return; - } - - rootVm[rootConfigKey].navGuards = true; - router.beforeEach(function (to, from, next) { - pause(rootVm); - next(); - }); - router.afterEach(function () { - rootVm.$nextTick(function () { - var _resume = resume(rootVm), - metaInfo = _resume.metaInfo; - - if (metaInfo && isFunction(metaInfo.afterNavigation)) { - metaInfo.afterNavigation(metaInfo); - } - }); - }); -} - -var appId = 1; -function createMixin(Vue, options) { - // for which Vue lifecycle hooks should the metaInfo be refreshed - var updateOnLifecycleHook = ['activated', 'deactivated', 'beforeMount']; // watch for client side component updates - - return { - beforeCreate: function beforeCreate() { - var _this2 = this; - - var rootKey = '$root'; - var $root = this[rootKey]; - var $options = this.$options; - var devtoolsEnabled = Vue.config.devtools; - Object.defineProperty(this, '_hasMetaInfo', { - configurable: true, - get: function get() { - // Show deprecation warning once when devtools enabled - if (devtoolsEnabled && !$root[rootConfigKey].deprecationWarningShown) { - warn('VueMeta DeprecationWarning: _hasMetaInfo has been deprecated and will be removed in a future version. Please use hasMetaInfo(vm) instead'); - $root[rootConfigKey].deprecationWarningShown = true; - } - - return hasMetaInfo(this); - } - }); // 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 (isUndefined($options[options.keyName]) || $options[options.keyName] === null) { - return; - } - - if (!$root[rootConfigKey]) { - $root[rootConfigKey] = { - appId: appId - }; - appId++; - - if (devtoolsEnabled && $root.$options[options.keyName]) { - // use nextTick so the children should be added to $root - this.$nextTick(function () { - // find the first child that lists fnOptions - var child = find($root.$children, function (c) { - return c.$vnode && c.$vnode.fnOptions; - }); - - if (child && child.$vnode.fnOptions[options.keyName]) { - warn("VueMeta has detected a possible global mixin which adds a ".concat(options.keyName, " property to all Vue components on the page. This could cause severe performance issues. If possible, use $meta().addApp to add meta information instead")); - } - }); - } - } // to speed up updates we keep track of branches which have a component with vue-meta info defined - // if _vueMeta = true it has info, if _vueMeta = false a child has info - - - if (!this[rootConfigKey]) { - this[rootConfigKey] = true; - var parent = this.$parent; - - while (parent && parent !== $root) { - if (isUndefined(parent[rootConfigKey])) { - parent[rootConfigKey] = false; - } - - parent = parent.$parent; - } - } // coerce function-style metaInfo to a computed prop so we can observe - // it on creation - - - if (isFunction($options[options.keyName])) { - $options.computed = $options.computed || {}; - $options.computed.$metaInfo = $options[options.keyName]; - - if (!this.$isServer) { - // 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) - this.$on('hook:created', function () { - this.$watch('$metaInfo', function () { - triggerUpdate(options, this[rootKey], 'watcher'); - }); - }); - } - } // force an initial refresh on page load and prevent other lifecycleHooks - // to triggerUpdate until this initial refresh is finished - // this is to make sure that when a page is opened in an inactive tab which - // has throttled rAF/timers we still immediately set the page title - - - if (isUndefined($root[rootConfigKey].initialized)) { - $root[rootConfigKey].initialized = this.$isServer; - - if (!$root[rootConfigKey].initialized) { - if (!$root[rootConfigKey].initializedSsr) { - $root[rootConfigKey].initializedSsr = true; - this.$on('hook:beforeMount', function () { - var $root = this; // if this Vue-app was server rendered, set the appId to 'ssr' - // only one SSR app per page is supported - - if ($root.$el && $root.$el.nodeType === 1 && $root.$el.hasAttribute('data-server-rendered')) { - $root[rootConfigKey].appId = options.ssrAppId; - } - }); - } // we use the mounted hook here as on page load - - - this.$on('hook:mounted', function () { - var $root = this[rootKey]; - - if (!$root[rootConfigKey].initialized) { - // used in triggerUpdate to check if a change was triggered - // during initialization - $root[rootConfigKey].initializing = true; // refresh meta in nextTick so all child components have loaded - - this.$nextTick(function () { - var _$root$$meta$refresh = $root.$meta().refresh(), - tags = _$root$$meta$refresh.tags, - metaInfo = _$root$$meta$refresh.metaInfo; // After ssr hydration (identifier by tags === false) check - // if initialized was set to null in triggerUpdate. That'd mean - // that during initilazation changes where triggered which need - // to be applied OR a metaInfo watcher was triggered before the - // current hook was called - // (during initialization all changes are blocked) - - - if (tags === false && $root[rootConfigKey].initialized === null) { - this.$nextTick(function () { - return triggerUpdate(options, $root, 'init'); - }); - } - - $root[rootConfigKey].initialized = true; - delete $root[rootConfigKey].initializing; // add the navigation guards if they havent been added yet - // they are needed for the afterNavigation callback - - if (!options.refreshOnceOnNavigation && metaInfo.afterNavigation) { - addNavGuards($root); - } - }); - } - }); // add the navigation guards if requested - - if (options.refreshOnceOnNavigation) { - addNavGuards($root); - } - } - } - - this.$on('hook:destroyed', function () { - var _this = this; - - // do not trigger refresh: - // - when user configured to not wait for transitions on destroyed - // - when the component doesnt have a parent - // - doesnt have metaInfo defined - if (!this.$parent || !hasMetaInfo(this)) { - return; - } - - delete this._hasMetaInfo; - this.$nextTick(function () { - if (!options.waitOnDestroyed || !_this.$el || !_this.$el.offsetParent) { - triggerUpdate(options, _this.$root, 'destroyed'); - return; - } // Wait that element is hidden before refreshing meta tags (to support animations) - - - var interval = setInterval(function () { - if (_this.$el && _this.$el.offsetParent !== null) { - /* istanbul ignore next line */ - return; - } - - clearInterval(interval); - triggerUpdate(options, _this.$root, 'destroyed'); - }, 50); - }); - }); // do not trigger refresh on the server side - - if (this.$isServer) { - /* istanbul ignore next */ - return; - } // no need to add this hooks on server side - - - updateOnLifecycleHook.forEach(function (lifecycleHook) { - _this2.$on("hook:".concat(lifecycleHook), function () { - triggerUpdate(options, this[rootKey], lifecycleHook); - }); - }); - } - }; -} - -function setOptions(options) { - // combine options - options = isObject(options) ? options : {}; // The options are set like this so they can - // be minified by terser while keeping the - // user api intact - // terser --mangle-properties keep_quoted=strict - - /* eslint-disable dot-notation */ - - return { - keyName: options['keyName'] || defaultOptions.keyName, - attribute: options['attribute'] || defaultOptions.attribute, - ssrAttribute: options['ssrAttribute'] || defaultOptions.ssrAttribute, - tagIDKeyName: options['tagIDKeyName'] || defaultOptions.tagIDKeyName, - contentKeyName: options['contentKeyName'] || defaultOptions.contentKeyName, - metaTemplateKeyName: options['metaTemplateKeyName'] || defaultOptions.metaTemplateKeyName, - debounceWait: isUndefined(options['debounceWait']) ? defaultOptions.debounceWait : options['debounceWait'], - waitOnDestroyed: isUndefined(options['waitOnDestroyed']) ? defaultOptions.waitOnDestroyed : options['waitOnDestroyed'], - ssrAppId: options['ssrAppId'] || defaultOptions.ssrAppId, - refreshOnceOnNavigation: !!options['refreshOnceOnNavigation'] - }; - /* eslint-enable dot-notation */ -} -function getOptions(options) { - var optionsCopy = {}; - - for (var key in options) { - optionsCopy[key] = options[key]; - } - - return optionsCopy; -} - -function ensureIsArray(arg, key) { - if (!key || !isObject(arg)) { - return isArray(arg) ? arg : []; - } - - if (!isArray(arg[key])) { - arg[key] = []; - } - - return arg; -} - -var serverSequences = [[/&/g, '&'], [//g, '>'], [/"/g, '"'], [/'/g, ''']]; -var clientSequences = [[/&/g, "&"], [//g, ">"], [/"/g, "\""], [/'/g, "'"]]; // sanitizes potentially dangerous characters - -function escape(info, options, escapeOptions, escapeKeys) { - var tagIDKeyName = options.tagIDKeyName; - var _escapeOptions$doEsca = escapeOptions.doEscape, - doEscape = _escapeOptions$doEsca === void 0 ? function (v) { - return v; - } : _escapeOptions$doEsca; - var escaped = {}; - - for (var key in info) { - var value = info[key]; // no need to escape configuration options - - if (includes(metaInfoOptionKeys, key)) { - escaped[key] = value; - continue; - } // do not use destructuring for disableOptionKeys, it increases transpiled size - // due to var checks while we are guaranteed the structure of the cb - - - var disableKey = disableOptionKeys[0]; - - if (escapeOptions[disableKey] && includes(escapeOptions[disableKey], key)) { - // this info[key] doesnt need to escaped if the option is listed in __dangerouslyDisableSanitizers - escaped[key] = value; - continue; - } - - var tagId = info[tagIDKeyName]; - - if (tagId) { - disableKey = disableOptionKeys[1]; // keys which are listed in __dangerouslyDisableSanitizersByTagID for the current vmid do not need to be escaped - - if (escapeOptions[disableKey] && escapeOptions[disableKey][tagId] && includes(escapeOptions[disableKey][tagId], key)) { - escaped[key] = value; - continue; - } - } - - if (isString(value)) { - escaped[key] = doEscape(value); - } else if (isArray(value)) { - escaped[key] = value.map(function (v) { - if (isPureObject(v)) { - return escape(v, options, escapeOptions, true); - } - - return doEscape(v); - }); - } else if (isPureObject(value)) { - escaped[key] = escape(value, options, escapeOptions, true); - } else { - escaped[key] = value; - } - - if (escapeKeys) { - var escapedKey = doEscape(key); - - if (key !== escapedKey) { - escaped[escapedKey] = escaped[key]; - delete escaped[key]; - } - } - } - - return escaped; -} -function escapeMetaInfo(options, info, escapeSequences) { - escapeSequences = escapeSequences || []; // do not use destructuring for seq, it increases transpiled size - // due to var checks while we are guaranteed the structure of the cb - - var escapeOptions = { - doEscape: function doEscape(value) { - return escapeSequences.reduce(function (val, seq) { - return val.replace(seq[0], seq[1]); - }, value); - } - }; - disableOptionKeys.forEach(function (disableKey, index) { - if (index === 0) { - ensureIsArray(info, disableKey); - } else if (index === 1) { - for (var key in info[disableKey]) { - ensureIsArray(info[disableKey], key); - } - } - - escapeOptions[disableKey] = info[disableKey]; - }); // begin sanitization - - return escape(info, options, escapeOptions); -} - -function applyTemplate(_ref, headObject, template, chunk) { - var component = _ref.component, - metaTemplateKeyName = _ref.metaTemplateKeyName, - contentKeyName = _ref.contentKeyName; - - if (template === true || headObject[metaTemplateKeyName] === true) { - // abort, template was already applied - return false; - } - - if (isUndefined(template) && headObject[metaTemplateKeyName]) { - template = headObject[metaTemplateKeyName]; - headObject[metaTemplateKeyName] = true; - } // return early if no template defined - - - if (!template) { - // cleanup faulty template properties - delete headObject[metaTemplateKeyName]; - return false; - } - - if (isUndefined(chunk)) { - chunk = headObject[contentKeyName]; - } - - headObject[contentKeyName] = isFunction(template) ? template.call(component, chunk) : template.replace(/%s/g, chunk); - return true; -} - -function _arrayMerge(_ref, target, source) { - var component = _ref.component, - tagIDKeyName = _ref.tagIDKeyName, - metaTemplateKeyName = _ref.metaTemplateKeyName, - contentKeyName = _ref.contentKeyName; - // 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 - var destination = []; - - if (!target.length && !source.length) { - return destination; - } - - target.forEach(function (targetItem, targetIndex) { - // no tagID so no need to check for duplicity - if (!targetItem[tagIDKeyName]) { - destination.push(targetItem); - return; - } - - var sourceIndex = findIndex(source, function (item) { - return item[tagIDKeyName] === targetItem[tagIDKeyName]; - }); - var sourceItem = source[sourceIndex]; // source doesnt contain any duplicate vmid's, we can keep targetItem - - if (sourceIndex === -1) { - destination.push(targetItem); - return; - } // when sourceItem explictly defines contentKeyName or innerHTML as undefined, its - // an indication that we need to skip the default behaviour or child has preference over parent - // which means we keep the targetItem and ignore/remove the sourceItem - - - if (contentKeyName in sourceItem && sourceItem[contentKeyName] === undefined || 'innerHTML' in sourceItem && sourceItem.innerHTML === undefined) { - destination.push(targetItem); // remove current index from source array so its not concatenated to destination below - - source.splice(sourceIndex, 1); - return; - } // we now know that targetItem is a duplicate and we should ignore it in favor of sourceItem - // if source specifies null as content then ignore both the target as the source - - - if (sourceItem[contentKeyName] === null || sourceItem.innerHTML === null) { - // remove current index from source array so its not concatenated to destination below - source.splice(sourceIndex, 1); - return; - } // now we only need to check if the target has a template to combine it with the source - - - var targetTemplate = targetItem[metaTemplateKeyName]; - - if (!targetTemplate) { - return; - } - - var sourceTemplate = sourceItem[metaTemplateKeyName]; - - if (!sourceTemplate) { - // use parent template and child content - applyTemplate({ - component: component, - metaTemplateKeyName: metaTemplateKeyName, - contentKeyName: contentKeyName - }, sourceItem, targetTemplate); // set template to true to indicate template was already applied - - sourceItem.template = true; - return; - } - - if (!sourceItem[contentKeyName]) { - // use parent content and child template - applyTemplate({ - component: component, - metaTemplateKeyName: metaTemplateKeyName, - contentKeyName: contentKeyName - }, sourceItem, undefined, targetItem[contentKeyName]); - } - }); - return destination.concat(source); -} -var warningShown = false; -function merge(target, source, options) { - options = options || {}; // remove properties explicitly set to false so child components can - // optionally _not_ overwrite the parents content - // (for array properties this is checked in arrayMerge) - - if (source.title === undefined) { - delete source.title; - } - - metaInfoAttributeKeys.forEach(function (attrKey) { - if (!source[attrKey]) { - return; - } - - for (var key in source[attrKey]) { - if (key in source[attrKey] && source[attrKey][key] === undefined) { - if (includes(booleanHtmlAttributes, key) && !warningShown) { - warn('VueMeta: Please note that since v2 the value undefined is not used to indicate boolean attributes anymore, see migration guide for details'); - warningShown = true; - } - - delete source[attrKey][key]; - } - } - }); - return deepmerge(target, source, { - arrayMerge: function arrayMerge(t, s) { - return _arrayMerge(options, t, s); - } - }); -} - -function getComponentMetaInfo(options, component) { - return getComponentOption(options || {}, component, defaultInfo); -} -/** - * 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 {Boolean} opts.deep - look for data in child components as well? - * @param {Function} opts.arrayMerge - how should arrays be merged? - * @param {String} opts.keyName - the name of the option to look for - * @param {Object} [result={}] - result so far - * @return {Object} result - final aggregated result - */ - -function getComponentOption(options, component, result) { - result = result || {}; - - if (component._inactive) { - return result; - } - - options = options || {}; - var _options = options, - keyName = _options.keyName; - var $metaInfo = component.$metaInfo, - $options = component.$options, - $children = component.$children; // only collect option data if it exists - - if ($options[keyName]) { - // if $metaInfo exists then [keyName] was defined as a function - // and set to the computed prop $metaInfo in the mixin - // using the computed prop should be a small performance increase - // because Vue caches those internally - var data = $metaInfo || $options[keyName]; // only merge data with result when its an object - // eg it could be a function when metaInfo() returns undefined - // dueo to the or statement above - - if (isObject(data)) { - result = merge(result, data, options); - } - } // collect & aggregate child options if deep = true - - - if ($children.length) { - $children.forEach(function (childComponent) { - // check if the childComponent is in a branch - // return otherwise so we dont walk all component branches unnecessarily - if (!inMetaInfoBranch(childComponent)) { - return; - } - - result = getComponentOption(options, childComponent, result); - }); - } - - return result; -} - -var querySelector = function querySelector(arg, el) { - return (el || document).querySelectorAll(arg); -}; -function getTag(tags, tag) { - if (!tags[tag]) { - tags[tag] = document.getElementsByTagName(tag)[0]; - } - - return tags[tag]; -} -function getElementsKey(_ref) { - var body = _ref.body, - pbody = _ref.pbody; - return body ? 'body' : pbody ? 'pbody' : 'head'; -} -function queryElements(parentNode, _ref2, attributes) { - var appId = _ref2.appId, - attribute = _ref2.attribute, - type = _ref2.type, - tagIDKeyName = _ref2.tagIDKeyName; - attributes = attributes || {}; - var queries = ["".concat(type, "[").concat(attribute, "=\"").concat(appId, "\"]"), "".concat(type, "[data-").concat(tagIDKeyName, "]")].map(function (query) { - for (var key in attributes) { - var val = attributes[key]; - var attributeValue = val && val !== true ? "=\"".concat(val, "\"") : ''; - query += "[data-".concat(key).concat(attributeValue, "]"); - } - - return query; - }); - return toArray(querySelector(queries.join(', '), parentNode)); -} -function removeElementsByAppId(_ref3, appId) { - var attribute = _ref3.attribute; - toArray(querySelector("[".concat(attribute, "=\"").concat(appId, "\"]"))).map(function (el) { - return el.remove(); - }); -} -function removeAttribute(el, attributeName) { - el.removeAttribute(attributeName); -} - -var callbacks = []; -function isDOMComplete(d) { - return (d || document).readyState === 'complete'; -} -function addCallback(query, callback) { - if (arguments.length === 1) { - callback = query; - query = ''; - } - - callbacks.push([query, callback]); -} -function addCallbacks(_ref, type, tags, autoAddListeners) { - var tagIDKeyName = _ref.tagIDKeyName; - var hasAsyncCallback = false; - tags.forEach(function (tag) { - if (!tag[tagIDKeyName] || !tag.callback) { - return; - } - - hasAsyncCallback = true; - addCallback("".concat(type, "[data-").concat(tagIDKeyName, "=\"").concat(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 = function () { - applyCallbacks(); - }; -} -function applyCallbacks(matchElement) { - callbacks.forEach(function (args) { - // do not use destructuring for args, it increases transpiled size - // due to var checks while we are guaranteed the structure of the cb - var query = args[0]; - var callback = args[1]; - var selector = "".concat(query, "[onload=\"this.__vm_l=1\"]"); - var elements = []; - - if (!matchElement) { - elements = toArray(querySelector(selector)); - } - - if (matchElement && matchElement.matches(selector)) { - elements = [matchElement]; - } - - elements.forEach(function (element) { - /* __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) { - return; - } - - var onload = function 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 - */ - - removeAttribute(element, '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(); - return; - } - - if (!element.__vm_ev) { - element.__vm_ev = true; - element.addEventListener('load', onload); - } - }); - }); -} - -// instead of adding it to the html - -var attributeMap = {}; -/** - * 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 - */ - -function updateAttribute(appId, options, type, attrs, tag) { - var _ref = options || {}, - attribute = _ref.attribute; - - var vueMetaAttrString = tag.getAttribute(attribute); - - if (vueMetaAttrString) { - attributeMap[type] = JSON.parse(decodeURI(vueMetaAttrString)); - removeAttribute(tag, attribute); - } - - var data = attributeMap[type] || {}; - var toUpdate = []; // remove attributes from the map - // which have been removed for this appId - - for (var attr in data) { - if (data[attr] && appId in data[attr]) { - toUpdate.push(attr); - - if (!attrs[attr]) { - delete data[attr][appId]; - } - } - } - - for (var _attr in attrs) { - var attrData = data[_attr]; - - if (!attrData || attrData[appId] !== attrs[_attr]) { - toUpdate.push(_attr); - - if (attrs[_attr]) { - data[_attr] = data[_attr] || {}; - data[_attr][appId] = attrs[_attr]; - } - } - } - - for (var _i = 0, _toUpdate = toUpdate; _i < _toUpdate.length; _i++) { - var _attr2 = _toUpdate[_i]; - var _attrData = data[_attr2]; - var attrValues = []; - - for (var _appId in _attrData) { - Array.prototype.push.apply(attrValues, [].concat(_attrData[_appId])); - } - - if (attrValues.length) { - var attrValue = includes(booleanHtmlAttributes, _attr2) && attrValues.some(Boolean) ? '' : attrValues.filter(Boolean).join(' '); - tag.setAttribute(_attr2, attrValue); - } else { - removeAttribute(tag, _attr2); - } - } - - attributeMap[type] = data; -} - -/** - * Updates the document title - * - * @param {String} title - the new title of the document - */ -function updateTitle(title) { - if (!title && title !== '') { - return; - } - - document.title = title; -} - -/** - * Updates meta tags inside and 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)} tags - an array of tag objects or a single object in case of base - * @return {Object} - a representation of what tags changed - */ - -function updateTag(appId, options, type, tags, head, body) { - var _ref = options || {}, - attribute = _ref.attribute, - tagIDKeyName = _ref.tagIDKeyName; - - var dataAttributes = commonDataAttributes.slice(); - dataAttributes.push(tagIDKeyName); - var newElements = []; - var queryOptions = { - appId: appId, - attribute: attribute, - type: type, - tagIDKeyName: tagIDKeyName - }; - var currentElements = { - head: queryElements(head, queryOptions), - pbody: queryElements(body, queryOptions, { - pbody: true - }), - body: queryElements(body, queryOptions, { - body: true - }) - }; - - 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.filter(function (x) { - var k = JSON.stringify(x); - var res = !includes(found, k); - found.push(k); - return res; - }); - } - - tags.forEach(function (tag) { - if (tag.skip) { - return; - } - - var newElement = document.createElement(type); - - if (!tag.once) { - newElement.setAttribute(attribute, appId); - } - - Object.keys(tag).forEach(function (attr) { - /* istanbul ignore next */ - if (includes(tagProperties, attr)) { - return; - } - - if (attr === 'innerHTML') { - newElement.innerHTML = tag.innerHTML; - return; - } - - if (attr === 'json') { - newElement.innerHTML = JSON.stringify(tag.json); - return; - } - - if (attr === 'cssText') { - if (newElement.styleSheet) { - /* istanbul ignore next */ - newElement.styleSheet.cssText = tag.cssText; - } else { - newElement.appendChild(document.createTextNode(tag.cssText)); - } - - return; - } - - if (attr === 'callback') { - newElement.onload = function () { - return tag[attr](newElement); - }; - - return; - } - - var _attr = includes(dataAttributes, attr) ? "data-".concat(attr) : attr; - - var isBooleanAttribute = includes(booleanHtmlAttributes, attr); - - if (isBooleanAttribute && !tag[attr]) { - return; - } - - var value = isBooleanAttribute ? '' : tag[attr]; - newElement.setAttribute(_attr, value); - }); - var oldElements = currentElements[getElementsKey(tag)]; // Remove a duplicate tag from domTagstoRemove, so it isn't cleared. - - var indexToDelete; - var hasEqualElement = oldElements.some(function (existingTag, index) { - indexToDelete = index; - return newElement.isEqualNode(existingTag); - }); - - if (hasEqualElement && (indexToDelete || indexToDelete === 0)) { - oldElements.splice(indexToDelete, 1); - } else { - newElements.push(newElement); - } - }); - var oldElements = []; - - for (var _type in currentElements) { - Array.prototype.push.apply(oldElements, currentElements[_type]); - } // remove old elements - - - oldElements.forEach(function (element) { - element.parentNode.removeChild(element); - }); // insert new elements - - newElements.forEach(function (element) { - if (element.hasAttribute('data-body')) { - body.appendChild(element); - return; - } - - if (element.hasAttribute('data-pbody')) { - body.insertBefore(element, body.firstChild); - return; - } - - head.appendChild(element); - }); - return { - oldTags: oldElements, - newTags: newElements - }; -} - -/** - * Performs client-side updates when new meta info is received - * - * @param {Object} newInfo - the meta info to update to - */ - -function updateClientMetaInfo(appId, options, newInfo) { - options = options || {}; - var _options = options, - ssrAttribute = _options.ssrAttribute, - ssrAppId = _options.ssrAppId; // only cache tags for current update - - var tags = {}; - var htmlTag = getTag(tags, 'html'); // if this is a server render, then dont update - - if (appId === ssrAppId && htmlTag.hasAttribute(ssrAttribute)) { - // remove the server render attribute so we can update on (next) changes - removeAttribute(htmlTag, ssrAttribute); // add load callbacks if the - - var addLoadListeners = false; - tagsSupportingOnload.forEach(function (type) { - if (newInfo[type] && addCallbacks(options, type, newInfo[type])) { - addLoadListeners = true; - } - }); - - if (addLoadListeners) { - addListeners(); - } - - return false; - } // initialize tracked changes - - - var tagsAdded = {}; - var tagsRemoved = {}; - - for (var type in newInfo) { - // ignore these - if (includes(metaInfoOptionKeys, type)) { - continue; - } - - if (type === 'title') { - // update the title - updateTitle(newInfo.title); - continue; - } - - if (includes(metaInfoAttributeKeys, type)) { - var tagName = type.substr(0, 4); - updateAttribute(appId, options, type, newInfo[type], getTag(tags, tagName)); - continue; - } // tags should always be an array, ignore if it isnt - - - if (!isArray(newInfo[type])) { - continue; - } - - var _updateTag = updateTag(appId, options, type, newInfo[type], getTag(tags, 'head'), getTag(tags, 'body')), - oldTags = _updateTag.oldTags, - newTags = _updateTag.newTags; - - if (newTags.length) { - tagsAdded[type] = newTags; - tagsRemoved[type] = oldTags; - } - } - - return { - tagsAdded: tagsAdded, - tagsRemoved: tagsRemoved - }; -} - -var appsMetaInfo; -function addApp(rootVm, appId, options) { - return { - set: function set(metaInfo) { - return setMetaInfo(rootVm, appId, options, metaInfo); - }, - remove: function remove() { - return removeMetaInfo(rootVm, appId, options); - } - }; -} -function setMetaInfo(rootVm, appId, options, metaInfo) { - // if a vm exists _and_ its mounted then immediately update - if (rootVm && rootVm.$el) { - return updateClientMetaInfo(appId, options, metaInfo); - } // store for later, the info - // will be set on the first refresh - - - appsMetaInfo = appsMetaInfo || {}; - appsMetaInfo[appId] = metaInfo; -} -function removeMetaInfo(rootVm, appId, options) { - if (rootVm && rootVm.$el) { - var tags = {}; - var _iteratorNormalCompletion = true; - var _didIteratorError = false; - var _iteratorError = undefined; - - try { - for (var _iterator = metaInfoAttributeKeys[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { - var type = _step.value; - var tagName = type.substr(0, 4); - updateAttribute(appId, options, type, {}, getTag(tags, tagName)); - } - } catch (err) { - _didIteratorError = true; - _iteratorError = err; - } finally { - try { - if (!_iteratorNormalCompletion && _iterator.return != null) { - _iterator.return(); - } - } finally { - if (_didIteratorError) { - throw _iteratorError; - } - } - } - - return removeElementsByAppId(options, appId); - } - - if (appsMetaInfo[appId]) { - delete appsMetaInfo[appId]; - clearAppsMetaInfo(); - } -} -function getAppsMetaInfo() { - return appsMetaInfo; -} -function clearAppsMetaInfo(force) { - if (force || !Object.keys(appsMetaInfo).length) { - appsMetaInfo = undefined; - } -} - -/** - * 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 - */ - -function getMetaInfo(options, info, escapeSequences, component) { - options = options || {}; - escapeSequences = escapeSequences || []; - var _options = options, - tagIDKeyName = _options.tagIDKeyName; // 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.titleTemplate !== '%s') { - applyTemplate({ - component: component, - contentKeyName: 'title' - }, info, 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] : []; - } - - if (info.meta) { - // remove meta items with duplicate vmid's - info.meta = info.meta.filter(function (metaItem, index, arr) { - var hasVmid = !!metaItem[tagIDKeyName]; - - if (!hasVmid) { - return true; - } - - var isFirstItemForVmid = index === findIndex(arr, function (item) { - return item[tagIDKeyName] === metaItem[tagIDKeyName]; - }); - return isFirstItemForVmid; - }); // apply templates if needed - - info.meta.forEach(function (metaObject) { - return applyTemplate(options, metaObject); - }); - } - - return escapeMetaInfo(options, info, escapeSequences); -} - -/** - * 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 - */ - -function refresh(rootVm, options) { - options = options || {}; // make sure vue-meta was initiated - - if (!rootVm[rootConfigKey]) { - showWarningNotSupported(); - return {}; - } // collect & aggregate all metaInfo $options - - - var rawInfo = getComponentMetaInfo(options, rootVm); - var metaInfo = getMetaInfo(options, rawInfo, clientSequences, rootVm); - var appId = rootVm[rootConfigKey].appId; - var tags = updateClientMetaInfo(appId, options, metaInfo); // emit "event" with new info - - if (tags && isFunction(metaInfo.changed)) { - metaInfo.changed(metaInfo, tags.tagsAdded, tags.tagsRemoved); - tags = { - addedTags: tags.tagsAdded, - removedTags: tags.tagsRemoved - }; - } - - var appsMetaInfo = getAppsMetaInfo(); - - if (appsMetaInfo) { - for (var additionalAppId in appsMetaInfo) { - updateClientMetaInfo(additionalAppId, options, appsMetaInfo[additionalAppId]); - delete appsMetaInfo[additionalAppId]; - } - - clearAppsMetaInfo(true); - } - - return { - vm: rootVm, - metaInfo: metaInfo, - // eslint-disable-line object-shorthand - tags: tags - }; -} - -/** - * 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 - */ - -function attributeGenerator(options, type, data, addSrrAttribute) { - var _ref = options || {}, - attribute = _ref.attribute, - ssrAttribute = _ref.ssrAttribute; - - var attributeStr = ''; - - for (var attr in data) { - var attrData = data[attr]; - var attrValues = []; - - for (var appId in attrData) { - attrValues.push.apply(attrValues, _toConsumableArray([].concat(attrData[appId]))); - } - - if (attrValues.length) { - attributeStr += booleanHtmlAttributes.includes(attr) && attrValues.some(Boolean) ? "".concat(attr) : "".concat(attr, "=\"").concat(attrValues.join(' '), "\""); - attributeStr += ' '; - } - } - - if (attributeStr) { - attributeStr += "".concat(attribute, "=\"").concat(encodeURI(JSON.stringify(data)), "\""); - } - - if (type === 'htmlAttrs' && addSrrAttribute) { - return "".concat(ssrAttribute).concat(attributeStr ? ' ' : '').concat(attributeStr); - } - - return attributeStr; -} - -/** - * Generates title output for the server - * - * @param {'title'} type - the string "title" - * @param {String} data - the title text - * @return {Object} - the title generator - */ -function titleGenerator(options, type, data, generatorOptions) { - var _ref = generatorOptions || {}, - ln = _ref.ln; - - if (!data) { - return ''; - } - - return "<".concat(type, ">").concat(data, "").concat(ln ? '\n' : ''); -} - -/** - * 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)} tags - an array of tag objects or a single object in case of base - * @return {Object} - the tag generator - */ - -function tagGenerator(options, type, tags, generatorOptions) { - var _ref = options || {}, - ssrAppId = _ref.ssrAppId, - attribute = _ref.attribute, - tagIDKeyName = _ref.tagIDKeyName; - - var _ref2 = generatorOptions || {}, - appId = _ref2.appId, - _ref2$body = _ref2.body, - body = _ref2$body === void 0 ? false : _ref2$body, - _ref2$pbody = _ref2.pbody, - pbody = _ref2$pbody === void 0 ? false : _ref2$pbody, - _ref2$ln = _ref2.ln, - ln = _ref2$ln === void 0 ? false : _ref2$ln; - - var dataAttributes = [tagIDKeyName].concat(_toConsumableArray(commonDataAttributes)); - - if (!tags || !tags.length) { - return ''; - } // build a string containing all tags of this type - - - return tags.reduce(function (tagsStr, tag) { - if (tag.skip) { - return tagsStr; - } - - var tagKeys = Object.keys(tag); - - if (tagKeys.length === 0) { - return tagsStr; // Bail on empty tag object - } - - if (Boolean(tag.body) !== body || Boolean(tag.pbody) !== pbody) { - return tagsStr; - } - - var attrs = tag.once ? '' : " ".concat(attribute, "=\"").concat(appId || ssrAppId, "\""); // build a string containing all attributes of this tag - - for (var attr in tag) { - // these attributes are treated as children on the tag - if (tagAttributeAsInnerContent.includes(attr) || tagProperties.includes(attr)) { - continue; - } - - if (attr === 'callback') { - attrs += ' onload="this.__vm_l=1"'; - continue; - } // these form the attribute list for this tag - - - var prefix = ''; - - if (dataAttributes.includes(attr)) { - prefix = 'data-'; - } - - var isBooleanAttr = !prefix && booleanHtmlAttributes.includes(attr); - - if (isBooleanAttr && !tag[attr]) { - continue; - } - - attrs += " ".concat(prefix).concat(attr) + (isBooleanAttr ? '' : "=\"".concat(tag[attr], "\"")); - } - - var json = ''; - - if (tag.json) { - json = JSON.stringify(tag.json); - } // grab child content from one of these attributes, if possible - - - var content = tag.innerHTML || tag.cssText || json; // generate tag exactly without any other redundant attribute - // these tags have no end tag - - var hasEndTag = !tagsWithoutEndTag.includes(type); // these tag types will have content inserted - - var hasContent = hasEndTag && tagsWithInnerContent.includes(type); // the final string for this specific tag - - return "".concat(tagsStr, "<").concat(type).concat(attrs).concat(!hasContent && hasEndTag ? '/' : '', ">") + (hasContent ? "".concat(content, "") : '') + (ln ? '\n' : ''); - }, ''); -} - -/** - * 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)} data - the data value - * @return {Object} - the new injector - */ - -function generateServerInjector(options, metaInfo) { - var serverInjector = { - data: metaInfo, - extraData: undefined, - addInfo: function addInfo(appId, metaInfo) { - this.extraData = this.extraData || {}; - this.extraData[appId] = metaInfo; - }, - callInjectors: function callInjectors(opts) { - var m = this.injectors; // only call title for the head - - return (opts.body || opts.pbody ? '' : m.title.text(opts)) + m.meta.text(opts) + m.link.text(opts) + m.style.text(opts) + m.script.text(opts) + m.noscript.text(opts); - }, - injectors: { - head: function head(ln) { - return serverInjector.callInjectors({ - ln: ln - }); - }, - bodyPrepend: function bodyPrepend(ln) { - return serverInjector.callInjectors({ - ln: ln, - pbody: true - }); - }, - bodyAppend: function bodyAppend(ln) { - return serverInjector.callInjectors({ - ln: ln, - body: true - }); - } - } - }; - - var _loop = function _loop(type) { - if (metaInfoOptionKeys.includes(type)) { - return "continue"; - } - - serverInjector.injectors[type] = { - text: function text(arg) { - if (type === 'title') { - return titleGenerator(options, type, serverInjector.data[type], arg); - } - - if (metaInfoAttributeKeys.includes(type)) { - var attributeData = {}; - var data = serverInjector.data[type]; - - if (data) { - for (var attr in data) { - attributeData[attr] = _defineProperty({}, options.ssrAppId, data[attr]); - } - } - - if (serverInjector.extraData) { - for (var appId in serverInjector.extraData) { - var _data = serverInjector.extraData[appId][type]; - - if (_data) { - for (var _attr in _data) { - attributeData[_attr] = _objectSpread2({}, attributeData[_attr], _defineProperty({}, appId, _data[_attr])); - } - } - } - } - - return attributeGenerator(options, type, attributeData, arg); - } - - var str = tagGenerator(options, type, serverInjector.data[type], arg); - - if (serverInjector.extraData) { - for (var _appId in serverInjector.extraData) { - var _data2 = serverInjector.extraData[_appId][type]; - var extraStr = tagGenerator(options, type, _data2, _objectSpread2({ - appId: _appId - }, arg)); - str = "".concat(str).concat(extraStr); - } - } - - return str; - } - }; - }; - - for (var type in defaultInfo) { - var _ret = _loop(type); - - if (_ret === "continue") continue; - } - - return serverInjector; -} - -/** - * Converts the state of the meta info object such that each item - * can be compiled to a tag string on the server - * - * @vm {Object} - Vue instance - ideally the root component - * @return {Object} - server meta info with `toString` methods - */ - -function inject(rootVm, options) { - // make sure vue-meta was initiated - if (!rootVm[rootConfigKey]) { - showWarningNotSupported(); - return {}; - } // collect & aggregate all metaInfo $options - - - var rawInfo = getComponentMetaInfo(options, rootVm); - var metaInfo = getMetaInfo(options, rawInfo, serverSequences, rootVm); // generate server injector - - var serverInjector = generateServerInjector(options, metaInfo); // add meta info from additional apps - - var appsMetaInfo = getAppsMetaInfo(); - - if (appsMetaInfo) { - for (var additionalAppId in appsMetaInfo) { - serverInjector.addInfo(additionalAppId, appsMetaInfo[additionalAppId]); - delete appsMetaInfo[additionalAppId]; - } - - clearAppsMetaInfo(true); - } - - return serverInjector.injectors; -} - -function $meta(options) { - options = options || {}; - /** - * Returns an injector for server-side rendering. - * @this {Object} - the Vue instance (a root component) - * @return {Object} - injector - */ - - var $root = this.$root; - return { - getOptions: function getOptions$1() { - return getOptions(options); - }, - setOptions: function setOptions(newOptions) { - var refreshNavKey = 'refreshOnceOnNavigation'; - - if (newOptions && newOptions[refreshNavKey]) { - options.refreshOnceOnNavigation = !!newOptions[refreshNavKey]; - addNavGuards($root); - } - - var debounceWaitKey = 'debounceWait'; - - if (newOptions && debounceWaitKey in newOptions) { - var debounceWait = parseInt(newOptions[debounceWaitKey]); - - if (!isNaN(debounceWait)) { - options.debounceWait = debounceWait; - } - } - - var waitOnDestroyedKey = 'waitOnDestroyed'; - - if (newOptions && waitOnDestroyedKey in newOptions) { - options.waitOnDestroyed = !!newOptions[waitOnDestroyedKey]; - } - }, - refresh: function refresh$1() { - return refresh($root, options); - }, - inject: function inject$1() { - return inject($root, options) ; - }, - pause: function pause$1() { - return pause($root); - }, - resume: function resume$1() { - return resume($root); - }, - addApp: function addApp$1(appId) { - return addApp($root, appId, options); - } - }; -} - -function generate(rawInfo, options) { - options = setOptions(options); - var metaInfo = getMetaInfo(options, rawInfo, serverSequences); - var serverInjector = generateServerInjector(options, metaInfo); - return serverInjector.injectors; -} - -/** - * Plugin install function. - * @param {Function} Vue - the Vue constructor. - */ - -function install(Vue, options) { - if (Vue.__vuemeta_installed) { - return; - } - - Vue.__vuemeta_installed = true; - options = setOptions(options); - - Vue.prototype.$meta = function () { - return $meta.call(this, options); - }; - - Vue.mixin(createMixin(Vue, options)); -} - -var index = { - version: version, - install: install, - generate: function generate$1(metaInfo, options) { - return generate(metaInfo, options) ; - }, - hasMetaInfo: hasMetaInfo -}; - -export default index; diff --git a/dist/vue-meta.js b/dist/vue-meta.js deleted file mode 100644 index f568330..0000000 --- a/dist/vue-meta.js +++ /dev/null @@ -1,1643 +0,0 @@ -/** - * vue-meta v2.3.3 - * (c) 2020 - * - Declan de Wet - * - Sébastien Chopin (@Atinux) - * - Pim (@pimlie) - * - All the amazing contributors - * @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'; - - var version = "2.3.3"; - - function _typeof(obj) { - "@babel/helpers - typeof"; - - if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { - _typeof = function (obj) { - return typeof obj; - }; - } else { - _typeof = function (obj) { - return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; - }; - } - - return _typeof(obj); - } - - /** - * checks if passed argument is an array - * @param {any} arg - the object to check - * @return {Boolean} - true if `arg` is an array - */ - function isArray(arg) { - return Array.isArray(arg); - } - function isUndefined(arg) { - return typeof arg === 'undefined'; - } - function isObject(arg) { - return _typeof(arg) === 'object'; - } - function isPureObject(arg) { - return _typeof(arg) === 'object' && arg !== null; - } - function isFunction(arg) { - return typeof arg === 'function'; - } - function isString(arg) { - return typeof arg === 'string'; - } - - function hasGlobalWindowFn() { - try { - return !isUndefined(window); - } catch (e) { - return false; - } - } - var hasGlobalWindow = hasGlobalWindowFn(); - - var _global = hasGlobalWindow ? window : global; - - var console = _global.console || {}; - function warn(str) { - /* istanbul ignore next */ - if (!console || !console.warn) { - return; - } - - console.warn(str); - } - var showWarningNotSupportedInBrowserBundle = function showWarningNotSupportedInBrowserBundle(method) { - return warn("".concat(method, " is not supported in browser builds")); - }; - var showWarningNotSupported = function showWarningNotSupported() { - return warn('This vue app/component has no vue-meta configuration'); - }; - - /** - * These are constant variables used throughout the application. - */ - // set some sane defaults - var defaultInfo = { - title: undefined, - titleChunk: '', - titleTemplate: '%s', - htmlAttrs: {}, - bodyAttrs: {}, - headAttrs: {}, - base: [], - link: [], - meta: [], - style: [], - script: [], - noscript: [], - __dangerouslyDisableSanitizers: [], - __dangerouslyDisableSanitizersByTagID: {} - }; - var rootConfigKey = '_vueMeta'; // 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 keyName = 'metaInfo'; // This is the attribute vue-meta arguments on elements to know which it should - // manage and which it should ignore. - - var 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 ssrAttribute = '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 tagIDKeyName = 'vmid'; // This is the key name for possible meta templates - - var metaTemplateKeyName = 'template'; // This is the key name for the content-holding property - - var contentKeyName = 'content'; // The id used for the ssr app - - var ssrAppId = 'ssr'; // How long meta update - - var debounceWait = 10; // How long meta update - - var waitOnDestroyed = true; - var defaultOptions = { - keyName: keyName, - attribute: attribute, - ssrAttribute: ssrAttribute, - tagIDKeyName: tagIDKeyName, - contentKeyName: contentKeyName, - metaTemplateKeyName: metaTemplateKeyName, - waitOnDestroyed: waitOnDestroyed, - debounceWait: debounceWait, - ssrAppId: ssrAppId - }; // might be a bit ugly, but minimizes the browser bundles a bit - - var defaultInfoKeys = Object.keys(defaultInfo); // The metaInfo property keys which are used to disable escaping - - var disableOptionKeys = [defaultInfoKeys[12], defaultInfoKeys[13]]; // List of metaInfo property keys which are configuration options (and dont generate html) - - var metaInfoOptionKeys = [defaultInfoKeys[1], defaultInfoKeys[2], 'changed'].concat(disableOptionKeys); // List of metaInfo property keys which only generates attributes and no tags - - var metaInfoAttributeKeys = [defaultInfoKeys[3], defaultInfoKeys[4], defaultInfoKeys[5]]; // HTML elements which support the onload event - - var tagsSupportingOnload = ['link', 'style', 'script']; // HTML elements which dont have a head tag (shortened to our needs) - var tagProperties = ['once', 'skip', 'template']; // Attributes which should be added with data- prefix - - var commonDataAttributes = ['body', 'pbody']; // from: https://github.com/kangax/html-minifier/blob/gh-pages/src/htmlminifier.js#L202 - - var booleanHtmlAttributes = ['allowfullscreen', 'amp', 'async', 'autofocus', 'autoplay', 'checked', 'compact', 'controls', 'declare', 'default', 'defaultchecked', 'defaultmuted', 'defaultselected', 'defer', 'disabled', 'enabled', 'formnovalidate', 'hidden', 'indeterminate', 'inert', 'ismap', 'itemscope', 'loop', 'multiple', 'muted', 'nohref', 'noresize', 'noshade', 'novalidate', 'nowrap', 'open', 'pauseonexit', 'readonly', 'required', 'reversed', 'scoped', 'seamless', 'selected', 'sortable', 'truespeed', 'typemustmatch', 'visible']; - - var batchId = null; - function triggerUpdate(_ref, rootVm, hookName) { - var debounceWait = _ref.debounceWait; - - // if an update was triggered during initialization or when an update was triggered by the - // metaInfo watcher, set initialized to null - // then we keep falsy value but know we need to run a triggerUpdate after initialization - if (!rootVm[rootConfigKey].initialized && (rootVm[rootConfigKey].initializing || hookName === 'watcher')) { - rootVm[rootConfigKey].initialized = null; - } - - if (rootVm[rootConfigKey].initialized && !rootVm[rootConfigKey].pausing) { - // batch potential DOM updates to prevent extraneous re-rendering - // eslint-disable-next-line no-void - batchUpdate(function () { - return void rootVm.$meta().refresh(); - }, debounceWait); - } - } - /** - * Performs a batched update. - * - * @param {(null|Number)} id - the ID of this update - * @param {Function} callback - the update to perform - * @return {Number} id - a new ID - */ - - function batchUpdate(callback, timeout) { - timeout = timeout === undefined ? 10 : timeout; - - if (!timeout) { - callback(); - return; - } - - clearTimeout(batchId); - batchId = setTimeout(function () { - callback(); - }, timeout); - return batchId; - } - - /* - * To reduce build size, this file provides simple polyfills without - * overly excessive type checking and without modifying - * the global Array.prototype - * The polyfills are automatically removed in the commonjs build - * Also, only files in client/ & shared/ should use these functions - * files in server/ still use normal js function - */ - function find(array, predicate, thisArg) { - if ( !Array.prototype.find) { - // idx needs to be a Number, for..in returns string - for (var idx = 0; idx < array.length; idx++) { - if (predicate.call(thisArg, array[idx], idx, array)) { - return array[idx]; - } - } - - return; - } - - return array.find(predicate, thisArg); - } - function findIndex(array, predicate, thisArg) { - if ( !Array.prototype.findIndex) { - // idx needs to be a Number, for..in returns string - for (var idx = 0; idx < array.length; idx++) { - if (predicate.call(thisArg, array[idx], idx, array)) { - return idx; - } - } - - return -1; - } - - return array.findIndex(predicate, thisArg); - } - function toArray(arg) { - if ( !Array.from) { - return Array.prototype.slice.call(arg); - } - - return Array.from(arg); - } - function includes(array, value) { - if ( !Array.prototype.includes) { - for (var idx in array) { - if (array[idx] === value) { - return true; - } - } - - return false; - } - - return array.includes(value); - } - - function hasMetaInfo(vm) { - vm = vm || this; - return vm && (vm[rootConfigKey] === true || isObject(vm[rootConfigKey])); - } // a component is in a metaInfo branch when itself has meta info or one of its (grand-)children has - - function inMetaInfoBranch(vm) { - vm = vm || this; - return vm && !isUndefined(vm[rootConfigKey]); - } - - function pause(rootVm, refresh) { - rootVm[rootConfigKey].pausing = true; - return function () { - return resume(rootVm, refresh); - }; - } - function resume(rootVm, refresh) { - rootVm[rootConfigKey].pausing = false; - - if (refresh || refresh === undefined) { - return rootVm.$meta().refresh(); - } - } - - function addNavGuards(rootVm) { - var router = rootVm.$router; // return when nav guards already added or no router exists - - if (rootVm[rootConfigKey].navGuards || !router) { - /* istanbul ignore next */ - return; - } - - rootVm[rootConfigKey].navGuards = true; - router.beforeEach(function (to, from, next) { - pause(rootVm); - next(); - }); - router.afterEach(function () { - rootVm.$nextTick(function () { - var _resume = resume(rootVm), - metaInfo = _resume.metaInfo; - - if (metaInfo && isFunction(metaInfo.afterNavigation)) { - metaInfo.afterNavigation(metaInfo); - } - }); - }); - } - - var appId = 1; - function createMixin(Vue, options) { - // for which Vue lifecycle hooks should the metaInfo be refreshed - var updateOnLifecycleHook = ['activated', 'deactivated', 'beforeMount']; // watch for client side component updates - - return { - beforeCreate: function beforeCreate() { - var _this2 = this; - - var rootKey = '$root'; - var $root = this[rootKey]; - var $options = this.$options; - var devtoolsEnabled = Vue.config.devtools; - Object.defineProperty(this, '_hasMetaInfo', { - configurable: true, - get: function get() { - // Show deprecation warning once when devtools enabled - if (devtoolsEnabled && !$root[rootConfigKey].deprecationWarningShown) { - warn('VueMeta DeprecationWarning: _hasMetaInfo has been deprecated and will be removed in a future version. Please use hasMetaInfo(vm) instead'); - $root[rootConfigKey].deprecationWarningShown = true; - } - - return hasMetaInfo(this); - } - }); // 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 (isUndefined($options[options.keyName]) || $options[options.keyName] === null) { - return; - } - - if (!$root[rootConfigKey]) { - $root[rootConfigKey] = { - appId: appId - }; - appId++; - - if (devtoolsEnabled && $root.$options[options.keyName]) { - // use nextTick so the children should be added to $root - this.$nextTick(function () { - // find the first child that lists fnOptions - var child = find($root.$children, function (c) { - return c.$vnode && c.$vnode.fnOptions; - }); - - if (child && child.$vnode.fnOptions[options.keyName]) { - warn("VueMeta has detected a possible global mixin which adds a ".concat(options.keyName, " property to all Vue components on the page. This could cause severe performance issues. If possible, use $meta().addApp to add meta information instead")); - } - }); - } - } // to speed up updates we keep track of branches which have a component with vue-meta info defined - // if _vueMeta = true it has info, if _vueMeta = false a child has info - - - if (!this[rootConfigKey]) { - this[rootConfigKey] = true; - var parent = this.$parent; - - while (parent && parent !== $root) { - if (isUndefined(parent[rootConfigKey])) { - parent[rootConfigKey] = false; - } - - parent = parent.$parent; - } - } // coerce function-style metaInfo to a computed prop so we can observe - // it on creation - - - if (isFunction($options[options.keyName])) { - $options.computed = $options.computed || {}; - $options.computed.$metaInfo = $options[options.keyName]; - - if (!this.$isServer) { - // 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) - this.$on('hook:created', function () { - this.$watch('$metaInfo', function () { - triggerUpdate(options, this[rootKey], 'watcher'); - }); - }); - } - } // force an initial refresh on page load and prevent other lifecycleHooks - // to triggerUpdate until this initial refresh is finished - // this is to make sure that when a page is opened in an inactive tab which - // has throttled rAF/timers we still immediately set the page title - - - if (isUndefined($root[rootConfigKey].initialized)) { - $root[rootConfigKey].initialized = this.$isServer; - - if (!$root[rootConfigKey].initialized) { - if (!$root[rootConfigKey].initializedSsr) { - $root[rootConfigKey].initializedSsr = true; - this.$on('hook:beforeMount', function () { - var $root = this; // if this Vue-app was server rendered, set the appId to 'ssr' - // only one SSR app per page is supported - - if ($root.$el && $root.$el.nodeType === 1 && $root.$el.hasAttribute('data-server-rendered')) { - $root[rootConfigKey].appId = options.ssrAppId; - } - }); - } // we use the mounted hook here as on page load - - - this.$on('hook:mounted', function () { - var $root = this[rootKey]; - - if (!$root[rootConfigKey].initialized) { - // used in triggerUpdate to check if a change was triggered - // during initialization - $root[rootConfigKey].initializing = true; // refresh meta in nextTick so all child components have loaded - - this.$nextTick(function () { - var _$root$$meta$refresh = $root.$meta().refresh(), - tags = _$root$$meta$refresh.tags, - metaInfo = _$root$$meta$refresh.metaInfo; // After ssr hydration (identifier by tags === false) check - // if initialized was set to null in triggerUpdate. That'd mean - // that during initilazation changes where triggered which need - // to be applied OR a metaInfo watcher was triggered before the - // current hook was called - // (during initialization all changes are blocked) - - - if (tags === false && $root[rootConfigKey].initialized === null) { - this.$nextTick(function () { - return triggerUpdate(options, $root, 'init'); - }); - } - - $root[rootConfigKey].initialized = true; - delete $root[rootConfigKey].initializing; // add the navigation guards if they havent been added yet - // they are needed for the afterNavigation callback - - if (!options.refreshOnceOnNavigation && metaInfo.afterNavigation) { - addNavGuards($root); - } - }); - } - }); // add the navigation guards if requested - - if (options.refreshOnceOnNavigation) { - addNavGuards($root); - } - } - } - - this.$on('hook:destroyed', function () { - var _this = this; - - // do not trigger refresh: - // - when user configured to not wait for transitions on destroyed - // - when the component doesnt have a parent - // - doesnt have metaInfo defined - if (!this.$parent || !hasMetaInfo(this)) { - return; - } - - delete this._hasMetaInfo; - this.$nextTick(function () { - if (!options.waitOnDestroyed || !_this.$el || !_this.$el.offsetParent) { - triggerUpdate(options, _this.$root, 'destroyed'); - return; - } // Wait that element is hidden before refreshing meta tags (to support animations) - - - var interval = setInterval(function () { - if (_this.$el && _this.$el.offsetParent !== null) { - /* istanbul ignore next line */ - return; - } - - clearInterval(interval); - triggerUpdate(options, _this.$root, 'destroyed'); - }, 50); - }); - }); // do not trigger refresh on the server side - - if (this.$isServer) { - /* istanbul ignore next */ - return; - } // no need to add this hooks on server side - - - updateOnLifecycleHook.forEach(function (lifecycleHook) { - _this2.$on("hook:".concat(lifecycleHook), function () { - triggerUpdate(options, this[rootKey], lifecycleHook); - }); - }); - } - }; - } - - function setOptions(options) { - // combine options - options = isObject(options) ? options : {}; // The options are set like this so they can - // be minified by terser while keeping the - // user api intact - // terser --mangle-properties keep_quoted=strict - - /* eslint-disable dot-notation */ - - return { - keyName: options['keyName'] || defaultOptions.keyName, - attribute: options['attribute'] || defaultOptions.attribute, - ssrAttribute: options['ssrAttribute'] || defaultOptions.ssrAttribute, - tagIDKeyName: options['tagIDKeyName'] || defaultOptions.tagIDKeyName, - contentKeyName: options['contentKeyName'] || defaultOptions.contentKeyName, - metaTemplateKeyName: options['metaTemplateKeyName'] || defaultOptions.metaTemplateKeyName, - debounceWait: isUndefined(options['debounceWait']) ? defaultOptions.debounceWait : options['debounceWait'], - waitOnDestroyed: isUndefined(options['waitOnDestroyed']) ? defaultOptions.waitOnDestroyed : options['waitOnDestroyed'], - ssrAppId: options['ssrAppId'] || defaultOptions.ssrAppId, - refreshOnceOnNavigation: !!options['refreshOnceOnNavigation'] - }; - /* eslint-enable dot-notation */ - } - function getOptions(options) { - var optionsCopy = {}; - - for (var key in options) { - optionsCopy[key] = options[key]; - } - - return optionsCopy; - } - - function ensureIsArray(arg, key) { - if (!key || !isObject(arg)) { - return isArray(arg) ? arg : []; - } - - if (!isArray(arg[key])) { - arg[key] = []; - } - - return arg; - } - - var clientSequences = [[/&/g, "&"], [//g, ">"], [/"/g, "\""], [/'/g, "'"]]; // sanitizes potentially dangerous characters - - function escape(info, options, escapeOptions, escapeKeys) { - var tagIDKeyName = options.tagIDKeyName; - var _escapeOptions$doEsca = escapeOptions.doEscape, - doEscape = _escapeOptions$doEsca === void 0 ? function (v) { - return v; - } : _escapeOptions$doEsca; - var escaped = {}; - - for (var key in info) { - var value = info[key]; // no need to escape configuration options - - if (includes(metaInfoOptionKeys, key)) { - escaped[key] = value; - continue; - } // do not use destructuring for disableOptionKeys, it increases transpiled size - // due to var checks while we are guaranteed the structure of the cb - - - var disableKey = disableOptionKeys[0]; - - if (escapeOptions[disableKey] && includes(escapeOptions[disableKey], key)) { - // this info[key] doesnt need to escaped if the option is listed in __dangerouslyDisableSanitizers - escaped[key] = value; - continue; - } - - var tagId = info[tagIDKeyName]; - - if (tagId) { - disableKey = disableOptionKeys[1]; // keys which are listed in __dangerouslyDisableSanitizersByTagID for the current vmid do not need to be escaped - - if (escapeOptions[disableKey] && escapeOptions[disableKey][tagId] && includes(escapeOptions[disableKey][tagId], key)) { - escaped[key] = value; - continue; - } - } - - if (isString(value)) { - escaped[key] = doEscape(value); - } else if (isArray(value)) { - escaped[key] = value.map(function (v) { - if (isPureObject(v)) { - return escape(v, options, escapeOptions, true); - } - - return doEscape(v); - }); - } else if (isPureObject(value)) { - escaped[key] = escape(value, options, escapeOptions, true); - } else { - escaped[key] = value; - } - - if (escapeKeys) { - var escapedKey = doEscape(key); - - if (key !== escapedKey) { - escaped[escapedKey] = escaped[key]; - delete escaped[key]; - } - } - } - - return escaped; - } - function escapeMetaInfo(options, info, escapeSequences) { - escapeSequences = escapeSequences || []; // do not use destructuring for seq, it increases transpiled size - // due to var checks while we are guaranteed the structure of the cb - - var escapeOptions = { - doEscape: function doEscape(value) { - return escapeSequences.reduce(function (val, seq) { - return val.replace(seq[0], seq[1]); - }, value); - } - }; - disableOptionKeys.forEach(function (disableKey, index) { - if (index === 0) { - ensureIsArray(info, disableKey); - } else if (index === 1) { - for (var key in info[disableKey]) { - ensureIsArray(info[disableKey], key); - } - } - - escapeOptions[disableKey] = info[disableKey]; - }); // begin sanitization - - return escape(info, options, escapeOptions); - } - - 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]' || false; - } // see https://github.com/facebook/react/blob/b5ac963fb791d1298e7f396236383bc955f916c1/src/isomorphic/classic/element/ReactElement.js#L21-L25 - - function cloneUnlessOtherwiseSpecified(value, options) { - return value; - } - - function getMergeFunction(key, options) { - { - return deepmerge; - } - } - - function getKeys(target) { - return Object.keys(target); - } - - function propertyIsOnObject(object, property) { - try { - return property in object; - } catch (_) { - return false; - } - } // Protects from prototype poisoning and unexpected merging up the prototype chain. - - - function propertyIsUnsafe(target, key) { - return propertyIsOnObject(target, key) // Properties are safe to merge if they don't exist in the target yet, - && !(Object.hasOwnProperty.call(target, key) // unsafe if they exist up the prototype chain, - && Object.propertyIsEnumerable.call(target, key)); // and also unsafe if they're nonenumerable. - } - - function mergeObject(target, source, options) { - var destination = {}; - - if (options.isMergeableObject(target)) { - getKeys(target).forEach(function (key) { - destination[key] = cloneUnlessOtherwiseSpecified(target[key]); - }); - } - - getKeys(source).forEach(function (key) { - if (propertyIsUnsafe(target, key)) { - return; - } - - if (propertyIsOnObject(target, key) && options.isMergeableObject(source[key])) { - destination[key] = getMergeFunction()(target[key], source[key], options); - } else { - destination[key] = cloneUnlessOtherwiseSpecified(source[key]); - } - }); - return destination; - } - - function deepmerge(target, source, options) { - options = options || {}; - options.arrayMerge = options.arrayMerge; - options.isMergeableObject = options.isMergeableObject || isMergeableObject; // cloneUnlessOtherwiseSpecified is added to `options` so that custom arrayMerge() - // implementations can use it. The caller may not replace it. - - options.cloneUnlessOtherwiseSpecified = cloneUnlessOtherwiseSpecified; - var sourceIsArray = Array.isArray(source); - var targetIsArray = Array.isArray(target); - var sourceAndTargetTypesMatch = sourceIsArray === targetIsArray; - - if (!sourceAndTargetTypesMatch) { - return cloneUnlessOtherwiseSpecified(source); - } else if (sourceIsArray) { - return options.arrayMerge(target, source, options); - } else { - return mergeObject(target, source, options); - } - } - var deepmerge_1 = deepmerge; - var cjs = deepmerge_1; - - function applyTemplate(_ref, headObject, template, chunk) { - var component = _ref.component, - metaTemplateKeyName = _ref.metaTemplateKeyName, - contentKeyName = _ref.contentKeyName; - - if (template === true || headObject[metaTemplateKeyName] === true) { - // abort, template was already applied - return false; - } - - if (isUndefined(template) && headObject[metaTemplateKeyName]) { - template = headObject[metaTemplateKeyName]; - headObject[metaTemplateKeyName] = true; - } // return early if no template defined - - - if (!template) { - // cleanup faulty template properties - delete headObject[metaTemplateKeyName]; - return false; - } - - if (isUndefined(chunk)) { - chunk = headObject[contentKeyName]; - } - - headObject[contentKeyName] = isFunction(template) ? template.call(component, chunk) : template.replace(/%s/g, chunk); - return true; - } - - function _arrayMerge(_ref, target, source) { - var component = _ref.component, - tagIDKeyName = _ref.tagIDKeyName, - metaTemplateKeyName = _ref.metaTemplateKeyName, - contentKeyName = _ref.contentKeyName; - // 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 - var destination = []; - - if (!target.length && !source.length) { - return destination; - } - - target.forEach(function (targetItem, targetIndex) { - // no tagID so no need to check for duplicity - if (!targetItem[tagIDKeyName]) { - destination.push(targetItem); - return; - } - - var sourceIndex = findIndex(source, function (item) { - return item[tagIDKeyName] === targetItem[tagIDKeyName]; - }); - var sourceItem = source[sourceIndex]; // source doesnt contain any duplicate vmid's, we can keep targetItem - - if (sourceIndex === -1) { - destination.push(targetItem); - return; - } // when sourceItem explictly defines contentKeyName or innerHTML as undefined, its - // an indication that we need to skip the default behaviour or child has preference over parent - // which means we keep the targetItem and ignore/remove the sourceItem - - - if (contentKeyName in sourceItem && sourceItem[contentKeyName] === undefined || 'innerHTML' in sourceItem && sourceItem.innerHTML === undefined) { - destination.push(targetItem); // remove current index from source array so its not concatenated to destination below - - source.splice(sourceIndex, 1); - return; - } // we now know that targetItem is a duplicate and we should ignore it in favor of sourceItem - // if source specifies null as content then ignore both the target as the source - - - if (sourceItem[contentKeyName] === null || sourceItem.innerHTML === null) { - // remove current index from source array so its not concatenated to destination below - source.splice(sourceIndex, 1); - return; - } // now we only need to check if the target has a template to combine it with the source - - - var targetTemplate = targetItem[metaTemplateKeyName]; - - if (!targetTemplate) { - return; - } - - var sourceTemplate = sourceItem[metaTemplateKeyName]; - - if (!sourceTemplate) { - // use parent template and child content - applyTemplate({ - component: component, - metaTemplateKeyName: metaTemplateKeyName, - contentKeyName: contentKeyName - }, sourceItem, targetTemplate); // set template to true to indicate template was already applied - - sourceItem.template = true; - return; - } - - if (!sourceItem[contentKeyName]) { - // use parent content and child template - applyTemplate({ - component: component, - metaTemplateKeyName: metaTemplateKeyName, - contentKeyName: contentKeyName - }, sourceItem, undefined, targetItem[contentKeyName]); - } - }); - return destination.concat(source); - } - var warningShown = false; - function merge(target, source, options) { - options = options || {}; // remove properties explicitly set to false so child components can - // optionally _not_ overwrite the parents content - // (for array properties this is checked in arrayMerge) - - if (source.title === undefined) { - delete source.title; - } - - metaInfoAttributeKeys.forEach(function (attrKey) { - if (!source[attrKey]) { - return; - } - - for (var key in source[attrKey]) { - if (key in source[attrKey] && source[attrKey][key] === undefined) { - if (includes(booleanHtmlAttributes, key) && !warningShown) { - warn('VueMeta: Please note that since v2 the value undefined is not used to indicate boolean attributes anymore, see migration guide for details'); - warningShown = true; - } - - delete source[attrKey][key]; - } - } - }); - return cjs(target, source, { - arrayMerge: function arrayMerge(t, s) { - return _arrayMerge(options, t, s); - } - }); - } - - function getComponentMetaInfo(options, component) { - return getComponentOption(options || {}, component, defaultInfo); - } - /** - * 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 {Boolean} opts.deep - look for data in child components as well? - * @param {Function} opts.arrayMerge - how should arrays be merged? - * @param {String} opts.keyName - the name of the option to look for - * @param {Object} [result={}] - result so far - * @return {Object} result - final aggregated result - */ - - function getComponentOption(options, component, result) { - result = result || {}; - - if (component._inactive) { - return result; - } - - options = options || {}; - var _options = options, - keyName = _options.keyName; - var $metaInfo = component.$metaInfo, - $options = component.$options, - $children = component.$children; // only collect option data if it exists - - if ($options[keyName]) { - // if $metaInfo exists then [keyName] was defined as a function - // and set to the computed prop $metaInfo in the mixin - // using the computed prop should be a small performance increase - // because Vue caches those internally - var data = $metaInfo || $options[keyName]; // only merge data with result when its an object - // eg it could be a function when metaInfo() returns undefined - // dueo to the or statement above - - if (isObject(data)) { - result = merge(result, data, options); - } - } // collect & aggregate child options if deep = true - - - if ($children.length) { - $children.forEach(function (childComponent) { - // check if the childComponent is in a branch - // return otherwise so we dont walk all component branches unnecessarily - if (!inMetaInfoBranch(childComponent)) { - return; - } - - result = getComponentOption(options, childComponent, result); - }); - } - - return result; - } - - var querySelector = function querySelector(arg, el) { - return (el || document).querySelectorAll(arg); - }; - function getTag(tags, tag) { - if (!tags[tag]) { - tags[tag] = document.getElementsByTagName(tag)[0]; - } - - return tags[tag]; - } - function getElementsKey(_ref) { - var body = _ref.body, - pbody = _ref.pbody; - return body ? 'body' : pbody ? 'pbody' : 'head'; - } - function queryElements(parentNode, _ref2, attributes) { - var appId = _ref2.appId, - attribute = _ref2.attribute, - type = _ref2.type, - tagIDKeyName = _ref2.tagIDKeyName; - attributes = attributes || {}; - var queries = ["".concat(type, "[").concat(attribute, "=\"").concat(appId, "\"]"), "".concat(type, "[data-").concat(tagIDKeyName, "]")].map(function (query) { - for (var key in attributes) { - var val = attributes[key]; - var attributeValue = val && val !== true ? "=\"".concat(val, "\"") : ''; - query += "[data-".concat(key).concat(attributeValue, "]"); - } - - return query; - }); - return toArray(querySelector(queries.join(', '), parentNode)); - } - function removeElementsByAppId(_ref3, appId) { - var attribute = _ref3.attribute; - toArray(querySelector("[".concat(attribute, "=\"").concat(appId, "\"]"))).map(function (el) { - return el.remove(); - }); - } - function removeAttribute(el, attributeName) { - el.removeAttribute(attributeName); - } - - var callbacks = []; - function isDOMComplete(d) { - return (d || document).readyState === 'complete'; - } - function addCallback(query, callback) { - if (arguments.length === 1) { - callback = query; - query = ''; - } - - callbacks.push([query, callback]); - } - function addCallbacks(_ref, type, tags, autoAddListeners) { - var tagIDKeyName = _ref.tagIDKeyName; - var hasAsyncCallback = false; - tags.forEach(function (tag) { - if (!tag[tagIDKeyName] || !tag.callback) { - return; - } - - hasAsyncCallback = true; - addCallback("".concat(type, "[data-").concat(tagIDKeyName, "=\"").concat(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 = function () { - applyCallbacks(); - }; - } - function applyCallbacks(matchElement) { - callbacks.forEach(function (args) { - // do not use destructuring for args, it increases transpiled size - // due to var checks while we are guaranteed the structure of the cb - var query = args[0]; - var callback = args[1]; - var selector = "".concat(query, "[onload=\"this.__vm_l=1\"]"); - var elements = []; - - if (!matchElement) { - elements = toArray(querySelector(selector)); - } - - if (matchElement && matchElement.matches(selector)) { - elements = [matchElement]; - } - - elements.forEach(function (element) { - /* __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) { - return; - } - - var onload = function 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 - */ - - removeAttribute(element, '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(); - return; - } - - if (!element.__vm_ev) { - element.__vm_ev = true; - element.addEventListener('load', onload); - } - }); - }); - } - - // instead of adding it to the html - - var attributeMap = {}; - /** - * 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 - */ - - function updateAttribute(appId, options, type, attrs, tag) { - var _ref = options || {}, - attribute = _ref.attribute; - - var vueMetaAttrString = tag.getAttribute(attribute); - - if (vueMetaAttrString) { - attributeMap[type] = JSON.parse(decodeURI(vueMetaAttrString)); - removeAttribute(tag, attribute); - } - - var data = attributeMap[type] || {}; - var toUpdate = []; // remove attributes from the map - // which have been removed for this appId - - for (var attr in data) { - if (data[attr] && appId in data[attr]) { - toUpdate.push(attr); - - if (!attrs[attr]) { - delete data[attr][appId]; - } - } - } - - for (var _attr in attrs) { - var attrData = data[_attr]; - - if (!attrData || attrData[appId] !== attrs[_attr]) { - toUpdate.push(_attr); - - if (attrs[_attr]) { - data[_attr] = data[_attr] || {}; - data[_attr][appId] = attrs[_attr]; - } - } - } - - for (var _i = 0, _toUpdate = toUpdate; _i < _toUpdate.length; _i++) { - var _attr2 = _toUpdate[_i]; - var _attrData = data[_attr2]; - var attrValues = []; - - for (var _appId in _attrData) { - Array.prototype.push.apply(attrValues, [].concat(_attrData[_appId])); - } - - if (attrValues.length) { - var attrValue = includes(booleanHtmlAttributes, _attr2) && attrValues.some(Boolean) ? '' : attrValues.filter(Boolean).join(' '); - tag.setAttribute(_attr2, attrValue); - } else { - removeAttribute(tag, _attr2); - } - } - - attributeMap[type] = data; - } - - /** - * Updates the document title - * - * @param {String} title - the new title of the document - */ - function updateTitle(title) { - if (!title && title !== '') { - return; - } - - document.title = title; - } - - /** - * Updates meta tags inside and 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)} tags - an array of tag objects or a single object in case of base - * @return {Object} - a representation of what tags changed - */ - - function updateTag(appId, options, type, tags, head, body) { - var _ref = options || {}, - attribute = _ref.attribute, - tagIDKeyName = _ref.tagIDKeyName; - - var dataAttributes = commonDataAttributes.slice(); - dataAttributes.push(tagIDKeyName); - var newElements = []; - var queryOptions = { - appId: appId, - attribute: attribute, - type: type, - tagIDKeyName: tagIDKeyName - }; - var currentElements = { - head: queryElements(head, queryOptions), - pbody: queryElements(body, queryOptions, { - pbody: true - }), - body: queryElements(body, queryOptions, { - body: true - }) - }; - - 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.filter(function (x) { - var k = JSON.stringify(x); - var res = !includes(found, k); - found.push(k); - return res; - }); - } - - tags.forEach(function (tag) { - if (tag.skip) { - return; - } - - var newElement = document.createElement(type); - - if (!tag.once) { - newElement.setAttribute(attribute, appId); - } - - Object.keys(tag).forEach(function (attr) { - /* istanbul ignore next */ - if (includes(tagProperties, attr)) { - return; - } - - if (attr === 'innerHTML') { - newElement.innerHTML = tag.innerHTML; - return; - } - - if (attr === 'json') { - newElement.innerHTML = JSON.stringify(tag.json); - return; - } - - if (attr === 'cssText') { - if (newElement.styleSheet) { - /* istanbul ignore next */ - newElement.styleSheet.cssText = tag.cssText; - } else { - newElement.appendChild(document.createTextNode(tag.cssText)); - } - - return; - } - - if (attr === 'callback') { - newElement.onload = function () { - return tag[attr](newElement); - }; - - return; - } - - var _attr = includes(dataAttributes, attr) ? "data-".concat(attr) : attr; - - var isBooleanAttribute = includes(booleanHtmlAttributes, attr); - - if (isBooleanAttribute && !tag[attr]) { - return; - } - - var value = isBooleanAttribute ? '' : tag[attr]; - newElement.setAttribute(_attr, value); - }); - var oldElements = currentElements[getElementsKey(tag)]; // Remove a duplicate tag from domTagstoRemove, so it isn't cleared. - - var indexToDelete; - var hasEqualElement = oldElements.some(function (existingTag, index) { - indexToDelete = index; - return newElement.isEqualNode(existingTag); - }); - - if (hasEqualElement && (indexToDelete || indexToDelete === 0)) { - oldElements.splice(indexToDelete, 1); - } else { - newElements.push(newElement); - } - }); - var oldElements = []; - - for (var _type in currentElements) { - Array.prototype.push.apply(oldElements, currentElements[_type]); - } // remove old elements - - - oldElements.forEach(function (element) { - element.parentNode.removeChild(element); - }); // insert new elements - - newElements.forEach(function (element) { - if (element.hasAttribute('data-body')) { - body.appendChild(element); - return; - } - - if (element.hasAttribute('data-pbody')) { - body.insertBefore(element, body.firstChild); - return; - } - - head.appendChild(element); - }); - return { - oldTags: oldElements, - newTags: newElements - }; - } - - /** - * Performs client-side updates when new meta info is received - * - * @param {Object} newInfo - the meta info to update to - */ - - function updateClientMetaInfo(appId, options, newInfo) { - options = options || {}; - var _options = options, - ssrAttribute = _options.ssrAttribute, - ssrAppId = _options.ssrAppId; // only cache tags for current update - - var tags = {}; - var htmlTag = getTag(tags, 'html'); // if this is a server render, then dont update - - if (appId === ssrAppId && htmlTag.hasAttribute(ssrAttribute)) { - // remove the server render attribute so we can update on (next) changes - removeAttribute(htmlTag, ssrAttribute); // add load callbacks if the - - var addLoadListeners = false; - tagsSupportingOnload.forEach(function (type) { - if (newInfo[type] && addCallbacks(options, type, newInfo[type])) { - addLoadListeners = true; - } - }); - - if (addLoadListeners) { - addListeners(); - } - - return false; - } // initialize tracked changes - - - var tagsAdded = {}; - var tagsRemoved = {}; - - for (var type in newInfo) { - // ignore these - if (includes(metaInfoOptionKeys, type)) { - continue; - } - - if (type === 'title') { - // update the title - updateTitle(newInfo.title); - continue; - } - - if (includes(metaInfoAttributeKeys, type)) { - var tagName = type.substr(0, 4); - updateAttribute(appId, options, type, newInfo[type], getTag(tags, tagName)); - continue; - } // tags should always be an array, ignore if it isnt - - - if (!isArray(newInfo[type])) { - continue; - } - - var _updateTag = updateTag(appId, options, type, newInfo[type], getTag(tags, 'head'), getTag(tags, 'body')), - oldTags = _updateTag.oldTags, - newTags = _updateTag.newTags; - - if (newTags.length) { - tagsAdded[type] = newTags; - tagsRemoved[type] = oldTags; - } - } - - return { - tagsAdded: tagsAdded, - tagsRemoved: tagsRemoved - }; - } - - var appsMetaInfo; - function addApp(rootVm, appId, options) { - return { - set: function set(metaInfo) { - return setMetaInfo(rootVm, appId, options, metaInfo); - }, - remove: function remove() { - return removeMetaInfo(rootVm, appId, options); - } - }; - } - function setMetaInfo(rootVm, appId, options, metaInfo) { - // if a vm exists _and_ its mounted then immediately update - if (rootVm && rootVm.$el) { - return updateClientMetaInfo(appId, options, metaInfo); - } // store for later, the info - // will be set on the first refresh - - - appsMetaInfo = appsMetaInfo || {}; - appsMetaInfo[appId] = metaInfo; - } - function removeMetaInfo(rootVm, appId, options) { - if (rootVm && rootVm.$el) { - var tags = {}; - var _iteratorNormalCompletion = true; - var _didIteratorError = false; - var _iteratorError = undefined; - - try { - for (var _iterator = metaInfoAttributeKeys[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { - var type = _step.value; - var tagName = type.substr(0, 4); - updateAttribute(appId, options, type, {}, getTag(tags, tagName)); - } - } catch (err) { - _didIteratorError = true; - _iteratorError = err; - } finally { - try { - if (!_iteratorNormalCompletion && _iterator.return != null) { - _iterator.return(); - } - } finally { - if (_didIteratorError) { - throw _iteratorError; - } - } - } - - return removeElementsByAppId(options, appId); - } - - if (appsMetaInfo[appId]) { - delete appsMetaInfo[appId]; - clearAppsMetaInfo(); - } - } - function getAppsMetaInfo() { - return appsMetaInfo; - } - function clearAppsMetaInfo(force) { - if (force || !Object.keys(appsMetaInfo).length) { - appsMetaInfo = undefined; - } - } - - /** - * 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 - */ - - function getMetaInfo(options, info, escapeSequences, component) { - options = options || {}; - escapeSequences = escapeSequences || []; - var _options = options, - tagIDKeyName = _options.tagIDKeyName; // 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.titleTemplate !== '%s') { - applyTemplate({ - component: component, - contentKeyName: 'title' - }, info, 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] : []; - } - - if (info.meta) { - // remove meta items with duplicate vmid's - info.meta = info.meta.filter(function (metaItem, index, arr) { - var hasVmid = !!metaItem[tagIDKeyName]; - - if (!hasVmid) { - return true; - } - - var isFirstItemForVmid = index === findIndex(arr, function (item) { - return item[tagIDKeyName] === metaItem[tagIDKeyName]; - }); - return isFirstItemForVmid; - }); // apply templates if needed - - info.meta.forEach(function (metaObject) { - return applyTemplate(options, metaObject); - }); - } - - return escapeMetaInfo(options, info, escapeSequences); - } - - /** - * 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 - */ - - function refresh(rootVm, options) { - options = options || {}; // make sure vue-meta was initiated - - if (!rootVm[rootConfigKey]) { - showWarningNotSupported(); - return {}; - } // collect & aggregate all metaInfo $options - - - var rawInfo = getComponentMetaInfo(options, rootVm); - var metaInfo = getMetaInfo(options, rawInfo, clientSequences, rootVm); - var appId = rootVm[rootConfigKey].appId; - var tags = updateClientMetaInfo(appId, options, metaInfo); // emit "event" with new info - - if (tags && isFunction(metaInfo.changed)) { - metaInfo.changed(metaInfo, tags.tagsAdded, tags.tagsRemoved); - tags = { - addedTags: tags.tagsAdded, - removedTags: tags.tagsRemoved - }; - } - - var appsMetaInfo = getAppsMetaInfo(); - - if (appsMetaInfo) { - for (var additionalAppId in appsMetaInfo) { - updateClientMetaInfo(additionalAppId, options, appsMetaInfo[additionalAppId]); - delete appsMetaInfo[additionalAppId]; - } - - clearAppsMetaInfo(true); - } - - return { - vm: rootVm, - metaInfo: metaInfo, - // eslint-disable-line object-shorthand - tags: tags - }; - } - - function $meta(options) { - options = options || {}; - /** - * Returns an injector for server-side rendering. - * @this {Object} - the Vue instance (a root component) - * @return {Object} - injector - */ - - var $root = this.$root; - return { - getOptions: function getOptions$1() { - return getOptions(options); - }, - setOptions: function setOptions(newOptions) { - var refreshNavKey = 'refreshOnceOnNavigation'; - - if (newOptions && newOptions[refreshNavKey]) { - options.refreshOnceOnNavigation = !!newOptions[refreshNavKey]; - addNavGuards($root); - } - - var debounceWaitKey = 'debounceWait'; - - if (newOptions && debounceWaitKey in newOptions) { - var debounceWait = parseInt(newOptions[debounceWaitKey]); - - if (!isNaN(debounceWait)) { - options.debounceWait = debounceWait; - } - } - - var waitOnDestroyedKey = 'waitOnDestroyed'; - - if (newOptions && waitOnDestroyedKey in newOptions) { - options.waitOnDestroyed = !!newOptions[waitOnDestroyedKey]; - } - }, - refresh: function refresh$1() { - return refresh($root, options); - }, - inject: function inject() { - return showWarningNotSupportedInBrowserBundle('inject'); - }, - pause: function pause$1() { - return pause($root); - }, - resume: function resume$1() { - return resume($root); - }, - addApp: function addApp$1(appId) { - return addApp($root, appId, options); - } - }; - } - - /** - * Plugin install function. - * @param {Function} Vue - the Vue constructor. - */ - - function install(Vue, options) { - if (Vue.__vuemeta_installed) { - return; - } - - Vue.__vuemeta_installed = true; - options = setOptions(options); - - Vue.prototype.$meta = function () { - return $meta.call(this, options); - }; - - Vue.mixin(createMixin(Vue, options)); - } - - var index = { - version: version, - install: install, - generate: function generate(metaInfo, options) { - return showWarningNotSupportedInBrowserBundle('generate'); - }, - hasMetaInfo: hasMetaInfo - }; - - return index; - -}))); diff --git a/dist/vue-meta.min.js b/dist/vue-meta.min.js deleted file mode 100644 index eca9c49..0000000 --- a/dist/vue-meta.min.js +++ /dev/null @@ -1,10 +0,0 @@ -/** - * vue-meta v2.3.3 - * (c) 2020 - * - Declan de Wet - * - Sébastien Chopin (@Atinux) - * - Pim (@pimlie) - * - All the amazing contributors - * @license MIT - */ -!function(n,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(n=n||self).VueMeta=t()}(this,(function(){"use strict";function n(t){return(n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(n){return typeof n}:function(n){return n&&"function"==typeof Symbol&&n.constructor===Symbol&&n!==Symbol.prototype?"symbol":typeof n})(t)}function t(n){return Array.isArray(n)}function e(n){return void 0===n}function r(t){return"object"===n(t)}function i(t){return"object"===n(t)&&null!==t}function o(n){return"function"==typeof n}var u=(function(){try{return!e(window)}catch(n){return!1}}()?window:global).console||{};function a(n){u&&u.warn&&u.warn(n)}var f=function(n){return a("".concat(n," is not supported in browser builds"))},c={title:void 0,titleChunk:"",titleTemplate:"%s",htmlAttrs:{},bodyAttrs:{},headAttrs:{},base:[],link:[],meta:[],style:[],script:[],noscript:[],__dangerouslyDisableSanitizers:[],__dangerouslyDisableSanitizersByTagID:{}},s="metaInfo",d="data-vue-meta",l="data-vue-meta-server-rendered",v="vmid",m="content",h="template",y=!0,p=10,b="ssr",g=Object.keys(c),A=[g[12],g[13]],j=[g[1],g[2],"changed"].concat(A),I=[g[3],g[4],g[5]],O=["link","style","script"],N=["once","skip","template"],T=["body","pbody"],w=["allowfullscreen","amp","async","autofocus","autoplay","checked","compact","controls","declare","default","defaultchecked","defaultmuted","defaultselected","defer","disabled","enabled","formnovalidate","hidden","indeterminate","inert","ismap","itemscope","loop","multiple","muted","nohref","noresize","noshade","novalidate","nowrap","open","pauseonexit","readonly","required","reversed","scoped","seamless","selected","sortable","truespeed","typemustmatch","visible"],k=null;function M(n,t,e){var r=n.t;t._vueMeta.i||!t._vueMeta.o&&"watcher"!==e||(t._vueMeta.i=null),t._vueMeta.i&&!t._vueMeta.u&&function(n,t){if(!(t=void 0===t?10:t))return void n();clearTimeout(k),k=setTimeout((function(){n()}),t)}((function(){t.$meta().refresh()}),r)}function S(n,t,e){if(!Array.prototype.findIndex){for(var r=0;r/g,">"],[/"/g,'"'],[/'/g,"'"]];function C(n,e,r){r=r||[];var o={A:function(n){return r.reduce((function(n,t){return n.replace(t[0],t[1])}),n)}};return A.forEach((function(n,t){if(0===t)R(e,n);else if(1===t)for(var r in e[n])R(e[n],r);o[n]=e[n]})),function n(e,r,o,u){var a=r.j,f=o.A,c=void 0===f?function(n){return n}:f,s={};for(var d in e){var l=e[d];if(K(j,d))s[d]=l;else{var v=A[0];if(o[v]&&K(o[v],d))s[d]=l;else{var m=e[a];if(m&&(v=A[1],o[v]&&o[v][m]&&K(o[v][m],d)))s[d]=l;else if("string"==typeof l?s[d]=c(l):t(l)?s[d]=l.map((function(t){return i(t)?n(t,r,o,!0):c(t)})):i(l)?s[d]=n(l,r,o,!0):s[d]=l,u){var h=c(d);d!==h&&(s[h]=s[d],delete s[d])}}}}return s}(e,n,o)}var E=function(t){return function(t){return!!t&&"object"===n(t)}(t)&&!function(n){var t=Object.prototype.toString.call(n);return"[object RegExp]"===t||"[object Date]"===t||!1}(t)};function H(n,t){return n}function L(n){return Object.keys(n)}function P(n,t){try{return t in n}catch(n){return!1}}function $(n,t,e){var r={};return e.I(n)&&L(n).forEach((function(t){r[t]=H(n[t])})),L(t).forEach((function(i){(function(n,t){return P(n,t)&&!(Object.hasOwnProperty.call(n,t)&&Object.propertyIsEnumerable.call(n,t))})(n,i)||(P(n,i)&&e.I(t[i])?r[i]=q(n[i],t[i],e):r[i]=H(t[i]))})),r}function q(n,t,e){(e=e||{}).O=e.O,e.I=e.I||E,e.cloneUnlessOtherwiseSpecified=H;var r=Array.isArray(t);return r===Array.isArray(n)?r?e.O(n,t,e):$(n,t,e):H(t)}var U=q;function F(n,t,r,i){var u=n.component,a=n.N,f=n.T;return!0!==r&&!0!==t[a]&&(e(r)&&t[a]&&(r=t[a],t[a]=!0),r?(e(i)&&(i=t[f]),t[f]=o(r)?r.call(u,i):r.replace(/%s/g,i),!0):(delete t[a],!1))}var G=!1;function Q(n,t,e){return e=e||{},void 0===t.title&&delete t.title,I.forEach((function(n){if(t[n])for(var e in t[n])e in t[n]&&void 0===t[n][e]&&(K(w,e)&&!G&&(a("VueMeta: Please note that since v2 the value undefined is not used to indicate boolean attributes anymore, see migration guide for details"),G=!0),delete t[n][e])})),U(n,t,{O:function(n,t){return function(n,t,e){var r=n.component,i=n.j,o=n.N,u=n.T,a=[];return t.length||e.length?(t.forEach((function(n,t){if(n[i]){var f=S(e,(function(t){return t[i]===n[i]})),c=e[f];if(-1!==f){if(u in c&&void 0===c[u]||"innerHTML"in c&&void 0===c.innerHTML)return a.push(n),void e.splice(f,1);if(null!==c[u]&&null!==c.innerHTML){var s=n[o];if(s){if(!c[o])return F({component:r,N:o,T:u},c,s),void(c.template=!0);c[u]||F({component:r,N:o,T:u},c,void 0,n[u])}}else e.splice(f,1)}else a.push(n)}else a.push(n)})),a.concat(e)):a}(e,n,t)}})}function X(n,t){return function n(t,i,o){if(o=o||{},i._inactive)return o;var u=(t=t||{}).v,a=i.$metaInfo,f=i.$options,c=i.$children;if(f[u]){var s=a||f[u];r(s)&&(o=Q(o,s,t))}c.length&&c.forEach((function(r){(function(n){return(n=n||this)&&!e(n._vueMeta)})(r)&&(o=n(t,r,o))}));return o}(n||{},t,c)}var Y=function(n,t){return(t||document).querySelectorAll(n)};function Z(n,t){return n[t]||(n[t]=document.getElementsByTagName(t)[0]),n[t]}function nn(n,t,e){var r=t.m,i=t.k,o=t.type,u=t.j;e=e||{};var a=["".concat(o,"[").concat(i,'="').concat(r,'"]'),"".concat(o,"[data-").concat(u,"]")].map((function(n){for(var t in e){var r=e[t],i=r&&!0!==r?'="'.concat(r,'"'):"";n+="[data-".concat(t).concat(i,"]")}return n}));return D(Y(a.join(", "),n))}function tn(n,t){n.removeAttribute(t)}var en=[];function rn(n,t,e,r){var i=n.j,o=!1;return e.forEach((function(n){n[i]&&n.callback&&(o=!0,function(n,t){1===arguments.length&&(t=n,n=""),en.push([n,t])}("".concat(t,"[data-").concat(i,'="').concat(n[i],'"]'),n.callback))})),r&&o?on():o}function on(){var n;"complete"!==(n||document).readyState?document.onreadystatechange=function(){un()}:un()}function un(n){en.forEach((function(t){var e=t[0],r=t[1],i="".concat(e,'[onload="this.__vm_l=1"]'),o=[];n||(o=D(Y(i))),n&&n.matches(i)&&(o=[n]),o.forEach((function(n){if(!n.__vm_cb){var t=function(){n.__vm_cb=!0,tn(n,"onload"),r(n)};n.__vm_l?t():n.__vm_ev||(n.__vm_ev=!0,n.addEventListener("load",t))}}))}))}var an,fn={};function cn(n,t,e,r,i){var o=(t||{}).k,u=i.getAttribute(o);u&&(fn[e]=JSON.parse(decodeURI(u)),tn(i,o));var a=fn[e]||{},f=[];for(var c in a)a[c]&&n in a[c]&&(f.push(c),r[c]||delete a[c][n]);for(var s in r){var d=a[s];d&&d[n]===r[s]||(f.push(s),r[s]&&(a[s]=a[s]||{},a[s][n]=r[s]))}for(var l=0,v=f;l1){var v=[];r=r.filter((function(n){var t=JSON.stringify(n),e=!K(v,t);return v.push(t),e}))}r.forEach((function(t){if(!t.skip){var r=document.createElement(e);t.once||r.setAttribute(a,n),Object.keys(t).forEach((function(n){if(!K(N,n))if("innerHTML"!==n)if("json"!==n)if("cssText"!==n)if("callback"!==n){var e=K(c,n)?"data-".concat(n):n,i=K(w,n);if(!i||t[n]){var o=i?"":t[n];r.setAttribute(e,o)}}else r.onload=function(){return t[n](r)};else r.styleSheet?r.styleSheet.cssText=t.cssText:r.appendChild(document.createTextNode(t.cssText));else r.innerHTML=JSON.stringify(t.json);else r.innerHTML=t.innerHTML}));var i,o=l[function(n){var t=n.body,e=n.pbody;return t?"body":e?"pbody":"head"}(t)];o.some((function(n,t){return i=t,r.isEqualNode(n)}))&&(i||0===i)?o.splice(i,1):s.push(r)}}));var m=[];for(var h in l)Array.prototype.push.apply(m,l[h]);return m.forEach((function(n){n.parentNode.removeChild(n)})),s.forEach((function(n){n.hasAttribute("data-body")?o.appendChild(n):n.hasAttribute("data-pbody")?o.insertBefore(n,o.firstChild):i.appendChild(n)})),{oldTags:m,newTags:s}}function dn(n,e,r){var i=e=e||{},o=i.M,u=i.h,a={},f=Z(a,"html");if(n===u&&f.hasAttribute(o)){tn(f,o);var c=!1;return O.forEach((function(n){r[n]&&rn(e,n,r[n])&&(c=!0)})),c&&on(),!1}var s,d={},l={};for(var v in r)if(!K(j,v))if("title"!==v){if(K(I,v)){var m=v.substr(0,4);cn(n,e,v,r[v],Z(a,m))}else if(t(r[v])){var h=sn(n,e,v,r[v],Z(a,"head"),Z(a,"body")),y=h.oldTags,p=h.newTags;p.length&&(d[v]=p,l[v]=y)}}else((s=r.title)||""===s)&&(document.title=s);return{S:d,D:l}}function ln(n,t,e){return{set:function(r){return function(n,t,e,r){if(n&&n.$el)return dn(t,e,r);(an=an||{})[t]=r}(n,t,e,r)},remove:function(){return function(n,t,e){if(n&&n.$el){var r={},i=!0,o=!1,u=void 0;try{for(var a,f=I[Symbol.iterator]();!(i=(a=f.next()).done);i=!0){var c=a.value,s=c.substr(0,4);cn(t,e,c,{},Z(r,s))}}catch(n){o=!0,u=n}finally{try{i||null==f.return||f.return()}finally{if(o)throw u}}return function(n,t){var e=n.k;D(Y("[".concat(e,'="').concat(t,'"]'))).map((function(n){return n.remove()}))}(e,t)}an[t]&&(delete an[t],mn())}(n,t,e)}}}function vn(){return an}function mn(n){!n&&Object.keys(an).length||(an=void 0)}function hn(n,t){if(t=t||{},!n._vueMeta)return a("This vue app/component has no vue-meta configuration"),{};var e=function(n,t,e,r){e=e||[];var i=(n=n||{}).j;return t.title&&(t.titleChunk=t.title),t.titleTemplate&&"%s"!==t.titleTemplate&&F({component:r,T:"title"},t,t.titleTemplate,t.titleChunk||""),t.base&&(t.base=Object.keys(t.base).length?[t.base]:[]),t.meta&&(t.meta=t.meta.filter((function(n,t,e){return!n[i]||t===S(e,(function(t){return t[i]===n[i]}))})),t.meta.forEach((function(t){return F(n,t)}))),C(n,t,e)}(t,X(t,n),W,n),r=dn(n._vueMeta.m,t,e);r&&o(e.changed)&&(e.changed(e,r.S,r.D),r={addedTags:r.S,removedTags:r.D});var i=vn();if(i){for(var u in i)dn(u,t,i[u]),delete i[u];mn(!0)}return{vm:n,metaInfo:e,tags:r}}function yn(n){n=n||{};var t=this.$root;return{getOptions:function(){return function(n){var t={};for(var e in n)t[e]=n[e];return t}(n)},setOptions:function(e){e&&e.p&&(n.p=!!e.p,z(t));if(e&&"debounceWait"in e){var r=parseInt(e.t);isNaN(r)||(n.t=r)}e&&"waitOnDestroyed"in e&&(n.g=!!e.g)},refresh:function(){return hn(t,n)},inject:function(){return f("inject")},pause:function(){return x(t)},resume:function(){return V(t)},addApp:function(e){return ln(t,e,n)}}}return{version:"2.3.3",install:function(n,t){n.__vuemeta_installed||(n.__vuemeta_installed=!0,t=function(n){return{v:(n=r(n)?n:{}).keyName||s,k:n.attribute||d,M:n.ssrAttribute||l,j:n.tagIDKeyName||v,T:n.contentKeyName||m,N:n.metaTemplateKeyName||h,t:e(n.debounceWait)?p:n.debounceWait,g:e(n.waitOnDestroyed)?y:n.waitOnDestroyed,h:n.ssrAppId||b,p:!!n.refreshOnceOnNavigation}}(t),n.prototype.$meta=function(){return yn.call(this,t)},n.mixin(J(n,t)))},generate:function(n,t){return f("generate")},hasMetaInfo:_}})); diff --git a/examples/_static/user-1.js b/examples/_static/user-1.js index be81e23..6908ddd 100644 --- a/examples/_static/user-1.js +++ b/examples/_static/user-1.js @@ -10,14 +10,14 @@ window.users.push({ zipcode: '92998-3874', geo: { lat: '-37.3159', - lng: '81.1496', - }, + lng: '81.1496' + } }, phone: '1-770-736-8031 x56442', website: 'hildegard.org', company: { name: 'Romaguera-Crona', catchPhrase: 'Multi-layered client-server neural-net', - bs: 'harness real-time e-markets', - }, + bs: 'harness real-time e-markets' + } }) diff --git a/examples/_static/user-2.js b/examples/_static/user-2.js index d2d68a3..f17f67d 100644 --- a/examples/_static/user-2.js +++ b/examples/_static/user-2.js @@ -10,14 +10,14 @@ window.users.push({ zipcode: '90566-7771', geo: { lat: '-43.9509', - lng: '-34.4618', - }, + lng: '-34.4618' + } }, phone: '010-692-6593 x09125', website: 'anastasia.net', company: { name: 'Deckow-Crist', catchPhrase: 'Proactive didactic contingency', - bs: 'synergize scalable supply-chains', - }, + bs: 'synergize scalable supply-chains' + } }) diff --git a/examples/_static/user-3.js b/examples/_static/user-3.js index dc22ba4..cd00e42 100644 --- a/examples/_static/user-3.js +++ b/examples/_static/user-3.js @@ -10,14 +10,14 @@ window.users.push({ zipcode: '59590-4157', geo: { lat: '-68.6102', - lng: '-47.0653', - }, + lng: '-47.0653' + } }, phone: '1-463-123-4447', website: 'ramiro.info', company: { name: 'Romaguera-Jacobson', catchPhrase: 'Face to face bifurcated interface', - bs: 'e-enable strategic applications', - }, + bs: 'e-enable strategic applications' + } }) diff --git a/examples/_static/user-4.js b/examples/_static/user-4.js index cac8a72..7084433 100644 --- a/examples/_static/user-4.js +++ b/examples/_static/user-4.js @@ -10,14 +10,14 @@ window.users.push({ zipcode: '53919-4257', geo: { lat: '29.4572', - lng: '-164.2990', - }, + lng: '-164.2990' + } }, phone: '493-170-9623 x156', website: 'kale.biz', company: { name: 'Robel-Corkery', catchPhrase: 'Multi-tiered zero tolerance productivity', - bs: 'transition cutting-edge web services', - }, + bs: 'transition cutting-edge web services' + } }) diff --git a/examples/async-callback/app.js b/examples/async-callback/app.js index ad1b19d..ae2a1af 100644 --- a/examples/async-callback/app.js +++ b/examples/async-callback/app.js @@ -6,7 +6,7 @@ Vue.use(VueMeta) window.users = [] new Vue({ - metaInfo() { + metaInfo () { return { title: 'Async Callback', titleTemplate: '%s | Vue Meta Examples', @@ -16,56 +16,56 @@ new Vue({ vmid: 'potatoes', src: '/user-3.js', async: true, - callback: this.updateCounter, + callback: this.updateCounter }, { skip: this.count < 1, vmid: 'vegetables', src: '/user-2.js', async: true, - callback: this.updateCounter, + callback: this.updateCounter }, { vmid: 'meat', src: '/user-1.js', async: true, - callback: el => this.loadCallback(el.getAttribute('data-vmid')), + callback: el => this.loadCallback(el.getAttribute('data-vmid')) }, - ...this.scripts, - ], + ...this.scripts + ] } }, - data() { + data () { return { count: 0, scripts: [], - users: window.users, + users: window.users } }, watch: { - count(val) { + count (val) { if (val === 3) { this.addScript() } - }, + } }, methods: { - updateCounter() { + updateCounter () { this.count++ }, - addScript() { + addScript () { this.scripts.push({ src: '/user-4.js', callback: () => { this.updateCounter() - }, + } }) }, - loadCallback(vmid) { + loadCallback (vmid) { if (vmid === 'meat') { this.updateCounter() } - }, + } }, template: `
@@ -84,5 +84,5 @@ new Vue({
- `, + ` }).$mount('#app') diff --git a/examples/basic-render/app.js b/examples/basic-render/app.js index 08bdedf..35a3bf8 100644 --- a/examples/basic-render/app.js +++ b/examples/basic-render/app.js @@ -8,17 +8,17 @@ Vue.component('child', { props: { page: { type: String, - default: '', - }, - }, - render(h) { - return h('h3', null, this.page) - }, - metaInfo() { - return { - title: this.page, + default: '' } }, + render (h) { + return h('h3', null, this.page) + }, + metaInfo () { + return { + title: this.page + } + } }) new Vue({ @@ -28,5 +28,5 @@ new Vue({

Inspect Element to see the meta info

- `, + ` }).$mount('#app') diff --git a/examples/basic/app.js b/examples/basic/app.js index 01e3c17..d90adc4 100644 --- a/examples/basic/app.js +++ b/examples/basic/app.js @@ -15,24 +15,24 @@ new Vue({ titleTemplate: '%s | Vue Meta Examples', htmlAttrs: { lang: 'en', - amp: undefined, + amp: undefined }, headAttrs: { - test: true, + test: true }, meta: [{ name: 'description', content: 'Hello', vmid: 'test' }], script: [ { innerHTML: '{ "@context": "http://www.schema.org", "@type": "Organization" }', - type: 'application/ld+json', + type: 'application/ld+json' }, { innerHTML: '{ "body": "yes" }', body: true, - type: 'application/ld+json', - }, + type: 'application/ld+json' + } ], - __dangerouslyDisableSanitizers: ['script'], - }), + __dangerouslyDisableSanitizers: ['script'] + }) }).$mount('#app') diff --git a/examples/keep-alive/app.js b/examples/keep-alive/app.js index d144507..c0f895e 100644 --- a/examples/keep-alive/app.js +++ b/examples/keep-alive/app.js @@ -6,18 +6,18 @@ Vue.use(VueMeta) Vue.component('foo', { template: '

Foo component

', metaInfo: { - title: 'Keep me Foo', - }, + title: 'Keep me Foo' + } }) new Vue({ - data() { + data () { return { showFoo: false } }, methods: { - show() { + show () { this.showFoo = !this.showFoo - }, + } }, template: `
@@ -29,6 +29,6 @@ new Vue({
`, metaInfo: () => ({ - title: 'Keep-alive', - }), + title: 'Keep-alive' + }) }).$mount('#app') diff --git a/examples/meta-loader.js b/examples/meta-loader.js index e388bf6..fa10731 100644 --- a/examples/meta-loader.js +++ b/examples/meta-loader.js @@ -5,12 +5,12 @@ const { processIf, getBaseTransformPreset, createObjectExpression, - createObjectProperty, + createObjectProperty } = require('@vue/compiler-core') const { parse } = require('@vue/compiler-dom') -function headTransform(node, context) { +function headTransform (node, context) { console.log('NODE', node) if (node.type === 1 /* NodeTypes.ELEMENT */) { return () => { @@ -35,13 +35,13 @@ module.exports = function (source, map) { // console.log('AST', ast) const [nodeTransforms, directiveTransforms] = getBaseTransformPreset({ - prefixIdentifiers: true, + prefixIdentifiers: true }) transform(ast, { prefixIdentifiers: true, nodeTransforms: [...nodeTransforms, headTransform], - directiveTransforms, + directiveTransforms }) const result = generate(ast, { mode: 'module' }) diff --git a/examples/multiple-apps/app.js b/examples/multiple-apps/app.js index f13a88c..f1b6388 100644 --- a/examples/multiple-apps/app.js +++ b/examples/multiple-apps/app.js @@ -6,50 +6,50 @@ Vue.use(VueMeta) // index.html contains a manual SSR render const app1 = new Vue({ - metaInfo() { + metaInfo () { return { title: 'App 1 title', bodyAttrs: { - class: 'app-1', + class: 'app-1' }, meta: [ { name: 'description', content: 'Hello from app 1', vmid: 'test' }, - { name: 'og:description', content: this.ogContent }, + { name: 'og:description', content: this.ogContent } ], script: [ { innerHTML: 'var appId=1.1', body: true }, - { innerHTML: 'var appId=1.2', vmid: 'app-id-body' }, - ], + { innerHTML: 'var appId=1.2', vmid: 'app-id-body' } + ] } }, - data() { + data () { return { - ogContent: 'Hello from ssr app', + ogContent: 'Hello from ssr app' } }, template: `

App 1

- `, + ` }) const app2 = new Vue({ metaInfo: () => ({ title: 'App 2 title', bodyAttrs: { - class: 'app-2', + class: 'app-2' }, meta: [ { name: 'description', content: 'Hello from app 2', vmid: 'test' }, - { name: 'og:description', content: 'Hello from app 2' }, + { name: 'og:description', content: 'Hello from app 2' } ], script: [ { innerHTML: 'var appId=2.1', body: true }, - { innerHTML: 'var appId=2.2', vmid: 'app-id-body', body: true }, - ], + { innerHTML: 'var appId=2.2', vmid: 'app-id-body', body: true } + ] }), template: `

App 2

- `, + ` }).$mount('#app2') app1.$mount('#app1') @@ -57,7 +57,7 @@ app1.$mount('#app1') const app3 = new Vue({ template: `

App 3 (empty metaInfo)

- `, + ` }).$mount('#app3') setTimeout(() => { diff --git a/examples/server.js b/examples/server.js index c4b760a..de78723 100644 --- a/examples/server.js +++ b/examples/server.js @@ -16,14 +16,14 @@ app.use( writeToDisk: true, stats: { colors: true, - chunks: false, - }, + chunks: false + } }) ) fs.readdirSync(__dirname) .filter(file => file !== 'ssr') - .forEach(file => { + .forEach((file) => { if (fs.statSync(path.join(__dirname, file)).isDirectory()) { app.use(rewrite(`/${file}/*`, `/${file}/index.html`)) } diff --git a/examples/ssr/App.js b/examples/ssr/App.js index 4a08d74..9faead4 100644 --- a/examples/ssr/App.js +++ b/examples/ssr/App.js @@ -6,7 +6,7 @@ Vue.use(VueMeta, { tagIDKeyName: 'hid' }) */ -export default function createMyApp() { +export default function createMyApp () { const Home = { template: `
About @@ -19,15 +19,15 @@ export default function createMyApp() { { hid: 'og:title', name: 'og:title', - content: 'Hello World', + content: 'Hello World' }, { hid: 'description', name: 'description', - content: 'Hello World', - }, - ], - }, + content: 'Hello World' + } + ] + } } const About = { @@ -42,28 +42,28 @@ export default function createMyApp() { { hid: 'og:title', name: 'og:title', - content: 'About World', + content: 'About World' }, { hid: 'description', name: 'description', - content: 'About World', - }, - ], - }, + content: 'About World' + } + ] + } } const router = createRouter({ history: createMemoryHistory('/ssr'), routes: [ { path: '/', component: Home }, - { path: '/about', component: About }, - ], + { path: '/about', component: About } + ] }) const app = createSSRApp({ router, - metaInfo() { + metaInfo () { return { title: 'Boring Title', htmlAttrs: { amp: true }, @@ -74,63 +74,63 @@ export default function createMyApp() { hid: 'og:title', name: 'og:title', template: chunk => `${chunk} - My Site`, - content: 'Default Title', + content: 'Default Title' }, { hid: 'description', name: 'description', - content: 'Say something', - }, + content: 'Say something' + } ], script: [ { hid: 'ldjson-schema', type: 'application/ld+json', innerHTML: - '{ "@context": "http://www.schema.org", "@type": "Organization" }', + '{ "@context": "http://www.schema.org", "@type": "Organization" }' }, { type: 'application/ld+json', innerHTML: '{ "body": "yes" }', - body: true, + body: true }, { hid: 'my-async-script-with-load-callback', src: '/user-1.js', body: true, defer: true, - callback: this.loadCallback, + callback: this.loadCallback }, { skip: this.count < 1, src: '/user-2.js', body: true, - callback: this.loadCallback, - }, + callback: this.loadCallback + } ], __dangerouslyDisableSanitizersByTagID: { - 'ldjson-schema': ['innerHTML'], - }, + 'ldjson-schema': ['innerHTML'] + } } }, - data() { + data () { return { count: 0, - users: process.server ? [] : window.users, + users: process.server ? [] : window.users } }, - mounted() { + mounted () { const { set, remove } = this.$meta().addApp('client-only') set({ - bodyAttrs: { class: 'client-only' }, + bodyAttrs: { class: 'client-only' } }) setTimeout(() => remove(), 3000) }, methods: { - loadCallback() { + loadCallback () { this.count++ - }, + } }, template: `
@@ -146,7 +146,7 @@ export default function createMyApp() { -
`, +
` }) app.use(router) diff --git a/examples/ssr/server.js b/examples/ssr/server.js index 61f2cb6..88c78a3 100644 --- a/examples/ssr/server.js +++ b/examples/ssr/server.js @@ -12,7 +12,7 @@ const compiled = template(templateContent, { interpolate: /{{([\s\S]+?)}}/g }) process.server = true -export async function renderPage({ url }) { +export async function renderPage ({ url }) { const { app, router } = await createApp() await router.push(url.substr(4)) @@ -30,17 +30,17 @@ export async function renderPage({ url }) { const pageHtml = compiled({ app: appHtml, htmlAttrs: { - text: () => {}, + text: () => {} }, headAttrs: { - text: () => {}, + text: () => {} }, bodyAttrs: { - text: () => {}, + text: () => {} }, head: () => {}, bodyPrepend: () => {}, - bodyAppend: () => {}, + bodyAppend: () => {} // ...app.$meta().inject() }) diff --git a/examples/vue-router/about.vue b/examples/vue-router/about.vue index 6027a8e..74f13fd 100644 --- a/examples/vue-router/about.vue +++ b/examples/vue-router/about.vue @@ -27,5 +27,3 @@ export default { } } - -useMeta() diff --git a/examples/vue-router/app.js b/examples/vue-router/app.js index d90d156..43417fa 100644 --- a/examples/vue-router/app.js +++ b/examples/vue-router/app.js @@ -6,10 +6,10 @@ import { inject, toRefs, h, - watch, + watch } from 'vue' import { createRouter, createWebHistory } from 'vue-router' -import { createManager, useMeta, useMetainfo } from '../../src' +import { createManager, useMeta, useMetainfo } from 'vue-meta' // import About from './about.vue' const metaUpdated = 'no' @@ -17,47 +17,47 @@ const metaUpdated = 'no' const ChildComponent = defineComponent({ name: 'child-component', props: { - page: String, + page: String }, template: `

You're looking at the {{ page }} page

Has metaInfo been updated due to navigation? {{ metaUpdated }}

`, - setup(props) { + setup (props) { const state = reactive({ date: null, - metaUpdated, + metaUpdated }) const title = props.page[0].toUpperCase() + props.page.slice(1) console.log('ChildComponent Setup') - useMeta({ + /* useMeta({ charset: 'utf16', title, description: 'Description ' + props.page, og: { title: 'Og Title ' + props.page, }, - }) + }) */ return { - ...toRefs(state), + ...toRefs(state) } - }, + } }) -function view(page) { +function view (page) { return { name: `section-${page}`, - render() { + render () { return h(ChildComponent, { page }) - }, + } } } const App = { - setup() { + setup () { // console.log('App', getCurrentInstance()) const { meta } = useMeta({ base: { href: '/vue-router', target: '_blank' }, @@ -69,69 +69,69 @@ const App = { description: 'Bla bla', image: [ 'https://picsum.photos/600/400/?image=80', - 'https://picsum.photos/600/400/?image=82', - ], + 'https://picsum.photos/600/400/?image=82' + ] }, twitter: { - title: 'Twitter Title', + title: 'Twitter Title' }, noscript: [ - '', - { tag: 'link', rel: 'stylesheet', href: 'style.css' }, + //'', + { tag: 'link', rel: 'stylesheet', href: 'style.css' } ], otherNoscript: { tag: 'noscript', 'data-test': 'hello', - content: [ - '', - { tag: 'link', rel: 'stylesheet', href: 'style2.css' }, - ], + children: [ + //'', + { tag: 'link', rel: 'stylesheet', href: 'style2.css' } + ] }, body: 'body-script1.js', script: [ - '', - { src: 'body-script2.js', target: 'body' }, - { src: 'body-script3.js', target: '#put-it-here' }, + //'', + { src: 'body-script2.js', to: 'body' }, + { src: 'body-script3.js', to: '#put-it-here' } ], esi: { - content: [ + children: [ { tag: 'choose', - content: [ + children: [ { tag: 'when', test: '$(HTTP_COOKIE{group})=="Advanced"', - content: [ + children: [ { tag: 'include', - src: 'http://www.example.com/advanced.html', - }, - ], - }, - ], - }, - ], - }, + src: 'http://www.example.com/advanced.html' + } + ] + } + ] + } + ] + } }) setTimeout(() => (meta.title = 'My Updated Title'), 2000) - const metainfo = useMetainfo() + const metadata = useMetainfo() - window.$metainfo = metainfo + window.$metainfo = metadata - watch(metainfo, (newValue, oldValue) => { + watch(metadata, (newValue, oldValue) => { console.log('UPDATE', newValue) }) return { - metainfo, + metadata } }, template: ` - +