4

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!

Oliver Busse
  • 3,375
  • 1
  • 16
  • 26
  • Can the data-uk-observe attribute do the trick? See http://getuikit.com/docs/documentation_javascript.html#dom-observe – Per Henrik Lausten Jun 25 '15 at 21:12
  • No luck with that. I set this attribute for obversing to the whole page element - the items still dissappear. – Oliver Busse Jun 25 '15 at 22:33
  • Checking your demo, all the content (tab content 1, tab content 2) is in the XHR response from the partial refresh. I can't help but wonder whether it's the XSP.partialRefreshPost's injection behavior interacting with the ui-kit observation that's inducing the issue (e.g.- could ui-kit's observe be failing due to the DOM elements being interrupted while being watched, during the update DOM portion of the partial refresh). I'm not familiar enough with ui-kit, but could one suspend the observation during the partial refresh onStart and resume it in the onComplete? – Eric McCormick Jun 26 '15 at 00:42

1 Answers1

3

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>
Adam R
  • 366
  • 3
  • 5
  • How new has UIKit to be to have this function? AFAIK we are using a current version, maybe not the bleeding edge version but only 2 months old. Using this it says that this function is unknown. – Oliver Busse Jun 26 '15 at 06:47
  • EDIT: I updated my demo to the latest version and now it works! I think you have at least to use 2.20 to get the init method. Thank you! – Oliver Busse Jun 26 '15 at 07:33