0
\$\begingroup\$

This was a little app I wrote looking for a way to create consistency in the way employees taking phone orders enter the address.

The purpose of the app is to require a user to enter a valid address.

The scope broadened to include two secondary objectives, performance and proper rendering.

  • Performance: No IF ELSE or Branch Instructions in the JavaScript.
  • Render the same on all Browsers desktop and mobile.

According to Intel's 64 and IA-32 Architectures Optimization Reference Manual, Branching Instructions should be "avoided whenever possible".

This is not an easy task. It requires a fair amount of data arrays.

The question is does the performance enhancement override the extra memory and overhead associated with the data arrays?

Many say that media queries are needed to achieve a responsive design. I cannot see where I could use media queries in this app.

The question is Why and Where would I use them?

Kind of an out of the box UI. Is it too unconventional for users to understand how to use it?

I have not checked lately but it did render identically on a number of Browsers I tested it on. I do not have a way to test it on a wide variety of Browsers.

Does it render properly on your Browser?

The most difficult thing was to keep any jitter out of the keyboard area. Clicking the Next Button changes the Keypad. I do not want any jitter in the sizing of the 6 keypads

There are 6 keyboards/keypads:

  1. Address Components House Number + N E S W
  2. Street Direction E,N,NE,NW,W,S,SE,SW, None
  3. Street Name alpha
  4. Street Name numeric (click #)
  5. Street Type (Ave, St, Blvd, Dr, Cir, Ct,Ln, etc...)*
  6. Zip Code

    • Street Type also has a <select><option> drop down with all 195 types of Streets in the US.

These 6 keypads are divs where 5 have display:none and one has display:block.

When clicking the Next Button I do not want to see any jitter from one keypad to the next. Does it jitter on your Browser?

Screen is responsive and holds up down to about 280px wide Browser window width.

Is it necessary to use media queries to have an app render on both desktop and mobile Browsers?

The UI could be better but that was not at issue here. It is basically un-styled. So far the CSS is mostly for responsive and consistent sizing of HTML elements.

When the Validate button is clicked it brings up a Google map and Street View photo of the address. What's a better way to validate your address than to see a photo of your street?

It also gets the properly formatted address from Google geo coding. Will also get the county, lat, lng, and attempt to get the neighborhood name.

The Validate may not work on the Snippet here although the link to the PHP page with the map and street view pic is in the HTML.

tKey=new Array(0,1,2,2,4,5);
var text=new Array();
text[0]=document.getElementById('hn');
text[1]=document.getElementById('sd');
text[2]=document.getElementById('sn');
text[3]=document.getElementById('sn');
text[4]=document.getElementById('st');
text[5]=document.getElementById('zc');
var showKey=new Array();
showKey[0]=document.getElementById('showHN');
showKey[1]=document.getElementById('showSD');
showKey[2]=document.getElementById('showSN');
showKey[4]=document.getElementById('showST');
showKey[3]=document.getElementById('showSN');
showKey[5]=document.getElementById('showZC');
var keys=new Array();
keys[0]=document.getElementById('hnKeys');
keys[1]=document.getElementById('sdKeys');
keys[2]=document.getElementById('snKeys');
keys[3]=document.getElementById('snnKeys');
keys[4]=document.getElementById('typeKeys');
keys[5]=document.getElementById('zcKeys');
var addr=document.getElementById('addr');
var spBar=document.getElementById('space');
var state=document.getElementById('state');
var key=new Array();
var sfx=new Array();
sfx[0]=document.getElementById('sfx0');
sfx[1]=document.getElementById('sfx1');
sfx[2]=document.getElementById('sfx2');
sfx[3]=document.getElementById('sfx3');
var type=new Array();
type['']=null;
type['1']=0;
type['2']=1;
type['3']=2;
type['4']=3;
type['5']=3;
type['6']=3;
type['7']=3;
type['8']=3;
type['9']=3;
type['0']=3;
key[0]=0;
key[1]=0;
key[2]=0;
key[3]=0;
key[4]=0;
key[5]=0;
var display=new Array('none','block');
var toggle=new Array(1,0);
var bg=new Array(null,'#0f0');
var num=0;
text[0].value='';
text[1].value='';
text[2].value='';
text[4].value='';
text[5].value='';
addr.value='';
var pad=Array('','0000','000','00','0','');
function hNum(n){text[0].value=text[0].value + n;showAddr();}
function sDirection(d){text[1].value=d;sdKeys.style.display=display[0];show(2);}
function sName(a){text[2].value=text[2].value + a;text[2].value=text[2].value.substr(0,1).toUpperCase() + text[2].value.substr(1);caps();showAddr();}
function snnName(a,k){text[2].value=text[2].value + a;show(k);}
function sType(t){text[4].value=t;typeKeys.style=display[0];show(5);}
function zipCode(n){zCode=parseInt('0'+text[5].value,10);zCode*=10;zCode+=n;text[5].value=zCode.toString();zcPad();showAddr();}
function hnBack(){text[0].value=text[0].value.substr(0,text[0].value.length-1);text[0].value=text[0].value;}
function snBack(){text[2].value=text[2].value.substr(0,text[2].value.length-1);text[2].value=text[2].value;}
function zcBack(){zCode=parseInt('0'+text[5].value,10);zCode=parseInt(zCode/=10,10);text[5].value=zCode.toString();pad() ;addr.value=text[0].value + ' ' + text[1].value + ' ' + text[2].value + ' ' + text[4].value + ', ' + text[5].value;}
function show(n){var s=key[n];var k=n;key[0]=0;key[1]=0;key[2]=0;key[3]=0;key[4]=0;key[5]=0;keys[0].style.display=display[0];keys[1].style.display=display[0];keys[2].style.display=display[0];keys[3].style.display=display[0];keys[4].style.display=display[0];keys[5].style.display=display[0];key[k]=toggle[s];keys[k].style.display=display[key[k]];sel(k);showAddr();text[k].focus();}
function caps(){for (var i=0;i< text[2].value.length;++i){if (text[2].value[i]==' ' && text[2].value.charCodeAt(i+1)>96){text[2].value=text[2].value.substr(0,i+1) + text[2].value.substr(i+1,1).toUpperCase();text[2].value=text[2].value;break;}}}
function zcPad(){var len=text[5].value.length;text[5].value=pad[len] + text[5].value;}
function sel(k){showKey[0].style.background=bg[key[0]];showKey[1].style.background=bg[0];showKey[2].style.background=bg[0];showKey[4].style.background=bg[0];showKey[5].style.background=bg[0];text[0].style.background=bg[0];text[1].style.background=bg[0];text[2].style.background=bg[0];text[4].style.background=bg[0];text[5].style.background=bg[0];showKey[tKey[k]].style.background=bg[key[tKey[k]]];text[tKey[k]].style.background=bg[key[tKey[k]]];}
function clr(t){text[t].value='';}
function pick(){var digit=text[2].value.substr(-1);sfx[0].style.background=null;sfx[1].style.background=null;sfx[2].style.background=null;sfx[3].style.background=null;sfx[type[digit]].style.background='#ff0';}
function showAddr(){addr.value=text[0].value + ' ' + text[1].value + ' ' + text[2].value + ' ' + text[4].value + ', ' + text[5].value;}
function stOther(){text[4].value = document.form.selectID.options[document.form.selectID.selectedIndex].value;}
show(0);
body,form{padding:0;margin:0;font:700 1em Arial,sans-serif;}
button,.clear,.tty,.row{display:inline;margin:0;padding:0;font:700 1.5em Arial,sans-serif;}
.clear{background:#fff;}
.tty{width:8.7%;font:700 1.5em Arial,sans-serif;}
.keyLabel{padding:0;margin:0 auto 0;font:700 1.3em times,serif;text-align:center;color:#f00;}
#selectID{font-size:1.25em;}
.sm{font-size:.5em;}
.show,#hn,#sd,#st,#sn,#tt,#zc{width:48%;margin:0;padding:0;font:700 1.2em Arial,sans-serif;}
#content{width:100%;max-width:479px;margin:0 auto 0;}
#title{text-align:center;padding:0;margin:0;}
#showKeyColumn{margin:0 0 0 0;width:100%;}
#hnKeys,#sdKeys,#snKeys,#snnKeys,#typeKeys,#zcKeys{display:none;padding:0;margin:0;border:0;width:100%;}
#hnKeyPad,#snnKeyPad,#zcKeyPad{margin:0;padding:0;width:100%;}
#snKeyPad{margin:0;}
#sdKeyPad{margin:0;}
#typeKeyPad{margin:0;}
.action{font:700 1.5em Arial,sans-serif;width:49%;margin:0 0 0 0;}
#sfx0,#sfx1,#sfx2,#sfx3{font:700 1.5em Arial,sans-serif;width:3em;margin:0;}
#sdNone,#space,#sub,.row{width:100%;}
#addr{width:99%;padding:0;margin:0 0 0 0;text-align:center;font:700 1.5em Arial,sans-serif;}
fieldset{border:0;margin:0;padding:0;}
.key{font:700 1.5em Arial,sans-serif;width:100%;width:85%;}
.sfx{font:700 1.5em Arial,sans-serif;width:3em;}
form{width:100%;padding:0;margin:0;}
.col3{width:32%;font:700 1.5em Arial,sans-serif;}
.col4{width:23.5%;font:700 1.5em Arial,sans-serif;}
#select{font:700 1.2em Arial,sans-serif;margin:0;padding:0;}
<div id="content">
<form action="http://ispeedlink.com/a/addrCheck.php" method="post" id="form" enctype="application/x-www-form-urlencoded" >
<p id="title">Address Components</p>
<div id="showKeyColumn">
<button id="showHN" class="show" type="button" value="0" onclick="show(0)">House Num.</button><span class="sm">&nbsp;</span><input id="hn" type="text" name="strNum" value="" onclick="show(0)" /><br/>
<button id="showSD" class="show" type="button" value="1" onclick="show(1)">St. Direction</button><span class="sm">&nbsp;</span><input id="sd" type="text" name="strDir" value="" onclick="show(1)" /><br/>
<button id="showSN" class="show" type="button" value="2" onclick="show(2)">Street Name</button><span class="sm">&nbsp;</span><input id="sn" type="text" name="strName" value="" onclick="show(2)" /><br/>
<button id="showST" class="show" type="button" value="3" onclick="show(4)">Street Type</button><span class="sm">&nbsp;</span><input id="st" type="text" name="strType" value="" onclick="show(4)" /><br/>
<button id="showZC" class="show" type="button" value="4" onclick="show(5)">Zip Code</button><span class="sm">&nbsp;</span><input id="zc" type="text" name="zipcode" value="" onclick="show(5)" /><br/></div>
<div id="hnKeys">
<p class="keyLabel">House Number</p>
<div id="hnKeyPad">
<button class="col4" type="button" name="sn1" onclick="hNum('N')" >N</button>
<button class="col4" type="button" name="sn1" onclick="hNum('1')" >1</button>
<button class="col4" type="button" name="sn2" onclick="hNum('2')" >2</button>
<button class="col4" type="button" name="sn3" onclick="hNum('3')" >3</button><br/>
<button class="col4" type="button" name="sn1" onclick="hNum('S')" >S</button>
<button class="col4" type="button" name="sn4" onclick="hNum('4')" >4</button>
<button class="col4" type="button" name="sn5" onclick="hNum('5')" >5</button>
<button class="col4" type="button" name="sn6" onclick="hNum('6')" >6</button><br/>
<button class="col4" type="button" name="sn1" onclick="hNum('E')" >E</button>
<button class="col4" type="button" name="sn7" onclick="hNum('7')" >7</button>
<button class="col4" type="button" name="sn8" onclick="hNum('8')" >8</button>
<button class="col4" type="button" name="sn9" onclick="hNum('9')" >9</button><br/>
<button class="col4" type="button" name="sn1" onclick="hNum('W')" >W</button>
<button class="col4" type="button" name="snClr" onclick="hNum('0')" >0</button>
<button class="col4" type="button" name="sn0" onclick="hNum('0')" >0</button>
<button class="col4" type="button" name="snBS" onclick="hnBack()" >&lt;</button><br/></div>
<button id="hnClear" class="action" type="button" onclick="clr(0)" >Clear</button>
<button id="hnNext" class="action" type="button" onclick="show(1)" >Next</button></div>
<div id="sdKeys">
<p class="keyLabel">Street Direction</p>
<div id="sdKeyPad">
<button class="row" type="button" onclick="clr(1);show(2)" >None</button><br/>
<button class="col4" type="button" value="E" onclick="sDirection('E')">E</button>
<button class="col4" type="button" value="N" onclick="sDirection('N')">N</button>
<button class="col4" type="button" value="NE" onclick="sDirection('NE')">NE</button>
<button class="col4" type="button" value="NW" onclick="sDirection('NW')">NW</button><br/>
<button class="col4" type="button" value="W" onclick="sDirection('W')">W</button>
<button class="col4" type="button" value="S" onclick="sDirection('S')">S</button>
<button class="col4" type="button" value="SE" onclick="sDirection('SE')">SE</button>
<button class="col4" type="button" value="SW" onclick="sDirection('SW')">SW</button><br/>
<button class="row" type="button" onclick="clr(1);show(2)" >None</button><br/>
</div>
<button id="sdClear" class="action" type="button" onclick="clr(1)" >Clear</button>
<button id="sdNext" class="action" type="button" onclick="show(2)" >Next</button></div>
<div id="snKeys">
<p class="keyLabel">Street Name</p>
<div id="snKeyPad">
<button class="tty" type="button" value="Q" onclick="sName('q')">Q</button>
<button class="tty" type="button" value="W" onclick="sName('w')">W</button>
<button class="tty" type="button" value="E" onclick="sName('e')">E</button>
<button class="tty" type="button" value="R" onclick="sName('r')">R</button>
<button class="tty" type="button" value="T" onclick="sName('t')">T</button>
<button class="tty" type="button" value="Y" onclick="sName('y')">Y</button>
<button class="tty" type="button" value="U" onclick="sName('u')">U</button>
<button class="tty" type="button" value="I" onclick="sName('i')">I</button>
<button class="tty" type="button" value="O" onclick="sName('o')">O</button>
<button class="tty" type="button" value="P" onclick="sName('p')">P</button><br/>&nbsp;&nbsp;
<button class="tty" type="button" value="A" onclick="sName('a')">A</button>
<button class="tty" type="button" value="S" onclick="sName('s')">S</button>
<button class="tty" type="button" value="D" onclick="sName('d')">D</button>
<button class="tty" type="button" value="F" onclick="sName('f')">F</button>
<button class="tty" type="button" value="G" onclick="sName('g')">G</button>
<button class="tty" type="button" value="H" onclick="sName('h')">H</button>
<button class="tty" type="button" value="J" onclick="sName('j')">J</button>
<button class="tty" type="button" value="K" onclick="sName('k')">K</button>
<button class="tty" type="button" value="L" onclick="sName('l')">L</button><br/>&nbsp;&nbsp;&nbsp;&nbsp;
<button class="tty" type="button" value="Z" onclick="sName('z')">Z</button>
<button class="tty" type="button" value="X" onclick="sName('x')">X</button>
<button class="tty" type="button" value="C" onclick="sName('c')">C</button>
<button class="tty" type="button" value="V" onclick="sName('v')">V</button>
<button class="tty" type="button" value="B" onclick="sName('b')">B</button>
<button class="tty" type="button" value="N" onclick="sName('n')">N</button>
<button class="tty" type="button" value="M" onclick="sName('m')">M</button>&nbsp;
<button id="shift" class="tty" type="button" value="" onclick="snBack()">&lt;</button>&nbsp;
<button id="num" class="tty" type="button" value="" onclick="snnName('',3)">#</button><br/>
<button id="space" class="action" type="button" name="space" onclick="sName(' ')" >Space</button></div>
<button id="snClear" class="action" type="button" onclick="clr(2)" >Clear</button>
<button id="snNext" class="action" type="button" onclick="show(4)" >Next</button></div>
<div id="snnKeys">
<p class="keyLabel">Street Name (numeric)</p>
<div id="snnKeyPad">
<button class="col4" type="button" name="sn1" onclick="sName('1');pick();" >1</button>
<button class="col4" type="button" name="sn2" onclick="sName('2');pick();" >2</button>
<button class="col4" type="button" name="sn3" onclick="sName('3');pick();" >3</button>
<button id="sfx0" class="col4" type="button" name="st" onclick="snnName('st',4);" >st</button><br/>
<button class="col4" type="button" name="sn4" onclick="sName('4');pick();" >4</button>
<button class="col4" type="button" name="sn5" onclick="sName('5');pick();" >5</button>
<button class="col4" type="button" name="sn6" onclick="sName('6');pick()" >6</button>
<button id="sfx1" class="col4" type="button" name="nd" onclick="snnName('nd',4)" >nd</button><br/>
<button class="col4" type="button" name="sn7" onclick="sName('7');pick();" >7</button>
<button class="col4" type="button" name="sn8" onclick="sName('8');pick();" >8</button>
<button class="col4" type="button" name="sn9" onclick="sName('9');pick();" >9</button>
<button id="sfx2" class="col4" type="button" name="rd" onclick="snnName('rd',4)" >rd</button><br/>
<button class="col4" type="button" name="snClr" onclick="snnName('',2)" >abc</button>
<button class="col4" type="button" name="sn0" onclick="sName('0');pick()" >0</button>
<button class="col4" type="button" name="snBS" onclick="snBack()" >&lt;</button>
<button id="sfx3" class="col4" type="button" name="rd" onclick="snnName('th',4)" >th</button><br/></div>
<button id="snnClear" class="action" type="button" onclick="clr(2)" >Clear</button>
<button id="snnNext" class="action" type="button" onclick="snnName('',4)" >Next</button></div>
<div id="typeKeys">
<p class="keyLabel">Street Type</p>
<div id="typeKeyPad">
<button class="col4" type="button" value="Ave" onclick="sType('Ave')">Ave</button>
<button class="col4" type="button" value="St" onclick="sType('St')">St</button>
<button class="col4" type="button" value="Rd" onclick="sType('Rd')">Rd</button>
<button class="col4" type="button" value="Blvd" onclick="sType('Blvd')">Blvd</button><br/>
<button class="col4" type="button" value="Dr" onclick="sType('Dr')">Dr</button>
<button class="col4" type="button" value="Cir" onclick="sType('Cir')">Cir</button>
<button class="col4" type="button" value="Ct" onclick="sType('Ct')">Ct</button>
<button class="col4" type="button" value="Ln" onclick="sType('Ln')">Ln</button><br/>
<button class="col4" type="button" value="Pl" onclick="sType('Pl')">Pl</button>
<button class="col4" type="button" value="Ter" onclick="sType('Ter')">Ter</button>
<button class="col4" type="button" value="Way" onclick="sType('Way')">Way</button>
<button class="col4" type="button" value="Hwy" onclick="sType('Hwy')">Hwy</button><br/>
<button class="col4" type="button" value="Pkwy" onclick="sType('Pkwy')">Pkwy</button>
<button class="col4" type="button" value="Sq" onclick="sType('Sq')">Sq</button>
<button class="col4" type="button" value="Trce" onclick="sType('Trce')">Trce</button>
<select id="selectID" class="col4" size="1" name="selectID" onchange="stOther()">
<option value="" disabled="disabled" selected="selected" >Other</option>
<option value="Aly">Alley</option><option value="Anx">Annex</option><option value="Arc">Arcade</option><option value="Ave">Avenue</option><option value="Byu">Bayoo</option><option value="Bch">Beach</option><option value="Bnd">Bend</option><option value="Blf">Bluff</option><option value="Blfs">Bluffs</option><option value="Btm">Bottom</option><option value="Blvd">Boulevard</option><option value="Br">Branch</option><option value="Brg">Bridge</option><option value="Brk">Brook</option><option value="Brks">Brooks</option><option value="Bg">Burg</option><option value="Bgs">Burgs</option><option value="Byp">Bypass</option><option value="Cp">Camp</option><option value="Cyn">Canyon</option><option value="Cpe">Cape</option><option value="Cswy">Causeway</option><option value="Ctr">Center</option><option value="Ctrs">Centers</option><option value="Cir">Circle</option><option value="Cirs">Circles</option><option value="Clf">Cliff</option><option value="Clfs">Cliffs</option><option value="Clb">Club</option><option value="Cmn">Common</option><option value="Cor">Corner</option><option value="Cors">Corners</option><option value="Crse">Course</option><option value="Ct">Court</option><option value="Cts">Courts</option><option value="Cv">Cove</option><option value="Cvs">Coves</option><option value="Cres">Crescent</option><option value="Crst">Crest</option><option value="Xing">Crossing</option><option value="Xrd">Crossroad</option><option value="Curv">Curve</option><option value="Dl">Dale</option><option value="Dm">Dam</option><option value="Dv">Divide</option><option value="Dr">Drive</option><option value="Drs">Drives</option><option value="Est">Estate</option><option value="Ests">Estates</option><option value="Expy">Expressway</option><option value="Ext">Extension</option><option value="Exts">Extensions</option><option value="Fall">Fall</option><option value="Fls">Falls</option><option value="Fry">Ferry</option><option value="Fld">Field</option><option value="Flds">Fields</option><option value="Flt">Flat</option><option value="Flts">Flats</option><option value="Frd">Ford</option><option value="Frds">Fords</option><option value="Frst">Forest</option><option value="Frg">Forge</option><option value="Frgs">Forges</option><option value="Frk">Fork</option><option value="Frks">Forks</option><option value="Ft">Fort</option><option value="Fwy">Freeway</option><option value="Gdn">Garden</option><option value="Gdns">Gardens</option><option value="Gln">Glen</option><option value="Glns">Glens</option><option value="Grn">Green</option><option value="Grns">Greens</option><option value="Grv">Grove</option><option value="Grvs">Groves</option><option value="Hbr">Harbor</option><option value="Hbrs">Harbors</option><option value="Hvn">Haven</option><option value="Hts">Heights</option><option value="Hwy">Highway</option><option value="Hl">Hill</option><option value="Hls">Hills</option><option value="Holw">Hollow</option><option value="Inlt">Inlet</option><option value="Is">Island</option><option value="Iss">Islands</option><option value="Isle">Isle</option><option value="Jct">Junction</option><option value="Jcts">Junctions</option><option value="Ky">Key</option><option value="Kys">Keys</option><option value="Knl">Knoll</option><option value="Knls">Knolls</option><option value="Lk">Lake</option><option value="Lks">Lakes</option><option value="Land">Land</option><option value="Lndg">Landing</option><option value="Ln">Lane</option><option value="Lgt">Light</option><option value="Lgts">Lights</option><option value="Lf">Loaf</option><option value="Lck">Lock</option><option value="Lcks">Locks</option><option value="Ldg">Lodge</option><option value="Loop">Loop</option><option value="Mall">Mall</option><option value="Mnr">Manor</option><option value="Mnrs">Manors</option><option value="Mdw">Meadow</option><option value="Mdws">Meadows</option><option value="Mews">Mews</option><option value="Ml">Mill</option><option value="Mls">Mills</option><option value="Msn">Mission</option><option value="Mtwy">Motorway</option><option value="Mt">Mount</option><option value="Mtn">Mountain</option><option value="Mtns">Mountains</option><option value="Nck">Neck</option><option value="Orch">Orchard</option><option value="Oval">Oval</option><option value="Opas">Overpass</option><option value="Park">Park</option><option value="Pkwy">Parkway</option><option value="Pass">Pass</option><option value="Psge">Passage</option><option value="Path">Path</option><option value="Pike">Pike</option><option value="Pne">Pine</option><option value="Pnes">Pines</option><option value="Pl">Place</option><option value="Pln">Plain</option><option value="Plns">Plains</option><option value="Plz">Plaza</option><option value="Pt">Point</option><option value="Pts">Points</option><option value="Prt">Port</option><option value="Pr">Prairie</option><option value="Radl">Radial</option><option value="Ramp">Ramp</option><option value="Rnch">Ranch</option><option value="Rpd">Rapid</option><option value="Rpds">Rapids</option><option value="Rst">Rest</option><option value="Rdg">Ridge</option><option value="Rdgs">Ridges</option><option value="Riv">River</option><option value="Rd">Road</option><option value="Rds">Roads</option><option value="Rte">Route</option><option value="Row">Row</option><option value="Rue">Rue</option><option value="Run">Run</option><option value="Shl">Shoal</option><option value="Shls">Shoals</option><option value="Shr">Shore</option><option value="Shrs">Shores</option><option value="Skwy">Skyway</option><option value="Spg">Spring</option><option value="Spgs">Springs</option><option value="Spur">Spur</option><option value="Sq">Square</option><option value="Sqs">Squares</option><option value="Sta">Station</option><option value="Stra">Stravenue</option><option value="Strm">Stream</option><option value="St">Street</option><option value="Sts">Streets</option><option value="Smt">Summit</option><option value="Ter">Terrace</option><option value="Trwy">Throughway</option><option value="Trce">Trace</option><option value="Trak">Track</option><option value="Trfy">Trafficway</option><option value="Trl">Trail</option><option value="Tunl">Tunnel</option><option value="Tpke">Turnpike</option><option value="Upas">Underpass</option><option value="Un">Union</option><option value="Vly">Valley</option><option value="Vlys">Valleys</option><option value="Via">Viaduct</option><option value="Vw">View</option><option value="Vws">Views</option><option value="Vlg">Village</option><option value="Vlgs">Villages</option><option value="Vl">Ville</option><option value="Vis">Vista</option><option value="Walk">Walk</option><option value="Wall">Wall</option><option value="Way">Way</option><option value="Ways">Ways</option><option value="Wl">Well</option><option value="Wls">Wells</option>
</select><br/></div>
<button id="stClear" class="action" type="button" onclick="clr(4)" >Clear</button>
<button id="stNext" class="action" type="button" onclick="show(5)" >Next</button></div>
<div id="zcKeys">
<p class="keyLabel">Zip Code</p>
<div id="zcKeyPad">
<button class="col3" type="button" value="1" onclick="zipCode(1)">1</button>
<button class="col3" type="button" value="2" onclick="zipCode(2)">2</button>
<button class="col3" type="button" value="3" onclick="zipCode(3)">3</button><br/>
<button class="col3" type="button" value="4" onclick="zipCode(4)">4</button>
<button class="col3" type="button" value="5" onclick="zipCode(5)">5</button>
<button class="col3" type="button" value="6" onclick="zipCode(6)">6</button><br/>
<button class="col3" type="button" value="7" onclick="zipCode(7)">7</button>
<button class="col3" type="button" value="8" onclick="zipCode(8)">8</button>
<button class="col3" type="button" value="9" onclick="zipCode(9)">9</button><br/>
<button class="col3" type="button" value="">&ensp;</button>
<button class="col3" type="button" value="0" onclick="zipCode(0)">0</button>
<button class="col3" type="button" value="Back" onclick="zcBack()">&lt;</button><br/></div>
<button id="zcClear" class="action" type="button" onclick="clr(5)" >Clear</button>
<button id="zcNext" class="action" type="button" onclick="show(0)" >Next</button></div>
<div><input id="addr" type="text" name="addr" value=""/><br/></div>
<div><button id="sub" class="action" type="submit" value="Validate">Validate</button></div>
</form></div>

\$\endgroup\$
  • \$\begingroup\$ @200_success I do not understand "no conditionals" and "golfing". I can answer Yes to all six questions on "To be on-topic". I have edited the question to be more clear on what type of response I am looking for. \$\endgroup\$ – Misunderstood Apr 9 '15 at 0:39
  • \$\begingroup\$ Thanks for adding the rationale for the "no conditionals" objective. \$\endgroup\$ – 200_success Apr 9 '15 at 0:50
  • \$\begingroup\$ @200_success The major point is that the code is incomprehensible. Is it worth it? It was a major effort to write code without conditional branching instructions. From a performance stand point it is bench marked with substantial performance improvement vs. traditional programming. Would it help if I were to give more insight on how this method works? Or should I just give up? \$\endgroup\$ – Misunderstood Apr 9 '15 at 0:58
  • \$\begingroup\$ I've reopened the question. Let's see what responses you get. \$\endgroup\$ – 200_success Apr 9 '15 at 0:59
3
\$\begingroup\$

UI

The UI is conceptually problematic. Start by reading Falsehoods programmers believe about addresses. Many of the odd cases cited there refer to non-US addresses. However, I can think of a few addresses that I would have trouble entering in your UI.

  • Unconventional House Numbers: Where does the "B" in 221B Baker Street go? How about fractional house numbers?
  • Suites and apartments: For geolocation, just a house number will do. For physical delivery of goods, you need a suite number or apartment number.
  • Unconventional Street Names: In Bellingham, WA, there is a street called Boulevard. California has El Camino Real. How do these names fit into your scheme?

There are UI bugs as well.

  • This button layout is not logical:

    EN
    WS

  • Selecting a street type using the drop-down box doesn't update the text field.
  • The behaviour of the ZIP Code field, with decreasing zero-padding as you type, is weird. Typing a few digits, then hitting the < button and seeing the zero-padding disappear, is even weirder.
  • Tabbing through the fields causes the labels to receive focus. What good does that do?

In summary, do you have a good justification for breaking up the address fields like that? The convenience of having customized keypads for each field is not enough of a reason to put up with all the problems it creates.

\$\endgroup\$
  • 1
    \$\begingroup\$ I'm impressed. That coming from a guy that is not easily impressed. The falsehoods link is invaluable. I do pizza delivery software. I was playing with this concept because addresses are a major problem in the online delivery. There is a fall back, you can type your address on the bottom line. But I do not think this concept is going to fly. There is a way to do this. Throw enough stuff at the wall and eventually something will stick. Teflon walls here. Back to the drawing board. I do appreciate your feedback. \$\endgroup\$ – Misunderstood Apr 9 '15 at 5:55
  • \$\begingroup\$ "good justification"? This reminded me why I did this. When perusing clients customer address database records I noticed the staff had various styles to entering addresses. The owner would want to use the list for mailing. The addresses were too unsightly, (e.g. upper lower, short cuts) to send to customers. \$\endgroup\$ – Misunderstood Apr 9 '15 at 15:05
  • \$\begingroup\$ That is a data normalization problem, not a data entry problem. You can apply heuristics to fix capitalization. There are also address databases for verification. \$\endgroup\$ – 200_success Apr 9 '15 at 15:14
3
\$\begingroup\$

The major point is that the code is incomprehensible. Is it worth it?

I don't think so. This doesn't seem like performance sensitive code. Even if you added a couple of branch instructions, it shouldn't lag (not now, and not with future extensions to the code either), so there is no reason to avoid them (except to see if you can do it).

The lack of branch instructions isn't the only reason that your code is extremely hard to read though. Your variable names and your formatting are also making your code hard to read, and thus hard to maintain.

There are tools which can minify your JavaScript and CSS for you (and they will do a better job than you will), so there is no reason for doing it that way, you can follow proper formatting rules (this goes for the JavaScript, CSS, and HTML):

  • each statement goes on it's own line.
  • more whitespace. spaces around =, +, etc after ;, etc. Newlines to separate logical blocks of code.
  • don't abbreviate variable and function names (with a couple conventional exceptions; i is often fine for index, etc). You want to reduce the work a reader has to do. They shouldn't have to think about what st in stOther means, what zc, sn, and hn mean in [x]Back, what s stands for in sName, sDirection, etc., if sel stands for select, what pick picks, and so on.
\$\endgroup\$
  • \$\begingroup\$ You got me. When I did this app it was a "to see if I can do it". It was, however, inspired by the Intel optimization suggestions. I have since found it to provide phenomenal performance enhancement where needed. Thank you for pointing the minimization. When I am done coding I have some search and replace routines that I use to minimize white space etc. Now I realize that is not a good thing when others are reviewing the code. This is my first question post here and did not think. I have always worked alone and no one sees my code. The short var names is my OCD saving pico seconds. \$\endgroup\$ – Misunderstood Apr 9 '15 at 13:03
3
\$\begingroup\$

Micro-optimization

CPUs may work best when they execute code that doesn't branch. However, you are programming at a much higher abstraction level. Just because you didn't write any if statements in your JavaScript code doesn't mean that it's branchless code.

Consider that all array accesses are checked, so that attempting to retrieve an item past the end of an array results in a JavaScript exception, not a segmentation fault. That means that every array[n] in JavaScript implicitly results in a branch instruction at the machine code level.

Whenever you look up any attribute of an object using a object.name operator or object['name'], that's a lookup in a hashtable somewhere. That lookup likely not branchless.

Consider also the nature of the tasks involved. Waiting for user input is not at all a CPU-limited activity. Browser layout is also not very CPU-intensive, and is full of unavoidable conditional logic. Removing conditional logic could be beneficial for a CPU-intensive task, such as video compression or encryption. It is not at all useful for this kind of application. Have you measured any appreciable difference in performance resulting from removal of branching? Even if you did have a performance problem, is branch removal the best strategy for fixing it? I would consider this strategy one of premature optimization.

In conclusion, I recommend that you write code in the most natural, logical, and maintainable way possible without regard to branch removal. If there are performance issues, it's likely that a completely different solution (e.g. replacing JavaScript code with some HTML5 feature or CSS effect) would yield much greater benefit.

Example

As a specific example, let's look at these two functions:

function show(n) {
    var s=key[n];
    var k=n;
    key[0]=0;key[1]=0;key[2]=0;key[3]=0;key[4]=0;key[5]=0;
    keys[0].style.display=display[0];
    keys[1].style.display=display[0];
    keys[2].style.display=display[0];
    keys[3].style.display=display[0];
    keys[4].style.display=display[0];
    keys[5].style.display=display[0];
    key[k]=toggle[s];
    keys[k].style.display=display[key[k]];
    sel(k);
    showAddr();
    text[k].focus();
}
function sel(k) {
    showKey[0].style.background=bg[key[0]];
    showKey[1].style.background=bg[0];
    showKey[2].style.background=bg[0];
    showKey[4].style.background=bg[0];
    showKey[5].style.background=bg[0];
    text[0].style.background=bg[0];
    text[1].style.background=bg[0];
    text[2].style.background=bg[0];
    text[4].style.background=bg[0];
    text[5].style.background=bg[0];
    showKey[tKey[k]].style.background=bg[key[tKey[k]]];
    text[tKey[k]].style.background=bg[key[tKey[k]]];
}

After analyzing it for a while, I see that show(n) activates the nth keypad and deactivates all the others. However, a much simpler technique for accomplishing that is to set a class on the top-level <div id="content"> element that indicates the currently active keypad, and let CSS rules take care of everything else. Your code should look more like this:

var contentElement = document.getElementById('content');

function showKeypad(keypadId) {
    contentElement.className = 'activeKeypad' + keypadId;
    showAddr();
    textField[keypadId].focus();
}

For an illustration of this single-master-switch technique, see iPhone notes application replica using HTML/CSS. (That illustration uses jQuery, but the principle is the same: executing $('#notes-app').removeClass('mode-note').addClass('mode-list') triggers a dramatic change in the UI by taking advantage of CSS cascading.) Using this technique results in code that is

  • more readable
  • shorter, less repetitive, and more maintainable
  • more efficient

… all without the headaches caused by premature micro-optimization.

\$\endgroup\$
  • \$\begingroup\$ Thank you for your insightful input, again. I agree this is not the best app to use this type of optimization. It was the first project where I discovered an app could be written with out branching instructions. I have since used this method in a PHP app with loops with a lot of decision making. Phenomenally fast. But as you pointed out, not only difficult to maintain, but an extraordinary amount of time to write. Desktop performance is not an issue. I wrote a pizza app in jQuery Mobile. An iPad took 2 sec. for the jQuery check box pop up to show. On a desktop delay was imperceptible. \$\endgroup\$ – Misunderstood Apr 9 '15 at 12:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.