PageSourceSearch

https://ui.cgtn.com/static/public/vendor/intersection-observer.js

js cgtn.com collected 2026-09-24 08:24:19 UTC 26,890 bytes, 914 lines download raw bytes

1/**
2 * Copyright 2016 Google Inc. All Rights Reserved.
3 *
4 * Licensed under the W3C SOFTWARE AND DOCUMENT NOTICE AND LICENSE.
5 *
6 *  https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
7 *
8 */
9
10(function(window, document) {
11'use strict';
12
13// Exits early if all IntersectionObserver and IntersectionObserverEntry
14// features are natively supported.
15if ('IntersectionObserver' in window &&
16    'IntersectionObserverEntry' in window &&
17    'intersectionRatio' in window.IntersectionObserverEntry.prototype) {
18
19  // Minimal polyfill for Edge 15's lack of `isIntersecting`
20  // See: https://github.com/w3c/IntersectionObserver/issues/211
21  if (!('isIntersecting' in window.IntersectionObserverEntry.prototype)) {
22    Object.defineProperty(window.IntersectionObserverEntry.prototype,
23      'isIntersecting', {
24      get: function () {
25        return this.intersectionRatio > 0;
26      }
27    });
28  }
29  return;
30}
31
32
33/**
34 * An IntersectionObserver registry. This registry exists to hold a strong
35 * reference to IntersectionObserver instances currently observering a target
36 * element. Without this registry, instances without another reference may be
37 * garbage collected.
38 */
39var registry = [];
40
41
42/**
43 * Creates the global IntersectionObserverEntry constructor.
44 * https://w3c.github.io/IntersectionObserver/#intersection-observer-entry
45 * @param {Object} entry A dictionary of instance properties.
46 * @constructor
47 */
48function IntersectionObserverEntry(entry) {
49  this.time = entry.time;
50  this.target = entry.target;
51  this.rootBounds = entry.rootBounds;
52  this.boundingClientRect = entry.boundingClientRect;
53  this.intersectionRect = entry.intersectionRect || getEmptyRect();
54  this.isIntersecting = !!entry.intersectionRect;
55
56  // Calculates the intersection ratio.
57  var targetRect = this.boundingClientRect;
58  var targetArea = targetRect.width * targetRect.height;
59  var intersectionRect = this.intersectionRect;
60  var intersectionArea = intersectionRect.width * intersectionRect.height;
61
62  // Sets intersection ratio.
63  if (targetArea) {
64    this.intersectionRatio = intersectionArea / targetArea;
65  } else {
66    // If area is zero and is intersecting, sets to 1, otherwise to 0
67    this.intersectionRatio = this.isIntersecting ? 1 : 0;
68  }
69}
70
71
72/**
73 * Creates the global IntersectionObserver constructor.
74 * https://w3c.github.io/IntersectionObserver/#intersection-observer-interface
75 * @param {Function} callback The function to be invoked after intersection
76 *     changes have queued. The function is not invoked if the queue has
77 *     been emptied by calling the `takeRecords` method.
78 * @param {Object=} opt_options Optional configuration options.
79 * @constructor
80 */
81function IntersectionObserver(callback, opt_options) {
82
83  var options = opt_options || {};
84
85  if (typeof callback != 'function') {
86    throw new Error('callback must be a function');
87  }
88
89  if (options.root && options.root.nodeType != 1) {
90    throw new Error('root must be an Element');
91  }
92
93  // Binds and throttles `this._checkForIntersections`.
94  this._checkForIntersections = throttle(
95      this._checkForIntersections.bind(this), this.THROTTLE_TIMEOUT);
96
97  // Private properties.
98  this._callback = callback;
99  this._observationTargets = [];
100  this._queuedEntries = [];
101  this._rootMarginValues = this._parseRootMargin(options.rootMargin);
102
103  // Public properties.
104  this.thresholds = this._initThresholds(options.threshold);
105  this.root = options.root || null;
106  this.rootMargin = this._rootMarginValues.map(function(margin) {
107    return margin.value + margin.unit;
108  }).join(' ');
109}
110
111
112/**
113 * The minimum interval within which the document will be checked for
114 * intersection changes.
115 */
116IntersectionObserver.prototype.THROTTLE_TIMEOUT = 100;
117
118
119/**
120 * The frequency in which the polyfill polls for intersection changes.
121 * this can be updated on a per instance basis and must be set prior to
122 * calling `observe` on the first target.
123 */
124IntersectionObserver.prototype.POLL_INTERVAL = null;
125
126/**
127 * Use a mutation observer on the root element
128 * to detect intersection changes.
129 */
130IntersectionObserver.prototype.USE_MUTATION_OBSERVER = true;
131
132
133/**
134 * Starts observing a target element for intersection changes based on
135 * the thresholds values.
136 * @param {Element} target The DOM element to observe.
137 */
138IntersectionObserver.prototype.observe = function(target) {
139  var isTargetAlreadyObserved = this._observationTargets.some(function(item) {
140    return item.element == target;
141  });
142
143  if (isTargetAlreadyObserved) {
144    return;
145  }
146
vendor: 2,303 bytes, lines 147-222
147  if (!(target && target.nodeType == 1)) {
148    throw new Error('target must be an Element');
149  }
150
151  this._registerInstance();
152  this._observationTargets.push({element: target, entry: null});
153  this._monitorIntersections();
154  this._checkForIntersections();
155};
156
157
158/**
159 * Stops observing a target element for intersection changes.
160 * @param {Element} target The DOM element to observe.
161 */
162IntersectionObserver.prototype.unobserve = function(target) {
163  this._observationTargets =
164      this._observationTargets.filter(function(item) {
165
166    return item.element != target;
167  });
168  if (!this._observationTargets.length) {
169    this._unmonitorIntersections();
170    this._unregisterInstance();
171  }
172};
173
174
175/**
176 * Stops observing all target elements for intersection changes.
177 */
178IntersectionObserver.prototype.disconnect = function() {
179  this._observationTargets = [];
180  this._unmonitorIntersections();
181  this._unregisterInstance();
182};
183
184
185/**
186 * Returns any queue entries that have not yet been reported to the
187 * callback and clears the queue. This can be used in conjunction with the
188 * callback to obtain the absolute most up-to-date intersection information.
189 * @return {Array} The currently queued entries.
190 */
191IntersectionObserver.prototype.takeRecords = function() {
192  var records = this._queuedEntries.slice();
193  this._queuedEntries = [];
194  return records;
195};
196
197
198/**
199 * Accepts the threshold value from the user configuration object and
200 * returns a sorted array of unique threshold values. If a value is not
201 * between 0 and 1 and error is thrown.
202 * @private
203 * @param {Array|number=} opt_threshold An optional threshold value or
204 *     a list of threshold values, defaulting to [0].
205 * @return {Array} A sorted list of unique and valid threshold values.
206 */
207IntersectionObserver.prototype._initThresholds = function(opt_threshold) {
208  var threshold = opt_threshold || [0];
209  if (!Array.isArray(threshold)) threshold = [threshold];
210
211  return threshold.sort().filter(function(t, i, a) {
212    if (typeof t != 'number' || isNaN(t) || t < 0 || t > 1) {
213      throw new Error('threshold must be a number between 0 and 1 inclusively');
214    }
215    return t !== a[i - 1];
216  });
217};
218
219
220/**
221 * Accepts the rootMargin value from the user configuration object
222 * and returns an array of the four margin values as an object c
222ontaining
223 * the value and unit properties. If any of the values are not properly
224 * formatted or use a unit other than px or %, and error is thrown.
225 * @private
226 * @param {string=} opt_rootMargin An optional rootMargin value,
227 *     defaulting to '0px'.
228 * @return {Array<Object>} An array of margin objects with the keys
229 *     value and unit.
230 */
231IntersectionObserver.prototype._parseRootMargin = function(opt_rootMargin) {
232  var marginString = opt_rootMargin || '0px';
233  var margins = marginString.split(/\s+/).map(function(margin) {
234    var parts = /^(-?\d*\.?\d+)(px|%)$/.exec(margin);
235    if (!parts) {
236      throw new Error('rootMargin must be specified in pixels or percent');
237    }
238    return {value: parseFloat(parts[1]), unit: parts[2]};
239  });
240
241  // Handles shorthand.
242  margins[1] = margins[1] || margins[0];
243  margins[2] = margins[2] || margins[0];
244  margins[3] = margins[3] || margins[1];
245
246  return margins;
247};
248
249
250/**
251 * Starts polling for intersection changes if the polling is not already
252 * happening, and if the page's visibilty state is visible.
253 * @private
254 */
255IntersectionObserver.prototype._monitorIntersections = function() {
256  if (!this._monitoringIntersections) {
257    this._monitoringIntersections = true;
258
259    // If a poll interval is set, use polling instead of listening to
260    // resize and scroll events or DOM mutations.
261    if (this.POLL_INTERVAL) {
262      this._monitoringInterval = setInterval(
263          this._checkForIntersections, this.POLL_INTERVAL);
264    }
265    else {
266      addEvent(window, 'resize', this._checkForIntersections, true);
267      addEvent(document, 'scroll', this._checkForIntersections, true);
268
269      if (this.USE_MUTATION_OBSERVER && 'MutationObserver' in window) {
270        this._domObserver = new MutationObserver(this._checkForIntersections);
271        this._domObserver.observe(document, {
272          attributes: true,
273          childList: true,
274          characterData: true,
275          subtree: true
276        });
277      }
278    }
279  }
280};
281
282
283/**
284 * Stops polling for intersection changes.
285 * @private
286 */
287IntersectionObserver.prototype._unmonitorIntersections = function() {
288  if (this._monitoringIntersections) {
289    this._monitoringIntersections = false;
290
291    clearInterval(this._monitoringInterval);
292    this._monitoringInterval = null;
293
294    removeEvent(window, 'resize', this._checkForIntersections, true);
295    removeEvent(document, 'scroll', this._checkForIntersections, true);
296
297    if (this._domObserver) {
298      this._domObserver.disconnect();
299      this._domObserver = null;
300    }
301  }
302};
303
304
305/**
306 * Scans each observation target for intersection changes and adds them
307 * to the internal entries queue. If new entries are found, it
308 * schedules the callback to be invoked.
309 * @private
310 */
311IntersectionObserver.prototype._checkForIntersections = function() {
312  var rootIsInDom = this._rootIsInDom();
313  var rootRect = rootIsInDom ? this._getRootRect() : getEmptyRect();
314  this._observationTargets.forEach(function(item) {
315    var target = item.element;
316    var targetRect = getBoundingClientRect(target);
317    var rootContainsTarget = this._rootContainsTarget(target);
318    var oldEntry = item.entry;
319    var intersectionRect = rootIsInDom && rootContainsTarget &&
320        this._computeTargetAndRootIntersection(target, rootRect);
321
322    var newEntry = item.entry = new IntersectionObserverEntry({
323      time: now(),
324      target: target,
325      boundingClientRect: targetRect,
326      rootBounds: rootRect,
327      intersectionRect: intersectionRect
328    });
329
330    if (!oldEntry) {
331      this._queuedEntries.push(newEntry);
332    } else if (rootIsInDom && rootContainsTarget) {
333      // If the new entry intersection ratio has crossed any of the
334      // thresholds, add a new entry.
335      if (this._hasCrossedThreshold(oldEntry, newEntry)) {
336        this._queuedEntries.push(newEntry);
337      }
338    } else {
339      // If the root is not in the DOM or target is not contained within
340      // root but the previous entry for this target had an intersection,
341      // add a new record indicating removal.
342      if (oldEntry && oldEntry.isIntersecting) {
343        this._queuedEntries.push(newEntry);
344      }
345    }
346  }, this);
347
348  if (this._queuedEntries.length) {
349    this._callback(this.takeRecords(), this);
350  }
351};
352
353
354/**
355 * Accepts a target and root rect computes the intersection between then
356 * following the algorithm in the spec.
357 * TODO(philipwalton): at this time clip-path is not considered.
358 * https://w3c.github.io/IntersectionObserver/#calculate-intersection-rect-algo
359 * @param {Element} target The target DOM element
360 * @param {Object} rootRect The bounding rect of the root after being
361 *     expanded by the rootMargin value.
362 * @return {?Object} The final intersection rect object or undefined if no
363 *     intersection is found.
364 * @private
365 */
366IntersectionObserver.prototype._computeTargetAndRootIntersection =
367    function(target, rootRect) {
368
369  // If the element isn't displayed, an intersection can't happen.
370  if (window.getComputedStyle(target).display  == 'none') return;
371
372  var targetRect = getBoundingClientRect(target);
373  var intersectionRect = targetRect;
374  var parent = getParentNode(target);
375  var atRoot = false;
vendor: 8,500 bytes, lines 376-652
376
377  while (!atRoot) {
378    var parentRect = null;
379    var parentComputedStyle = parent.nodeType == 1 ?
380        window.getComputedStyle(parent) : {};
381
382    // If the parent isn't displayed, an intersection can't happen.
383    if (parentComputedStyle.display == 'none') return;
384
385    if (parent == this.root || parent == document) {
386      atRoot = true;
387      parentRect = rootRect;
388    } else {
389      // If the element has a non-visible overflow, and it's not the <body>
390      // or <html> element, update the intersection rect.
391      // Note: <body> and <html> cannot be clipped to a rect that's not also
392      // the document rect, so no need to compute a new intersection.
393      if (parent != document.body &&
394          parent != document.documentElement &&
395          parentComputedStyle.overflow != 'visible') {
396        parentRect = getBoundingClientRect(parent);
397      }
398    }
399
400    // If either of the above conditionals set a new parentRect,
401    // calculate new intersection data.
402    if (parentRect) {
403      intersectionRect = computeRectIntersection(parentRect, intersectionRect);
404
405      if (!intersectionRect) break;
406    }
407    parent = getParentNode(parent);
408  }
409  return intersectionRect;
410};
411
412
413/**
414 * Returns the root rect after being expanded by the rootMargin value.
415 * @return {Object} The expanded root rect.
416 * @private
417 */
418IntersectionObserver.prototype._getRootRect = function() {
419  var rootRect;
420  if (this.root) {
421    rootRect = getBoundingClientRect(this.root);
422  } else {
423    // Use <html>/<body> instead of window since scroll bars affect size.
424    var html = document.documentElement;
425    var body = document.body;
426    rootRect = {
427      top: 0,
428      left: 0,
429      right: html.clientWidth || body.clientWidth,
430      width: html.clientWidth || body.clientWidth,
431      bottom: html.clientHeight || body.clientHeight,
432      height: html.clientHeight || body.clientHeight
433    };
434  }
435  return this._expandRectByRootMargin(rootRect);
436};
437
438
439/**
440 * Accepts a rect and expands it by the rootMargin value.
441 * @param {Object} rect The rect object to expand.
442 * @return {Object} The expanded rect.
443 * @private
444 */
445IntersectionObserver.prototype._expandRectByRootMargin = function(rect) {
446  var margins = this._rootMarginValues.map(function(margin, i) {
447    return margin.unit == 'px' ? margin.value :
448        margin.value * (i % 2 ? rect.width : rect.height) / 100;
449  });
450  var newRect = {
451    top: rect.top - margins[0],
452    right: rect.right + margins[1],
453    bottom: rect.bottom + margins[2],
454    left: rect.left - margins[3]
455  };
456  newRect.width = newRect.right - newRect.left;
457  newRect.height = newRect.bottom - newRect.top;
458
459  return newRect;
460};
461
462
463/**
464 * Accepts an old and new entry and returns true if at least one of the
465 * threshold values has been crossed.
466 * @param {?IntersectionObserverEntry} oldEntry The previous entry for a
467 *    particular target element or null if no previous entry exists.
468 * @param {IntersectionObserverEntry} newEntry The current entry for a
469 *    particular target element.
470 * @return {boolean} Returns true if a any threshold has been crossed.
471 * @private
472 */
473IntersectionObserver.prototype._hasCrossedThreshold =
474    function(oldEntry, newEntry) {
475
476  // To make comparing easier, an entry that has a ratio of 0
477  // but does not actually intersect is given a value of -1
478  var oldRatio = oldEntry && oldEntry.isIntersecting ?
479      oldEntry.intersectionRatio || 0 : -1;
480  var newRatio = newEntry.isIntersecting ?
481      newEntry.intersectionRatio || 0 : -1;
482
483  // Ignore unchanged ratios
484  if (oldRatio === newRatio) return;
485
486  for (var i = 0; i < this.thresholds.length; i++) {
487    var threshold = this.thresholds[i];
488
489    // Return true if an entry matches a threshold or if the new ratio
490    // and the old ratio are on the opposite sides of a threshold.
491    if (threshold == oldRatio || threshold == newRatio ||
492        threshold < oldRatio !== threshold < newRatio) {
493      return true;
494    }
495  }
496};
497
498
499/**
500 * Returns whether or not the root element is an element and is in the DOM.
501 * @return {boolean} True if the root element is an element and is in the DOM.
502 * @private
503 */
504IntersectionObserver.prototype._rootIsInDom = function() {
505  return !this.root || containsDeep(document, this.root);
506};
507
508
509/**
510 * Returns whether or not the target element is a child of root.
511 * @param {Element} target The target element to check.
512 * @return {boolean} True if the target element is a child of root.
513 * @private
514 */
515IntersectionObserver.prototype._rootContainsTarget = function(target) {
516  return containsDeep(this.root || document, target);
517};
518
519
520/**
521 * Adds the instance to the global IntersectionObserver registry if it isn't
522 * already present.
523 * @private
524 */
525IntersectionObserver.prototype._registerInstance = function() {
526  if (registry.indexOf(this) < 0) {
527    registry.push(this);
528  }
529};
530
531
532/**
533 * Removes the instance from the global IntersectionObserver registry.
534 * @private
535 */
536IntersectionObserver.prototype._unregisterInstance = function() {
537  var index = registry.indexOf(this);
538  if (index != -1) registry.splice(index, 1);
539};
540
541
542/**
543 * Returns the result of the performance.now() method or null in browsers
544 * that don't support the API.
545 * @return {number} The elapsed time since the page was requested.
546 */
547function now() {
548  return window.performance && performance.now && performance.now();
549}
550
551
552/**
553 * Throttles a function and delays its executiong, so it's only called at most
554 * once within a given time period.
555 * @param {Function} fn The function to throttle.
556 * @param {number} timeout The amount of time that must pass before the
557 *     function can be called again.
558 * @return {Function} The throttled function.
559 */
560function throttle(fn, timeout) {
561  var timer = null;
562  return function () {
563    if (!timer) {
564      timer = setTimeout(function() {
565        fn();
566        timer = null;
567      }, timeout);
568    }
569  };
570}
571
572
573/**
574 * Adds an event handler to a DOM node ensuring cross-browser compatibility.
575 * @param {Node} node The DOM node to add the event handler to.
576 * @param {string} event The event name.
577 * @param {Function} fn The event handler to add.
578 * @param {boolean} opt_useCapture Optionally adds the even to the capture
579 *     phase. Note: this only works in modern browsers.
580 */
581function addEvent(node, event, fn, opt_useCapture) {
582  if (typeof node.addEventListener == 'function') {
583    node.addEventListener(event, fn, opt_useCapture || false);
584  }
585  else if (typeof node.attachEvent == 'function' ) {
586    node.attachEvent('on'+event, fn);
587  }else if (typeof node.attachEvent == 'object'){
588    //chen edit, for ie8
589    window.attachEvent('on'+event, fn);
590  }
591}
592
593
594/**
595 * Removes a previously added event handler from a DOM node.
596 * @param {Node} node The DOM node to remove the event handler from.
597 * @param {string} event The event name.
598 * @param {Function} fn The event handler to remove.
599 * @param {boolean} opt_useCapture If the event handler was added with this
600 *     flag set to true, it should be set to true here in order to remove it.
601 */
602function removeEvent(node, event, fn, opt_useCapture) {
603  if (typeof node.removeEventListener == 'function') {
604    node.removeEventListener(event, fn, opt_useCapture || false);
605  }
606  else if (typeof node.detatchEvent == 'function') {
607    node.detatchEvent('on' + event, fn);
608  }else if (typeof node.detatchEvent == 'object'){
609    //chen edit, for ie8
610    window.detatchEvent('on'+event, fn);
611  }
612}
613
614
615/**
616 * Returns the intersection between two rect objects.
617 * @param {Object} rect1 The first rect.
618 * @param {Object} rect2 The second rect.
619 * @return {?Object} The intersection rect or undefined if no intersection
620 *     is found.
621 */
622function computeRectIntersection(rect1, rect2) {
623  var top = Math.max(rect1.top, rect2.top);
624  var bottom = Math.min(rect1.bottom, rect2.bottom);
625  var left = Math.max(rect1.left, rect2.left);
626  var right = Math.min(rect1.right, rect2.right);
627  var width = right - left;
628  var height = bottom - top;
629
630  return (width >= 0 && height >= 0) && {
631    top: top,
632    bottom: bottom,
633    left: left,
634    right: right,
635    width: width,
636    height: height
637  };
638}
639
640
641/**
642 * Shims the native getBoundingClientRect for compatibility with older IE.
643 * @param {Element} el The element whose bounding rect to get.
644 * @return {Object} The (possibly shimmed) rect of the element.
645 */
646function getBoundingClientRect(el) {
647  var rect;
648
649  try {
650    rect = el.getBoundingClientRect();
651  } catch (err) {
652    // Ignore Windows 7 IE11 "Unspecified error"
653    // https://github.com/w3c/IntersectionObserver/pull/205
654  }
655
656  if (!rect) return getEmptyRect();
657
658  // Older IE
659  if (!(rect.width && rect.height)) {
660    rect = {
661      top: rect.top,
662      right: rect.right,
663      bottom: rect.bottom,
664      left: rect.left,
665      width: rect.right - rect.left,
666      height: rect.bottom - rect.top
667    };
668  }
669  return rect;
670}
671
672
673/**
674 * Returns an empty rect object. An empty rect is returned when an element
675 * is not in the DOM.
676 * @return {Object} The empty rect.
677 */
678function getEmptyRect() {
679  return {
680    top: 0,
681    bottom: 0,
682    left: 0,
683    right: 0,
684    width: 0,
685    height: 0
686  };
687}
688
689/**
690 * Checks to see if a parent element contains a child elemnt (including inside
691 * shadow DOM).
692 * @param {Node} parent The parent element.
693 * @param {Node} child The child element.
694 * @return {boolean} True if the parent node contains the child node.
695 */
696function containsDeep(parent, child) {
697  var node = child;
698  while (node) {
699    if (node == parent) return true;
700
701    node = getParentNode(node);
702  }
703  return false;
704}
705
706
707/**
708 * Gets the parent node of an element or its host element if the parent node
709 * is a shadow root.
710 * @param {Node} node The node whose parent to get.
711 * @return {Node|null} The parent node or null if no parent exists.
712 */
713function getParentNode(node) {
714  var parent = node.parentNode;
715
716  if (parent && parent.nodeType == 11 && parent.host) {
717    // If the parent is a shadow root, return the host element.
718    return parent.host;
719  }
720  return parent;
721}
722
723
724// Exposes the constructors globally.
725window.IntersectionObserver = IntersectionObserver;
726window.IntersectionObserverEntry = IntersectionObserverEntry;
727
728}(window, document));
729
730(function(){
731  //ie8 bind
732  if (!Function.prototype.bind) {
733    Function.prototype.bind = function (oThis) {
734      if (typeof this !== "function") {
735        throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
736      }
737      var aArgs = Array.prototype.slice.call(arguments, 1),
738          fToBind = this,
739          fNOP = function () {},
740          fBound = function () {
741            return fToBind.apply(this instanceof fNOP && oThis
742                    ? this
743                    : oThis,
744                aArgs.concat(Array.prototype.slice.call(arguments)));
745          };
746      fNOP.prototype = this.prototype;
747      fBound.prototype = new fNOP();
748      return fBound;
749    };
750  }
751
752  //map
753  if (!Array.prototype.map) {
754    Array.prototype.map = function(callback, thisArg) {
755      var T, A, k;
756      if (this == null) {
757        throw new TypeError(" this is null or not defined");
758      }
759      var O = Object(this);
760      var len = O.length >>> 0;
761      if (typeof callback !== "function") {
762        throw new TypeError(callback + " is not a function");
763      }
764      if (thisArg) {
765        T = thisArg;
766      }
767      A = new Array(len);
768      k = 0;
769      while(k < len) {
770        var kValue, mappedValue;
771        if (k in O) {
772          kValue = O[ k ];
773          mappedValue = callback.call(T, kValue, k, O);
774          A[ k ] = mappedValue;
775        }
776        k++;
777      }
778      return A;
779    };
780  }
781
782  //ie8 isArray
783  if (!Array.isArray) {
784    Array.isArray = function(arg) {
785      return Object.prototype.toString.call(arg) === '[object Array]';
786    };
787  }
788
789  //ie8 filter
790  if (!Array.prototype.filter)
791  {
792    Array.prototype.filter = function(fun /*, thisp */)
793    {
794      "use strict";
795
796      if (this === void 0 || this === null)
797        throw new TypeError();
798
799      var t = Object(this);
800      var len = t.length >>> 0;
801      if (typeof fun !== "function")
802        throw new TypeError();
803
804      var res = [];
805      var thisp = arguments[1];
806      for (var i = 0; i < len; i++)
807      {
808        if (i in t)
809        {
810          var val = t[i]; // in case fun mutates this
811          if (fun.call(thisp, val, i, t))
812            res.push(val);
813        }
814      }
815
816      return res;
817    };
818  }
819
820  // Production steps of ECMA-262, Edition 5, 15.4.4.17
821// Reference: http://es5.github.io/#x15.4.4.17
822  if (!Array.prototype.some) {
823    Array.prototype.some = function(fun/*, thisArg*/) {
824      'use strict';
825
826      if (this == null) {
827        throw new TypeError('Array.prototype.some called on null or undefined');
828      }
829
830      if (typeof fun !== 'function') {
831        throw new TypeError();
832      }
833
834      var t = Object(this);
835      var len = t.length >>> 0;
836
837      var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
838      for (var i = 0; i < len; i++) {
839        if (i in t && fun.call(thisArg, t[i], i, t)) {
840          return true;
841        }
842      }
843
844      return false;
845    };
846  }
847
848  //添加数组IndexOf方法
849  if (!Array.prototype.indexOf){
850    Array.prototype.indexOf = function(elt /*, from*/){
851      var len = this.length >>> 0;
852
853      var from = Number(arguments[1]) || 0;
854      from = (from < 0)
855          ? Math.ceil(from)
856          : Math.floor(from);
857      if (from < 0)
858        from += len;
859
860      for (; from < len; from++){
861        if (from in this && this[from] === elt)
862          return from;
863      }
864      return -1;
865    };
866  }
867
868  if ( !Array.prototype.forEach ) {
869    Array.prototype.forEach = function forEach( callback, thisArg ) {
870      var T, k;
871      if ( this == null ) {
872        throw new TypeError( "this is null or not defined" );
873      }
874      var O = Object(this);
875      var len = O.length >>> 0;
876      if ( typeof callback !== "function" ) {
877        throw new TypeError( callback + " is not a function" );
878      }
879      if ( arguments.length > 1 ) {
880        T = thisArg;
881      }
882      k = 0;
883      while( k < len ) {
884        var kValue;
885        if ( k in O ) {
886          kValue = O[ k ];
887          callback.call( T, kValue, k, O );
888        }
889        k++;
890      }
891    };
892  }
893
894
895  if (!window.getComputedStyle) {
896    window.getComputedStyle = function(el, pseudo) {
897      this.el = el;
898      this.getPropertyValue = function(prop) {
899        var re = /(\-([a-z]){1})/g;
900        if (prop == 'float') prop = 'styleFloat';
901        if (re.test(prop)) {
902          prop = prop.replace(re, function () {
903            return arguments[2].toUpperCase();
904          });
905        }
906        return el.currentStyle[prop] ? el.currentStyle[prop] : null;
907      }
908      this.display = this.getPropertyValue('display');
909      this.overflow = this.getPropertyValue('overflow');
910      return this;
911    }
912  }
913
914}())

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.