PageRenderTime 44ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/ajax/libs/gas/1.3.5/gas.core.js

https://gitlab.com/Mirros/cdnjs
JavaScript | 503 lines | 288 code | 38 blank | 177 comment | 65 complexity | 5454ae85fdd70397cdfc8f238a58d7ed MD5 | raw file
  1. /**
  2. * @preserve Copyright 2011, Cardinal Path and Direct Performance.
  3. *
  4. * GAS - Google Analytics on Steroids
  5. * https://bitbucket.org/dpc/gas
  6. *
  7. * @author Eduardo Cereto <eduardocereto@gmail.com>
  8. * Licensed under the MIT license.
  9. */
  10. (function(window, undefined) {
  11. /**
  12. * GAS - Google Analytics on Steroids
  13. *
  14. * Helper Functions
  15. *
  16. * Copyright 2011, Cardinal Path and Direct Performance
  17. * Licensed under the MIT license.
  18. *
  19. * @author Eduardo Cereto <eduardocereto@gmail.com>
  20. */
  21. /**
  22. * GasHelper singleton class
  23. *
  24. * Should be called when ga.js is loaded to get the pageTracker.
  25. *
  26. * @constructor
  27. */
  28. var GasHelper = function() {
  29. this._setDummyTracker();
  30. };
  31. GasHelper.prototype._setDummyTracker = function() {
  32. if (!this['tracker']) {
  33. var trackers = window['_gat']['_getTrackers']();
  34. if (trackers.length > 0) {
  35. this['tracker'] = trackers[0];
  36. }
  37. }
  38. };
  39. /**
  40. * Returns true if the element is found in the Array, false otherwise.
  41. *
  42. * @param {Array} obj Array to search at.
  43. * @param {object} item Item to search form.
  44. * @return {boolean} true if contains.
  45. */
  46. GasHelper.prototype.inArray = function(obj, item) {
  47. if (obj && obj.length) {
  48. for (var i = 0; i < obj.length; i++) {
  49. if (obj[i] === item) {
  50. return true;
  51. }
  52. }
  53. }
  54. return false;
  55. };
  56. /**
  57. * Checks if the object is an Array
  58. *
  59. * @param {object} obj Object to check.
  60. * @return {boolean} true if the object is an Array.
  61. */
  62. GasHelper.prototype.isArray = function(obj) {
  63. return toString.call(obj) === '[object Array]';
  64. };
  65. /**
  66. * Removes special characters and Lowercase String
  67. *
  68. * @param {string} str to be sanitized.
  69. * @param {boolean} strict_opt If we should remove any non ascii char.
  70. * @return {string} Sanitized string.
  71. */
  72. GasHelper.prototype._sanitizeString = function(str, strict_opt) {
  73. str = str.toLowerCase()
  74. .replace(/^\ +/, '')
  75. .replace(/\ +$/, '')
  76. .replace(/\s+/g, '_')
  77. .replace(/[áàâãåäæª]/g, 'a')
  78. .replace(/[éèêëЄ]/g, 'e')
  79. .replace(/[íìîï]/g, 'i')
  80. .replace(/[óòôõöøº]/g, 'o')
  81. .replace(/[úùûü]/g, 'u')
  82. .replace(/[碩]/g, 'c');
  83. if (strict_opt) {
  84. str = str.replace(/[^a-z0-9_-]/g, '_');
  85. }
  86. return str.replace(/_+/g, '_');
  87. };
  88. /**
  89. * Cross Browser helper to addEventListener.
  90. *
  91. * ga_next.js currently have a _addEventListener directive. So _gas will
  92. * allways prefer that if available, and will use this one only as a fallback
  93. *
  94. * @param {HTMLElement} obj The Element to attach event to.
  95. * @param {string} evt The event that will trigger the binded function.
  96. * @param {function(event)} ofnc The function to bind to the element.
  97. * @param {boolean} bubble true if event should be fired at bubble phase.
  98. * Defaults to false. Works only on W3C compliant browser. MSFT don't support
  99. * it.
  100. * @return {boolean} true if it was successfuly binded.
  101. */
  102. GasHelper.prototype._addEventListener = function(obj, evt, ofnc, bubble) {
  103. var fnc = function(event) {
  104. if (!event || !event.target) {
  105. event = window.event;
  106. event.target = event.srcElement;
  107. }
  108. return ofnc.call(obj, event);
  109. };
  110. // W3C model
  111. if (obj.addEventListener) {
  112. obj.addEventListener(evt, fnc, !!bubble);
  113. return true;
  114. }
  115. // M$ft model
  116. else if (obj.attachEvent) {
  117. return obj.attachEvent('on' + evt, fnc);
  118. }
  119. // Browser doesn't support W3C or M$ft model. Time to go old school
  120. else {
  121. evt = 'on' + evt;
  122. if (typeof obj[evt] === 'function') {
  123. // Object already has a function on traditional
  124. // Let's wrap it with our own function inside another function
  125. fnc = (function(f1, f2) {
  126. return function() {
  127. f1.apply(this, arguments);
  128. f2.apply(this, arguments);
  129. }
  130. })(obj[evt], fnc);
  131. }
  132. obj[evt] = fnc;
  133. return true;
  134. }
  135. };
  136. /**
  137. * Cross Browser Helper to emulate jQuery.live
  138. *
  139. * Binds to the document root. Listens to all events of the specific type.
  140. * If event don't bubble it won't catch
  141. */
  142. GasHelper.prototype._liveEvent = function(tag, evt, ofunc) {
  143. var gh = this;
  144. tag = tag.toUpperCase();
  145. tag = tag.split(',');
  146. gh._addEventListener(document, evt, function(me) {
  147. for (var el = me.srcElement; el.nodeName !== 'HTML';
  148. el = el.parentNode)
  149. {
  150. if (gh.inArray(tag, el.nodeName) || el.parentNode === null) {
  151. break;
  152. }
  153. }
  154. if (el && gh.inArray(tag, el.nodeName)) {
  155. ofunc.call(el, me);
  156. }
  157. }, true);
  158. };
  159. /**
  160. * Cross Browser DomReady function.
  161. *
  162. * Inspired by: http://dean.edwards.name/weblog/2006/06/again/#comment367184
  163. *
  164. * @param {function(Event)} callback DOMReady callback.
  165. * @return {boolean} Ignore return value.
  166. */
  167. GasHelper.prototype._DOMReady = function(callback) {
  168. var scp = this;
  169. var cb = function() {
  170. if (arguments.callee.done) return;
  171. arguments.callee.done = true;
  172. callback.apply(scp, arguments);
  173. };
  174. if (/^(interactive|complete)/.test(document.readyState)) return cb();
  175. this._addEventListener(document, 'DOMContentLoaded', cb, false);
  176. this._addEventListener(window, 'load', cb, false);
  177. };
  178. /**
  179. * GAS - Google Analytics on Steroids
  180. *
  181. * Copyright 2011, Cardinal Path and Direct Performance
  182. * Licensed under the MIT license.
  183. *
  184. * @author Eduardo Cereto <eduardocereto@gmail.com>
  185. */
  186. /**
  187. * Google Analytics original _gaq.
  188. *
  189. * This never tries to do something that is not supposed to. So it won't break
  190. * in the future.
  191. */
  192. window['_gaq'] = window['_gaq'] || [];
  193. var _prev_gas = window['_gas'] || [];
  194. // Avoid duplicate definition
  195. if (_prev_gas._accounts_length >= 0) {
  196. return;
  197. }
  198. //Shortcuts, these speed up and compress the code
  199. var document = window.document,
  200. toString = Object.prototype.toString,
  201. hasOwn = Object.prototype.hasOwnProperty,
  202. push = Array.prototype.push,
  203. slice = Array.prototype.slice,
  204. trim = String.prototype.trim,
  205. sindexOf = String.prototype.indexOf,
  206. aindexOf = Array.prototype.indexOf,
  207. url = document.location.href,
  208. documentElement = document.documentElement;
  209. /**
  210. * GAS Sigleton
  211. * @constructor
  212. */
  213. function GAS() {
  214. var self = this;
  215. self['version'] = '1.3.5';
  216. self._accounts = {};
  217. self._accounts_length = 0;
  218. self._queue = _prev_gas;
  219. self._default_tracker = '_gas1';
  220. self.gh = {};
  221. self._hooks = {
  222. '_addHook': [self._addHook]
  223. };
  224. // Need to be pushed to make sure tracker is done
  225. // Sets up helpers, very first thing pushed into gas
  226. self.push(function() {
  227. self.gh = new GasHelper();
  228. });
  229. }
  230. /**
  231. * First standard Hook that is responsible to add next Hooks
  232. *
  233. * _addHook calls always reurn false so they don't get pushed to _gaq
  234. * @param {string} fn The function you wish to add a Hook to.
  235. * @param {function()} cb The callback function to be appended to hooks.
  236. * @return {boolean} Always false.
  237. */
  238. GAS.prototype._addHook = function(fn, cb) {
  239. if (typeof fn === 'string' && typeof cb === 'function') {
  240. if (typeof _gas._hooks[fn] === 'undefined') {
  241. _gas._hooks[fn] = [];
  242. }
  243. _gas._hooks[fn].push(cb);
  244. }
  245. return false;
  246. };
  247. /**
  248. * Construct the correct account name to be used on _gaq calls.
  249. *
  250. * The account name for the first unamed account pushed to _gas is the standard
  251. * account name. It's pushed without the account name to _gaq, so if someone
  252. * calls directly _gaq it works as expected.
  253. * @param {string} acct Account name.
  254. * @return {string} Correct account name to be used already with trailling dot.
  255. */
  256. function _build_acct_name(acct) {
  257. return acct === _gas._default_tracker ? '' : acct + '.';
  258. }
  259. function _gaq_push(arr) {
  260. if (_gas.debug_mode) {
  261. try {
  262. console.log(arr);
  263. }catch (e) {}
  264. }
  265. return window['_gaq'].push(arr);
  266. }
  267. /**
  268. * Everything pushed to _gas is executed by this call.
  269. *
  270. * This function should not be called directly. Instead use _gas.push
  271. * @return {number} This is the same return as _gaq.push calls.
  272. */
  273. GAS.prototype._execute = function() {
  274. var args = slice.call(arguments),
  275. self = this,
  276. sub = args.shift(),
  277. gaq_execute = true,
  278. i, foo, hooks, acct_name, repl_sub, return_val = 0;
  279. if (typeof sub === 'function') {
  280. // Pushed functions are executed right away
  281. return _gaq_push(
  282. (function(s, gh) {
  283. return function() {
  284. // pushed functions receive helpers through this object
  285. s.call(gh);
  286. };
  287. })(sub, self.gh)
  288. );
  289. }else if (typeof sub === 'object' && sub.length > 0) {
  290. foo = sub.shift();
  291. if (sindexOf.call(foo, '.') >= 0) {
  292. acct_name = foo.split('.')[0];
  293. foo = foo.split('.')[1];
  294. }else {
  295. acct_name = undefined;
  296. }
  297. // Execute hooks
  298. hooks = self._hooks[foo];
  299. if (hooks && hooks.length > 0) {
  300. for (i = 0; i < hooks.length; i++) {
  301. try {
  302. repl_sub = hooks[i].apply(self.gh, sub);
  303. if (repl_sub === false) {
  304. // Returning false from a hook cancel the call
  305. gaq_execute = false;
  306. }else {
  307. if (repl_sub && repl_sub.length > 0) {
  308. // Returning an array changes the call parameters
  309. sub = repl_sub;
  310. }
  311. }
  312. }catch (e) {
  313. if (foo !== '_trackException') {
  314. self.push(['_trackException', e]);
  315. }
  316. }
  317. }
  318. }
  319. // Cancel execution on _gaq if any hook returned false
  320. if (gaq_execute === false) {
  321. return 1;
  322. }
  323. // Intercept _setAccount calls
  324. if (foo === '_setAccount') {
  325. for (i in self._accounts) {
  326. if (self._accounts[i] == sub[0]) {
  327. // Repeated account
  328. if (acct_name === undefined) {
  329. return 1;
  330. }
  331. }
  332. }
  333. acct_name = acct_name || '_gas' +
  334. String(self._accounts_length + 1);
  335. // Force that the first unamed account is _gas1
  336. if (typeof self._accounts['_gas1'] == 'undefined' &&
  337. sindexOf.call(acct_name, '_gas') != -1) {
  338. acct_name = '_gas1';
  339. }
  340. self._accounts[acct_name] = sub[0];
  341. self._accounts_length += 1;
  342. acct_name = _build_acct_name(acct_name);
  343. return_val = _gaq_push([acct_name + foo, sub[0]]);
  344. // Must try t get the tracker if it's a _setAccount
  345. self.gh._setDummyTracker();
  346. return return_val;
  347. }
  348. // Intercept _linka and _linkByPost
  349. if (foo === '_link' || foo === '_linkByPost') {
  350. args = slice.call(sub);
  351. args.unshift(foo);
  352. return _gaq_push(args);
  353. }
  354. // If user provides account than trigger event for just that account.
  355. var acc_foo;
  356. if (acct_name && self._accounts[acct_name]) {
  357. acc_foo = _build_acct_name(acct_name) + foo;
  358. args = slice.call(sub);
  359. args.unshift(acc_foo);
  360. return _gaq_push(args);
  361. }
  362. // Call Original _gaq, for all accounts
  363. for (i in self._accounts) {
  364. if (hasOwn.call(self._accounts, i)) {
  365. acc_foo = _build_acct_name(i) + foo;
  366. args = slice.call(sub);
  367. args.unshift(acc_foo);
  368. return_val += _gaq_push(args);
  369. }
  370. }
  371. return return_val ? 1 : 0;
  372. }
  373. };
  374. /**
  375. * Standard method to execute GA commands.
  376. *
  377. * Everything pushed to _gas is in fact pushed back to _gaq. So Helpers are
  378. * ready for hooks. This creates _gaq as a series of functions that call
  379. * _gas._execute() with the same arguments.
  380. */
  381. GAS.prototype.push = function() {
  382. var self = this;
  383. var args = slice.call(arguments);
  384. for (var i = 0; i < args.length; i++) {
  385. (function(arr, self) {
  386. window['_gaq'].push(function() {
  387. self._execute.call(self, arr);
  388. });
  389. })(args[i], self);
  390. }
  391. };
  392. /**
  393. * _gas main object.
  394. *
  395. * It's supposed to be used just like _gaq but here we extend it. In it's core
  396. * everything pushed to _gas is run through possible hooks and then pushed to
  397. * _gaq
  398. */
  399. window['_gas'] = _gas = new GAS();
  400. /**
  401. * Hook for _trackException
  402. *
  403. * Watchout for circular calls
  404. */
  405. _gas.push(['_addHook', '_trackException', function(exception, message) {
  406. _gas.push(['_trackEvent',
  407. 'Exception ' + (exception.name || 'Error'),
  408. message || exception.message || exception,
  409. url
  410. ]);
  411. return false;
  412. }]);
  413. /**
  414. * Hook to enable Debug Mode
  415. */
  416. _gas.push(['_addHook', '_setDebug', function(set_debug) {
  417. _gas.debug_mode = !!set_debug;
  418. }]);
  419. /**
  420. * Hook to Remove other Hooks
  421. *
  422. * It will remove the last inserted hook from a _gas function.
  423. *
  424. * @param {string} func _gas Function Name to remove Hooks from.
  425. * @return {boolean} Always returns false.
  426. */
  427. _gas.push(['_addHook', '_popHook', function(func) {
  428. var arr = _gas._hooks[func];
  429. if (arr && arr.pop) {
  430. arr.pop();
  431. }
  432. return false;
  433. }]);
  434. /**
  435. * Hook to set the default tracker.
  436. *
  437. * The default tracker is the nameless tracker that is pushed into _gaq_push
  438. */
  439. _gas.push(['_addHook', '_setDefaultTracker', function(tname) {
  440. _gas._default_tracker = tname;
  441. }]);
  442. /**
  443. * Wrap-up
  444. */
  445. // Execute previous functions
  446. while (_gas._queue.length > 0) {
  447. _gas.push(_gas._queue.shift());
  448. }
  449. // Import ga.js
  450. if (_gaq && _gaq.length >= 0) {
  451. (function() {
  452. var ga = document.createElement('script');
  453. ga.type = 'text/javascript';
  454. ga.async = true;
  455. ga.src = (
  456. 'https:' == document.location.protocol ?
  457. 'https://ssl' :
  458. 'http://www'
  459. ) +
  460. '.google-analytics.com/ga.js';
  461. var s = document.getElementsByTagName('script')[0];
  462. s.parentNode.insertBefore(ga, s);
  463. })();
  464. }
  465. })(window);