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.
- data/vendor/assets/javascripts/isc_analytics/session/index.js +1 -0
- data/vendor/assets/javascripts/isc_analytics/session/session-0.4.js +414 -0
- data/vendor/assets/javascripts/isc_analytics/yepnope/css_prefix.js +21 -0
- data/vendor/assets/javascripts/isc_analytics/yepnope/index.js +2 -0
- data/vendor/assets/javascripts/isc_analytics/yepnope/yepnope.js +546 -0
- metadata +6 -1
@@ -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,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:
|
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
|