Skip to content
This repository has been archived by the owner on Apr 9, 2019. It is now read-only.

Fix onmouseover animation glitch #71

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

mociepka
Copy link

Patch prevents animation start when slide is selected.

@Casper1131
Copy link

/*************************************************!
*

  • Version: 2.2.0
  • Copyright: (c) 2010-2013 Nicola Hibbert
  • Licence: MIT

**************************************************/

;(function($) {

var LiteAccordion = function(elem, options) {

    var defaults = {
        containerWidth : 960,                   // fixed (px)
        containerHeight : 320,                  // fixed (px)
        headerWidth : 48,                       // fixed (px)

        activateOn : 'click',                   // click or mouseover
        firstSlide : 1,                         // displays slide (n) on page load
        slideSpeed : 800,                       // slide animation speed
        onTriggerSlide : function(e) {},        // callback on slide activate
        onSlideAnimComplete : function() {},    // callback on slide anim complete

        autoPlay : false,                       // automatically cycle through slides
        pauseOnHover : false,                   // pause on hover
        cycleSpeed : 6000,                      // time between slide cycles
        easing : 'swing',                       // custom easing function

        theme : 'basic',                        // basic, dark, light, or stitch
        rounded : false,                        // square or rounded corners
        enumerateSlides : false,                // put numbers on slides
        linkable : false                        // link slides via hash
    },

    // merge defaults with options in new settings object
        settings = $.extend({}, defaults, options),

    // 'globals'
        slides = elem.children('ol').children('li'),
        header = slides.children(':first-child'),
        slideLen = slides.length,
        slideWidth = settings.containerWidth - slideLen * settings.headerWidth,

    // public methods
        methods = {

            // start elem animation
            play : function(index) {
                console.log(index);
                var next = core.nextSlide(index && index);

                if (core.playing) return;

                // start autoplay
                core.playing = setInterval(function() {
                    header.eq(next()).trigger('click.liteAccordion');
                }, settings.cycleSpeed);
            },

            // stop elem animation
            stop : function() {
                clearInterval(core.playing);
                core.playing = 0;
            },

            // trigger next slide
            next : function() {
                methods.stop();
                header.eq(core.currentSlide === slideLen - 1 ? 0 : core.currentSlide + 1).trigger('click.liteAccordion');
            },

            // trigger previous slide
            prev : function() {
                methods.stop();
                header.eq(core.currentSlide - 1).trigger('click.liteAccordion');
            },

            // destroy plugin instance
            destroy : function() {
                // stop autoplay
                methods.stop();

                // remove hashchange event bound to window
                $(window).off('.liteAccordion');

                // remove generated styles, classes, data, events
                elem
                    .attr('style', '')
                    .removeClass('liteAccordion basic dark light stitch')
                    .removeData('liteAccordion')
                    .off('.liteAccordion')
                    .find('li > :first-child')
                    .off('.liteAccordion')
                    .filter('.selected')
                    .removeClass('selected')
                    .end()
                    .find('b')
                    .remove();

                slides
                    .removeClass('slide')
                    .children()
                    .attr('style', '');
            },

            // poke around the internals (NOT CHAINABLE)
            debug : function() {
                return {
                    elem : elem,
                    defaults : defaults,
                    settings : settings,
                    methods : methods,
                    core : core
                };
            },
            resize:function(data){
                settings = $.extend({}, defaults, data),
                slides = elem.children('ol').children('li'),
                header = slides.children(':first-child'),
                slideLen = slides.length,
                slideWidth = settings.containerWidth - slideLen * settings.headerWidth;


                core.setStyles();
            }
        },

    // core utility and animation methods
        core = {

            // set style properties
            setStyles : function() {
                // set container height and width, theme and corner style
                elem
                    .width(settings.containerWidth)
                    .height(settings.containerHeight)
                    .addClass('liteAccordion')
                    .addClass(settings.rounded && 'rounded')
                    .addClass(settings.theme);

                // set slide heights
                slides
                    .addClass('slide')
                    .children(':first-child')
                    .height(settings.headerWidth);

                // set slide positions
                core.setSlidePositions();
            },

            // set initial positions for each slide
            setSlidePositions : function() {
                var selected = header.filter('.selected');

                // account for already selected slide
                if (!selected.length) header.eq(settings.firstSlide - 1).addClass('selected');

                header.each(function(index) {
                    var $this = $(this),
                        left = index * settings.headerWidth,
                        margin = header.first().next(),
                        offset = parseInt(margin.css('marginLeft'), 10) || parseInt(margin.css('marginRight'), 10) || 0;

                    // compensate for already selected slide on resize
                    if (selected.length) {
                        if (index > header.index(selected)) left += slideWidth;
                    } else {
                        if (index >= settings.firstSlide) left += slideWidth;
                    }

                    // set each slide position
                    $this
                        .css('left', left)
                        .width(settings.containerHeight)
                        .next()
                            .width(slideWidth - offset)
                            .css({ left : left, paddingLeft : settings.headerWidth });

                    // add number to bottom of tab
                    settings.enumerateSlides && $this.append('<b>' + (index + 1) + '</b>');

                });
            },

            // bind events
            bindEvents : function() {
                // bind click and mouseover events
                if (settings.activateOn === 'click') {
                    header.on('click.liteAccordion', core.triggerSlide);
                } else if (settings.activateOn === 'mouseover') {
                    header.on('click.liteAccordion mouseover.liteAccordion', core.triggerSlide);
                }

                // bind hashchange event
                if (settings.linkable) {
                    $(window).on('hashchange.liteAccordion', function(e) {
                        var url = slides.filter(function() {
                            return $(this).attr('data-slide-name') === window.location.hash.split('#')[1];
                        });

                        // if slide name exists
                        if (url.length) {
                            // trigger slide
                            core.triggerSlide.call(url.children('h2')[0], e);
                        }
                    });
                }

                // pause on hover (can't use custom events with $.hover())
                if (settings.pauseOnHover && settings.autoPlay) {
                    elem
                        .on('mouseover.liteAccordion', function() {
                            core.playing && methods.stop();
                        })
                        .on('mouseout.liteAccordion', function() {
                            !core.playing && methods.play(core.currentSlide);
                        });
                }
            },

            // counter for autoPlay (zero index firstSlide on init)
            currentSlide : settings.firstSlide - 1,

            // next slide index
            nextSlide : function(index) {
                var next = index + 1 || core.currentSlide + 1;

                // closure
                return function() {
                    return next++ % slideLen;
                };
            },

            // holds interval counter
            playing : 0,

            slideAnimCompleteFlag : false,

            // trigger slide animation
            triggerSlide : function(e) {
                var $this = $(this),
                    tab = {
                        elem : $this,
                        index : header.index($this),
                        next : $this.next(),
                        prev : $this.parent().prev().children('h2'),
                        parent : $this.parent()
                    };

                // current hash not correct?
                if (settings.linkable && tab.parent.attr('data-slide-name')) {
                    if (tab.parent.attr('data-slide-name') !== window.location.hash.split('#')[1]) {
                        // exit early and try again (prevents double trigger (issue #60))
                        return window.location.hash = '#' + tab.parent.attr('data-slide-name');
                    }
                }

                // update core.currentSlide
                core.currentSlide = tab.index;

                // reset onSlideAnimComplete callback flag
                core.slideAnimCompleteFlag = false;

                // trigger callback in context of sibling div (jQuery wrapped)
                settings.onTriggerSlide.call(tab.next, $this);

                // animate
                if ($this.hasClass('selected') && $this.position().left < slideWidth / 2) {
                    // animate single selected tab
                    core.animSlide.call(tab);
                } else {
                    // animate groups
                    core.animSlideGroup(tab);
                }

                // stop autoplay, reset current slide index in core.nextSlide closure
                if (settings.autoPlay) {
                    methods.stop();
                    methods.play(header.index(header.filter('.selected')));
                }
            },

            animSlide : function(triggerTab) {
                var _this = this;

                // set pos for single selected tab
                if (typeof this.pos === 'undefined') this.pos = slideWidth;

                // remove, then add selected class
                header.removeClass('selected').filter(this.elem).addClass('selected');

                // if slide index not zero
                if (!!this.index) {
                    this.elem
                        .add(this.next)
                        .stop(true)
                        .animate({
                            left : this.pos + this.index * settings.headerWidth
                        },
                            settings.slideSpeed,
                            settings.easing,
                            function() {
                                // flag ensures that fn is only called one time per triggerSlide
                                if (!core.slideAnimCompleteFlag) {
                                    // trigger onSlideAnimComplete callback in context of sibling div (jQuery wrapped)
                                    settings.onSlideAnimComplete.call(triggerTab ? triggerTab.next : _this.prev.next());
                                    core.slideAnimCompleteFlag = true;
                                }
                            });

                        // remove, then add selected class
                        header.removeClass('selected').filter(this.prev).addClass('selected');

                }
            },

            // animates left and right groups of slides
            animSlideGroup : function(triggerTab) {
                var group = ['left', 'right'];

                $.each(group, function(index, side) {
                    var filterExpr, left;

                    if (side === 'left')  {
                        filterExpr = ':lt(' + (triggerTab.index + 1) + ')';
                        left = 0;
                    } else {
                        filterExpr = ':gt(' + triggerTab.index + ')';
                        left = slideWidth;
                    }

                    slides
                        .filter(filterExpr)
                        .children('h2')
                        .each(function() {
                            var $this = $(this),
                                tab = {
                                    elem : $this,
                                    index : header.index($this),
                                    next : $this.next(),
                                    prev : $this.parent().prev().children('h2'),
                                    pos : left
                                };

                            // trigger item anim, pass original trigger context for callback fn
                            core.animSlide.call(tab, triggerTab);
                        });

                });

                // remove, then add selected class
                header.removeClass('selected').filter(triggerTab.elem).addClass('selected');
            },

            ieClass : function(version) {
                if (version < 7) methods.destroy();
                if (version >= 10) return;
                if (version === 7 || version === 8) {
                    slides.each(function(index) {
                        $(this).addClass('slide-' + index);
                    });
                }

                elem.addClass('ie ie' + version);
            },

            init : function() {
                var ua = navigator.userAgent,
                    index = ua.indexOf('MSIE');

                // test for ie
                if (index !== -1) {
                    ua = ua.slice(index + 5, index + 7);
                    core.ieClass(+ua);
                }

                // init styles and events
                core.setStyles();
                core.bindEvents();

                // check slide speed is not faster than cycle speed
                if (settings.cycleSpeed < settings.slideSpeed) settings.cycleSpeed = settings.slideSpeed;

                // init autoplay
                settings.autoPlay && methods.play();
            }
        };

    // init plugin
    core.init();

    // expose methods
    return methods;

};

$.fn.liteAccordion = function() {
    var method=arguments[0];
    var elem = this,
        instance = elem.data('liteAccordion');

    // if creating a new instance
    if (typeof method === 'object' || !method) {
        return elem.each(function() {
            var liteAccordion;

            // if plugin already instantiated, return
            if (instance) return;

            // otherwise create a new instance
            liteAccordion = new LiteAccordion(elem, method);
            elem.data('liteAccordion', liteAccordion);
        });

    // otherwise, call method on current instance
    } else if (typeof method === 'string' && instance[method]) {
         arguments = Array.prototype.slice.call(arguments, 1);      
        // debug method isn't chainable b/c we need the debug object to be returned
        if (method === 'debug') {
            return instance[method].call(elem);
        } else { // the rest of the methods are chainable though
            instance[method].apply(elem, arguments);

            return elem;
        }
    }
};

})(jQuery);
Added a resize event $('#elem').LiteAccordion('resize'{containerWidth:200,containerHeight:200});
Also fixed issue of play index;
Thank you i really hate writing plugins from stracth this save me some time

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants