0

I'm using superfish with the supersubs plugin plugin for my main navigation. That works perfect, except of one little problem. Some of the Submenu-ULs contain font-icons, that are embeded in i-tags, others don't. I think, the problem is, that the supersub plugin reads the width of the ULs on pageload and the icons aren't loaded at this point. So the script gets the wrong UL-width, which results in line break, due to the submenu being too small.

Now I'm trying to check, wheter a submenu-Ul contains a font icon or not, and want to add some extra width to the specific UL in case of an icon.

Below you see the supersubs plugin with my code in between, that is not working. The code is placed in the "each"-lop, that reads everey UL including it's childs and adds some CSS to the elements in order to get the ULs-width.

How do I determine, wheter an UL contains an i-tag?

Thanks
Lukas

// Initialize Supersubs Plugin
function supersubs_init(){
    $(document).ready(function(){
        $("ul.sf-menu").supersubs({
            minWidth:    13,
            maxWidth:    25,
            extraWidth:  1
        });
    });
}

jQuery(function($){

$.fn.supersubs = function(options){
    var opts = $.extend({}, $.fn.supersubs.defaults, options);
    // return original object to support chaining
    return this.each(function() {
        // cache selections
        var $$ = $(this);
        // support metadata
        var o = $.meta ? $.extend({}, opts, $$.data()) : opts;
        // get the font size of menu.
        // .css('fontSize') returns various results cross-browser, so measure an em dash instead
        var fontsize = $('<li id="menu-fontsize">&#8212;</li>').css({
            'padding' : 0,
            'position' : 'absolute',
            'top' : '-999em',
            'width' : 'auto'
        }).appendTo($$).width(); //clientWidth is faster, but was incorrect here
        // remove em dash
        $('#menu-fontsize').remove();
        // cache all ul elements
        $ULs = $$.find('ul');
        // loop through each ul in menu
        $ULs.each(function(i) {
            var $s_ul = $ULs;
            // cache this ul
            var $ul = $ULs.eq(i);
            // get all (li) children of this ul
            var $LIs = $ul.children();
            // get all anchor grand-children
            var $As = $LIs.children('a');
            // force content to one line and save current float property
            var liFloat = $LIs.css('white-space','nowrap').css('float');
            // remove width restrictions and floats so elements remain vertically stacked
            // check if font icons are being displayed and add extra width
            var emWidth = $ul.add ($LIs).add($As).css({
                'float' : 'none',
                'width' : 'auto'
            })
            // this ul will now be shrink-wrapped to longest li due to position:absolute
            // so save its width as ems. Clientwidth is 2 times faster than .width() - thanks Dan Switzer
            .end().end()[0].clientWidth / fontsize;
            // add more width to ensure lines don't turn over at certain sizes in various browsers


            // !!! THIS IS NOT WORKING !!!
            if($($ULs + 'i[class^="icon-"]').length != 0){
                emWidth += o.extraWidth + 1.25;
            }
            else{
                emWidth += o.extraWidth;
            }

            // restrict to at least minWidth and at most maxWidth
            if (emWidth > o.maxWidth)       { emWidth = o.maxWidth; }
            else if (emWidth < o.minWidth)  { emWidth = o.minWidth; }
            emWidth += 'em';
            // set ul to width in ems
            $ul.css('width',emWidth);
            // restore li floats to avoid IE bugs
            // set li width to full width of this ul
            // revert white-space to normal
            $LIs.css({
                'float' : liFloat,
                'width' : '100%',
                'white-space' : 'normal'
            })
            // update offset position of descendant ul to reflect new width of parent
            .each(function(){
                var $childUl = $('>ul',this);
                var offsetDirection = $childUl.css('left')!==undefined ? 'left' : 'right';
                $childUl.css(offsetDirection,emWidth);
            });
        });

    });
};
// expose defaults
$.fn.supersubs.defaults = {
    minWidth        : 13,       // requires em unit.
    maxWidth        : 25,       // requires em unit.
    extraWidth      : 2         // extra width can ensure lines don't sometimes turn over due to slight browser differences in how they round-off values
};
});
Alexander
  • 23,432
  • 11
  • 63
  • 73
  • Try printing `$ULs + 'i[class^="icon-"]'` and you will see why it is not working, it just simply doesn't make sense concatenating a string to an object. Without the layout and CSS, it can't be possible to discard the usage of CSS to solve this – Alexander Sep 15 '12 at 14:13

2 Answers2

0
var i = $('#ul-id').find('i');
if(i.length > 0)
{
  alert('hey i have i tag inside');
}
Ronel Solano
  • 63
  • 1
  • 6
  • Hi, thanks for your answer so far. Your code works, but is not solving my problem (sorry if I did not described it detailed enough). The problem is, that I do not have the ID of the UL (there is no ID at all), so I can't adress a particular UL. The result is, that the extra width is being added all the time, cause the code reads all ULs, inculding the ones with the i-tags. – LB-Projects Sep 15 '12 at 14:09
0

For the record, this CSS rule may probably had done it. (Untested)

ul.sf-menu > li [class^="icon-"] {
  display: inline-block;
  width: 1.25em;
}​

UPDATE

According to OP, this worked for him:

ul.sf-menu > li [class^="icon-"] {
  margin-right: 4px;
  display: inline-block;
  vertical-align: baseline;
}
Alexander
  • 23,432
  • 11
  • 63
  • 73
  • The font icons actually have a width of 1.25em and the inline-block property (the CSS looks similar to yours). The problem is, that they seem to load too slow for the script to be recognized. But I realized another problem. Chrome and Safari DO add the 1.25em width from the icon's stylesheet while Firefox and IE don't do that. Any suggestions, how to avoid those differences between the browsers? – LB-Projects Sep 15 '12 at 14:34
  • @LB-Projects, Sorry, I can't buy that. That shouldn't be a problem :) – Alexander Sep 15 '12 at 14:37
  • (You can also try `min-width`) – Alexander Sep 15 '12 at 14:39
  • No, it is no problem, but the reason for the problem doesn't seem to be the width of the element. You may take a look at the site: http://projects.lb-home.de/ It is working in Firefox and IE, but not in Chrome and Safari. – LB-Projects Sep 15 '12 at 14:40
  • min-width doesn't change anything. But I realized, that the width is being calculated correctly, when some content is being added to the i-tag. The font icon itself is actually appended via :before pseudo selector. – LB-Projects Sep 15 '12 at 14:44
  • @LB-Projects, I can't see anything, mind showing a screenshot? It should work in Firefox with or without content in the `` element. (I have no idea about IE, I haven't used it in ages) – Alexander Sep 15 '12 at 14:49
  • I got it work now with the CSS below. The only problem was, that I floated the icon left, so for some reason, the script didn't got the width of the icon in FF and IE. `ul.sf-menu > li [class^="icon-"] { margin-right: 4px; display: inline-block; vertical-align: baseline; }` Thanks again for your helpful ideas. ;) – LB-Projects Sep 15 '12 at 15:24