|
| 1 | +'use strict'; |
| 2 | + |
| 3 | +/** |
| 4 | + * Module dependencies. |
| 5 | + */ |
| 6 | + |
| 7 | +var Identify = require('segmentio-facade').Identify; |
| 8 | +var convert = require('@segment/convert-dates'); |
| 9 | +var integration = require('@segment/analytics.js-integration'); |
| 10 | +var push = require('global-queue')('_hsq'); |
| 11 | +var each = require('@ndhoule/each'); |
| 12 | + |
| 13 | +/** |
| 14 | + * Expose `HubSpot` integration. |
| 15 | + */ |
| 16 | + |
| 17 | +var HubSpot = module.exports = integration('HubSpot') |
| 18 | + .assumesPageview() |
| 19 | + .global('_hsq') |
| 20 | + .option('portalId', null) |
| 21 | + .tag('<script id="hs-analytics" src="https://js.hs-analytics.net/analytics/{{ cacheBuster }}/{{ portalId }}.js">'); |
| 22 | + |
| 23 | +/** |
| 24 | + * Initialize. |
| 25 | + * |
| 26 | + * @api public |
| 27 | + */ |
| 28 | + |
| 29 | +HubSpot.prototype.initialize = function() { |
| 30 | + window._hsq = []; |
| 31 | + var cacheBuster = Math.ceil(new Date() / 300000) * 300000; |
| 32 | + this.load({ cacheBuster: cacheBuster }, this.ready); |
| 33 | +}; |
| 34 | + |
| 35 | +/** |
| 36 | + * Loaded? |
| 37 | + * |
| 38 | + * @api private |
| 39 | + * @return {boolean} |
| 40 | + */ |
| 41 | + |
| 42 | +HubSpot.prototype.loaded = function() { |
| 43 | + return !!(window._hsq && window._hsq.push !== Array.prototype.push); |
| 44 | +}; |
| 45 | + |
| 46 | +/** |
| 47 | + * Page. |
| 48 | + * |
| 49 | + * @api public |
| 50 | + * @param {Page} page |
| 51 | + */ |
| 52 | + |
| 53 | +HubSpot.prototype.page = function() { |
| 54 | + push('trackPageView'); |
| 55 | +}; |
| 56 | + |
| 57 | +/** |
| 58 | + * Identify. |
| 59 | + * |
| 60 | + * @api public |
| 61 | + * @param {Identify} identify |
| 62 | + */ |
| 63 | + |
| 64 | +HubSpot.prototype.identify = function(identify) { |
| 65 | + // use newer version of Identify to have access to `companyName` |
| 66 | + var newIdentify = new Identify({ |
| 67 | + traits: identify.traits(), |
| 68 | + userId: identify.userId() |
| 69 | + }); |
| 70 | + |
| 71 | + if (!newIdentify.email()) { |
| 72 | + return; |
| 73 | + } |
| 74 | + |
| 75 | + var traits = newIdentify.traits({ firstName: 'firstname', lastName: 'lastname' }); |
| 76 | + traits = convertDates(traits); |
| 77 | + traits = formatTraits(traits); |
| 78 | + |
| 79 | + if (newIdentify.companyName() !== undefined) { |
| 80 | + traits.company = newIdentify.companyName(); |
| 81 | + } |
| 82 | + |
| 83 | + push('identify', traits); |
| 84 | +}; |
| 85 | + |
| 86 | +/** |
| 87 | + * Track. |
| 88 | + * |
| 89 | + * @api public |
| 90 | + * @param {Track} track |
| 91 | + */ |
| 92 | + |
| 93 | +HubSpot.prototype.track = function(track) { |
| 94 | + // Hubspot expects properties.id to be the name of the .track() event |
| 95 | + // Ref: http://developers.hubspot.com/docs/methods/enterprise_events/javascript_api |
| 96 | + var props = convertDates(track.properties({ id: '_id', revenue: 'value' })); |
| 97 | + props.id = track.event(); |
| 98 | + |
| 99 | + push('trackEvent', track.event(), props); |
| 100 | +}; |
| 101 | + |
| 102 | +/** |
| 103 | + * Convert all the dates in the HubSpot properties to millisecond times |
| 104 | + * |
| 105 | + * @api private |
| 106 | + * @param {Object} properties |
| 107 | + */ |
| 108 | + |
| 109 | +function convertDates(properties) { |
| 110 | + return convert(properties, function(date) { return date.getTime(); }); |
| 111 | +} |
| 112 | + |
| 113 | +/** |
| 114 | + * lowercase & snakecase any trait with uppercase letters or spaces |
| 115 | + * Hubspot cannot accept uppercases or spaces |
| 116 | + * |
| 117 | + * @api private |
| 118 | + * @param {Object} traits |
| 119 | + * @return {Object} ret |
| 120 | + */ |
| 121 | + |
| 122 | +function formatTraits(traits) { |
| 123 | + var ret = {}; |
| 124 | + each(function(value, key) { |
| 125 | + // Using split/join due to IE 11 failing to properly support regex in str.replace() |
| 126 | + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/@@replace |
| 127 | + var k = key.toLowerCase() |
| 128 | + .split(' ').join('_') // spaces |
| 129 | + .split('.').join('_') // Periods |
| 130 | + .split('\n').join('_') // new lines |
| 131 | + .split('\v').join('_') // Vertical tabs |
| 132 | + .split('\t').join('_') // Regular tabs |
| 133 | + .split('\f').join('_') // form feeds |
| 134 | + .split('\r').join('_'); // Carriage returns |
| 135 | + ret[k] = value; |
| 136 | + }, traits); |
| 137 | + |
| 138 | + return ret; |
| 139 | +} |
0 commit comments