HTML::YUI3::Menu - Convert a Tree::DAG_Node object into the HTML and JS for a YUI3 menu


Get a tree of type Tree::DAG_Node from somewhere, and convert it into HTML.

This program is shipped as scripts/

All programs in scripts/ are described below, under "Testing this module".

        #!/usr/bin/env perl
        use strict;
        use warnings;
        use DBI;
        use HTML::YUI3::Menu;
        use HTML::YUI3::Menu::Util::Config;
        use Tree::DAG_Node::Persist;
        # --------------------------
        my($dbh)    = DBI -> connect($ENV{DBI_DSN}, $ENV{DBI_USER}, $ENV{DBI_PASS});
        my($driver) = Tree::DAG_Node::Persist -> new
         context    => 'HTML::YUI3::Menu',
         dbh        => $dbh,
         table_name => 'items',
        my($tree)   = $driver -> read(['url']);
        my($config) = HTML::YUI3::Menu::Util::Config -> new -> config;
        my($yui)    = HTML::YUI3::Menu -> new
                 horizontal    => 1,
                 menu_buttons  => 0,
                 split_buttons => 0,
                 switch_js     => 1,
                 template_path => $$config{template_path},
                 tree          => $tree,
        $yui -> run;

        my($menu) = $yui -> menu;
        my($js)   = $yui -> js;


HTML::YUI3::Menu converts a tree of type Tree::DAG_Node into the HTML and JS for a YUI3 menu.


This module is available as a Unix-style distro (*.tgz).

See for help on unpacking and installing distros.

Installing the module

The Module Itself

Install HTML::YUI3::Menu as you would for any Perl module:


        cpanm HTML::YUI3::Menu

or run:

        sudo cpan HTML::YUI3::Menu

or unpack the distro, and then either:

        perl Build.PL
        ./Build test
        sudo ./Build install


        perl Makefile.PL
        make (or dmake or nmake)
        make test
        make install

The Configuration File

All that remains is to tell HTML::YUI3::Menu your values for some options.

For that, see config/

If you are using Build.PL, running Build (without parameters) will run scripts/, as explained next.

If you are using Makefile.PL, running make (without parameters) will also run scripts/

Either way, before editing the config file, ensure you run scripts/ It will copy the config file using File::HomeDir, to a directory where the run-time code in HTML::YUI3::Menu will look for it.

        shell>cd HTML-YUI3-Menu-1.00
        shell>perl scripts/

Under Debian, this directory will be $HOME/.perl/HTML-YUI3-Menu/. When you run, it will report where it has copied the config file to.

Check the docs for File::HomeDir to see what your operating system returns for a call to my_dist_config().

The point of this is that after the module is installed, the config file will be easily accessible and editable without needing permission to write to the directory structure in which modules are stored.

That's why File::HomeDir and Path::Class are pre-requisites for this module.

All modules which ship with their own config file are advised to use the same mechanism for storing such files.

Constructor and Initialization

new() is called as my($builder) = HTML::YUI3::Menu -> new(k1 => v1, k2 => v2, ...).

It returns a new object of type HTML::YUI3::Menu.

Key-value pairs in accepted in the parameter list (see corresponding methods for details):

o horizontal => $Boolean
o menu_buttons => $Boolean
o split_buttons => $Boolean
o switch_js => $Boolean
o template_path => $path
o tree => $tree



Set the option to make menus vertical (0) or horizontal (1).

Note: At the moment, you must always set this to 1.

The default is 0.

This option is mandatory.


Returns the Javascript generated by the call to run().

The return value does not include a <script ...> ... </script> container.

This JS should be output just before the </body> tag.

Returns the HTML generated by the call to run().

The HTML will probably be output just after the <body> tag.

Set the option to make menu items text (0) or buttons (1).

The default is 0.

Note: See split_buttons() for what happens when you try to set both menu_buttons(1) and split_buttons(1).

See the "FAQ" for details.


Generate the HTML and JS.


Set the option to make menu buttons normal (0) or split (1).

The default is 0.

See the "FAQ" for details.

In the constructor, if you specify both menu_buttons => 1 and split_buttons => 1, menu_buttons is forced to be 0, so you get split buttons.

However, if you call these methods after creating the object, and wish to set split_buttons to 1, you must also explicitly set menu_buttons to 0, otherwise the output will be not as expected.


Skip (0) or add (1) the contents of switch.statement.tx into the generated Javascript.

The default is 0.

Using 0 means you want a request to be sent to the url (if any) of each menu item when the user clicks that item.

Using 1 means you want the url to be disabled. In this case, the urls are used to generate a set of Javascript function names, and when the user clicks on a menu item, the corresponding function is executed. That could, for instance, set up an Ajax request to the server.

You must write the code for these Javascript functions, and include them (preferably) in the <head> part of the web page.

See the "FAQ" for details.


Set the path to the Text::Xslate templates.

These templates are shipped in htdocs/assets/templates/html/yui3/menu/.

See "Testing this module" for instructions on installing them, and the "FAQ" for a discussion on the template_path option in the config file.

The default is ''.

It is mandatory to use new(template_path => $a_path) or template_path($a_path) before calling run().


Set the Tree::DAG_Node object holding the menu.

This option is mandatory.

Testing this module

        # 1: Prepare to use Postgres, or whatever.
        export DBI_DSN
        export DBI_USER
        export DBI_PASS

        # 2 Somehow create a new, empty database called 'menus'.

        # 3: Install:
        cpanm Tree::DAG_Node::Persist

        # 4: Create a suitable table 'items' in the 'menus' database,
        # giving it an extra column called 'url'.
        # also ships with Tree::DAG_Node::Persist V 1.03.
        scripts/ -e "url:varchar(255)" -t items

        # 5: Generate a menu and store it in the database,
        # using Tree::DAG_Node and Tree::DAG_Node::Persist.

        # 6: If desired, plot the menu.
        # Install graphviz:
        # Install the Perl interface.
        # $DR represents your web server's doc root.
        cpanm GraphViz
        scripts/ > $DR/menu.svg

        # 7: Install this module.
        cpanm HTML::YUI3::Menu

        # 8: Copy the config file to ~/.perl/HTML-YUI3-Menu.
        # You'll need to download the distro to do this.

        # 9: Edit ~/.perl/HTML-YUI3-Menu/ as desired.

        # 10: Install YUI3's yui-min.js to the directory under your web server's
        # doc root, as you've specified in the config file.
        # Download from
        cp yui-min.js $DR/assets/js/yui3

        # 11: Copy the templates shipped with this module to a directory under
        # your doc root, also as you've specified in the config file.
        cp -r htdocs/assets/* $DR/assets

        # 11: Generate the HTML.
        perl scripts/ > $DR/menu.html

        # 12: Experiment with options.
        # Edit scripts/ to set either menu_buttons => 1
        # or split_buttons => 1.
        perl scripts/ > $DR/menu.html


o What is YUI?

A Javascript library. YUI stands for the Yahoo User Interface. See

o How do I create the tree?

Use Tree::DAG_Node and give each node in the tree, i.e. each menu item, a name and, optionally, a url.

The name is set by $node -> name($name) and the url is set by ${$node -> attribute}{url}.

If you wish, save the menu to a database using Tree::DAG_Node::Persist.

See scripts/

o What is a split button?

With YUI3, menu items can be of 3 types:

A menu item which is text is just the text.

A menu item which is a button has a down arrow and a vertical bar on the right side (of the text), separating it from the next button.

A menu item which is a split button has a vertical bar on its right, a down arrow, and another vertical bar.

The down arrows indicate submenus.

o Are urls mandatory?

No. Any menu item will be ok without a url.

o Can menu buttons have their own urls?

Yes, but they don't have to have them.

For menu items which don't have submenus, the item is useless if it does not have a url.

But see the next question.

o What are name and url?

The node name appears as the text in the menu.

The url is used in a href, so that when the user clicks that menu item, the web client sends a request to that url.

At least, that's true for text items and split button items.

There is complexity in the behaviour of menu buttons 'v' split buttons.

With menu buttons, the url is not used, since the href must point to the submenu. That's part of the design of YUI3.

Split buttons can have their own url, and for both menu buttons and split buttons, each submenu item can have its own url.

o What is switch_js?

If you wish to stop the user's click on a menu item actually doing a submit to the url, you can set switch_js => 1, and this module makes various changes to the generated HTML, as described above.

See the next 2 questions.

o How are urls converted into Javascript function names?

Some examples: '/Build' becomes build(), and '/UpdateVersionNumber' becomes update_version_number().

o What is switch.statement.tx?

This module will fabricate a switch statement, using switch.statement.tx, and insert the Javascript into yui.js.tx, for output just before the </body> tag.

The generated switch statement will look like:

        menu.on("click", function(e)
                switch ('href') )
                case "/Build":
                // Etc, down to...
                case "/UpdateVersionNumber":

So, clicking on a menu item calls the Javascript funtion, which you write and put in the <head> of the web page.

o What goes into the config file?

A sample config file is shipped as config/

o In the config file, why is template_path so long?

My doc root is Debian's RAM disk, /dev/shm/, and within that a directory html/.

Under that directory, all my modules use /assets/templates/..., where the ... comes from the name of the module.

So, HTML::YUI3::Menu will become html/yui3/menu/. Hence the template path is: /dev/shm/html/assets/templates/html/yui3/menu/.

For other modules, beside templates/ there would be css/ or js/, depending on what ships with each module.

o Why is the default for horizontal 0 when every program has to set it to 1?

Because when that code is working, all defaults will be 0, which is much less confusing.

o Is there any sample code?

Yes, see "Testing this module".

o What is scripts/

After this module is installed, you will probably need to edit the config file.

But before editing it, use to copy it from config/ to ~/.perl/HTML-YUI3-Menu/.

Check the docs for File::HomeDir to see what your operating system returns for a call to my_dist_config().

The point of this is that after the module is installed, the config file will be easily accessible and editable without needing permission to write to the directory structure in which modules are stored.

That's why File::HomeDir and Path::Class are pre-requisites for this module.

All modules which ship with their own config file are advised to use the same mechanism for storing such files.

Machine-Readable Change Log

The file CHANGES was converted into Changelog.ini by Module::Metadata::Changes.


Email the author, or log a bug on RT:


HTML::YUI3::Menu was written by Ron Savage <> in 2011.

Home page:


Australian copyright (c) 2011, Ron Savage.

        All Programs of mine are 'OSI Certified Open Source Software';
        you can redistribute them and/or modify them under the terms of
        The Artistic License, a copy of which is available at: