Contents |
This article explains how to build from scratch a layout for Web Runtime widgets with these UI features:
Also, the built layout will support the following functionalities:
The following pictures shows how the layout appears in portrait and landscape mode:
Portrait mode

Landscape mode

The layout is structured into these main DOM elements:
The basic layout structure is the following:
<html>
<body>
<div id="header">
</div>
<div id="right_toolbar">
</div>
<div id="screen_container">
</div>
<div id="bottom_toolbar">
<div id="toolbar_buttons">
</div>
</div>
</body>
</html>
The DIV element with toolbar_buttons id is a placeholder element for the toolbars' buttons.
In order to properly layout the various interface elements, very few basic CSS rules are needed:
#right_toolbar
{
float:right;
}
#screen_container
{
overflow-y:auto;
}
Things to note in the above CSS code:
An alternative approach to have the buttons' toolbar differently placed depending on the display orientation, based on absolute positioning, is visible in the STEW widget, and is explained in details here: STEW: supporting screen rotation
All the widget layout is managed through a layout JavaScript object, that will be defined and implemented in this section. This object takes care of layout appearance, events management, and view switching.
First, some properties are set in order to control the layout behavior and appearance.
var layout =
{
/* true if the layout must use softkeys
* false if the layout must use toolbar buttons
*/
useSoftkeys: false,
/* CSS class applied to the buttons' toolbar */
toolbarButtonCssClass: 'toolbar_button',
/* value of the last detected display width */
lastDetectedWidth: 0,
/* value of the last detected display height */
lastDetectedHeight: 0,
/* holds a reference to the currently displayed view */
currentScreen: null
}
Depending on the useSoftkeys property value, the layout will generate and handle softkey menu items or toolbar buttons, that will be inserted in the toolbar_buttons placeholder DIV element. In order to do this, the following addMainOption() method is defined:
var layout =
{
[...]
addMainOption: function(text, id, handler)
{
if(this.useSoftkeys)
{
var item = new MenuItem(text, id);
item.onSelect = handler;
menu.append(item);
}
else
{
var button = document.createElement('div');
button.className = this.toolbarButtonCssClass;
button.appendChild(document.createTextNode(text));
button.onclick = handler;
document.getElementById('toolbar_buttons').appendChild(button);
}
},
}
The three arguments passed to the addMainOption() method are:
First, a helper methods is defined in order to detect display orientation:
var layout =
{
[...]
isLandscape: function()
{
return window.innerWidth > window.innerHeight;
}
The layout object has to manage the widget's appearance, and specifically has to perform these operations:
All these operations are managed by the following setupInterface() method:
var layout =
{
[...]
setupInterface: function()
{
if(!this.useSoftkeys)
menu.hideSoftkeys();
this.lastDetectedWidth = window.innerWidth;
this.lastDetectedHeight = window.innerHeight;
if(this.useSoftkeys)
{
document.getElementById('screen_container').style.height =
(this.lastDetectedHeight - document.getElementById('header').offsetHeight) + 'px';
}
else if(this.isLandscape())
{
document.getElementById('bottom_toolbar').style.display = 'none';
document.getElementById('right_toolbar').style.display = '';
document.getElementById('right_toolbar').appendChild(document.getElementById('toolbar_buttons'));
document.getElementById('right_toolbar').style.height =
(this.lastDetectedHeight - document.getElementById('header').offsetHeight) + 'px';
document.getElementById('screen_container').style.height =
(this.lastDetectedHeight - document.getElementById('header').offsetHeight) + 'px';
}
else
{
document.getElementById('bottom_toolbar').style.display = '';
document.getElementById('right_toolbar').style.display = 'none';
document.getElementById('bottom_toolbar').appendChild(document.getElementById('toolbar_buttons'));
document.getElementById('screen_container').style.height =
(this.lastDetectedHeight - document.getElementById('header').offsetHeight - document.getElementById('toolbar_buttons').offsetHeight) + 'px';
}
}
}
When the display changes orientation, the interface needs to be relayed out, in order to resize and move elements appropriately. Since all these things are performed by the setupInterface() method, the following onResize() method will uniquely call this method:
var layout =
{
[...]
onResize: function()
{
this.setupInterface();
},
}
In order to easily change the main view of the widget, the gotoScreen() is defined, that will hide the currently visible view, and show the new one.
var layout =
{
[...]
gotoScreen: function(screenId, clearHistory)
{
var newScreen = document.getElementById(screenId);
if(newScreen)
{
if(this.currentScreen != null)
{
this.currentScreen.style.display = 'none';
}
this.currentScreen = newScreen;
this.currentScreen.style.display = '';
}
}
}
Now, all is ready to be initialized and used. So, it is possible to define an init() method that will take care of:
var layout =
{
[...]
init: function(startScreen)
{
this.setupInterface();
var self = this;
window.addEventListener(
'resize',
function()
{
self.onResize();
},
false
);
this.gotoScreen(startScreen);
}
}
Some devices, as explained here, do not support the 'onResize' event. So, the approach defined in the linked Forum Nokia Library page is implemented, in order to correctly manage display resize events also on these devices. The following pollResize() method is defined:
var layout =
{
[...]
pollResize: function()
{
if(window.innerWidth != this.lastDetectedWidth || window.innerHeight != this.lastDetectedHeight)
{
this.onResize();
}
}
}
And is scheduled to be periodically called by the init() method, that is modified as follows:
var layout =
{
[...]
init: function(startScreen)
{
[...]
setInterval(
function()
{
self.pollResize();
}
,
1000
);
}
}
Usage of the layout object is quite straightforward, and requires these steps:
) in your widget's HTML code:
<html>
<head>
<script language="javascript" type="text/javascript" src="layout.js"></script>
<link rel="stylesheet" href="layout.css" type="text/css">
</head>
[...]
</html>
<html>
[...]
<body onLoad="javascript:init();">
<div id="header">
Widget Layout sample
</div>
<div id="right_toolbar">
</div>
<div id="screen_container">
<div class="screen" id="screen_home" style="display: none;">
<strong>Widget Layout with Header and Buttons' Toolbar</strong>
</div>
<div class="screen" id="screen_info" style="display: none;">
<h2>Widget Info</h2>
Some infos about the application
</div>
<div class="screen" id="screen_more" style="display: none;">
Some more info...
</div>
</div>
<div id="bottom_toolbar">
<div id="toolbar_buttons">
</div>
</div>
</body>
</html>
function init()
{
layout.useSoftkeys = false;
layout.addMainOption('Home', 1001, function(){layout.gotoScreen("screen_home");})
layout.addMainOption('Info', 1002, function(){layout.gotoScreen("screen_info");})
layout.addMainOption('More', 1003, function(){layout.gotoScreen("screen_more");})
layout.init('screen_home');
}
So this example layout does not use softkeys: 3 buttons are so created, and each of them brings to a view defined in the above HTML code. Screenshots of the sample widget are visible at the beginning of this article.
The following related files are available for download:
No related wiki articles found