Comparing version
# Next | ||
[diff](https://github.com/mib200/vue-gtm/compare/3.3.2...master) | ||
[diff](https://github.com/mib200/vue-gtm/compare/3.4.0...master) | ||
# 3.4.0 | ||
[diff](https://github.com/mib200/vue-gtm/compare/3.3.2...3.4.0) | ||
- Provide possibility to override `isInBrowserContext` check ([01f3651]) | ||
- Significantly improve JSDoc ([9edc30d]) | ||
- Add `vue-router` as `devDependency` for type definition ([593af25]) | ||
**Vue 3 only** | ||
- Fix `vue-router` access `base` from history options ([e150975]) | ||
- Do not track any views if navigation is aborted or cancelled ([007608b]) | ||
_You can see logs in the browser console if you have enabled debug mode_ | ||
[01f3651]: https://github.com/mib200/vue-gtm/commit/01f3651de1df4f679c60af05697af41b1a38d39b | ||
[9edc30d]: https://github.com/mib200/vue-gtm/commit/9edc30daf0c2bdf542c82d07c2f413421f44de3d | ||
[593af25]: https://github.com/mib200/vue-gtm/commit/593af254f51a122f868c3687f42abdcb3549b07e | ||
[e150975]: https://github.com/mib200/vue-gtm/commit/e1509755536ee6219580422c2611620b5b89140d | ||
[007608b]: https://github.com/mib200/vue-gtm/commit/007608bfbdb68658d130b74b3802df1779d4fa5e | ||
# 3.3.2 | ||
@@ -6,0 +26,0 @@ |
@@ -0,22 +1,70 @@ | ||
import type Router from "vue-router"; | ||
/** | ||
* Query parameter object that will be send to GTM. | ||
*/ | ||
export interface VueGtmQueryParams { | ||
/** | ||
* GTM auth environment parameter. | ||
*/ | ||
gtm_auth: string; | ||
/** | ||
* GTM preview environment parameter. | ||
*/ | ||
gtm_preview: string; | ||
/** | ||
* GTM cookies win environment parameter. | ||
*/ | ||
gtm_cookies_win: string; | ||
} | ||
/** | ||
* GTM ID Container. | ||
*/ | ||
export interface VueGtmContainer { | ||
/** | ||
* GTM Container ID. | ||
*/ | ||
id: string; | ||
/** | ||
* Add url query string when load gtm.js with GTM ID. | ||
*/ | ||
queryParams?: VueGtmQueryParams; | ||
} | ||
/** | ||
* Options passed to the plugin. | ||
*/ | ||
export interface VueGtmUseOptions { | ||
/** | ||
* Your GTM single container ID, array of container ids ['GTM-xxxxxx', 'GTM-yyyyyy'], or array of objects [{id: 'GTM-xxxxxx', queryPararms: { gtm_auth: 'abc123', gtm_preview: 'env-4', gtm_cookies_win: 'x'}}, {id: 'GTM-yyyyyy', queryParams: {gtm_auth: 'abc234', gtm_preview: 'env-5', gtm_cookies_win: 'x'}}]. | ||
* Your GTM single container ID, array of container ids or array of objects. | ||
* | ||
* @example | ||
* 'GTM-xxxxxx' | ||
* // or | ||
* ['GTM-xxxxxx', 'GTM-yyyyyy'] | ||
* // or | ||
* [{ | ||
* id: 'GTM-xxxxxx', | ||
* queryParams: { | ||
* gtm_auth: 'abc123', | ||
* gtm_preview: 'env-4', | ||
* gtm_cookies_win: 'x' | ||
* } | ||
* }, { | ||
* id: 'GTM-yyyyyy', | ||
* queryParams: { | ||
* gtm_auth: 'abc234', | ||
* gtm_preview: 'env-5', | ||
* gtm_cookies_win: 'x' | ||
* } | ||
* }] | ||
*/ | ||
id: string | string[] | VueGtmContainer[]; | ||
/** | ||
* Add url query string when load gtm.js with GTM ID | ||
* Add url query string when load gtm.js with GTM ID. | ||
*/ | ||
queryParams?: VueGtmQueryParams; | ||
/** | ||
* Script can be set to `defer` to speed up page load at the cost of less accurate results (in case visitor leaves before script is loaded, which is unlikely but possible). Defaults to false, so the script is loaded `async` by default | ||
* Script can be set to `defer` to speed up page load at the cost of less accurate results (in case visitor leaves before script is loaded, which is unlikely but possible). | ||
* | ||
* Defaults to false, so the script is loaded `async` by default. | ||
* | ||
* @default false | ||
@@ -26,3 +74,3 @@ */ | ||
/** | ||
* Will add `async` and `defer` to the script tag to not block requests for old browsers that do not support `async` | ||
* Will add `async` and `defer` to the script tag to not block requests for old browsers that do not support `async`. | ||
* | ||
@@ -33,4 +81,6 @@ * @default false | ||
/** | ||
* Plugin can be disabled by setting this to `false` for Ex: `enabled: !!GDPR_Cookie` | ||
* Plugin can be disabled by setting this to `false`. | ||
* | ||
* @example enabled: !!GDPR_Cookie | ||
* | ||
* @default true | ||
@@ -40,26 +90,34 @@ */ | ||
/** | ||
* Whether or not display console logs debugs | ||
* Whether or not to display console logs debugs. | ||
*/ | ||
debug?: boolean; | ||
/** | ||
* Whether or not to load the GTM Script (Helpful if you are including GTM manually, but need the dataLayer functionality in your components) | ||
* Whether or not to load the GTM Script. | ||
* | ||
* Helpful if you are including GTM manually, but need the dataLayer functionality in your components. | ||
*/ | ||
loadScript?: boolean; | ||
/** | ||
* Pass the router instance to automatically sync with router | ||
* Pass the router instance to automatically sync with router. | ||
*/ | ||
vueRouter?: { | ||
readonly options: any; | ||
afterEach(guard: (to: any, from: any) => any): () => void; | ||
}; | ||
vueRouter?: Router; | ||
/** | ||
* Don't trigger events for specified router names (case insensitive) | ||
* Don't trigger events for specified router names (case insensitive). | ||
*/ | ||
ignoredViews?: string[]; | ||
/** | ||
* Whether or not call `trackView` in `Vue.nextTick` | ||
* Whether or not call `trackView` in `Vue.nextTick`. | ||
*/ | ||
trackOnNextTick?: boolean; | ||
} | ||
declare const config: VueGtmUseOptions; | ||
export default config; | ||
/** | ||
* Default configuration for the plugin. | ||
*/ | ||
export declare const DEFAULT_CONFIG: Readonly<{ | ||
enabled: true; | ||
debug: false; | ||
trackOnNextTick: false; | ||
loadScript: true; | ||
defer: false; | ||
compatibility: false; | ||
}>; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
// @ts-ignore | ||
var config = { | ||
exports.DEFAULT_CONFIG = void 0; | ||
/** | ||
* Default configuration for the plugin. | ||
*/ | ||
exports.DEFAULT_CONFIG = { | ||
enabled: true, | ||
debug: false, | ||
trackOnNextTick: false, | ||
queryParams: undefined, | ||
loadScript: true, | ||
@@ -13,2 +15,1 @@ defer: false, | ||
}; | ||
exports.default = config; |
@@ -1,11 +0,13 @@ | ||
import { Plugin } from "vue"; | ||
import { PluginObject } from "vue"; | ||
import { VueGtmUseOptions } from "./config"; | ||
import GtmPlugin from "./plugin"; | ||
export declare function createGtm(options: VueGtmUseOptions): VueGtmPlugin; | ||
declare module "@vue/runtime-core" { | ||
interface ComponentCustomProperties { | ||
declare module "vue/types/vue" { | ||
interface Vue { | ||
$gtm: GtmPlugin; | ||
} | ||
interface VueConstructor<V extends Vue = Vue> { | ||
gtm: GtmPlugin; | ||
} | ||
} | ||
export declare type VueGtmPlugin = Plugin; | ||
export declare type VueGtmPlugin = PluginObject<VueGtmUseOptions>; | ||
export { VueGtmUseOptions } from "./config"; | ||
@@ -15,4 +17,6 @@ declare const _default: VueGtmPlugin; | ||
/** | ||
* Returns gtm plugin to be used via composition api inside setup method | ||
* Returns GTM plugin instance to be used via Composition API inside setup method. | ||
* | ||
* @returns The Vue GTM instance if the it was installed, otherwise `undefined`. | ||
*/ | ||
export declare function useGtm(): GtmPlugin | undefined; |
@@ -25,4 +25,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.useGtm = exports.createGtm = void 0; | ||
var vue_1 = require("vue"); | ||
exports.useGtm = void 0; | ||
var config_1 = require("./config"); | ||
@@ -34,21 +33,31 @@ var plugin_1 = require("./plugin"); | ||
/** | ||
* Installation procedure | ||
* Assert that the given id is a valid GTM Container ID. | ||
* | ||
* @param Vue | ||
* @param initConf | ||
* Tested against pattern: `/^GTM-[0-9A-Z]+$/`. | ||
* | ||
* @param id A GTM Container ID. | ||
*/ | ||
function install(Vue, initConf) { | ||
function assertIsGtmId(id) { | ||
if (typeof id !== "string" || !GTM_ID_PATTERN.test(id)) { | ||
throw new Error("GTM-ID '" + id + "' is not valid"); | ||
} | ||
} | ||
/** | ||
* Installation procedure. | ||
* | ||
* @param Vue The Vue instance. | ||
* @param options Configuration options. | ||
*/ | ||
function install(Vue, options) { | ||
var e_1, _a; | ||
if (initConf === void 0) { initConf = { id: "" }; } | ||
if (Array.isArray(initConf.id)) { | ||
if (options === void 0) { options = { id: "" }; } | ||
if (Array.isArray(options.id)) { | ||
try { | ||
for (var _b = __values(initConf.id), _c = _b.next(); !_c.done; _c = _b.next()) { | ||
for (var _b = __values(options.id), _c = _b.next(); !_c.done; _c = _b.next()) { | ||
var idOrObject = _c.value; | ||
if (typeof idOrObject === "string") { | ||
if (!GTM_ID_PATTERN.test(idOrObject)) { | ||
throw new Error("GTM-ID '" + idOrObject + "' is not valid"); | ||
} | ||
assertIsGtmId(idOrObject); | ||
} | ||
else if (!GTM_ID_PATTERN.test(idOrObject.id)) { | ||
throw new Error("GTM-ID '" + idOrObject.id + "' is not valid"); | ||
else { | ||
assertIsGtmId(idOrObject.id); | ||
} | ||
@@ -65,30 +74,23 @@ } | ||
} | ||
else if (!GTM_ID_PATTERN.test(initConf.id)) { | ||
throw new Error("GTM-ID '" + initConf.id + "' is not valid"); | ||
else { | ||
assertIsGtmId(options.id); | ||
} | ||
// Apply default configuration | ||
initConf = __assign(__assign({}, config_1.default), initConf); | ||
config_1.default.id = initConf.id; | ||
config_1.default.debug = initConf.debug; | ||
config_1.default.enabled = initConf.enabled; | ||
config_1.default.loadScript = initConf.loadScript; | ||
config_1.default.defer = initConf.defer; | ||
config_1.default.compatibility = initConf.compatibility; | ||
config_1.default.queryParams = __assign(__assign({}, config_1.default.queryParams), initConf.queryParams); | ||
options = __assign(__assign({}, config_1.DEFAULT_CONFIG), options); | ||
// Add to vue prototype and also from globals | ||
gtmPlugin = new plugin_1.default(config_1.default.id); | ||
Vue.config.globalProperties.$gtm = gtmPlugin; | ||
gtmPlugin = new plugin_1.default(options.id, options); | ||
Vue.prototype.$gtm = Vue.gtm = gtmPlugin; | ||
// Handle vue-router if defined | ||
if (initConf.vueRouter) { | ||
initVueRouterGuard(Vue, initConf); | ||
if (options.vueRouter) { | ||
initVueRouterGuard(Vue, options.vueRouter, options.ignoredViews, options.trackOnNextTick); | ||
} | ||
// Load GTM script when enabled | ||
if (config_1.default.enabled && config_1.default.loadScript) { | ||
if (Array.isArray(initConf.id)) { | ||
initConf.id.forEach(function (id) { | ||
if (gtmPlugin.options.enabled && gtmPlugin.options.loadScript) { | ||
if (Array.isArray(options.id)) { | ||
options.id.forEach(function (id) { | ||
if (typeof id === "string") { | ||
utils_1.loadScript(id, initConf); | ||
utils_1.loadScript(id, options); | ||
} | ||
else { | ||
var newConf = __assign({}, initConf); | ||
var newConf = __assign({}, options); | ||
if (id.queryParams != null) { | ||
@@ -102,20 +104,18 @@ newConf.queryParams = __assign(__assign({}, newConf.queryParams), id.queryParams); | ||
else { | ||
utils_1.loadScript(initConf.id, initConf); | ||
utils_1.loadScript(options.id, options); | ||
} | ||
} | ||
Vue.provide("gtm", initConf); | ||
} | ||
/** | ||
* Init the router guard. | ||
* Initialize the router guard. | ||
* | ||
* @param Vue - The Vue instance | ||
* @param vueRouter - The Vue router instance to attach guard | ||
* @param ignoredViews - An array of route name to ignore | ||
* @param trackOnNextTick - Whether or not call trackView in Vue.nextTick | ||
* | ||
* @returns The ignored routes names formalized. | ||
* @param Vue The Vue instance. | ||
* @param vueRouter The Vue router instance to attach the guard. | ||
* @param ignoredViews An array of route name that will be ignored. | ||
* @param trackOnNextTick Whether or not to call `trackView` in `Vue.nextTick`. | ||
*/ | ||
function initVueRouterGuard(Vue, _a) { | ||
var vueRouter = _a.vueRouter, _b = _a.ignoredViews, ignoredViews = _b === void 0 ? [] : _b, trackOnNextTick = _a.trackOnNextTick; | ||
function initVueRouterGuard(Vue, vueRouter, ignoredViews, trackOnNextTick) { | ||
if (ignoredViews === void 0) { ignoredViews = []; } | ||
if (!vueRouter) { | ||
console.warn("[VueGtm]: You tried to register 'vueRouter' for vue-gtm, but 'vue-router' was not found."); | ||
return; | ||
@@ -126,11 +126,11 @@ } | ||
vueRouter.afterEach(function (to) { | ||
var _a, _b; | ||
var _a, _b, _c; | ||
// Ignore some routes | ||
if (!to.name || ignoredViews.indexOf(to.name.toLowerCase()) !== -1) { | ||
if (typeof to.name !== "string" || ignoredViews.indexOf(to.name.toLowerCase()) !== -1) { | ||
return; | ||
} | ||
// Dispatch vue event using meta gtm value if defined otherwise fallback to route name | ||
var name = (_a = to.meta.gtm) !== null && _a !== void 0 ? _a : to.name; | ||
var additionalEventData = (_b = to.meta.gtmAdditionalEventData) !== null && _b !== void 0 ? _b : {}; | ||
var baseUrl = vueRouter.options.base || ""; | ||
var name = to.meta && typeof to.meta.gtm === "string" && !!to.meta.gtm ? to.meta.gtm : to.name; | ||
var additionalEventData = (_b = (_a = to.meta) === null || _a === void 0 ? void 0 : _a.gtmAdditionalEventData) !== null && _b !== void 0 ? _b : {}; | ||
var baseUrl = (_c = vueRouter.options.base) !== null && _c !== void 0 ? _c : ""; | ||
var fullUrl = baseUrl; | ||
@@ -142,3 +142,3 @@ if (!fullUrl.endsWith("/")) { | ||
if (trackOnNextTick) { | ||
void vue_1.nextTick(function () { | ||
Vue.nextTick(function () { | ||
gtmPlugin === null || gtmPlugin === void 0 ? void 0 : gtmPlugin.trackView(name, fullUrl, additionalEventData); | ||
@@ -151,12 +151,9 @@ }); | ||
}); | ||
return ignoredViews; | ||
} | ||
function createGtm(options) { | ||
return { install: function (app) { return install(app, options); } }; | ||
} | ||
exports.createGtm = createGtm; | ||
var _default = { install: install }; | ||
exports.default = _default; | ||
/** | ||
* Returns gtm plugin to be used via composition api inside setup method | ||
* Returns GTM plugin instance to be used via Composition API inside setup method. | ||
* | ||
* @returns The Vue GTM instance if the it was installed, otherwise `undefined`. | ||
*/ | ||
@@ -163,0 +160,0 @@ function useGtm() { |
@@ -1,2 +0,7 @@ | ||
import { VueGtmContainer } from "./config"; | ||
import { DEFAULT_CONFIG, VueGtmContainer, VueGtmUseOptions } from "./config"; | ||
/** | ||
* Object within the `window.dataLayer`. | ||
* | ||
* @see [developers.google.com/tag-manager/devguide](https://developers.google.com/tag-manager/devguide) | ||
*/ | ||
export interface DataLayerObject extends Record<string, any> { | ||
@@ -7,5 +12,13 @@ event: string; | ||
interface Window { | ||
/** | ||
* `dataLayer` used by GTM. | ||
* | ||
* @see [developers.google.com/tag-manager/devguide](https://developers.google.com/tag-manager/devguide) | ||
*/ | ||
dataLayer?: DataLayerObject[]; | ||
} | ||
} | ||
/** | ||
* Object definition for a track event. | ||
*/ | ||
export interface VueGtmTrackEventParams { | ||
@@ -21,30 +34,89 @@ [key: string]: any; | ||
/** | ||
* Plugin main class | ||
* The Vue GTM Plugin main class. | ||
*/ | ||
export default class VueGtmPlugin { | ||
readonly id: string | string[] | VueGtmContainer[]; | ||
constructor(id: string | string[] | VueGtmContainer[]); | ||
readonly options: Pick<VueGtmUseOptions, keyof typeof DEFAULT_CONFIG | "queryParams">; | ||
/** | ||
* Check if plugin is enabled | ||
* Constructs a new `VueGTMPlugin`. | ||
* | ||
* @param id A GTM Container ID. | ||
* @param options Options. | ||
*/ | ||
constructor(id: string | string[] | VueGtmContainer[], options?: Pick<VueGtmUseOptions, keyof typeof DEFAULT_CONFIG | "queryParams">); | ||
/** | ||
* Whether the script is running in a browser or not. | ||
* | ||
* You can override this function if you need to. | ||
* | ||
* @returns `true` if the script runs in browser context. | ||
*/ | ||
isInBrowserContext: () => boolean; | ||
/** | ||
* Check if plugin is enabled. | ||
* | ||
* @returns `true` if the plugin is enabled, otherwise `false`. | ||
*/ | ||
enabled(): boolean; | ||
/** | ||
* Enable or disable plugin | ||
* Enable or disable plugin. | ||
* | ||
* @param val state | ||
* When enabling with this function, the script will be attached to the `document` if: | ||
* | ||
* - the script runs in browser context | ||
* - the `document` doesn't have the script already attached | ||
* - the `loadScript` option is set to `true` | ||
* | ||
* @param enabled `true` to enable, `false` to disable. Default: `true`. | ||
*/ | ||
enable(val: boolean): void; | ||
enable(enabled?: boolean): void; | ||
/** | ||
* Check if plugin is in debug mode | ||
* Check if plugin is in debug mode. | ||
* | ||
* @returns `true` if the plugin is in debug mode, otherwise `false`. | ||
*/ | ||
debugEnabled(): boolean; | ||
/** | ||
* Enable or disable debug mode | ||
* Enable or disable debug mode. | ||
* | ||
* @param val state | ||
* @param enable `true` to enable, `false` to disable. | ||
*/ | ||
debug(val: boolean): void; | ||
debug(enable: boolean): void; | ||
/** | ||
* Returns the `window.dataLayer` array if the script is running in browser context and the plugin is enabled, | ||
* otherwise `false`. | ||
* | ||
* @returns The `window.dataLayer` if script is running in browser context and plugin is enabled, otherwise `false`. | ||
*/ | ||
dataLayer(): DataLayerObject[] | false; | ||
/** | ||
* Track a view event with `event: "content-view"`. | ||
* | ||
* The event will only be send if the script runs in browser context and the if plugin is enabled. | ||
* | ||
* If debug mode is enabled, a "Dispatching TrackView" is logged, | ||
* regardless of whether the plugin is enabled or the plugin is being executed in browser context. | ||
* | ||
* @param screenName Name of the screen passed as `"content-view-name"`. | ||
* @param path Path passed as `"content-name"`. | ||
* @param additionalEventData Additional data for the event object. `event`, `"content-name"` and `"content-view-name"` will always be overridden. | ||
*/ | ||
trackView(screenName: string, path: string, additionalEventData?: Record<string, any>): void; | ||
/** | ||
* Track an event. | ||
* | ||
* The event will only be send if the script runs in browser context and the if plugin is enabled. | ||
* | ||
* If debug mode is enabled, a "Dispatching event" is logged, | ||
* regardless of whether the plugin is enabled or the plugin is being executed in browser context. | ||
* | ||
* @param param0 Object that will be used for configuring the event object passed to GTM. | ||
* @param param0.event `event`, default to `"interaction"` when pushed to `window.dataLayer`. | ||
* @param param0.category Optional `category`, passed as `target`. | ||
* @param param0.action Optional `action`, passed as `action`. | ||
* @param param0.label Optional `label`, passed as `"target-properties"`. | ||
* @param param0.value Optional `value`, passed as `value`. | ||
* @param param0.noninteraction Optional `noninteraction`, passed as `"interaction-type"`. | ||
*/ | ||
trackEvent({ event, category, action, label, value, noninteraction, ...rest }?: VueGtmTrackEventParams): void; | ||
} |
@@ -27,25 +27,50 @@ "use strict"; | ||
var utils_1 = require("./utils"); | ||
var inBrowser = typeof window !== "undefined"; | ||
/** | ||
* Plugin main class | ||
* The Vue GTM Plugin main class. | ||
*/ | ||
var VueGtmPlugin = /** @class */ (function () { | ||
function VueGtmPlugin(id) { | ||
/** | ||
* Constructs a new `VueGTMPlugin`. | ||
* | ||
* @param id A GTM Container ID. | ||
* @param options Options. | ||
*/ | ||
function VueGtmPlugin(id, options) { | ||
if (options === void 0) { options = config_1.DEFAULT_CONFIG; } | ||
this.id = id; | ||
this.options = options; | ||
/** | ||
* Whether the script is running in a browser or not. | ||
* | ||
* You can override this function if you need to. | ||
* | ||
* @returns `true` if the script runs in browser context. | ||
*/ | ||
this.isInBrowserContext = function () { return typeof window !== "undefined"; }; | ||
} | ||
/** | ||
* Check if plugin is enabled | ||
* Check if plugin is enabled. | ||
* | ||
* @returns `true` if the plugin is enabled, otherwise `false`. | ||
*/ | ||
VueGtmPlugin.prototype.enabled = function () { | ||
var _a; | ||
return (_a = config_1.default.enabled) !== null && _a !== void 0 ? _a : true; | ||
return (_a = this.options.enabled) !== null && _a !== void 0 ? _a : true; | ||
}; | ||
/** | ||
* Enable or disable plugin | ||
* Enable or disable plugin. | ||
* | ||
* @param val state | ||
* When enabling with this function, the script will be attached to the `document` if: | ||
* | ||
* - the script runs in browser context | ||
* - the `document` doesn't have the script already attached | ||
* - the `loadScript` option is set to `true` | ||
* | ||
* @param enabled `true` to enable, `false` to disable. Default: `true`. | ||
*/ | ||
VueGtmPlugin.prototype.enable = function (val) { | ||
config_1.default.enabled = val; | ||
if (inBrowser && !!val && !utils_1.hasScript() && config_1.default.loadScript) { | ||
VueGtmPlugin.prototype.enable = function (enabled) { | ||
var _this = this; | ||
if (enabled === void 0) { enabled = true; } | ||
this.options.enabled = enabled; | ||
if (this.isInBrowserContext() && enabled && !utils_1.hasScript() && this.options.loadScript) { | ||
if (Array.isArray(this.id)) { | ||
@@ -55,5 +80,5 @@ this.id.forEach(function (id) { | ||
utils_1.loadScript(id, { | ||
defer: config_1.default.defer, | ||
compatibility: config_1.default.compatibility, | ||
queryParams: config_1.default.queryParams, | ||
defer: _this.options.defer, | ||
compatibility: _this.options.compatibility, | ||
queryParams: _this.options.queryParams, | ||
}); | ||
@@ -63,4 +88,4 @@ } | ||
utils_1.loadScript(id.id, { | ||
defer: config_1.default.defer, | ||
compatibility: config_1.default.compatibility, | ||
defer: _this.options.defer, | ||
compatibility: _this.options.compatibility, | ||
queryParams: id.queryParams, | ||
@@ -73,5 +98,5 @@ }); | ||
utils_1.loadScript(this.id, { | ||
defer: config_1.default.defer, | ||
compatibility: config_1.default.compatibility, | ||
queryParams: config_1.default.queryParams, | ||
defer: this.options.defer, | ||
compatibility: this.options.compatibility, | ||
queryParams: this.options.queryParams, | ||
}); | ||
@@ -82,19 +107,27 @@ } | ||
/** | ||
* Check if plugin is in debug mode | ||
* Check if plugin is in debug mode. | ||
* | ||
* @returns `true` if the plugin is in debug mode, otherwise `false`. | ||
*/ | ||
VueGtmPlugin.prototype.debugEnabled = function () { | ||
var _a; | ||
return (_a = config_1.default.debug) !== null && _a !== void 0 ? _a : false; | ||
return (_a = this.options.debug) !== null && _a !== void 0 ? _a : false; | ||
}; | ||
/** | ||
* Enable or disable debug mode | ||
* Enable or disable debug mode. | ||
* | ||
* @param val state | ||
* @param enable `true` to enable, `false` to disable. | ||
*/ | ||
VueGtmPlugin.prototype.debug = function (val) { | ||
config_1.default.debug = val; | ||
VueGtmPlugin.prototype.debug = function (enable) { | ||
this.options.debug = enable; | ||
}; | ||
/** | ||
* Returns the `window.dataLayer` array if the script is running in browser context and the plugin is enabled, | ||
* otherwise `false`. | ||
* | ||
* @returns The `window.dataLayer` if script is running in browser context and plugin is enabled, otherwise `false`. | ||
*/ | ||
VueGtmPlugin.prototype.dataLayer = function () { | ||
var _a; | ||
if (inBrowser && config_1.default.enabled) { | ||
if (this.isInBrowserContext() && this.options.enabled) { | ||
return (window.dataLayer = (_a = window.dataLayer) !== null && _a !== void 0 ? _a : []); | ||
@@ -104,7 +137,21 @@ } | ||
}; | ||
/** | ||
* Track a view event with `event: "content-view"`. | ||
* | ||
* The event will only be send if the script runs in browser context and the if plugin is enabled. | ||
* | ||
* If debug mode is enabled, a "Dispatching TrackView" is logged, | ||
* regardless of whether the plugin is enabled or the plugin is being executed in browser context. | ||
* | ||
* @param screenName Name of the screen passed as `"content-view-name"`. | ||
* @param path Path passed as `"content-name"`. | ||
* @param additionalEventData Additional data for the event object. `event`, `"content-name"` and `"content-view-name"` will always be overridden. | ||
*/ | ||
VueGtmPlugin.prototype.trackView = function (screenName, path, additionalEventData) { | ||
var _a; | ||
if (additionalEventData === void 0) { additionalEventData = {}; } | ||
utils_1.logDebug("Dispatching TrackView", { screenName: screenName, path: path }); | ||
if (inBrowser && config_1.default.enabled) { | ||
if (this.options.debug) { | ||
console.log("[VueGtm]: Dispatching TrackView", { screenName: screenName, path: path }); | ||
} | ||
if (this.isInBrowserContext() && this.options.enabled) { | ||
var dataLayer = (window.dataLayer = (_a = window.dataLayer) !== null && _a !== void 0 ? _a : []); | ||
@@ -114,2 +161,18 @@ dataLayer.push(__assign(__assign({}, additionalEventData), { event: "content-view", "content-name": path, "content-view-name": screenName })); | ||
}; | ||
/** | ||
* Track an event. | ||
* | ||
* The event will only be send if the script runs in browser context and the if plugin is enabled. | ||
* | ||
* If debug mode is enabled, a "Dispatching event" is logged, | ||
* regardless of whether the plugin is enabled or the plugin is being executed in browser context. | ||
* | ||
* @param param0 Object that will be used for configuring the event object passed to GTM. | ||
* @param param0.event `event`, default to `"interaction"` when pushed to `window.dataLayer`. | ||
* @param param0.category Optional `category`, passed as `target`. | ||
* @param param0.action Optional `action`, passed as `action`. | ||
* @param param0.label Optional `label`, passed as `"target-properties"`. | ||
* @param param0.value Optional `value`, passed as `value`. | ||
* @param param0.noninteraction Optional `noninteraction`, passed as `"interaction-type"`. | ||
*/ | ||
VueGtmPlugin.prototype.trackEvent = function (_a) { | ||
@@ -119,8 +182,10 @@ var _b; | ||
var event = _a.event, _c = _a.category, category = _c === void 0 ? null : _c, _d = _a.action, action = _d === void 0 ? null : _d, _e = _a.label, label = _e === void 0 ? null : _e, _f = _a.value, value = _f === void 0 ? null : _f, _g = _a.noninteraction, noninteraction = _g === void 0 ? false : _g, rest = __rest(_a, ["event", "category", "action", "label", "value", "noninteraction"]); | ||
utils_1.logDebug("Dispatching event", __assign({ event: event, | ||
category: category, | ||
action: action, | ||
label: label, | ||
value: value }, rest)); | ||
if (inBrowser && config_1.default.enabled) { | ||
if (this.options.debug) { | ||
console.log("[VueGtm]: Dispatching event", __assign({ event: event, | ||
category: category, | ||
action: action, | ||
label: label, | ||
value: value }, rest)); | ||
} | ||
if (this.isInBrowserContext() && this.options.enabled) { | ||
var dataLayer = (window.dataLayer = (_b = window.dataLayer) !== null && _b !== void 0 ? _b : []); | ||
@@ -127,0 +192,0 @@ dataLayer.push(__assign({ event: event !== null && event !== void 0 ? event : "interaction", target: category, action: action, "target-properties": label, value: value, "interaction-type": noninteraction }, rest)); |
import "url-search-params-polyfill"; | ||
import { VueGtmUseOptions } from "./config"; | ||
/** | ||
* Console log depending on config debug mode | ||
* Load GTM script tag. | ||
* | ||
* @param message | ||
* @param id GTM ID. | ||
* @param config The config object. | ||
*/ | ||
export declare function logDebug(message: string, args: Record<string, any>): void; | ||
export declare function loadScript(id: string, config?: Pick<VueGtmUseOptions, "defer" | "compatibility" | "queryParams">): void; | ||
/** | ||
* Load GTM script tag | ||
* Check if GTM script is in the document. | ||
* | ||
* @param id GTM ID | ||
* @param params query params object | ||
* @returns `true` if in the `document` is a `script` with `src` containing `googletagmanager.com/gtm.js`, otherwise `false`. | ||
*/ | ||
export declare function loadScript(id: string, config?: Pick<VueGtmUseOptions, "defer" | "compatibility" | "queryParams">): void; | ||
/** | ||
* Check if GTM script is in the document | ||
*/ | ||
export declare function hasScript(): boolean; |
@@ -13,43 +13,11 @@ "use strict"; | ||
}; | ||
var __read = (this && this.__read) || function (o, n) { | ||
var m = typeof Symbol === "function" && o[Symbol.iterator]; | ||
if (!m) return o; | ||
var i = m.call(o), r, ar = [], e; | ||
try { | ||
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); | ||
} | ||
catch (error) { e = { error: error }; } | ||
finally { | ||
try { | ||
if (r && !r.done && (m = i["return"])) m.call(i); | ||
} | ||
finally { if (e) throw e.error; } | ||
} | ||
return ar; | ||
}; | ||
var __spread = (this && this.__spread) || function () { | ||
for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i])); | ||
return ar; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.hasScript = exports.loadScript = exports.logDebug = void 0; | ||
exports.hasScript = exports.loadScript = void 0; | ||
require("url-search-params-polyfill"); | ||
var config_1 = require("./config"); | ||
/** | ||
* Console log depending on config debug mode | ||
* Load GTM script tag. | ||
* | ||
* @param message | ||
* @param id GTM ID. | ||
* @param config The config object. | ||
*/ | ||
function logDebug(message, args) { | ||
if (config_1.default.debug) { | ||
console.log.apply(console, __spread(["VueGtm :"], arguments)); | ||
} | ||
} | ||
exports.logDebug = logDebug; | ||
/** | ||
* Load GTM script tag | ||
* | ||
* @param id GTM ID | ||
* @param params query params object | ||
*/ | ||
function loadScript(id, config) { | ||
@@ -77,3 +45,5 @@ var _a, _b, _c; | ||
/** | ||
* Check if GTM script is in the document | ||
* Check if GTM script is in the document. | ||
* | ||
* @returns `true` if in the `document` is a `script` with `src` containing `googletagmanager.com/gtm.js`, otherwise `false`. | ||
*/ | ||
@@ -80,0 +50,0 @@ function hasScript() { |
{ | ||
"name": "vue-gtm", | ||
"version": "3.3.2", | ||
"version": "3.4.0-vue2", | ||
"description": "Google Tag Manager implementation in Vue application", | ||
@@ -67,5 +67,7 @@ "main": "dist/index.js", | ||
"@typescript-eslint/parser": "~4.15.0", | ||
"eslint": "~7.19.0", | ||
"eslint": "~7.20.0", | ||
"eslint-config-prettier": "~7.2.0", | ||
"eslint-plugin-jsdoc": "~32.0.0", | ||
"eslint-plugin-prettier": "~3.3.1", | ||
"eslint-plugin-spellcheck": "~0.0.17", | ||
"jest": "~26.6.3", | ||
@@ -76,8 +78,9 @@ "jest-junit": "~12.0.0", | ||
"ts-jest": "~26.5.1", | ||
"typescript": "^4.1.5", | ||
"vue": "^3.0.0" | ||
"typescript": "~4.1.5", | ||
"vue": "^2.6.12", | ||
"vue-router": "^3.5.0" | ||
}, | ||
"peerDependencies": { | ||
"vue": "^3.0.0" | ||
"vue": "^2.6.0" | ||
} | ||
} |
@@ -69,3 +69,3 @@ <h1 align="center">Vue Google Tag Manager</h1> | ||
createGtm({ | ||
id: "GTM-xxxxxx", // Your GTM single container ID, array of container ids ['GTM-xxxxxx', 'GTM-yyyyyy'] or array of objects [{id: 'GTM-xxxxxx', queryPararms: { gtm_auth: 'abc123', gtm_preview: 'env-4', gtm_cookies_win: 'x'}}, {id: 'GTM-yyyyyy', queryParams: {gtm_auth: 'abc234', gtm_preview: 'env-5', gtm_cookies_win: 'x'}}], // Your GTM single container ID or array of container ids ['GTM-xxxxxx', 'GTM-yyyyyy'] | ||
id: "GTM-xxxxxx", // Your GTM single container ID, array of container ids ['GTM-xxxxxx', 'GTM-yyyyyy'] or array of objects [{id: 'GTM-xxxxxx', queryParams: { gtm_auth: 'abc123', gtm_preview: 'env-4', gtm_cookies_win: 'x'}}, {id: 'GTM-yyyyyy', queryParams: {gtm_auth: 'abc234', gtm_preview: 'env-5', gtm_cookies_win: 'x'}}], // Your GTM single container ID or array of container ids ['GTM-xxxxxx', 'GTM-yyyyyy'] | ||
queryParams: { | ||
@@ -147,3 +147,3 @@ // Add url query string when load gtm.js with GTM ID (optional) | ||
mounted() { | ||
this.$gtm.trackView("MyScreenName", "currentpath"); | ||
this.$gtm.trackView("MyScreenName", "currentPath"); | ||
}, | ||
@@ -150,0 +150,0 @@ }; |
@@ -0,24 +1,74 @@ | ||
import type Router from "vue-router"; | ||
/** | ||
* Query parameter object that will be send to GTM. | ||
*/ | ||
export interface VueGtmQueryParams { | ||
/** | ||
* GTM auth environment parameter. | ||
*/ | ||
gtm_auth: string; | ||
/** | ||
* GTM preview environment parameter. | ||
*/ | ||
gtm_preview: string; | ||
/** | ||
* GTM cookies win environment parameter. | ||
*/ | ||
gtm_cookies_win: string; | ||
} | ||
/** | ||
* GTM ID Container. | ||
*/ | ||
export interface VueGtmContainer { | ||
/** | ||
* GTM Container ID. | ||
*/ | ||
id: string; | ||
/** | ||
* Add url query string when load gtm.js with GTM ID. | ||
*/ | ||
queryParams?: VueGtmQueryParams; | ||
} | ||
/** | ||
* Options passed to the plugin. | ||
*/ | ||
export interface VueGtmUseOptions { | ||
// eslint-disable-next-line spellcheck/spell-checker | ||
/** | ||
* Your GTM single container ID, array of container ids ['GTM-xxxxxx', 'GTM-yyyyyy'], or array of objects [{id: 'GTM-xxxxxx', queryPararms: { gtm_auth: 'abc123', gtm_preview: 'env-4', gtm_cookies_win: 'x'}}, {id: 'GTM-yyyyyy', queryParams: {gtm_auth: 'abc234', gtm_preview: 'env-5', gtm_cookies_win: 'x'}}]. | ||
* Your GTM single container ID, array of container ids or array of objects. | ||
* | ||
* @example | ||
* 'GTM-xxxxxx' | ||
* // or | ||
* ['GTM-xxxxxx', 'GTM-yyyyyy'] | ||
* // or | ||
* [{ | ||
* id: 'GTM-xxxxxx', | ||
* queryParams: { | ||
* gtm_auth: 'abc123', | ||
* gtm_preview: 'env-4', | ||
* gtm_cookies_win: 'x' | ||
* } | ||
* }, { | ||
* id: 'GTM-yyyyyy', | ||
* queryParams: { | ||
* gtm_auth: 'abc234', | ||
* gtm_preview: 'env-5', | ||
* gtm_cookies_win: 'x' | ||
* } | ||
* }] | ||
*/ | ||
id: string | string[] | VueGtmContainer[]; | ||
/** | ||
* Add url query string when load gtm.js with GTM ID | ||
* Add url query string when load gtm.js with GTM ID. | ||
*/ | ||
queryParams?: VueGtmQueryParams; | ||
/** | ||
* Script can be set to `defer` to speed up page load at the cost of less accurate results (in case visitor leaves before script is loaded, which is unlikely but possible). Defaults to false, so the script is loaded `async` by default | ||
* Script can be set to `defer` to speed up page load at the cost of less accurate results (in case visitor leaves before script is loaded, which is unlikely but possible). | ||
* | ||
* Defaults to false, so the script is loaded `async` by default. | ||
* | ||
* @default false | ||
@@ -28,3 +78,3 @@ */ | ||
/** | ||
* Will add `async` and `defer` to the script tag to not block requests for old browsers that do not support `async` | ||
* Will add `async` and `defer` to the script tag to not block requests for old browsers that do not support `async`. | ||
* | ||
@@ -35,4 +85,6 @@ * @default false | ||
/** | ||
* Plugin can be disabled by setting this to `false` for Ex: `enabled: !!GDPR_Cookie` | ||
* Plugin can be disabled by setting this to `false`. | ||
* | ||
* @example enabled: !!GDPR_Cookie | ||
* | ||
* @default true | ||
@@ -42,22 +94,21 @@ */ | ||
/** | ||
* Whether or not display console logs debugs | ||
* Whether or not to display console logs debugs. | ||
*/ | ||
debug?: boolean; | ||
/** | ||
* Whether or not to load the GTM Script (Helpful if you are including GTM manually, but need the dataLayer functionality in your components) | ||
* Whether or not to load the GTM Script. | ||
* | ||
* Helpful if you are including GTM manually, but need the dataLayer functionality in your components. | ||
*/ | ||
loadScript?: boolean; | ||
/** | ||
* Pass the router instance to automatically sync with router | ||
* Pass the router instance to automatically sync with router. | ||
*/ | ||
vueRouter?: { | ||
readonly options: any; | ||
afterEach(guard: (to: any, from: any) => any): () => void; | ||
}; | ||
vueRouter?: Router; | ||
/** | ||
* Don't trigger events for specified router names (case insensitive) | ||
* Don't trigger events for specified router names (case insensitive). | ||
*/ | ||
ignoredViews?: string[]; | ||
/** | ||
* Whether or not call `trackView` in `Vue.nextTick` | ||
* Whether or not call `trackView` in `Vue.nextTick`. | ||
*/ | ||
@@ -67,13 +118,19 @@ trackOnNextTick?: boolean; | ||
// @ts-ignore | ||
const config: VueGtmUseOptions = { | ||
/** | ||
* Default configuration for the plugin. | ||
*/ | ||
export const DEFAULT_CONFIG: Readonly<{ | ||
enabled: true; | ||
debug: false; | ||
trackOnNextTick: false; | ||
loadScript: true; | ||
defer: false; | ||
compatibility: false; | ||
}> = { | ||
enabled: true, | ||
debug: false, | ||
trackOnNextTick: false, | ||
queryParams: undefined, | ||
loadScript: true, | ||
defer: false, | ||
compatibility: false, | ||
}; | ||
export default config; | ||
} as const; |
166
src/index.ts
@@ -1,3 +0,3 @@ | ||
import { App, nextTick, Plugin } from "vue"; | ||
import pluginConfig, { VueGtmContainer, VueGtmQueryParams, VueGtmUseOptions } from "./config"; | ||
import _Vue, { PluginObject } from "vue"; | ||
import { DEFAULT_CONFIG, VueGtmContainer, VueGtmQueryParams, VueGtmUseOptions } from "./config"; | ||
import GtmPlugin from "./plugin"; | ||
@@ -8,55 +8,56 @@ import { loadScript } from "./utils"; | ||
const GTM_ID_PATTERN: RegExp = /^GTM-[0-9A-Z]+$/; | ||
/** | ||
* Installation procedure | ||
* Assert that the given id is a valid GTM Container ID. | ||
* | ||
* @param Vue | ||
* @param initConf | ||
* Tested against pattern: `/^GTM-[0-9A-Z]+$/`. | ||
* | ||
* @param id A GTM Container ID. | ||
*/ | ||
function install(Vue: App, initConf: VueGtmUseOptions = { id: "" }): void { | ||
if (Array.isArray(initConf.id)) { | ||
for (const idOrObject of initConf.id) { | ||
function assertIsGtmId(id: string): asserts id { | ||
if (typeof id !== "string" || !GTM_ID_PATTERN.test(id)) { | ||
throw new Error(`GTM-ID '${id}' is not valid`); | ||
} | ||
} | ||
/** | ||
* Installation procedure. | ||
* | ||
* @param Vue The Vue instance. | ||
* @param options Configuration options. | ||
*/ | ||
function install(Vue: typeof _Vue, options: VueGtmUseOptions = { id: "" }): void { | ||
if (Array.isArray(options.id)) { | ||
for (const idOrObject of options.id) { | ||
if (typeof idOrObject === "string") { | ||
if (!GTM_ID_PATTERN.test(idOrObject)) { | ||
throw new Error(`GTM-ID '${idOrObject}' is not valid`); | ||
} | ||
} else if (!GTM_ID_PATTERN.test(idOrObject.id)) { | ||
throw new Error(`GTM-ID '${idOrObject.id}' is not valid`); | ||
assertIsGtmId(idOrObject); | ||
} else { | ||
assertIsGtmId(idOrObject.id); | ||
} | ||
} | ||
} else if (!GTM_ID_PATTERN.test(initConf.id)) { | ||
throw new Error(`GTM-ID '${initConf.id}' is not valid`); | ||
} else { | ||
assertIsGtmId(options.id); | ||
} | ||
// Apply default configuration | ||
initConf = { ...pluginConfig, ...initConf }; | ||
options = { ...DEFAULT_CONFIG, ...options }; | ||
pluginConfig.id = initConf.id; | ||
pluginConfig.debug = initConf.debug; | ||
pluginConfig.enabled = initConf.enabled; | ||
pluginConfig.loadScript = initConf.loadScript; | ||
pluginConfig.defer = initConf.defer; | ||
pluginConfig.compatibility = initConf.compatibility; | ||
pluginConfig.queryParams = { | ||
...pluginConfig.queryParams, | ||
...initConf.queryParams, | ||
} as VueGtmQueryParams; | ||
// Add to vue prototype and also from globals | ||
gtmPlugin = new GtmPlugin(pluginConfig.id); | ||
Vue.config.globalProperties.$gtm = gtmPlugin; | ||
gtmPlugin = new GtmPlugin(options.id, options); | ||
Vue.prototype.$gtm = Vue.gtm = gtmPlugin; | ||
// Handle vue-router if defined | ||
if (initConf.vueRouter) { | ||
initVueRouterGuard(Vue, initConf); | ||
if (options.vueRouter) { | ||
initVueRouterGuard(Vue, options.vueRouter, options.ignoredViews, options.trackOnNextTick); | ||
} | ||
// Load GTM script when enabled | ||
if (pluginConfig.enabled && pluginConfig.loadScript) { | ||
if (Array.isArray(initConf.id)) { | ||
initConf.id.forEach((id: string | VueGtmContainer) => { | ||
if (gtmPlugin.options.enabled && gtmPlugin.options.loadScript) { | ||
if (Array.isArray(options.id)) { | ||
options.id.forEach((id: string | VueGtmContainer) => { | ||
if (typeof id === "string") { | ||
loadScript(id, initConf); | ||
loadScript(id, options); | ||
} else { | ||
const newConf: VueGtmUseOptions = { | ||
...initConf, | ||
...options, | ||
}; | ||
@@ -75,24 +76,23 @@ | ||
} else { | ||
loadScript(initConf.id, initConf); | ||
loadScript(options.id, options); | ||
} | ||
} | ||
Vue.provide("gtm", initConf); | ||
} | ||
/** | ||
* Init the router guard. | ||
* Initialize the router guard. | ||
* | ||
* @param Vue - The Vue instance | ||
* @param vueRouter - The Vue router instance to attach guard | ||
* @param ignoredViews - An array of route name to ignore | ||
* @param trackOnNextTick - Whether or not call trackView in Vue.nextTick | ||
* | ||
* @returns The ignored routes names formalized. | ||
* @param Vue The Vue instance. | ||
* @param vueRouter The Vue router instance to attach the guard. | ||
* @param ignoredViews An array of route name that will be ignored. | ||
* @param trackOnNextTick Whether or not to call `trackView` in `Vue.nextTick`. | ||
*/ | ||
function initVueRouterGuard( | ||
Vue: App, | ||
{ vueRouter, ignoredViews = [], trackOnNextTick }: VueGtmUseOptions | ||
): string[] | undefined { | ||
Vue: typeof _Vue, | ||
vueRouter: VueGtmUseOptions["vueRouter"], | ||
ignoredViews: VueGtmUseOptions["ignoredViews"] = [], | ||
trackOnNextTick: VueGtmUseOptions["trackOnNextTick"] | ||
): void { | ||
if (!vueRouter) { | ||
console.warn("[VueGtm]: You tried to register 'vueRouter' for vue-gtm, but 'vue-router' was not found."); | ||
return; | ||
@@ -104,50 +104,38 @@ } | ||
vueRouter.afterEach( | ||
(to: { | ||
name?: string; | ||
meta: Partial<{ | ||
gtm: string; | ||
gtmAdditionalEventData: Record<string, any>; | ||
}>; | ||
fullPath: string; | ||
}) => { | ||
// Ignore some routes | ||
if (!to.name || ignoredViews.indexOf(to.name.toLowerCase()) !== -1) { | ||
return; | ||
} | ||
vueRouter.afterEach((to) => { | ||
// Ignore some routes | ||
if (typeof to.name !== "string" || ignoredViews.indexOf(to.name.toLowerCase()) !== -1) { | ||
return; | ||
} | ||
// Dispatch vue event using meta gtm value if defined otherwise fallback to route name | ||
const name: string = to.meta.gtm ?? to.name; | ||
const additionalEventData: Record<string, any> = to.meta.gtmAdditionalEventData ?? {}; | ||
const baseUrl: string = vueRouter.options.base || ""; | ||
let fullUrl: string = baseUrl; | ||
if (!fullUrl.endsWith("/")) { | ||
fullUrl += "/"; | ||
} | ||
fullUrl += to.fullPath.startsWith("/") ? to.fullPath.substr(1) : to.fullPath; | ||
// Dispatch vue event using meta gtm value if defined otherwise fallback to route name | ||
const name: string = to.meta && typeof to.meta.gtm === "string" && !!to.meta.gtm ? to.meta.gtm : to.name; | ||
const additionalEventData: Record<string, any> = to.meta?.gtmAdditionalEventData ?? {}; | ||
const baseUrl: string = vueRouter.options.base ?? ""; | ||
let fullUrl: string = baseUrl; | ||
if (!fullUrl.endsWith("/")) { | ||
fullUrl += "/"; | ||
} | ||
fullUrl += to.fullPath.startsWith("/") ? to.fullPath.substr(1) : to.fullPath; | ||
if (trackOnNextTick) { | ||
void nextTick(() => { | ||
gtmPlugin?.trackView(name, fullUrl, additionalEventData); | ||
}); | ||
} else { | ||
if (trackOnNextTick) { | ||
Vue.nextTick(() => { | ||
gtmPlugin?.trackView(name, fullUrl, additionalEventData); | ||
} | ||
}); | ||
} else { | ||
gtmPlugin?.trackView(name, fullUrl, additionalEventData); | ||
} | ||
); | ||
return ignoredViews; | ||
}); | ||
} | ||
export function createGtm(options: VueGtmUseOptions): VueGtmPlugin { | ||
return { install: (app: App) => install(app, options) }; | ||
} | ||
declare module "@vue/runtime-core" { | ||
export interface ComponentCustomProperties { | ||
declare module "vue/types/vue" { | ||
export interface Vue { | ||
$gtm: GtmPlugin; | ||
} | ||
export interface VueConstructor<V extends Vue = Vue> { | ||
gtm: GtmPlugin; | ||
} | ||
} | ||
export type VueGtmPlugin = Plugin; | ||
export type VueGtmPlugin = PluginObject<VueGtmUseOptions>; | ||
export { VueGtmUseOptions } from "./config"; | ||
@@ -160,3 +148,5 @@ | ||
/** | ||
* Returns gtm plugin to be used via composition api inside setup method | ||
* Returns GTM plugin instance to be used via Composition API inside setup method. | ||
* | ||
* @returns The Vue GTM instance if the it was installed, otherwise `undefined`. | ||
*/ | ||
@@ -163,0 +153,0 @@ export function useGtm(): GtmPlugin | undefined { |
@@ -1,4 +0,9 @@ | ||
import pluginConfig, { VueGtmContainer } from "./config"; | ||
import { hasScript, loadScript, logDebug } from "./utils"; | ||
import { DEFAULT_CONFIG, VueGtmContainer, VueGtmUseOptions } from "./config"; | ||
import { hasScript, loadScript } from "./utils"; | ||
/** | ||
* Object within the `window.dataLayer`. | ||
* | ||
* @see [developers.google.com/tag-manager/devguide](https://developers.google.com/tag-manager/devguide) | ||
*/ | ||
export interface DataLayerObject extends Record<string, any> { | ||
@@ -10,2 +15,7 @@ event: string; | ||
interface Window { | ||
/** | ||
* `dataLayer` used by GTM. | ||
* | ||
* @see [developers.google.com/tag-manager/devguide](https://developers.google.com/tag-manager/devguide) | ||
*/ | ||
dataLayer?: DataLayerObject[]; | ||
@@ -15,4 +25,5 @@ } | ||
const inBrowser: boolean = typeof window !== "undefined"; | ||
/** | ||
* Object definition for a track event. | ||
*/ | ||
export interface VueGtmTrackEventParams { | ||
@@ -29,23 +40,49 @@ [key: string]: any; | ||
/** | ||
* Plugin main class | ||
* The Vue GTM Plugin main class. | ||
*/ | ||
export default class VueGtmPlugin { | ||
constructor(public readonly id: string | string[] | VueGtmContainer[]) {} | ||
/** | ||
* Constructs a new `VueGTMPlugin`. | ||
* | ||
* @param id A GTM Container ID. | ||
* @param options Options. | ||
*/ | ||
public constructor( | ||
public readonly id: string | string[] | VueGtmContainer[], | ||
public readonly options: Pick<VueGtmUseOptions, keyof typeof DEFAULT_CONFIG | "queryParams"> = DEFAULT_CONFIG | ||
) {} | ||
/** | ||
* Check if plugin is enabled | ||
* Whether the script is running in a browser or not. | ||
* | ||
* You can override this function if you need to. | ||
* | ||
* @returns `true` if the script runs in browser context. | ||
*/ | ||
enabled(): boolean { | ||
return pluginConfig.enabled ?? true; | ||
public isInBrowserContext: () => boolean = () => typeof window !== "undefined"; | ||
/** | ||
* Check if plugin is enabled. | ||
* | ||
* @returns `true` if the plugin is enabled, otherwise `false`. | ||
*/ | ||
public enabled(): boolean { | ||
return this.options.enabled ?? true; | ||
} | ||
/** | ||
* Enable or disable plugin | ||
* Enable or disable plugin. | ||
* | ||
* @param val state | ||
* When enabling with this function, the script will be attached to the `document` if: | ||
* | ||
* - the script runs in browser context | ||
* - the `document` doesn't have the script already attached | ||
* - the `loadScript` option is set to `true` | ||
* | ||
* @param enabled `true` to enable, `false` to disable. Default: `true`. | ||
*/ | ||
enable(val: boolean): void { | ||
pluginConfig.enabled = val; | ||
public enable(enabled: boolean = true): void { | ||
this.options.enabled = enabled; | ||
if (inBrowser && !!val && !hasScript() && pluginConfig.loadScript) { | ||
if (this.isInBrowserContext() && enabled && !hasScript() && this.options.loadScript) { | ||
if (Array.isArray(this.id)) { | ||
@@ -55,10 +92,10 @@ this.id.forEach((id: string | VueGtmContainer) => { | ||
loadScript(id, { | ||
defer: pluginConfig.defer, | ||
compatibility: pluginConfig.compatibility, | ||
queryParams: pluginConfig.queryParams, | ||
defer: this.options.defer, | ||
compatibility: this.options.compatibility, | ||
queryParams: this.options.queryParams, | ||
}); | ||
} else { | ||
loadScript(id.id, { | ||
defer: pluginConfig.defer, | ||
compatibility: pluginConfig.compatibility, | ||
defer: this.options.defer, | ||
compatibility: this.options.compatibility, | ||
queryParams: id.queryParams, | ||
@@ -70,5 +107,5 @@ }); | ||
loadScript(this.id, { | ||
defer: pluginConfig.defer, | ||
compatibility: pluginConfig.compatibility, | ||
queryParams: pluginConfig.queryParams, | ||
defer: this.options.defer, | ||
compatibility: this.options.compatibility, | ||
queryParams: this.options.queryParams, | ||
}); | ||
@@ -80,19 +117,27 @@ } | ||
/** | ||
* Check if plugin is in debug mode | ||
* Check if plugin is in debug mode. | ||
* | ||
* @returns `true` if the plugin is in debug mode, otherwise `false`. | ||
*/ | ||
debugEnabled(): boolean { | ||
return pluginConfig.debug ?? false; | ||
public debugEnabled(): boolean { | ||
return this.options.debug ?? false; | ||
} | ||
/** | ||
* Enable or disable debug mode | ||
* Enable or disable debug mode. | ||
* | ||
* @param val state | ||
* @param enable `true` to enable, `false` to disable. | ||
*/ | ||
debug(val: boolean): void { | ||
pluginConfig.debug = val; | ||
public debug(enable: boolean): void { | ||
this.options.debug = enable; | ||
} | ||
dataLayer(): DataLayerObject[] | false { | ||
if (inBrowser && pluginConfig.enabled) { | ||
/** | ||
* Returns the `window.dataLayer` array if the script is running in browser context and the plugin is enabled, | ||
* otherwise `false`. | ||
* | ||
* @returns The `window.dataLayer` if script is running in browser context and plugin is enabled, otherwise `false`. | ||
*/ | ||
public dataLayer(): DataLayerObject[] | false { | ||
if (this.isInBrowserContext() && this.options.enabled) { | ||
return (window.dataLayer = window.dataLayer ?? []); | ||
@@ -103,6 +148,20 @@ } | ||
trackView(screenName: string, path: string, additionalEventData: Record<string, any> = {}): void { | ||
logDebug("Dispatching TrackView", { screenName, path }); | ||
/** | ||
* Track a view event with `event: "content-view"`. | ||
* | ||
* The event will only be send if the script runs in browser context and the if plugin is enabled. | ||
* | ||
* If debug mode is enabled, a "Dispatching TrackView" is logged, | ||
* regardless of whether the plugin is enabled or the plugin is being executed in browser context. | ||
* | ||
* @param screenName Name of the screen passed as `"content-view-name"`. | ||
* @param path Path passed as `"content-name"`. | ||
* @param additionalEventData Additional data for the event object. `event`, `"content-name"` and `"content-view-name"` will always be overridden. | ||
*/ | ||
public trackView(screenName: string, path: string, additionalEventData: Record<string, any> = {}): void { | ||
if (this.options.debug) { | ||
console.log("[VueGtm]: Dispatching TrackView", { screenName, path }); | ||
} | ||
if (inBrowser && pluginConfig.enabled) { | ||
if (this.isInBrowserContext() && this.options.enabled) { | ||
const dataLayer: DataLayerObject[] = (window.dataLayer = window.dataLayer ?? []); | ||
@@ -118,3 +177,19 @@ dataLayer.push({ | ||
trackEvent({ | ||
/** | ||
* Track an event. | ||
* | ||
* The event will only be send if the script runs in browser context and the if plugin is enabled. | ||
* | ||
* If debug mode is enabled, a "Dispatching event" is logged, | ||
* regardless of whether the plugin is enabled or the plugin is being executed in browser context. | ||
* | ||
* @param param0 Object that will be used for configuring the event object passed to GTM. | ||
* @param param0.event `event`, default to `"interaction"` when pushed to `window.dataLayer`. | ||
* @param param0.category Optional `category`, passed as `target`. | ||
* @param param0.action Optional `action`, passed as `action`. | ||
* @param param0.label Optional `label`, passed as `"target-properties"`. | ||
* @param param0.value Optional `value`, passed as `value`. | ||
* @param param0.noninteraction Optional `noninteraction`, passed as `"interaction-type"`. | ||
*/ | ||
public trackEvent({ | ||
event, | ||
@@ -128,12 +203,14 @@ category = null, | ||
}: VueGtmTrackEventParams = {}): void { | ||
logDebug("Dispatching event", { | ||
event, | ||
category, | ||
action, | ||
label, | ||
value, | ||
...rest, | ||
}); | ||
if (this.options.debug) { | ||
console.log("[VueGtm]: Dispatching event", { | ||
event, | ||
category, | ||
action, | ||
label, | ||
value, | ||
...rest, | ||
}); | ||
} | ||
if (inBrowser && pluginConfig.enabled) { | ||
if (this.isInBrowserContext() && this.options.enabled) { | ||
const dataLayer: DataLayerObject[] = (window.dataLayer = window.dataLayer ?? []); | ||
@@ -140,0 +217,0 @@ dataLayer.push({ |
import "url-search-params-polyfill"; | ||
import pluginConfig, { VueGtmUseOptions } from "./config"; | ||
import { VueGtmUseOptions } from "./config"; | ||
/** | ||
* Console log depending on config debug mode | ||
* Load GTM script tag. | ||
* | ||
* @param message | ||
* @param id GTM ID. | ||
* @param config The config object. | ||
*/ | ||
export function logDebug(message: string, args: Record<string, any>): void { | ||
if (pluginConfig.debug) { | ||
console.log("VueGtm :", ...arguments); | ||
} | ||
} | ||
/** | ||
* Load GTM script tag | ||
* | ||
* @param id GTM ID | ||
* @param params query params object | ||
*/ | ||
export function loadScript( | ||
@@ -52,3 +41,5 @@ id: string, | ||
/** | ||
* Check if GTM script is in the document | ||
* Check if GTM script is in the document. | ||
* | ||
* @returns `true` if in the `document` is a `script` with `src` containing `googletagmanager.com/gtm.js`, otherwise `false`. | ||
*/ | ||
@@ -55,0 +46,0 @@ export function hasScript(): boolean { |
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
68716
19.67%1211
29.94%16
23.08%1
Infinity%