Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Webpack #8

Open
Volmarg opened this issue Feb 28, 2021 · 0 comments
Open

Support for Webpack #8

Volmarg opened this issue Feb 28, 2021 · 0 comments

Comments

@Volmarg
Copy link

Volmarg commented Feb 28, 2021

Hello,
Not going to make a pull request. This is the code which I use with webpack.

JquerySmartTab.ts (this is the original js file, adjusted to webpack/typsecript)

/**
 * @link http://www.techlaboratory.net/jquery-smarttab
 * @description the logic provided in here is the original logic taken from the plugin
 *              however some changes were provided so that it can work with the webpack
 *
 */
export default class JquerySmartTab {

    // volmarg - fix adding logic to initial call
    private initialCall: boolean = true;

    private defaults = {
        selected: 0,
        // Initial selected tab, 0 = first tab
        theme: 'default',
        // theme for the tab, related css need to include for other than default theme
        orientation: 'horizontal',
        // Nav menu orientation. horizontal/vertical
        justified: true,
        // Nav menu justification. true/false
        autoAdjustHeight: true,
        // Automatically adjust content height
        backButtonSupport: true,
        // Enable the back button support
        enableURLhash: true,
        // Enable selection of the tab based on url hash
        transition: {
            animation: 'none',
            // Effect on navigation, none/fade/slide-horizontal/slide-vertical/slide-swing
            speed: '400',
            // Transion animation speed
            easing: '' // Transition animation easing. Not supported without a jQuery easing plugin

        },
        autoProgress: {
            // Auto navigate tabs on interval
            enabled: false,
            // Enable/Disable Auto navigation
            interval: 3500,
            // Auto navigate Interval (used only if "autoProgress" is enabled)
            stopOnFocus: true // Stop auto navigation on focus and resume on outfocus

        },
        keyboardSettings: {
            keyNavigation: true,
            // Enable/Disable keyboard navigation(left and right keys are used if enabled)
            keyLeft: [37],
            // Left key code
            keyRight: [39] // Right key code

        }
    };

    private options;
    private main;
    private nav;
    private tabs;
    private container;
    private pages;
    private current_index;
    private autoProgressId;

    _typeof(obj) {
        "@babel/helpers - typeof";
        if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
            this._typeof = function _typeof(obj) {
                return typeof obj;
            };
        } else {
            this._typeof = function _typeof(obj) {
                return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
            };
        }
        return this._typeof(obj);
    }

    _classCallCheck(instance, Constructor) {
        if (!(instance instanceof Constructor)) {
            throw new TypeError("Cannot call a class as a function");
        }
    }

    _defineProperties(target, props) {
        for (var i = 0; i < props.length; i++) {
            var descriptor = props[i];
            descriptor.enumerable = descriptor.enumerable || false;
            descriptor.configurable = true;
            if ("value" in descriptor) descriptor.writable = true;
            Object.defineProperty(target, descriptor.key, descriptor);
        }
    }

    _createClass(Constructor, protoProps, staticProps) {
        if (protoProps) this._defineProperties(Constructor.prototype, protoProps);
        if (staticProps) this._defineProperties(Constructor, staticProps);
        return Constructor;
    }

    public initForElementAndOptions(element, options) {
        // this._classCallCheck(this, this.initForElementAndOptions);

        // Merge user settings with default
        this.options = $.extend(true, {}, this.defaults, options); // Main container element

        this.main = $(element); // Navigation bar element

        this.nav = this._getFirstDescendant('.nav'); // Tab anchor elements

        this.tabs = this.nav.find('.nav-link'); // Content container

        this.container = this._getFirstDescendant('.tab-content'); // Content pages

        this.pages = this.container.children('.tab-pane'); // Active Tab index

        this.current_index = null; // Autoprogress timer id

        this.autoProgressId = null; // Assign options

        this._initOptions(); // Initial load

        this._initLoad();
    } // Initial Load Method


    private _initLoad() {
        // Clean the elements
        this.pages.hide();
        this.tabs.removeClass('active'); // Get the initial tab index

        var idx = this._getTabIndex(); // Show the initial tab


        this._showTab(idx);
    } // Initialize options

    private _initOptions() {
        // Set the elements
        this._setElements(); // Assign plugin events


        this._setEvents();
    }

    private _getFirstDescendant(selector) {
        // Check for first level element
        var elm = this.main.children(selector);

        if (elm.length > 0) {
            return elm;
        } // Check for second level element


        this.main.children().each(function (i, n) {
            var tmp = $(n).children(selector);

            if (tmp.length > 0) {
                elm = tmp;
                return false;
            }
        });

        if (elm.length > 0) {
            return elm;
        } // Element not found


        this._showError("Element not found " + selector);

        return false;
    }

    private _setElements() {
        // Set the main element
        this.main.addClass('st');

        if (this.options.justified === true) {
            this.main.addClass('st-justified');
        } else {
            this.main.removeClass('st-justified');
        }

        this._setTheme(this.options.theme);

        this._setOrientation(this.options.orientation);
    }

    private _setEvents() {
        var _this = this;

        // Check if event handler already exists
        if (this.main.data('click-init')) {
            return true;
        } // Flag item to prevent attaching handler again


        this.main.data('click-init', true); // Anchor click event

        $(this.tabs).on("click", function (e) {
            e.preventDefault();

            _this._showTab(_this.tabs.index(e.currentTarget));
        }); // Keyboard navigation event

        if (this.options.keyboardSettings.keyNavigation) {
            $(document).keyup(function (e) {
                _this._keyNav(e);
            });
        } // Back/forward browser button event


        if (this.options.backButtonSupport) {
            $(window).on('hashchange', function (e) {
                var idx = _this._getURLHashIndex();

                if (idx !== false) {
                    e.preventDefault();

                    _this._showTab(idx);
                }
            });
        }

        if (this.options.autoProgress.enabled && this.options.autoProgress.stopOnFocus) {
            $(this.main).on("mouseover", function (e) {
                e.preventDefault();

                _this._stopAutoProgress();
            });
            $(this.main).on("mouseleave", function (e) {
                e.preventDefault();

                _this._startAutoProgress();
            });
        }
    }

    private _showNext() {
        var si = 0; // Find the next showable step

        for (var i = this.current_index + 1; i < this.tabs.length; i++) {
            if (this._isShowable(i)) {
                si = i;
                break;
            }
        }

        this._showTab(si);
    }

    private _showPrevious() {
        var si = this.tabs.length - 1; // Find the previous showable step

        for (var i = this.current_index - 1; i >= 0; i--) {
            if (this._isShowable(i)) {
                si = i;
                break;
            }
        }

        this._showTab(si);
    }

    private _isShowable(idx) {
        if (this.tabs.eq(idx).hasClass('disabled') || this.tabs.eq(idx).hasClass('hidden')) {
            return false;
        }

        return true;
    }

    private _showTab(idx) {
        // If current tab is requested again, skip
        if (idx == this.current_index) {
            return false;
        } // If tab not found, skip


        if (!this.tabs.eq(idx)) {
            return false;
        } // If it is a disabled tab, skip


        if (!this._isShowable(idx)) {
            return false;
        } // Load tab content


        this._loadTab(idx);
    }

    private _loadTab(idx) {
        var _this2 = this;

        // Get current tab element
        var curTab = this._getAnchor(this.current_index);

        if (this.current_index !== null) {
            // Trigger "leaveTab" event
            if (this._triggerEvent("leaveTab", [curTab, this.current_index]) === false) {
                return false;
            }
        } // Get next tab element


        var selTab = this._getAnchor(idx); // Get the content if used


        var getTabContent = this._triggerEvent("tabContent", [selTab, idx]);

        if (getTabContent) {
            if (_this2._typeof(getTabContent) == "object") {
                getTabContent.then(function (res) {
                    _this2._setTabContent(idx, res);

                    _this2._transitTab(idx);
                })["catch"](function (err) {
                    console.error(err);

                    _this2._setTabContent(idx, err);

                    _this2._transitTab(idx);
                });
            } else if (typeof getTabContent == "string") {
                this._setTabContent(idx, getTabContent);

                this._transitTab(idx);
            } else {
                this._transitTab(idx);
            }
        } else {
            this._transitTab(idx);
        }
    }

    private _getAnchor(idx) {
        if (idx == null) {
            return null;
        }

        return this.tabs.eq(idx);
    }

    private _getPage(idx) {
        if (idx == null) {
            return null;
        }

        var anchor = this._getAnchor(idx);

        return anchor.length > 0 ? this.main.find(anchor.attr("href")) : null;
    }

    private _setTabContent(idx, html) {
        var page = this._getPage(idx);

        if (page) {
            page.html(html);
        }
    }

    private _transitTab(idx) {
        var _this3 = this;

        // Get tab to show element
        var selTab = this._getAnchor(idx); // Change the url hash to new tab


        this._setURLHash(selTab.attr("href")); // Update controls


        this._setAnchor(idx); // Animate the tab


        this._doTabAnimation(idx, function () {
            // Fix height with content
            _this3._fixHeight(idx); // Trigger "showTab" event


            _this3._triggerEvent("showTab", [selTab, _this3.current_index]); // Restart auto progress if enabled


            _this3._restartAutoProgress();
        }); // Update the current index


        this.current_index = idx;
    }

    private _doTabAnimation(idx, callback) {
        var _this4 = this;

        // Get current tab element
        var curPage = this._getPage(this.current_index); // Get next tab element


        var selPage = this._getPage(idx); // Get the transition effect


        var transitionEffect = this.options.transition.animation.toLowerCase(); // Complete any ongoing animations

        this._stopAnimations();

        switch (transitionEffect) {
            case 'slide-horizontal':
            case 'slide-h':
                // horizontal slide
                var containerWidth = this.container.width();
                var curLastLeft = containerWidth;
                var nextFirstLeft = containerWidth * -2; // Forward direction

                if (idx > this.current_index) {
                    curLastLeft = containerWidth * -1;
                    nextFirstLeft = containerWidth;
                } // First load set the container width


                if (this.current_index == null) {
                    this.container.height(selPage.outerHeight());
                }

                var css_pos, css_left;

                if (curPage) {
                    css_pos = curPage.css("position");
                    css_left = curPage.css("left");
                    curPage.css("position", 'absolute').css("left", 0).animate({
                        left: curLastLeft
                    }, this.options.transition.speed, this.options.transition.easing, function () {
                        $(this).hide();
                        curPage.css("position", css_pos).css("left", css_left);
                    });
                }

                css_pos = selPage.css("position");
                css_left = selPage.css("left");
                selPage.css("position", 'absolute').css("left", nextFirstLeft).outerWidth(containerWidth).show().animate({
                    left: 0
                }, this.options.transition.speed, this.options.transition.easing, function () {
                    selPage.css("position", css_pos).css("left", css_left);
                    callback();
                });
                break;

            case 'slide-vertical':
            case 'slide-v':
                // vertical slide
                var containerHeight = this.container.height();
                var curLastTop = containerHeight;
                var nextFirstTop = containerHeight * -2; // Forward direction

                if (idx > this.current_index) {
                    curLastTop = containerHeight * -1;
                    nextFirstTop = containerHeight;
                }

                var css_vpos, css_vtop;

                if (curPage) {
                    css_vpos = curPage.css("position");
                    css_vtop = curPage.css("top");
                    curPage.css("position", 'absolute').css("top", 0).animate({
                        top: curLastTop
                    }, this.options.transition.speed, this.options.transition.easing, function () {
                        $(this).hide();
                        curPage.css("position", css_vpos).css("top", css_vtop);
                    });
                }

                css_vpos = selPage.css("position");
                css_vtop = selPage.css("top");
                selPage.css("position", 'absolute').css("top", nextFirstTop).show().animate({
                    top: 0
                }, this.options.transition.speed, this.options.transition.easing, function () {
                    selPage.css("position", css_vpos).css("top", css_vtop);
                    callback();
                });
                break;

            case 'slide-swing':
            case 'slide-s':
                // normal slide
                if (curPage) {
                    curPage.slideUp('fast', this.options.transition.easing, function () {
                        selPage.slideDown(_this4.options.transition.speed, _this4.options.transition.easing, function () {
                            callback();
                        });
                    });
                } else {
                    selPage.slideDown(this.options.transition.speed, this.options.transition.easing, function () {
                        callback();
                    });
                }

                break;

            case 'fade':
                // normal fade
                if (curPage) {
                    curPage.fadeOut('fast', this.options.transition.easing, function () {
                        selPage.fadeIn('fast', _this4.options.transition.easing, function () {
                            callback();
                        });
                    });
                } else {
                    selPage.fadeIn(this.options.transition.speed, this.options.transition.easing, function () {
                        callback();
                    });
                }

                break;

            default:
                if (curPage) {
                    curPage.hide();
                }

                selPage.show();
                callback();
                break;
        }
    }

    private _stopAnimations() {
        this.pages.finish();
        this.container.finish();
    };

    private _setAnchor(idx) {
        this.tabs.eq(this.current_index).removeClass("active");
        this.tabs.eq(idx).addClass("active");
    }

    private _getTabIndex() {
        // Get selected tab from the url
        var idx = this._getURLHashIndex();

        return idx === false ? this.options.selected : idx;
    }

    /**
     * @description here is the logic for handling animated height for wrapper - works good for modals,
     *              but the issue is that when modal is being hidden the panel height is initially 0
     */
    public _fixHeight(idx) {
        // volmarg - fix first tab not being active, add animation later on here

        // Auto adjust height of the container
        // if (this.options.autoAdjustHeight) {
        //     var selPage = this._getPage(idx);
        //     console.log(selPage.outerHeight());
        //
        //     this.container.finish().animate({
        //         height: selPage.outerHeight()
        //     }, this.options.transition.speed);
        // }
    }


    private _setTheme(theme) {
        this.main.removeClass(function (index, className) {
            return (className.match(/(^|\s)st-theme-\S+/g) || []).join(' ');
        }).addClass('st-theme-' + theme);
    }

    private _setOrientation(orientation) {
        this.main.removeClass('st-vertical st-horizontal').addClass('st-' + orientation);
    } // HELPER FUNCTIONS


    private _keyNav(e) {
        // Keyboard navigation
        if ($.inArray(e.which, this.options.keyboardSettings.keyLeft) > -1) {
            // left
            this._showPrevious();

            e.preventDefault();
        } else if ($.inArray(e.which, this.options.keyboardSettings.keyRight) > -1) {
            // right
            this._showNext();

            e.preventDefault();
        } else {
            return; // exit this handler for other keys
        }
    } // Auto progress

    private _startAutoProgress() {
        var _this5 = this;

        if (this.options.autoProgress.enabled && !this.autoProgressId) {
            this.autoProgressId = setInterval(function () {
                return _this5._showNext();
            }, this.options.autoProgress.interval);
        }
    }

    private _stopAutoProgress() {
        if (this.autoProgressId) {
            clearInterval(this.autoProgressId);
            this.autoProgressId = null;
        }
    }

    private _restartAutoProgress() {
        this._stopAutoProgress();

        this._startAutoProgress();
    }

    private _triggerEvent(name, params) {
        // Trigger an event
        var e = $.Event(name);
        this.main.trigger(e, params);

        if (e.isDefaultPrevented()) {
            return false;
        }

        //@ts-ignore
        return e.result;
    }

    private _setURLHash(hash) {
        if (this.options.enableURLhash && window.location.hash !== hash) {
            history.pushState(null, null, hash);
        }
    }

    private _getURLHashIndex() {
        if (this.options.enableURLhash) {
            // Get tab number from url hash if available
            var hash = window.location.hash;

            if (hash.length > 0) {
                var elm = this.nav.find("a[href*='" + hash + "']");

                if (elm.length > 0) {
                    return this.tabs.index(elm);
                }
            }
        }

        return false;
    }

    private _loader(action) {
        switch (action) {
            case 'show':
                this.main.addClass('st-loading');
                break;

            case 'hide':
                this.main.removeClass('st-loading');
                break;

            default:
                this.main.toggleClass('st-loading');
        }
    }

    private _showError(msg) {
        console.error(msg);
    } // PUBLIC FUNCTIONS

    private goToTab(tabIndex) {
        this._showTab(tabIndex);
    }

    public setOptions(options) {
        this.options = $.extend(true, {}, this.options, options);

        this._initOptions();
    }

    public loader(state) {
        if (state === "show") {
            this.main.addClass('st-loading');
        } else {
            this.main.removeClass('st-loading');
        }
    }

}

SmartTab.ts (in this file I call the adjusted jquery-smarttab)

    /**
     * @description will initialize the smart tab for given dom element
     *
     * @param htmlElement
     * @private
     */
    private initializeForHtmlElement(htmlElement: HTMLElement): void
    {
        let jquerySmartTab = new JquerySmartTab();
        let $element = $(htmlElement);
        jquerySmartTab.initForElementAndOptions($element, {
            selected          : this.DEFAULT_ACTIVE_TAB, // Initial selected tab, 0 = first tab (self: note - not working, first tab is always active but that's fine),
            theme             : 'github',                // theme for the tab, related css need to include for other than default theme
            orientation       : 'horizontal',            // Nav menu orientation. horizontal/vertical
            justified         : true,                    // Nav menu justification. true/false
            autoAdjustHeight  : true,                    // Automatically adjust content height
            backButtonSupport : true,                    // Enable the back button support
            enableURLhash     : true,                    // Enable selection of the tab based on url hash
            transition: {
                animation : 'none', // Effect on navigation, none/fade/slide-horizontal/slide-vertical/slide-swing
                speed     : '400',  // Transion animation speed
                easing    :''       // Transition animation easing. Not supported without a jQuery easing plugin
            },
            autoProgress: {          // Auto navigate tabs on interval
                enabled     : false, // Enable/Disable Auto navigation
                interval    : 3500,  // Auto navigate Interval (used only if "autoProgress" is set to true)
                stopOnFocus : true,  // Stop auto navigation on focus and resume on outfocus
            },
            keyboardSettings: {
                keyNavigation : false, // Enable/Disable keyboard navigation(left and right keys are used if enabled)
            }
        });
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant