isc_analytics 0.5 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1 @@
1
+ //= require_tree .
@@ -0,0 +1,414 @@
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
+ (function(win, doc, nav){
10
+ // Changing the API Version invalidates olde cookies with previous api version tags.
11
+ var API_VERSION = 0.4;
12
+
13
+ // Settings: defaults
14
+ var options = {
15
+ // Use the HTML5 Geolocation API
16
+ // this ONLY returns lat & long, no city/address
17
+ use_html5_location: false,
18
+ // Attempts to use IPInfoDB if provided a valid key
19
+ // Get a key at http://ipinfodb.com/register.php
20
+ ipinfodb_key: false,
21
+ // Leaving true allows for fallback for both
22
+ // the HTML5 location and the IPInfoDB
23
+ gapi_location: true,
24
+ // Name of the location cookie (set blank to disable cookie)
25
+ // - WARNING: different providers use the same cookie
26
+ // - if switching providers, remember to use another cookie or provide checks for old cookies
27
+ location_cookie: "location",
28
+ // Location cookie expiration in hours
29
+ location_cookie_timeout: 5,
30
+ // Session expiration in days
31
+ session_timeout: 32,
32
+ // Session cookie name (set blank to disable cookie)
33
+ session_cookie: "first_session"
34
+ };
35
+
36
+ // Session object
37
+ var SessionRunner = function(){
38
+ // Helper for querying.
39
+ // Usage: session.current_session.referrer_info.hostname.contains(['github.com','news.ycombinator.com'])
40
+ String.prototype.contains = function(other_str){
41
+ if (typeof(other_str) === 'string'){
42
+ return (this.indexOf(other_str) !== -1); }
43
+ for (var i = 0; i < other_str.length; i++){
44
+ if (this.indexOf(other_str[i]) !== -1){ return true; } }
45
+ return false; }
46
+ // Merge options
47
+ if (win.session && win.session.options) {
48
+ for (option in win.session.options){
49
+ options[option] = win.session.options[option]; }
50
+ }
51
+ // Modules to run
52
+ // If the module has arguments,
53
+ // it _needs_ to return a callback function.
54
+ var unloaded_modules = {
55
+ api_version: API_VERSION,
56
+ locale: modules.locale(),
57
+ current_session: modules.session(),
58
+ original_session: modules.session(
59
+ options.session_cookie,
60
+ options.session_timeout * 24 * 60 * 60 * 1000),
61
+ browser: modules.browser(),
62
+ plugins: modules.plugins(),
63
+ time: modules.time(),
64
+ device: modules.device()
65
+ };
66
+ // Location switch
67
+ if (options.use_html5_location){
68
+ unloaded_modules.location = modules.html5_location();
69
+ } else if (options.ipinfodb_key){
70
+ unloaded_modules.location = modules.ipinfodb_location(options.ipinfodb_key);
71
+ } else if (options.gapi_location){
72
+ unloaded_modules.location = modules.gapi_location();
73
+ }
74
+ // Cache win.session.start
75
+ if (win.session && win.session.start){
76
+ var start = win.session.start;
77
+ }
78
+ // Set up checking, if all modules are ready
79
+ var asynchs = 0, module, result,
80
+ check_asynch = function(){
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
+ asynchs--;
95
+ check_asynch();
96
+ });
97
+ asynchs++;
98
+ } catch(err){
99
+ if (win.console && typeof(console.log) === "function"){
100
+ console.log(err); }
101
+ }
102
+ } else {
103
+ win.session[name] = module;
104
+ } }
105
+ check_asynch();
106
+ };
107
+
108
+
109
+ // Browser (and OS) detection
110
+ var browser = {
111
+ detect: function(){
112
+ return {
113
+ browser: this.search(this.data.browser),
114
+ version: this.search(nav.userAgent) || this.search(nav.appVersion),
115
+ os: this.search(this.data.os)
116
+ } },
117
+ search: function(data) {
118
+ if (typeof data === "object"){
119
+ // search for string match
120
+ for(var i = 0; i < data.length; i++) {
121
+ var dataString = data[i].string,
122
+ dataProp = data[i].prop;
123
+ this.version_string = data[i].versionSearch || data[i].identity;
124
+ if (dataString){
125
+ if (dataString.indexOf(data[i].subString) != -1){
126
+ return data[i].identity;
127
+ }
128
+ } else if (dataProp){
129
+ return data[i].identity;
130
+ }
131
+ }
132
+ } else {
133
+ // search for version number
134
+ var index = data.indexOf(this.version_string);
135
+ if (index == -1) return;
136
+ return parseFloat(data.substr(index + this.version_string.length + 1));
137
+ }
138
+ },
139
+ data: {
140
+ browser: [
141
+ { string: nav.userAgent, subString: "Chrome", identity: "Chrome" },
142
+ { string: nav.userAgent, subString: "OmniWeb", versionSearch: "OmniWeb/", identity: "OmniWeb" },
143
+ { string: nav.vendor, subString: "Apple", identity: "Safari", versionSearch: "Version" },
144
+ { prop: win.opera, identity: "Opera", versionSearch: "Version" },
145
+ { string: nav.vendor, subString: "iCab",identity: "iCab" },
146
+ { string: nav.vendor, subString: "KDE", identity: "Konqueror" },
147
+ { string: nav.userAgent, subString: "Firefox", identity: "Firefox" },
148
+ { string: nav.vendor, subString: "Camino", identity: "Camino" },
149
+ { string: nav.userAgent, subString: "Netscape", identity: "Netscape" },
150
+ { string: nav.userAgent, subString: "MSIE", identity: "Explorer", versionSearch: "MSIE" },
151
+ { string: nav.userAgent, subString: "Gecko", identity: "Mozilla", versionSearch: "rv" },
152
+ { string: nav.userAgent, subString: "Mozilla", identity: "Netscape", versionSearch: "Mozilla" }
153
+ ],
154
+ os: [
155
+ { string: nav.platform, subString: "Win", identity: "Windows" },
156
+ { string: nav.platform, subString: "Mac", identity: "Mac" },
157
+ { string: nav.userAgent, subString: "iPhone", identity: "iPhone/iPod" },
158
+ { string: nav.userAgent, subString: "iPad", identitiy: "iPad" },
159
+ { string: nav.platform, subString: "Linux", identity: "Linux" },
160
+ { string: nav.userAgent, subString: "Android", identity: "Android" }
161
+ ]}
162
+ };
163
+
164
+ var modules = {
165
+ browser: function(){
166
+ return browser.detect();
167
+ },
168
+ time: function(){
169
+ // split date and grab timezone estimation.
170
+ // timezone estimation: http://www.onlineaspect.com/2007/06/08/auto-detect-a-time-zone-with-javascript/
171
+ var d1 = new Date(), d2 = new Date();
172
+ d1.setMonth(0); d1.setDate(1); d2.setMonth(6); d2.setDate(1);
173
+ return({tz_offset: -(new Date().getTimezoneOffset()) / 60, observes_dst: (d1.getTimezoneOffset() !== d2.getTimezoneOffset()) });
174
+ // Gives a browser estimation, not guaranteed to be correct.
175
+ },
176
+ locale: function() {
177
+ var lang = (
178
+ nav.language ||
179
+ nav.browserLanguage ||
180
+ nav.systemLanguage ||
181
+ nav.userLanguage
182
+ ).split("-");
183
+ if (lang.length == 2){
184
+ return { country: lang[1].toLowerCase(), lang: lang[0].toLowerCase() };
185
+ } else if (lang) {
186
+ return {lang: lang[0].toLowerCase(), country: null };
187
+ } else { return{lang: null, country: null }; }
188
+ },
189
+ device: function() {
190
+ var device = {
191
+ screen: {
192
+ width: screen.width,
193
+ height: screen.height
194
+ }
195
+ };
196
+ var html = doc.documentElement,
197
+ body = doc.getElementsByTagName("body")[0];
198
+ device.viewport = {
199
+ width: win.innerWidth || html.clientWidth || body.clientWidth,
200
+ height: win.innerHeight || html.clientHeight || body.clientHeight
201
+ };
202
+ device.is_tablet = !!nav.userAgent.match(/(iPad|SCH-I800|xoom|kindle)/i);
203
+ 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);
204
+ device.is_mobile = (device.is_tablet || device.is_phone);
205
+ return device;
206
+ },
207
+ plugins: function(){
208
+ var check_plugin = function(name){
209
+ if (nav.plugins){
210
+ var plugin, i = 0, length = nav.plugins.length;
211
+ for (; i < length; i++ ){
212
+ plugin = nav.plugins[i];
213
+ if (plugin && plugin.name && plugin.name.toLowerCase().indexOf(name) !== -1){
214
+ return true;
215
+ } }
216
+ return false;
217
+ } return false;
218
+ }
219
+ return {
220
+ flash: check_plugin("flash"),
221
+ silverlight: check_plugin("silverlight"),
222
+ java: check_plugin("java"),
223
+ quicktime: check_plugin("quicktime")
224
+ };
225
+ },
226
+ session: function (cookie, expires){
227
+ var session = util.get_obj(cookie);
228
+ if (session == null){
229
+ session = {
230
+ visits: 1,
231
+ start: new Date().getTime(), last_visit: new Date().getTime(),
232
+ url: win.location.href, path: win.location.pathname,
233
+ referrer: doc.referrer, referrer_info: util.parse_url(doc.referrer),
234
+ search: { engine: null, query: null }
235
+ };
236
+ var search_engines = [
237
+ { name: "Google", host: "google", query: "q" },
238
+ { name: "Bing", host: "bing.com", query: "q" },
239
+ { name: "Yahoo", host: "search.yahoo", query: "p" },
240
+ { name: "AOL", host: "search.aol", query: "q" },
241
+ { name: "Ask", host: "ask.com", query: "q" },
242
+ { name: "Baidu", host: "baidu.com", query: "wd" }
243
+ ], length = search_engines.length,
244
+ engine, match, i = 0,
245
+ fallbacks = 'q query term p wd query text'.split(' ');
246
+ for (i = 0; i < length; i++){
247
+ engine = search_engines[i];
248
+ if (session.referrer_info.host.indexOf(engine.host) !== -1){
249
+ session.search.engine = engine.name;
250
+ session.search.query = session.referrer_info.query[engine.query];
251
+ session.search.terms = session.search.query ? session.search.query.split(" ") : null;
252
+ break;
253
+ }
254
+ }
255
+ if (session.search.engine === null && session.referrer_info.search.length > 1){
256
+ for (i = 0; i < fallbacks.length; i++){
257
+ var terms = session.referrer_info.query[fallbacks[i]];
258
+ if (terms){
259
+ session.search.engine = "Unknown";
260
+ session.search.query = terms; session.search.terms = terms.split(" ");
261
+ break;
262
+ }
263
+ }
264
+ }
265
+ } else {
266
+ session.last_visit = new Date().getTime();
267
+ session.visits++;
268
+ }
269
+ util.set_cookie(cookie, util.package_obj(session), expires);
270
+ return session;
271
+ },
272
+ html5_location: function(){
273
+ return function(callback){
274
+ nav.geolocation.getCurrentPosition(function(pos){
275
+ pos.source = 'html5';
276
+ callback(pos);
277
+ }, function(err) {
278
+ if (options.gapi_location){
279
+ modules.gapi_location()(callback);
280
+ } else {
281
+ callback({error: true, source: 'html5'}); }
282
+ });
283
+ };
284
+ },
285
+ gapi_location: function(){
286
+ return function(callback){
287
+ var location = util.get_obj(options.location_cookie);
288
+ if (!location || location.source !== 'google'){
289
+ win.gloader_ready = function() {
290
+ if ("google" in win){
291
+ if (win.google.loader.ClientLocation){
292
+ win.google.loader.ClientLocation.source = "google";
293
+ callback(win.google.loader.ClientLocation);
294
+ } else {
295
+ callback({error: true, source: "google"});
296
+ }
297
+ util.set_cookie(
298
+ options.location_cookie,
299
+ util.package_obj(win.google.loader.ClientLocation),
300
+ options.location_cookie_timeout * 60 * 60 * 1000);
301
+ }}
302
+ util.embed_script("https://www.google.com/jsapi?callback=gloader_ready");
303
+ } else {
304
+ callback(location);
305
+ }}
306
+ },
307
+ ipinfodb_location: function(api_key){
308
+ return function (callback){
309
+ var location_cookie = util.get_obj(options.location_cookie);
310
+ if (location_cookie && location_cookie.source === 'ipinfodb'){ callback(location_cookie); }
311
+ win.ipinfocb = function(data){
312
+ if (data.statusCode === "OK"){
313
+ data.source = "ipinfodb";
314
+ util.set_cookie(
315
+ options.location_cookie,
316
+ util.package_obj(data),
317
+ options.location_cookie * 60 * 60 * 1000);
318
+ callback(data);
319
+ } else {
320
+ if (options.gapi_location){ return modules.gapi_location()(callback); }
321
+ else { callback({error: true, source: "ipinfodb", message: data.statusMessage}); }
322
+ }}
323
+ util.embed_script("http://api.ipinfodb.com/v3/ip-city/?key=" + api_key + "&format=json&callback=ipinfocb");
324
+ }}
325
+ };
326
+
327
+ // Utilities
328
+ var util = {
329
+ parse_url: function(url_str){
330
+ var a = doc.createElement("a"), query = {};
331
+ a.href = url_str; query_str = a.search.substr(1);
332
+ // Disassemble query string
333
+ if (query_str != ''){
334
+ var pairs = query_str.split("&"), i = 0,
335
+ length = pairs.length, parts;
336
+ for (; i < length; i++){
337
+ parts = pairs[i].split("=");
338
+ if (parts.length === 2){
339
+ query[parts[0]] = decodeURI(parts[1]); }
340
+ }
341
+ }
342
+ return {
343
+ host: a.host,
344
+ path: a.pathname,
345
+ protocol: a.protocol,
346
+ port: a.port === '' ? 80 : a.port,
347
+ search: a.search,
348
+ query: query }
349
+ },
350
+ set_cookie: function(cname, value, expires, options){ // from jquery.cookie.js
351
+ if (!doc.cookie || !cname || !value){ return null; }
352
+ if (!options){ var options = {}; }
353
+ if (value === null || value === undefined){ expires = -1; }
354
+ if (expires){ options.expires = (new Date().getTime()) + expires; }
355
+ return (document.cookie = [
356
+ encodeURIComponent(cname), '=',
357
+ encodeURIComponent(String(value)),
358
+ options.expires ? '; expires=' + new Date(options.expires).toUTCString() : '', // use expires attribute, max-age is not supported by IE
359
+ options.path ? '; path=' + options.path : '',
360
+ options.domain ? '; domain=' + options.domain : '',
361
+ (win.location && win.location.protocol === 'https:') ? '; secure' : ''
362
+ ].join(''));
363
+ },
364
+ get_cookie: function(cookie_name, result){ // from jquery.cookie.js
365
+ return (result = new RegExp('(?:^|; )' + encodeURIComponent(cookie_name) + '=([^;]*)').exec(document.cookie)) ? decodeURIComponent(result[1]) : null;
366
+ },
367
+ embed_script: function(url){
368
+ var element = doc.createElement("script");
369
+ element.type = "text/javascript";
370
+ element.src = url;
371
+ doc.getElementsByTagName("body")[0].appendChild(element);
372
+ },
373
+ package_obj: function (obj){
374
+ obj.version = API_VERSION;
375
+ var ret = JSON.stringify(obj);
376
+ delete obj.version; return ret;
377
+ },
378
+ get_obj: function(cookie_name){
379
+ var obj;
380
+ try { obj = JSON.parse(util.get_cookie(cookie_name)); } catch(e){};
381
+ if (obj && obj.version == API_VERSION){
382
+ delete obj.version; return obj;
383
+ }
384
+ }
385
+ };
386
+
387
+ // JSON
388
+ var JSON = {
389
+ parse: (win.JSON && win.JSON.parse) || function(data){
390
+ if (typeof data !== "string" || !data){ return null; }
391
+ return (new Function("return " + data))();
392
+ },
393
+ stringify: (win.JSON && win.JSON.stringify) || function(object){
394
+ var type = typeof object;
395
+ if (type !== "object" || object === null) {
396
+ if (type === "string"){ return '"' + object + '"'; }
397
+ } else {
398
+ var k, v, json = [],
399
+ isArray = (object && object.constructor === Array);
400
+ for (k in object ) {
401
+ v = object[k]; type = typeof v;
402
+ if (type === "string")
403
+ v = '"' + v + '"';
404
+ else if (type === "object" && v !== null)
405
+ v = this.stringify(v);
406
+ json.push((isArray ? "" : '"' + k + '":') + v);
407
+ }
408
+ return (isArray ? "[" : "{") + json.join(",") + (isArray ? "]" : "}");
409
+ } } };
410
+
411
+ // Initialize SessionRunner
412
+ SessionRunner();
413
+
414
+ })(window, document, navigator);
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Yepnope CSS Force prefix
3
+ *
4
+ * Use a combination of any prefix, and they should work
5
+ * Usage: ['css!genStyles.php?234', 'normal-styles.css' ]
6
+ *
7
+ * Official Yepnope Plugin
8
+ *
9
+ * WTFPL License
10
+ *
11
+ * by Alex Sexton | AlexSexton@gmail.com
12
+ */
13
+ ( function ( yepnope ) {
14
+ // add each prefix
15
+ yepnope.addPrefix( 'css', function ( resource ) {
16
+ // Set the force flag
17
+ resource.forceCSS = true;
18
+ //carry on
19
+ return resource;
20
+ } );
21
+ } )( this.yepnope );
@@ -0,0 +1,2 @@
1
+ //= require ./yepnope
2
+ //= require ./css_prefix
@@ -0,0 +1,546 @@
1
+ /*yepnope1.0.2|WTFPL*/
2
+ // yepnope.js
3
+ // Version - 1.0.2
4
+ //
5
+ // by
6
+ // Alex Sexton - @SlexAxton - AlexSexton[at]gmail.com
7
+ // Ralph Holzmann - @ralphholzmann - ralphholzmann[at]gmail.com
8
+ //
9
+ // http://yepnopejs.com/
10
+ // https://github.com/SlexAxton/yepnope.js/
11
+ //
12
+ // Tri-license - WTFPL | MIT | BSD
13
+ //
14
+ // Please minify before use.
15
+ // Also available as Modernizr.load via the Modernizr Project
16
+ //
17
+ ( function ( window, doc, undef ) {
18
+
19
+ var docElement = doc.documentElement,
20
+ sTimeout = window.setTimeout,
21
+ firstScript = doc.getElementsByTagName( 'script' )[ 0 ],
22
+ toString = {}.toString,
23
+ execStack = [],
24
+ started = 0,
25
+ // Before you get mad about browser sniffs, please read:
26
+ // https://github.com/Modernizr/Modernizr/wiki/Undetectables
27
+ // If you have a better solution, we are actively looking to solve the problem
28
+ isGecko = ( 'MozAppearance' in docElement.style ),
29
+ isGeckoLTE18 = isGecko && !! doc.createRange().compareNode,
30
+ isGeckoGT18 = isGecko && ! isGeckoLTE18,
31
+ insBeforeObj = isGeckoLTE18 ? docElement : firstScript.parentNode,
32
+ // Thanks to @jdalton for showing us this opera detection (by way of @kangax) (and probably @miketaylr too, or whatever...)
33
+ isOpera = window.opera && toString.call( window.opera ) == '[object Opera]',
34
+ isWebkit = ( 'webkitAppearance' in docElement.style ),
35
+ isNewerWebkit = isWebkit && 'async' in doc.createElement('script'),
36
+ strJsElem = isGecko ? 'object' : ( isOpera || isNewerWebkit ) ? 'img' : 'script',
37
+ strCssElem = isWebkit ? 'img' : strJsElem,
38
+ isArray = Array.isArray || function ( obj ) {
39
+ return toString.call( obj ) == '[object Array]';
40
+ },
41
+ isObject = function ( obj ) {
42
+ return Object(obj) === obj;
43
+ },
44
+ isString = function ( s ) {
45
+ return typeof s == 'string';
46
+ },
47
+ isFunction = function ( fn ) {
48
+ return toString.call( fn ) == '[object Function]';
49
+ },
50
+ globalFilters = [],
51
+ prefixes = {},
52
+ handler,
53
+ yepnope;
54
+
55
+ /* Loader helper functions */
56
+ function isFileReady ( readyState ) {
57
+ // Check to see if any of the ways a file can be ready are available as properties on the file's element
58
+ return ( ! readyState || readyState == 'loaded' || readyState == 'complete' );
59
+ }
60
+
61
+ function execWhenReady () {
62
+ var execStackReady = 1,
63
+ i = -1;
64
+
65
+ // Loop through the stack of scripts in the cue and execute them when all scripts in a group are ready
66
+ while ( execStack.length - ++i ) {
67
+ if ( execStack[ i ].s && ! ( execStackReady = execStack[ i ].r ) ) {
68
+ // As soon as we encounter a script that isn't ready, stop looking for more
69
+ break;
70
+ }
71
+ }
72
+
73
+ // If we've set the stack as ready in the loop, make it happen here
74
+ execStackReady && executeStack();
75
+
76
+ }
77
+
78
+ // Takes a preloaded js obj (changes in different browsers) and injects it into the head
79
+ // in the appropriate order
80
+ function injectJs ( oldObj ) {
81
+ var script = doc.createElement( 'script' ),
82
+ done;
83
+
84
+ script.src = oldObj.s;
85
+
86
+ // Bind to load events
87
+ script.onreadystatechange = script.onload = function () {
88
+
89
+ if ( ! done && isFileReady( script.readyState ) ) {
90
+
91
+ // Set done to prevent this function from being called twice.
92
+ done = 1;
93
+ execWhenReady();
94
+
95
+ // Handle memory leak in IE
96
+ script.onload = script.onreadystatechange = null;
97
+ }
98
+ };
99
+
100
+ // 404 Fallback
101
+ sTimeout( function () {
102
+ if ( ! done ) {
103
+ done = 1;
104
+ execWhenReady();
105
+ }
106
+ }, yepnope.errorTimeout );
107
+
108
+ // Inject script into to document
109
+ // or immediately callback if we know there
110
+ // was previously a timeout error
111
+ oldObj.e ? script.onload() : firstScript.parentNode.insertBefore( script, firstScript );
112
+ }
113
+
114
+ // Takes a preloaded css obj (changes in different browsers) and injects it into the head
115
+ // in the appropriate order
116
+ // Many credits to John Hann (@unscriptable) for a lot of the ideas here - found in the css! plugin for RequireJS
117
+ function injectCss ( oldObj ) {
118
+
119
+ // Create stylesheet link
120
+ var link = doc.createElement( 'link' ),
121
+ done;
122
+
123
+ // Add attributes
124
+ link.href = oldObj.s;
125
+ link.rel = 'stylesheet';
126
+ link.type = 'text/css';
127
+
128
+ // Poll for changes in webkit and gecko
129
+ if ( ! oldObj.e && ( isWebkit || isGecko ) ) {
130
+ // A self executing function with a sTimeout poll to call itself
131
+ // again until the css file is added successfully
132
+ var poll = function ( link ) {
133
+ sTimeout( function () {
134
+ // Don't run again if we're already done
135
+ if ( ! done ) {
136
+ try {
137
+ // In supporting browsers, we can see the length of the cssRules of the file go up
138
+ if ( link.sheet.cssRules.length ) {
139
+ // Then turn off the poll
140
+ done = 1;
141
+ // And execute a function to execute callbacks when all dependencies are met
142
+ execWhenReady();
143
+ }
144
+ // otherwise, wait another interval and try again
145
+ else {
146
+ poll( link );
147
+ }
148
+ }
149
+ catch ( ex ) {
150
+ // In the case that the browser does not support the cssRules array (cross domain)
151
+ // just check the error message to see if it's a security error
152
+ if ( ( ex.code == 1e3 ) || ( ex.message == 'security' || ex.message == 'denied' ) ) {
153
+ // if it's a security error, that means it loaded a cross domain file, so stop the timeout loop
154
+ done = 1;
155
+ // and execute a check to see if we can run the callback(s) immediately after this function ends
156
+ sTimeout( function () {
157
+ execWhenReady();
158
+ }, 0 );
159
+ }
160
+ // otherwise, continue to poll
161
+ else {
162
+ poll( link );
163
+ }
164
+ }
165
+ }
166
+ }, 0 );
167
+ };
168
+ poll( link );
169
+
170
+ }
171
+ // Onload handler for IE and Opera
172
+ else {
173
+ // In browsers that allow the onload event on link tags, just use it
174
+ link.onload = function () {
175
+ if ( ! done ) {
176
+ // Set our flag to complete
177
+ done = 1;
178
+ // Check to see if we can call the callback
179
+ sTimeout( function () {
180
+ execWhenReady();
181
+ }, 0 );
182
+ }
183
+ };
184
+
185
+ // if we shouldn't inject due to error or settings, just call this right away
186
+ oldObj.e && link.onload();
187
+ }
188
+
189
+ // 404 Fallback
190
+ sTimeout( function () {
191
+ if ( ! done ) {
192
+ done = 1;
193
+ execWhenReady();
194
+ }
195
+ }, yepnope.errorTimeout );
196
+
197
+ // Inject CSS
198
+ // only inject if there are no errors, and we didn't set the no inject flag ( oldObj.e )
199
+ ! oldObj.e && firstScript.parentNode.insertBefore( link, firstScript );
200
+ }
201
+
202
+ function executeStack ( ) {
203
+ // shift an element off of the stack
204
+ var i = execStack.shift();
205
+ started = 1;
206
+
207
+ // if a is truthy and the first item in the stack has an src
208
+ if ( i ) {
209
+ // if it's a script, inject it into the head with no type attribute
210
+ if ( i.t ) {
211
+ // Inject after a timeout so FF has time to be a jerk about it and
212
+ // not double load (ignore the cache)
213
+ sTimeout( function () {
214
+ i.t == 'c' ? injectCss( i ) : injectJs( i );
215
+ }, 0 );
216
+ }
217
+ // Otherwise, just call the function and potentially run the stack
218
+ else {
219
+ i();
220
+ execWhenReady();
221
+ }
222
+ }
223
+ else {
224
+ // just reset out of recursive mode
225
+ started = 0;
226
+ }
227
+ }
228
+
229
+ function preloadFile ( elem, url, type, splicePoint, docElement, dontExec ) {
230
+
231
+ // Create appropriate element for browser and type
232
+ var preloadElem = doc.createElement( elem ),
233
+ done = 0,
234
+ stackObject = {
235
+ t: type, // type
236
+ s: url, // src
237
+ //r: 0, // ready
238
+ e : dontExec // set to true if we don't want to reinject
239
+ };
240
+
241
+ function onload () {
242
+
243
+ // If the script/css file is loaded
244
+ if ( ! done && isFileReady( preloadElem.readyState ) ) {
245
+
246
+ // Set done to prevent this function from being called twice.
247
+ stackObject.r = done = 1;
248
+
249
+ ! started && execWhenReady();
250
+
251
+ // Handle memory leak in IE
252
+ preloadElem.onload = preloadElem.onreadystatechange = null;
253
+ sTimeout(function(){ insBeforeObj.removeChild( preloadElem ) }, 0);
254
+ }
255
+ }
256
+
257
+ // Just set the src and the data attributes so we don't have differentiate between elem types
258
+ preloadElem.src = preloadElem.data = url;
259
+
260
+ // Don't let it show up visually
261
+ ! isGeckoLTE18 && ( preloadElem.style.display = 'none' );
262
+ preloadElem.width = preloadElem.height = '0';
263
+
264
+
265
+ // Only if we have a type to add should we set the type attribute (a real script has no type)
266
+ if ( elem != 'object' ) {
267
+ preloadElem.type = type;
268
+ }
269
+
270
+ // Attach handlers for all browsers
271
+ preloadElem.onload = preloadElem.onreadystatechange = onload;
272
+
273
+ // If it's an image
274
+ if ( elem == 'img' ) {
275
+ // Use the onerror callback as the 'completed' indicator
276
+ preloadElem.onerror = onload;
277
+ }
278
+ // Otherwise, if it's a script element
279
+ else if ( elem == 'script' ) {
280
+ // handle errors on script elements when we can
281
+ preloadElem.onerror = function () {
282
+ stackObject.e = stackObject.r = 1;
283
+ executeStack();
284
+ };
285
+ }
286
+
287
+ // inject the element into the stack depending on if it's
288
+ // in the middle of other scripts or not
289
+ execStack.splice( splicePoint, 0, stackObject );
290
+
291
+ // The only place these can't go is in the <head> element, since objects won't load in there
292
+ // so we have two options - insert before the head element (which is hard to assume) - or
293
+ // insertBefore technically takes null/undefined as a second param and it will insert the element into
294
+ // the parent last. We try the head, and it automatically falls back to undefined.
295
+ insBeforeObj.insertBefore( preloadElem, isGeckoLTE18 ? null : firstScript );
296
+
297
+ // If something fails, and onerror doesn't fire,
298
+ // continue after a timeout.
299
+ sTimeout( function () {
300
+ if ( ! done ) {
301
+ // Remove the node from the dom
302
+ insBeforeObj.removeChild( preloadElem );
303
+ // Set it to ready to move on
304
+ // indicate that this had a timeout error on our stack object
305
+ stackObject.r = stackObject.e = done = 1;
306
+ // Continue on
307
+ execWhenReady();
308
+ }
309
+ }, yepnope.errorTimeout );
310
+ }
311
+
312
+ function load ( resource, type, dontExec ) {
313
+
314
+ var elem = ( type == 'c' ? strCssElem : strJsElem );
315
+
316
+ // If this method gets hit multiple times, we should flag
317
+ // that the execution of other threads should halt.
318
+ started = 0;
319
+
320
+ // We'll do 'j' for js and 'c' for css, yay for unreadable minification tactics
321
+ type = type || 'j';
322
+ if ( isString( resource ) ) {
323
+ // if the resource passed in here is a string, preload the file
324
+ preloadFile( elem, resource, type, this.i++, docElement, dontExec );
325
+ } else {
326
+ // Otherwise it's a resource object and we can splice it into the app at the current location
327
+ execStack.splice( this.i++, 0, resource );
328
+ execStack.length == 1 && executeStack();
329
+ }
330
+
331
+ // OMG is this jQueries? For chaining...
332
+ return this;
333
+ }
334
+
335
+ // return the yepnope object with a fresh loader attached
336
+ function getYepnope () {
337
+ var y = yepnope;
338
+ y.loader = {
339
+ load: load,
340
+ i : 0
341
+ };
342
+ return y;
343
+ }
344
+
345
+ /* End loader helper functions */
346
+ // Yepnope Function
347
+ yepnope = function ( needs ) {
348
+
349
+ var i,
350
+ need,
351
+ // start the chain as a plain instance
352
+ chain = this.yepnope.loader;
353
+
354
+ function satisfyPrefixes ( url ) {
355
+ // split all prefixes out
356
+ var parts = url.split( '!' ),
357
+ gLen = globalFilters.length,
358
+ origUrl = parts.pop(),
359
+ pLen = parts.length,
360
+ res = {
361
+ url : origUrl,
362
+ // keep this one static for callback variable consistency
363
+ origUrl : origUrl,
364
+ prefixes : parts
365
+ },
366
+ mFunc,
367
+ j;
368
+
369
+ // loop through prefixes
370
+ // if there are none, this automatically gets skipped
371
+ for ( j = 0; j < pLen; j++ ) {
372
+ mFunc = prefixes[ parts[ j ] ];
373
+ if ( mFunc ) {
374
+ res = mFunc( res );
375
+ }
376
+ }
377
+
378
+ // Go through our global filters
379
+ for ( j = 0; j < gLen; j++ ) {
380
+ res = globalFilters[ j ]( res );
381
+ }
382
+
383
+ // return the final url
384
+ return res;
385
+ }
386
+
387
+ function loadScriptOrStyle ( input, callback, chain, index, testResult ) {
388
+ // run through our set of prefixes
389
+ var resource = satisfyPrefixes( input ),
390
+ autoCallback = resource.autoCallback;
391
+
392
+ // if no object is returned or the url is empty/0 just exit the load
393
+ if ( resource.bypass ) {
394
+ return;
395
+ }
396
+
397
+ // Determine callback, if any
398
+ if ( callback ) {
399
+ callback = isFunction( callback ) ? callback : callback[ input ] || callback[ index ] || callback[ ( input.split( '/' ).pop().split( '?' )[ 0 ] ) ];
400
+ }
401
+
402
+ // if someone is overriding all normal functionality
403
+ if ( resource.instead ) {
404
+ return resource.instead( input, callback, chain, index, testResult );
405
+ }
406
+ else {
407
+
408
+ chain.load( resource.url, ( ( resource.forceCSS || ( ! resource.forceJS && /css$/.test( resource.url ) ) ) ) ? 'c' : undef, resource.noexec );
409
+
410
+ // If we have a callback, we'll start the chain over
411
+ if ( isFunction( callback ) || isFunction( autoCallback ) ) {
412
+ // Call getJS with our current stack of things
413
+ chain.load( function () {
414
+ // Hijack yepnope and restart index counter
415
+ getYepnope();
416
+ // Call our callbacks with this set of data
417
+ callback && callback( resource.origUrl, testResult, index );
418
+ autoCallback && autoCallback( resource.origUrl, testResult, index );
419
+ } );
420
+ }
421
+ }
422
+ }
423
+
424
+ function loadFromTestObject ( testObject, chain ) {
425
+ var testResult = !! testObject.test,
426
+ group = testResult ? testObject.yep : testObject.nope,
427
+ always = testObject.load || testObject.both,
428
+ callback = testObject.callback,
429
+ callbackKey;
430
+
431
+ // Reusable function for dealing with the different input types
432
+ // NOTE:: relies on closures to keep 'chain' up to date, a bit confusing, but
433
+ // much smaller than the functional equivalent in this case.
434
+ function handleGroup ( needGroup ) {
435
+ // If it's a string
436
+ if ( isString( needGroup ) ) {
437
+ // Just load the script of style
438
+ loadScriptOrStyle( needGroup, callback, chain, 0, testResult );
439
+ }
440
+ // See if we have an object. Doesn't matter if it's an array or a key/val hash
441
+ // Note:: order cannot be guaranteed on an key value object with multiple elements
442
+ // since the for-in does not preserve order. Arrays _should_ go in order though.
443
+ else if ( isObject( needGroup ) ) {
444
+ for ( callbackKey in needGroup ) {
445
+ // Safari 2 does not have hasOwnProperty, but not worth the bytes for a shim
446
+ // patch if needed. Kangax has a nice shim for it. Or just remove the check
447
+ // and promise not to extend the object prototype.
448
+ if ( needGroup.hasOwnProperty( callbackKey ) ) {
449
+ loadScriptOrStyle( needGroup[ callbackKey ], callback, chain, callbackKey, testResult );
450
+ }
451
+ }
452
+ }
453
+ }
454
+
455
+ // figure out what this group should do
456
+ handleGroup( group );
457
+
458
+ // Run our loader on the load/both group too
459
+ handleGroup( always );
460
+
461
+ // Fire complete callback
462
+ if ( testObject.complete ) {
463
+ chain.load( testObject.complete );
464
+ }
465
+
466
+ }
467
+
468
+ // Someone just decides to load a single script or css file as a string
469
+ if ( isString( needs ) ) {
470
+ loadScriptOrStyle( needs, 0, chain, 0 );
471
+ }
472
+ // Normal case is likely an array of different types of loading options
473
+ else if ( isArray( needs ) ) {
474
+ // go through the list of needs
475
+ for( i = 0; i < needs.length; i++ ) {
476
+ need = needs[ i ];
477
+
478
+ // if it's a string, just load it
479
+ if ( isString( need ) ) {
480
+ loadScriptOrStyle( need, 0, chain, 0 );
481
+ }
482
+ // if it's an array, call our function recursively
483
+ else if ( isArray( need ) ) {
484
+ yepnope( need );
485
+ }
486
+ // if it's an object, use our modernizr logic to win
487
+ else if ( isObject( need ) ) {
488
+ loadFromTestObject( need, chain );
489
+ }
490
+ }
491
+ }
492
+ // Allow a single object to be passed in
493
+ else if ( isObject( needs ) ) {
494
+ loadFromTestObject( needs, chain );
495
+ }
496
+ };
497
+
498
+ // This publicly exposed function is for allowing
499
+ // you to add functionality based on prefixes on the
500
+ // string files you add. 'css!' is a builtin prefix
501
+ //
502
+ // The arguments are the prefix (not including the !) as a string
503
+ // and
504
+ // A callback function. This function is passed a resource object
505
+ // that can be manipulated and then returned. (like middleware. har.)
506
+ //
507
+ // Examples of this can be seen in the officially supported ie prefix
508
+ yepnope.addPrefix = function ( prefix, callback ) {
509
+ prefixes[ prefix ] = callback;
510
+ };
511
+
512
+ // A filter is a global function that every resource
513
+ // object that passes through yepnope will see. You can
514
+ // of course conditionally choose to modify the resource objects
515
+ // or just pass them along. The filter function takes the resource
516
+ // object and is expected to return one.
517
+ //
518
+ // The best example of a filter is the 'autoprotocol' officially
519
+ // supported filter
520
+ yepnope.addFilter = function ( filter ) {
521
+ globalFilters.push( filter );
522
+ };
523
+
524
+ // Default error timeout to 10sec - modify to alter
525
+ yepnope.errorTimeout = 1e4;
526
+
527
+ // Webreflection readystate hack
528
+ // safe for jQuery 1.4+ ( i.e. don't use yepnope with jQuery 1.3.2 )
529
+ // if the readyState is null and we have a listener
530
+ if ( doc.readyState == null && doc.addEventListener ) {
531
+ // set the ready state to loading
532
+ doc.readyState = 'loading';
533
+ // call the listener
534
+ doc.addEventListener( 'DOMContentLoaded', handler = function () {
535
+ // Remove the listener
536
+ doc.removeEventListener( 'DOMContentLoaded', handler, 0 );
537
+ // Set it to ready
538
+ doc.readyState = 'complete';
539
+ }, 0 );
540
+ }
541
+
542
+ // Attach loader &
543
+ // Leak it
544
+ window.yepnope = getYepnope();
545
+
546
+ } )( this, this.document );
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: isc_analytics
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.5'
4
+ version: 0.5.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -81,6 +81,11 @@ files:
81
81
  - lib/isc_analytics/services.rb
82
82
  - lib/isc_analytics/tags.rb
83
83
  - lib/isc_analytics.rb
84
+ - vendor/assets/javascripts/isc_analytics/session/index.js
85
+ - vendor/assets/javascripts/isc_analytics/session/session-0.4.js
86
+ - vendor/assets/javascripts/isc_analytics/yepnope/css_prefix.js
87
+ - vendor/assets/javascripts/isc_analytics/yepnope/index.js
88
+ - vendor/assets/javascripts/isc_analytics/yepnope/yepnope.js
84
89
  - Rakefile
85
90
  - Gemfile
86
91
  - README.md