Moo XXV

Jan. 16th, 2016 06:50 am
buzzy: Rigby from Regular Show sitting in front of a computer (Computer Rigby)
[personal profile] buzzy
The project of the day was making select/option/optgroup elements use jQuery UI's Selectmenu. This was a lot harder than I expected, mainly for cosmetic reasons. First, the drop down indicator (usually a downward pointing triangle) was too high and to the left, so it was overlapping text. The text also appeared to be much larger than the text in the original select element, so the jQuery UI version would always underestimate the required width. After a lot of restyling, I had a basic, working select element, but I didn't want it to be merely basic; if I did, I would've stuck with the regular one. Before Firefox moved to GTK3 on Linux, option elements could be styled. In several places, I use color as an additional indicator, for example, there's a status indicator that can be either green or yellow. (There used to be a red, but that was removed. There's a text equivalent for those who are color-blind, but for those who aren't, it may be easier to just pick the color.) There's also a theme selector that shows the dominant colors of each theme. None of that is visible in Firefox on Linux. At first, I repurposed some of the demo source code, but I found that didn't work correctly, so I wrote my own. To allow the style, class, and title attributes of the option elements to become part of the li elements that make up the Selectmenu, I customized the _renderItem extension point. To allow the drop down to fade in, I hooked the _resizeMenu extension point, since that's the closest extension point to where it starts showing the drop down. (I couldn't get it to fade out when closed and the slide down effect doesn't work very well if there are a lot of items.) The code uses a regular event to make sure the currently selected item is visible when the menu drops down and uses a loop to make sure that each select element's title becomes a part of the new Selectmenu. Here's the code I wrote, which can be dropped into any JavaScript file assuming you've already loaded jQuery and jQuery UI. It only runs if a drop-down SELECT is on the page. I added lots of comments for its display here so you can see what I did and why; the version I'm running doesn't have any comments. If this code helps you, let me know; this site has an internal messaging system. With this code done, it's time to tweak my CSS.
if ($("select:not([multiple])").length > 0) {
    $.widget("custom.styledselectmenu", $.ui.selectmenu, {
        // Customized to allow STYLE, CLASS, and TITLE attributes of the
        // OPTION elements to become a part of the new LI element.
        _renderItem: function (ul, item) {
            return $("<li>", {
                text: item.label,
                style: item.element.attr("style"),
                "class": (item.disabled ? "ui-state-disabled " : "") +
                    item.element.attr("class"),
                title: item.element.attr("title")
            } ).appendTo(ul);
        },
        // We want to fade in here, but to do that, we have to manually size
        // the menu.
        _resizeMenu: function () {
            this.menu.width(
                $("#" + this.menu.attr("aria-labelledby")).width()
            ).show();
            // If we use jQuery UI effects, it shows up in the wrong place.
            // slideDown doesn't work if the SELECT has a lot of options.
            this.menuWrap.hide().fadeIn(200);
        }
    } );
    $("select:not([multiple])").styledselectmenu( {
        open: function (ev, ui) {
            // When the menu drops down, make sure the currently selected item
            // is visible. This is only useful if your SELECTs have a lot of
            // items.
            var x = $(".ui-menu .ui-state-focus");
            if (x.length > 0) {
                x[0].scrollIntoView(true);
            }
        },
        close: function (ev, ui) {
            // If we don't hide the menu at this point, it stays open because
            // we faded in.
            $("#" + ev.target.id + "-menu").hide();
        },
        // Default positioning doesn't work well if the selectmenu is at the
        // bottom of a page. Fixed with collision: "flip"
        position: { my: "left top", at: "left bottom", collision: "flip" }
    } );
    // Make sure the TITLE attributes on SELECT elements make it to the
    // selectMenu version.
    $('span[role="combobox"]').each( function (i) {
        var x = $(this).attr("id")
        if (x.length < 7) {
            return;
        }
        x = "#" + x.substr(0, x.length - 7);
        $(this).attr("title", $(x).attr("title"));
    } );
}

Profile

buzzy: Timon from The Lion King looking sleepy...or maybe sassy. (Default)
Buzzy

May 2020

S M T W T F S
     12
3456789
10111213141516
17181920212223
24252627282930
31      

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jul. 1st, 2025 08:41 am
Powered by Dreamwidth Studios