PageRenderTime 27ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/files//0.4.1/session.js

https://gitlab.com/Mirros/jsdelivr
JavaScript | 423 lines | 370 code | 8 blank | 45 comment | 106 complexity | c171ffc03d26e00442fd54848e9edbf4 MD5 | raw file
  1. /**
  2. * session.js 0.4.1
  3. * (c) 2012 Iain, CodeJoust
  4. * session.js is freely distributable under the MIT license.
  5. * Portions of session.js are inspired or borrowed from Underscore.js, and quirksmode.org demo javascript.
  6. * This version uses google's jsapi library for location services.
  7. * For details, see: https://github.com/codejoust/session.js
  8. */
  9. var session_fetch = (function(win, doc, nav){
  10. // Changing the API Version invalidates olde cookies with previous api version tags.
  11. var API_VERSION = 0.4;
  12. // Settings: defaults
  13. var options = {
  14. // Use the HTML5 Geolocation API
  15. // this ONLY returns lat & long, no city/address
  16. use_html5_location: false,
  17. // Attempts to use IPInfoDB if provided a valid key
  18. // Get a key at http://ipinfodb.com/register.php
  19. ipinfodb_key: false,
  20. // Leaving true allows for fallback for both
  21. // the HTML5 location and the IPInfoDB
  22. gapi_location: true,
  23. // Name of the location cookie (set blank to disable cookie)
  24. // - WARNING: different providers use the same cookie
  25. // - if switching providers, remember to use another cookie or provide checks for old cookies
  26. location_cookie: "location",
  27. // Location cookie expiration in hours
  28. location_cookie_timeout: 5,
  29. // Session expiration in days
  30. session_timeout: 32,
  31. // Session cookie name (set blank to disable cookie)
  32. session_cookie: "first_session"
  33. };
  34. // Session object
  35. var SessionRunner = function(){
  36. win.session = win.session || {};
  37. // Helper for querying.
  38. // Usage: session.current_session.referrer_info.hostname.contains(['github.com','news.ycombinator.com'])
  39. win.session.contains = function(other_str){
  40. if (typeof(other_str) === 'string'){
  41. return (this.indexOf(other_str) !== -1); }
  42. for (var i = 0; i < other_str.length; i++){
  43. if (this.indexOf(other_str[i]) !== -1){ return true; } }
  44. return false; }
  45. // Merge options
  46. if (win.session && win.session.options) {
  47. for (option in win.session.options){
  48. options[option] = win.session.options[option]; }
  49. }
  50. // Modules to run
  51. // If the module has arguments,
  52. // it _needs_ to return a callback function.
  53. var unloaded_modules = {
  54. api_version: API_VERSION,
  55. locale: modules.locale(),
  56. current_session: modules.session(),
  57. original_session: modules.session(
  58. options.session_cookie,
  59. options.session_timeout * 24 * 60 * 60 * 1000),
  60. browser: modules.browser(),
  61. plugins: modules.plugins(),
  62. time: modules.time(),
  63. device: modules.device()
  64. };
  65. // Location switch
  66. if (options.use_html5_location){
  67. unloaded_modules.location = modules.html5_location();
  68. } else if (options.ipinfodb_key){
  69. unloaded_modules.location = modules.ipinfodb_location(options.ipinfodb_key);
  70. } else if (options.gapi_location){
  71. unloaded_modules.location = modules.gapi_location();
  72. }
  73. // Cache win.session.start
  74. if (win.session && win.session.start){
  75. var start = win.session.start;
  76. }
  77. // Set up checking, if all modules are ready
  78. var asynchs = 0, module, result,
  79. check_asynch = function(deinc){
  80. if (deinc){ asynchs--; }
  81. if (asynchs === 0){
  82. // Run start calback
  83. if (start){ start(win.session); }
  84. }
  85. };
  86. win.session = {};
  87. // Run asynchronous methods
  88. for (var name in unloaded_modules){
  89. module = unloaded_modules[name];
  90. if (typeof module === "function"){
  91. try {
  92. module(function(data){
  93. win.session[name] = data;
  94. check_asynch(true);
  95. });
  96. asynchs++;
  97. } catch(err){
  98. if (win.console && typeof(console.log) === "function"){
  99. console.log(err); check_asynch(true); }
  100. }
  101. } else {
  102. win.session[name] = module;
  103. } }
  104. check_asynch();
  105. };
  106. // Browser (and OS) detection
  107. var browser = {
  108. detect: function(){
  109. return {
  110. browser: this.search(this.data.browser),
  111. version: this.search(nav.userAgent) || this.search(nav.appVersion),
  112. os: this.search(this.data.os)
  113. } },
  114. search: function(data) {
  115. if (typeof data === "object"){
  116. // search for string match
  117. for(var i = 0; i < data.length; i++) {
  118. var dataString = data[i].string,
  119. dataProp = data[i].prop;
  120. this.version_string = data[i].versionSearch || data[i].identity;
  121. if (dataString){
  122. if (dataString.indexOf(data[i].subString) != -1){
  123. return data[i].identity;
  124. }
  125. } else if (dataProp){
  126. return data[i].identity;
  127. }
  128. }
  129. } else {
  130. // search for version number
  131. var index = data.indexOf(this.version_string);
  132. if (index == -1) return;
  133. return parseFloat(data.substr(index + this.version_string.length + 1));
  134. }
  135. },
  136. data: {
  137. browser: [
  138. { string: nav.userAgent, subString: "Chrome", identity: "Chrome" },
  139. { string: nav.userAgent, subString: "OmniWeb", versionSearch: "OmniWeb/", identity: "OmniWeb" },
  140. { string: nav.vendor, subString: "Apple", identity: "Safari", versionSearch: "Version" },
  141. { prop: win.opera, identity: "Opera", versionSearch: "Version" },
  142. { string: nav.vendor, subString: "iCab",identity: "iCab" },
  143. { string: nav.vendor, subString: "KDE", identity: "Konqueror" },
  144. { string: nav.userAgent, subString: "Firefox", identity: "Firefox" },
  145. { string: nav.vendor, subString: "Camino", identity: "Camino" },
  146. { string: nav.userAgent, subString: "Netscape", identity: "Netscape" },
  147. { string: nav.userAgent, subString: "MSIE", identity: "Explorer", versionSearch: "MSIE" },
  148. { string: nav.userAgent, subString: "Gecko", identity: "Mozilla", versionSearch: "rv" },
  149. { string: nav.userAgent, subString: "Mozilla", identity: "Netscape", versionSearch: "Mozilla" }
  150. ],
  151. os: [
  152. { string: nav.platform, subString: "Win", identity: "Windows" },
  153. { string: nav.platform, subString: "Mac", identity: "Mac" },
  154. { string: nav.userAgent, subString: "iPhone", identity: "iPhone/iPod" },
  155. { string: nav.userAgent, subString: "iPad", identity: "iPad" },
  156. { string: nav.userAgent, subString: "Android", identity: "Android" },
  157. { string: nav.platform, subString: "Linux", identity: "Linux" }
  158. ]}
  159. };
  160. var modules = {
  161. browser: function(){
  162. return browser.detect();
  163. },
  164. time: function(){
  165. // split date and grab timezone estimation.
  166. // timezone estimation: http://www.onlineaspect.com/2007/06/08/auto-detect-a-time-zone-with-javascript/
  167. var d1 = new Date(), d2 = new Date();
  168. d1.setMonth(0); d1.setDate(1); d2.setMonth(6); d2.setDate(1);
  169. return({tz_offset: -(new Date().getTimezoneOffset()) / 60, observes_dst: (d1.getTimezoneOffset() !== d2.getTimezoneOffset()) });
  170. // Gives a browser estimation, not guaranteed to be correct.
  171. },
  172. locale: function() {
  173. var lang = ((
  174. nav.language ||
  175. nav.browserLanguage ||
  176. nav.systemLanguage ||
  177. nav.userLanguage
  178. ) || '').split("-");
  179. if (lang.length == 2){
  180. return { country: lang[1].toLowerCase(), lang: lang[0].toLowerCase() };
  181. } else if (lang) {
  182. return {lang: lang[0].toLowerCase(), country: null };
  183. } else { return{lang: null, country: null }; }
  184. },
  185. device: function() {
  186. var device = {
  187. screen: {
  188. width: win.screen.width,
  189. height: win.screen.height
  190. }
  191. };
  192. device.viewport = {
  193. width: win.innerWidth || doc.documentElement.clientWidth || doc.body.clientWidth,
  194. height: win.innerHeight || doc.documentElement.clientHeight || doc.body.clientHeight
  195. };
  196. device.is_tablet = !!nav.userAgent.match(/(iPad|SCH-I800|xoom|kindle)/i);
  197. 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);
  198. device.is_mobile = device.is_tablet || device.is_phone;
  199. return device;
  200. },
  201. plugins: function(){
  202. var check_plugin = function(name){
  203. if (nav.plugins){
  204. var plugin, i = 0, length = nav.plugins.length;
  205. for (; i < length; i++ ){
  206. plugin = nav.plugins[i];
  207. if (plugin && plugin.name && plugin.name.toLowerCase().indexOf(name) !== -1){
  208. return true;
  209. } }
  210. return false;
  211. } return false;
  212. }
  213. return {
  214. flash: check_plugin("flash"),
  215. silverlight: check_plugin("silverlight"),
  216. java: check_plugin("java"),
  217. quicktime: check_plugin("quicktime")
  218. };
  219. },
  220. session: function (cookie, expires){
  221. var session = util.get_obj(cookie);
  222. if (session == null){
  223. session = {
  224. visits: 1,
  225. start: new Date().getTime(), last_visit: new Date().getTime(),
  226. url: win.location.href, path: win.location.pathname,
  227. referrer: doc.referrer, referrer_info: util.parse_url(doc.referrer),
  228. search: { engine: null, query: null }
  229. };
  230. var search_engines = [
  231. { name: "Google", host: "google", query: "q" },
  232. { name: "Bing", host: "bing.com", query: "q" },
  233. { name: "Yahoo", host: "search.yahoo", query: "p" },
  234. { name: "AOL", host: "search.aol", query: "q" },
  235. { name: "Ask", host: "ask.com", query: "q" },
  236. { name: "Baidu", host: "baidu.com", query: "wd" }
  237. ], length = search_engines.length,
  238. engine, match, i = 0,
  239. fallbacks = 'q query term p wd query text'.split(' ');
  240. for (i = 0; i < length; i++){
  241. engine = search_engines[i];
  242. if (session.referrer_info.host.indexOf(engine.host) !== -1){
  243. session.search.engine = engine.name;
  244. session.search.query = session.referrer_info.query[engine.query];
  245. session.search.terms = session.search.query ? session.search.query.split(" ") : null;
  246. break;
  247. }
  248. }
  249. if (session.search.engine === null && session.referrer_info.search.length > 1){
  250. for (i = 0; i < fallbacks.length; i++){
  251. var terms = session.referrer_info.query[fallbacks[i]];
  252. if (terms){
  253. session.search.engine = "Unknown";
  254. session.search.query = terms; session.search.terms = terms.split(" ");
  255. break;
  256. }
  257. }
  258. }
  259. } else {
  260. session.prev_visit = session.last_visit;
  261. session.last_visit = new Date().getTime();
  262. session.visits++;
  263. session.time_since_last_visit = session.last_visit - session.prev_visit;
  264. }
  265. util.set_cookie(cookie, util.package_obj(session), expires);
  266. return session;
  267. },
  268. html5_location: function(){
  269. return function(callback){
  270. nav.geolocation.getCurrentPosition(function(pos){
  271. pos.source = 'html5';
  272. callback(pos);
  273. }, function(err) {
  274. if (options.gapi_location){
  275. modules.gapi_location()(callback);
  276. } else {
  277. callback({error: true, source: 'html5'}); }
  278. });
  279. };
  280. },
  281. gapi_location: function(){
  282. return function(callback){
  283. var location = util.get_obj(options.location_cookie);
  284. if (!location || location.source !== 'google'){
  285. win.gloader_ready = function() {
  286. if ("google" in win){
  287. if (win.google.loader.ClientLocation){
  288. win.google.loader.ClientLocation.source = "google";
  289. callback(win.google.loader.ClientLocation);
  290. } else {
  291. callback({error: true, source: "google"});
  292. }
  293. util.set_cookie(
  294. options.location_cookie,
  295. util.package_obj(win.google.loader.ClientLocation),
  296. options.location_cookie_timeout * 60 * 60 * 1000);
  297. }}
  298. util.embed_script("https://www.google.com/jsapi?callback=gloader_ready");
  299. } else {
  300. callback(location);
  301. }}
  302. },
  303. ipinfodb_location: function(api_key){
  304. return function (callback){
  305. var location_cookie = util.get_obj(options.location_cookie);
  306. if (location_cookie && location_cookie.source === 'ipinfodb'){ callback(location_cookie); }
  307. win.ipinfocb = function(data){
  308. if (data.statusCode === "OK"){
  309. data.source = "ipinfodb";
  310. util.set_cookie(
  311. options.location_cookie,
  312. util.package_obj(data),
  313. options.location_cookie * 60 * 60 * 1000);
  314. callback(data);
  315. } else {
  316. if (options.gapi_location){ return modules.gapi_location()(callback); }
  317. else { callback({error: true, source: "ipinfodb", message: data.statusMessage}); }
  318. }}
  319. util.embed_script("http://api.ipinfodb.com/v3/ip-city/?key=" + api_key + "&format=json&callback=ipinfocb");
  320. }}
  321. };
  322. // Utilities
  323. var util = {
  324. parse_url: function(url_str){
  325. var a = doc.createElement("a"), query = {};
  326. a.href = url_str; query_str = a.search.substr(1);
  327. // Disassemble query string
  328. if (query_str != ''){
  329. var pairs = query_str.split("&"), i = 0,
  330. length = pairs.length, parts;
  331. for (; i < length; i++){
  332. parts = pairs[i].split("=");
  333. if (parts.length === 2){
  334. query[parts[0]] = decodeURI(parts[1]); }
  335. }
  336. }
  337. return {
  338. host: a.host,
  339. path: a.pathname,
  340. protocol: a.protocol,
  341. port: a.port === '' ? 80 : a.port,
  342. search: a.search,
  343. query: query }
  344. },
  345. set_cookie: function(cname, value, expires, options){ // from jquery.cookie.js
  346. if (!cname){ return null; }
  347. if (!options){ var options = {}; }
  348. if (value === null || value === undefined){ expires = -1; }
  349. if (expires){ options.expires = (new Date().getTime()) + expires; }
  350. return (doc.cookie = [
  351. encodeURIComponent(cname), '=',
  352. encodeURIComponent(String(value)),
  353. options.expires ? '; expires=' + new Date(options.expires).toUTCString() : '', // use expires attribute, max-age is not supported by IE
  354. '; path=' + (options.path ? options.path : '/'),
  355. options.domain ? '; domain=' + options.domain : '',
  356. (win.location && win.location.protocol === 'https:') ? '; secure' : ''
  357. ].join(''));
  358. },
  359. get_cookie: function(cookie_name, result){ // from jquery.cookie.js
  360. return (result = new RegExp('(?:^|; )' + encodeURIComponent(cookie_name) + '=([^;]*)').exec(doc.cookie)) ? decodeURIComponent(result[1]) : null;
  361. },
  362. embed_script: function(url){
  363. var element = doc.createElement("script");
  364. element.type = "text/javascript";
  365. element.src = url;
  366. doc.getElementsByTagName("body")[0].appendChild(element);
  367. },
  368. package_obj: function (obj){
  369. if(obj) {
  370. obj.version = API_VERSION;
  371. var ret = JSON.stringify(obj);
  372. delete obj.version;
  373. return ret;
  374. }
  375. },
  376. get_obj: function(cookie_name){
  377. var obj;
  378. try { obj = JSON.parse(util.get_cookie(cookie_name)); } catch(e){};
  379. if (obj && obj.version == API_VERSION){
  380. delete obj.version; return obj;
  381. }
  382. }
  383. };
  384. // JSON
  385. var JSON = {
  386. parse: (win.JSON && win.JSON.parse) || function(data){
  387. if (typeof data !== "string" || !data){ return null; }
  388. return (new Function("return " + data))();
  389. },
  390. stringify: (win.JSON && win.JSON.stringify) || function(object){
  391. var type = typeof object;
  392. if (type !== "object" || object === null) {
  393. if (type === "string"){ return '"' + object + '"'; }
  394. } else {
  395. var k, v, json = [],
  396. isArray = (object && object.constructor === Array);
  397. for (k in object ) {
  398. v = object[k]; type = typeof v;
  399. if (type === "string")
  400. v = '"' + v + '"';
  401. else if (type === "object" && v !== null)
  402. v = this.stringify(v);
  403. json.push((isArray ? "" : '"' + k + '":') + v);
  404. }
  405. return (isArray ? "[" : "{") + json.join(",") + (isArray ? "]" : "}");
  406. } } };
  407. // Initialize SessionRunner
  408. SessionRunner();
  409. });
  410. // Switch for testing purposes.
  411. if (typeof(window.exports) === 'undefined'){
  412. session_fetch(window, document, navigator);
  413. } else {
  414. window.exports.session = session_fetch;
  415. }