isc_analytics 0.5 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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