PageRenderTime 50ms CodeModel.GetById 10ms app.highlight 33ms RepoModel.GetById 1ms app.codeStats 1ms

/shared/assets/frontend/js/analytics-src/analytics.utils.js

https://github.com/deltafactory/landing-pages
JavaScript | 657 lines | 480 code | 47 blank | 130 comment | 109 complexity | f6db6b5cb9b0d29bd61668042ac5c9c9 MD5 | raw file
  1/**
  2 * # _inbound UTILS
  3 *
  4 * This file contains all of the utility functions used by analytics
  5 *
  6 * @author David Wells <david@inboundnow.com>
  7 * @version 0.0.1
  8 */
  9var _inboundUtils = (function(_inbound) {
 10
 11    var storageSupported;
 12
 13    _inbound.Utils = {
 14        init: function() {
 15
 16            this.polyFills();
 17            this.checkLocalStorage();
 18            this.SetUID();
 19            this.storeReferralData();
 20
 21        },
 22        /*! http://stackoverflow.com/questions/951791/javascript-global-error-handling */
 23        /* Polyfills for missing browser functionality */
 24        polyFills: function() {
 25            /* Console.log fix for old browsers */
 26            if (!window.console) {
 27                window.console = {};
 28            }
 29            var m = [
 30                "log", "info", "warn", "error", "debug", "trace", "dir", "group",
 31                "groupCollapsed", "groupEnd", "time", "timeEnd", "profile", "profileEnd",
 32                "dirxml", "assert", "count", "markTimeline", "timeStamp", "clear"
 33            ];
 34            // define undefined methods as noops to prevent errors
 35            for (var i = 0; i < m.length; i++) {
 36                if (!window.console[m[i]]) {
 37                    window.console[m[i]] = function() {};
 38                }
 39            }
 40            /* Event trigger polyfill for IE9 and 10
 41            (function() {
 42                function CustomEvent(event, params) {
 43                    params = params || {
 44                        bubbles: false,
 45                        cancelable: false,
 46                        detail: undefined
 47                    };
 48                    var evt = document.createEvent('CustomEvent');
 49                    evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
 50                    return evt;
 51                }
 52
 53                CustomEvent.prototype = window.Event.prototype;
 54
 55                window.CustomEvent = CustomEvent;
 56            })();*/
 57            /* custom event for ie8+ https://gist.github.com/WebReflection/6693661 */
 58            try{new CustomEvent('?');}catch(o_O){
 59              /*!(C) Andrea Giammarchi -- WTFPL License*/
 60              this.CustomEvent = function(
 61                eventName,
 62                defaultInitDict
 63              ){
 64
 65                // the infamous substitute
 66                function CustomEvent(type, eventInitDict) {
 67                  var event = document.createEvent(eventName);
 68                  if (type !== null) {
 69                    initCustomEvent.call(
 70                      event,
 71                      type,
 72                      (eventInitDict || (
 73                        // if falsy we can just use defaults
 74                        eventInitDict = defaultInitDict
 75                      )).bubbles,
 76                      eventInitDict.cancelable,
 77                      eventInitDict.detail
 78                    );
 79                  } else {
 80                    // no need to put the expando property otherwise
 81                    // since an event cannot be initialized twice
 82                    // previous case is the most common one anyway
 83                    // but if we end up here ... there it goes
 84                    event.initCustomEvent = initCustomEvent;
 85                  }
 86                  return event;
 87                }
 88
 89                // borrowed or attached at runtime
 90                function initCustomEvent(
 91                  type, bubbles, cancelable, detail
 92                ) {
 93                  this['init' + eventName](type, bubbles, cancelable, detail);
 94                  'detail' in this || (this.detail = detail);
 95                }
 96
 97                // that's it
 98                return CustomEvent;
 99              }(
100                // is this IE9 or IE10 ?
101                // where CustomEvent is there
102                // but not usable as construtor ?
103                this.CustomEvent ?
104                  // use the CustomEvent interface in such case
105                  'CustomEvent' : 'Event',
106                  // otherwise the common compatible one
107                {
108                  bubbles: false,
109                  cancelable: false,
110                  detail: null
111                }
112              );
113            }
114            /* querySelectorAll polyfill for ie7+ */
115            if (!document.querySelectorAll) {
116              document.querySelectorAll = function (selectors) {
117                var style = document.createElement('style'), elements = [], element;
118                document.documentElement.firstChild.appendChild(style);
119                document._qsa = [];
120
121                style.styleSheet.cssText = selectors + '{x-qsa:expression(document._qsa && document._qsa.push(this))}';
122                window.scrollBy(0, 0);
123                style.parentNode.removeChild(style);
124
125                while (document._qsa.length) {
126                  element = document._qsa.shift();
127                  element.style.removeAttribute('x-qsa');
128                  elements.push(element);
129                }
130                document._qsa = null;
131                return elements;
132              };
133            }
134
135            if (!document.querySelector) {
136              document.querySelector = function (selectors) {
137                var elements = document.querySelectorAll(selectors);
138                return (elements.length) ? elements[0] : null;
139              };
140            }
141            /* Innertext shim for firefox https://github.com/duckinator/innerText-polyfill/blob/master/innertext.js */
142            if ( (!('innerText' in document.createElement('a'))) && ('getSelection' in window) ) {
143                HTMLElement.prototype.__defineGetter__("innerText", function() {
144                    var selection = window.getSelection(),
145                        ranges    = [],
146                        str;
147
148                    // Save existing selections.
149                    for (var i = 0; i < selection.rangeCount; i++) {
150                        ranges[i] = selection.getRangeAt(i);
151                    }
152
153                    // Deselect everything.
154                    selection.removeAllRanges();
155
156                    // Select `el` and all child nodes.
157                    // 'this' is the element .innerText got called on
158                    selection.selectAllChildren(this);
159
160                    // Get the string representation of the selected nodes.
161                    str = selection.toString();
162
163                    // Deselect everything. Again.
164                    selection.removeAllRanges();
165
166                    // Restore all formerly existing selections.
167                    for (var i = 0; i < ranges.length; i++) {
168                        selection.addRange(ranges[i]);
169                    }
170
171                    // Oh look, this is what we wanted.
172                    // String representation of the element, close to as rendered.
173                    return str;
174                })
175            }
176        },
177        /**
178         * Create cookie
179         *
180         * ```js
181         * // Creates cookie for 10 days
182         * _inbound.utils.createCookie( 'cookie_name', 'value', 10 );
183         * ```
184         *
185         * @param  {string} name        Name of cookie
186         * @param  {string} value       Value of cookie
187         * @param  {string} days        Length of storage
188         */
189        createCookie: function(name, value, days) {
190            var expires = "";
191            if (days) {
192                var date = new Date();
193                date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
194                expires = "; expires=" + date.toGMTString();
195            }
196            document.cookie = name + "=" + value + expires + "; path=/";
197        },
198        /**
199         * Read cookie value
200         *
201         * ```js
202         * var cookie = _inbound.utils.readCookie( 'cookie_name' );
203         * console.log(cookie); // cookie value
204         * ```
205         * @param  {string} name name of cookie
206         * @return {string}      value of cookie
207         */
208        readCookie: function(name) {
209            var nameEQ = name + "=";
210            var ca = document.cookie.split(';');
211            for (var i = 0; i < ca.length; i++) {
212                var c = ca[i];
213                while (c.charAt(0) === ' ') {
214                    c = c.substring(1, c.length);
215                }
216                if (c.indexOf(nameEQ) === 0) {
217                    return c.substring(nameEQ.length, c.length);
218                }
219            }
220            return null;
221        },
222        /**
223         * Erase cookie
224         *
225         * ```js
226         * // usage:
227         * _inbound.utils.eraseCookie( 'cookie_name' );
228         * // deletes 'cookie_name' value
229         * ```
230         * @param  {string} name name of cookie
231         * @return {string}      value of cookie
232         */
233        eraseCookie: function(name) {
234            this.createCookie(name, "", -1);
235        },
236        /* Get All Cookies */
237        getAllCookies: function() {
238            var cookies = {};
239            if (document.cookie && document.cookie !== '') {
240                var split = document.cookie.split(';');
241                for (var i = 0; i < split.length; i++) {
242                    var name_value = split[i].split("=");
243                    name_value[0] = name_value[0].replace(/^ /, '');
244                    cookies[decodeURIComponent(name_value[0])] = decodeURIComponent(name_value[1]);
245                }
246            }
247            _inbound.totalStorage('inbound_cookies', cookies); // store cookie data
248            return cookies;
249        },
250        /* Grab URL params and save */
251        setUrlParams: function() {
252            var urlParams = {};
253
254            (function() {
255                var e,
256                    d = function(s) {
257                        return decodeURIComponent(s).replace(/\+/g, " ");
258                    },
259                    q = window.location.search.substring(1),
260                    r = /([^&=]+)=?([^&]*)/g;
261
262                while (e = r.exec(q)) {
263                    if (e[1].indexOf("[") == "-1")
264                        urlParams[d(e[1])] = d(e[2]);
265                    else {
266                        var b1 = e[1].indexOf("["),
267                            aN = e[1].slice(b1 + 1, e[1].indexOf("]", b1)),
268                            pN = d(e[1].slice(0, b1));
269
270                        if (typeof urlParams[pN] != "object")
271                            urlParams[d(pN)] = {},
272                            urlParams[d(pN)].length = 0;
273
274                        if (aN)
275                            urlParams[d(pN)][d(aN)] = d(e[2]);
276                        else
277                            Array.prototype.push.call(urlParams[d(pN)], d(e[2]));
278
279                    }
280                }
281            })();
282
283            /* Set Param Cookies */
284            for (var k in urlParams) {
285                if (typeof urlParams[k] == "object") {
286                    for (var k2 in urlParams[k])
287                        this.createCookie(k2, urlParams[k][k2], 30);
288                } else {
289                    this.createCookie(k, urlParams[k], 30);
290                }
291            }
292            /* Set Param LocalStorage */
293            if (storageSupported) {
294                var pastParams = _inbound.totalStorage('inbound_url_params') || {};
295                var params = this.mergeObjs(pastParams, urlParams);
296                _inbound.totalStorage('inbound_url_params', params); // store cookie data
297            }
298
299            var options = {'option1': 'yo', 'option2': 'woooo'};
300
301            _inbound.trigger('url_parameters', urlParams, options);
302
303        },
304        getAllUrlParams: function() {
305            var get_params = {};
306            if (storageSupported) {
307                var get_params = _inbound.totalStorage('inbound_url_params');
308            }
309            return get_params;
310        },
311        /* Get url param */
312        getParameterVal: function(name, string) {
313            return (RegExp(name + '=' + '(.+?)(&|$)').exec(string)||[,false])[1];
314        },
315        // Check local storage
316        // provate browsing safari fix https://github.com/marcuswestin/store.js/issues/42#issuecomment-25274685
317        checkLocalStorage: function() {
318            if ('localStorage' in window) {
319                try {
320                    ls = (typeof window.localStorage === 'undefined') ? undefined : window.localStorage;
321                    if (typeof ls == 'undefined' || typeof window.JSON == 'undefined') {
322                        storageSupported = false;
323                    } else {
324                        storageSupported = true;
325                    }
326
327                } catch (err) {
328                    storageSupported = false;
329                }
330            }
331            return storageSupported;
332            /* http://spin.atomicobject.com/2013/01/23/ios-private-browsing-localstorage/
333            var hasStorage;
334            hasStorage = function() {
335              var mod, result;
336              try {
337                mod = new Date;
338                localStorage.setItem(mod, mod.toString());
339                result = localStorage.getItem(mod) === mod.toString();
340                localStorage.removeItem(mod);
341                return result;
342              } catch (_error) {}
343            };
344             */
345        },
346        /* Add days to datetime */
347        addDays: function(myDate, days) {
348            return new Date(myDate.getTime() + days * 24 * 60 * 60 * 1000);
349        },
350        GetDate: function() {
351            var time_now = new Date(),
352                day = time_now.getDate() + 1;
353            year = time_now.getFullYear(),
354                hour = time_now.getHours(),
355                minutes = time_now.getMinutes(),
356                seconds = time_now.getSeconds(),
357                month = time_now.getMonth() + 1;
358            if (month < 10) {
359                month = '0' + month;
360            }
361            _inbound.debug('Current Date:', function() {
362                console.log(year + '/' + month + "/" + day + " " + hour + ":" + minutes + ":" + seconds);
363            });
364            var datetime = year + '/' + month + "/" + day + " " + hour + ":" + minutes + ":" + seconds;
365            return datetime;
366        },
367        /* Set Expiration Date of Session Logging. LEGACY Not in Use */
368        SetSessionTimeout: function() {
369            var session = this.readCookie("lead_session_expire");
370            //console.log(session_check);
371            if (!session) {
372                //_inbound.trigger('session_start'); // trigger 'inbound_analytics_session_start'
373            } else {
374                //_inbound.trigger('session_resume'); // trigger 'inbound_analytics_session_active'
375            }
376            var d = new Date();
377            d.setTime(d.getTime() + 30 * 60 * 1000);
378
379            this.createCookie("lead_session_expire", true, d, true); // Set cookie on page load
380
381        },
382        storeReferralData: function() {
383            //console.log(expire_time);
384            var d = new Date(),
385            referrer = document.referrer || "Direct Traffic",
386            referrer_cookie = _inbound.Utils.readCookie("inbound_referral_site"),
387            original_src = _inbound.totalStorage('inbound_original_referral');
388
389            d.setTime(d.getTime() + 30 * 60 * 1000);
390
391            if (!referrer_cookie) {
392                this.createCookie("inbound_referral_site", referrer, d, true);
393            }
394            if (!original_src) {
395                _inbound.totalStorage('inbound_original_referral', original_src);
396            }
397        },
398        CreateUID: function(length) {
399            var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz'.split(''),
400                str = '';
401            if (!length) {
402                length = Math.floor(Math.random() * chars.length);
403            }
404            for (var i = 0; i < length; i++) {
405                str += chars[Math.floor(Math.random() * chars.length)];
406            }
407            return str;
408        },
409        SetUID: function(leadUID) {
410            /* Set Lead UID */
411            if (!this.readCookie("wp_lead_uid")) {
412                var wp_lead_uid = leadUID || this.CreateUID(35);
413                this.createCookie("wp_lead_uid", wp_lead_uid);
414            }
415        },
416        /* Count number of session visits */
417        countProperties: function(obj) {
418            var count = 0;
419            for (var prop in obj) {
420                if (obj.hasOwnProperty(prop))
421                    ++count;
422            }
423            return count;
424        },
425        mergeObjs: function(obj1, obj2) {
426            var obj3 = {};
427            for (var attrname in obj1) {
428                obj3[attrname] = obj1[attrname];
429            }
430            for (var attrname in obj2) {
431                obj3[attrname] = obj2[attrname];
432            }
433            return obj3;
434        },
435        hasClass: function(className, el) {
436            var hasClass = false;
437            if ('classList' in document.documentElement) {
438                var hasClass = el.classList.contains(className);
439            } else {
440                var hasClass = new RegExp('(^|\\s)' + className + '(\\s|$)').test(el.className); /* IE Polyfill */
441            }
442            return hasClass;
443        },
444        addClass: function(className, elem) {
445            if ('classList' in document.documentElement) {
446                elem.classList.add(className);
447            } else {
448                if (!this.hasClass(elem, className)) {
449                    elem.className += (elem.className ? ' ' : '') + className;
450                }
451            }
452        },
453        removeClass: function(className, elem) {
454            if ('classList' in document.documentElement) {
455
456                elem.classList.remove(className);
457            } else {
458                if (this.hasClass(elem, className)) {
459                    elem.className = elem.className.replace(new RegExp('(^|\\s)*' + className + '(\\s|$)*', 'g'), '');
460                }
461            }
462        },
463        trim: function(s) {
464            s = s.replace(/(^\s*)|(\s*$)/gi, "");
465            s = s.replace(/[ ]{2,}/gi, " ");
466            s = s.replace(/\n /, "\n");
467            return s;
468        },
469        ajaxPolyFill: function() {
470            if (typeof XMLHttpRequest !== 'undefined') {
471                return new XMLHttpRequest();
472            }
473            var versions = [
474                "MSXML2.XmlHttp.5.0",
475                "MSXML2.XmlHttp.4.0",
476                "MSXML2.XmlHttp.3.0",
477                "MSXML2.XmlHttp.2.0",
478                "Microsoft.XmlHttp"
479            ];
480
481            var xhr;
482            for (var i = 0; i < versions.length; i++) {
483                try {
484                    xhr = new ActiveXObject(versions[i]);
485                    break;
486                } catch (e) {}
487            }
488            return xhr;
489        },
490        ajaxSendData: function(url, callback, method, data, sync) {
491            var x = this.ajaxPolyFill();
492            x.open(method, url, sync);
493            x.onreadystatechange = function() {
494                if (x.readyState == 4) {
495                    callback(x.responseText)
496                }
497            };
498            if (method == 'POST') {
499                x.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
500            }
501            x.send(data);
502        },
503        ajaxGet: function(url, data, callback, sync) {
504            var query = [];
505            for (var key in data) {
506                query.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key]));
507            }
508            this.ajaxSendData(url + '?' + query.join('&'), callback, 'GET', null, sync)
509        },
510        ajaxPost: function(url, data, callback, sync) {
511            var query = [];
512            for (var key in data) {
513                query.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key]));
514            }
515            this.ajaxSendData(url, callback, 'POST', query.join('&'), sync)
516        },
517        makeRequest: function(url, data) {
518            if (window.XMLHttpRequest) { // Mozilla, Safari, ...
519                httpRequest = new XMLHttpRequest();
520            } else if (window.ActiveXObject) { // IE
521                try {
522                    httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
523                } catch (e) {
524                    try {
525                        httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
526                    } catch (e) {}
527                }
528            }
529
530            if (!httpRequest) {
531                alert('Giving up :( Cannot create an XMLHTTP instance');
532                return false;
533            }
534            httpRequest.onreadystatechange = _inbound.LeadsAPI.alertContents;
535            httpRequest.open('GET', url);
536            httpRequest.send(data);
537        },
538        domReady: function(win, fn) {
539
540            var done = false,
541                top = true,
542
543                doc = win.document,
544                root = doc.documentElement,
545
546                add = doc.addEventListener ? 'addEventListener' : 'attachEvent',
547                rem = doc.addEventListener ? 'removeEventListener' : 'detachEvent',
548                pre = doc.addEventListener ? '' : 'on',
549
550                init = function(e) {
551                    if (e.type == 'readystatechange' && doc.readyState != 'complete') return;
552                    (e.type == 'load' ? win : doc)[rem](pre + e.type, init, false);
553                    if (!done && (done = true)) fn.call(win, e.type || e);
554                },
555
556                poll = function() {
557                    try {
558                        root.doScroll('left');
559                    } catch (e) {
560                        setTimeout(poll, 50);
561                        return;
562                    }
563                    init('poll');
564                };
565
566            if (doc.readyState == 'complete') fn.call(win, 'lazy');
567            else {
568                if (doc.createEventObject && root.doScroll) {
569                    try {
570                        top = !win.frameElement;
571                    } catch (e) {}
572                    if (top) poll();
573                }
574                doc[add](pre + 'DOMContentLoaded', init, false);
575                doc[add](pre + 'readystatechange', init, false);
576                win[add](pre + 'load', init, false);
577            }
578
579        },
580        /* Cross-browser event listening  */
581        addListener: function(element, eventName, listener) {
582            //console.log(eventName);
583            //console.log(listener);
584            if (element.addEventListener) {
585                element.addEventListener(eventName, listener, false);
586            } else if (element.attachEvent) {
587                element.attachEvent("on" + eventName, listener);
588            } else {
589                element['on' + eventName] = listener;
590            }
591        },
592        removeListener: function(element, eventName, listener) {
593
594            if (element.removeEventListener) {
595                element.removeEventListener(eventName, listener, false);
596            } else if (element.detachEvent) {
597                element.detachEvent("on" + eventName, listener);
598            } else {
599                element["on" + eventName] = null;
600            }
601        },
602        /*
603         * Throttle function borrowed from:
604         * Underscore.js 1.5.2
605         * http://underscorejs.org
606         * (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
607         * Underscore may be freely distributed under the MIT license.
608         */
609        throttle: function (func, wait) {
610          var context, args, result;
611          var timeout = null;
612          var previous = 0;
613          var later = function() {
614            previous = new Date;
615            timeout = null;
616            result = func.apply(context, args);
617          };
618          return function() {
619            var now = new Date;
620            if (!previous) previous = now;
621            var remaining = wait - (now - previous);
622            context = this;
623            args = arguments;
624            if (remaining <= 0) {
625              clearTimeout(timeout);
626              timeout = null;
627              previous = now;
628              result = func.apply(context, args);
629            } else if (!timeout) {
630              timeout = setTimeout(later, remaining);
631            }
632            return result;
633          };
634        },
635        /*
636         * Determine which version of GA is being used
637         * "ga", "_gaq", and "dataLayer" are the possible globals
638         */
639        checkTypeofGA: function() {
640          if (typeof ga === "function") {
641            universalGA = true;
642          }
643
644          if (typeof _gaq !== "undefined" && typeof _gaq.push === "function") {
645            classicGA = true;
646          }
647
648          if (typeof dataLayer !== "undefined" && typeof dataLayer.push === "function") {
649            googleTagManager = true;
650          }
651
652        }
653    };
654
655    return _inbound;
656
657})(_inbound || {});