r908 - in branches/experimental: tests/visual/menu ui
Author: paul.bakaus
Date: Tue Nov 11 06:54:09 2008
New Revision: 908
Modified:
branches/experimental/tests/visual/menu/menu.html
branches/experimental/ui/ui.menu.js
Log:
menu: added flyoutDelay option, added 'add' method to add nodes to the menu
on the fly (currently only works with flyout menus), refactored flyout code
(no scoped variables in timeouts + double event bindings anymore, thank god)
Modified: branches/experimental/tests/visual/menu/menu.html
==============================================================================
--- branches/experimental/tests/visual/menu/menu.html (original)
+++ branches/experimental/tests/visual/menu/menu.html Tue Nov 11 06:54:09
2008
@@ -46,6 +46,7 @@
$('button').menu({
items: '#items2',
mode: 'dropdown',
+ flyoutDelay: 300,
choose: function(e, ui) {
console.log('Selected item ', ui.item);
},
@@ -53,6 +54,10 @@
//console.log('Browsing item ', ui.item);
},
open: function(e, ui) {
+
+ //$(this).menu('add', '<li><a href="#">Test Item 1</a></li>');
+ $(this).menu('add', '<li><a href="#">Test Item 2</a><ul><li><a
href="#">Test Item Sub</a></li></ul></li>', '1/1');
+
//console.log('Opened menu');
},
close: function(e, ui) {
Modified: branches/experimental/ui/ui.menu.js
==============================================================================
--- branches/experimental/ui/ui.menu.js (original)
+++ branches/experimental/ui/ui.menu.js Tue Nov 11 06:54:09 2008
@@ -23,6 +23,10 @@
_init: function() {
var o = this.options;
+ $.extend(this, {
+ _showTimers: [],
+ _hideTimers: []
+ });
//Prepare a nodelist of list items that's not in the DOM (anymore)
if(o.items.constructor == String) {
@@ -50,22 +54,13 @@
this.menu.addClass('ui-menu-container');
//Attach hover states for items
- $('li', this.items)
- .hover(function() {
- $(this)
- .addClass(o.hoverClassSecondary)
- .find('a:eq(0)').addClass(o.hoverClass +' ui-menu-item-on').focus();
- }, function() {
- $(this)
- .removeClass(o.hoverClassSecondary)
- .find('> a').removeClass(o.hoverClass +' ui-menu-item-on').blur();
- });
+ this._attachHoverStates(this.items);
// when there are multiple levels of hierarchy, create flyout or
drilldown menu
if ($('ul', this.items).length) {
if(this.options.type == 'drilldown')
this._prepareDrilldown();
- if(this.options.type == 'normal')
+ if(this.options.type == 'flyout')
this._prepareFlyout();
}
@@ -95,6 +90,75 @@
},
+ _itemOver: function(item, e) {
+
+ var item = $(item), self = this;
+ item
+ .addClass(this.options.hoverClassSecondary)
+ .find('a:eq(0)').addClass(this.options.hoverClass +'
ui-menu-item-on').focus();
+
+
+ if(this.options.type == 'flyout' && item.is(':has(ul)')) {
+
+ var subList = $('> ul', item);
+
+ for (var i=0; i < this._hideTimers.length; i++) {
+ if(this._hideTimers[i][1][0] == subList[0])
clearTimeout(this._hideTimers[i][0]);
+ };
+
+ this._showTimers.push([setTimeout(function(){
+ subList.addClass('ui-component-content').show();
+ subList.positionAround(e, {
+ around: subList.parent(),
+ direction: 'right',
+ offset: [0,-1]
+ });
+ self._trigger('browse', e, { item: subList });
+ }, this.options.flyoutDelay), subList]);
+
+ }
+
+ },
+
+ _itemOut: function(item, e) {
+
+ var item = $(item), self = this;
+ item
+ .removeClass(this.options.hoverClassSecondary)
+ .find('> a').removeClass(this.options.hoverClass +'
ui-menu-item-on').blur();
+
+
+ if(this.options.type == 'flyout' && item.is(':has(ul)')) {
+
+ for (var i=0; i < this._showTimers.length; i++) {
+ if(this._showTimers[i][1][0] == $('> ul', item)[0])
clearTimeout(this._showTimers[i][0]);
+ };
+
+ this._hideTimers.push([setTimeout(function(){
+ $('> ul', item).removeClass('ui-component-content').hide();
+ }, this.options.flyoutDelay), $('> ul', item)]);
+
+ }
+
+ },
+
+ _attachHoverStates: function(items, andSelf) {
+
+ var self = this, items = andSelf ? $('li', items).add(items) : $('li',
items);
+ items.each(function() {
+ if(!$.data(this, 'menu-hover-attached')) {
+ $(this)
+ .data('menu-hover-attached', true)
+ .hover(function(e) {
+ self._itemOver(this, e);
+ }, function(e) {
+ self._itemOut(this, e);
+ });
+ }
+ });
+
+ },
+
_resetDrilldown: function(stayOpen) {
this.breadcrumb.empty().append(this.crumbDefaultHeader);
$('.ui-menu-current', this.menu).removeClass('ui-menu-current');
@@ -259,77 +323,101 @@
},
+ _attachFlyoutStyles: function(item) {
+
+ item.style.position = 'relative';
+ var showTimer, hideTimer, self = this;
+ var sublists = $('ul', item); //select all sub lists from this point
+
+ sublists
+ .css({
+ position: 'absolute',
+ top: -1,
+ left: this.options.width, //Show them at the left of the preceding list
+ width: this.options.width, //Set the width according to the options
+ visibility: 'visible' })
+ .hide();
+
+
+ $('> a', item)
+ .addClass('ui-menu-indicator') //Add a class that shows the little
arrow to indicate a sub list
+ .html('<span class="'+self.options.nextMenuClass+'">'+$('> a',
item).text()+'</span>'); //Insert a new span
+
+ },
+
_prepareFlyout: function() {
var self = this;
this.items.addClass('ui-menu-flyout');
- this.menu.find('li:has(ul)') //Find all li's that have sub lists
- .css({ position: 'relative' }) //position them relativ to allow sub
lists stick to them
- .each(function() {
-
- var showTimer, hideTimer;
- var sublists = $('ul', this); //select all sub lists from this point
-
- sublists
- .css({
- position: 'absolute',
- top: -1,
- left: self.options.width, //Show them at the left of the preceding
list
- width: self.options.width, //Set the width according to the options
- visibility: 'visible' })
- .hide();
-
- $('> a', this)
- .addClass('ui-menu-indicator') //Add a class that shows the little
arrow to indicate a sub list
- .html('<span class="'+self.options.nextMenuClass+'">'+$('> a',
this).text()+'</span>') //Insert a new span
- .hover(function(e) {
-
- if(hideTimer) clearTimeout(hideTimer);
- var subList = $(this).next();
-
- showTimer = setTimeout(function(){
- subList.addClass('ui-component-content').show();
- subList.positionAround(e, {
- around: subList.parent(),
- direction: 'right',
- offset: [0,-1]
- });
- self._trigger('browse', e, { item: subList });
- }, 300);
-
- }, function() {
-
- if(showTimer) clearTimeout(showTimer);
- var subList = $(this).next();
-
- hideTimer = setTimeout(function(){
- subList.removeClass('ui-component-content').hide();
- }, 300);
- });
-
- $('ul a', this)
- .hover(function(){
- if(hideTimer) clearTimeout(hideTimer);
- }, function() {
- hideTimer = setTimeout(function(){
- sublists.hide();
- }, 300);
- }
- );
-
- });
-
+ //Find all li's that have sub lists and attach behaviour to them
+ this.menu.find('li:has(ul)').each(function() {
+ self._attachFlyoutStyles(this);
+ });
+ //Attach the choose click handler to all list items
$('a', this.menu).bind('click', function(e){
- self._choose($(this.parentNode), e);
- return false;
+ self._choose($(this.parentNode), e);
+ e.preventDefault();
});
},
- _generateMarkupFromJSON: function() {
+ _generateMarkupFromJSON: function(json) {
+
+ },
+
+ add: function(item, position) {
+
+ var self = this;
+ var item = $(item.constructor == String || item.jquery ? item :
this._generateMarkupFromJSON());
+
+ if(!position) {
+ this.items.append(item);
+ } else {
+
+ position = position.split('/');
+ var hash = '', old = '', append;
+ for (var i=0; i < position.length; i++) {
+ old = hash; hash += 'li:eq(' + (parseInt(position[i],10)-1) + ') ';
+ if(!$(hash, this.items).length) { append = true; break; }
+ };
+
+ if(!append) { //We want to have it before/after a node
+ $(hash, this.items).before(item);
+ } else {
+
+ if(!$(old, this.items).find('ul').length) {
+ $(old, this.items).append('<ul></ul>');
+ this._attachFlyoutStyles($(old, this.items)[0]);
+ }
+
+ $(old, this.items).find('ul').append(item);
+
+ }
+
+ }
+
+ if(this.options.type == 'drilldown') {
+
+
+
+ } else { //It's a flyout menu item
+
+ this._attachHoverStates(item, true);
+
+ //Find all li's that have sub lists and attach styling to them
+ if(item.is(':has(ul)')) this._attachFlyoutStyles(item[0]);
+ item.find('li:has(ul)').each(function() {
self._attachFlyoutStyles(this); });
+
+ //Attach the choose click handler to all list items
+ $('a', item).bind('click', function(e){
+ self._choose($(this.parentNode), e);
+ e.preventDefault();
+ });
+
+ }
},
@@ -396,7 +484,7 @@
$.extend($.ui.menu, {
manager: [],
defaults: {
- type: 'normal', //Can be set to either normal, drilldown or toolbar
+ type: 'flyout', //Can be set to either flyout, drilldown or toolbar
mode: 'static', //Can be set to context (open on right click), dropdown
or static (render into the selected element)
items: '> ul', //Can be either a jQuery selector, therefore using markup
in the selected node, or a JSON list of menu entries
appendTo: 'body', //Only in case of context/dropdown - where the actual
menu is being appended to,
@@ -410,6 +498,9 @@
hoverClass: 'ui-hover-state',
hoverClassSecondary: 'ui-component-content',
nextMenuClass: 'ui-arrow-right-default', // class to style the link
(specifically, a span within the link) used in the multi-level menu to show
the next level
+
+ //flyout specific
+ flyoutDelay: 300,
//drilldown menu specific
crossSpeed: 300, // cross-fade speed for multi-level menus