Prior posts in this series:
One of the reasons that widgets are an interesting alternative to mobile web sites is their ability to integrate into the Windows Mobile shell similar to native or managed applications. Menus are one of these integration points. When designing your widget you should consider using the menus in additional to placing links within the content on your html page. Menus are a great way of controlling navigation within your application as they are always at the bottom of the screen, regardless of where the user has scrolled to (like mobile websites, widgets tend to be elongated, allowing vertical scrolling but eliminating horizontal scrolling where possible).
For example, the menu may contain items such as Home, Exit, About – items that are will be there regardless of where the user is in the widget. This is not to say you can’t dynamically control what’s displayed in the menu, in fact far from it as you can easily add and remove, enable and disable menu items.
In the previous post you saw how we can display manifest information to the user. Whilst this was useful in demonstrating how to read information from the manifest, it’s not likely that we always want that information to be displayed. Lets add a menu item that will toggle the visibility of this information.
To start with, we need to encapsulate the manifest information in the main.htm file into a single div that we can hide and show. This way we only need to toggle a single div, rather than each of the manifest information divs.
—————–
Main.htm
—————–<div id="about" style="display:none;">
<div id="manifestVersion" class="manifest"></div>
…
</div>
The next thing we need to do is add some helper methods to make working with widget menus that much easier. Note that this code will create menu items when running as a widget but it will also create div elements for menus when running in a standard browser, this aids debugging as you can test the navigation/event handling of your menus from within Visual Studio.
—————–
widget.js
—————–// Creates a menu with specified label and click handler
createMenuItem: function (label, handler) {
var mi = null;
this.LAST_MENU_ID ++;
if (window.widget && window.widget.menu) {
var mi = window.widget.menu.createMenuItem(this.LAST_MENU_ID);
if (mi) {
mi.text = label;
if (handler) {
mi.onSelect = handler;
}
}
}
else if (isGadget != true) {
mi = document.createElement("div");
mi.innerHTML = label;
mi.text = label;
if (handler) {
mi.onclick = handler;
}
mi.id = "menu" + id;
}
return mi;
},
// Returns a menu item whose ID is specified
getMenuItemById: function (id) {
var mi = null;
if (window.widget && window.widget.menu) {
mi = window.widget.menu.getMenuItemById(id);
}
else {
mi = $get("menu" + id);
}return mi;
},
getMenuText: function (mi) {
if (window.widget && window.widget.menu) {
return mi.text;
}
else {
return mi.innerHTML;
}
},
// Appends the menu item to the main menu at the end. If the id of the menuitem to be added already exists in the menu, an exception will be thrown.
appendMenuItem: function (mi) {
if (mi && window.widget && window.widget.menu) {
window.widget.menu.append(mi);
}
else {
var right = $get("rightSoftKey");
right.appendChild(mi);
right.parentNode.style.display = "block";
}
},
// Appends the menu item to the parent menu at the end. If the id of the menuitem to be added already exists in the menu, an exception will be thrown.
appendSubMenuItem: function (parent, mi) {
if (parent && mi && window.widget && window.widget.menu) {
parent.append(mi);
}
else {
if (parent.childNodes.length == 1) {
var list = document.createElement("div");
list.style.margin = "10px";
parent.appendChild(list);
}
parent.childNodes[1].appendChild(mi);
}
},
// Removes the menu item from the main menu. If the specified id does not correspond to an item in the menu, an exception will be thrown.
removeMenuItem: function (mi) {
if (mi && window.widget && window.widget.menu) {
window.widget.menu.remove(mi);
}
else {
var right = $get("rightSoftKey");
right.removeChild(mi);
}
},
// Removes the menu item from the sub main menu. If the specified id does not correspond to an item in the menu, an exception will be thrown.
removeSubMenuItem: function (parent, mi) {
if (parent && mi && window.widget && window.widget.menu) {
parent.remove(mi);
}
else {
parent.childNodes[1].removeChild(mi);
if (parent.childNodes.length == 1) {
parent.removeChild(parent.childNodes[1]);
}
}
},// Sets the softkey of the widget. Currently we supprt setting the left softkey and right soft key.
// If there is an error setting the soft key, exception will be thrown. If the softkey index is invalid, exception will be thrown.
setSoftKey: function (mi, softkeyIndex) {
if (mi && window.widget && window.widget.menu) {
window.widget.menu.setSoftKey(mi, softkeyIndex);
}
},
// Sets the left softkey for the widget menu item
setLeftSoftKey: function (mi) {
if (mi && window.widget && window.widget.menu) {
window.widget.menu.setSoftKey(mi, widget.menu.leftSoftKeyIndex);
}
else {
var left = $get("leftSoftKey");
left.appendChild(mi);
left.parentNode.style.display = "block";
}
},
// Sets the right softkey for the widget menu item
setRightSoftKey: function (mi) {
if (mi && window.widget && window.widget.menu) {
window.widget.menu.setSoftKey(mi, widget.menu.rightSoftKeyIndex);
}
else {
var right = $get("rightSoftKey");
right.removeChild(mi);
right.parentNode.style.display = "block";
}
},
// enable/disable a menu item
toggleMenuItem: function (id, on) {
var mi = this.getMenuItemById(id);
if (mi) {
mi.enabled = on;
}
}And of course we need to add code to main.js in order to actually create the menus:
—————–
main.js
—————–function onLoad() {
// Omitted code as it is the same as previous posts
createMenuItems();
}// Create the menu items
function createMenuItems() {// create Refresh as left soft key for the main page
createLeftSoftKey();// create right soft key and its sub menu items
createRightMenuItems();
}// create Blog link as left soft key
function createLeftSoftKey() {
// Add the Back menu item and set it to disabled
var mi = WidgetAPI.createMenuItem("Blog", onNavigateToBlog);
if (mi && mi!=null) {
mi.enabled = true;
WidgetAPI.setLeftSoftKey(mi);
}
}function onNavigateToBlog() {
window.open("https://blogimages.builttoroam.com/nick");
}// Add sub menu items to right soft key "Menu"
function createRightMenuItems() {
// Add the Home menu item and set it to disabled
aboutMenu = WidgetAPI.createMenuItem("About", onAbout);
if (aboutMenu && aboutMenu != null) {
aboutMenu.enabled = true;
WidgetAPI.appendMenuItem(aboutMenu);
}}
Lastly, returning to the main.htm file we need to add two hidden divs which will be used during testing to display the menu items when the widget is run on the desktop. These divs will remain hidden when the widget is run on the device.
—————–
Main.htm
—————–<!– Testing on desktop only –>
<div style="display:none;">
LEFT:
<div id="leftSoftKey">
</div>
</div>
<div style="display:none;">
RIGHT:
<div id="rightSoftKey">
<div onclick="window.close()" >Exit</div>
</div>
</div>
</body>
</html>
Here’s the widget in action – you can see that the left menu (which used to read Exit) now reads Blog and that the right menu includes both the standard Exit item and an About item. Clicking the About item displays the hidden manifest information.
If you run this from within Visual Studio, what you will see is that the left and right menus are simulated by divs that are created at the end of the page. In the same way as the widget running on the device, clicking the About will display/hide the manifest information area.