sajari-website
Version:
Website extensions for the Sajari API. Automatically index site content, add user profiles, render search and recommendations, etc.
295 lines (271 loc) • 5.77 kB
JavaScript
/*
* profile.js - Handles Sajari profile information
*/
var cookie = require("./utils/cookie");
var encoder = require("./utils/encode");
var unique = require("./utils/unique");
var enc = new encoder();
var isArray = require('sajari/src/js/utils/isArray.js');
var opts = {
cname: 'sjID',
pname: 'sjPR',
ename: 'sjPE',
sname: 'sjSE',
clicked: 'sjCL',
expires: 365, // days
maxStrings: 10, // max weighted profile strings to keep
maxURLs: 10, // maximum number of url clicks to track
weight: 0.05, // default contextual profile weight
session: false, // if true, profiles are session based and not stored beyond
domain: window.location.hostname.toLowerCase().replace(/^www(.)/, '')
};
/**
* Profile constructor
*/
function profile(options) {
options = options || {};
for (var o in options) {
this[o] = options[o];
}
if (options.data === undefined) {
this.data = {
meta: {},
weighted: []
};
}
if (this.data.meta === undefined) {
this.data.meta = {};
}
if (this.data.weighted === undefined) {
this.data.weighted = [];
}
this.gaId = getGAID();
if (this.visitorId === undefined) {
this.visitorId = cookie.get(opts.cname);
if (this.visitorId === undefined) {
this.visitorId = new Date().getTime() + '.' + Math.floor(Math.random() * 1000000);
}
}
this.sequence = getPageSequence();
this.load();
}
profile.prototype = {
/**
* Load profile meta data
*/
load: function() {
// MIGRATE OLD - REMOVE
var p = getLegacySession(opts.pname);
if (p) {
this.data.meta = p;
this.save();
}
// END MIGRATE OLD
var e;
if (opts.session) {
e = getSession(opts.ename);
if (e) {
this.data = e;
}
return;
}
e = getLocal(opts.ename);
if (e) {
this.data = e;
}
},
/**
* Save profile meta data
*/
save: function() {
if (opts.session) {
setSession(opts.ename, this.data);
return;
}
setLocal(opts.ename, this.data);
},
/**
* Set a config option post creation
*/
option: function(option, value) {
if (option && value) {
opts[option] = value;
}
},
/**
* Set profile meta data
*/
set: function(text, meta) {
if (meta) {
for (var k in meta) {
this.data.meta[k] = meta[k];
}
this.save();
}
if (text) {
this.data.weighted.push(text);
this.data.weighted = unique(this.data.weighted);
if (this.data.weighted.length > this.maxStrings) {
this.data.weighted.shift();
}
this.save();
}
},
/**
* Get profile meta data
*/
get: function() {
return this.data;
},
/**
* If a user clicks a recommended URL, we store that to not show it again in the near future
*/
addClickedUrl: function(url) {
var u = url.split("?"); // TODO: Might be a problem for sites using query params for real stuff
var arr = getSession(opts.clicked);
if (!arr) {
arr = [];
}
for (var i = 0; i < arr.length; i++) {
if (arr[i] === u[0]) {
return;
}
}
arr.push(u[0]);
if (arr.length > this.maxURLs) {
arr.shift();
}
setSession(opts.clicked, arr);
},
/**
* Get the most recent "num" clicked URL's
*/
getClickedUrls: function(num) {
var arr = getSession(opts.clicked);
if (arr) {
return arr.slice(Math.max(arr.length - num, 1));
}
return [];
},
/**
* Encode to args
*/
toArgs: function(data) {
if (data === undefined) {
data = {};
}
for (var key in this.data.meta) {
var val = this.data.meta[key];
if (isArray(val)) {
val = val.join(';');
} else if (typeof val === 'object') {
val = JSON.stringify(val);
}
data['meta[' + key + ']'] = val;
}
var n = this.data.weighted.length;
for (var i = 0; i < n; i++) {
var w = ((i + 1) / (n / 0.05)).toFixed(4);
data['q[' + w + ']'] = this.data.weighted[i];
}
data.mimetype = 'text/plain+weighted';
return data;
},
/**
* Sets a hardcoded visitor identifier
*/
setVisitorId: function(id) {
if (id !== undefined) {
this.visitorId = id + '';
cookie.set(opts.cname, this.visitorId, {
path: '/',
expires: opts.expires,
domain: opts.domain
});
}
return this.visitorId;
}
};
/**
* Returns the current visitors Google Analytics ID if it exists
*/
function getGAID() {
var userId = '';
var gaUserCookie = cookie.get("_ga");
if (gaUserCookie !== undefined) {
var cookieValues = gaUserCookie.split('.');
if (cookieValues.length > 2) {
userId = cookieValues[2];
}
}
return userId;
}
/*
* Contains the page view sequence in this session
*/
function getPageSequence() {
var s = cookie.get(opts.sname);
if (s === undefined) {
s = 0;
}
s++;
cookie.set(opts.sname, s, {
path: '/',
domain: opts.domain
});
return s;
}
/*
* Set data in local storage safely if it exists
*/
function setLocal(name, data) {
if (typeof(Storage) !== "undefined") {
var e = enc.encode(data);
localStorage.setItem(name, e);
return true;
}
}
/*
* Retrieve data in local storage safely if it exists
*/
function getLocal(name) {
if (typeof(Storage) !== "undefined") {
var d = localStorage.getItem(name);
if (d) {
return enc.decode(d);
}
}
}
/*
* Set data in session storage safely if it exists
*/
function setSession(name, data) {
if (typeof(Storage) !== "undefined") {
var e = enc.encode(data);
sessionStorage.setItem(name, e);
return true;
}
}
/*
* Retrieve data in session storage safely if it exists
*/
function getSession(name) {
if (typeof(Storage) !== "undefined") {
var d = sessionStorage.getItem(name);
if (d) {
return enc.decode(d);
}
}
}
/*
* Retrieve legacy data in session storage safely if it exists
*/
function getLegacySession(name) {
if (typeof(Storage) !== "undefined") {
var d = sessionStorage.getItem(name);
if (d) {
return JSON.parse(d);
}
}
}
module.exports = profile;