[jquery-ui] r3424 committed - menu: nested menu refactoring, for now as its own widget

7 views
Skip to first unread message

codesite...@google.com

unread,
Nov 9, 2009, 8:12:28 AM11/9/09
to jquery...@googlegroups.com
Revision: 3424
Author: joern.zaefferer
Date: Mon Nov 9 05:11:21 2009
Log: menu: nested menu refactoring, for now as its own widget
http://code.google.com/p/jquery-ui/source/detail?r=3424

Modified:
/branches/dev/tests/visual/menu/nested.html

=======================================
--- /branches/dev/tests/visual/menu/nested.html Mon Nov 9 03:10:32 2009
+++ /branches/dev/tests/visual/menu/nested.html Mon Nov 9 05:11:21 2009
@@ -9,67 +9,98 @@
<script type="text/javascript"
src="../../../ui/jquery.ui.core.js"></script>
<script type="text/javascript"
src="../../../ui/jquery.ui.menu.js"></script>
<script type="text/javascript"
src="../../../ui/jquery.ui.position.js"></script>
- <script type="text/javascript"
src="http://jqueryui.com/themeroller/themeswitchertool/"></script>
<script type="text/javascript">
$(function() {
- $.fn.themeswitcher && $('<div/>').css({
- position: "absolute",
- right: 10,
- top: 10
- }).appendTo(document.body).themeswitcher();
-
-
- var submenu;
- var menu = $("#menu").menu({
+ $.widget("ui.nestedmenu", {
+ _init: function() {
+ var self = this;
+ this.active = this.element;
+
+ // hide submenus and create indicator icons
+ this.element.find("ul").hide().prev("a").prepend('<span class="ui-icon
ui-icon-carat-1-e"></span>');
+
+ this.element.find("ul").andSelf().menu({
+ selected: this.options.selected,
+ focus: function(event, ui) {
+ self.active = ui.item.parent();
+ // put a previous submenu back into its place and hide it
+ self.hideDown();
+ var nested = $(">ul", ui.item);
+ if (nested.length) {
+ // append to body in order to display the submenu above the parent
menu, instead of inside of it
+ nested.appendTo(document.body).menu("deactivate").show().position({
+ my: "left top",
+ at: "right top",
+ of: ui.item
+ // store the current submenu
+ }).data("menuparent", ui.item);
+
+ self.active.data("submenu", nested);
+ }
+ }
+ })
+ },
+
+ up: function() {
+ if (!this.active.data("menuparent"))
+ return;
+ this.active.menu("deactivate");
+ this.active = this.active.data("menuparent").parent();
+ },
+
+ down: function() {
+ var submenu = this.active.data("submenu");
+ if (!submenu)
+ return;
+ submenu.data("menu").activate(submenu.children(":first"))
+ this.active = submenu;
+ },
+
+ show: function() {
+ this.element.menu("deactivate").show();
+ this.active = this.element;
+ },
+
+ hide: function() {
+ this.hideDown();
+ var child = this.active.hide(), parent;
+ while(child.data("menuparent")) {
+ parent = child.data("menuparent");
+ child.appendTo(parent).removeData("menuparent");
+ child = parent.parent().removeData("submenu").hide();
+ }
+ },
+
+ hideDown: function() {
+ var submenu = this.active.data("submenu");
+ while(submenu) {
+ var parent = submenu.data("menuparent");
+ submenu.appendTo(parent).hide().removeData("menuparent");
+ parent.parent().removeData("submenu");
+ submenu = submenu.data("submenu");
+ };
+ }
+ });
+
+ var nestedmenu = $("#menu").nestedmenu({
selected: function(event, ui) {
$("#log").append("<div>Selected " + ui.item.text() + "</div>");
- },
- focus: function(event, ui) {
- // put a previous submenu back into its place and hide it
- if (submenu) {
- submenu.appendTo(submenu.data("menuparent")).hide();
- submenu = null;
- }
- var nested = $("ul", ui.item);
- if (nested.length) {
- nested.menu({
- selected: function(event, ui) {
- $("#log").append("<div>Selected " + ui.item.text() + "</div>");
- }
- // append to body in order to display the submenu above the parent
menu, instead of inside of it
- }).appendTo(document.body).menu("deactivate").show().position({
- my: "left top",
- at: "right top",
- of: ui.item
- });
- // store the current submenu
- submenu = nested;
- submenu.data("menuparent", ui.item);
- }
}
}).hide();

- // hide submenus and create indicator icons
- menu.find("ul").hide().prev("a").prepend('<span class="ui-icon
ui-icon-carat-1-e"></span>');
-
-
$("button").click(function(event) {
// TODO required to prevent the click handler below from handling this
event
event.stopPropagation();
- $("#menu").menu("deactivate").show().position({
+ nestedmenu.nestedmenu("show").position({
my: "left top",
at: "right top",
of: event.pageX > 0 ? event : this
});
$().one("click", function() {
- menu.hide();
- if (submenu) {
- submenu.appendTo(submenu.data("menuparent")).hide();
- submenu = null;
- }
+ nestedmenu.nestedmenu("hide");
})
}).keydown(function(event) {
- var menu = submenu && submenu.data("menufocussed") &&
submenu.data("menu") || $("#menu" + this.id).data("menu");
+ var menu = nestedmenu.data("nestedmenu").active.data("menu");
if (menu.widget().is(":hidden"))
return;
event.stopPropagation();
@@ -84,17 +115,10 @@
menu.previous();
break;
case $.ui.keyCode.LEFT:
- if (submenu && submenu.data("menufocussed")) {
- submenu.data("menufocussed", false);
- menu.deactivate();
- }
+ nestedmenu.nestedmenu("up");
break;
case $.ui.keyCode.RIGHT:
- if (submenu) {
- submenu.data("menufocussed", true);
- menu = submenu.data("menu");
- menu.activate(menu.element.children(":first"));
- }
+ nestedmenu.nestedmenu("down");
break;
case $.ui.keyCode.DOWN:
menu.next();
@@ -103,25 +127,11 @@
case $.ui.keyCode.ENTER:
case $.ui.keyCode.TAB:
menu.select();
- menu.widget().hide();
- if (submenu) {
- submenu.appendTo(submenu.data("menuparent"));
- submenu.removeData("menuparent");
- submenu = null;
- // also hide parent
- $("#menu" + this.id).hide();
- }
+ nestedmenu.nestedmenu("hide");
event.preventDefault();
break;
case $.ui.keyCode.ESCAPE:
- menu.widget().hide();
- if (submenu) {
- submenu.appendTo(submenu.data("menuparent"));
- submenu.removeData("menuparent");
- submenu = null;
- // also hide parent
- $("#menu" + this.id).hide();
- }
+ nestedmenu.nestedmenu("hide");
break;
default:
clearTimeout(menu.filterTimer);
@@ -177,7 +187,23 @@
<ul>
<li><a href="#">Aberdeen</a></li>
<li><a href="#">Ada</a></li>
- <li><a href="#">Adamsville</a></li>
+ <li>
+ <a href="#">Adamsville</a>
+ <ul>
+ <li><a href="#">Anaheim</a></li>
+ <li>
+ <a href="#">Cologne</a>
+ <ul>
+ <li><a href="#">Mberdeen</a></li>
+ <li><a href="#">Mda</a></li>
+ <li><a href="#">Mdamsville</a></li>
+ <li><a href="#">Mddyston</a></li>
+ <li><a href="#">Mmesville</a></li>
+ </ul>
+ </li>
+ <li><a href="#">Frankfurt</a></li>
+ </ul>
+ </li>
<li><a href="#">Addyston</a></li>
<li><a href="#">Amesville</a></li>
</ul>

Jörn Zaefferer

unread,
Nov 9, 2009, 8:22:08 AM11/9/09
to jquery...@googlegroups.com

Richard D. Worth

unread,
Nov 9, 2009, 8:26:19 AM11/9/09
to jquery...@googlegroups.com
This is nice. The only slight improvement that I think could be added is to allow for a slight delay before closing the submenu so that you can cut to a submenu item at a diagonal instead of having to go right and then down. Currently, you have to be quite deliberate about staying on the horizontal until you are on that submenu before moving down, or it closes and you have to go back up and reopen it and try again.

- Richard

Jörn Zaefferer

unread,
Nov 9, 2009, 8:43:52 AM11/9/09
to jquery...@googlegroups.com
Make sense, I'll look into it. Probably another time...

Jörn

Todd Parker

unread,
Nov 9, 2009, 9:42:36 AM11/9/09
to jquery...@googlegroups.com
I agree that would be nice because it makes the menus much easier to use. A simple timer that would wait 200-500ms (Not sure exactly what's best) before closing when your mouse out would do the trick.

BTW - these flyout menus work great. They even flip like a charm. Nice work!

_t


todd.parker  .: .   filament group inc.  
102 south street #3 boston, ma 02111  

phone + 617.482.7120 
fax     + 617.687.0212
web     + filamentgroup.com

Scott Jehl

unread,
Nov 9, 2009, 10:04:37 AM11/9/09
to jquery...@googlegroups.com
Nice work Jörn!

A couple things:
- The menus seem to need top and bottom padding to match the right and left
- When using the keyboard to navigate, we think if you focus on a node that has a child menu, it should stay closed until you key into it with the right arrow. Then focus can move to the first node in the menu as soon as it opens. Same thing when you key out of a child menu using the left arrow, the menu should close.

I'll check out that border issue in IE6.
-Scott


Scott Jehl

unread,
Nov 9, 2009, 10:17:08 AM11/9/09
to jquery...@googlegroups.com
I'll see if I can do some quick cleanup now on the CSS to work the visual issues out.
-Scott

Jörn Zaefferer

unread,
Nov 9, 2009, 10:28:24 AM11/9/09
to jquery...@googlegroups.com
That would be great.

Currently the open-submenu behaviour is the same for mouse and keyboard, which I think works quite well. Its not how other menus work like, but I'd like to at least explore this approach. Is there any drawback to showing it on focus?

Jörn

Scott Jehl

unread,
Nov 9, 2009, 10:29:49 AM11/9/09
to jquery...@googlegroups.com
oh another thought:
I think the menus should default to the ui-corner-all class, rather than ui-corner-bottom. The first menu's corners will probably need to depend on the context, but I wonder if we should allow an option for that or just write the CSS override certain menus need to have square corners...

Jörn Zaefferer

unread,
Nov 9, 2009, 10:34:15 AM11/9/09
to jquery...@googlegroups.com
Good point, I'll change that. Autocomplete can replace it then with ui-corner-bottom.

Jörn

Todd Parker

unread,
Nov 9, 2009, 10:44:31 AM11/9/09
to jquery...@googlegroups.com
Having it open on focus for mouse and keyboard seems fine but the real problem happens when navigating back. For example, when you have navigated 3 levels in with the keyboard (Amserdam > Adamsville > Anaheim), then click the left arrow, it feels odd that the 3rd menu is still open. On both Mac & PC, clicking left arrow key will close the child menu so it's really clear where you are currently navigating. All desktop OS menus use slightly different behavior between mouse and keyboard:

Keyboard:
You must press the right arrow to open a child menu, left arrow closes child and places focus back on parent item

Mouse:
Hover opens child menu after a brief delay, mousing back to parent leaves child menu open (like your menu does)

Since this is consistent across Mac & PC, it seems like there are subtle usability reasons why this difference in behavior should be maintained. 

I've also noticed that both platforms use a brief timer (~200ms) before opening child menus which probably makes it feel less jumpy when mousing or arrowing down through a menu because child menus don't keep opening and closing.

_t


todd.parker  .: .   filament group inc.  
102 south street #3 boston, ma 02111  

phone + 617.482.7120 
fax     + 617.687.0212
web     + filamentgroup.com


Scott Jehl

unread,
Nov 9, 2009, 10:44:36 AM11/9/09
to jquery...@googlegroups.com
K thanks.
Another thought:
I think these menus should be nested. As it is, it's very difficult to style them with any context, and I think it would help accessibility as well if the child menus were actually children of the items they appear to be.
What do you think?

Scott Jehl

unread,
Nov 9, 2009, 10:49:07 AM11/9/09
to jquery...@googlegroups.com
Also, this would allow you to have one aria-active descendent per total menu widget, which seems more appropriate to spec, I think?

Also, aria-related: I believe the role of menuitem has to be on the anchors rather than the LI's. This recommendation goes against the spec (and will break validation), which says it should be an immediate child of role="menu", but at least to my knowledge, the current setup won't work in some common screen reader setups we've tested because the LI isn't natively focusable.
Anyone disagree?

Jörn Zaefferer

unread,
Nov 9, 2009, 10:56:38 AM11/9/09
to jquery...@googlegroups.com
How do you do that with a root-ul with overflow:auto? So far it looks like I have to rip them out in order to position them at the right place without screwing up the container.

Jörn

Scott Jehl

unread,
Nov 9, 2009, 11:41:45 AM11/9/09
to jquery...@googlegroups.com
Good question. 
I'm not sure how best to solve this. 

We could either:
a) not support scrolling within flyout menu containers, which means we could easily style menu children with CSS and they might be more naturally accessible.
b) support scrolling flyout menus, but figure out workarounds to style menus that are actually child menus but appended as siblings to the top menu (and also figure out a way to make this accessible).
c) create a custom scrolling solution, where we accessibly hide menu items that go beyond the viewing area, and append a node that lets a user click to reveal one item at a time. Keyboard users would simply arrow through normally as if nothing is hidden. This is what Mac and Windows do. It would let us support large sets without having to break up the markup hierarchy.

Personally, I think I'd rather do C, and advise against large menu lists since they're difficult to use anyway.

Thoughts?

Jörn Zaefferer

unread,
Nov 9, 2009, 12:22:11 PM11/9/09
to jquery...@googlegroups.com
That custom scrolling feature that Windows and OSX provide is horrible. I hate it.

Is the markup hierachy really important, as long as we provide the propery ARIA attributes? Are there any for nested lists?

Jörn

Scott Jehl

unread,
Nov 9, 2009, 12:34:36 PM11/9/09
to jquery...@googlegroups.com
Hmm.. I agree but scrollbars in flyouts are just as bad to use, and uglier visually too. 

A fourth solution could be to lock all the menus to the top, which could allow us to put overflow: auto on just the outermost container. 
Perhaps we could switch to that model whenever menus are found to be too tall for screen area..? See http://footjoy.com for example. 

Just a thought.

As for hierarchy... I'm not sure. It seems like every time you entered a submenu in this case, the screen reader would act as if it's a different widget. The ARIA spec seems to suggest having one active descendent of a whole nested UL, which can be matched to that roving ID. Also, when you focus on a node that has children, you'd get contextual info on the number of child items and such (maybe that would work now too, as long as the menu isn't shown until triggered, as Todd suggests..?).
Still, unraveling the nesting is inconvenient for styling as well, even if we find a workaround for a11y.

Jörn Zaefferer

unread,
Nov 13, 2009, 8:11:51 AM11/13/09
to jquery...@googlegroups.com
WAI-ARIA mentions for menuitem that it should have aria-haspopup set to true when it has a submenu, and activation of that item should activate the submenu: http://www.w3.org/TR/wai-aria/#menuitem
Thats still different from what we have no, where activation just selects the menu item, not the submenu. Windows menus behave that way, so implementating that together with the aria-haspopup attribute should provide a good solution. I think I can extend the menu's focus-event to provide the information if the focus was triggered by mouse or keyboard.

Also worth reading is the ARIA example: http://www.w3.org/TR/wai-aria/#managingfocus
Especially this: "Sometimes a tree structure is not explicit via the DOM and logical structure of a page. In such cases the relationships must still be made explicit using the states and properties. In the following example, the aria-owns attribute indicates that the div with id "external_listitem" should be considered a child of the ul element with the property, even though it is not a child in the DOM."
In other words, even when picking the DOM apart for layout purposes, using the appropiate ARIA roles we can provide the tree relationship.

Am I missing something? If not, I'll go on and implement those attributes and change the focus-submenu behaviour. Once that is in place, I'll look into delay opening and closing submenus and build more examples.

Jörn

Scott Jehl

unread,
Nov 13, 2009, 10:16:53 AM11/13/09
to jquery...@googlegroups.com
Okay, well this seems to make sense as a workaround, so at least in readers that support this ARIA behavior, it should be technically compatible.

I'm still concerned that this goes against what our end users would expect, particularly concerning styling the menu. I expected a UL UL css selector would reach a submenu node, and I assume most users would expect that too.  If we go this route, we'll need to add a class that allows us to address submenus separately than the top-level menu.

Just to be clear, are you proposing this to avoid the overflow: auto problem? 
If so, I think we could use embedded hierarchy and work around the scrolling issue when it occurs.

Are there other reasons why this approach would be beneficial?






Scott Jehl | filament group, inc  |  102 South Street #3, Boston, MA 02111




Jörn Zaefferer

unread,
Nov 13, 2009, 10:44:20 AM11/13/09
to jquery...@googlegroups.com
Yes, the purpose was a workaround for overflow:auto. Which I'd like to keep the default for menus as they handle scrolling very well (mouse native, keyboard implemented in widget).

Dunno what an "embedded hierachy" is supposed to be, just plain nested lists? What are alternative workarounds for the scrolling issue?

Jörn

Scott Jehl

unread,
Nov 13, 2009, 11:11:41 AM11/13/09
to jquery...@googlegroups.com
Dunno what an "embedded hierachy" is supposed to be, just plain nested lists? What are alternative workarounds for the scrolling issue?
Sorry, that wasn't clear. I meant nested lists,  which have native benefits of their own as well that screen readers can take advantage of (even those without latest ARIA support).

If there's really no way to work around the overflow problem, this solution could do, but it does feel like an unnatural workaround, that's all I'm saying.

The idea of using a scrollbar within a flyout menu seems like a problem in itself to us, requiring very careful mouse movement that would probably be more annoying to users than a custom solution with an arrow at the bottom that scrolls the items either on hover, click, or arrow key.

I'm assuming the usability challenges that come with scrolling within flyouts are the reason both Mac and Windows handle it with custom arrows at the top or bottom instead.

If we chose to do a custom solution, I *think* we could do it without using overflow at all. It would require some creativity, but no more than we're doing to work around this issue with sibling appends currently.

My initial thought is that whenever there isn't enough room for a menu to show all its items, the items at the bottom will be hidden accessibly (ui-hidden-accessible class), we could append an extra element to the bottom with behavior to show those items on click (while hiding the first visible item in the list as well).

A flyout menu that is taller than the window will probably be an exception situation anyway, right? It seems we should handle it as an exception case, rather than changing the behavior of all menus (sibling rather than embedded) to accommodate it.




Kevin Dalman

unread,
Nov 14, 2009, 6:30:10 PM11/14/09
to jQuery UI Development
I copied the demo page and did some testing. This exposed a issue in
ui.position -- I am using the version linked in this demo. I'm posting
it here because the nestedmenu widget demo shows the problem. Here is
what I did...

To make the menu align to the bottom/left of the trigger element (I'm
using a hyperlink instead of a button), I changed the alignment on the
initalization options...

*** ORIGINAL ***
nestedmenu.nestedmenu("show").position({
my: "left top",
at: "right top",
of: event.pageX > 0 ? event : this
});

*** REVISED ***
nestedmenu.nestedmenu("show").position({
my: "left top",
at: "right top",
of: this
});

The orginal 'of' option only seems applicable if creating a context-
menu. If the menu is attached to a trigger-element, it *should*
specify 'this'.

As soon as I made this change, it exposed a bug in ui.position: The
position of the menus is *miscalculated* the first time they are
opened. After the first time each menu/submenu is displayed, the
position corrects itself.

I traced the glitch to 'this.offsetLeft', which was not returning the
correct value. I believe this is related to the fact that the menu is
a UL element. If you do not hide the menu mark-up onLoad, you'll
notice that it is not left-aligned to the margin. I assume the UL must
have a left-margin, which this.offsetLeft takes into consideration
when returning an offset value.

To address this issue, I replace this.offsetLeft with $(this).position
().left. Here is the original and revised markup (punctuation adjusted
to my standard)...

***
*** ui.position - ORIGINAL
***
var
offset = elem.offset()
, delta = {
left: parseInt(elem.css('left'), 10)
, top: parseInt(elem.css('top'), 10)
}
;

// in case of 'auto'
delta.left = !isNaN(delta.left)
? delta.left
: isRelative
? 0
: this.offsetLeft
;
delta.top = !isNaN(delta.top)
? delta.top
: isRelative
? 0
: this.offsetTop
;

***
*** ui.position - REVISED
***
var
offset = elem.offset()
, position = elem.position()
, delta = {
left: parseInt(elem.css('left'), 10)
, top: parseInt(elem.css('top'), 10)
}
;

// in case of 'auto'
delta.left = !isNaN(delta.left)
? delta.left
: isRelative
? 0
: position.left
;
delta.top = !isNaN(delta.top)
? delta.top
: isRelative
? 0
: position.top
;

Now the returned values are correct and the menus line up correctly
the first time they are accessed. Since position() is a core method,
it seems a reasonable solution to use this rather than the problematic
offsetLeft/Top.

FYI, this glitch appeared under IE7 with the HTML 4.01 Strict doctype.
I did not test any other variations.

It's easy to reproduce this misalignment - just change the options on
Jörn's demo page, ie:

nestedmenu.nestedmenu("show").position({
my: "left top",
at: "right top",
of: this
});

I'm going to use this for navigation menus in a production website.
I'll let you know if I stumble across any other issues.

/Kevin


On Nov 9, 5:22 am, Jörn Zaefferer <joern.zaeffe...@googlemail.com>
wrote:
>
> Give it a try:http://jquery-ui.googlecode.com/svn/branches/dev/tests/visual/menu/ne...
>

Scott González

unread,
Nov 14, 2009, 7:24:14 PM11/14/09
to jquery...@googlegroups.com
Hey Kevin,

The code you're talking about is in the .offset() setter, which will not be released. This code lives in core now (and is completely different from this code). The plugin can't be updated until we pull 1.4 into trunk though.

Kevin Dalman

unread,
Nov 15, 2009, 1:25:58 PM11/15/09
to jQuery UI Development
Thanks Scott,

> The code you're talking about is in the .offset() setter, which will not be
> released. This code lives in core now (and is completely different from this
> code).

Right, I should have been more specific. It appears ui.position has a
dependancy on this new offset-setter functionality, and the comment
says it "is planned for jQuery 1.4", so I considered it an integral
part of the ui.position widget.

> The plugin can't be updated until we pull 1.4 into trunk though.

That's fine. I'm just passing it on for reference - whenever and
however it's useful.

Scott González

unread,
Nov 15, 2009, 1:32:58 PM11/15/09
to jquery...@googlegroups.com
Could you test with a nightly of jQuery and just delete the offset
part in ui.postion? That should show if the bug will exist for real.

Thanks.

Kevin Dalman

unread,
Nov 16, 2009, 3:18:55 AM11/16/09
to jQuery UI Development
I switched to the latest nightly build of jQuery and disabled the
offset code in ui.position...

There IS still a bug similar to my previous description, though the
position errors are slightly different. Now the menu appears:
* aligned to the top of the page
* shifted left by the amount of BODY.paddingLeft

As before, each menu/submenu displays in the correct position *after
the first time shown*.

I found the setOffest method in the nightly build and applied the same
fix as before. This fixed the problem - everything appears in the
correct position the first time. Here is the modified code:

// line 5062
var curElem = jQuery( elem ),
curOffset = curElem.offset(),
position = curElem.position(), // NEW
// OLD curTop = parseInt( jQuery.curCSS( elem, 'top', true ),
10 ) || 0,
// OLD curLeft = parseInt( jQuery.curCSS( elem, 'left', true ),
10) || 0,
props = {
top: (options.top - curOffset.top) + position.top, // OLD
curTop
left: (options.left - curOffset.left) + position.left // OLD
curLeft
};

It seems that position() handles 'hidden element' correctly, but curCSS
() does not.

Hope that helps.

Kevin Dalman

unread,
Nov 16, 2009, 1:14:22 PM11/16/09
to jQuery UI Development
BTW, it would be nice if code in the core and in all jQuery libraries
followed the convention of prefixing jQuery objects with "$". This
would make it easier to follow because "elem" would always be the DOM-
element and $elem the elem wrapped in a jQuery object. This would
avoid the different syntax in each area, like "curElem", which still
doesn't make clear whether it is a DOM or jQuery reference. (though
the setOffset method is so small that it's not a problem)

The same '$name' standard should apply to UI widgets. It makes object
pointers crystal clear. It also creates a clear relationship between
the DOM and jQuery objects, eg: $(menu) = $menu

Just my 2-cents.
> > >> code). The plugin can't be updated until we pull 1.4 into trunk though.- Hide quoted text -
>
> - Show quoted text -

Scott González

unread,
Nov 16, 2009, 2:49:10 PM11/16/09
to jquery...@googlegroups.com
On Mon, Nov 16, 2009 at 1:14 PM, Kevin Dalman <kevin....@gmail.com> wrote:

BTW, it would be nice if code in the core and in all jQuery libraries
followed the convention of prefixing jQuery objects with "$". This
would make it easier to follow because "elem" would always be the DOM-
element and $elem the elem wrapped in a jQuery object. This would
avoid the different syntax in each area, like "curElem", which still
doesn't make clear whether it is a DOM or jQuery reference. (though
the setOffset method is so small that it's not a problem)

The same '$name' standard should apply to UI widgets. It makes object
pointers crystal clear. It also creates a clear relationship between
the DOM and jQuery objects, eg: $(menu) = $menu

Just my 2-cents.

We don't use Hungarian notation anywhere else, so this doesn't really make sense.

Kevin Dalman

unread,
Nov 16, 2009, 4:44:30 PM11/16/09
to jQuery UI Development
> We don't use Hungarian notation anywhere else, so this doesn't really make
> sense.

This is not Hungarian notation - it is a coding convention that is no
different from the conventions for events and methods names,
indentation, commenting, etc. It has become the defacto standard
adopted by most jQuery developers, including many of jQuery's own
developers. It facilitates easier reading and sharing of code, which
is why I suggested it. I've reviewed enough jQuery files to be annoyed
that vars like "elem" are often used for *both* DOM and jQuery
objects.

Many people *you know* specifically recommend it - for example:

"...here is a jQuery-specific naming convention that I highly
recommend. Use an initial $ on every variable that contains a jQuery
object:"

var $foo = $('#foo'), foo = foo[0];
$foo.show(); // jQuery
var id = foo.id; // DOM

"It's always a good idea to cache a jQuery object instead of repeating
the query or $() call over and over again, and the $ prefix is a good
visible reminder that it's a jQuery object."

- Mike Geary

Most jQuery books recommend it and use it in all their examples. For
example, from the jQuery Cookbook...

$element = $(this);
$element.addClass("clicked");

You'll also find it on the Learning jQuery website and other places,
so even jQuery newbies are taught to use it to make their code more
readable.

Plus, the convention is similar to other changes to the core...

"As of jQuery Revision 1371, the DOM Expando name has changed from
'events' to '$events'."

So I posted this suggestion not as a personal preference, but because
it is a widely used and published convention. Therefore it seemed
reasonable to *consider* whether core files and widgets should follow
the convention used by jQuery's own developers!

I'm not pushing the issue - just wanted to clarify.

Cheers


On Nov 16, 11:49 am, Scott González <scott.gonza...@gmail.com> wrote:
Reply all
Reply to author
Forward
0 new messages