DHTML Toolbars
Release Notes and Tutorial
The DHTML Toolbars package provides full-function toolbars and menus, implemented completely in Dynamic HTML. Your toolbars can look and act like Microsoft Office toolbars (the default), or you can easily change the package's appearance and behavior.
The DHTML Toolbars package provides:
Toolbar elements can contain arbitrary HTML. You can build toolbar buttons and menu items that look like a Windows application, or you can create your own look.
Try out the toolbar on the top of this page to get a sense of what they can do. Enter a search string, pull down the Contents menu to jump to a section, change the current selection to bold, etc.
The Toolbar package is included as a sample in the DHTML Editing Component SDK. The SDK can be downloaded from http://www.microsoft.com/workshop/author/dhtml/edit/download.asp The package is part of the DHTML Editing Component SDK. The DHTML editing control plus the Toolbars package allows you to build a full-featured WYSIWYG HTML editor on a Web page. After you've downloaded the SDK see the WebEdit sample for an example of this.
The rest of this document contains:
The section gives you the basics for using the DHTML Toolbar package, and lets you get up and running quickly.
A Web page using DHTML toolbars must have the following structure:
<head>
<link
REL="stylesheet" TYPE="text/css"
HREF="toolbars.css">
</head>
<body>
... Toolbar
definitions ...
... Content container ...
<script LANGUAGE="Javascript"
SRC="toolbars.js"></script>
<script
LANGUAGE="Javascript">tbScriptletDefinitionFile =
"menubody.htm"; </script>
<script
LANGUAGE="Javascript"
SRC="tbMenus.js"></script>
</body>
The Toolbar package is broken into two pieces: toolbars and menus. Since the menu package cause additional page loading overhead, you should only include it when you actually have menus on your page.
The Toolbar package is made up of four files:
You will typically put these files in a common directory on your Web server so that different applications can all access a common location.
Every page that uses the Toolbar package must:
The Toolbar package manages the layout of the entire page. It adjusts the toolbars and the content element when the user resizes the page or changes how toolbars are docked.
Note: the Toolbar package defines many internal functions, variables and attributes. Since these end up in the namespace of your document, you need to be sure that you aren't colliding with them. The Toolbar package uses the convention of preceding all its functions, variables and attributes with 'tb' or 'TB'. If you avoid starting your functions, variables and attributes with 'tb' or 'TB', you will be safe.
Toolbars are specified via a series of nested <div> tags. Each DIV represents a toolbar element, such as a menu item, a toolbar button, or a toolbar itself.
Each toolbar DIV must contain a class attribute, which specifies the type of toolbar element this DIV represents. For example, CLASS=tbMenu is a menu element, CLASS=tbToolbar is a toolbar.
Optional attributes on the toolbar divs provide additional information such as whether a button is a toggle or a radio button (TBTYPE=toggle, TBTYPE=radio), whether a toolbar is initially docked on the top or bottom of the page (TBSTATE=dockedTop, TBSTATE=dockedBottom), etc.
Our first example shows a three button toolbar on a page. The content container simply has "Hello World" in it. The example is live. Go ahead and try it.
<head>
<link
REL="stylesheet" TYPE="text/css"
HREF="toolbars.css">
</head>
<body>
<!-- Toolbar
definitions -->
<div
class="tbToolbar" ID="Toolbar1">
<div class="tbButton" ID="DECMD_CUT"
TITLE="Cut" onclick="alert('Cut button hit');">
<img class="tbIcon"
src="images/cut.gif" WIDTH="23"
HEIGHT="22">
</div>
<div class="tbButton"
ID="DECMD_COPY" TITLE="Copy" onclick="alert('Copy
button hit');">
<img
class="tbIcon" src="images/copy.gif"
WIDTH="23" HEIGHT="22">
</div>
<div
class="tbSeparator"></div>
<div class="tbButton" ID="DECMD_PASTE"
TITLE="Paste" onclick="alert('Paste button
hit');">
<img
class="tbIcon" src="images/paste.gif"
WIDTH="23" HEIGHT="22">
</div>
</div>
<!-- Content element -->
<div id="tbContentElement"
class="tbContentElement" style="overflow:auto;
background-color: white; border: 2 inset white">
Hello World!
</div>
<script
LANGUAGE="Javascript">tbScriptletDefinitionFile =
"menubody.htm"; </script><script
LANGUAGE="Javascript"
SRC="toolbars.js"></script>
</body>
This example shows several important things:
The available toolbar elements are:
Toolbar buttons and menu items support several types of behavior, specified via the TBTYPE attribute:
The TBSTATE attribute is used to specify the state of toolbar buttons and menu items. TBSTATE has the following possible values:
The next example has two toolbars that contain examples of each of the types, behaviors and states described above. Since it uses menus, the menu script blocks are included. Try it out:
Instead of reviewing the entire sample we'll focus in on a few key areas. First, the structure of menus. Here's the source to the second menu, with the menu contents shown in red:
<div
class="tbToolbar" ID="Toolbar2"> <div
class="tbMenu" ID="Menu2">
Second
<div
class="tbMenuItem" ID="FORMAT_FONT"
TBTYPE="toggle" onclick="alert('Toggle');">
Toggle Menu Item
</div>
<div
class="tbSeparator"></div>
<div class="tbMenuItem"
ID="FORMAT_JUSTIFYLEFT" TBTYPE="radio"
NAME="MenuJustify" onclick="alert('Left Radio');">
Left Radio
<img class="tbIcon"
src="images/alignleft.gif" WIDTH="23"
HEIGHT="22">
</div>
<div
class="tbMenuItem" ID="FORMAT_JUSTIFYCENTER"
TBTYPE="radio" TBSTATE="checked"
NAME="MenuJustify" onclick="alert('Center
Radio');">
Center Radio
<img
class="tbIcon" src="images/center.gif"
WIDTH="23" HEIGHT="22">
</div>
<div class="tbMenuItem"
ID="FORMAT_JUSTIFYRIGHT" TBTYPE="radio"
NAME="MenuJustify" onclick="alert('Right
Radio');">
Right Radio
<img
class="tbIcon" src="images/alignright.gif"
WIDTH="23" HEIGHT="22">
</div>
<div
class="tbSeparator"></div>
<div class="tbSubmenu" ID="SUBMENU">
Submenu
<div class="tbMenuItem"
ID=SUBMENU1 onclick="alert('red');">
<span style="color:red"> Red
</span>
</div>
<div
class="tbMenuItem" ID=SUBMENU2
onclick="alert('green');">
<span style="color:green"> Green
</span>
</div>
<div
class="tbMenuItem" ID=SUBMENU3 onclick="alert('bold
yellow');">
<span style="color:yellow"> <b>
Bold Yellow </b> </span>
</div>
</div>
</div>
Note how menu items and submenus are nested within a menu div. Also note how a submenu is both an entry in the parent menu as well as containing its own menu items (and submenus).
Next, lets look at tbGeneral items. Here's the source to the font name element:
<select
ID="FontName" class="tbGeneral"
style="width:140" TITLE="Font Name"
onchange="alert('Font name set to: ' + FontName.value);">
<option value=Arial>Arial
<option value="Arial
Narrow">Arial Narrow
<option value=System>System
<option value="Times New Roman">Times New Roman
<option
value=Verdana>Verdana
</select>
Note that you must always specify an explicit width for tbGeneral items (style="width:140" in this example). tbGeneral elements are much more open-ended than other toolbar elements. The Toolbar package doesn't support TBTYPE or TBSTATE. for tbGeneral items; you need to do these operations on your own, in an appropriate fashion for the element you are using. You also need to decide which events to handle for the particular element (the onchange event is used in this example).
Toolbar buttons (tbButton) and menu items (tbMenuItem) only support the onclick event; no other events are fired. The onclick event does not use the standard event object; instead, you should use the tbEventSrcElement object defined in toolbars.js if you have a common event handler and need to figure out which element generated the event. Event handlers cannot be modified or reset at runtime.
Menus (tbMenu) and submens (tbSubmenu) support the tbOnMenuShow event. This event is fired immediately before the menu is shown. This gives the host the opportunity to dynamically set menu state. Menus and submenus do not support any other events besides tbOnMenuShow.
As mentioned above, tbGeneral elements fire all events and you need to choose which ones you pick up.
No events are fired for the other toolbar elements.
You can programmatically set the state of a toolbar element state at any time by calling the TBSetState(element, newState) function. This allows you to check, uncheck or gray out an element. TBSetState takes an element object and the new state value for the object.
When changing the state of a menu item, TBRebuildMenu must be called in order that the new menu item state is reflected in the menu. Typically the state of menu items on a given menu are updated before the menu is shown in the menu's tbOnMenuShow handler, then TBRebuildMenu is called. See the reference documentation section for details on TBRebuildMenu.
The DHTML Toolbars package manages the layout of the entire page. Thefore, you need to create a contents element that contains all the non-toolbar data on the page. You identify the content element by setting its ID to "tbContentElement" and its CLASS to "tbContentElement".
To host arbitrary content on the page, wrap a <div> around it, as follows:
<div
id="tbContentElement" class="tbContentElement"
style="overflow:auto; background-color: white; border: 2 inset white;
padding-left:10; padding-right:10">
... Content Here
...
</div>
You can also have the contents of the page be composed of a control, such as the DHTML Editing control. For example:
<OBJECT
id="tbContentElement" class="tbContentElement"
classid="clsid:683364AF-B37D-11D1-ADC5-006008A5848C">
</OBJECT>
Another approach is to have the contents and the toolbars be on seperate pages and use an <iframe> to put the contents into the toolbar page. This allows you to cleanly seperate contents from code, and easily reuse a set of toolbars on many different pages, ie:
<iframe id="tbContentElement" class="tbContentElement" src="contentFile.htm"></iframe>
The downside of this approach is that menus will not be dismissed if you click inside the <iframe>; there is no way to get the mousedown event from the <iframe> to outer page.
A final approach which solves this problem is to use the DHTML Edit control in browse mode to host the inner page, ie:
<OBJECT
id="tbContentElement" class="tbContentElement"
classid="clsid:683364AF-B37D-11D1-ADC5-006008A5848C">
<PARAM NAME="BrowseMode"
VALUE="-1">
</OBJECT>
You then use the LoadURL method to load up the document with the inner page.
It is important that you do not have anything other than toolbar definitions, a content element and the script file includes in the <body> section of your page.
The WebEdit sample shows how the Toolbars package can be used to build a complete HTML editor on a Web page without menus. From the WebEdit sample directory, load the file NoMenus.htm to see an example of this. Load the file FullEdit.htm for an example of an HTML editor that uses menus. Note: you must install the DHTML Editing component in order to run this sample.
This section shows some of the more advanced techniques.
Toolbars themselves have state. The TBSTATE attribute can be usedon any toolbar. It has the following values when used on a toolbar:
Toolbar state can be specified initially or changed dynamically via TBSetState().
Toolbars will be able to be dragged around by the user to reorder them and move them between the top and bottom docking locations. At present this functionality is not yet implemented. Unfortunately it is not be possible to implement floating toolbars, since they can't always be kept on top when there are windowed controls on the page.
An extremely useful facility is the ability to specify the contents of toolbars and menus on the fly programmatically. The Toolbar package allows you to add and delete any element (and entire toolbars). You can also change any aspect of an existing element on the fly.
The basic approach is to make your changes to the toolbar divs using the standard IE4 DOM, then call a function to let the toolbar package know that you've made changes. In order to optimize performance, you should make all your changes via the DOM, then call the toolbar package once.
There are two Toolbar package functions that you call to notify of changes:
See the reference documentation section for details on these calls.
The Contents menu on the current page is a good example of how to build menus on the fly. It creates a heirarchical menu structure for all the <H1> and <H2> elements on this page. Try it out!
There is one tricky issue with building menus on the fly. The toolbar package needs to know the maximum nesting depth of the submenu on the page when the page is first being built. Therefore, you might need to statically declare some dummy submenus if you are building your menus on the fly. That is exactly what the Contents menu example does, declaring a "DummyContentsSubmenu" so that there is one level of nesting when this page is first built.
Set the class attribute of a toolbar div to one of these styles in order to specify the type of toolbar element it is.
tbToolbar.
Toolbar.
tbButton. Toolbar button
tbIcon. Toolbar or menu icon
tbSeparator. Toolbar or menu
sepertor
tbMenu. Pulldown menu
tbMenuItem. Menu item
tbSubmenu. Submenu
tbGeneral.
Arbitrary HTML element in a toolbar.
tbContentElement. Identifies an HTML element
as the page body. One and only one element on the page must have this class.
The element must also have its ID set to "tbContentElement".
Optional toolbar element characteristics are set via these attributes.
TBTYPE. Element type. If no TBTYPE attribute is specified then the element is a simple button. Possible values are:
Toolbars: can have a TBTYPE attribute. Values are:
TBSTATE. State of the element. Possible values are:
If no TBSTATE attribute is specified then the state is unchecked. Toolbars can also have a TBSTATE attribute. Values are:
Default is dockedTop.
tbOnMenuShow. For tbMenu and tbSubmenu only. Event handler that is called immediately prior to showing a menu or submenu. Use this to set the state of menu items. This attribute can either be set on individual menus and submenus, or on a toolbar, in which case it is fired for every menu and submenu within that toolbar. The menu that is about to be shown is provided in tbEventSrcElement (see below).
Programmatic interfaces to the toolbar package.
TBSetState(element, newState)
Sets
the state of element to newState.
element is an object. newState
is a string containing a TBSTATE
value.
TBRebuildToolbar(toolbar,
rebuildMenus)
Use this routine to change the contents of a toolbar on the fly. Make
all changes (adding, removing and modifying toolbar elements), then call
this routine once. This routine can also be used to add an entirely new
toolbar. toolbar is an object, the toolbar to
rebuild.
rebuildMenus is a boolean that
specifies whether the menus and submenus contained in the toolbar should
also be rebuilt. Only set this to true if you need them rebuilt; its an
expensive operation.
TBRebuildMenu(menu, rebuildSubmenus)
Use this
routine to change the contents of a menu or a submenu on the fly. Make all
changes (adding, removing and modifying menu items), then call this routine
once. menu is an object; the menu to rebuild.
rebuildSubmenus is a boolean that specifies
whether the submenus on this menu should also be rebuilt. TBRebuildMenu must
be called after changing the state of menu items using TBSetState.
tbEventSrcElement. Contains the element object that an event was fired on. The toolbar package can't support the standard event object; this object performs a similar function.
TB_STS_OK.
Successful return value.
TB_E_INVALID_CLASS. An element has an
unrecognized class attribute (probably a misspelling).
TB_E_INVALID_TYPE.
Invalid
TBTYPE value.
TB_E_INVALID_STATE. Invalid TBSTATE value.
TB_E_NO_ID.
Element does not
have an ID.