PageSourceSearch

https://www.appliedmechtech.com/wp-content/plugins/sp-client-docum…?ver=b7864d8d025a5deee82aa982a79fddb9

js appliedmechtech.com collected 2026-10-08 07:24:51 UTC 23,509 bytes, 612 lines download raw bytes

1/*
2 *  Project: jquery.responsiveTabs.js
3 *  Description: A plugin that creates responsive tabs, optimized for all devices
4 *  Author: Jelle Kralt ([email protected])
5 *  Version: 1.4.2
6 *  License: MIT
7 */
8
9;(function ( $, window, undefined ) {
10
11    /** Default settings */
12    var defaults = {
13        active: null,
14        event: 'click',
15        disabled: [],
16        collapsible: 'accordion',
17        startCollapsed: false,
18        rotate: false,
19        setHash: false,
20        animation: 'default',
21        duration: 500,
22        scrollToAccordion: false,
23        activate: function(){},
24        deactivate: function(){},
25        load: function(){},
26        activateState: function(){},
27        classes: {
28            stateDefault: 'r-tabs-state-default',
29            stateActive: 'r-tabs-state-active',
30            stateDisabled: 'r-tabs-state-disabled',
31            stateExcluded: 'r-tabs-state-excluded',
32            tab: 'r-tabs-tab',
33            anchor: 'r-tabs-anchor',
34            panel: 'r-tabs-panel',
35            accordionTitle: 'r-tabs-accordion-title'
36        }
37    };
38
39    /**
40     * Responsive Tabs
41     * @constructor
42     * @param {object} element - The HTML element the validator should be bound to
43     * @param {object} options - An option map
44     */
45    function ResponsiveTabs(element, options) {
46        this.element = element; // Selected DOM element
47        this.$element = $(element); // Selected jQuery element
48
49        this.tabs = []; // Create tabs array
50        this.state = ''; // Define the plugin state (tabs/accordion)
51        this.rotateInterval = 0; // Define rotate interval
52        this.$queue = $({});
53
54        // Extend the defaults with the passed options
55        this.options = $.extend( {}, defaults, options);
56
57        this.init();
58    }
59
60
61    /**
62     * This function initializes the tab plugin
63     */
64    ResponsiveTabs.prototype.init = function () {
65        var _this = this;
66
67        // Load all the elements
68        this.tabs = this._loadElements();
69        this._loadClasses();
70        this._loadEvents();
71
72        // Window resize bind to check state
73        $(window).on('resize', function(e) {
74            _this._setState(e);
75        });
76
77        // Hashchange event
78        $(window).on('hashchange', function(e) {
79            var tabRef = _this._getTabRefBySelector(window.location.hash);
80            var oTab = _this._getTab(tabRef);
81
82            // Check if a tab is found that matches the hash
83            if(tabRef >= 0 && !oTab._ignoreHashChange && !oTab.disabled) {
84                // If so, open the tab and auto close the current one
85                _this._openTab(e, _this._getTab(tabRef), true);
86            }
87        });
88
89        // Start rotate event if rotate option is defined
90        if(this.options.rotate !== false) {
91            this.startRotation();
92        }
93
94        // --------------------
95        // Define plugin events
96        //
97
98        // Activate: this event is called when a tab is selected
99        this.$element.bind('tabs-activate', function(e, oTab) {
100            _this.options.activate.call(this, e, oTab);
101        });
102        // Deactivate: this event is called when a tab is closed
103        this.$element.bind('tabs-deactivate', function(e, oTab) {
104            _this.options.deactivate.call(this, e, oTab);
105        });
106        // Activate State: this event is called when the plugin switches states
107        this.$element.bind('tabs-activate-state', function(e, state) {
108            _this.options.activateState.call(this, e, state);
109        });
110
111        // Load: this event is called when the plugin has been loaded
112        this.$element.bind('tabs-load', function(e) {
113            var startTab;
114
115            _this._setState(e); // Set state
116
117            // Check if the panel should be collaped on load
118            if(_this.options.startCollapsed !== true && !(_this.options.startCollapsed === 'accordion' && _this.state === 'accordion')) {
119
120                startTab = _this._getStartTab();
121
122                // Open the initial tab
123                _this._openTab(e, startTab); // Open first tab
124
125                // Call the callback function
126                _this.options.load.call(this, e, startTab); // Call the load callback
127            }
128        });
129        // Trigger loaded event
130        this.$element.trigger('tabs-load');
131    };
132    
133    //
134    // PRIVATE FUNCTIONS
135    //
136
137    /**
138     * This function loads the tab elements and stores them in an array
139     * @returns {Array} Array of tab elements
140     */
141    ResponsiveTabs.prototype._loadElements = function() {
142        var _this = this;
143        var $ul = this.$element.children('ul');
144        var tabs = [];
145        var id = 0;
146
147        // Add the classes to the basic html elements
148        this.$element.addClass('r-tabs'); // Tab container
149        $ul.addClass('r-tabs-nav'); // List container
150
151        // Get tab buttons and store their data in an array
152        $('li', $ul).each(function() {
153            var $tab = $(this);
154            var isExcluded = $tab.hasClass(_this.options.classes.stateExcluded);
155            var $anchor, $panel, $accordionTab, $accordionAnchor, panelSelector;
156
157            // Check if the tab should be excluded
158            if(!isExcluded) {
159
160                $anchor = $('a', $tab);
161                panelSelector = $anchor.attr('href');
162                $panel = $(panelSelector);
163                $accordionTab = $('<div></div>').insertBefore($panel);
164                $accordionAnchor = $('<a></a>').attr('href', panelSelector).html($anchor.html()).appendTo($accordionTab);
165
166                var oTab = {
167                    _ignoreHashChange: false,
168                    id: id,
169                    disabled: ($.inArray(id, _this.options.disabled) !== -1),
170                    tab: $(this),
171                    anchor: $('a', $tab),
172                    panel: $panel,
173                    selector: panelSelector,
174                    accordionTab: $accordionTab,
175                    accordionAnchor: $accordionAnchor,
176                    active: false
177                };
178
179                // 1up the ID
180                id++;
181                // Add to tab array
182                tabs.push(oTab);
183            }
184        });
185        return tabs;
186    };
187
188
189    /**
190     * This function adds classes to the tab elements based on the options
191     */
192    ResponsiveTabs.prototype._loadClasses = function() {
193        for (var i=0; i<this.tabs.length; i++) {
194            this.tabs[i].tab.addClass(this.options.classes.stateDefault).addClass(this.options.classes.tab);
195            this.tabs[i].anchor.addClass(this.options.classes.anchor);
196            this.tabs[i].panel.addClass(this.options.classes.stateDefault).addClass(this.options.classes.panel);
197            this.tabs[i].accordionTab.addClass(this.options.classes.accordionTitle);
198            this.tabs[i].accordionAnchor.addClass(this.options.classes.anchor);
199            if(this.tabs[i].disabled) {
200                this.tabs[i].tab.removeClass(this.options.classes.stateDefault).addClass(this.options.classes.stateDisabled);
201                this.tabs[i].accordionTab.removeClass(this.options.classes.stateDefault).addClass(this.options.classes.stateDisabled);
202           }
203        }
204    };
205
206    /**
207     * This function adds events to the tab elements
208     */
209    ResponsiveTabs.prototype._loadEvents = function() {
210        var _this = this;
211
212        // Define activate event on a tab element
213        var fActivate = function(e) {
214            var current = _this._getCurrentTab(); // Fetch current tab
215            var activatedTab = e.data.tab;
216
217            e.preventDefault();
218
219            // Make sure this tab isn't disabled
220            if(!activatedTab.disabled) {
221
222                // Check if hash has to be set in the URL location
223                if(_this.options.setHash) {
224                    window.location.hash = activatedTab.selector;
225                }
226
227                e.data.tab._ignoreHashChange = true;
228
229                // Check if the activated tab isnt the current one or if its collapsible. If not, do nothing
230                if(current !== activatedTab || _this._isCollapisble()) {
231                    // The activated tab is either another tab of the current one. If it's the current tab it is collapsible
232                    // Either way, the current tab can be closed
233                    _this._closeTab(e, current);
234
235                    // Check if the activated tab isnt the current one or if it isnt collapsible
236                    if(current !== activatedTab || !_this._isCollapisble()) {
237                        _this._openTab(e, activatedTab, false, true);
238                    }
239                }
240            }
241        };
242
243        // Loop tabs
244        for (var i=0; i<this.tabs.length; i++) {
245            // Add activate function to the tab and accordion selection element
246            this.tabs[i].anchor.on(_this.options.event, {tab: _this.tabs[i]}, fActivate);
247            this.tabs[i].accordionAnchor.on(_this.options.event, {tab: _this.tabs[i]}, fActivate);
248        }
249    };
250
251    /**
252     * This function gets the tab that should be opened at start
253     * @returns {Object} Tab object
254     */
255    ResponsiveTabs.prototype._getStartTab = function() {
256        var tabRef = this._getTabRefBySelector(window.location.hash);
257        var startTab;
258        
259        // Check if the page has a hash set that is linked to a tab
260        if(tabRef >= 0 && !this._getTab(tabRef).disabled) {
261            // If so, set the current tab to the linked tab
262            startTab = this._getTab(tabRef);
263        } else if(this.options.active > 0 && !this._getTab(this.options.active).disabled) {
264            startTab = this._getTab(this.options.active);
265        } else {
266            // If not, just get the first one
267            startTab = this._getTab(0);
268        }
269
270        return startTab;
271    };
272
273    /**
274     * This function sets the current state of the plugin
275     * @param {Event} e - The event that triggers the state change
276     */
277    ResponsiveTabs.prototype._setState = function(e) {
278        var $ul = $('ul', this.$element);
279        var oldState = this.state;
280        var startCollapsedIsState = (typeof this.options.startCollapsed === 'string');
281        var startTab;
282
283        // The state is based on the visibility of the tabs list
284        if($ul.is(':visible')){
285            // Tab list is visible, so the state is 'tabs'
286            this.state = 'tabs';
287        } else {
288            // Tab list is invisible, so the state is 'accordion'
289            this.state = 'accordion';
290        }
291
292        // If the new state is different from the old state
293        if(this.state !== oldState) {
294            // If so, the state activate trigger must be called
295            this.$element.trigger('tabs-activate-state', {oldState: oldState, newState: this.state});
296
297            // Check if the state switch should open a tab
298            if(oldState && startCollapsedIsState && this.options.startCollapsed !== this.state && this._getCurrentTab() === undefined) {
299                // Get initial tab
300                startTab = this._getStartTab(e);
301                // Open the initial tab
302                this._openTab(e, startTab); // Open first tab
303            }
304
305
306        }
307    };
308
309    /**
310     * This function opens a tab
311     * @param {Event} e - The event that triggers the tab opening
312     * @param {Object} oTab - The tab object that should be opened
313     * @param {Boolean} closeCurrent - Defines if the current tab should be closed
314     * @param {Boolean} stopRotation - Defines if the tab rotation loop should be stopped
315     */
316    ResponsiveTabs.prototype._openTab = function(e, oTab, closeCurrent, stopRotation) {
317        var _this = this;
318
319        // Check if the current tab has to be closed
320        if(closeCurrent) {
321            this._closeTab(e, this._getCurrentTab());
322        }
323
324        // Check if the rotation has to be stopped when activated
325        if(stopRotation && this.rotateInterval > 0) {
326            this.stopRotation();
327        }
328
329        // Set this tab to active
330        oTab.active = true;
331        // Set active classes to the tab button and accordion tab button
332        oTab.tab.removeClass(_this.options.classes.stateDefault).addClass(_this.options.classes.stateActive);
333        oTab.accordionTab.removeClass(_this.options.classes.stateDefault).addClass(_this.options.classes.stateActive);
334
335        // Run panel transiton
336        _this._doTransition(oTab.panel, _this.options.animation, 'open', function() {
337            // When finished, set active class to the panel
338            oTab.panel.removeClass(_this.options.classes.stateDefault).addClass(_this.options.classes.stateActive);
339          
340           // And if enabled and state is accordion, scroll to the accordion tab
341            if(_this.getState() === 'accordion' && _this.options.scrollToAccordion && (!_this._isInView(oTab.accordionTab) || _this.options.animation !== 'default')) {
342                // Check if the animation option is enabled, and if the duration isn't 0
343                if(_this.options.animation !== 'default' && _this.options.duration > 0) {
344                    // If so, set scrollTop with animate and use the 'animation' duration
345                    $('html, body').animate({
346                        scrollTop: oTab.accordionTab.offset().top
347                    }, _this.options.duration);
348                } else {
349                    //  If not, just set scrollTop
350                    $('html, body').scrollTop(oTab.accordionTab.offset().top);
351                }
352            }
353        });
354
355
356
357        this.$element.trigger('tabs-activate', oTab);
358    };
359
360    /**
361     * This function closes a tab
362     * @param {Event} e - The event that is triggered when a tab is closed
363     * @param {Object} oTab - The tab object that should be closed
364     */
365    ResponsiveTabs.prototype._closeTab = function(e, oTab) {
366        var _this = this;
367
368        if(oTab !== undefined) {
369
370            // Deactivate tab
371            oTab.active = false;
372            // Set default class to the tab button
373            oTab.tab.removeClass(_this.options.classes.stateActive).addClass(_this.options.classes.stateDefault);
374
375            // Run panel transition
376            _this._doTransition(oTab.panel, _this.options.animation, 'close', function() {
377                // Set default class to the accordion tab button and tab panel
378                oTab.accordionTab.removeClass(_this.options.classes.stateActive).addClass(_this.options.classes.stateDefault);
379                oTab.panel.removeClass(_this.options.classes.stateActive).addClass(_this.options.classes.stateDefault);
380            }, true);
381
382            this.$element.trigger('tabs-deactivate', oTab);
383        }
384    };
385
386    /**
387     * This function runs an effect on a panel
388     * @param {Element} panel - The HTML element of the tab panel
389     * @param {String} method - The transition method reference
390     * @param {String} state - The state (open/closed) that the panel should transition to
391     * @param {Function} callback - The callback function that is called after the transition
392     * @param {Boolean} dequeue - Defines if the event queue should be dequeued after the transition
393     */
394    ResponsiveTabs.prototype._doTransition = function(panel, method, state, callback, dequeue) {
395        var effect;
396        var _this = this;
397
398        // Get effect based on method
399        switch(method) {
400            case 'slide':
401                effect = (state === 'open') ? 'slideDown' : 'slideUp';
402                break;
403            case 'fade':
404                effect = (state === 'open') ? 'fadeIn' : 'fadeOut';
405                break;
406            default:
407                effect = (state === 'open') ? 'show' : 'hide';
408                // When default is used, set the duration to 0
409                _this.options.duration = 0;
410                break;
411        }
412
413        // Add the transition to a custom queue
414        this.$queue.queue('responsive-tabs',function(next){
415            // Run the transition on the panel
416            panel[effect]({
417                duration: _this.options.duration,
418                complete: function() {
419                    // Call the callback function
420                    callback.call(panel, method, state);
421                    // Run the next function in the queue
422                    next();
423                }
424            });
425        });
426
427        // When the panel is openend, dequeue everything so the animation starts
428        if(state === 'open' || dequeue) {
429            this.$queue.dequeue('responsive-tabs');
430        }
431
432    };
433
434    /**
435     * This function returns the collapsibility of the tab in this state
436     * @returns {Boolean} The collapsibility of the tab
437     */
438    ResponsiveTabs.prototype._isCollapisble = function() {
439        return (typeof this.options.collapsible === 'boolean' && this.options.collapsible) || (typeof this.options.collapsible === 'string' && this.options.collapsible === this.get
439State());
440    };
441
442    /**
443     * This function returns a tab by numeric reference
444     * @param {Integer} numRef - Numeric tab reference
445     * @returns {Object} Tab object
446     */
447    ResponsiveTabs.prototype._getTab = function(numRef) {
448        return this.tabs[numRef];
449    };
450
451    /**
452     * This function returns the numeric tab reference based on a hash selector
453     * @param {String} selector - Hash selector
454     * @returns {Integer} Numeric tab reference
455     */
456    ResponsiveTabs.prototype._getTabRefBySelector = function(selector) {
457        // Loop all tabs
458        for (var i=0; i<this.tabs.length; i++) {
459            // Check if the hash selector is equal to the tab selector
460            if(this.tabs[i].selector === selector) {
461                return i;
462            }
463        }
464        // If none is found return a negative index
465        return -1;
466    };
467
468    /**
469     * This function returns the current tab element
470     * @returns {Object} Current tab element
471     */
472    ResponsiveTabs.prototype._getCurrentTab = function() {
473        return this._getTab(this._getCurrentTabRef());
474    };
475
476    /**
477     * This function returns the next tab's numeric reference
478     * @param {Integer} currentTabRef - Current numeric tab reference
479     * @returns {Integer} Numeric tab reference
480     */
481    ResponsiveTabs.prototype._getNextTabRef = function(currentTabRef) {
482        var tabRef = (currentTabRef || this._getCurrentTabRef());
483        var nextTabRef = (tabRef === this.tabs.length - 1) ? 0 : tabRef + 1;
484        return (this._getTab(nextTabRef).disabled) ? this._getNextTabRef(nextTabRef) : nextTabRef;
485    };
486
487    /**
488     * This function returns the previous tab's numeric reference
489     * @returns {Integer} Numeric tab reference
490     */
491    ResponsiveTabs.prototype._getPreviousTabRef = function() {
492        return (this._getCurrentTabRef() === 0) ? this.tabs.length - 1 : this._getCurrentTabRef() - 1;
493    };
494
495    /**
496     * This function returns the current tab's numeric reference
497     * @returns {Integer} Numeric tab reference
498     */
499    ResponsiveTabs.prototype._getCurrentTabRef = function() {
500        // Loop all tabs
501        for (var i=0; i<this.tabs.length; i++) {
502            // If this tab is active, return it
503            if(this.tabs[i].active) {
504                return i;
505            }
506        }
507        // No tabs have been found, return negative index
508        return -1;
509    };
510
511    //
512    // HELPER FUNCTIONS
513    // 
514
515    ResponsiveTabs.prototype._isInView = function($element) {
516        var docViewTop = $(window).scrollTop(),
517            docViewBottom = docViewTop + $(window).height(),
518            elemTop = $element.offset().top,
519            elemBottom = elemTop + $element.height();
520        return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
521    };
522
523    //
524    // PUBLIC FUNCTIONS
525    //
526
527    /**
528     * This function activates a tab
529     * @param {Integer} tabRef - Numeric tab reference
530     * @param {Boolean} stopRotation - Defines if the tab rotation should stop after activation
531     */
532    ResponsiveTabs.prototype.activate = function(tabRef, stopRotation) {
533        var e = jQuery.Event('tabs-activate');
534        var oTab = this._getTab(tabRef);
535        if(!oTab.disabled) {
536            this._openTab(e, oTab, true, stopRotation || true);
537        }
538    };
539
540    /**
541     * This function deactivates a tab
542     * @param {Integer} tabRef - Numeric tab reference
543     */
544    ResponsiveTabs.prototype.deactivate = function(tabRef) {
545        var e = jQuery.Event('tabs-dectivate');
546        var oTab = this._getTab(tabRef);
547        if(!oTab.disabled) {
548            this._closeTab(e, oTab);
549        }
550    };
551
552    /**
553     * This function gets the current state of the plugin
554     * @returns {String} State of the plugin
555     */
556    ResponsiveTabs.prototype.getState = function() {
557        return this.state;
558    };
559
560    /**
561     * This function starts the rotation of the tabs
562     * @param {Integer} speed - The speed of the rotation
563     */
564    ResponsiveTabs.prototype.startRotation = function(speed) {
565        var _this = this;
566        // Make sure not all tabs are disabled
567        if(this.tabs.length > this.options.disabled.length) {
568            this.rotateInterval = setInterval(function(){
569                var e = jQuery.Event('rotate');
570                _this._openTab(e, _this._getTab(_this._getNextTabRef()), true);
571            }, speed || (($.isNumeric(_this.options.rotate)) ? _this.options.rotate : 4000) );
572        } else {
573            throw new Error("Rotation is not possible if all tabs are disabled");
574        }
575    };
576
577    /**
578     * This function stops the rotation of the tabs
579     */
580    ResponsiveTabs.prototype.stopRotation = function() {
581        window.clearInterval(this.rotateInterval);
582        this.rotateInterval = 0;
583    };
584
585    /** jQuery wrapper */
586    $.fn.responsiveTabs = function ( options ) {
587        var args = arguments;
588        if (options === undefined || typeof options === 'object') {
589            return this.each(function () {
590                if (!$.data(this, 'responsivetabs')) {
591                    $.data(this, 'responsivetabs', new ResponsiveTabs( this, options ));
592                }
593            });
594        } else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
595            return this.each(function () {
596                var instance = $.data(this, 'responsivetabs');
597
598                if (instance instanceof ResponsiveTabs && typeof instance[options] === 'function') {
599                    instance[options].apply( instance, Array.prototype.slice.call( args, 1 ) );
600                }
601
602                // Allow instances to be destroyed via the 'destroy' method
603                if (options === 'destroy') {
604                    // TODO: destroy instance classes, etc
605                    $.data(this, 'responsivetabs', null);
606                }
607            });
608        }
609    };
610
611}(jQuery, window));
612

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.