Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/materialize-css/js/scrollspy.js')
-rw-r--r--node_modules/materialize-css/js/scrollspy.js295
1 files changed, 295 insertions, 0 deletions
diff --git a/node_modules/materialize-css/js/scrollspy.js b/node_modules/materialize-css/js/scrollspy.js
new file mode 100644
index 0000000000..5c085e5732
--- /dev/null
+++ b/node_modules/materialize-css/js/scrollspy.js
@@ -0,0 +1,295 @@
+(function($, anim) {
+ 'use strict';
+
+ let _defaults = {
+ throttle: 100,
+ scrollOffset: 200, // offset - 200 allows elements near bottom of page to scroll
+ activeClass: 'active',
+ getActiveElement: function(id) {
+ return 'a[href="#' + id + '"]';
+ }
+ };
+
+ /**
+ * @class
+ *
+ */
+ class ScrollSpy extends Component {
+ /**
+ * Construct ScrollSpy instance
+ * @constructor
+ * @param {Element} el
+ * @param {Object} options
+ */
+ constructor(el, options) {
+ super(ScrollSpy, el, options);
+
+ this.el.M_ScrollSpy = this;
+
+ /**
+ * Options for the modal
+ * @member Modal#options
+ * @prop {Number} [throttle=100] - Throttle of scroll handler
+ * @prop {Number} [scrollOffset=200] - Offset for centering element when scrolled to
+ * @prop {String} [activeClass='active'] - Class applied to active elements
+ * @prop {Function} [getActiveElement] - Used to find active element
+ */
+ this.options = $.extend({}, ScrollSpy.defaults, options);
+
+ // setup
+ ScrollSpy._elements.push(this);
+ ScrollSpy._count++;
+ ScrollSpy._increment++;
+ this.tickId = -1;
+ this.id = ScrollSpy._increment;
+ this._setupEventHandlers();
+ this._handleWindowScroll();
+ }
+
+ static get defaults() {
+ return _defaults;
+ }
+
+ static init(els, options) {
+ return super.init(this, els, options);
+ }
+
+ /**
+ * Get Instance
+ */
+ static getInstance(el) {
+ let domElem = !!el.jquery ? el[0] : el;
+ return domElem.M_ScrollSpy;
+ }
+
+ /**
+ * Teardown component
+ */
+ destroy() {
+ ScrollSpy._elements.splice(ScrollSpy._elements.indexOf(this), 1);
+ ScrollSpy._elementsInView.splice(ScrollSpy._elementsInView.indexOf(this), 1);
+ ScrollSpy._visibleElements.splice(ScrollSpy._visibleElements.indexOf(this.$el), 1);
+ ScrollSpy._count--;
+ this._removeEventHandlers();
+ $(this.options.getActiveElement(this.$el.attr('id'))).removeClass(this.options.activeClass);
+ this.el.M_ScrollSpy = undefined;
+ }
+
+ /**
+ * Setup Event Handlers
+ */
+ _setupEventHandlers() {
+ let throttledResize = M.throttle(this._handleWindowScroll, 200);
+ this._handleThrottledResizeBound = throttledResize.bind(this);
+ this._handleWindowScrollBound = this._handleWindowScroll.bind(this);
+ if (ScrollSpy._count === 1) {
+ window.addEventListener('scroll', this._handleWindowScrollBound);
+ window.addEventListener('resize', this._handleThrottledResizeBound);
+ document.body.addEventListener('click', this._handleTriggerClick);
+ }
+ }
+
+ /**
+ * Remove Event Handlers
+ */
+ _removeEventHandlers() {
+ if (ScrollSpy._count === 0) {
+ window.removeEventListener('scroll', this._handleWindowScrollBound);
+ window.removeEventListener('resize', this._handleThrottledResizeBound);
+ document.body.removeEventListener('click', this._handleTriggerClick);
+ }
+ }
+
+ /**
+ * Handle Trigger Click
+ * @param {Event} e
+ */
+ _handleTriggerClick(e) {
+ let $trigger = $(e.target);
+ for (let i = ScrollSpy._elements.length - 1; i >= 0; i--) {
+ let scrollspy = ScrollSpy._elements[i];
+ if ($trigger.is('a[href="#' + scrollspy.$el.attr('id') + '"]')) {
+ e.preventDefault();
+ let offset = scrollspy.$el.offset().top + 1;
+
+ anim({
+ targets: [document.documentElement, document.body],
+ scrollTop: offset - scrollspy.options.scrollOffset,
+ duration: 400,
+ easing: 'easeOutCubic'
+ });
+ break;
+ }
+ }
+ }
+
+ /**
+ * Handle Window Scroll
+ */
+ _handleWindowScroll() {
+ // unique tick id
+ ScrollSpy._ticks++;
+
+ // viewport rectangle
+ let top = M.getDocumentScrollTop(),
+ left = M.getDocumentScrollLeft(),
+ right = left + window.innerWidth,
+ bottom = top + window.innerHeight;
+
+ // determine which elements are in view
+ let intersections = ScrollSpy._findElements(top, right, bottom, left);
+ for (let i = 0; i < intersections.length; i++) {
+ let scrollspy = intersections[i];
+ let lastTick = scrollspy.tickId;
+ if (lastTick < 0) {
+ // entered into view
+ scrollspy._enter();
+ }
+
+ // update tick id
+ scrollspy.tickId = ScrollSpy._ticks;
+ }
+
+ for (let i = 0; i < ScrollSpy._elementsInView.length; i++) {
+ let scrollspy = ScrollSpy._elementsInView[i];
+ let lastTick = scrollspy.tickId;
+ if (lastTick >= 0 && lastTick !== ScrollSpy._ticks) {
+ // exited from view
+ scrollspy._exit();
+ scrollspy.tickId = -1;
+ }
+ }
+
+ // remember elements in view for next tick
+ ScrollSpy._elementsInView = intersections;
+ }
+
+ /**
+ * Find elements that are within the boundary
+ * @param {number} top
+ * @param {number} right
+ * @param {number} bottom
+ * @param {number} left
+ * @return {Array.<ScrollSpy>} A collection of elements
+ */
+ static _findElements(top, right, bottom, left) {
+ let hits = [];
+ for (let i = 0; i < ScrollSpy._elements.length; i++) {
+ let scrollspy = ScrollSpy._elements[i];
+ let currTop = top + scrollspy.options.scrollOffset || 200;
+
+ if (scrollspy.$el.height() > 0) {
+ let elTop = scrollspy.$el.offset().top,
+ elLeft = scrollspy.$el.offset().left,
+ elRight = elLeft + scrollspy.$el.width(),
+ elBottom = elTop + scrollspy.$el.height();
+
+ let isIntersect = !(
+ elLeft > right ||
+ elRight < left ||
+ elTop > bottom ||
+ elBottom < currTop
+ );
+
+ if (isIntersect) {
+ hits.push(scrollspy);
+ }
+ }
+ }
+ return hits;
+ }
+
+ _enter() {
+ ScrollSpy._visibleElements = ScrollSpy._visibleElements.filter(function(value) {
+ return value.height() != 0;
+ });
+
+ if (ScrollSpy._visibleElements[0]) {
+ $(this.options.getActiveElement(ScrollSpy._visibleElements[0].attr('id'))).removeClass(
+ this.options.activeClass
+ );
+ if (
+ ScrollSpy._visibleElements[0][0].M_ScrollSpy &&
+ this.id < ScrollSpy._visibleElements[0][0].M_ScrollSpy.id
+ ) {
+ ScrollSpy._visibleElements.unshift(this.$el);
+ } else {
+ ScrollSpy._visibleElements.push(this.$el);
+ }
+ } else {
+ ScrollSpy._visibleElements.push(this.$el);
+ }
+
+ $(this.options.getActiveElement(ScrollSpy._visibleElements[0].attr('id'))).addClass(
+ this.options.activeClass
+ );
+ }
+
+ _exit() {
+ ScrollSpy._visibleElements = ScrollSpy._visibleElements.filter(function(value) {
+ return value.height() != 0;
+ });
+
+ if (ScrollSpy._visibleElements[0]) {
+ $(this.options.getActiveElement(ScrollSpy._visibleElements[0].attr('id'))).removeClass(
+ this.options.activeClass
+ );
+
+ ScrollSpy._visibleElements = ScrollSpy._visibleElements.filter((el) => {
+ return el.attr('id') != this.$el.attr('id');
+ });
+ if (ScrollSpy._visibleElements[0]) {
+ // Check if empty
+ $(this.options.getActiveElement(ScrollSpy._visibleElements[0].attr('id'))).addClass(
+ this.options.activeClass
+ );
+ }
+ }
+ }
+ }
+
+ /**
+ * @static
+ * @memberof ScrollSpy
+ * @type {Array.<ScrollSpy>}
+ */
+ ScrollSpy._elements = [];
+
+ /**
+ * @static
+ * @memberof ScrollSpy
+ * @type {Array.<ScrollSpy>}
+ */
+ ScrollSpy._elementsInView = [];
+
+ /**
+ * @static
+ * @memberof ScrollSpy
+ * @type {Array.<cash>}
+ */
+ ScrollSpy._visibleElements = [];
+
+ /**
+ * @static
+ * @memberof ScrollSpy
+ */
+ ScrollSpy._count = 0;
+
+ /**
+ * @static
+ * @memberof ScrollSpy
+ */
+ ScrollSpy._increment = 0;
+
+ /**
+ * @static
+ * @memberof ScrollSpy
+ */
+ ScrollSpy._ticks = 0;
+
+ M.ScrollSpy = ScrollSpy;
+
+ if (M.jQueryLoaded) {
+ M.initializeJqueryWrapper(ScrollSpy, 'scrollSpy', 'M_ScrollSpy');
+ }
+})(cash, M.anime);