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.
Regular builds of the Toolbar package can be downloaded from http://rad/triedit The package is part of the DHTML Editing Control 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 you can see a sample of this.
Questions, bug reports and comments should go to the DHTML Editing Component mailing list. Add yourself to this mailing list to get announcements and see what other people are up to. Or feel free to send mail to the author directly.
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="tbSeperator"></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="tbSeperator"></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="tbSeperator"></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.
At present it is not possible to change toolbar elements; that is, add or delete elements, change the content of a menu, etc. However, this capability will be available shortly.
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.
Here's a sample that shows how the Toolbars package can be used to build a complete HTML editor on a Web page without menus. Here's a verson that includes 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 able 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 four 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
tbSeperator. 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.
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.
This section lists the current set of known problems and bugs, plus the known work items still left to do for the first release.
This section gives a brief description of how the Toolbars package is implemented, and some tips on customizing it.
<<<To be completed shortly...