/files//0.4.1/session.js
JavaScript | 423 lines | 370 code | 8 blank | 45 comment | 106 complexity | c171ffc03d26e00442fd54848e9edbf4 MD5 | raw file
- /**
- * session.js 0.4.1
- * (c) 2012 Iain, CodeJoust
- * session.js is freely distributable under the MIT license.
- * Portions of session.js are inspired or borrowed from Underscore.js, and quirksmode.org demo javascript.
- * This version uses google's jsapi library for location services.
- * For details, see: https://github.com/codejoust/session.js
- */
- var session_fetch = (function(win, doc, nav){
- // Changing the API Version invalidates olde cookies with previous api version tags.
- var API_VERSION = 0.4;
- // Settings: defaults
- var options = {
- // Use the HTML5 Geolocation API
- // this ONLY returns lat & long, no city/address
- use_html5_location: false,
- // Attempts to use IPInfoDB if provided a valid key
- // Get a key at http://ipinfodb.com/register.php
- ipinfodb_key: false,
- // Leaving true allows for fallback for both
- // the HTML5 location and the IPInfoDB
- gapi_location: true,
- // Name of the location cookie (set blank to disable cookie)
- // - WARNING: different providers use the same cookie
- // - if switching providers, remember to use another cookie or provide checks for old cookies
- location_cookie: "location",
- // Location cookie expiration in hours
- location_cookie_timeout: 5,
- // Session expiration in days
- session_timeout: 32,
- // Session cookie name (set blank to disable cookie)
- session_cookie: "first_session"
- };
-
- // Session object
- var SessionRunner = function(){
- win.session = win.session || {};
- // Helper for querying.
- // Usage: session.current_session.referrer_info.hostname.contains(['github.com','news.ycombinator.com'])
- win.session.contains = function(other_str){
- if (typeof(other_str) === 'string'){
- return (this.indexOf(other_str) !== -1); }
- for (var i = 0; i < other_str.length; i++){
- if (this.indexOf(other_str[i]) !== -1){ return true; } }
- return false; }
- // Merge options
- if (win.session && win.session.options) {
- for (option in win.session.options){
- options[option] = win.session.options[option]; }
- }
- // Modules to run
- // If the module has arguments,
- // it _needs_ to return a callback function.
- var unloaded_modules = {
- api_version: API_VERSION,
- locale: modules.locale(),
- current_session: modules.session(),
- original_session: modules.session(
- options.session_cookie,
- options.session_timeout * 24 * 60 * 60 * 1000),
- browser: modules.browser(),
- plugins: modules.plugins(),
- time: modules.time(),
- device: modules.device()
- };
- // Location switch
- if (options.use_html5_location){
- unloaded_modules.location = modules.html5_location();
- } else if (options.ipinfodb_key){
- unloaded_modules.location = modules.ipinfodb_location(options.ipinfodb_key);
- } else if (options.gapi_location){
- unloaded_modules.location = modules.gapi_location();
- }
- // Cache win.session.start
- if (win.session && win.session.start){
- var start = win.session.start;
- }
- // Set up checking, if all modules are ready
- var asynchs = 0, module, result,
- check_asynch = function(deinc){
- if (deinc){ asynchs--; }
- if (asynchs === 0){
- // Run start calback
- if (start){ start(win.session); }
- }
- };
- win.session = {};
- // Run asynchronous methods
- for (var name in unloaded_modules){
- module = unloaded_modules[name];
- if (typeof module === "function"){
- try {
- module(function(data){
- win.session[name] = data;
- check_asynch(true);
- });
- asynchs++;
- } catch(err){
- if (win.console && typeof(console.log) === "function"){
- console.log(err); check_asynch(true); }
- }
- } else {
- win.session[name] = module;
- } }
- check_asynch();
- };
-
-
- // Browser (and OS) detection
- var browser = {
- detect: function(){
- return {
- browser: this.search(this.data.browser),
- version: this.search(nav.userAgent) || this.search(nav.appVersion),
- os: this.search(this.data.os)
- } },
- search: function(data) {
- if (typeof data === "object"){
- // search for string match
- for(var i = 0; i < data.length; i++) {
- var dataString = data[i].string,
- dataProp = data[i].prop;
- this.version_string = data[i].versionSearch || data[i].identity;
- if (dataString){
- if (dataString.indexOf(data[i].subString) != -1){
- return data[i].identity;
- }
- } else if (dataProp){
- return data[i].identity;
- }
- }
- } else {
- // search for version number
- var index = data.indexOf(this.version_string);
- if (index == -1) return;
- return parseFloat(data.substr(index + this.version_string.length + 1));
- }
- },
- data: {
- browser: [
- { string: nav.userAgent, subString: "Chrome", identity: "Chrome" },
- { string: nav.userAgent, subString: "OmniWeb", versionSearch: "OmniWeb/", identity: "OmniWeb" },
- { string: nav.vendor, subString: "Apple", identity: "Safari", versionSearch: "Version" },
- { prop: win.opera, identity: "Opera", versionSearch: "Version" },
- { string: nav.vendor, subString: "iCab",identity: "iCab" },
- { string: nav.vendor, subString: "KDE", identity: "Konqueror" },
- { string: nav.userAgent, subString: "Firefox", identity: "Firefox" },
- { string: nav.vendor, subString: "Camino", identity: "Camino" },
- { string: nav.userAgent, subString: "Netscape", identity: "Netscape" },
- { string: nav.userAgent, subString: "MSIE", identity: "Explorer", versionSearch: "MSIE" },
- { string: nav.userAgent, subString: "Gecko", identity: "Mozilla", versionSearch: "rv" },
- { string: nav.userAgent, subString: "Mozilla", identity: "Netscape", versionSearch: "Mozilla" }
- ],
- os: [
- { string: nav.platform, subString: "Win", identity: "Windows" },
- { string: nav.platform, subString: "Mac", identity: "Mac" },
- { string: nav.userAgent, subString: "iPhone", identity: "iPhone/iPod" },
- { string: nav.userAgent, subString: "iPad", identity: "iPad" },
- { string: nav.userAgent, subString: "Android", identity: "Android" },
- { string: nav.platform, subString: "Linux", identity: "Linux" }
- ]}
- };
-
- var modules = {
- browser: function(){
- return browser.detect();
- },
- time: function(){
- // split date and grab timezone estimation.
- // timezone estimation: http://www.onlineaspect.com/2007/06/08/auto-detect-a-time-zone-with-javascript/
- var d1 = new Date(), d2 = new Date();
- d1.setMonth(0); d1.setDate(1); d2.setMonth(6); d2.setDate(1);
- return({tz_offset: -(new Date().getTimezoneOffset()) / 60, observes_dst: (d1.getTimezoneOffset() !== d2.getTimezoneOffset()) });
- // Gives a browser estimation, not guaranteed to be correct.
- },
- locale: function() {
- var lang = ((
- nav.language ||
- nav.browserLanguage ||
- nav.systemLanguage ||
- nav.userLanguage
- ) || '').split("-");
- if (lang.length == 2){
- return { country: lang[1].toLowerCase(), lang: lang[0].toLowerCase() };
- } else if (lang) {
- return {lang: lang[0].toLowerCase(), country: null };
- } else { return{lang: null, country: null }; }
- },
- device: function() {
- var device = {
- screen: {
- width: win.screen.width,
- height: win.screen.height
- }
- };
- device.viewport = {
- width: win.innerWidth || doc.documentElement.clientWidth || doc.body.clientWidth,
- height: win.innerHeight || doc.documentElement.clientHeight || doc.body.clientHeight
- };
- device.is_tablet = !!nav.userAgent.match(/(iPad|SCH-I800|xoom|kindle)/i);
- device.is_phone = !device.is_tablet && !!nav.userAgent.match(/(iPhone|iPod|blackberry|android 0.5|htc|lg|midp|mmp|mobile|nokia|opera mini|palm|pocket|psp|sgh|smartphone|symbian|treo mini|Playstation Portable|SonyEricsson|Samsung|MobileExplorer|PalmSource|Benq|Windows Phone|Windows Mobile|IEMobile|Windows CE|Nintendo Wii)/i);
- device.is_mobile = device.is_tablet || device.is_phone;
- return device;
- },
- plugins: function(){
- var check_plugin = function(name){
- if (nav.plugins){
- var plugin, i = 0, length = nav.plugins.length;
- for (; i < length; i++ ){
- plugin = nav.plugins[i];
- if (plugin && plugin.name && plugin.name.toLowerCase().indexOf(name) !== -1){
- return true;
- } }
- return false;
- } return false;
- }
- return {
- flash: check_plugin("flash"),
- silverlight: check_plugin("silverlight"),
- java: check_plugin("java"),
- quicktime: check_plugin("quicktime")
- };
- },
- session: function (cookie, expires){
- var session = util.get_obj(cookie);
- if (session == null){
- session = {
- visits: 1,
- start: new Date().getTime(), last_visit: new Date().getTime(),
- url: win.location.href, path: win.location.pathname,
- referrer: doc.referrer, referrer_info: util.parse_url(doc.referrer),
- search: { engine: null, query: null }
- };
- var search_engines = [
- { name: "Google", host: "google", query: "q" },
- { name: "Bing", host: "bing.com", query: "q" },
- { name: "Yahoo", host: "search.yahoo", query: "p" },
- { name: "AOL", host: "search.aol", query: "q" },
- { name: "Ask", host: "ask.com", query: "q" },
- { name: "Baidu", host: "baidu.com", query: "wd" }
- ], length = search_engines.length,
- engine, match, i = 0,
- fallbacks = 'q query term p wd query text'.split(' ');
- for (i = 0; i < length; i++){
- engine = search_engines[i];
- if (session.referrer_info.host.indexOf(engine.host) !== -1){
- session.search.engine = engine.name;
- session.search.query = session.referrer_info.query[engine.query];
- session.search.terms = session.search.query ? session.search.query.split(" ") : null;
- break;
- }
- }
- if (session.search.engine === null && session.referrer_info.search.length > 1){
- for (i = 0; i < fallbacks.length; i++){
- var terms = session.referrer_info.query[fallbacks[i]];
- if (terms){
- session.search.engine = "Unknown";
- session.search.query = terms; session.search.terms = terms.split(" ");
- break;
- }
- }
- }
- } else {
- session.prev_visit = session.last_visit;
- session.last_visit = new Date().getTime();
- session.visits++;
- session.time_since_last_visit = session.last_visit - session.prev_visit;
- }
- util.set_cookie(cookie, util.package_obj(session), expires);
- return session;
- },
- html5_location: function(){
- return function(callback){
- nav.geolocation.getCurrentPosition(function(pos){
- pos.source = 'html5';
- callback(pos);
- }, function(err) {
- if (options.gapi_location){
- modules.gapi_location()(callback);
- } else {
- callback({error: true, source: 'html5'}); }
- });
- };
- },
- gapi_location: function(){
- return function(callback){
- var location = util.get_obj(options.location_cookie);
- if (!location || location.source !== 'google'){
- win.gloader_ready = function() {
- if ("google" in win){
- if (win.google.loader.ClientLocation){
- win.google.loader.ClientLocation.source = "google";
- callback(win.google.loader.ClientLocation);
- } else {
- callback({error: true, source: "google"});
- }
- util.set_cookie(
- options.location_cookie,
- util.package_obj(win.google.loader.ClientLocation),
- options.location_cookie_timeout * 60 * 60 * 1000);
- }}
- util.embed_script("https://www.google.com/jsapi?callback=gloader_ready");
- } else {
- callback(location);
- }}
- },
- ipinfodb_location: function(api_key){
- return function (callback){
- var location_cookie = util.get_obj(options.location_cookie);
- if (location_cookie && location_cookie.source === 'ipinfodb'){ callback(location_cookie); }
- win.ipinfocb = function(data){
- if (data.statusCode === "OK"){
- data.source = "ipinfodb";
- util.set_cookie(
- options.location_cookie,
- util.package_obj(data),
- options.location_cookie * 60 * 60 * 1000);
- callback(data);
- } else {
- if (options.gapi_location){ return modules.gapi_location()(callback); }
- else { callback({error: true, source: "ipinfodb", message: data.statusMessage}); }
- }}
- util.embed_script("http://api.ipinfodb.com/v3/ip-city/?key=" + api_key + "&format=json&callback=ipinfocb");
- }}
- };
-
- // Utilities
- var util = {
- parse_url: function(url_str){
- var a = doc.createElement("a"), query = {};
- a.href = url_str; query_str = a.search.substr(1);
- // Disassemble query string
- if (query_str != ''){
- var pairs = query_str.split("&"), i = 0,
- length = pairs.length, parts;
- for (; i < length; i++){
- parts = pairs[i].split("=");
- if (parts.length === 2){
- query[parts[0]] = decodeURI(parts[1]); }
- }
- }
- return {
- host: a.host,
- path: a.pathname,
- protocol: a.protocol,
- port: a.port === '' ? 80 : a.port,
- search: a.search,
- query: query }
- },
- set_cookie: function(cname, value, expires, options){ // from jquery.cookie.js
- if (!cname){ return null; }
- if (!options){ var options = {}; }
- if (value === null || value === undefined){ expires = -1; }
- if (expires){ options.expires = (new Date().getTime()) + expires; }
- return (doc.cookie = [
- encodeURIComponent(cname), '=',
- encodeURIComponent(String(value)),
- options.expires ? '; expires=' + new Date(options.expires).toUTCString() : '', // use expires attribute, max-age is not supported by IE
- '; path=' + (options.path ? options.path : '/'),
- options.domain ? '; domain=' + options.domain : '',
- (win.location && win.location.protocol === 'https:') ? '; secure' : ''
- ].join(''));
- },
- get_cookie: function(cookie_name, result){ // from jquery.cookie.js
- return (result = new RegExp('(?:^|; )' + encodeURIComponent(cookie_name) + '=([^;]*)').exec(doc.cookie)) ? decodeURIComponent(result[1]) : null;
- },
- embed_script: function(url){
- var element = doc.createElement("script");
- element.type = "text/javascript";
- element.src = url;
- doc.getElementsByTagName("body")[0].appendChild(element);
- },
- package_obj: function (obj){
- if(obj) {
- obj.version = API_VERSION;
- var ret = JSON.stringify(obj);
- delete obj.version;
- return ret;
- }
- },
- get_obj: function(cookie_name){
- var obj;
- try { obj = JSON.parse(util.get_cookie(cookie_name)); } catch(e){};
- if (obj && obj.version == API_VERSION){
- delete obj.version; return obj;
- }
- }
- };
-
- // JSON
- var JSON = {
- parse: (win.JSON && win.JSON.parse) || function(data){
- if (typeof data !== "string" || !data){ return null; }
- return (new Function("return " + data))();
- },
- stringify: (win.JSON && win.JSON.stringify) || function(object){
- var type = typeof object;
- if (type !== "object" || object === null) {
- if (type === "string"){ return '"' + object + '"'; }
- } else {
- var k, v, json = [],
- isArray = (object && object.constructor === Array);
- for (k in object ) {
- v = object[k]; type = typeof v;
- if (type === "string")
- v = '"' + v + '"';
- else if (type === "object" && v !== null)
- v = this.stringify(v);
- json.push((isArray ? "" : '"' + k + '":') + v);
- }
- return (isArray ? "[" : "{") + json.join(",") + (isArray ? "]" : "}");
- } } };
-
- // Initialize SessionRunner
- SessionRunner();
-
- });
- // Switch for testing purposes.
- if (typeof(window.exports) === 'undefined'){
- session_fetch(window, document, navigator);
- } else {
- window.exports.session = session_fetch;
- }