Adding HTML5 Tabs

edited May 2015 in Client Help
I asked about this a few months ago, and I know at least one person has figured it out, but I haven't had much luck myself despite spending pretty considerable time trying, so I thought I'd ask again.

Can anyone give a quick example of adding a tab to the HTML5 client?

Ideally, I would love a minimal example that:
  1. Creates a new inactive tab called "My New Tab" and adds it to the upper-right container.
  2. Swaps to that tab (I'd like to see how to swap tabs with a function rather than by clicking so I can automate it - e.g., so I can swap to my limb counter's display whenever I get into combat).
  3. Pushes a paragraph of text into the tab.
  4. Updates the tab, replacing that paragraph of text with a different paragraph of text.
  5. Updates the tab, appending below the existing paragraph (not as essential - if there isn't an easy way to append, I can always just keep the string, append to it, and replace the tab content as in #4).
Ideally the tab would retain the styling of the existing tabs, and integrate with the right-click context menu for instance, though obviously neither of those are essential.

@Sarapis, I know you said documentation was forthcoming, but (especially because I got the sense that this sort of more-advanced UI stuff wouldn't be in it) is there any chance you could get whoever is writing the client to pop over and bang out a quick, simple example of the above? I know I'm not the only person interested in answers to these particular questions and it's the only thing really holding me back with the HTML5 client right now.


  • (Ideally this would be with the "newclient", since the announce post's bit about "Reworked backend allowing for a simpler window/tab interface" suggests that the newer client might have a significantly different answer than the old.)
  • I tried the newclient and I looked a bit into that. I came up with something but just to add a new 'tab' acting just like the others. I don't remember exactly what it was about. but I might have something that might help there. Gonna check as soon as I get the chance. for now: I messed with the default_tabs(or something like that) table in the scripts.
  • Try this: Package Tab testing 2015-5-4.js

    The gist: create a tab object (there are different types of tab object with different key, but I _guess_ you want the content one), add it to the display elements, add it to the default elements (ugly work around to make appearing and disappearing of the tab possible) and then move it to a box you want.

    Appending can be done via normal jQuery to the content_html div.

    activating can be done via the activate_tab(id, activate) function, where id is the "id" field of your created tab and activate activates the tab, if true. If false, it deactivates the tab (makes it disappear).

    I hope that helps :)
  • @Keneanung, you are a god among men.

    I have a couple of questions left:
    1. The reason you're doing client.tab_default_location("quests") is to get some sort of identifier for the upper-right container, right? Is there a reason to get at the identifier indirectly like this via the quest tab's default location rather than just using the identifier itself? Is the identifier generated dynamically in some sense that doesn't guarantee it'll be the same between sessions?
    2. activate_tab(id, activate) seems to let me hide and display the tab, but do you know what function gets called to actually swap which tab is in focus (the thing that gets called on left click of the tab)? Having it hide/display the tab isn't terribly useful when I have to go click over to it each time anyway to actually see its contents.
    3. Any chance you have a convenient list sitting around of tab_types and/or icons?
    #2 is what I most need an answer for, since it's pretty clunky without that.

    This is already incredibly useful though. Thanks so much for sharing!
  • edited May 2015
    Nevermind about #3. I realised I can just look at the index.

    (Reordering the tabs would be nice to know how to do too though, since you can't save the tab positions after moving them like you can the default tabs.)
  • After experimenting a little more, I'm curious as to why I don't seem to be able to get it to work in an onLoad function. If I turn your make tab alias into an onLoad function, the tab doesn't appear (though typing onLoad in and running it again makes it show up). I can't think of any way to get around this other than writing some sort of sleep function.
  • So, I did some experimenting and got some answers. The other questions need more experiments.

    1.) Well, you could use "container_[1,2,3,4]" or probabably even "floater", but I was too lazy to look up which container was which. I only knew I wanted it to show up in the quest panel.
    2.) The only way I found to show the tab contents was something like $("#tab_[tab_id] > a").click() so in the example tab case you'd do $("#tab_test_tab > a").click() The selector basically says "all 'a' elements that are childeren of the element with the id 'tab_test_tab'".
    3.) You found already. Maybe add them here just for completeness sake?
    4.) Reordering can be done with the third argument to move_tab_to_existing_container, which is the position of the tab.
    5.) The onLoad needs more experiments, I had no time to test this yet.
  • I found the anchor you were searching for with $("#tab_[tab_id] > a")

    If your tab has the id "test", you want $('a[href$="#tab_content_test"]')

    One thing to note is that, if you have an alias that 1) creates the tab 2) emulates a click on the tab to make it active, you get an odd behavior where the tab appears to switch, but the content in it doesn't. Adding a client.redraw_interface() after the emulated click makes it work.

    I still can't get it to work with onLoad - I'm guessing that the onLoad function runs all of the user scripts before it clears client_elements and repopulates it from the saved configuration.
  • For the newclient, have a look at client.client_elements - to add a new tab, add a new entry to client.client_elements (check out the existing ones for examples), call client.move_tab_to_existing_container(id, containerid) where id is your new tab's id, and the tab should show. You may want to add it to one of the lists in client.display_tabs too, otherwise it will disappear if you reset the interface.

    As always, please keep in mind that any of this could change in new versions.

  • Daennar said:
    For the newclient, have a look at client.client_elements - to add a new tab, add a new entry to client.client_elements (check out the existing ones for examples), call client.move_tab_to_existing_container(id, containerid) where id is your new tab's id, and the tab should show. You may want to add it to one of the lists in client.display_tabs too, otherwise it will disappear if you reset the interface.

    As always, please keep in mind that any of this could change in new versions.

    @Daennar tanks for the feedback. This supports what we found out for now.

    Your answer suggests that it should not be necessary to add it to the default_display_elements list. However, if you don't do that, it is not possible to activate the tab again after deactivating. It'll also produce an error message in that case, but that is another bug. Could you look into that?

    Oh and... a little off-topic, but since we got you here... What license is the client published under? Would it be possible to put the code on github or other code hosting sites? That way we could easily follow changes and maybe even suggest bugfixes ourselves.
  • Oops, sorry, default_display_tabs is what I meant, not display_tabs - move_tab_to_existing_container handles the display_tabs one.

    Licensing, not any open-source license, so no github, I'm afraid. We may change that, but that would be for @Sarapis to decide.

  • edited May 2015
    Adding a tab to the default_display_tabs does not prevent it from being removed by interface resets, because interface resets will regenerate default_display_tabs every time by calling set_element_defaults (resetting default_display_tabs  is the very last json copy functionality in that function). This is also the reason why you can't add tabs in onLoad functions @Tael . Whenever a package is loaded, reset_ui is called after 500ms. A current workaround would be something like (now using an example from Tael's nice spiritlore script):
    setTimeout(function () {
    }, 600 // give client.reset_ui() enough time to finish before adding the new tab. );
    However subsequent interface resets will still remove the tab.
  • Interface updates no longer redo the default tab list, which means that your custom tabs shouldn't be wiped by them. I may reverse this change if it has some unexpected side effects, but I don't really expect any.

    Additionally, there is now a new (for now semi-undocumented) function: client.register_custom_tab(tab, containerid), where tab is an object containing the information about the tab, with the same structure as the contents of client.client_elements. Tabs added in this way should survive interface adjustments and resets.

    All this is experimental, please report any issues here or using the feedback form within the client. Thanks!
  • edited May 2015
    @Keneanung: So I have learned to do some things.

    If you want to get the index of the active tab in container_3: $("#container_3 > div").tabs("option", "active");

    If you want to change the active tab in container_3 to the second tab: $("#container_3 > div").tabs("option", "active", 1);

    If you want to save a reference to the last tab before you swap so you can swap back to it, you can put it all together like so:

    var active_tab_index = $("#container_3 > div").tabs("option", "active");
    var last_tab_id = $("#container_3 > div > ul > li").eq(active_tab_index).attr("id");
    var last_tab = $("#" + last_tab_id);

    You can alternatively just save the id, but then things will get screwy if the user reorders the tabs before you end up swapping back to the index.
  • edited May 2015
    So... since fiddling with the HTML5 client I always got itches, because I come from OOP languages. I took the opportunity of tabs and made a library, that is a OOP like wrapper around the client functions concerning tabs.

    Usage is simple:

    var new_tab = Object.create(Tab);
    new_tab.init(name, title (shown in the right click menu), mouseover, icon, container);

    new_tab then has the following functions:

    new_tab.move(container, index) - changes container and/or index

    new_tab.hide() - hides the tab - shows the tab again

    new_tab.append(what, newline) - appends what to the tab with an optional newline (bool)

    new_tab.clear() - empties the tab content

    new_tab.get_content_div() - returns the jQuery object for the content div

    new_tab.activate() - activates the tab ("clicks it")

    new_tab.deactivate() - "clicks" the tab that was active before making it active, if that tab is still in the same container

    The library brings also a TabContainer enum with "upper_left", "lower_left", "main", "upper_right" and "lower_right" properties for better readable "container" denomination,

    Here's an example with my test_tab:

    var test_tab = Object.create(Tab);
    test_tab.init("test_tab", "Test", "This is a test", "quests", TabContainer.upper_right);

Sign In or Register to comment.