r876 - in branches/experimental: tests/visual/menu ui

r876 - in branches/experimental: tests/visual/menu ui


Author: paul.bakaus
Date: Fri Nov 7 03:54:23 2008
New Revision: 876
Modified:
branches/experimental/tests/visual/menu/menu.html
branches/experimental/ui/ui.core.position.js
branches/experimental/ui/ui.menu.js
Log:
core (experimental): renamed positionTo to positionAround, option relatedTo
to around
menu: implemented drilldown (still needs refactoring, selectCategories
doesn't work fully), browse/select/open/close events
Modified: branches/experimental/tests/visual/menu/menu.html
==============================================================================
--- branches/experimental/tests/visual/menu/menu.html    (original)
+++ branches/experimental/tests/visual/menu/menu.html    Fri Nov 7 03:54:23
2008
@@ -16,6 +16,7 @@
            body,html {
                margin: 0;
                padding: 0;
+                font-size: 12px;
            }
            
            #menu2 {
@@ -29,16 +30,49 @@
            $(document).ready(function() {
                
                $('#menu1').menu({
-                    mode: 'static'
+                    mode: 'static',
+                    type: 'drilldown',
+                    //selectCategories: true,
+                    select: function(e, ui) {
+                        console.log('Selected item ', ui.item);
+                    },
+                    browse: function(e, ui) {
+                        console.log('Browsing item ', ui.item);
+                    }
                });
                
                $('button').menu({
-                    items: '#items2'
+                    items: '#items2',
+                    //type: 'drilldown',
+                    select: function(e, ui) {
+                        console.log('Selected item ', ui.item);
+                    },
+                    browse: function(e, ui) {
+                        console.log('Browsing item ', ui.item);
+                    },
+                    open: function(e, ui) {
+                        console.log('Opened menu');
+                    },
+                    close: function(e, ui) {
+                        console.log('Closed menu');
+                    }
                });
                
                $('#menu2').menu({
                    items: '#items3',
-                    mode: 'context'
+                    mode: 'context',
+                    select: function(e, ui) {
+                        console.log('Selected item ', ui.item);
+                    },
+                    browse: function(e, ui) {
+                        console.log('Browsing item ', ui.item);
+                    },
+                    open: function(e, ui) {
+                        console.log('Opened menu');
+                    },
+                    close: function(e, ui) {
+                        console.log('Closed menu');
+                    }
                });
                
            });
Modified: branches/experimental/ui/ui.core.position.js
==============================================================================
--- branches/experimental/ui/ui.core.position.js    (original)
+++ branches/experimental/ui/ui.core.position.js    Fri Nov 7 03:54:23 2008
@@ -1,7 +1,7 @@
-$.fn.positionTo = function(e, o) {
+$.fn.positionAround = function(e, o) {
    var options = $.extend({
-        relativeTo: 'mouse',
+        around: 'mouse',
        direction: 'default',
        forceDirection: false    
    }, o);
@@ -20,9 +20,9 @@
    };
    
-    if($(options.relativeTo).length && $(options.relativeTo)[0].nodeName) {
//If relativeTo is an element
+    if($(options.around).length && $(options.around)[0].nodeName) { //If
around is an element
        
-        var element = $(options.relativeTo),
+        var element = $(options.around),
            offset = element.offset(),
            relHeight = element[0].offsetHeight,
            relWidth = element[0].offsetWidth
Modified: branches/experimental/ui/ui.menu.js
==============================================================================
--- branches/experimental/ui/ui.menu.js    (original)
+++ branches/experimental/ui/ui.menu.js    Fri Nov 7 03:54:23 2008
@@ -72,7 +72,7 @@
        }
        
        this.items.css('visibility', 'visible');        
-        if(this.menu.css('position') != 'absolute') //If the position isn't
absolute,
+        if(this.menu.css('position') != 'absolute' &&
this.options.type != 'drilldown') //If the position isn't absolute,
            
this.menu.css('position', 'absolute').height(this.menu.height()).css('position', 'relative');
//set a hard value for the height
            
@@ -98,7 +98,161 @@
    },
    
    _prepareDrilldown: function() {
+
+        var self = this;
+
+        var breadcrumb = $('<ul class="ui-menu-dd-breadcrumb
ui-component-content"></ul>');
+        var crumbDefaultHeader = $('<li
class="ui-menu-dd-text">'+this.options.crumbDefaultText+'</li>');
+        var firstCrumbText = this.options.backLink ? this.options.backLinkText :
this.options.topLinkText;
+        var firstCrumbClass = this.options.backLink ? 'ui-menu-prev-list
ui-arrow-left-default' : 'ui-menu-all-lists';
+        var firstCrumb = $('<li class="'+firstCrumbClass+'"><a
href="#">'+firstCrumbText+'</a></li>');
+        
+        if (!this.items.is('.ui-menu-dd')) {        
+            
+            this.menu
+                .css({ overflow: 'hidden' })
+                .find('ul').addClass('ui-component-content');
+                
+            this.items
+                .addClass('ui-menu-dd ui-menu-current')
+                .find('ul').css({ width: this.options.width });
+                
+            // set up links to be split-button (selectable nodes + navigation
links) or single button (navigation only)
+            this.items.find('a').each(function(){
+                
+                if($(this).next().is('ul')) {
+                    if (self.options.selectCategories) {                    
+                        $(this).addClass('ui-menu-split-btn').html('<span>'+
$(this).text()+'</span>')
+                            .after('<a href="#" class="ui-menu-nextlevel"><span
class="'+self.options.nextMenuClass+'">View next level &gt;</span></a>');
+                    }
+                    else {
+                        $(this).addClass('ui-menu-indicator').html('<span
class="'+self.options.nextMenuClass+'">'+ $(this).text()+'</span>');
+                    };        
+                };
+
+            });            
+            
+            // standardize all menu heights & widths so that they cover the
previous menu completely    
+            var listHeights = [];
+            this.items.find('ul').each(function(i){ listHeights[i] =
$(this).height(); });
+            listHeights.sort(function(a, b) { return b - a; });        
+            this.items.find('ul').css({ height: listHeights[0], width:
this.options.width });
+            
+            // apply scrollbar to the menu when it exceeds max height
+            if (listHeights[0] > this.options.maxHeight) {
+                this.menu
+                    .find('.ui-menu-dd')
+                    .addClass('ui-menu-scroll')
+                    .css({ height: this.options.maxHeight,
overflow: 'auto', 'overflow-x': 'hidden' })
+                        .find('ul')
+                        .css({ width: this.options.width - 16 });
+            } else {
+
+                this.menu
+                    .find('.ui-menu-dd')
+                    .css({ height: listHeights[0] }).find('ul').css({ width:
this.options.width });
+            };
+            
+        };
+        
+
+        this.options.backLink ?
breadcrumb.addClass('ui-menu-footer').appendTo(this.menu) :
breadcrumb.addClass('ui-menu-header').prependTo(this.menu);
+        breadcrumb.append(crumbDefaultHeader);
        
+        this.resetDrilldownMenu = function(stayOpen){
+            breadcrumb.empty().append(crumbDefaultHeader);
+            $('.ui-menu-current').removeClass('ui-menu-current');    
+            if (!stayOpen) { self.menu.find('.ui-menu-dd ul').css({
visibility: 'hidden' }); }
+        };
+        
+        var showNextLevel = function(el, e){
+            
+            var thisLink = $(el);
+            var thisList = $(el).parents('ul:eq(0)');
+            var nextList = $(el).next();        
+            
+            // first breadcrumb link
+            if (breadcrumb.find('li').size() == 1){                
+                breadcrumb.empty().append(firstCrumb);
+                
+                // 'back' link
+                if (firstCrumb.is('.ui-menu-prev-list')) {        
+                    
+                    $('.ui-menu-prev-list a').bind('click.menu', function(){
+                        
+                        $('.ui-menu-current').animate({ left: self.options.width },
self.options.crossSpeed);                            
+                        if ($('.ui-menu-current').parents('ul').eq(0).is('.ui-menu')) {
+                            self.resetDrilldownMenu(true);                    
+                        }
+                        else {
+                            $('.ui-menu-current')
+                                .removeClass('ui-menu-current')
+                                .parents('ul').eq(0).addClass('ui-menu-current');
+                        };
+                        return false;
+                    });
+                    
+                }    // standard breadcrumb
+                else if (firstCrumb.is('.ui-menu-all-lists')) {
+                    
+                    $('.ui-menu-all-lists a').bind('click.menu', function(){
+                        
self.menu.find('ul').not('.ui-menu, .ui-menu-dd-breadcrumb').animate({
left: self.options.width }, self.options.crossSpeed);
+                        if ($(this).next().is('span')) { $(this).next().remove(); }
+                        self.resetDrilldownMenu(true);    
+                        return false;        
+                    });
+                    
+                };
+                            
+            };        
+            
+            var addNewCrumb = function() {
+                
+                var crumbText = (thisLink.prev().is('a')) ? thisLink.prev().text() :
thisLink.text();                    
+                var newCrumb = $('<li class="ui-menu-current-crumb" style="display:
none;"><a href="javascript://"
class="ui-menu-crumb">'+crumbText+'</a></li>');            
+                $('.ui-menu-current-crumb').removeClass('ui-menu-current-crumb');
+                newCrumb.appendTo(breadcrumb).prev().append(' <span>&gt;</span>');            
+                newCrumb.show().find('a').click(function(e){
+                    if ($(this).parent().is('.ui-menu-current-crumb')){
+                        self._trigger('select', e, { item: $(this.parentNode) });    
+                        return false;
+                    }
+                    else {
+                        nextList.find('ul').animate({ left: self.options.width },
self.options.crossSpeed);                                    
+                        $(this).parent().nextAll().css({ visibility: 'hidden'
}).slideUp(self.options.crossSpeed, function(){$(this).remove();});
+                        
$(this).parent().addClass('ui-menu-current-crumb').find('a').next().remove();
+                        self._trigger('browse', e, { item: null }); //TODO: Reference to item
+                        return false;
+                    };
+                });
+                
+            };
+            
+            if (!self.options.backLink)
+                addNewCrumb();
+                
+            // show the next list
+            $('.ui-menu-current').removeClass('ui-menu-current');
+            nextList.css({ visibility: 'visible', left: self.options.width })
+                .animate({ left: 0 }, self.options.crossSpeed)
+                .addClass('ui-menu-current');
+                
+            self._trigger('browse', e, { item: nextList });    
+            
+        };
+        // end showNextLevel
+                
+        self.items.find('a').bind('click.menu', function(e){        
+            if ($(this).is('.ui-menu-indicator') ||
$(this).is('.ui-menu-nextlevel')) {
+                showNextLevel(this, e);
+                return false;
+            }
+            else {
+                self._trigger('select', e, { item: $(this.parentNode) });
+                return false;
+            };        
+        });
+
    },
    
    _prepareFlyout: function() {
@@ -133,10 +287,11 @@
                        
                        showTimer = setTimeout(function(){
                            subList.addClass('ui-component-content').show();
-                            subList.positionTo(e, {
-                                relativeTo: subList.parent(),
+                            subList.positionAround(e, {
+                                around: subList.parent(),
                                direction: 'right'
-                            });    
+                            });
+                            self._trigger('browse', e, { item: subList });    
                        }, 300);
                        
                    }, function() {
@@ -160,9 +315,10 @@
                );
            });
-        
-        $('a', this.menu).bind('click', function(){
-            alert('clicked');        
+
+
+        $('a', this.menu).bind('click', function(e){
+            self._trigger('select', e, { item: $(this.parentNode) });    
            return false;
        });
            
@@ -183,13 +339,14 @@
        }
    
        this.menu.show();
-        this.menu.positionTo(e, {
-            relativeTo: this.options.mode == 'context' ? 'mouse' : this.element,
+        this.menu.positionAround(e, {
+            around: this.options.mode == 'context' ? 'mouse' : this.element,
            direction: this.options.direction
        });
        
        $.ui.menu.manager.push(this);
        this.visible = true;
+        this._trigger('open', e, { });
        
    },
    
@@ -203,18 +360,19 @@
        }
        for (var i=0; i < $.ui.menu.manager.length; i++) {
-            if(exclusion != $.ui.menu.manager[i]) $.ui.menu.manager[i].close();
+            if(exclusion != $.ui.menu.manager[i])
$.ui.menu.manager[i].close(excludeEvent);
        };
        
    },
    
-    close: function() {
+    close: function(e) {
        
        this.menu.hide();
        for (var i=0; i < $.ui.menu.manager.length; i++) {
            if($.ui.menu.manager[i] == this) $.ui.menu.manager.splice(i,1);
        };
        this.visible = false;
+        this._trigger('close', e, { });
        
    }
    
@@ -223,21 +381,27 @@
$.extend($.ui.menu, {
    manager: [],
    defaults: {
-        type: 'normal', //Can be set to either normal, ipod style or toolbar
-        mode: 'dropdown', //Can be set to context (open on click) or static
(render into the selected element)
+        type: 'normal', //Can be set to either normal, drilldown or toolbar
+        mode: 'dropdown', //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,
        exclusive: true, //Defines wether only this menu can be shown at the
same time
        
        width: 180,
-        height: null, //If height specified and surpassed, up and down arrows at
both ends are shown to navigate up and down,
+        maxHeight: 200, //If height specified and surpassed, scrollbars will be
added to the drilldown
        
        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
        
-        //iPod menu specific
-        backLink: true // in the ipod-style menu: instead of breadcrumbs, show
only a 'back' link
+        //drilldown menu specific
+        crossSpeed: 300, // cross-fade speed for multi-level menus
+        backLink: true, // in the drilldown-style menu: instead of breadcrumbs,
show only a 'back' link,
+        backLinkText: 'Back',
+        topLinkText: 'All',
+        crumbDefaultText: ' ',
+        selectCategories: false // set to true if each menu item is a split
button where you can choose either the text (to make a selection) or "next"
arrow (to navigate)
+        
    }
});