]> _ Git - c6-wordpress.git/commitdiff
WIP #2685 @0.05
authornael <nael@cubedesigners.com>
Wed, 15 May 2019 16:02:24 +0000 (18:02 +0200)
committernael <nael@cubedesigners.com>
Wed, 15 May 2019 16:02:24 +0000 (18:02 +0200)
wp-content/themes/c6/resources/assets/scripts/gumshoe.js [new file with mode: 0644]
wp-content/themes/c6/resources/assets/styles/layouts/footer.styl

diff --git a/wp-content/themes/c6/resources/assets/scripts/gumshoe.js b/wp-content/themes/c6/resources/assets/scripts/gumshoe.js
new file mode 100644 (file)
index 0000000..b240494
--- /dev/null
@@ -0,0 +1,488 @@
+/* eslint-disable */
+
+/*!
+    Modified version for cubedesigners to make sure there is always one item active even when outside the viewport
+ * gumshoejs v5.1.1
+ * A simple, framework-agnostic scrollspy script.
+ * (c) 2019 Chris Ferdinandi
+ * MIT License
+ * http://github.com/cferdinandi/gumshoe
+ */
+
+(function (root, factory) {
+    if ( typeof define === 'function' && define.amd ) {
+        define([], (function () {
+            return factory(root);
+        }));
+    } else if ( typeof exports === 'object' ) {
+        module.exports = factory(root);
+    } else {
+        root.Gumshoe = factory(root);
+    }
+})(typeof global !== 'undefined' ? global : typeof window !== 'undefined' ? window : this, (function (window) {
+
+    'use strict';
+
+    //
+    // Defaults
+    //
+
+    var defaults = {
+
+        // Active classes
+        navClass: 'active',
+        contentClass: 'active',
+
+        // Nested navigation
+        nested: false,
+        nestedClass: 'active',
+
+        // Offset & reflow
+        offset: 0,
+        reflow: false,
+
+        // Event support
+        events: true
+
+    };
+
+
+    //
+    // Methods
+    //
+
+    /**
+     * Merge two or more objects together.
+     * @param   {Object}   objects  The objects to merge together
+     * @returns {Object}            Merged values of defaults and options
+     */
+    var extend = function () {
+        var merged = {};
+        Array.prototype.forEach.call(arguments, (function (obj) {
+            for (var key in obj) {
+                if (!obj.hasOwnProperty(key)) return;
+                merged[key] = obj[key];
+            }
+        }));
+        return merged;
+    };
+
+    /**
+     * Emit a custom event
+     * @param  {String} type   The event type
+     * @param  {Node}   elem   The element to attach the event to
+     * @param  {Object} detail Any details to pass along with the event
+     */
+    var emitEvent = function (type, elem, detail) {
+
+        // Make sure events are enabled
+        if (!detail.settings.events) return;
+
+        // Create a new event
+        var event = new CustomEvent(type, {
+            bubbles: true,
+            cancelable: true,
+            detail: detail
+        });
+
+        // Dispatch the event
+        elem.dispatchEvent(event);
+
+    };
+
+    /**
+     * Get an element's distance from the top of the Document.
+     * @param  {Node} elem The element
+     * @return {Number}    Distance from the top in pixels
+     */
+    var getOffsetTop = function (elem) {
+        var location = 0;
+        if (elem.offsetParent) {
+            while (elem) {
+                location += elem.offsetTop;
+                elem = elem.offsetParent;
+            }
+        }
+        return location >= 0 ? location : 0;
+    };
+
+    /**
+     * Sort content from first to last in the DOM
+     * @param  {Array} contents The content areas
+     */
+    var sortContents = function (contents) {
+        if(contents) {
+            contents.sort((function (item1, item2) {
+                var offset1 = getOffsetTop(item1.content);
+                var offset2 = getOffsetTop(item2.content);
+                if (offset1 < offset2) return -1;
+                return 1;
+            }));
+        }
+    };
+
+    /**
+     * Get the offset to use for calculating position
+     * @param  {Object} settings The settings for this instantiation
+     * @return {Float}           The number of pixels to offset the calculations
+     */
+    var getOffset = function (settings) {
+
+        // if the offset is a function run it
+        if (typeof settings.offset === 'function') {
+            return parseFloat(settings.offset());
+        }
+
+        // Otherwise, return it as-is
+        return parseFloat(settings.offset);
+
+    };
+
+    /**
+     * Get the document element's height
+     * @private
+     * @returns {Number}
+     */
+    var getDocumentHeight = function () {
+        return Math.max(
+            document.body.scrollHeight, document.documentElement.scrollHeight,
+            document.body.offsetHeight, document.documentElement.offsetHeight,
+            document.body.clientHeight, document.documentElement.clientHeight
+        );
+    };
+
+    /**
+     * Determine if an element is in view
+     * @param  {Node}    elem     The element
+     * @param  {Object}  settings The settings for this instantiation
+     * @param  {Boolean} bottom   If true, check if element is above bottom of viewport instead
+     * @return {Boolean}          Returns true if element is in the viewport
+     */
+    var isInView = function (elem, settings, bottom) {
+        var bounds = elem.getBoundingClientRect();
+        var offset = getOffset(settings);
+        if (bottom) {
+            return parseInt(bounds.bottom, 10) < (window.innerHeight || document.documentElement.clientHeight);
+        }
+        return parseInt(bounds.top, 10) <= offset;
+    };
+
+    /**
+     * Check if at the bottom of the viewport
+     * @return {Boolean} If true, page is at the bottom of the viewport
+     */
+    var isAtBottom = function () {
+        if (window.innerHeight + window.pageYOffset >= getDocumentHeight()) return true;
+        return false;
+    };
+
+    /**
+     * Check if the last item should be used (even if not at the top of the page)
+     * @param  {Object} item     The last item
+     * @param  {Object} settings The settings for this instantiation
+     * @return {Boolean}         If true, use the last item
+     */
+    var useLastItem = function (item, settings) {
+        if (isAtBottom() && isInView(item.content, settings, true)) return true;
+        return false;
+    };
+
+    /**
+     * Get the active content
+     * @param  {Array}  contents The content areas
+     * @param  {Object} settings The settings for this instantiation
+     * @return {Object}          The content area and matching navigation link
+     */
+    var getActive = function (contents, settings) {
+        var last = contents[contents.length-1];
+        if (useLastItem(last, settings)) return last;
+        for (var i = contents.length - 1; i >= 0; i--) {
+            if (isInView(contents[i].content, settings)) return contents[i];
+        }
+        return contents[0]; //     select first item by default if no active sections are found
+    };
+
+    /**
+     * Deactivate parent navs in a nested navigation
+     * @param  {Node}   nav      The starting navigation element
+     * @param  {Object} settings The settings for this instantiation
+     */
+    var deactivateNested = function (nav, settings) {
+
+        // If nesting isn't activated, bail
+        if (!settings.nested) return;
+
+        // Get the parent navigation
+        var li = nav.parentNode.closest('li');
+        if (!li) return;
+
+        // Remove the active class
+        li.classList.remove(settings.nestedClass);
+
+        // Apply recursively to any parent navigation elements
+        deactivateNested(li, settings);
+
+    };
+
+    /**
+     * Deactivate a nav and content area
+     * @param  {Object} items    The nav item and content to deactivate
+     * @param  {Object} settings The settings for this instantiation
+     */
+    var deactivate = function (items, settings) {
+
+        // Make sure their are items to deactivate
+        if (!items) return;
+
+        // Get the parent list item
+        var li = items.nav.closest('li');
+        if (!li) return;
+
+        // Remove the active class from the nav and content
+        li.classList.remove(settings.navClass);
+        items.content.classList.remove(settings.contentClass);
+
+        // Deactivate any parent navs in a nested navigation
+        deactivateNested(li, settings);
+
+        // Emit a custom event
+        emitEvent('gumshoeDeactivate', li, {
+            link: items.nav,
+            content: items.content,
+            settings: settings
+        });
+
+    };
+
+
+    /**
+     * Activate parent navs in a nested navigation
+     * @param  {Node}   nav      The starting navigation element
+     * @param  {Object} settings The settings for this instantiation
+     */
+    var activateNested = function (nav, settings) {
+
+        // If nesting isn't activated, bail
+        if (!settings.nested) return;
+
+        // Get the parent navigation
+        var li = nav.parentNode.closest('li');
+        if (!li) return;
+
+        // Add the active class
+        li.classList.add(settings.nestedClass);
+
+        // Apply recursively to any parent navigation elements
+        activateNested(li, settings);
+
+    };
+
+    /**
+     * Activate a nav and content area
+     * @param  {Object} items    The nav item and content to activate
+     * @param  {Object} settings The settings for this instantiation
+     */
+    var activate = function (items, settings) {
+
+        // Make sure their are items to activate
+        if (!items) return;
+
+        // Get the parent list item
+        var li = items.nav.closest('li');
+        if (!li) return;
+
+        // Add the active class to the nav and content
+        li.classList.add(settings.navClass);
+        items.content.classList.add(settings.contentClass);
+
+        // Activate any parent navs in a nested navigation
+        activateNested(li, settings);
+
+        // Emit a custom event
+        emitEvent('gumshoeActivate', li, {
+            link: items.nav,
+            content: items.content,
+            settings: settings
+        });
+
+    };
+
+    /**
+     * Create the Constructor object
+     * @param {String} selector The selector to use for navigation items
+     * @param {Object} options  User options and settings
+     */
+    var Constructor = function (selector, options) {
+
+        //
+        // Variables
+        //
+
+        var publicAPIs = {};
+        var navItems, contents, current, timeout, settings;
+
+
+        //
+        // Methods
+        //
+
+        /**
+         * Set variables from DOM elements
+         */
+        publicAPIs.setup = function () {
+
+            // Get all nav items
+            navItems = document.querySelectorAll(selector);
+
+            // Create contents array
+            contents = [];
+
+            // Loop through each item, get it's matching content, and push to the array
+            Array.prototype.forEach.call(navItems, (function (item) {
+
+                // Get the content for the nav item
+                var content = document.getElementById(decodeURIComponent(item.hash.substr(1)));
+                if (!content) return;
+
+                // Push to the contents array
+                contents.push({
+                    nav: item,
+                    content: content
+                });
+
+            }));
+
+            // Sort contents by the order they appear in the DOM
+            sortContents(contents);
+
+        };
+
+        /**
+         * Detect which content is currently active
+         */
+        publicAPIs.detect = function () {
+
+            // Get the active content
+            var active = getActive(contents, settings);
+
+            // if there's no active content, deactivate and bail
+            if (!active) {
+                if (current) {
+                    deactivate(current, settings);
+                    current = null;
+                }
+                return;
+            }
+
+            // If the active content is the one currently active, do nothing
+            if (current && active.content === current.content) return;
+
+            // Deactivate the current content and activate the new content
+            deactivate(current, settings);
+            activate(active, settings);
+
+            // Update the currently active content
+            current = active;
+
+        };
+
+        /**
+         * Detect the active content on scroll
+         * Debounced for performance
+         */
+        var scrollHandler = function (event) {
+
+            // If there's a timer, cancel it
+            if (timeout) {
+                window.cancelAnimationFrame(timeout);
+            }
+
+            // Setup debounce callback
+            timeout = window.requestAnimationFrame(publicAPIs.detect);
+
+        };
+
+        /**
+         * Update content sorting on resize
+         * Debounced for performance
+         */
+        var resizeHandler = function (event) {
+
+            // If there's a timer, cancel it
+            if (timeout) {
+                window.cancelAnimationFrame(timeout);
+            }
+
+            // Setup debounce callback
+            timeout = window.requestAnimationFrame((function () {
+                sortContents(contents);
+                publicAPIs.detect();
+            }));
+
+        };
+
+        /**
+         * Destroy the current instantiation
+         */
+        publicAPIs.destroy = function () {
+
+            // Undo DOM changes
+            if (current) {
+                deactivate(current, settings);
+            }
+
+            // Remove event listeners
+            window.removeEventListener('scroll', scrollHandler, false);
+            if (settings.reflow) {
+                window.removeEventListener('resize', resizeHandler, false);
+            }
+
+            // Reset variables
+            contents = null;
+            navItems = null;
+            current = null;
+            timeout = null;
+            settings = null;
+
+        };
+
+        /**
+         * Initialize the current instantiation
+         */
+        var init = function () {
+
+            // Merge user options into defaults
+            settings = extend(defaults, options || {});
+
+            // Setup variables based on the current DOM
+            publicAPIs.setup();
+
+            // Find the currently active content
+            publicAPIs.detect();
+
+            // Setup event listeners
+            window.addEventListener('scroll', scrollHandler, false);
+            if (settings.reflow) {
+                window.addEventListener('resize', resizeHandler, false);
+            }
+
+        };
+
+
+        //
+        // Initialize and return the public APIs
+        //
+
+        init();
+        return publicAPIs;
+
+    };
+
+
+    //
+    // Return the Constructor
+    //
+
+    return Constructor;
+
+}));
\ No newline at end of file
index 8083f143253802bc4614ccdbbe450bfe388041b7..a5fd86e04a777cb7021d69ccf776a80e450f0f0f 100644 (file)
@@ -1,5 +1,5 @@
 $breakpoint-footer-cols-2 = 980px // When to break to 2 col view
-$breakpoint-footer-medium = 800px // Layout with logo + address on same line / other items stacked below
+$breakpoint-footer-medium = 810px // Layout with logo + address on same line / other items stacked below
 $breakpoint-footer-cols-1 = 500px // When to break to 1 col view
 
 .footer
@@ -134,5 +134,5 @@ $breakpoint-footer-cols-1 = 500px // When to break to 1 col view
     opacity: 0.5
     //constrain(padding-right, 5vw) // Needed to match 5vw applied internally to footer-columns right side
 
-    +below($breakpoint-footer-cols-1)
+    +below($breakpoint-footer-cols-2)
       text-align: center