I’ve been working with a great deal of DekiScript recently and I haven’t really had much time to “show off” any of my developments. Well, just this week I completed a new DekiScript dropdown menu and it’s quite nice so I figured I’d share.
The dropdown menu was developed using a combination of DekiScript and JQuery. It is very easy to implement and doesn’t require using any extensions. Simply just create a new template and paste in the provided code. The template then can by included on desired pages to provide an additional layer of navigation to your community.
The menu that is generated from the template displays two tiers of navigation and originates from the Deki root by default. Alternatively you can specify a path either statically or dynamically using DekiScript to identify where the navigation should originate from.
The code can be cleanly separated into two portions, DekiScript which handles the markup and Jquery which takes care of the CSS. Lets first take a look at the DekiScript as a whole and then I’ll step through individual portions of the DekiScript code.
{{
var langpath ="/";
if ($path) {
let langpath=$path;
}
var langdir = wiki.getpage(langpath);
var topnav = langdir.subpages;
var subnav;
var navhtml;
var tophtml;
var subhtml;
var dropicon;
var topselect;
foreach(var top in topnav) {
let subhtml='';
let subnav = top.subpages;
let dropicon='';
let topselect='';
foreach(var sub in subnav) {
let subhtml..=('<li class="'..sub.name..'">'..web.link(sub.uri,sub.title)..'</li>')
}
if (#subnav > 0) {
let dropicon='<span class="dropicon">v</span>';
}
if (string.contains(page.uri,top.uri)) {
let topselect=' selected ';
}
let navhtml..=('<li class="'..top.name..topselect..'"><span>'..web.link(top.uri,top.title)
..dropicon..'</span><ul>'..subhtml..'</ul></li>');
}
web.html('<ul id="DWdynnav">'..navhtml..'</ul>');
}}
Now lets break it down into smaller DekiScript chunks to take a look at what each piece is doing. The first part of the DekiScript is responsible for defining the path that the navigation should originate from. I used var langpath ="/"; to set the path default to your wiki homepage. $path is a template variable and is optional. If you are going to provide a path (discussed at the bottom of this blog post) you will do so when you call the template from the page that will display the menu. Lastly I need to work with the page object so I can access the properties and subpages to map out my menu. This is done by using var langdir = wiki.getpage(langpath);. Wiki.getpage returns a page object so if I later needed to I can access properties of the navigations origin page using something such as langdir.title or langdir.author.
var langpath ="/";
if ($path) {
let langpath=$path;
}
var langdir = wiki.getpage(langpath);
The next section is fairly simple. First I am finding out what pages are going to make up my top nav or the 1st tier of the dropdown menu. This is done by accessing the properties of langdir as mentioned in the previous section. You can see that I use var topnav = langdir.subpages; which will set topnav to a map of page objects which I will loop through soon to build my structure. After that I have to define a series of variables that are used to generate the navigations, HTML, CSS and the dropdown icon.
var topnav = langdir.subpages;
var subnav;
var navhtml;
var tophtml;
var subhtml;
var dropicon;
var topselect;
So here’s where it gets a little trickier. To start off I need to loop through each item from the topnav so I setup my foreach loop using foreach(var top in topnav). As I start looping there are some variables that need to be set, they may have different outputs based on the dropdown content.
The first and most important variable I have to set is the dropdown pages. I do this by using let subnav = top.subpages; which will again return a map of page objects which I can later loop through to output the subpages. The other variable are just being reset.
Now that I know the dropdown pages (subnav) I can begin to generate the HTML that will be used to construct the navigation. As I loop through the subnav pages using foreach(var sub in subnav) I am appending new HTML to the subhtml variable which looks like this let subhtml..=('<li class="'..sub.name..'">'..web.link(sub.uri,sub.title)..'</li>')
After I have generated my subnav I need to differentiate my topnav menu items with a subnav from the topnav menu items with no subnav. Basically, if a topnav menu item does have subpage I want to display a little down arrow to let users know. This is done by using if (#subnav > 0). The # will return a count of the objects in the subnav variable, if any. If the topnav does have a submenu I add in a down arrow using let dropicon='<span class="dropicon">v</span>';.
The next part is not really necessary but I added it in regardless. Using if (string.contains(page.uri,top.uri)) I am comparing the topnav page URI’s to the location of the page the the user is on. If their is a match I output let topselect=' selected '; which is later used in the topnav class. This allows users to know where they are relative to all of the pages in the dropdown menu.
The last part simply pulls all of the previous pieces together to construct the final HTML that will be used for the menu. You can see that I am using some DekiScript page properties such as top.name and top.title and I’m also using some DekiScript functions such as web.link. Lastly I’m placing my variables as need throughout the HTML: topselect, dropicon, subhtml.
let navhtml..=('<li class="'..top.name..topselect..'"><span>'..web.link(top.uri,top.title)
..dropicon..'</span><ul>'..subhtml..'</ul></li>');
foreach(var top in topnav) {
let subnav = top.subpages;
let subhtml='';
let dropicon='';
let topselect='';
foreach(var sub in subnav) {
let subhtml..=('<li class="'..sub.name..'">'..web.link(sub.uri,sub.title)..'</li>')
}
if (#subnav > 0) {
let dropicon='<span class="dropicon">v</span>';
}
if (string.contains(page.uri,top.uri)) {
let topselect=' selected ';
}
let navhtml..=('<li class="'..top.name..topselect..'"><span>'..web.link(top.uri,top.title)
..dropicon..'</span><ul>'..subhtml..'</ul></li>');
}
If you were to leave this output without the additional Jquery code you would have a bulleted list of a page and it’s subpages. Now for the sanity of the readers I’m not going to step through Jquery. All you should know is that it is completely customizable and I created color and style variables at the top to easily modify the look and feel of the menu. You can view a full output of the DekiScript SOURCE with the Jquery at http://wiki.developer.mindtouch.com/User:Howleyda/DekiScript_dropdown_menu/Source. To utilize this code simply copy and page the content into a new template on your Deki.
The very last part which is most important is including the template in a wiki page.
If you want to show the root menu use {{template.DropDown()}}
If you want to specify a path use something like {{template.DropDown{path:page.path} }} or {{template.DropDown{path:"/DekiScript"} }}
Thanks for reading,
Damien Howley
@DamienH