jueves, 13 de diciembre de 2012

HTML Flow with Javascript


I've been working today on this page flow and I like it.

The idea is to make things easier for users. They usually are confused when an application takes them from one screen to another.

This example will show how all the screens are piled up (using a simple animation, which must be optimized) as the user goes deeper and deeper through the application.

I did not used jQuery because I wanted to make it as small as possible. And now that I'm writting this, I realize that it'd be better if I give Google's Dart a chance...

Keep reading and be ready for Dart, very soon!

(Just copy and pase the following code into a HTML file and make doble-click to see it working on a browser)

<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>My Two parts screen</title>
<style>
body {
font-family:Arial;
font-size:16px;
background:#ddd;
}
/* Decoration */
.box {
position:absolute;
left:5%;
top:5%;
padding:5px;
background:#fff;
border:1px solid #ccc;
}
.box #inner {
padding:1em;
}
</style>
<script>
/* Do after body is fully loaded */
function onBodyComplete()
{
setBoxDiv();
}
/* Get current window's width */
function getWidth() 
{
var myWidth = 0, myHeight = 0;
if( typeof( window.innerWidth ) == 'number' ) {
//Non-IE
myWidth = window.innerWidth;
myHeight = window.innerHeight;
} else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
//IE 6+ in 'standards compliant mode'
myWidth = document.documentElement.clientWidth;
myHeight = document.documentElement.clientHeight;
} else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
//IE 4 compatible
myWidth = document.body.clientWidth;
myHeight = document.body.clientHeight;
}
return myWidth;
}
/* Window resizes */
window.onresize = function() {
onBodyComplete();
};
/* Utility functions for the framework*/
function $(divId) {
return document.getElementById(divId);
}
function log(text) {
console.log(text);
}
function doMessage(text)
{
$('message').innerHTML = text;
}
/* Use this function for animating down any DIV element */
function animateDown(divId, pixels, callback)
{
log('animateDown');
var ele = $(divId);
if ( ele == null )
{
console.log('animateDown: element is null!');
return false;
}
var currentMarginTop = ele.style.marginTop;
currentMarginTop = currentMarginTop.replace('px','');
if ( parseInt( currentMarginTop ) >= parseInt( pixels ) ) 
{
log('animateDown: ' + currentMarginTop + ' >= ' + pixels );
ele.style.marginTop = pixels + 'px';
if ( callback != null ) callback();
return true;
}
else
{
moveDown(divId, pixels, callback, currentMarginTop);
}
}
/* This function works along with the animateDown function */
function moveDown(divId, pixels, callback, currentMarginTop)
{
var ele = $(divId);
if ( ele == null )
{
console.log('MoveDown: element is null!');
return false;
}
if ( currentMarginTop == '' ) 
currentMarginTop = 0;
currentMarginTop += 2;
ele.style.marginTop = currentMarginTop + 'px';
setTimeout("animateDown('"+divId+"', '"+pixels+"', "+callback+");", 100);
}
/* Use this function for animating up any DIV element */
function animateUp(divId, pixels, callback)
{
log('animateUp');
var ele = $(divId);
if ( ele == null )
{
console.log('animateUp: element is null!');
return false;
}
var currentMarginTop = ele.style.marginTop;
currentMarginTop = currentMarginTop.replace('px','');
if( typeof( currentMarginTop ) == 'number' )
{
// Nothing
}
else
{
if ( currentMarginTop == '' ) currentMarginTop = 0;
currentMarginTop = parseInt( currentMarginTop );
}

if( typeof( pixels ) == 'number' )
{
// Nothing
}
else
{
pixels = parseInt( pixels );
}
if ( currentMarginTop > 1000 ) currentMarginTop = 500;
if (  currentMarginTop <= pixels ) 
{
ele.style.marginTop = pixels + 'px';
if ( callback != null ) callback();
return true;
}
else
{
moveUp(divId, pixels, callback, currentMarginTop);
}
}
/* This function works along with the animateUp function */
function moveUp(divId, pixels, callback, currentMarginTop)
{
var ele = $(divId);
if ( ele == null )
{
console.log('moveUp: element is null!');
return false;
}
currentMarginTop -= 60;
ele.style.marginTop = currentMarginTop + 'px';
setTimeout("animateUp('"+divId+"', '"+pixels+"', "+callback+");", 0);
}
/* Use this function for showing or hiding a DIV element */
function makeVisible(divId, show)
{
if ( show ) 
$(divId).style.display = 'inline';
else
$(divId).style.display = 'none';
}
/* Use this function for setting height for any DIV element */
function setBoxHeight(boxId, newHeight)
{
$(boxId).style.height = newHeight + 'px';
}
/* 
*
* Utility functions for the application
*
*/
/* Will set width and height for all the components on the screen */
function setBoxDiv() 
{
var percent = '85%';
$('back-box').style.width = percent;
$('back-box').style.height = hForMsg + 'px';
$('login').style.width = percent;
$('login').style.height = hForLogin + 'px';
$('menu').style.width = percent;
$('menu').style.height = hForMenu + 'px';
$('menu-1').style.width = percent;
$('menu-1').style.height = hForMenu1 + 'px';
$('menu-2').style.width = percent;
$('menu-2').style.height = hForMenu1 + 'px';
}
var fDivIdMessageFromMenuDetail;
var fMessageFromMenuDetail;
/* Use this function for showing a message if you are inside a menu option detail */
function sendMessageFromMenuDetail(divId, text)
{
fDivIdMessageFromMenuDetail = divId;
fMessageFromMenuDetail = text;
animateDown(divId, hForMsg, function () 
doMessage(fMessageFromMenuDetail); 
setTimeout("animateUp('" + fDivIdMessageFromMenuDetail + "', 0, null)", 1500);
)
}
/* Use this function for showing an error from the login screen */
function sendErrorLogin(text)
{
fMessageFromMenuDetail = text;
animateDown('login', hForMsg, function () 
doMessage(fMessageFromMenuDetail); 
setTimeout("animateUp('login', 0, null)", 1500);
)
}
/* Use this function when the login is correct */
function sendCorrectLogin()
{
doMessage(''); 
makeVisible('menu', true);
animateDown('login', hForMenu, function () 
writeInfoInYoutLoginBox();
)
}
/* Use this function for showing the logged-in user info on screen */
function writeInfoInYoutLoginBox()
{
$('login').innerHTML = "<div id='inner'>You are logged as: <b>Walter Rodriguez</b>" + 
"<p><input type='button' value='Close Session' onClick='logoff()' /></p></div>";
}
/* Use this function for writting the FORM for making a login */
function writeLoginForm()
{
var text = '<div id="inner"><strong>ABM</strong>' +
'<form>' +
'<p>' +
'<label for="username">Username: </label>' +
'<input type="text" id="username" value="admin" />' + 
'</p>' +
'<p>' + 
'<label for="pass">Password: </label>' + 
'<input type="password" id="pass" value="pass" />' + 
'</p>' + 
'<p>' + 
'<input type="button" value="Simulate login incorrect" onClick="sendErrorLogin(\'Login incorrect. Please try again.\')" />' + 
'<input type="button" value="Simulate login correct" onClick="sendCorrectLogin()" />' + 
'</p>' + 
'</form></div>';
$('login').innerHTML = text;
}
/* This function will accomodate the screen for a logoff scenario */
function logoff()
{
doMessage(''); 
closeAllEnabledMenuDetail();
animateUp('login', 0, function () 
makeVisible('menu', false);
writeLoginForm();
)
}
var fMenuId;
/* Use this function when clicking a menu option */
function showDetailForOptionMenu(menuId)
{
fMenuId = menuId;
doMessage('');
hideAllEnabledMenuDetail();
animateDown('login', (hForMenu + hForMenu1), function () 
animateDown('menu', hForMenu1, function () 
{
makeVisible(fMenuId, true);
)
)
}
/* Use this function for closing the menu window */
function closeMenuDetail(menuId)
{
fMenuId = menuId;
doMessage('');
animateUp(menuId, 0, function ()
{
makeVisible(fMenuId, false);
animateUp('login', hForMenu, function () 
animateUp('menu', 0, function () 
// Nothing
)
)
}
);
}
/* Use this function for closing all the detailed menu option screens available */
function closeAllEnabledMenuDetail()
{
closeMenuDetail('menu-1');
closeMenuDetail('menu-2');
}
/* Use this function for hiding all the detailed menu option screens available */
function hideAllEnabledMenuDetail()
{
makeVisible('menu-1', false);
makeVisible('menu-2', false);
}
var hTiny = 100;
var hSmall = 200;
var hMedium = 300;
var hLarge = 450;
var hForMsg = hTiny;
var hForLogin = hSmall;
var hForMenu = hMedium;
var hForMenu1 = hLarge;
</script>
</head>
<body onLoad="onBodyComplete()">
<div id="wrapper">
<!-- box with error message for all boxes -->
<div id="back-box" class="box">
<div id="inner">
<div id="message"></div>
</div>
</div>

<!-- menu details -->
<div id="menu-1" class="box" style="display:none;">
<div id="inner">
<b>MENU OPTION DETAIL</b>
<p>Bla..</p>
<p>Bla..</p>
<p>Bla..</p>
<p>Bla..</p>
<p>Showing action for option menu 1</p>
<p><input type="button" value="Show message from option detail" 
onClick="sendMessageFromMenuDetail('menu-1','You just fired a message...')" /></p>
<p><input type="button" value="Back to Menu" onClick="closeMenuDetail('menu-1')" /></p>
</div>
</div>

<div id="menu-2" class="box" style="display:none;">
<div id="inner">
<b>MENU OPTION DETAIL</b>
<p>Showing action for option menu 2</p>
<p><input type="button" value="Back to Menu" onClick="closeMenuDetail('menu-2')" /></p>
</div>
</div>
<!-- menu list after login -->
<div id="menu" class="box" style="display:none;">
<div id="inner">
<b>MAIN MENU</b>
<ul>
<li><a href="javascript:showDetailForOptionMenu('menu-1')">Option 1</a></li>
<li><a href="javascript:showDetailForOptionMenu('menu-2')">Option 2</a></li>
<li>Option 3</li>
<li>Option 4</li>
<li>Option 5</li>
<li>Option 6</li>
<li>Option 7</li>
<li>Option 8</li>
<li>Option 9</li>
</ul>
<p><input type='button' value='Close Session' onClick='logoff()' /></p>
</div>
</div>
<!-- login box -->
<div id="login" class="box">
<!-- the Login form will be painted here via javascript -->
</div>
</div>
<script>writeLoginForm()</script>
</body>
</html>