Sonntag, Januar 06, 2008

Building menus with OpenAjax events

Implementing menus is often based on publishing events. I personally cannot remember any system that does not.

The web control that is used to implement menubars is therefore a good sample for a html, css and JavaScript based component that is extendable and completely relies on a declarative approach (also a widely used pattern menu system).

HTML

The html code for building a menubar is implemented by using an outer <div> element and on level of inner elements that can implement image-buttons, text-buttons and separators by using <span> and <img> html elements.

The look and feel of all the elements is defined by using CSS rules based on class names.

The class name "VEMenuBar" is used for the outermost element. Buttons are marked by using “VEMenu” and the separators are marked with the class name “VEMenuSeparator”.

Here is a small sample:  

<div class="VEMenuBar" eventnamespace="de.mathertel.datasource"> 
  <span class="VEMenu" eventname="search">Search</span> 
  <img class="VEMenuSeparator" alt="" src="../controls/images/white.gif" /> 
  <img class="VEMenu" alt="show first record" eventname="first" src="../controls/images/first.gif" /> 
</div>
CSS

Based on the class names the design can be specified. Some of the class names are modified when the hover effect is enabled on the page.

.VEMenuBar { background-color:#eeeeee;padding:2px 8px 2px 8px;height:20px;overflow:hidden;}

This defines the background color of the menubar. The padding definition will keep the inner icons away from the border.

.VEMenuBar * { vertical-align:top;}

All elements will be vertically aligned by the top.

.VEMenuBar span {display:-moz-inline-box;display:inline-block;}

<span> elements inside the menubar can be used to create buttons with a text caption. This rule is used to position span elements by using the padding.
The IE will use the inline-block rule and Mozilla/Firefox will use the -moz-inline-box rule. They both don't understand the other syntax and will just ignore it.

.VEMenu { border:0px;padding:2px}

This rule is used for the state of an icon that is not hovered or pushed. In my layout it has no border and is padding the graphic by using 2 pixels on every side.

.VEMenuHover { border-style:solid;border-width:1px;border-color: #acc1e4 #203050 #203050 #acc1e4;padding:1px}

This is the state of an icon when the mouse is over it but is not pushed. In my layout I use 1 pixel of border on every side with some colors that makes the icon look like being raised a little bit. I reduce the padding to 1px to avoid the shifting and flickering of the graphic.

.VEMenuPushed { border-style:solid;border-width:1px;border-color: #203050 #acc1e4 #acc1e4 #203050;padding:1px}

This is the state of a icon when the icon is pushed down. In my layout I use 1 pixel of border on every side but with different colors and I reduce the padding to 1 px to avoid the shifting and flickering of the graphic.

.VEMenuSeparator { display:inline-block;height:20px;width:1px;border-left:solid 1px #203050;}

Separators between groups of symbols are included by using a 1x1 white pixel image with a classname "VEMenuSeparator" that is displayed with a darker border on the left side.

Declaring and publishing events

Event publishing is the duty of this component. All that we need to declare is what event will be published by a inner element and that is done by using attributes of these elements.

eventname

This attribute that is valid on any nested element of the menubar’s outermost <div> element contains the event name that will be published when the element is clicked. This attribute may contain only a local event name or a full qualified eventname including the namespace.

eventnamespace

This attribute that on the menubar’s outermost <div> element and specifies a namespace that is used for any eventnames that are not fully qualified.

(Fully qualified eventnames are determined by the fact that they contain a dot character.)

The menubar behavior (MenubarBehavior)

This behavior implements all the basic functionality for menubars. When bound to a html element it also loops through all the children elements on the first level an sets the hover attribute to true for those elements that have a class name "VEMenu". This allows enabling the hover effect without implementing the hover attribute for every menu item.

If you set the tabindex property on menu items another functionality is enabled. By setting tabindex to a value greater then 0 the element can get the focus either by using the tab key until you reach the right element or by using the menu with the mouse. When pressing the space bar while the focus is on a specific menuitem the onclick method of the menuitem will be called. This allows you to use the keyboard instead of clicking with the mouse and also allows repeating menu commands in an easy way.

When using ASP.NET it is easy to build a menubar by using the available web control:

<ve:MenuBar runat="server" eventnamespace="de.mathertel.edit"> 
  ...
</ve:MenuBar> 

The implementation in JavaScript is available here:

http://www.mathertel.de/AjaxEngine/documentation/ViewDoc.aspx?file=~/controls/menubar.js

A sample page that uses this control is available here:

http://www.mathertel.de/AjaxEngine/S04_VisualEffects/InlineEditDemo.aspx

(see the source code of the page by using the view link in the upper right corner)

Keine Kommentare: