PageSourceSearch

https://patrisser.com/Files/C_S_X%20History_Timeline_files/analytics.js.download

js patrisser.com collected 2026-10-03 22:39:04 UTC 15,130 bytes, 474 lines download raw bytes

1// @license  magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3.0
2/* eslint-disable no-var, semi, prefer-arrow-callback, prefer-template */
3
4/**
5 * Collection of methods for sending analytics events to Archive.org's analytics server.
6 *
7 * These events are used for internal stats and sent (in anonymized form) to Google Analytics.
8 *
9 * @see analytics.md
10 *
11 * @type {Object}
12 */
13window.archive_analytics = (function defineArchiveAnalytics() {
14  // keep orignal Date object so as not to be affected by wayback's
15  // hijacking global Date object
16  var Date = window.Date;
17  var ARCHIVE_ANALYTICS_VERSION = 2;
18  var DEFAULT_SERVICE = 'ao_2';
19  var NO_SAMPLING_SERVICE = 'ao_no_sampling'; // sends every event instead of a percentage
20
21  var startTime = new Date();
22
23  /**
24   * @return {Boolean}
25   */
26  function isPerformanceTimingApiSupported() {
27    return 'performance' in window && 'timing' in window.performance;
28  }
29
30  /**
31   * Determines how many milliseconds elapsed between the browser starting to parse the DOM and
32   * the current time.
33   *
34   * Uses the Performance API or a fallback value if it's not available.
35   *
36   * @see https://developer.mozilla.org/en-US/docs/Web/API/Performance_API
37   *
38   * @return {Number}
39   */
40  function getLoadTime() {
41    var start;
42
43    if (isPerformanceTimingApiSupported())
44      start = window.performance.timing.domLoading;
45    else
46      start = startTime.getTime();
47
48    return new Date().getTime() - start;
49  }
50
51  /**
52   * Determines how many milliseconds elapsed between the user navigating to the page and
53   * the current time.
54   *
55   * @see https://developer.mozilla.org/en-US/docs/Web/API/Performance_API
56   *
57   * @return {Number|null} null if the browser doesn't support the Performance API
58   */
59  function getNavToDoneTime() {
60    if (!isPerformanceTimingApiSupported())
61      return null;
62
63    return new Date().getTime() - window.performance.timing.navigationStart;
64  }
65
66  /**
67   * Performs an arithmetic calculation on a string with a number and unit, while maintaining
68   * the unit.
69   *
70   * @param {String} original value to modify, with a unit
71   * @param {Function} doOperation accepts one Number parameter, returns a Number
72   * @returns {String}
73   */
74  function computeWithUnit(original, doOperation) {
75    var number = parseFloat(original, 10);
76    var unit = original.replace(/(\d*\.\d+)|\d+/, '');
77
78    return doOperation(number) + unit;
79  }
80
81  /**
82   * Computes the default font size of the browser.
83   *
84   * @returns {String|null} computed font-size with units (typically pixels), null if it cannot be computed
85   */
86  function getDefaultFontSize() {
87    var fontSizeStr;
88
89    if (!('getComputedStyle' in window))
90      return null;
91
92    var style = window.getComputedStyle(document.documentElement);
93    if (!style)
94      return null;
95
96    fontSizeStr = style.fontSize;
97
98    // Don't modify the value if tracking book reader.
99    if (document.querySelector('#BookReader'))
100      return fontSizeStr;
101
102    return computeWithUnit(fontSizeStr, function reverseBootstrapFontSize(number) {
103      // Undo the 62.5% size applied in the Bootstrap CSS.
104      return number * 1.6;
105    });
106  }
107
108  /**
109   * Get the URL parameters for a given Location
110   * @param  {Location}
111   * @return {Object} The URL parameters
112   */
113  function getParams(location) {
114    if (!location) location = window.location;
115    var vars;
116    var i;
117    var pair;
118    var params = {};
119    var query = location.search;
120    if (!query) return params;
121    vars = query.substring(1).split('&');
122    for (i = 0; i < vars.length; i++) {
123      pair = vars[i].split('=');
124      params[pair[0]] = decodeURIComponent(pair[1]);
125    }
126    return params;
127  }
128
129  function getMetaProp(name) {
130    var metaTag = document.querySelector('meta[property=' + name + ']');
131    return metaTag ? metaTag.getAttribute('content') || null : null;
132  }
133
134  var ArchiveAnalytics = {
135    /**
136     * @type {String|null}
137     */
138    service: getMetaProp('service'),
139    mediaType: getMetaProp('mediatype'),
140    primaryCollection: getMetaProp('primary_collection'),
141
142    /**
143     * Key-value pairs to send in pageviews (you can read this after a pageview to see what was
144     * sent).
145     *
146     * @type {Object}
147     */
148    values: {},
149
150    /**
151     * Sends an analytics ping, preferably using navigator.sendBeacon()
152     * @param {Object}   values
153     * @param {Function} [onload_callback]      (deprecated) callback to invoke once ping to analytics server is done
154     * @param {Boolean}  [augment_for_ao_site]  (deprecated) if true, add some archive.org site-specific values
155     */
156    send_ping: function send_ping(values, onload_callback, augment_for_ao_site) {
157      if (typeof window.navigator !== 'undefined' && typeof window.navigator.sendBeacon !== 'undefined')
158        this.send_ping_via_beacon(values);
159      else
160        this.send_ping_via_image(values);
161    },
162
163    /**
164     * Sends a ping via Beacon API
165     * NOTE: Assumes window.navigator.sendBeacon exists
166     * @param {Object} values Tracking parameters to pass
167     */
168    send_ping_via_beacon: function send_ping_via_beacon(values) {
169      var url = this.generate_tracking_url(values || {});
170      window.navigator.sendBeacon(url);
171    },
172
173    /**
174     * Sends a ping via Image object
175     * @param {Object} values Tracking parameters to pass
176     */
177    send_ping_via_image: function send_ping_via_image(values) {
178      var url = this.generate_tracking_url(values || {});
179      var loadtime_img = new Image(1, 1);
180      loadtime_img.src = url;
181      loadtime_img.alt = '';
182    },
183
184    /**
185     * Construct complete tracking URL containing payload
186     * @param {Object} params Tracking parameters to pass
187     * @return {String} URL to use for tracking call
188     */
189    generate_tracking_url: function generate_tracking_url(params) {
190      var baseUrl = '//analytics.archive.org/0.gif';
191      var keys;
192      var outputParams = params;
193      var outputParamsArray = [];
194
195      outputParams.service = outputParams.service || this.service || DEFAULT_SERVICE;
196
197      // Build array of querystring parameters
198      keys = Object.keys(outputParams);
199      keys.forEach(function keyIteration(key) {
200        outputParamsArray.push(encodeURIComponent(key) + '=' + encodeURIComponent(outputParams[key]));
201      });
202      outputParamsArray.push('version=' + ARCHIVE_ANALYTICS_VERSION);
203      outputParamsArray.push('count=' + (keys.length + 2)); // Include `version` and `count` in count
204
205      return baseUrl + '?' + outputParamsArray.join('&');
206    },
207
208    /**
209     * @param {int} page Page number
210     */
211    send_scroll_fetch_event: function send_scroll_fetch_event(page) {
212      var additionalValues = { ev: page };
213      var loadTime = getLoadTime();
214      var navToDoneTime = getNavToDoneTime();
215      if (loadTime) additionalValues.loadtime = loadTime;
216      if (navToDoneTime) additionalValues.nav_to_done_ms = navToDoneTime;
217      this.send_event('page_action', 'scroll_fetch', location.pathname, additionalValues);
218    },
219
220    send_scroll_fetch_base_event: function send_scroll_fetch_base_event() {
221      var additionalValues = {};
222      var loadTime = getLoadTime();
223      var navToDoneTime = getNavToDoneTime();
224      if (loadTime) additionalValues.loadtime = loadTime;
225      if (navToDoneTime) additionalValues.nav_to_done_ms = navToDoneTime;
226      this.send_event('page_action', 'scroll_fetch_base', location.pathname, additionalValues);
227    },
228
229    /**
230     * @param {Object} [options]
231     * @param {String} [options.mediaType]
232     * @param {String} [options.mediaLanguage]
233     * @param {String} [options.page] The path portion of the page URL
234     */
235    send_pageview: function send_pageview(options) {
236      var settings = options || {};
237
238      var defaultFontSize;
239      var loadTime = getLoadTime();
240      var mediaType = settings.mediaType;
241      var primaryCollection = settings.primaryCollection;
242      var page = settings.page;
243      var navToDoneTime = getNavToDoneTime();
244
245      /**
246       * @return {String}
247       */
248      function get_locale() {
249        if (navigator) {
250          if (navigator.language)
251            return navigator.language;
252
253          else if (navigator.browserLanguage)
254            return navigator.browserLanguage;
255
256          else if (navigator.systemLanguage)
257            return navigator.systemLanguage;
258
259          else if (navigator.userLanguage)
260            return navigator.userLanguage;
261        }
262        return '';
263      }
264
265      defaultFontSize = getDefaultFontSize();
266
267      // Set field values
268      this.values.kind     = 'pageview';
269      this.values.timediff = (new Date().getTimezoneOffset()/60)*(-1); // *timezone* diff from UTC
270      this.values.locale   = get_locale();
271      this.values.referrer = (document.referrer == '' ? '-' : document.referrer);
272
273      if (loadTime)
274        this.values.loadtime = loadTime;
275
276      if (navToDoneTime)
277        this.values.nav_to_done_ms = navToDoneTime;
278
279      if (settings.trackingId) {
280        this.values.ga_tid = settings.trackingId;
281      }
282
283      /* START CUSTOM DIMENSIONS */
284      if (defaultFontSize)
285        this.values.iaprop_fontSize = defaultFontSize;
286
287      if ('devicePixelRatio' in window)
288        this.values.iaprop_devicePixelRatio = window.devicePixelRatio;
289
290      if (mediaType)
291        this.values.iaprop_mediaType = mediaType;
292
293      if (settings.mediaLanguage) {
294        this.values.iaprop_mediaLanguage = settings.mediaLanguage;
295      }
296
297      if (primaryCollection) {
298        this.values.iaprop_primaryCollection = primaryCollection;
299      }
300      /* END CUSTOM DIMENSIONS */
301
302      if (page)
303        this.values.page = page;
304
305      this.send_ping(this.values);
306    },
307
308    /**
309     * Sends a tracking "Event".
310     * @param {string} category
311     * @param {string} action
312     * @param {string} label
313     * @param {Object} additionalEventParams
314     */
315    send_event: function send_event(
316        category,
317        action,
318        label,
319        additionalEventParams
320    ) {
321      if (!label) label = window.location.pathname;
322      if (!additionalEventParams) additionalEventParams = {};
323      if (additionalEventParams.mediaLanguage) {
324        additionalEventParams.ga_cd4 = additionalEventParams.mediaLanguage;
325        delete additionalEventParams.mediaLanguage;
326      }
327      var eventParams = Object.assign(
328        {
329          kind: 'event',
330          ec: category,
331          ea: action,
332          el: label,
333          cache_bust: Math.random(),
334        },
335        additionalEventParams
336      );
337      this.send_ping(eventParams);
338    },
339
340    /**
341     * Sends every event instead of a small percentage.
342     *
343     * Use this sparingly as it can generate a lot of events.
344     *
345     * @param {string} category
346     * @param {string} action
347     * @param {string} label
348     * @param {Object}
348 additionalEventParams
349     */
350    send_event_no_sampling: function send_event_no_sampling(
351      category,
352      action,
353      label,
354      additionalEventParams
355    ) {
356      var extraParams = additionalEventParams || {};
357      extraParams.service = NO_SAMPLING_SERVICE;
358      this.send_event(category, action, label, extraParams);
359    },
360
361    /**
362     * @param {Object} options see this.send_pageview options
363     */
364    send_pageview_on_load: function send_pageview_on_load(options) {
365      var self = this;
366      window.addEventListener('load', function send_pageview_with_options() {
367        self.send_pageview(options);
368      });
369    },
370
371    /**
372     * Handles tracking events passed in URL.
373     * Assumes category and action values are separated by a "|" character.
374     * NOTE: Uses the unsampled analytics property. Watch out for future high click links!
375     * @param {Location}
376     */
377    process_url_events: function process_url_events(location) {
378      var eventValues;
379      var actionValue;
380      var eventValue = getParams(location).iax;
381      if (!eventValue) return;
382      eventValues = eventValue.split('|');
383      actionValue = eventValues.length >= 1 ? eventValues[1] : '';
384      this.send_event_no_sampling(
385        eventValues[0],
386        actionValue,
387        window.location.pathname
388      );
389    },
390
391    /**
392     * Attaches handlers for event tracking.
393     *
394     * To enable click tracking for a link, add a `data-event-click-tracking`
395     * attribute containing the Google Analytics Event Category and Action, separated
396     * by a vertical pipe (|).
397     * e.g. `<a href="foobar" data-event-click-tracking="TopNav|FooBar">`
398     *
399     * To enable form submit tracking, add a `data-event-form-tracking` attribute
400     * to the `form` tag.
401     * e.g. `<form data-event-form-tracking="TopNav|SearchForm" method="GET">`
402     *
403     * Additional tracking options can be added via a `data-event-tracking-options`
404     * parameter. This parameter, if included, should be a JSON string of the parameters.
405     * Valid parameters are:
406     * - service {string}: Corresponds to the Google Analytics property data values flow into
407     */
408    set_up_event_tracking: function set_up_event_tracking() {
409      var self = this;
410      var clickTrackingAttributeName = 'event-click-tracking';
411      var formTrackingAttributeName = 'event-form-tracking';
412      var trackingOptionsAttributeName = 'event-tracking-options';
413
414      function handleAction(event, attributeName) {
415        var selector = '[data-' + attributeName + ']';
416        var eventTarget = event.target;
417        if (!eventTarget) return;
418        var target = eventTarget.closest(selector);
419        if (!target) return;
420        var categoryAction;
421        var categoryActionParts;
422        var options;
423        categoryAction = target.dataset[toCamelCase(attributeName)];
424        if (!categoryAction) return;
425        categoryActionParts = categoryAction.split('|');
426        options = target.dataset[toCamelCase(trackingOptionsAttributeName)];
427        options = options ? JSON.parse(options) : {};
428        self.send_event(
429          categoryActionParts[0],
430          categoryActionParts[1],
431          categoryActionParts[2] || window.location.pathname,
432          options.service ? { service: options.service } : {}
433        );
434      }
435
436      function toCamelCase(str) {
437        return str.replace(/\W+(.)/g, function (match, chr) {
438          return chr.toUpperCase();
439        });
440      };
441
442      document.addEventListener('click', function(e) {
443        handleAction(e, clickTrackingAttributeName);
444      });
445
446      document.addEventListener('submit', function(e) {
447        handleAction(e, formTrackingAttributeName);
448      });
449    },
450
451    /**
452     * @returns {Object[]}
453     */
454    get_data_packets: function get_data_packets() {
455      return [this.values];
456    },
457
458    /**
459     * Creates a tracking image for tracking JS compatibility.
460     *
461     * @param {string} type The type value for track_js_case in query params for 0.gif
462     */
463    create_tracking_image: function create_tracking_image(type) {
464      this.send_ping_via_image({
465        cache_bust: Math.random(),
466        kind: 'track_js',
467        track_js_case: type,
468      });
469    }
470  };
471
472  return ArchiveAnalytics;
473}());
474// @license-end

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.