diff --git a/README.md b/README.md
deleted file mode 100644
index 2ce477a..0000000
--- a/README.md
+++ /dev/null
@@ -1,80 +0,0 @@
-Session.js
-==
-
-Gives information about the current session.
-
-To use: include the file session.js, then access the visitor object.
-It uses the google javascript loader to get location data.
-For async loading, use the window.session_loaded callback.
-
-To add more fields, add or remove included modules and options near the bottom of the js file.
-
-
-API demo dump of `window.session`:
-
- {
- "api_version": 0.2,
- "locale": {
- "country": "US",
- "lang": "en"
- },
- "cur_session": {
- "visits": 1,
- "search": {
- "engine": null,
- "query": null
- },
- "referrer": "",
- "url": "http://localhost:8000/demo.html",
- "path": "/demo.html",
- "start": 1325893718929,
- "last_visit": 1325893718929
- },
- "orig_session": {
- "visits": 20,
- "search": {
- "engine": null,
- "query": null
- },
- "referrer": "http://localhost:8000/",
- "url": "http://localhost:8000/test_visitor.html",
- "path": "/test_visitor.html",
- "start": 1325886709703,
- "last_visit": 1325893718932
- },
- "browser": {
- "browser": "Chrome",
- "version": 16,
- "OS": "Mac"
- },
- "plugins": {
- "flash": true,
- "silverlight": true,
- "java": true,
- "quicktime": true
- },
- "device": {
- "screen": {
- "width": 1280,
- "height": 1024
- },
- "viewport": {
- "width": 1206,
- "height": 816
- },
- "is_phone": false,
- "is_tablet": false,
- "is_mobile": false
- },
- "location": {
- "latitude": 35.046,
- "longitude": -85.31,
- "address": {
- "city": "Chattanooga",
- "region": "TN",
- "country": "USA",
- "country_code": "US"
- }
- }
- }
-
diff --git a/demo.html b/demo.html
deleted file mode 100644
index 9f484c7..0000000
--- a/demo.html
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
- Session.js demo
- Demo output:
-
-
-
-
-
-
-
diff --git a/example.html b/example.html
new file mode 100644
index 0000000..ed51501
--- /dev/null
+++ b/example.html
@@ -0,0 +1,61 @@
+
+
+
+
+ Session.js example usage
+
+
+Session.js Example Usage:
+Info:
+loading motd...
+
+ View Example Source
+
+
+
About
+
Session.js is a javascript library that lets you customize your page according to the current session.
+
Such an example would be autosuggesting location box values, or timezones, based on either location or system settings returned by javascript.
+
For more information, check out the github project page or the API demo.
+
+
+
+
+
+
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..d7f1118
--- /dev/null
+++ b/index.html
@@ -0,0 +1,153 @@
+
+
+ Demo for Session.js
+
+
+
+
+ Session.js Demo Page
+ Demo output:
+
+ loading...
+
+
+ Session.JS on GitHub by Iain
+
+
+
+
diff --git a/ipinfodb_demo.html b/ipinfodb_demo.html
new file mode 100644
index 0000000..1e05175
--- /dev/null
+++ b/ipinfodb_demo.html
@@ -0,0 +1,162 @@
+
+
+ Demo for Session.js
+
+
+
+
+ Session.js Demo Page
+ Using ipinfodb for location lookup
+ Demo output:
+
+ loading...
+
+
+ Session.JS on GitHub by Iain
+
+
+
+
+
diff --git a/pack.sh b/pack.sh
deleted file mode 100755
index e43c0ce..0000000
--- a/pack.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh
-echo 'Packing session.js to session.min.js'
-uglifyjs session.js > session.min.js
diff --git a/session-0.4.js b/session-0.4.js
new file mode 100644
index 0000000..b618452
--- /dev/null
+++ b/session-0.4.js
@@ -0,0 +1,414 @@
+/**
+ * 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
+ */
+(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(){
+ // Helper for querying.
+ // Usage: session.current_session.referrer_info.hostname.contains(['github.com','news.ycombinator.com'])
+ String.prototype.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(){
+ 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;
+ asynchs--;
+ check_asynch();
+ });
+ asynchs++;
+ } catch(err){
+ if (win.console && typeof(console.log) === "function"){
+ console.log(err); }
+ }
+ } 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", identitiy: "iPad" },
+ { string: nav.platform, subString: "Linux", identity: "Linux" },
+ { string: nav.userAgent, subString: "Android", identity: "Android" }
+ ]}
+ };
+
+ 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: screen.width,
+ height: screen.height
+ }
+ };
+ var html = doc.documentElement,
+ body = doc.getElementsByTagName("body")[0];
+ 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.isTablet && !!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.last_visit = new Date().getTime();
+ session.visits++;
+ }
+ 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 (!doc.cookie || !cname || !value){ return null; }
+ if (!options){ var options = {}; }
+ if (value === null || value === undefined){ expires = -1; }
+ if (expires){ options.expires = (new Date().getTime()) + expires; }
+ return (document.cookie = [
+ encodeURIComponent(cname), '=',
+ encodeURIComponent(String(value)),
+ options.expires ? '; expires=' + new Date(options.expires).toUTCString() : '', // use expires attribute, max-age is not supported by IE
+ options.path ? '; 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(document.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){
+ 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();
+
+})(window, document, navigator);
diff --git a/session-0.4.min.js b/session-0.4.min.js
new file mode 100644
index 0000000..089cee5
--- /dev/null
+++ b/session-0.4.min.js
@@ -0,0 +1,8 @@
+/**
+ * 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
+ */(function(e,t,n){var r=.4,i={use_html5_location:!1,ipinfodb_key:!1,gapi_location:!0,location_cookie:"location",location_cookie_timeout:5,session_timeout:32,session_cookie:"first_session"},s=function(){String.prototype.contains=function(e){if(typeof e=="string")return this.indexOf(e)!==-1;for(var t=0;t1)for(l=0;l 0 ) {
- c_start=document.cookie.indexOf(c_name + "=");
- if (c_start != -1){
- c_start=c_start + c_name.length+1;
- c_end=document.cookie.indexOf(";",c_start);
- if (c_end == -1) {
- c_end=document.cookie.length;
- } return unescape(document.cookie.substring(c_start,c_end));
- } } return null; },
- each: function(obj, iterator, context) { // from underscore.js
- if (obj == null) return;
- if (obj.length === +obj.length) {
- for (var i = 0, l = obj.length; i < l; i++) {
- if (i in obj && iterator.call(context, obj[i], i, obj) === {}) return;
+ };
+ 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 {
- for (var key in obj) {
- if (hasOwnProperty.call(obj, key)) {
- if (iterator.call(context, obj[key], key, obj) === {}) return;
+ win.session[name] = module;
+ } }
+ check_asynch();
+ };
+
+
+ // Browser (and OS) detection
+ var browser = {
+ detect: function(){
+ var ret = {
+ browser: this.search(this.data.browser),
+ version: this.search(nav.userAgent) || this.search(nav.appVersion),
+ os: this.search(this.data.os)
+ };
+ if (ret.os=='Linux'){
+ var distros = ['CentOS','Debian','Fedora','Gentoo','Mandriva','Mageia','Red Hat','Slackware','SUSE','Turbolinux','Ubuntu'];
+ for (var i = 0; i < distros.length;i++){
+ if (nav.useragent.toLowerCase().match(distros[i].toLowerCase())){
+ ret.distro = distros[i];
+ break;
}
}
}
- },
- any: function(obj, iterator, context) {
- iterator || (iterator = _.identity);
- var result = false;
- if (obj == null) return result;
- utils.each(obj, function(value, index, list) {
- if (result || (result = iterator.call(context, value, index, list))) return {};
- });
- return !!result;
- },
- search: function(obj, iterator, context) {
- var result;
- utils.any(obj, function(value, index, list) {
- result = iterator.call(context, value, index, list);
- if (result){ return true; }
- });
- return result;
- },
- find: function(obj, iterator, context) {
- var result;
- utils.any(obj, function(value, index, list) {
- if (iterator.call(context, value, index, list)) {
- result = value;
- return true;
- }
- });
- return result;
- },
- is_undef: function(obj){ return obj === void 0; }, // from underscore.js
- try_obj: function(tries, obj){
- for (var i = 0; i < tries.length; i++){
- obj_try = obj[tries[i]];
- if (!utils.is_undef(obj_try) && obj_try != null && obj_try != ''){
- return obj_try;
+ return ret;
+ },
+ 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));
}
- return null;
},
- try_props: function(props){
- for(var i = 0; i < props.length; i++){
- if (!utils.is_undef(props[i]) && props[i] != null && props[i] != ''){
- return props[i];
- }
- }
- }
+ 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 = {
- location: function(cookie_name){
- var embed_script = function(url){
- var scr = document.createElement('script');
- scr.type = 'text/javascript';
- scr.src = url;
- document.getElementsByTagName('head')[0].appendChild(scr);
- }
- return function(cb){
- var loc = null;
- if (!utils.get_cookie(cookie_name)){
- win.gloader_loaded = function() {
- if ('google' in window) {
- cb(win.google.loader.ClientLocation);
- utils.set_cookie(cookie_name,utils.stringify_json(win.google.loader.ClientLocation), 1000 * 60 * 60 * 2);} }
- embed_script('https://www.google.com/jsapi?callback=gloader_loaded');
- } else { cb(utils.parse_json(utils.get_cookie(cookie_name))); }
- }
+ browser: function(){
+ return browser.detect();
},
- locale: function(){
- var res = utils.search(['language', 'browserLanguage', 'systemLanguage', 'userLanguage'], function(prop_name){
- return navigator[prop_name];
- }), res_parts = res.split('-');
- if (res_parts.length == 2){
- return {country: res_parts[1], lang: res_parts[0]}
- } else { return {country: res} }
+ 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.
},
- browser: function(){
- return BrowserDetect.detect_browser();
+ 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: screen.width, height: screen.height}, viewport: {}};
- var elem=doc.documentElement, doc_body=doc.getElementsByTagName('body')[0], agent = navigator.userAgent;
- device.viewport.width=(win.innerWidth||elem.clientWidth||doc_body.clientWidth);
- device.viewport.height=(win.innerHeight||elem.clientHeight||doc_body.clientHeight);
- device.is_phone = !!(agent.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_tablet = !!(agent.match(/(iPad|SCH-I800|xoom|kindle)/i));
+ 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(plugin_name){
- if (navigator.plugins){
- return !!utils.find(navigator.plugins, function(plugin){
- if (plugin && plugin['name'] && plugin['name'].toLowerCase().indexOf(plugin_name) !== -1){
+ 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;
+ };
+ var check_activex_flash = function(versions){
+ var found = true;
+ for (var i = 0; i < versions.length; i++){
+ try {
+ var obj = new ActiveXObject("ShockwaveFlash.ShockwaveFlash" + versions[i])
+ , found = !0;
+ } catch (e){ /* nil */ }
+ if (found) return true;
}
+ return false;
}
return {
- flash: check_plugin('flash'),
- silverlight: check_plugin('silverlight'),
- java: check_plugin('java'),
- quicktime: check_plugin('quicktime'),
- }
+ flash: check_plugin("flash") || check_activex_flash(['.7','.6','']),
+ silverlight: check_plugin("silverlight"),
+ java: check_plugin("java"),
+ quicktime: check_plugin("quicktime")
+ };
},
- session: function(cookie_name, expires){
- if (cookie_name){ var sess = utils.get_cookie(cookie_name); }
- if (!sess){
- sess = {visits: 1, search: {engine: null, query: null}}
- var engines = [{nm: 'Google', url: "https?://(?:www\.)?(?:images.)?google.(?:com|[a-z]{2}|com?.[a-z]{2})", query: 'q'},
- {nm: "Bing", url: "https?://(?:www\.)?bing.com", query: "q"},
- {nm: "Yahoo", url:"https?://(?:www\.)?(?:.+.)?search.yahoo.(?:com|[a-z]{2}|com?.[a-z]{2})", query: "p"},
- {nm: "AOL", url:"https?://(?:www\.)?(?:aol)?search.aol.(?:com|[a-z]{2}|com?.[a-z]{2})", query: "q"},
- {nm: "Ask", url:"https?://(?:www\.)?(?:[a-z]+.)?ask.com", query:"q"},
- {nm: "Baidu", url:"https?://(?:www\.)?baidu.com", query:"wd"}];
- utils.find(engines, function(engine){
- var res = RegExp(engine['url'] + '/.*[?&]' + engine.query + '=([^&]+)').exec(doc.referrer);
- if (res){
- sess.search.engine = engine.nm;
- sess.search.query = engine.query;
- return true;
+ 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 (!sess.search.engine){
- utils.find(['q','query','term','p','wd','query','text'], function(query_term){
- var res = RegExp("[?&]" + query_term + "=([^&]+)").exec(doc.referrer);
- if (res){
- sess.search.engine = 'Unknown';
- sess.search.query = res;
- return true;
+ }
+ 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;
}
- });
+ }
}
- sess.referrer = doc.referrer;
- sess.url = win.location.href;
- sess.path = win.location.pathname;
- sess.start = (new Date()).getTime();
- sess.last_visit = sess.start;
- if (cookie_name){ utils.set_cookie(cookie_name, JSON.stringify(sess), expires); }
} else {
- sess = JSON.parse(sess);
- sess.last_visit = (new Date()).getTime();
- sess.visits += 1;
- utils.set_cookie(cookie_name, JSON.stringify(sess), expires)
+ 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;
}
- return sess;
- }
- }
- var session_loader = {
- modules: {
- locale: modules.locale(),
- cur_session: modules.session(),
- orig_session: modules.session('first_session', 1000 * 60 * 60 * 24 * (opts.session_days || 32)),
- browser: modules.browser(),
- plugins: modules.plugins(),
- device: modules.device()
+ util.set_obj(cookie, session, expires);
+ return session;
},
- init: function(){
- if (opts.enable_location){
- session_loader.modules['location'] = modules.location('location');
- }
- // Setup session Object
- var asyncs = 0, check_async = function(){
- if (asyncs == 0){ win.session_loaded && win.session_loaded(win.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'}); }
+ });
};
- win.modules = session_loader.modules;
- win.session = {api_version: 0.2}
- for (module_name in session_loader.modules){
- (function(module_name){
- var module_runner = session_loader.modules[module_name];
- if (typeof(module_runner) === 'function'){
- //try {
- var ret = module_runner;
- if (typeof(ret) === 'function'){
- asyncs++;
- ret(function(data){
- win.session[module_name] = data;
- asyncs--;
- check_async();
- });
+ },
+ 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 {
- win.session[module_name] = ret;
+ callback({error: true, source: "google"});
}
- //} catch (e) { if (typeof(console) !== 'undefined'){ console.log(e); } }
+ util.set_obj(
+ options.location_cookie,
+ 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);
+ }};
+ },
+ architecture: function(){
+ var arch = n.userAgent.match(/x86_64|Win64|WOW64|x86-64|x64\;|AMD64|amd64/) ||
+ (n.cpuClass === 'x64') ? 'x64' : 'x86';
+ return {
+ arch: arch,
+ is_x64: arch == 'x64',
+ is_x86: arch == 'x68'
+ }
+ },
+ ipinfodb_location: function(api_key){
+ return function (callback){
+ var location_cookie = util.get_obj(options.location_cookie);
+ if (!location_cookie && location_cookie.source === 'ipinfodb'){
+ win.ipinfocb = function(data){
+ if (data.statusCode === "OK"){
+ data.source = "ipinfodb";
+ util.set_obj(
+ options.location_cookie,
+ data,
+ options.location_cookie * 60 * 60 * 1000);
+ callback(data);
} else {
- win.session[module_name] = module_runner;
- }
- })(module_name);
+ 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");
+ } else { callback(location_cookie); }
+ }}
+ };
+
+ // Utilities
+ var util = {
+ parse_url: function(url_str){
+ var a = doc.createElement("a"), query = {};
+ a.href = url_str; var 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){ 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;
+ }
+ },
+ set_obj: function(cname, value, expires, options){
+ util.set_cookie(cname, util.package_obj(value), expires, options);
+ },
+ 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;
}
}
};
- session_loader.init();
-})(window, document);
+
+ // cookie options override
+ if (options.get_object != null){
+ util.get_obj = options['get_object']; }
+ if (options.set_object != null){
+ util.set_obj = options['set_object']; }
+
+ // 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;
+}
diff --git a/session.min.js b/session.min.js
index 7b1feea..85b992c 100644
--- a/session.min.js
+++ b/session.min.js
@@ -1,8 +1 @@
-/**
- * session.js 0.0.2
- * (c) 2012 Iain, CodeJoust
- * session 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
- */(function(win,doc){var opts={enable_location:!0,session_days:32};"session_opts"in window&&(opts=session_opts);var BrowserDetect={detect_browser:function(){return{browser:this.searchString(this.dataBrowser),version:this.searchVersion(navigator.userAgent)||this.searchVersion(navigator.appVersion),OS:this.searchString(this.dataOS)}},searchString:function(a){for(var b=0;b0){c_start=document.cookie.indexOf(a+"=");if(c_start!=-1){c_start=c_start+a.length+1,c_end=document.cookie.indexOf(";",c_start),c_end==-1&&(c_end=document.cookie.length);return unescape(document.cookie.substring(c_start,c_end))}}return null},each:function(a,b,c){if(a!=null)if(a.length===+a.length){for(var d=0,e=a.length;d1){for(i=0;i