Skip to content

Commit

Permalink
Handle cookie expiration and visit duration better
Browse files Browse the repository at this point in the history
  • Loading branch information
ankane committed Feb 27, 2018
1 parent 0085e70 commit f2d2284
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 111 deletions.
4 changes: 4 additions & 0 deletions app/controllers/ahoy/visits_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ module Ahoy
class VisitsController < BaseController
def create
ahoy.track_visit

# set proper ttl if cookie generated from JavaScript
set_ahoy_cookies if params[:js] && !Ahoy.api_only

render json: {
visit_token: ahoy.visit_token,
visitor_token: ahoy.visitor_token,
Expand Down
249 changes: 138 additions & 111 deletions vendor/assets/javascripts/ahoy.js
Original file line number Diff line number Diff line change
@@ -1,76 +1,76 @@
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["ahoy"] = factory();
else
root["ahoy"] = factory();
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["ahoy"] = factory();
else
root["ahoy"] = factory();
})(typeof self !== 'undefined' ? self : this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 0);
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
Expand All @@ -88,8 +88,20 @@ var _objectToFormdata = __webpack_require__(1);

var _objectToFormdata2 = _interopRequireDefault(_objectToFormdata);

var _cookies = __webpack_require__(2);

var _cookies2 = _interopRequireDefault(_cookies);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

/*
* Ahoy.js
* Simple, powerful JavaScript analytics
* https://github.com/ankane/ahoy.js
* v0.3.0
* MIT License
*/

var config = {
urlPrefix: "",
visitsUrl: "/ahoy/visits",
Expand All @@ -99,13 +111,7 @@ var config = {
platform: "Web",
useBeacon: true,
startOnReady: true
}; /*
* Ahoy.js
* Simple, powerful JavaScript analytics
* https://github.com/ankane/ahoy.js
* v0.3.0
* MIT License
*/
};

var ahoy = window.ahoy || window.Ahoy || {};

Expand Down Expand Up @@ -145,41 +151,16 @@ function canTrackNow() {

// cookies

// http://www.quirksmode.org/js/cookies.html
function setCookie(name, value, ttl) {
var expires = "";
var cookieDomain = "";
if (ttl) {
var date = new Date();
date.setTime(date.getTime() + ttl * 60 * 1000);
expires = "; expires=" + date.toGMTString();
}
var domain = config.cookieDomain || config.domain;
if (domain) {
cookieDomain = "; domain=" + domain;
}
document.cookie = name + "=" + escape(value) + expires + cookieDomain + "; path=/";
_cookies2.default.set(name, value, ttl, config.cookieDomain || config.domain);
}

function getCookie(name) {
var i = void 0,
c = void 0;
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for (i = 0; i < ca.length; i++) {
c = ca[i];
while (c.charAt(0) === ' ') {
c = c.substring(1, c.length);
}
if (c.indexOf(nameEQ) === 0) {
return unescape(c.substring(nameEQ.length, c.length));
}
}
return null;
return _cookies2.default.get(name);
}

function destroyCookie(name) {
setCookie(name, "", -1);
_cookies2.default.set(name, "", -1);
}

function log(message) {
Expand Down Expand Up @@ -400,7 +381,8 @@ function createVisit() {
platform: config.platform,
landing_page: window.location.href,
screen_width: window.screen.width,
screen_height: window.screen.height
screen_height: window.screen.height,
js: true
};

// referrer
Expand Down Expand Up @@ -452,31 +434,32 @@ ahoy.track = function (name, properties) {
id: generateId()
};

// wait for createVisit to log
documentReady(function () {
log(event);
});

ready(function () {
if (!ahoy.getVisitId()) {
createVisit();
}

event.visit_token = ahoy.getVisitId();
event.visitor_token = ahoy.getVisitorId();
ready(function () {
log(event);

if (canTrackNow()) {
trackEventNow(event);
} else {
eventQueue.push(event);
saveEventQueue();
event.visit_token = ahoy.getVisitId();
event.visitor_token = ahoy.getVisitorId();

// wait in case navigating to reduce duplicate events
setTimeout(function () {
trackEvent(event);
}, 1000);
}
if (canTrackNow()) {
trackEventNow(event);
} else {
eventQueue.push(event);
saveEventQueue();

// wait in case navigating to reduce duplicate events
setTimeout(function () {
trackEvent(event);
}, 1000);
}
});
});

return true;
};

ahoy.trackView = function (additionalProperties) {
Expand Down Expand Up @@ -623,6 +606,50 @@ function objectToFormData (obj, fd, pre) {
module.exports = objectToFormData


/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


Object.defineProperty(exports, "__esModule", {
value: true
});
// http://www.quirksmode.org/js/cookies.html

exports.default = {
set: function set(name, value, ttl, domain) {
var expires = "";
var cookieDomain = "";
if (ttl) {
var date = new Date();
date.setTime(date.getTime() + ttl * 60 * 1000);
expires = "; expires=" + date.toGMTString();
}
if (domain) {
cookieDomain = "; domain=" + domain;
}
document.cookie = name + "=" + escape(value) + expires + cookieDomain + "; path=/";
},
get: function get(name) {
var i = void 0,
c = void 0;
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for (i = 0; i < ca.length; i++) {
c = ca[i];
while (c.charAt(0) === ' ') {
c = c.substring(1, c.length);
}
if (c.indexOf(nameEQ) === 0) {
return unescape(c.substring(nameEQ.length, c.length));
}
}
return null;
}
};

/***/ })
/******/ ])["default"];
});
});

0 comments on commit f2d2284

Please sign in to comment.