Cascading Popup Menus v5.2
Overview
This file explains how to go about creating and editing menus using the
Cascading Popup Menus JavaScript.
If you're not familiar with JavaScript syntax, you may find the
Syntax Helper script useful, which can create the relevant commands
listed here from selections in forms.
Colour coding used in this document: Variable or Object Name,
'String value', Number value,
Boolean value (true or false), File Name.
Conditions of Use
By using this script, you agree that:
- EITHER:
- Donating Users: This script is "donation-ware". Users who decide to
make a donation to support this script
may use it without placing a visible link on the resulting website.
Please consider making a donation, as I have put in a lot of time developing, debugging and
documenting scripts, and any support is welcome.
- Free Users: If you download and use this script for free, you must place a
visible link on websites using this script to the front page of my site, e.g.
'DHTML / JavaScript by TwinHelix Designs'.
- You must leave the "Script Name/Copyright/URL" comment in the source of the script file.
- This script is provided on an "AS-IS" basis, without any warranties, and you use it
entirely at your own risk.
- You must not redistribute this script to third parties, either intact or modified.
If these conditions do not suit your project, please contact me to arrange alternatives.
Files You Need
This script is split over several files:
- pop_style.css: The CSS information used to control menu text and
border appearance.
This must be included in the <HEAD> of any files containing menus.
- pop_core.js: The core menu functions, you don't need to edit this.
I have provided two copies, one with comments in it if you do wish to edit it, and one with all the
comments removed for deploying on a website.
- pop_data.js: Contains your menu information and layout, this is the
file you need to edit. You can have several menu data files one one page if you want.
- pop_events.js writes the menus to the current document.
This must be included right after the <BODY> tag of all files containing
menus, and not nested inside tables/forms/divs/etc.
The pop_core.js and pop_data.js must be included
in order, either above the events file (for single frame usage) or in the frameset (for cross-frame
usage of the script, see the Frameset Readme for more info).
Menu Data: File Structure
var ItemStyleName = new ItemStyle(...parameters...);
var ObjectName = new PopupMenu('ObjectName');
with (ObjectName)
{
startMenu(...parameters...);
addItem(...parameters...);
}
...menu effects and optional code...
First, you create ItemStyles, which are collections of sizes, colours,
borders and CSS classnames to be applied to menus and items later.
This allows you to give different menus a consistent look and feel.
Then, you create one or more menu objects, giving each a unique name. The example script includes
one named pMenu. Each menu object must be passed its own name in quotes.
To these menu objects, you add individual menus using the startMenu and
addItem commands.
Finally, the Menu Effects section at the bottom of the file is optional.
It contains extra code for borders, dropshadows, animation, custom mouse events in menus (examples
like status messages are included), and custom item arrangement.
Comments are included there, alongside the functions called. Read through if you're interested.
Otherwise, the entire menu effects section can be deleted if you don't want to use them.
ItemStyle()
var ItemStyleName = new ItemStyle(
Length,
Spacing,
'Popout Indicator',
Indicator Position,
Padding,
'Out Background',
'Over Background',
'Out Text Class',
'Over Text Class',
'Out Border Class',
'Over Border Class',
Out Opacity,
Over Opacity,
'Link Cursor',
'Default Cursor');
- Length: In pixels. For horizontal menus this is the width of items
using this ItemStyle, for vertical menus it's the height.
- Spacing: Gap, in pixels, after items that use this ItemStyle.
- 'Popout Indicator': The small arrow indicating a submenu.
Set it to '' for no indicator, otherwise it can be an HTML string like
'>' or an '<IMG>' tag.
To swap on mouseover, set as 'SWAP:out text^over text'.
- Indicator Position: In pixels, measured from the left item edge
(if it's a positive number) or right edge (negative).
- Padding: In pixels, the gap between the item edge and text.
- 'Backgrounds' (x2): You can use background colours or images; to use
background images, set a filename like '/images/pic.gif', or for colours
use a colour name/value.
For fading background colours, you can use the form '10#112233' where the
number before the # is the fade speed (in percent).
For transparent backgrounds use an empty string ''.
- 'Text/Border Classes' (x2): These refer to classes in the
.CSS file, and set the font/colour/size of the text and borders.
If you don't want borders, set the border class to an empty string ''.
- Opacities (x2): Set these to null (without quotes) if you want solid
items, or use numbers between 0 and 100 for translucent items.
- 'CSS Cursors' (x2): The 'Link Cursor' applies to all items that link
to files or JavaScript commands, and the default cursor is used for empty or 'sm:' items.
Cursor values should be valid CSS cursor names like 'default', 'hand', 'crosshair' and so on
(note that 'hand' is automatically translated into 'pointer' where needed).
startMenu()
startMenu(
'Menuname',
Orientation,
Left Offset,
Top Offset,
Menu Breadth,
Default ItemStyle,
'Parent Frame',
Show onclick);
- 'Menuname': A string like 'root' or
'mFile', which you can use to refer to this menu and pop it out.
Any menuname starting with the letters 'root' is special, shown initially
and never hidden.
Don't use spaces or special characters in menunames!
- Orientation: Use true for a vertical menu,
or false for a horizontal menubar.
- Offsets: Specify the point in the page over which the menus will hover.
If you set the Left or Top position as a NUMBER, e.g. 130 this menu will
be offset from the item that popped it out by that many pixels.
If you set them as a STRING 'in quotes', this menu will be offset from the
top/left corner of the whole document in pixels.
Strings are evaluated as JavaScript expressions that can centre, right-align, scroll or otherwise
position the menu, see the advanced positioning section for more info.
Note: 'root' menus are always absolutely positioned from the page corner.
- Menu Breadth: The breadth is the width of vertical menus, or the
height of horizontal menus, both in pixels.
- Default ItemStyle: Used for item in this menu unless they specify one
of their own, to control appearance and item lengths.
- OPTIONAL: 'Parent Frame': If left out or set to an empty string
'', menus will display in the current window.
Otherwise, set to a frame reference like 'content' to show the menu in a
frame by that name (only if you're using the frameset version of the script).
- OPTIONAL: Show onclick: Set to true to show
this menu onclick instead of the default onmouseover appearance.
addItem()
addItem(
'Item HTML',
'URL / Menuname / Command',
'Item Type',
Custom ItemStyle,
Length,
Spacing.....);
- 'Item HTML': The text or HTML to display in the item.
It can change on hover, using the format: 'SWAP:Out text^Over text'.
Try swapping two <IMG> tags for rollover image items perhaps.
- 'URL / Menuname / Command': What to do with the item when the user
points at it or clicks it. Set to either a URL like '/folder/file.html',
a menuname like 'mFile', or a JavaScript command like
'alert("hello")'.
Note that URLs are usually relative to the HTML page that contains the menu, so if you are
using folders or frames specify URLs absolutely, that is starting with a slash '/'.
- 'Item Type': If your item loads a filename in the current window,
set it to an empty string ''.
If you want to load a file in another frame, set it to a frame reference like
'top.content' to load your file in a frame named 'content'.
If you are popping out a submenu, set it to 'sm:'.
If your item runs a JavaScript command, set it to 'js:'.
- OPTIONAL: Custom ItemStyle: If you want, pass an ItemStyle to this item
to override the menu default (e.g. for 'header' items in menus).
Set it to null or leave out entirely to use the default menu ItemStyle.
- OPTIONAL: Length, Spacing.....: You can
override the ItemStyle parameters individually, in the same order as ItemStyles, if you want to give
this item a unique size, colour, indicator etc. See examples in the demo script for this.
The addItem() and startMenu() commands return references to the objects they create.
One practical use for this is to add an onclick action to an 'sm:' type menu item (that normally
cannot navigate to a file), set as evaluable strings.
You can also apply onmouseover and onmouseout handlers to items the same way.
Suggested syntax:
with(addItem('Text', 'menuName', 'sm:')) onclick='window.location.href="file.html"';
Advanced Positioning (Centering menus etc.)
As mentioned above, the Left and Top positions for each menu can be JavaScript expressions.
I've provided several functions in this script with the page object,
to detect window dimensions or the position of a named anchor, and use that to align menus.
They are:
- 'page.winW()', 'page.winH()':
These return the width and height of the window area.
- 'page.scrollX()', 'page.scrollY()':
These return the current scroll position of the page.
- 'page.elmPos("name").x',
'page.elmPos("name").y': Return the X/Y positions of an anchor tag.
This function resides in the "Menu Effects" section of the script and is optional.
The values from these expressions are then set as the distance (in pixels) from the upper-left
corner of the entire document, to the upper-left corner of the menu in question (this overrides the
normal relative positioning from parent menus).
You can write your own expressions if you want (and call your own functions perhaps), otherwise
here are some cut-and-paste replacements for the standard root menu in the single-frame example:
// Centre the menu, set its left position as half the window width, less half the menu width:
startMenu('root', false, 'page.winW()/2 - pMenu.menu.root[0].menuW/2',
0, 17, hBar);
// Scroll the menu with the page, set its top position to the window scroll position.
startMenu('root', false, 10, 'page.scrollY()', 17, hBar);
// Hover the menu over an anchor <a id="home" name="home"> in the page,
positioned 20px below it.
// If you're doing this, you should have the anchor before or near this script in the document,
// a good idea is to move the whole script just before the closing BODY tag.
startMenu('root', false, 'page.elmPos("home").x',
'page.elmPos("home").y + 20', 17, hBar);
If you're using cross-frame menus, include the name of the relevant frame in the expression
like so: 'content.page.scrollY()'.
Frameset Readme
This script supports displaying menus in different frames with a few tweaks -- see the
demo frameset.
To do this, you must include the pop_core.js and any
pop_data.js files in the frameset, and include the
.CSS and pop_events.js files in ALL documents
loaded in the frames.
Then, all you have to do is make sure you include a 'parent frame' value with each of your startMenu()
commands, so menus will display in the correct frame.
There are several restrictions however:
- Menu cannot overlap frame borders -- they're HTML elements and must remain wholly in one
frame only.
- All files loaded must be from the same domain as the frameset. This means you can't load in
a page of Google search results (or similar) and pop menus out over it.
- You must load HTML documents in the frames, of course -- you can't pop menus out over PDFs,
Word documents, text files, and so on.
- I recommend you don't nest frames, that is load another frameset inside your menu frameset.
If you are doing this, remember to set parent menus to 'content.subFrameName' or similar.
I also recommend you specify item filenames absolutely, e.g.
'/folder/file.html', as relative navigation around framesets can get tricky.
Item targets are measured relative to the frameset file, so addItem('a', 'b',
'') will load 'b' in the whole frameset.
Of course, you can set the frame target normally to load files in subframes, like addItem('a', 'b',
'content');
The example setup allows the menus in sub-frames scroll with their windows. All you have to do is
use the 'page' object in that frame in a formula to get the current scrolling position of that
frame, and then add or subtract pixels to position the menus from the scroll position, e.g. for a
menu in a frame named 'xyz', we would set it to appear in that frame and appear near the top and
100px from the left:
startMenu('menuName', false, 'xyz.page.scrollX()+100',
'xyz.page.scrollY()+10', 17, hBar, 'xyz');
Relative positioning works too (that is, numbers as positions), but only really makes sense if the
menus are in the same frame or the frames are aligned with each other in the frameset.