angulartics
Advanced tools
Comparing version 0.15.20 to 0.16.1
{ | ||
"name": "angulartics", | ||
"version": "0.15.20", | ||
"version": "0.16.1", | ||
"main": [ | ||
@@ -5,0 +5,0 @@ "src/angulartics.js", |
@@ -7,2 +7,2 @@ /** | ||
*/ | ||
!function(a){"use strict";a.module("angulartics.mixpanel",["angulartics"]).config(["$analyticsProvider",function(a){angulartics.waitForVendorApi("mixpanel",500,"__loaded",function(b){a.registerPageTrack(function(a){b.track("Page Viewed",{page:a})})}),angulartics.waitForVendorApi("mixpanel",500,"__loaded",function(b){a.registerEventTrack(function(a,c){b.track(a,c)})}),angulartics.waitForVendorApi("mixpanel",500,function(b){a.registerSetUsername(function(a){b.identify(a)})}),angulartics.waitForVendorApi("mixpanel",500,function(b){a.registerSetUserProperties(function(a){b.people.set(a)})}),angulartics.waitForVendorApi("mixpanel",500,function(b){a.registerSetUserPropertiesOnce(function(a){b.people.set_once(a)})})}])}(angular); | ||
!function(a){"use strict";a.module("angulartics.mixpanel",["angulartics"]).config(["$analyticsProvider",function(a){angulartics.waitForVendorApi("mixpanel",500,function(b){a.registerSetUsername(function(a){b.identify(a)})}),angulartics.waitForVendorApi("mixpanel",500,function(b){a.registerSetSuperPropertiesOnce(function(a){b.register_once(a)})}),angulartics.waitForVendorApi("mixpanel",500,function(b){a.registerSetSuperProperties(function(a){b.register(a)})}),angulartics.waitForVendorApi("mixpanel",500,function(b){a.registerSetUserPropertiesOnce(function(a){b.people.set_once(a)})}),angulartics.waitForVendorApi("mixpanel",500,function(b){a.registerSetUserProperties(function(a){b.people.set(a)})}),angulartics.waitForVendorApi("mixpanel",500,"__loaded",function(b){a.registerPageTrack(function(a){b.track("Page Viewed",{page:a})})}),angulartics.waitForVendorApi("mixpanel",500,"__loaded",function(b){a.registerEventTrack(function(a,c){b.track(a,c)})})}])}(angular); |
@@ -7,2 +7,2 @@ /** | ||
*/ | ||
!function(a){"use strict";a.module("angulartics.piwik",["angulartics"]).config(["$analyticsProvider",function(a){a.settings.trackRelativePath=!0,a.registerPageTrack(function(a){window._paq&&(_paq.push(["setCustomUrl",a]),_paq.push(["trackPageView"]))}),a.registerEventTrack(function(a,b){if(b.value){var c=parseInt(b.value,10);b.value=isNaN(c)?0:c}console.warn("Piwik doesn't support event tracking -- silently ignored."),console.warn(" action [%s]",a),console.warn(" category [%s]",b.category),console.warn(" label [%s]",b.label),console.warn(" value [%s]",b.value),console.warn(" noninteraction [%s]",b.noninteraction),console.warn("")})}])}(angular); | ||
!function(a){"use strict";a.module("angulartics.piwik",["angulartics"]).config(["$analyticsProvider",function(a){a.settings.trackRelativePath=!0,a.registerPageTrack(function(a){window._paq&&(_paq.push(["setCustomUrl",a]),_paq.push(["trackPageView"]))}),a.registerEventTrack(function(a,b){if(b.value){var c=parseInt(b.value,10);b.value=isNaN(c)?0:c}window._paq&&_paq.push(["trackEvent",b.category,a,b.label,b.value])})}])}(angular); |
@@ -6,2 +6,2 @@ /** | ||
*/ | ||
!function(a){"use strict";var b=window.angulartics||(window.angulartics={});b.waitForVendorApi=function(a,c,d,e){e||(e=d,d=void 0),!Object.prototype.hasOwnProperty.call(window,a)||void 0!==d&&void 0===window[a][d]?setTimeout(function(){b.waitForVendorApi(a,c,d,e)},c):e(window[a])},a.module("angulartics",[]).provider("$analytics",function(){var b={pageTracking:{autoTrackFirstPage:!0,autoTrackVirtualPages:!0,trackRelativePath:!1,autoBasePath:!1,basePath:"",bufferFlushDelay:1e3},eventTracking:{bufferFlushDelay:1e3}},c={pageviews:[],events:[],setUsername:[],setUserProperties:[],setUserPropertiesOnce:[]},d=function(a){c.pageviews.push(a)},e=function(a,b){c.events.push({name:a,properties:b})},f=function(a){c.setUsername.push(a)},g=function(a){c.setUserProperties.push(a)},h=function(a){c.setUserPropertiesOnce.push(a)},i={settings:b,pageTrack:d,eventTrack:e,setUsername:f,setUserProperties:g,setUserPropertiesOnce:h},j=function(d){i.pageTrack=d,a.forEach(c.pageviews,function(a,c){setTimeout(function(){i.pageTrack(a)},c*b.pageTracking.bufferFlushDelay)})},k=function(d){i.eventTrack=d,a.forEach(c.events,function(a,c){setTimeout(function(){i.eventTrack(a.name,a.properties)},c*b.eventTracking.bufferFlushDelay)})},l=function(d){i.setUsername=d,a.forEach(c.setUsername,function(a,c){setTimeout(function(){i.setUsername(a)},c*b.pageTracking.bufferFlushDelay)})},m=function(d){i.setUserProperties=d,a.forEach(c.setUserProperties,function(a,c){setTimeout(function(){i.setUserProperties(a)},c*b.pageTracking.bufferFlushDelay)})},n=function(d){i.setUserPropertiesOnce=d,a.forEach(c.setUserPropertiesOnce,function(a,c){setTimeout(function(){i.setUserPropertiesOnce(a)},c*b.pageTracking.bufferFlushDelay)})};return{$get:function(){return i},settings:b,virtualPageviews:function(a){this.settings.pageTracking.autoTrackVirtualPages=a},firstPageview:function(a){this.settings.pageTracking.autoTrackFirstPage=a},withBase:function(b){this.settings.pageTracking.basePath=b?a.element("base").attr("href").slice(0,-1):""},withAutoBase:function(a){this.settings.pageTracking.autoBasePath=a},registerPageTrack:j,registerEventTrack:k,registerSetUsername:l,registerSetUserProperties:m,registerSetUserPropertiesOnce:n}}).run(["$rootScope","$location","$window","$analytics","$injector",function(a,b,c,d,e){if(d.settings.pageTracking.autoTrackFirstPage){var f=!0;if(e.has("$route")){var g=e.get("$route");for(var h in g.routes){f=!1;break}}else if(e.has("$state")){var i=e.get("$state");for(var j in i.states){f=!1;break}}else f=!1;if(f)if(d.settings.pageTracking.autoBasePath&&(d.settings.pageTracking.basePath=c.location.pathname),d.settings.trackRelativePath){var k=d.settings.pageTracking.basePath+b.url();d.pageTrack(k)}else d.pageTrack(b.absUrl())}d.settings.pageTracking.autoTrackVirtualPages&&(d.settings.pageTracking.autoBasePath&&(d.settings.pageTracking.basePath=c.location.pathname+"#"),e.has("$route")&&a.$on("$routeChangeSuccess",function(a,c){if(!c||!(c.$$route||c).redirectTo){var e=d.settings.pageTracking.basePath+b.url();d.pageTrack(e)}}),e.has("$state")&&a.$on("$stateChangeSuccess",function(){var a=d.settings.pageTracking.basePath+b.url();d.pageTrack(a)}))}]).directive("analyticsOn",["$analytics",function(b){function c(a){return["a:","button:","button:button","button:submit","input:button","input:submit"].indexOf(a.tagName.toLowerCase()+":"+(a.type||""))>=0}function d(a){return c(a)?"click":"click"}function e(a){return c(a)?a.innerText||a.value:a.id||a.name||a.tagName}function f(a){return"analytics"===a.substr(0,9)&&-1===["On","Event"].indexOf(a.substr(9))}return{restrict:"A",scope:!1,link:function(c,g,h){var i=h.analyticsOn||d(g[0]);a.element(g[0]).bind(i,function(){var c=h.analyticsEvent||e(g[0]),d={};a.forEach(h.$attr,function(a,b){f(b)&&(d[b.slice(9).toLowerCase()]=h[b])}),b.eventTrack(c,d)})}}}])}(angular); | ||
!function(a){"use strict";var b=window.angulartics||(window.angulartics={});b.waitForVendorCount=0,b.waitForVendorApi=function(a,c,d,e,f){f||b.waitForVendorCount++,e||(e=d,d=void 0),!Object.prototype.hasOwnProperty.call(window,a)||void 0!==d&&void 0===window[a][d]?setTimeout(function(){b.waitForVendorApi(a,c,d,e,!0)},c):(b.waitForVendorCount--,e(window[a]))},a.module("angulartics",[]).provider("$analytics",function(){var c={pageTracking:{autoTrackFirstPage:!0,autoTrackVirtualPages:!0,trackRelativePath:!1,autoBasePath:!1,basePath:""},eventTracking:{},bufferFlushDelay:1e3},d=["pageTrack","eventTrack","setUsername","setUserProperties","setUserPropertiesOnce","setSuperProperties","setSuperPropertiesOnce"],e={},f={},g=function(a){return function(){b.waitForVendorCount&&(e[a]||(e[a]=[]),e[a].push(arguments))}},h=function(b,c){return f[b]||(f[b]=[]),f[b].push(c),function(){var c=arguments;a.forEach(f[b],function(a){a.apply(this,c)},this)}},i={settings:c},j=function(a,b){b?setTimeout(a,b):a()},k={$get:function(){return i},api:i,settings:c,virtualPageviews:function(a){this.settings.pageTracking.autoTrackVirtualPages=a},firstPageview:function(a){this.settings.pageTracking.autoTrackFirstPage=a},withBase:function(b){this.settings.pageTracking.basePath=b?a.element("base").attr("href").slice(0,-1):""},withAutoBase:function(a){this.settings.pageTracking.autoBasePath=a}},l=function(b,d){i[b]=h(b,d);var f=c[b],g=f?f.bufferFlushDelay:null,k=null!==g?g:c.bufferFlushDelay;a.forEach(e[b],function(a,b){j(function(){d.apply(this,a)},b*k)})},m=function(a){return a.replace(/^./,function(a){return a.toUpperCase()})},n=function(a){var b="register"+m(a);k[b]=function(b){l(a,b)},i[a]=h(a,g(a))};return a.forEach(d,n),k}).run(["$rootScope","$location","$window","$analytics","$injector",function(a,b,c,d,e){if(d.settings.pageTracking.autoTrackFirstPage){var f=!0;if(e.has("$route")){var g=e.get("$route");for(var h in g.routes){f=!1;break}}else if(e.has("$state")){var i=e.get("$state");for(var j in i.states){f=!1;break}}else f=!1;if(f)if(d.settings.pageTracking.autoBasePath&&(d.settings.pageTracking.basePath=c.location.pathname),d.settings.trackRelativePath){var k=d.settings.pageTracking.basePath+b.url();d.pageTrack(k)}else d.pageTrack(b.absUrl())}d.settings.pageTracking.autoTrackVirtualPages&&(d.settings.pageTracking.autoBasePath&&(d.settings.pageTracking.basePath=c.location.pathname+"#"),e.has("$route")&&a.$on("$routeChangeSuccess",function(a,c){if(!c||!(c.$$route||c).redirectTo){var e=d.settings.pageTracking.basePath+b.url();d.pageTrack(e)}}),e.has("$state")&&a.$on("$stateChangeSuccess",function(){var a=d.settings.pageTracking.basePath+b.url();d.pageTrack(a)}))}]).directive("analyticsOn",["$analytics","$timeout",function(b){function c(a){return["a:","button:","button:button","button:submit","input:button","input:submit"].indexOf(a.tagName.toLowerCase()+":"+(a.type||""))>=0}function d(a){return c(a)?"click":"click"}function e(a){return c(a)?a.innerText||a.value:a.id||a.name||a.tagName}function f(a){return"analytics"===a.substr(0,9)&&-1===["On","Event","If","Properties","EventType"].indexOf(a.substr(9))}function g(a){var b=a.slice(9);return"undefined"!=typeof b&&null!==b&&b.length>0?b.substring(0,1).toLowerCase()+b.substring(1):b}return{restrict:"A",scope:!0,link:function(c,h,i){var j=i.analyticsOn||d(h[0]);c.$analytics={},a.forEach(i.$attr,function(a,b){f(b)&&i.$observe(b,function(a){c.$analytics[g(b)]=a})}),a.element(h[0]).bind(j,function(d){var f=i.analyticsEvent||e(h[0]);c.$analytics.eventType=d.type,(!i.analyticsIf||c.$eval(i.analyticsIf))&&(i.analyticsProperties&&a.extend(c.$analytics,c.$eval(i.analyticsProperties)),b.eventTrack(f,c.$analytics))})}}}])}(angular); |
@@ -28,8 +28,2 @@ module.exports = function(grunt) { | ||
changelog: { | ||
options: { | ||
// Task-specific options go here. | ||
} | ||
}, | ||
uglify: { | ||
@@ -72,3 +66,2 @@ options: { | ||
grunt.loadNpmTasks('grunt-contrib-clean'); | ||
grunt.loadNpmTasks('grunt-conventional-changelog'); | ||
@@ -75,0 +68,0 @@ grunt.registerTask('test', ['jshint', 'karma']); |
{ | ||
"name": "angulartics", | ||
"description": "Vendor-agnostic web analytics for AngularJS applications", | ||
"version": "0.15.20", | ||
"version": "0.16.1", | ||
"filename": "./src/angulartics.min.js", | ||
@@ -6,0 +6,0 @@ "homepage": "http://luisfarzati.github.io/angulartics", |
@@ -58,2 +58,54 @@ angulartics | ||
## for Google Tag Manager | ||
angular.module('myApp', ['angulartics', 'angulartics.google.tagmanager']) | ||
Add the full tracking code from Google Tag Manager to the beginning of your body tag. | ||
Setup listeners in Google Tag Manager | ||
* 6 Macros | ||
- Macro Name: angulartics page path | ||
- Macro Type: Data Layer Variable | ||
- Data Layer Variable Name: content-name | ||
- Macro Name: angulartics event category | ||
- Macro Type: Data Layer Variable | ||
- Data Layer Variable Name: target | ||
- Macro Name: angulartics event action | ||
- Macro Type: Data Layer Variable | ||
- Data Layer Variable Name: action | ||
- Macro Name: angulartics event label | ||
- Macro Type: Data Layer Variable | ||
- Data Layer Variable Name: target-properties | ||
- Macro Name: angulartics event value | ||
- Macro Type: Data Layer Variable | ||
- Data Layer Variable Name: value | ||
- Macro Name: angulartics event interaction type | ||
- Macro Type: Data Layer Variable | ||
- Data Layer Variable Name: interaction-type | ||
* 2 Rules | ||
- Rule Name: Angulartics events | ||
- Condition: {{event}} equals interaction | ||
- Rule Name: Angulartics pageviews | ||
- Condition: {{event}} equals content-view | ||
* 2 Tags | ||
- Tag Name: Angulartics Events | ||
- Tag Type: Universal Analytics | ||
- Tracking ID: YourGoogleAnalyticsID | ||
- Track Type: Event | ||
- Category: {{angulartics event category}} | ||
- Action: {{angulartics event action}} | ||
- Label: {{angulartics event label}} | ||
- Value: {{angulartics event value}} | ||
- Non-Interaction Hit: {{angulartics event interaction type}} | ||
- Firing Rules: Angulartics events | ||
- Tag Name: Angulartics Pageviews | ||
- Tag Type: Universal Analytics | ||
- Tracking ID: YourGoogleAnalyticsID | ||
- Track Type: Page View | ||
- More settings | ||
- Basic Confiruration | ||
- Document Path: {{angulartics page path}} | ||
- Firing Rules: Angulartics pageviews | ||
## for other providers | ||
@@ -60,0 +112,0 @@ |
@@ -17,11 +17,12 @@ /** | ||
.config(['$analyticsProvider', function ($analyticsProvider) { | ||
angulartics.waitForVendorApi('mixpanel', 500, '__loaded', function (mixpanel) { | ||
$analyticsProvider.registerPageTrack(function (path) { | ||
mixpanel.track( "Page Viewed", { "page": path } ); | ||
angulartics.waitForVendorApi('mixpanel', 500, function (mixpanel) { | ||
$analyticsProvider.registerSetUsername(function (userId) { | ||
mixpanel.identify(userId); | ||
}); | ||
}); | ||
angulartics.waitForVendorApi('mixpanel', 500, '__loaded', function (mixpanel) { | ||
$analyticsProvider.registerEventTrack(function (action, properties) { | ||
mixpanel.track(action, properties); | ||
angulartics.waitForVendorApi('mixpanel', 500, function (mixpanel) { | ||
$analyticsProvider.registerSetSuperPropertiesOnce(function (properties) { | ||
mixpanel.register_once(properties); | ||
}); | ||
@@ -31,4 +32,4 @@ }); | ||
angulartics.waitForVendorApi('mixpanel', 500, function (mixpanel) { | ||
$analyticsProvider.registerSetUsername(function (userId) { | ||
mixpanel.identify(userId); | ||
$analyticsProvider.registerSetSuperProperties(function (properties) { | ||
mixpanel.register(properties); | ||
}); | ||
@@ -38,2 +39,8 @@ }); | ||
angulartics.waitForVendorApi('mixpanel', 500, function (mixpanel) { | ||
$analyticsProvider.registerSetUserPropertiesOnce(function (properties) { | ||
mixpanel.people.set_once(properties); | ||
}); | ||
}); | ||
angulartics.waitForVendorApi('mixpanel', 500, function (mixpanel) { | ||
$analyticsProvider.registerSetUserProperties(function (properties) { | ||
@@ -44,8 +51,15 @@ mixpanel.people.set(properties); | ||
angulartics.waitForVendorApi('mixpanel', 500, function (mixpanel) { | ||
$analyticsProvider.registerSetUserPropertiesOnce(function (properties) { | ||
mixpanel.people.set_once(properties); | ||
angulartics.waitForVendorApi('mixpanel', 500, '__loaded', function (mixpanel) { | ||
$analyticsProvider.registerPageTrack(function (path) { | ||
mixpanel.track( "Page Viewed", { "page": path } ); | ||
}); | ||
}); | ||
angulartics.waitForVendorApi('mixpanel', 500, '__loaded', function (mixpanel) { | ||
$analyticsProvider.registerEventTrack(function (action, properties) { | ||
mixpanel.track(action, properties); | ||
}); | ||
}); | ||
}]); | ||
})(angular); |
@@ -32,16 +32,12 @@ /** | ||
$analyticsProvider.registerEventTrack(function(action, properties) { | ||
// GA requires that eventValue be an integer, see: | ||
// https://developers.google.com/analytics/devguides/collection/analyticsjs/field-reference#eventValue | ||
// https://github.com/luisfarzati/angulartics/issues/81 | ||
if (properties.value) { | ||
// PAQ requires that eventValue be an integer, see: | ||
// http://piwik.org/docs/event-tracking/ | ||
if(properties.value) { | ||
var parsed = parseInt(properties.value, 10); | ||
properties.value = isNaN(parsed) ? 0 : parsed; | ||
} | ||
console.warn('Piwik doesn\'t support event tracking -- silently ignored.'); | ||
console.warn('\t action\t[%s]', action); | ||
console.warn('\t category\t[%s]', properties.category); | ||
console.warn('\t label\t[%s]', properties.label); | ||
console.warn('\t value\t[%s]', properties.value); | ||
console.warn('\t noninteraction\t[%s]', properties.noninteraction); | ||
console.warn(''); | ||
if (window._paq) { | ||
_paq.push(['trackEvent', properties.category, action, properties.label, properties.value]); | ||
} | ||
}); | ||
@@ -48,0 +44,0 @@ |
@@ -10,8 +10,11 @@ /** | ||
var angulartics = window.angulartics || (window.angulartics = {}); | ||
angulartics.waitForVendorApi = function (objectName, delay, containsField, registerFn) { | ||
angulartics.waitForVendorCount = 0; | ||
angulartics.waitForVendorApi = function (objectName, delay, containsField, registerFn, onTimeout) { | ||
if (!onTimeout) { angulartics.waitForVendorCount++; } | ||
if (!registerFn) { registerFn = containsField; containsField = undefined; } | ||
if (!Object.prototype.hasOwnProperty.call(window, objectName) || (containsField !== undefined && window[objectName][containsField] === undefined)) { | ||
setTimeout(function () { angulartics.waitForVendorApi(objectName, delay, containsField, registerFn); }, delay); | ||
setTimeout(function () { angulartics.waitForVendorApi(objectName, delay, containsField, registerFn, true); }, delay); | ||
} | ||
else { | ||
angulartics.waitForVendorCount--; | ||
registerFn(window[objectName]); | ||
@@ -33,76 +36,65 @@ } | ||
autoBasePath: false, | ||
basePath: '', | ||
bufferFlushDelay: 1000 | ||
basePath: '' | ||
}, | ||
eventTracking: { | ||
bufferFlushDelay: 1000 | ||
} | ||
eventTracking: {}, | ||
bufferFlushDelay: 1000 // Support only one configuration for buffer flush delay to simplify buffering | ||
}; | ||
// List of known handlers that plugins can register themselves for | ||
var knownHandlers = [ | ||
'pageTrack', | ||
'eventTrack', | ||
'setUsername', | ||
'setUserProperties', | ||
'setUserPropertiesOnce', | ||
'setSuperProperties', | ||
'setSuperPropertiesOnce' | ||
]; | ||
// Cache and handler properties will match values in 'knownHandlers' as the buffering functons are installed. | ||
var cache = {}; | ||
var handlers = {}; | ||
var cache = { | ||
pageviews: [], | ||
events: [], | ||
setUsername: [], | ||
setUserProperties: [], | ||
setUserPropertiesOnce: [] | ||
// General buffering handler | ||
var bufferedHandler = function(handlerName){ | ||
return function(){ | ||
if(angulartics.waitForVendorCount){ | ||
if(!cache[handlerName]){ cache[handlerName] = []; } | ||
cache[handlerName].push(arguments); | ||
} | ||
}; | ||
}; | ||
var bufferedPageTrack = function (path) { | ||
cache.pageviews.push(path); | ||
// As handlers are installed by plugins, they get pushed into a list and invoked in order. | ||
var updateHandlers = function(handlerName, fn){ | ||
if(!handlers[handlerName]){ | ||
handlers[handlerName] = []; | ||
} | ||
handlers[handlerName].push(fn); | ||
return function(){ | ||
var handlerArgs = arguments; | ||
angular.forEach(handlers[handlerName], function(handler){ | ||
handler.apply(this, handlerArgs); | ||
}, this); | ||
}; | ||
}; | ||
var bufferedEventTrack = function (event, properties) { | ||
cache.events.push({name: event, properties: properties}); | ||
}; | ||
var bufferedSetUsername = function (name) { | ||
cache.setUsername.push(name); | ||
}; | ||
var bufferedSetUserProperties = function (properties) { | ||
cache.setUserProperties.push(properties); | ||
}; | ||
var bufferedSetUserPropertiesOnce = function (properties) { | ||
cache.setUserPropertiesOnce.push(properties); | ||
}; | ||
// The api (returned by this provider) gets populated with handlers below. | ||
var api = { | ||
settings: settings, | ||
pageTrack: bufferedPageTrack, | ||
eventTrack: bufferedEventTrack, | ||
setUsername: bufferedSetUsername, | ||
setUserProperties: bufferedSetUserProperties, | ||
setUserPropertiesOnce: bufferedSetUserPropertiesOnce | ||
settings: settings | ||
}; | ||
var registerPageTrack = function (fn) { | ||
api.pageTrack = fn; | ||
angular.forEach(cache.pageviews, function (path, index) { | ||
setTimeout(function () { api.pageTrack(path); }, index * settings.pageTracking.bufferFlushDelay); | ||
}); | ||
// Will run setTimeout if delay is > 0 | ||
// Runs immediately if no delay to make sure cache/buffer is flushed before anything else. | ||
// Plugins should take care to register handlers by order of precedence. | ||
var onTimeout = function(fn, delay){ | ||
if(delay){ | ||
setTimeout(fn, delay); | ||
} else { | ||
fn(); | ||
} | ||
}; | ||
var registerEventTrack = function (fn) { | ||
api.eventTrack = fn; | ||
angular.forEach(cache.events, function (event, index) { | ||
setTimeout(function () { api.eventTrack(event.name, event.properties); }, index * settings.eventTracking.bufferFlushDelay); | ||
}); | ||
}; | ||
var registerSetUsername = function (fn) { | ||
api.setUsername = fn; | ||
angular.forEach(cache.setUsername, function (name, index) { | ||
setTimeout(function () { api.setUsername(name); }, index * settings.pageTracking.bufferFlushDelay); | ||
}); | ||
}; | ||
var registerSetUserProperties = function (fn) { | ||
api.setUserProperties = fn; | ||
angular.forEach(cache.setUserProperties, function (properties, index) { | ||
setTimeout(function () { api.setUserProperties(properties); }, index * settings.pageTracking.bufferFlushDelay); | ||
}); | ||
}; | ||
var registerSetUserPropertiesOnce = function (fn) { | ||
api.setUserPropertiesOnce = fn; | ||
angular.forEach(cache.setUserPropertiesOnce, function (properties, index) { | ||
setTimeout(function () { api.setUserPropertiesOnce(properties); }, index * settings.pageTracking.bufferFlushDelay); | ||
}); | ||
}; | ||
return { | ||
var provider = { | ||
$get: function() { return api; }, | ||
api: api, | ||
settings: settings, | ||
@@ -112,9 +104,34 @@ virtualPageviews: function (value) { this.settings.pageTracking.autoTrackVirtualPages = value; }, | ||
withBase: function (value) { this.settings.pageTracking.basePath = (value) ? angular.element('base').attr('href').slice(0, -1) : ''; }, | ||
withAutoBase: function (value) { this.settings.pageTracking.autoBasePath = value; }, | ||
registerPageTrack: registerPageTrack, | ||
registerEventTrack: registerEventTrack, | ||
registerSetUsername: registerSetUsername, | ||
registerSetUserProperties: registerSetUserProperties, | ||
registerSetUserPropertiesOnce: registerSetUserPropertiesOnce | ||
withAutoBase: function (value) { this.settings.pageTracking.autoBasePath = value; }, | ||
}; | ||
// General function to register plugin handlers. Flushes buffers immediately upon registration according to the specified delay. | ||
var register = function(handlerName, fn){ | ||
api[handlerName] = updateHandlers(handlerName, fn); | ||
var handlerSettings = settings[handlerName]; | ||
var handlerDelay = (handlerSettings) ? handlerSettings.bufferFlushDelay : null; | ||
var delay = (handlerDelay !== null) ? handlerDelay : settings.bufferFlushDelay; | ||
angular.forEach(cache[handlerName], function (args, index) { | ||
onTimeout(function () { fn.apply(this, args); }, index * delay); | ||
}); | ||
}; | ||
var capitalize = function (input) { | ||
return input.replace(/^./, function (match) { | ||
return match.toUpperCase(); | ||
}); | ||
}; | ||
// Adds to the provider a 'register#{handlerName}' function that manages multiple plugins and buffer flushing. | ||
var installHandlerRegisterFunction = function(handlerName){ | ||
var registerName = 'register'+capitalize(handlerName); | ||
provider[registerName] = function(fn){ | ||
register(handlerName, fn); | ||
}; | ||
api[handlerName] = updateHandlers(handlerName, bufferedHandler(handlerName)); | ||
}; | ||
// Set up register functions for each known handler | ||
angular.forEach(knownHandlers, installHandlerRegisterFunction); | ||
return provider; | ||
}) | ||
@@ -176,3 +193,3 @@ | ||
.directive('analyticsOn', ['$analytics', function ($analytics) { | ||
.directive('analyticsOn', ['$analytics', '$timeout', function ($analytics, $timeout) { | ||
function isCommand(element) { | ||
@@ -194,21 +211,47 @@ return ['a:','button:','button:button','button:submit','input:button','input:submit'].indexOf( | ||
function isProperty(name) { | ||
return name.substr(0, 9) === 'analytics' && ['On', 'Event'].indexOf(name.substr(9)) === -1; | ||
return name.substr(0, 9) === 'analytics' && ['On', 'Event', 'If', 'Properties', 'EventType'].indexOf(name.substr(9)) === -1; | ||
} | ||
function propertyName(name) { | ||
var s = name.slice(9); // slice off the 'analytics' prefix | ||
if (typeof s !== 'undefined' && s!==null && s.length > 0) { | ||
return s.substring(0, 1).toLowerCase() + s.substring(1); | ||
} | ||
else { | ||
return s; | ||
} | ||
} | ||
return { | ||
restrict: 'A', | ||
scope: false, | ||
scope: true, | ||
link: function ($scope, $element, $attrs) { | ||
var eventType = $attrs.analyticsOn || inferEventType($element[0]); | ||
$scope.$analytics = {}; | ||
angular.element($element[0]).bind(eventType, function () { | ||
angular.forEach($attrs.$attr, function(attr, name) { | ||
if (isProperty(name)) { | ||
$attrs.$observe(name, function(value){ | ||
$scope.$analytics[propertyName(name)] = value; | ||
}); | ||
} | ||
}); | ||
angular.element($element[0]).bind(eventType, function ($event) { | ||
var eventName = $attrs.analyticsEvent || inferEventName($element[0]); | ||
var properties = {}; | ||
angular.forEach($attrs.$attr, function(attr, name) { | ||
if (isProperty(name)) { | ||
properties[name.slice(9).toLowerCase()] = $attrs[name]; | ||
} | ||
}); | ||
$scope.$analytics.eventType = $event.type; | ||
$analytics.eventTrack(eventName, properties); | ||
if($attrs.analyticsIf){ | ||
if(! $scope.$eval($attrs.analyticsIf)){ | ||
return; // Cancel this event if we don't pass the analytics-if condition | ||
} | ||
} | ||
// Allow components to pass through an expression that gets merged on to the event properties | ||
// eg. analytics-properites='myComponentScope.someConfigExpression.$analyticsProperties' | ||
if($attrs.analyticsProperties){ | ||
angular.extend($scope.$analytics, $scope.$eval($attrs.analyticsProperties)); | ||
} | ||
$analytics.eventTrack(eventName, $scope.$analytics); | ||
}); | ||
@@ -215,0 +258,0 @@ } |
@@ -0,1 +1,31 @@ | ||
describe('window.angulartics', function(){ | ||
beforeEach(function(){ | ||
jasmine.Clock.useMock(); | ||
}); | ||
afterEach(function(){ | ||
delete window.angularticsTestVendor; | ||
}); | ||
it('should manage vendor wait count', function(){ | ||
spy = jasmine.createSpy('vendorCallback'); | ||
spyWhenLoaded = jasmine.createSpy('vendorCallbackWhenLoaded'); | ||
angulartics.waitForVendorApi('angularticsTestVendor', 1, 'loaded', spy); | ||
angulartics.waitForVendorApi('angularticsTestVendor', 1, spyWhenLoaded); | ||
expect(window.angulartics.waitForVendorCount).toEqual(2); | ||
jasmine.Clock.tick(1); | ||
expect(window.angulartics.waitForVendorCount).toEqual(2); | ||
window.angularticsTestVendor = {}; | ||
jasmine.Clock.tick(1); | ||
expect(angulartics.waitForVendorCount).toEqual(1); | ||
window.angularticsTestVendor.loaded = true; | ||
jasmine.Clock.tick(1); | ||
expect(window.angulartics.waitForVendorCount).toEqual(0); | ||
expect(spyWhenLoaded).toHaveBeenCalledWith(window.angularticsTestVendor); | ||
}); | ||
}); | ||
describe('Module: angulartics', function() { | ||
@@ -67,2 +97,100 @@ 'use strict'; | ||
describe('$analyticsProvider', function(){ | ||
describe('registration', function(){ | ||
var expectedHandler = [ | ||
'pageTrack', | ||
'eventTrack', | ||
'setUsername', | ||
'setUserProperties', | ||
'setUserPropertiesOnce', | ||
'setSuperProperties', | ||
'setSuperPropertiesOnce' | ||
]; | ||
var capitalize = function (input) { | ||
return input.replace(/^./, function (match) { | ||
return match.toUpperCase(); | ||
}); | ||
}; | ||
var $analytics, $analyticsProvider; | ||
beforeEach(function(){ | ||
module(function(_$analyticsProvider_){ | ||
$analyticsProvider = _$analyticsProvider_; | ||
}); | ||
inject(function(_$analytics_){ | ||
$analytics = _$analytics_; | ||
}); | ||
}); | ||
angular.forEach(expectedHandler, function(handlerName){ | ||
it('should install a register function for "'+handlerName+'" on $analyticsProvider', function(){ | ||
var fn = $analyticsProvider['register'+capitalize(handlerName)]; | ||
expect(fn).toBeDefined(); | ||
expect(typeof fn).toEqual('function'); | ||
}); | ||
it('should expose a handler "'+handlerName+'" on $analytics', function(){ | ||
var fn = $analytics[handlerName]; | ||
expect(fn).toBeDefined(); | ||
expect(typeof fn).toEqual('function'); | ||
}); | ||
}); | ||
}); | ||
}); | ||
describe('$analytics', function(){ | ||
describe('buffering', function(){ | ||
var $analytics, $analyticsProvider, eventTrackSpy; | ||
beforeEach(function(){ | ||
module(function(_$analyticsProvider_){ | ||
$analyticsProvider = _$analyticsProvider_; | ||
$analyticsProvider.settings.bufferFlushDelay = 0; | ||
}); | ||
inject(function(_$analytics_){ | ||
$analytics = _$analytics_; | ||
}); | ||
}); | ||
beforeEach(function(){ | ||
eventTrackSpy = jasmine.createSpy('eventTrackSpy'); | ||
}); | ||
it('should buffer events if waiting on a vendor', function(){ | ||
angulartics.waitForVendorCount++; // Mock that we're waiting for a vendor api | ||
$analytics.eventTrack('foo'); // These events should be buffered | ||
$analytics.eventTrack('bar'); // This event should be buffered | ||
$analyticsProvider.registerEventTrack(eventTrackSpy); // This should immediately flush | ||
expect(eventTrackSpy.calls.length).toEqual(2); | ||
expect(eventTrackSpy.calls[0].args).toEqual(['foo']); | ||
expect(eventTrackSpy.calls[1].args).toEqual(['bar']); | ||
}); | ||
it('should not buffer events if not waiting on any vendors', function(){ | ||
angulartics.waitForVendorCount = 0; // Mock that we're waiting for a vendor api | ||
$analytics.eventTrack('foo'); // These events should be buffered | ||
$analyticsProvider.registerEventTrack(eventTrackSpy); // This should immediately flush | ||
expect(eventTrackSpy).not.toHaveBeenCalled(); | ||
}); | ||
it('should continue to buffer events until all vendors are resolved', function(){ | ||
angulartics.waitForVendorCount = 2; // Mock that we're waiting for a vendor api | ||
$analytics.eventTrack('foo'); // These events should be buffered | ||
$analyticsProvider.registerEventTrack(eventTrackSpy); // This should immediately flush | ||
expect(eventTrackSpy).toHaveBeenCalledWith('foo'); | ||
$analytics.eventTrack('bar'); | ||
expect(eventTrackSpy.calls.length).toEqual(2); | ||
expect(eventTrackSpy.calls[1].args).toEqual(['bar']); | ||
var secondVendor = jasmine.createSpy('secondVendor'); | ||
$analyticsProvider.registerEventTrack(secondVendor); // This should immediately flush | ||
expect(secondVendor.calls.length).toEqual(2); | ||
expect(secondVendor.calls[0].args).toEqual(['foo']); | ||
expect(secondVendor.calls[1].args).toEqual(['bar']); | ||
}); | ||
}); | ||
}); | ||
describe('Directive: analyticsOn', function () { | ||
@@ -69,0 +197,0 @@ var analytics, |
131629
1130
209