UNPKG

@morr/vue3-head

Version:

Manipulating the meta information of the head tag, a simple and easy way

291 lines (267 loc) 6.86 kB
/* eslint-disable */ ;(function() { 'use strict' var opt = { complement: window.document.title, separator: '|' } var diffTitle = {} var els = [] var diffEls = [] var installed = false var util = { /** * Shorthand * @type {Object} */ shorthand: { ch: 'charset', tg: 'target', n: 'name', he: 'http-equiv', ip: 'itemprop', c: 'content', p: 'property', sc: 'scheme', r: 'rel', h: 'href', sz: 'sizes', t: 'type', s: 'src', a: 'async', d: 'defer', i: 'inner' }, /** * This function return the element <head> * @type {Function} * @return {Object} */ getPlace: function (place) { return window.document.getElementsByTagName(place)[0] }, /** * Undo the window.document title for previous state * @type {Function} * @param {Object} state */ undoTitle: function (state) { if (!state.before) return window.document.title = state.before }, /** * Undo elements to its previous state * @type {Function} */ undo: function () { if (!els.length) return els.forEach(function (el) { el.parentElement.removeChild(el) }) els = [] }, /** * Set attributes in element * @type {Function} * @param {Object} obj * @param {HTMLElement} el * @return {HTMLElement} with defined attributes */ prepareElement: function (obj, el) { var self = this Object.keys(obj).forEach(function (prop) { var sh = self.shorthand[prop] || prop if (sh.match(/(body|undo|replace)/g)) return if (sh === 'inner') { el.textContent = obj[prop] return } el.setAttribute(sh, obj[prop]) }) return el }, /** * Change window.document title * @type {Function} * @param {Object} obj */ title: function (obj) { if (!obj) return diffTitle.before = opt.complement var complement = obj.complement === '' ? obj.complement : (obj.complement || opt.complement) var separator = obj.separator === '' ? obj.separator : (obj.separator || opt.separator) var title = obj.inner + ' ' + separator + ' ' + complement window.document.title = title.trim() }, /** * Update Element */ update: function () { if (!els.length) return els.forEach(function(el, key) { if (diffEls[key] && !diffEls[key].isEqualNode(el)) { el.parentElement.replaceChild(diffEls[key], els[key]) els.splice(key, 1, diffEls[key]) return } }) diffEls = [] }, /** * Add Elements * @param {Object} obj * @param {HTMLElement} el * @param {HTMLElement} parent */ add: function (obj, el, parent) { parent.appendChild(el) // Fixed elements that do not suffer removal if (obj.undo !== undefined && !obj.undo) return // Elements which are removed els.push(el) }, /** * Handle of create elements * @type {Function} * @param {Array} arr * @param {String} tag - style, link, meta, script, base * @param {String} place - Default 'head' * @param {Boolean} update */ handle: function (arr, tag, place, update) { var self = this if (!arr) return arr.forEach(function (obj) { var parent = (obj.body) ? self.getPlace('body') : self.getPlace(place) var el = window.document.getElementById(obj.id) if (!el) { el = window.document.createElement(tag) update = false } // Elements that will substitute data if (el.hasAttribute('id')) { self.prepareElement(obj, el) return } // Other elements el = self.prepareElement(obj, el) // Updated elements if (update) { diffEls.push(el) return } // Append Elements self.add(obj, el, parent) }) } } /** * Plugin | vue-head * @param {Function} Vue * @param {Object} options */ function VueHead (Vue, options) { if (installed) return installed = true if (options) { Vue.util.extend(opt, options) } /** * Initializes and updates the elements in the head * @param {Boolean} update */ function init (update) { var self = this var head = (typeof self.$options.head === 'function') ? self.$options.head.bind(self)() : self.$options.head if (!head) return Object.keys(head).forEach(function (key) { var prop = head[key] if (!prop) return var obj = (typeof prop === 'function') ? head[key].bind(self)() : head[key] if (key === 'title') { util[key](obj) return } util.handle(obj, key, 'head', update) }) // self.$emit('okHead') } /** * Remove the meta tags elements in the head */ function destroy () { if (!this.$options.head) return util.undoTitle(diffTitle) util.undo() } // v3 if (!Vue.version || Vue.version.match(/[3].(.)+/g)) { Vue.mixin({ created: function () { var self = this self.$on && self.$on('updateHead', function () { init.call(this, true) util.update() }) }, mounted: function () { init.call(this) }, beforeUnmount: function () { destroy.call(this) } }) } // v1 else if (Vue.version.match(/[1].(.)+/g)) { Vue.mixin({ ready: function () { init.call(this) }, destroyed: function () { destroy.call(this) }, events: { updateHead: function () { init.call(this, true) util.update() } } }) } // v2 else if (Vue.version.match(/[2].(.)+/g)) { Vue.mixin({ created: function () { var self = this self.$on('updateHead', function () { init.call(this, true) util.update() }) }, mounted: function () { init.call(this) }, beforeDestroy: function () { destroy.call(this) } }) } } VueHead.version = '3.0.0' // auto install if (typeof Vue !== 'undefined') { Vue.use(VueHead) } if(typeof exports === 'object' && typeof module === 'object') { module.exports = VueHead } else if(typeof define === 'function' && define.amd) { define(function () { return VueHead }) } else if (typeof window !== 'undefined') { window.VueHead = VueHead } })()