Search code examples
javascriptxpagesgetuikit

UIkit tabs and switcher do not work after partial refresh


Ok, this is a bit special. We are using UIkit in our XPages application. We also use the tabs and switcher component (http://getuikit.com/docs/tab.html and http://getuikit.com/docs/switcher.html). They work fine until we do a partial refresh of the page. The reason is that those components are initiliazed only once after the pages is loaded. This happens directly in the lib we bind to the page - no own init script etc. After the refresh I must re-init the whole stuff - but I am not familiar with the syntax or even the possibilities. I searched the UIkit lib though and found something like this:

(function(UI) {

"use strict";

UI.component('tab', {

    defaults: {
        'target'    : '>li:not(.uk-tab-responsive, .uk-disabled)',
        'connect'   : false,
        'active'    : 0,
        'animation' : false,
        'duration'  : 200
    },

    boot: function() {

        // init code
        UI.ready(function(context) {

            UI.$("[data-uk-tab]", context).each(function() {

                var tab = UI.$(this);

                if (!tab.data("tab")) {
                    var obj = UI.tab(tab, UI.Utils.options(tab.attr("data-uk-tab")));
                }
            });
        });
    },

    init: function() {

        var $this = this;

        this.current = false;

        this.on("click.uikit.tab", this.options.target, function(e) {

            e.preventDefault();

            if ($this.switcher && $this.switcher.animating) {
                return;
            }

            var current = $this.find($this.options.target).not(this);

            current.removeClass("uk-active").blur();

            $this.trigger("change.uk.tab", [UI.$(this).addClass("uk-active"), $this.current]);

            $this.current = UI.$(this);

            // Update ARIA
            if (!$this.options.connect) {
                current.attr('aria-expanded', 'false');
                UI.$(this).attr('aria-expanded', 'true');
            }
        });

        if (this.options.connect) {
            this.connect = UI.$(this.options.connect);
        }

        // init responsive tab
        this.responsivetab = UI.$('<li class="uk-tab-responsive uk-active"><a></a></li>').append('<div class="uk-dropdown uk-dropdown-small"><ul class="uk-nav uk-nav-dropdown"></ul><div>');

        this.responsivetab.dropdown = this.responsivetab.find('.uk-dropdown');
        this.responsivetab.lst      = this.responsivetab.dropdown.find('ul');
        this.responsivetab.caption  = this.responsivetab.find('a:first');

        if (this.element.hasClass("uk-tab-bottom")) this.responsivetab.dropdown.addClass("uk-dropdown-up");

        // handle click
        this.responsivetab.lst.on('click.uikit.tab', 'a', function(e) {

            e.preventDefault();
            e.stopPropagation();

            var link = UI.$(this);

            $this.element.children('li:not(.uk-tab-responsive)').eq(link.data('index')).trigger('click');
        });

        this.on('show.uk.switcher change.uk.tab', function(e, tab) {
            $this.responsivetab.caption.html(tab.text());
        });

        this.element.append(this.responsivetab);

        // init UIkit components
        if (this.options.connect) {
            this.switcher = UI.switcher(this.element, {
                "toggle"    : ">li:not(.uk-tab-responsive)",
                "connect"   : this.options.connect,
                "active"    : this.options.active,
                "animation" : this.options.animation,
                "duration"  : this.options.duration
            });
        }

        UI.dropdown(this.responsivetab, {"mode": "click"});

        // init
        $this.trigger("change.uk.tab", [this.element.find(this.options.target).filter('.uk-active')]);

        this.check();

        UI.$win.on('resize orientationchange', UI.Utils.debounce(function(){
            if ($this.element.is(":visible"))  $this.check();
        }, 100));

        this.on('display.uk.check', function(){
            if ($this.element.is(":visible"))  $this.check();
        });
    },

    check: function() {

        var children = this.element.children('li:not(.uk-tab-responsive)').removeClass('uk-hidden');

        if (!children.length) return;

        var top          = (children.eq(0).offset().top + Math.ceil(children.eq(0).height()/2)),
            doresponsive = false,
            item, link;

        this.responsivetab.lst.empty();

        children.each(function(){

            if (UI.$(this).offset().top > top) {
                doresponsive = true;
            }
        });

        if (doresponsive) {

            for (var i = 0; i < children.length; i++) {

                item = UI.$(children.eq(i));
                link = item.find('a');

                if (item.css('float') != 'none' && !item.attr('uk-dropdown')) {

                    item.addClass('uk-hidden');

                    if (!item.hasClass('uk-disabled')) {
                        this.responsivetab.lst.append('<li><a href="'+link.attr('href')+'" data-index="'+i+'">'+link.html()+'</a></li>');
                    }
                }
            }
        }

        this.responsivetab[this.responsivetab.lst.children('li').length ? 'removeClass':'addClass']('uk-hidden');
    }
});
})(UIkit);

Similar code is created for the connected switcher component.

You can see a demo of my problem here: http://notesx.net/customrenderer.nsf/demo.xsp

Source code here: https://github.com/zeromancer1972/CustomRendererDemo/blob/master/ODP/XPages/demo.xsp

As this is part of the library itself I'd like to find a way to call this from outside the library.

Any ideas are highly appreciated!


Solution

  • Newer versions of uikit have an init method, upgrade and call it from the onComplete event of the combo box.

    <xp:comboBox
        id="comboBox1">
        <xp:selectItems>
            <xp:this.value><![CDATA[#{javascript:return ["value 1", "value 2"];}]]></xp:this.value>
        </xp:selectItems>
        <xp:eventHandler
            event="onchange"
            submit="true"
            refreshMode="partial"
            refreshId="page"
            onComplete="$.UIkit.init();">
        </xp:eventHandler>
    </xp:comboBox>