<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1829691255062570719</id><updated>2011-11-04T22:04:52.537-07:00</updated><category term='unobtrusive'/><category term='dom'/><category term='javascript'/><category term='internet explorer'/><category term='apple'/><category term='free'/><category term='tutorial'/><category term='noob'/><category term='cross browser'/><category term='web standards'/><category term='aboutme'/><category term='code examples'/><category term='editor'/><category term='iphone'/><category term='webstandards'/><category term='css'/><category term='iphoneui'/><category term='texteditor'/><category term='user interface'/><category term='HTML'/><category term='lgpl'/><category term='forms'/><category term='strings'/><category term='numbers'/><category term='codeeditor'/><category term='safari'/><category term='firstpost'/><title type='text'>FundaMental Disaster</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://fundamentaldisaster.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1829691255062570719/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://fundamentaldisaster.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Greg Burghardt</name><uri>http://www.blogger.com/profile/14825576215668294298</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>10</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1829691255062570719.post-4784151761630858565</id><published>2008-10-24T11:23:00.000-07:00</published><updated>2008-11-11T09:31:29.563-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='internet explorer'/><category scheme='http://www.blogger.com/atom/ns#' term='code examples'/><category scheme='http://www.blogger.com/atom/ns#' term='cross browser'/><category scheme='http://www.blogger.com/atom/ns#' term='web standards'/><title type='text'>Cross-Browser JavaScript: Creating DOM Nodes That Set The name Property</title><content type='html'>&lt;h3 class="post-subtitle"&gt;Creating and appending DOM nodes
to a form can be tricky. Internet Explorer needs special care when you
create a DOM node and then set the name property. This handy JavaScript
gets around these cross browser issues efficiently, and without browser
detection.&lt;/h3&gt;
&lt;p&gt;Web browsers have come a long way. We can create Document Object Model nodes at will using the universally supported &lt;code&gt;document.createElement&lt;/code&gt;
function, then you try creating form fields in Internet Explorer and
you hit a snag.&lt;/p&gt;
&lt;p&gt;Form fields, in order to be useful, need a &lt;code&gt;name&lt;/code&gt;
attribute in HTML. In JavaScript, you set the &lt;code&gt;name&lt;/code&gt;
property. It's two simple lines of code. Nothing special. No hoops to
jump through:&lt;/p&gt;
&lt;pre class="code-block"&gt;// Create a new form input to hold a first name:&lt;br /&gt;var el = document.createElement("input");&lt;br /&gt;el.name = "fname";&lt;/pre&gt;
&lt;p&gt;You append this new &lt;code&gt;input&lt;/code&gt; to your &lt;code&gt;form&lt;/code&gt;
and then try to access it using the &lt;code&gt;form.elements.field_name&lt;/code&gt; syntax and you can't find the &lt;code&gt;"fname"&lt;/code&gt; field. Turns out, Internet Explorer requires a
little fudging:&lt;/p&gt;
&lt;pre class="code-block"&gt;// Create a new form input for Internet Explorer:&lt;br /&gt;var el = document.createElement("&amp;lt;input name=fname&amp;gt;");&lt;/pre&gt;
&lt;p&gt;In one fell swoop, you must create the new element AND assign
the &lt;code&gt;name&lt;/code&gt; property before Internet Explorer
will append this element to the form's document object model, making it available through the &lt;code&gt;form.elements.&lt;em&gt;field_name&lt;/em&gt;&lt;/code&gt; syntax. The
problem is, standards compliant browsers, i.e. "every other browser
developed within the last 8 years," will throw a JavaScript error if
they try executing that code.&lt;/p&gt;
&lt;p&gt;You could try browser detection, which usually involves
parsing the user agent string of the browser. Most browsers allow you
to change the user agent string, so this is no longer a viable method.
Plus, what do you do when a new browser or browser version comes out?
You'd have to change your function. Turns out, a simple &lt;code&gt;try-catch&lt;/code&gt;
block is the answer.&lt;/p&gt;
&lt;h4 class="entry-subtitle2"&gt;Creating a named DOM node the
coss browser way&lt;/h4&gt;
&lt;p&gt;We can create our own &lt;code&gt;createElement&lt;/code&gt;
function to account for the difference in Internet Explorer's
implementation of &lt;code&gt;document.createElement&lt;/code&gt;:&lt;/p&gt;
&lt;div class="expando expando-third"&gt;
&lt;pre class="code-block"&gt;function createElement(nodeName, name) {&lt;br /&gt;  var node;&lt;br /&gt;  try {&lt;br /&gt;    node = document.createElement("&amp;lt;"+nodeName+" name="+name+"&amp;gt;");&lt;br /&gt;  } catch (e) {&lt;br /&gt;    node = document.createElement(nodeName);&lt;br /&gt;    node.name = name;&lt;br /&gt;  }&lt;br /&gt;  return node;&lt;br /&gt;}&lt;/pre&gt;
&lt;span class="corner corner-top"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="corner corner-bottom"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;It works fine and dandy. Every time you call the function, it
tries doing it Internet Explorer's way, but you take a performance hit
because of the &lt;code&gt;try-catch&lt;/code&gt; block that executes
every time the &lt;code&gt;createElement&lt;/code&gt; function
executes. With a little runtime retooling, we can get around this using
three functions instead of one:&lt;/p&gt;
&lt;div class="expando expando-third"&gt;
&lt;pre class="code-block"&gt;/**&lt;br /&gt; * Cross browser method for creating new DOM nodes with name attributes. This&lt;br /&gt; * gets around an Internet Explorer bug that prevents that get the name property&lt;br /&gt; *&amp;nbsp;assigned to them and their values aren't sent when the form submits.&lt;br /&gt; *&lt;br /&gt; * @param   string  required  Node name, like "div" or "input"&lt;br /&gt; * @param   string  required  Value of the name attribute&lt;br /&gt; * @return  object  New DOM node&lt;br /&gt; */&lt;br /&gt;function createElement(nodeName, name) {&lt;br /&gt;  var node;&lt;br /&gt;  try {&lt;br /&gt;    node = createElementMsie(nodeName, name);&lt;br /&gt;    createElement = createElementMsie;&lt;br /&gt;  } catch (e) {&lt;br /&gt;    node = createElementStandard(nodeName, name);&lt;br /&gt;    createElement = createElementStandard;&lt;br /&gt;  }&lt;br /&gt;  return node;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * Code required by Internet Explorer when creating a new DOM node with the&lt;br /&gt; * name attribute set.&lt;br /&gt; */&lt;br /&gt;function createElementMsie(nodeName, name) {&lt;br /&gt;  return document.createElement("&amp;lt;"+nodeName+" name="+name+"&amp;gt;");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * Code required by all other browsers that support web standards.&lt;br /&gt; */&lt;br /&gt;function createElementStandard(nodeName, name) {&lt;br /&gt;  var node = document.createElement(nodeName);&lt;br /&gt;  node.name = name;&lt;br /&gt;  return node;&lt;br /&gt;}&lt;/pre&gt;
&lt;span class="corner corner-top"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="corner corner-bottom"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;When the page first loads, you've got three functions. The &lt;code&gt;createElement&lt;/code&gt;
function, which is what you will&amp;nbsp;&lt;em&gt;always&lt;/em&gt;
use, has a &lt;code&gt;try-catch&lt;/code&gt; block that calls two
other functions. The &lt;code&gt;createElementMsie&lt;/code&gt;
function attempts to create the new DOM node using Internet Explorer's
implementation. If the function call succeeds, the &lt;code&gt;createElement&lt;/code&gt;
function is &lt;em&gt;reassigned&lt;/em&gt; to be the &lt;code&gt;createElementMsie&lt;/code&gt;
function. All subsequent calls to &lt;code&gt;createElement&lt;/code&gt;
will run the code in &lt;code&gt;createElementMsie&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In the &lt;code&gt;catch&lt;/code&gt; clause, the browser has
failed to execute &lt;code&gt;createElementMsie&lt;/code&gt;, and
therefore doesn't support Internet Explorer's implementation of &lt;code&gt;document.createElement&lt;/code&gt;.
Here we assume it is a standards compliant browser and doesn't need any
hand holding. It calls &lt;code&gt;createElementStandard&lt;/code&gt;,
and when that succeeds it reassigns the &lt;code&gt;createElement&lt;/code&gt;
function to be the &lt;code&gt;createElementStandard&lt;/code&gt;
function. All subsequent calls to &lt;code&gt;createElement&lt;/code&gt;
run the code in &lt;code&gt;createElementStandard&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You still take a performance hit with these three functions
because the &lt;code&gt;try-catch&lt;/code&gt; block is executed, &lt;em&gt;but
only for the first time you call createElement.&lt;/em&gt; From the
second time you call &lt;code&gt;createElement&lt;/code&gt; onwards,
it directly executes the code the browser supports. The &lt;code&gt;try-catch&lt;/code&gt;
block doesn't exist anymore, and you've gotten around Internet
Explorer's faulty implementation of the &lt;code&gt;document.createElement&lt;/code&gt;
function. You can now create form fields at will and feel safe in
knowing Internet Explorer will actually send those field values to the
server when the form is submitted.&lt;/p&gt;
&lt;h5 class="code-label"&gt;Using createElement:&lt;/h5&gt;
&lt;pre class="code-block"&gt;var el = createElement("input", "fname");&lt;br /&gt;// append the new INPUT to the form.&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1829691255062570719-4784151761630858565?l=fundamentaldisaster.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fundamentaldisaster.blogspot.com/feeds/4784151761630858565/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1829691255062570719&amp;postID=4784151761630858565' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1829691255062570719/posts/default/4784151761630858565'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1829691255062570719/posts/default/4784151761630858565'/><link rel='alternate' type='text/html' href='http://fundamentaldisaster.blogspot.com/2008/10/cross-browser-javascript-creating-dom.html' title='Cross-Browser JavaScript: Creating DOM Nodes That Set The name Property'/><author><name>Greg Burghardt</name><uri>http://www.blogger.com/profile/14825576215668294298</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1829691255062570719.post-9022587959178216754</id><published>2008-10-07T19:37:00.000-07:00</published><updated>2008-10-07T19:42:40.604-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='code examples'/><category scheme='http://www.blogger.com/atom/ns#' term='web standards'/><category scheme='http://www.blogger.com/atom/ns#' term='unobtrusive'/><title type='text'>JavaScript Zebra Stripes: Alternate Background Colors on Tables and Lists</title><content type='html'>&lt;p&gt;Love
it or hate it, alternating background colors is a common design request
for web designers. If you maintain a site of static HTML files, this
"zebra striping" effect can become time consuming and tedious. Even if
you use a content management system or a server side language,
automation is your friend. This script is the automation you want.&lt;/p&gt;&lt;p&gt;There
are tons of similar scripts on the Internet, and all do a great job.
I've found they have some short comings. I don't always just want to
alternate background colors on table rows. I often do not want
cells in the table header and footer to have alternating colors either. Things
get real messy when I want alternating colors on list items, and
especially definition lists. This script package seeks to solve all
these problems.&lt;/p&gt;&lt;h4 class="entry-subtitle2"&gt;Browser Support&lt;/h4&gt;
&lt;p&gt;All standards compliant browsers are supported, as well as Internet Explorer version 5.0 and newer. If the browser supports the &lt;code&gt;*.getElementsByTagName&lt;/code&gt;
method, then the browser supports this script. This is also safe to use
with any pre existing JavaScript library or framework. It packages all
the related functions into an object called&amp;nbsp;&lt;code&gt;stripes&lt;/code&gt;.
As long as you don't have a global variable or function named
"stripes," this is safe to use, and since it utilizes only standard &lt;abbr title="Document Object Model"&gt;DOM&lt;/abbr&gt; &lt;abbr title="Application Programming Interface"&gt;API&lt;/abbr&gt; calls, no additional JavaScript libraries are required.&lt;/p&gt;&lt;h4 class="entry-subtitle entry-subtitle2"&gt;Using the &lt;code&gt;stripes&lt;/code&gt; functions&lt;/h4&gt;&lt;p&gt;Usually
you'll want some sort of JavaScript event to kick things off. I
recommend the onload event if you don't use a JavaScript framework like
Mootools or jQuery. A simple function call in the &lt;code&gt;onload&lt;/code&gt; attribute of the &lt;code&gt;body&lt;/code&gt; tag will suffice:&lt;/p&gt;&lt;pre class="code-block"&gt;&amp;lt;body onload="&lt;strong&gt;stripes.execute();&lt;/strong&gt;"&amp;gt;&lt;/pre&gt;
&lt;p&gt;For those who like unobtrusive JavaScript, you can add this to the window.onload function:&lt;/p&gt;&lt;pre class="code-block"&gt;window.onload = function() {&lt;br /&gt;  &lt;strong&gt;stripes.execute();&lt;/strong&gt;&lt;br /&gt;};&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;stripes.execute()&lt;/code&gt; function will parse the entire
document object model. For very large HTML files, you might not want
the function parsing the entire DOM tree. You can specify a root DOM
element from which to start searching by passing an HTML tag Id or DOM
node reference to the &lt;code&gt;stripes.execute()&lt;/code&gt; function. If no argument is passed, or the Id passed does not exist in the HTML document, then the &lt;code&gt;document&lt;/code&gt; element is used.&lt;/p&gt;&lt;pre class="code-block"&gt;// Only search in &amp;lt;div id="content"&amp;gt;&lt;br /&gt;&lt;br /&gt;window.onload = function() {&lt;br /&gt;  stripes.execute( "content" );&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;/* --- OR --- */&lt;br /&gt;&lt;br /&gt;window.onload = function() {&lt;br /&gt;  var contentNode = document.getElementById( "content" );&lt;br /&gt;  stripes.execute( contentNode );&lt;br /&gt;};&lt;/pre&gt;&lt;h4 class="entry-subtitle2"&gt;How it works&lt;/h4&gt;&lt;p&gt;The
only thing this script package does is change class names on DOM node
elements. For tables, a class name is assigned to the &lt;code&gt;&amp;lt;tr&amp;gt;&lt;/code&gt; tag.
For unordered and ordered lists, the class name is assigned to the
&lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt; tag. Lastly, for definition lists the class name is assigned
to the &lt;code&gt;&amp;lt;dt&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;dd&amp;gt;&lt;/code&gt; tags. All you need to do is add style
rules to your CSS.&lt;/p&gt;&lt;p&gt;The script comes preprogrammed with two class
names. Even rows or list items are given the class &lt;code&gt;"rowA"&lt;/code&gt;. Odd rows or
list items are given the class &lt;code&gt;"rowB"&lt;/code&gt;. You can easily change the class
names in the JavaScript source code. Below is a snippet showing you
where you can change these default class names: &lt;/p&gt;&lt;pre class="code-block"&gt;window.stripes = {&lt;br /&gt;  &lt;br /&gt;  &lt;strong&gt;stripeRowEven : "rowA",&lt;br /&gt;  stripeRowOdd : "rowB",&lt;br /&gt;  stripeParentClass : "stripes",&lt;/strong&gt;&lt;br /&gt;  &lt;br /&gt;  ...&lt;br /&gt;  &lt;br /&gt;};&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;stripeRowEven&lt;/code&gt; and &lt;code&gt;stripeRowOdd&lt;/code&gt;
properties contain the class names assigned to table rows, list items,
and definition terms and descriptions. The third property, &lt;code&gt;stripeParentClass&lt;/code&gt;,
is the class name the script will search for when making the zebra
stripes. As mentioned earlier, this script works for tables, unordered
lists, ordered lists and definition lists:&lt;/p&gt;&lt;h5 class="code-label"&gt;HTML Structure Supported for TABLEs&lt;/h5&gt;&lt;div class="expando expando-quarter"&gt;
&lt;pre class="code-block"&gt;&amp;lt;table cellpadding="5" cellspacing="0" border="1" &lt;strong&gt;class="stripes"&lt;/strong&gt;&amp;gt;&lt;br /&gt;  &amp;lt;thead&amp;gt;&lt;br /&gt;    &amp;lt;tr&amp;gt;&lt;br /&gt;      &amp;lt;th&amp;gt;Heading 1&amp;lt;/th&amp;gt;&lt;br /&gt;      &amp;lt;th&amp;gt;Heading 2&amp;lt;/th&amp;gt;&lt;br /&gt;      &amp;lt;th&amp;gt;Heading 3&amp;lt;/th&amp;gt;&lt;br /&gt;    &amp;lt;/tr&amp;gt;&lt;br /&gt;  &amp;lt;/thead&amp;gt;&lt;br /&gt;  &amp;lt;tfoot&amp;gt;&lt;br /&gt;    &amp;lt;tr&amp;gt;&lt;br /&gt;      &amp;lt;th&amp;gt;Footer 1&amp;lt;/th&amp;gt;&lt;br /&gt;      &amp;lt;th&amp;gt;Footer 2&amp;lt;/th&amp;gt;&lt;br /&gt;      &amp;lt;th&amp;gt;Footer 3&amp;lt;/th&amp;gt;&lt;br /&gt;    &amp;lt;/tr&amp;gt;&lt;br /&gt;  &amp;lt;/tfoot&amp;gt;&lt;br /&gt;  &amp;lt;tbody&amp;gt;&lt;br /&gt;    &amp;lt;tr&amp;gt;&lt;br /&gt;      &amp;lt;td&amp;gt;Cell 1.1&amp;lt;/td&amp;gt;&lt;br /&gt;      &amp;lt;td&amp;gt;Cell 1.2&amp;lt;/td&amp;gt;&lt;br /&gt;      &amp;lt;td&amp;gt;Cell 1.3&amp;lt;/td&amp;gt;&lt;br /&gt;    &amp;lt;/tr&amp;gt;&lt;br /&gt;    &amp;lt;tr&amp;gt;&lt;br /&gt;      &amp;lt;td&amp;gt;Cell 2.1&amp;lt;/td&amp;gt;&lt;br /&gt;      &amp;lt;td&amp;gt;Cell 2.2&amp;lt;/td&amp;gt;&lt;br /&gt;      &amp;lt;td&amp;gt;Cell 2.3&amp;lt;/td&amp;gt;&lt;br /&gt;    &amp;lt;/tr&amp;gt;&lt;br /&gt;  &amp;lt;/tbody&amp;gt;&lt;br /&gt;&amp;lt;/table&amp;gt;&lt;/pre&gt;
&lt;span class="corner corner-top"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="corner corner-bottom"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;h5 class="code-label"&gt;HTML Structure for Lists&lt;/h5&gt;&lt;div class="expando expando-quarter"&gt;
&lt;pre class="code-block"&gt;&amp;lt;ul &lt;strong&gt;class="stripes"&lt;/strong&gt;&amp;gt;&lt;br /&gt;  &amp;lt;li&amp;gt;List Item 1&amp;lt;/li&amp;gt;&lt;br /&gt;  &amp;lt;li&amp;gt;List Item 2&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;lt;/ul&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;ol &lt;strong&gt;class="stripes"&lt;/strong&gt;&amp;gt;&lt;br /&gt;  &amp;lt;li&amp;gt;List Item 1&amp;lt;/li&amp;gt;&lt;br /&gt;  &amp;lt;li&amp;gt;List Item 2&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;dl &lt;strong&gt;class="stripes"&lt;/strong&gt;&amp;gt;&lt;br /&gt;  &lt;br /&gt;  &amp;lt;dt&amp;gt;Definition Term 1&amp;lt;/dt&amp;gt;&lt;br /&gt;  &amp;lt;dd&amp;gt;Description 1.1&amp;lt;/dd&amp;gt;&lt;br /&gt;  &amp;lt;dd&amp;gt;Description 1.2&amp;lt;/dd&amp;gt;&lt;br /&gt;  &lt;br /&gt;  &amp;lt;dt&amp;gt;Definition Term 2&amp;lt;/dt&amp;gt;&lt;br /&gt;  &amp;lt;dd&amp;gt;Description 2.1&amp;lt;/dd&amp;gt;&lt;br /&gt;  &amp;lt;dd&amp;gt;Description 2.2&amp;lt;/dd&amp;gt;&lt;br /&gt;  &amp;lt;dd&amp;gt;Description 2.3&amp;lt;/dd&amp;gt;&lt;br /&gt;  &lt;br /&gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;&lt;/pre&gt;
&lt;span class="corner corner-top"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="corner corner-bottom"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;p&gt;You'll notice that with the &lt;code&gt;&amp;lt;dl&amp;gt;&lt;/code&gt; tags you can specify more
than one &lt;code&gt;&amp;lt;dt&amp;gt;&lt;/code&gt;, and more than one &lt;code&gt;&amp;lt;dd&amp;gt;&lt;/code&gt; per definition term.
After the script runs, the tables and lists will be given this HTML
structure:&lt;/p&gt;&lt;h5 class="code-label"&gt;Tables, after scripts.execute()&lt;/h5&gt;&lt;div class="expando expando-quarter"&gt;
&lt;pre class="code-block"&gt;&amp;lt;table cellpadding="5" cellspacing="0" border="1" class="stripes"&amp;gt;&lt;br /&gt;  &amp;lt;thead&amp;gt;&lt;br /&gt;    &amp;lt;tr&amp;gt;&lt;br /&gt;      &amp;lt;th&amp;gt;Heading 1&amp;lt;/th&amp;gt;&lt;br /&gt;      &amp;lt;th&amp;gt;Heading 2&amp;lt;/th&amp;gt;&lt;br /&gt;      &amp;lt;th&amp;gt;Heading 3&amp;lt;/th&amp;gt;&lt;br /&gt;    &amp;lt;/tr&amp;gt;&lt;br /&gt;  &amp;lt;/thead&amp;gt;&lt;br /&gt;  &amp;lt;tfoot&amp;gt;&lt;br /&gt;    &amp;lt;tr&amp;gt;&lt;br /&gt;      &amp;lt;th&amp;gt;Footer 1&amp;lt;/th&amp;gt;&lt;br /&gt;      &amp;lt;th&amp;gt;Footer 2&amp;lt;/th&amp;gt;&lt;br /&gt;      &amp;lt;th&amp;gt;Footer 3&amp;lt;/th&amp;gt;&lt;br /&gt;    &amp;lt;/tr&amp;gt;&lt;br /&gt;  &amp;lt;/tfoot&amp;gt;&lt;br /&gt;  &amp;lt;tbody&amp;gt;&lt;br /&gt;    &amp;lt;tr &lt;strong&gt;class="rowA"&lt;/strong&gt;&amp;gt;&lt;br /&gt;      &amp;lt;td&amp;gt;Cell 1.1&amp;lt;/td&amp;gt;&lt;br /&gt;      &amp;lt;td&amp;gt;Cell 1.2&amp;lt;/td&amp;gt;&lt;br /&gt;      &amp;lt;td&amp;gt;Cell 1.3&amp;lt;/td&amp;gt;&lt;br /&gt;    &amp;lt;/tr&amp;gt;&lt;br /&gt;    &amp;lt;tr &lt;strong&gt;class="rowB"&lt;/strong&gt;&amp;gt;&lt;br /&gt;      &amp;lt;td&amp;gt;Cell 2.1&amp;lt;/td&amp;gt;&lt;br /&gt;      &amp;lt;td&amp;gt;Cell 2.2&amp;lt;/td&amp;gt;&lt;br /&gt;      &amp;lt;td&amp;gt;Cell 2.3&amp;lt;/td&amp;gt;&lt;br /&gt;    &amp;lt;/tr&amp;gt;&lt;br /&gt;  &amp;lt;/tbody&amp;gt;&lt;br /&gt;&amp;lt;/table&amp;gt;&lt;/pre&gt;
&lt;span class="corner corner-top"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="corner corner-bottom"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;h5 class="code-label"&gt;Lists after stripes.execute()&lt;/h5&gt;&lt;div class="expando expando-quarter"&gt;
&lt;pre class="code-block"&gt;&amp;lt;ul class="stripes"&amp;gt;&lt;br /&gt;  &amp;lt;li &lt;strong&gt;class="rowA"&lt;/strong&gt;&amp;gt;List Item 1&amp;lt;/li&amp;gt;&lt;br /&gt;  &amp;lt;li &lt;strong&gt;class="rowB"&lt;/strong&gt;&amp;gt;List Item 2&amp;lt;/li&amp;gt;&lt;br /&gt;  &amp;lt;li &lt;strong&gt;class="rowA"&lt;/strong&gt;&amp;gt;List Item 3&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;lt;/ul&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;ol class="stripes"&amp;gt;&lt;br /&gt;  &amp;lt;li &lt;strong&gt;class="rowA"&lt;/strong&gt;&amp;gt;List Item 1&amp;lt;/li&amp;gt;&lt;br /&gt;  &amp;lt;li &lt;strong&gt;class="rowB"&lt;/strong&gt;&amp;gt;List Item 2&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;dl class="stripes"&amp;gt;&lt;br /&gt;  &lt;br /&gt;  &amp;lt;dt &lt;strong&gt;class="rowA"&lt;/strong&gt;&amp;gt;Definition Term 1&amp;lt;/dt&amp;gt;&lt;br /&gt;  &amp;lt;dd &lt;strong&gt;class="rowA"&lt;/strong&gt;&amp;gt;Description 1.1&amp;lt;/dd&amp;gt;&lt;br /&gt;  &amp;lt;dd &lt;strong&gt;class="rowA"&lt;/strong&gt;&amp;gt;Description 1.2&amp;lt;/dd&amp;gt;&lt;br /&gt;  &lt;br /&gt;  &amp;lt;dt &lt;strong&gt;class="rowB"&lt;/strong&gt;&amp;gt;Definition Term 2&amp;lt;/dt&amp;gt;&lt;br /&gt;  &amp;lt;dd &lt;strong&gt;class="rowB"&lt;/strong&gt;&amp;gt;Description 2.1&amp;lt;/dd&amp;gt;&lt;br /&gt;  &amp;lt;dd &lt;strong&gt;class="rowB"&lt;/strong&gt;&amp;gt;Description 2.2&amp;lt;/dd&amp;gt;&lt;br /&gt;  &amp;lt;dd &lt;strong&gt;class="rowB"&lt;/strong&gt;&amp;gt;Description 2.3&amp;lt;/dd&amp;gt;&lt;br /&gt;  &lt;br /&gt;&amp;lt;/dl&amp;gt;&lt;br /&gt;&lt;/pre&gt;
&lt;span class="corner corner-top"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="corner corner-bottom"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;h4 class="entry-subtitle2"&gt;Styling the zebra stripes with CSS&lt;/h4&gt;&lt;p&gt;With a small amount of CSS, you can style your zebra stripes.&lt;/p&gt;&lt;pre class="code-block"&gt;.rowA {&lt;br /&gt;  background-color: #f0f0f0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.rowB {&lt;br /&gt;  background-color: #d0d0d0;&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;You can change how tables and lists are displayed by using different CSS selectors:&lt;/p&gt;&lt;pre class="code-block"&gt;tr.rowA {&lt;br /&gt;  background-color: #f0f0f0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;tr.rowB {&lt;br /&gt;  background-color: #d0d0d0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;li.rowA {&lt;br /&gt;  background-color: #fccccc;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;li.rowB {&lt;br /&gt;  background-color: #dccccc;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;dt.rowA {&lt;br /&gt;  background-color: #000;&lt;br /&gt;  color: #fff;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;dd.rowA {&lt;br /&gt;  background-color: #505050;&lt;br /&gt;  color: #fff;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;dt.rowB {&lt;br /&gt;  background-color: #ccc;&lt;br /&gt;  color: #000;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;dd.rowB {&lt;br /&gt;  background-color: #d0d0d0;&lt;br /&gt;  color: #000;&lt;br /&gt;}&lt;/pre&gt;&lt;h4 class="entry-subtitle2"&gt;Download the &lt;code&gt;stripes&lt;/code&gt; JavaScript source code&lt;/h4&gt;&lt;ol&gt;&lt;li&gt;Click on the box below to highlight the code.&lt;/li&gt;&lt;li&gt;Copy it.&lt;/li&gt;&lt;li&gt;Paste it into a blank text file.&lt;/li&gt;&lt;li&gt;Save it as &lt;code&gt;package.stripes.js&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Include it in your HTML documents using a &lt;code&gt;&amp;lt;script src=""&amp;gt;&lt;/code&gt; tag.&lt;/li&gt;&lt;/ol&gt;&lt;div class="expando"&gt;&lt;textarea class="code-block" onfocus="this.select();" readonly="readonly" cols="60" rows="16" name="txt_code"&gt;/*

Author: Greg Burghardt
greg [underscore] burghardt [at] yahoo [dot] com
Copyright 2007, Greg Burghardt

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

http://www.gnu.org/licenses/lgpl.txt

*/


/**
 * @package   stripes
 * @desc      Easily create zebra striped tables and lists.
 * @copyright (c) 2008 Greg Burghardt
 * @contact   Greg Burghardt: greg [underscore] burghardt [at] yahoo [dot] com
 * @link      http://fundamentaldisaster.blogspot.com/2008/10/javascript-zebra-stripes-alternate.html
 * @property  string  stripeRowEven       Class name for even rows
 * @property  string  stripeRowOdd        Class name for odd rows
 * @property  string  stripeParentClass   Class name for striped tables or lists
 */
window.stripes = {
  
  stripeRowEven : "rowA",
  stripeRowOdd : "rowB",
  stripeParentClass : "stripes",
  
  /**
   * @package stripes
   * @method  create
   * @desc    Creates zebra stripes on table and list elements.
   * @param   mixed   required  HTML Id or node reference
   * @return  void
   */
  create : function(el) {
    if (typeof(el) == "string") {
      el = document.getElementById(el);
    }
    if (!el || !el.nodeName) {
      return;
    }
    switch ( el.nodeName.toLowerCase() ) {
      case "table":
      case "tbody":
        this.createTable(el);
        break;
      case "ul":
      case "ol":
        this.createList(el);
        break;
      case "dl":
        this.createDL(el);
        break;
    }
  },
  
  /**
   * @package stripes
   * @method  createDL
   * @desc    Creates zebra stripes on definition lists.
   * @param   mixed   required  HTML Id or node reference
   * @return  void
   */
  createDL : function(dl) {
    var i = 0;
    var end = dl.childNodes.length;
    var termCount = 0;
    var child;
    var currentClass = this.stripeRowEven;
    
    while (i &amp;lt; end) {
      child = dl.childNodes[i];
      if (child.nodeName == "DT") {
        currentClass = (termCount % 2 == 0) ? this.stripeRowEven : this.stripeRowOdd;
        termCount++;
        child.className = currentClass;
      } else if (child.nodeName == "DD") {
        child.className = currentClass;
      }
      i++;
    }
  },
  
  /**
   * @package stripes
   * @method  createList
   * @desc    Creates zebra stripes on &amp;lt;UL&amp;gt; and &amp;lt;OL&amp;gt; lists.
   * @param   mixed   required  HTML Id or node reference
   * @return  void
   */
  createList : function(list) {
    var i = 0;
    var itemCount = 0;
    var end = list.childNodes.length;
    
    while (i &amp;lt; end) {
      if (list.childNodes[i].nodeName == "LI") {
        list.childNodes[i].className = (itemCount % 2 == 0) ? this.stripeRowEven : this.stripeRowOdd;
        itemCount++;
      }
      i++;
    }
  },
  
  /**
   * @package stripes
   * @method  createTable
   * @desc    Creates zebra stripes on tables.
   * @param   mixed   required  HTML Id or node reference
   * @return  void
   */
  createTable : function(table) {
    var row = 0;
    var rowEnd = table.rows.length;
    var parentNodeName = ""
    
    while (row &amp;lt; rowEnd) {
      parentNodeName = table.rows[row].parentNode.nodeName;
      if (parentNodeName != "THEAD" &amp;amp;&amp;amp; parentNodeName != "TFOOT") {
        table.rows[row].className = (row % 2 == 0) ? this.stripeRowEven : this.stripeRowOdd;
      }
      row++;
    }
    table = null;
  },
  
  /**
   * @package stripes
   * @method  execute
   * @desc    Calls the create() function. Usefull of onload events.
   * @param   mixed   required  HTML Id or node reference to root element
   * @return  void
   */
  execute : function(root) {
    // Get root by Id
    if ( typeof(root) == "string" ) {
      root = document.getElementById(root);
    }
    
    // Default root is document element
    if ( !root || typeof(root) != "object" ) {
      root = document;
    }
    
    var nodeNames = ["table", "ul", "ol", "dl"];
    var name = 0;
    var nodeNamesEnd = nodeNames.length;
    var nodeList;
    var node = 0;
    var nodesEnd = 0;
    
    while (name &amp;lt; nodeNamesEnd) {
      nodeList = root.getElementsByTagName( nodeNames[name] );
      node = 0;
      nodeListEnd = nodeList.length;
      
      while (node &amp;lt; nodeListEnd) {
        if (nodeList[node].className &amp;amp;&amp;amp; nodeList[node].className == this.stripeParentClass) {
          this.create( nodeList[node] );
        }
        node++;
      }
      
      name++;
    }
    
    root = null;
    nodeList = null;
  }
  
};&lt;/textarea&gt;&lt;span class="corner corner-top"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="corner corner-bottom"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;&lt;h4 class="entry-subtitle2"&gt;Who can use this script&lt;/h4&gt;&lt;p&gt;The
short answer? Anyone. It's released under the LGPL license and is free
for commercial and non commercial use. Let's face it, this isn't ground
breaking stuff here, so copy it. Distribute it. Use it. But always
include some form of recognition and never claim it as your own. If you
feel so inclined, link back to this page.&amp;nbsp;If you have comments, suggestions or problems, post them below.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1829691255062570719-9022587959178216754?l=fundamentaldisaster.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fundamentaldisaster.blogspot.com/feeds/9022587959178216754/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1829691255062570719&amp;postID=9022587959178216754' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1829691255062570719/posts/default/9022587959178216754'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1829691255062570719/posts/default/9022587959178216754'/><link rel='alternate' type='text/html' href='http://fundamentaldisaster.blogspot.com/2008/10/javascript-zebra-stripes-alternate.html' title='JavaScript Zebra Stripes: Alternate Background Colors on Tables and Lists'/><author><name>Greg Burghardt</name><uri>http://www.blogger.com/profile/14825576215668294298</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1829691255062570719.post-7070747152112383696</id><published>2007-11-30T07:33:00.000-08:00</published><updated>2008-02-06T09:31:09.257-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='code examples'/><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='strings'/><category scheme='http://www.blogger.com/atom/ns#' term='numbers'/><category scheme='http://www.blogger.com/atom/ns#' term='web standards'/><title type='text'>A Practical Guide To Numbers in JavaScript</title><content type='html'>&lt;h3 class="post-subtitle"&gt;
                        Dealing with numbers, strings and JavaScript can be frustrating for a beginner. This is a down-and-dirty explanation of converting strings to numbers, detecting if a string is a number, and handy functions for manipulating numbers.
                      &lt;/h3&gt;
                      &lt;p&gt;
                        How many times have you gotten a number from a FORM field on your web page, tried to add it to a number only to get the wrong value back!? One of the most basic tasks of any program is converting between different data types. JavaScript is pretty flexible, but there are still some rules.
                      &lt;/p&gt;
                      &lt;p&gt;
                        In most programming languages, a number is a primitive data type, meaning it's just a value stored in memory. In JavaScript, a number is both a primitive data type and a whole class of data and functions. Whether or not a primitive number or object-oriented number is used depends on how you are using it. A few quick examples are in order.
                      &lt;/p&gt;
                      &lt;h4 class="code-label"&gt;
                        Creating Number Variables in JavaScript
                      &lt;/h4&gt;
&lt;pre class="code-block"&gt;var num1 = new Number("4");
var num2 = 4;&lt;/pre&gt;
                      &lt;p&gt;
                        There are two basic ways of declaring number variables in JavaScript: By calling the &lt;code&gt;Number&lt;/code&gt; class constructor directly using the &lt;code&gt;new&lt;/code&gt; command, and by simply assigning a number to a variable. The most effecient method is by simply assigning a number to a variable, as this creates a primitive value number. The &lt;code&gt;new Number()&lt;/code&gt; method creates an instance of the &lt;code&gt;Number&lt;/code&gt; class and adds functions and properties to the number variable. The browser will try converting any data passed to the &lt;code&gt;Number()&lt;/code&gt; function into a number, and if you're not carefull you'll get a &lt;code&gt;NaN&lt;/code&gt; value, which means the value is &lt;strong&gt;N&lt;/strong&gt;ot &lt;strong&gt;A&lt;/strong&gt; &lt;strong&gt;N&lt;/strong&gt;umber.
                      &lt;/p&gt;
                      &lt;p&gt;
                        Once you have a number variable declared, you'll want to do some math. JavaScript gives us the basic mathematical operators, like +, -, * and / for add, subtract, multiply and divide. Below is a list of some of the mathematical operators in JavaScript:
                      &lt;/p&gt;
                      &lt;table class="dataTable" border="0" cellpadding="2" cellspacing="2"&gt;
                        &lt;caption&gt;
                          Common JavaScript Mathematical Operators
                        &lt;/caption&gt;
                        &lt;thead&gt;
                          &lt;tr&gt;
                            &lt;th&gt;
                              Operator
                            &lt;/th&gt;
                            &lt;th&gt;
                              Name
                            &lt;/th&gt;
                            &lt;th&gt;
                              Description
                            &lt;/th&gt;
                          &lt;/tr&gt;
                        &lt;/thead&gt;
                        &lt;tbody&gt;
                          &lt;tr&gt;
                            &lt;td&gt;
                              &lt;code&gt;+&lt;/code&gt;
                            &lt;/td&gt;
                            &lt;td&gt;
                              Addition
                            &lt;/td&gt;
                            &lt;td&gt;
                              The sum of two numbers.
                            &lt;/td&gt;
                          &lt;/tr&gt;
                          &lt;tr&gt;
                            &lt;td&gt;
                              ++
                            &lt;/td&gt;
                            &lt;td&gt;
                              Increment
                            &lt;/td&gt;
                            &lt;td&gt;
                              Increase the number by 1: &lt;code&gt;num1++;&lt;/code&gt;
                            &lt;/td&gt;
                          &lt;/tr&gt;
                          &lt;tr&gt;
                            &lt;td&gt;
                              &lt;code&gt;+=&lt;/code&gt;
                            &lt;/td&gt;
                            &lt;td&gt;
                              Add-to
                            &lt;/td&gt;
                            &lt;td&gt;
                              Add a number to the current value: &lt;code&gt;num += 2;&lt;/code&gt;
                            &lt;/td&gt;
                          &lt;/tr&gt;
                          &lt;tr&gt;
                            &lt;td&gt;
                              &lt;code&gt;-&lt;/code&gt;
                            &lt;/td&gt;
                            &lt;td&gt;
                              Subtraction
                            &lt;/td&gt;
                            &lt;td&gt;
                              The difference between two numbers.
                            &lt;/td&gt;
                          &lt;/tr&gt;
                          &lt;tr&gt;
                            &lt;td&gt;
                              &lt;code&gt;--&lt;/code&gt;
                            &lt;/td&gt;
                            &lt;td&gt;
                              Decrement
                            &lt;/td&gt;
                            &lt;td&gt;
                              Decrease the number by 1: &lt;code&gt;num1--;&lt;/code&gt;
                            &lt;/td&gt;
                          &lt;/tr&gt;
                          &lt;tr&gt;
                            &lt;td&gt;
                              &lt;code&gt;-=&lt;/code&gt;
                            &lt;/td&gt;
                            &lt;td&gt;
                              Subtract-from
                            &lt;/td&gt;
                            &lt;td&gt;
                              Subtract from the current value: &lt;code&gt;num1 -= 2;&lt;/code&gt;
                            &lt;/td&gt;
                          &lt;/tr&gt;
                          &lt;tr&gt;
                            &lt;td&gt;
                              &lt;code&gt;*&lt;/code&gt;
                            &lt;/td&gt;
                            &lt;td&gt;
                              Multiplication
                            &lt;/td&gt;
                            &lt;td&gt;
                              The multiplication of two numbers
                            &lt;/td&gt;
                          &lt;/tr&gt;
                          &lt;tr&gt;
                            &lt;td&gt;
                              &lt;code&gt;/&lt;/code&gt;
                            &lt;/td&gt;
                            &lt;td&gt;
                              Division
                            &lt;/td&gt;
                            &lt;td&gt;
                              Division of two numbers
                            &lt;/td&gt;
                          &lt;/tr&gt;
                          &lt;tr&gt;
                            &lt;td&gt;
                              &lt;code&gt;%&lt;/code&gt;
                            &lt;/td&gt;
                            &lt;td&gt;
                              Modulus
                            &lt;/td&gt;
                            &lt;td&gt;
                              Returns the remainder of the division of two numbers
                            &lt;/td&gt;
                          &lt;/tr&gt;
                        &lt;/tbody&gt;
                      &lt;/table&gt;
                      &lt;p&gt;
                        All the operators work as expected except for the addition operator. In JavaScript, the &lt;code&gt;+&lt;/code&gt; operator returns the sum of two numbers, or joins two strings together. The following code example illustrates when the browser knows whether to join a string or perform a mathematical operation:
                      &lt;/p&gt;
                      &lt;h4 class="code-label"&gt;
                        Using &lt;code&gt;+&lt;/code&gt; to join two strings, or add two numbers
                      &lt;/h4&gt;
&lt;pre class="code-block"&gt;var sum1 = 5 + 2;
var sum2 = 5 + "2";

alert(sum1); // Shows the number 7
alert(sum2); // Shows the string "52"&lt;/pre&gt;
                      &lt;p&gt;
                        When you add a string to a number, the browser automatically converts the number to a string, and then joins the two strings. The operation &lt;code&gt;5 + "2"&lt;/code&gt; is interpretted by the browser as &lt;code&gt;"5" + "2"&lt;/code&gt;, joining the two strings together and converting the end result into a string. This is an easy way to convert a number to a string, but is little help for converting a string to a number.
                      &lt;/p&gt;
                      &lt;p&gt;
                        In most programming languages, you have two basic types of numbers: Integers, which represent whole numbers like 1, 8 or -3; and floating point numbers like 33.8 and -6.5. JavaScript uses floating point numbers with up to 16 decimal places.
                      &lt;/p&gt;
                      &lt;p&gt;
                        While the addition operator adds two numbers or joins two strings, the subtraction operator only subtracts two numbers. The browser also makes your life easier by automatically converting data types:
                      &lt;/p&gt;
&lt;pre class="code-block"&gt;var diff1 = 5 - 2;
var diff2 = "5" - 2;

alert(diff1) // Shows the number 3
alert(diff2) // Shows the number 3&lt;/pre&gt;
                      &lt;p&gt;
                        When you try subtracting a number from a string, the browser automatically converts the string to a number, and then performs the mathematical operation.We've seen how mathematical operators can convert between strings and numbers, but you aren't limited to those methods. There are many more which can be used for different reasons.
                      &lt;/p&gt;
                      &lt;h4 class="entry-subtitle2"&gt;
                        Converting Strings to Numbers
                      &lt;/h4&gt;
                      &lt;p&gt;
                        There are four main ways to convert a string to a number: The &lt;code&gt;parseFloat&lt;/code&gt;, &lt;code&gt;parseInt&lt;/code&gt; and &lt;code&gt;Number&lt;/code&gt; functions, and subtracting a number from a string. First, let's revisit the &lt;code&gt;Number()&lt;/code&gt; function.
                      &lt;/p&gt;
                      &lt;p&gt;
                        Earlier we learned &lt;strong&gt;the &lt;code&gt;Number()&lt;/code&gt; function takes a value and converts it to a number, and is also the class constructor used for all number variables in JavaScript.&lt;/strong&gt; It seems like the obvious choice, but let's take a closer look.
                      &lt;/p&gt;
&lt;pre class="code-block"&gt;var num1 = Number("2.25");
var num2 = Number("Price: $2.25");
var num3 = Number("three");
var num4 = Number("200.8 dollars");

alert(num1); // Shows the number 2.25
alert(num2); // Shows NaN (Not A Number)
alert(num3); // Shows NaN
alert(num4); // Shows NaN&lt;/pre&gt;
                      &lt;p&gt;
                        Right away we can see a problem. The &lt;code&gt;Number()&lt;/code&gt; function successfully converts a string to a number only as long as the string only contains numeric characters (those being 0 through 9, the decimal point or period, and the negative sign or minus). If there are any other characters, the &lt;code&gt;Number&lt;/code&gt; function returns a &lt;code&gt;NaN&lt;/code&gt; value, which literally means "Not A Number." If we have full control of what gets put in a string variable, the &lt;code&gt;Number()&lt;/code&gt; function may be the right choice, but if you are taking input from the user, we may get non-numeric characters. We need a way to remove non-numeric characters from a string, then convert them to a number.
                      &lt;/p&gt;
                      &lt;h5 class="entry-subtitle2"&gt;
                        Cleaning and converting strings to numbers using the &lt;code&gt;parseFloat()&lt;/code&gt; and &lt;code&gt;parseInt()&lt;/code&gt; functions
                      &lt;/h5&gt;
                      &lt;p&gt;
                        JavaScript gives us two built in functions that help remove non-numeric characters from a string. The &lt;code&gt;parseFloat&lt;/code&gt; function returns a floating point number, or decimal number, and the &lt;code&gt;parseInt&lt;/code&gt; function returns an integer number. Later on we'll see why special care must be taken with the &lt;code&gt;parseInt&lt;/code&gt; function.
                      &lt;/p&gt;
                      &lt;h6 class="code-label"&gt;
                        Using parseFloat
                      &lt;/h6&gt;
&lt;pre class="code-block"&gt;var num1 = parseFloat("2.25");
var num2 = parseFloat("Price: $2.25");
var num3 = parseFloat("three");
var num4 = parseFloat("200.8 million dollars");

alert(num1); // Shows the number 2.25
alert(num2); // Shows NaN (Not A Number)
alert(num3); // Shows NaN (Not A Number)
alert(num4); // Shows the number 200.8&lt;/pre&gt;
                      &lt;p&gt;
                        We run into a similar problem with &lt;code&gt;parseFloat&lt;/code&gt; that we have with the &lt;code&gt;Number&lt;/code&gt; function. If the string contains non-numeric characters before the numeric characters, a &lt;code&gt;NaN&lt;/code&gt; value is returned. It does, however, remove non-numeric characters &lt;em&gt;after&lt;/em&gt; the numeric characters, and returns a floating point number. Likewise, if only numeric characters are in the string, a floating point number is returned. Lastly, if no numeric characters exist in the string, a &lt;code&gt;NaN&lt;/code&gt; value is returned.
                      &lt;/p&gt;
                      &lt;h6 class="code-label"&gt;
                        Using parseInt
                      &lt;/h6&gt;
&lt;pre class="code-block"&gt;var num1 = parseInt("2.25");
var num2 = parseInt("Price: $2.25");
var num3 = parseInt("three");
var num4 = parseInt("200.8 million dollars");
var num5 = parseInt("0x10");

alert(num1); // Shows the number 2
alert(num2); // Shows NaN (Not A Number)
alert(num3); // Shows NaN (Not A Number)
alert(num4); // Shows the number 200
alert(num5); // Shows the number 16&lt;/pre&gt;
                      &lt;p&gt;
                        The &lt;code&gt;parseInt&lt;/code&gt; function works exactly the same as the &lt;code&gt;parseFloat&lt;/code&gt; function, with two notable differences: It returns a number rounded down to the next integer, and it doesn't &lt;em&gt;always&lt;/em&gt; return &lt;code&gt;NaN&lt;/code&gt; when you give it non-numeric characters. In fact, it appears quite confusing. Giving &lt;code&gt;parseInt&lt;/code&gt; the string "0x10" returns the number 16 ... um ... what? Sixteen? Giving it the characters zero-x-one-zero is equal to the number 16? Yes. The &lt;code&gt;parseInt&lt;/code&gt; function takes up to two parameters: The string to convert to a number, &lt;strong&gt;and an optional second parameter specifying the number system the string should be interpretted as, called the radix&lt;/strong&gt;. When using &lt;code&gt;parseInt&lt;/code&gt;, always pass 10 as the second parameter, meaning the &lt;code&gt;parseInt&lt;/code&gt; function should interpret the string as a base 10 number. A base 10 number uses the numerals 0 through 9, and every tenth value is put at a new decimal spot. We
                        don't have a number to represent the number ten, instead we use 10: We have one group of ten, and zero groups of one.
                      &lt;/p&gt;
                      &lt;p&gt;
                        When the string passed to the &lt;code&gt;parseInt&lt;/code&gt; function begins with "0x" and no second parameter is given, the &lt;code&gt;parseInt&lt;/code&gt; function treats the string like a base 16, or hexadecimal number. The hexadecimal number 10 is equal to the decimal number 16. In hex, you have one group of 16, and zero groups of 1. The equivalent number in the decimal or base 10 system is 16: one group of ten, and 6 groups of one.
                      &lt;/p&gt;
                      &lt;h6 class="code-label"&gt;
                        The proper way to use parseInt
                      &lt;/h6&gt;
&lt;pre class="code-block"&gt;var num1 = parseInt("2.25", 10);
var num4 = parseInt("0x10", 10);

alert(num1); // Shows the number 2
alert(num2); // Shows NaN (Not A Number)&lt;/pre&gt;
                      &lt;p&gt;
                        In the example above, the &lt;code&gt;parseInt&lt;/code&gt; function is told that the string should be treated as a base 10 number, and thus "0x10" is Not A Number (&lt;code&gt;NaN&lt;/code&gt;). Since humans use the decimal system when counting, you should always pass 10 as the second parameter to the &lt;code&gt;parseInt&lt;/code&gt; function. If 10 is not passed as the second parameter and a user accidentally types in 0x15 instead of 0.15, you would get 21 instead of the number zero, and your calculations will be incorrect.
                      &lt;/p&gt;
                      &lt;table class="dataTable" border="0" cellpadding="0" cellspacing="0"&gt;
                        &lt;caption&gt;
                          Number, parseFloat and parseInt Summary
                        &lt;/caption&gt;
                        &lt;thead&gt;
                          &lt;tr&gt;
                            &lt;th&gt;
                              Function
                            &lt;/th&gt;
                            &lt;th&gt;
                              Parameters
                            &lt;/th&gt;
                            &lt;th&gt;
                              Return Value
                            &lt;/th&gt;
                          &lt;/tr&gt;
                        &lt;/thead&gt;
                        &lt;tbody&gt;
                          &lt;tr&gt;
                            &lt;td&gt;
                              Number
                            &lt;/td&gt;
                            &lt;td&gt;
                              String[required]
                            &lt;/td&gt;
                            &lt;td&gt;
                              Number or NaN if the string contains non-numeric characters.
                            &lt;/td&gt;
                          &lt;/tr&gt;
                          &lt;tr&gt;
                            &lt;td&gt;
                              parseFloat
                            &lt;/td&gt;
                            &lt;td&gt;
                              String[required]
                            &lt;/td&gt;
                            &lt;td&gt;
                              Number or NaN if the string contains non-numeric characters.
                            &lt;/td&gt;
                          &lt;/tr&gt;
                          &lt;tr&gt;
                            &lt;td&gt;
                              parseInt
                            &lt;/td&gt;
                            &lt;td&gt;
                              String[required], Number[optional]
                            &lt;/td&gt;
                            &lt;td&gt;
                              The first parameter is a string, and the second parameter is a number. The second parameter is optional, and is the number system the string should be interpretted as. Use 10 unless you want a different number system. An integer rounded down to the nearest number is returned, or NaN if any non-numeric characters are found.
                            &lt;/td&gt;
                          &lt;/tr&gt;
                        &lt;/tbody&gt;
                      &lt;/table&gt;
                      &lt;h5 class="entry-subtitle2"&gt;
                        toNumber(): Clean strings and convert them to numbers
                      &lt;/h5&gt;
                      &lt;p&gt;
                        The &lt;code&gt;parseFloat&lt;/code&gt; and &lt;code&gt;parseInt&lt;/code&gt; functions still don't allow us to remove all non numeric characters. Unfortunately, JavaScript doesn't have a function for this, so we'll build one. You can probably search the Internet for something similar, and many times it is named toNumeric or toNumber.
                      &lt;/p&gt;
                      &lt;h6 class="code-label"&gt;
                        Function definition for toNumber
                      &lt;/h6&gt;
                      &lt;div class="expando expando-quarter"&gt;
&lt;pre class="code-block"&gt;/**
 * toNumber  Converts a string to a number
 *
 * @param   string (required)   String to convert to a number
 * @param   bool   (optional)   Make it an integer and drop decimal
 * @param   bool   (optional)   Round number up or down to nearest int?
 * @return  float, int or NaN   Number, or null if string not a number
 */
function toNumber(str, isInteger, roundNum) {
  var num;
  var strType = typeof(str);
  
  if (strType == "string") {
    // Strip non-numeric chars and convert to number
    num = Number(str.replace(/[^0-9-.]/g, ""));
  } else if (strType != "number") {
    // Return NaN if not a number
    return NaN;
  }
  
  if (isNaN(num)) {
    return NaN;
  } else if (isInteger) {
    return Math.floor(num);
  } else if (roundNum) {
    return Math.round(num);
  } else {
    return num;
  }
  
}&lt;/pre&gt;
                        &lt;span class="corner corner-top"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
                        &lt;span class="corner corner-bottom"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
                      &lt;/div&gt;
                      &lt;p&gt;
                        The &lt;code&gt;toNumber&lt;/code&gt; function removes non-numeric characters from a string, and also allows you to specify whether or not the number is a floating point number or integer, and if it should be rounded to the nearest integer instead of dropping the decimal all together. If the string passed to the &lt;code&gt;toNumber&lt;/code&gt; function contains no numeric characters, a null value is returned. Let's see how we can use this function:
                      &lt;/p&gt;
                      
                      &lt;h6 class="code-label"&gt;
                        How the toNumber function reacts to various input
                      &lt;/h6&gt;
&lt;pre class="code-block"&gt;var num1 = toNumber("2.25");
var num2 = toNumber("Price: $2.25");
var num3 = toNumber("200.8 million dollars");
var num4 = toNumber("103.8", true);
var num5 = toNumber("103.8", true, true);
var num6 = toNumber("no numbers here");

alert(num1); // Shows the number 2.25
alert(num2); // Shows the number 2.25
alert(num3); // Shows the number 200.8
alert(num4); // Shows the number 103
alert(num5); // Shows the number 104
alert(num6); // Shows null&lt;/pre&gt;
                      &lt;p&gt;
                        As mention earlier, users can type whatever they want into form fields, so you must clean the data before you can do any math with it. The &lt;code&gt;toNumber&lt;/code&gt; function does several things:
                      &lt;/p&gt;
                      &lt;ol class="paragraph"&gt;
                        &lt;li&gt;
                          If a number variable is given, the number is returned as a floating point, integer or rounded floating point number.
                        &lt;/li&gt;
                        &lt;li&gt;
                          Removes all non-numeric characters from the string, both before and after the number characters.
                        &lt;/li&gt;
                        &lt;li&gt;
                          You can specify if the number is an integer, and also if it should be rounded up or down to the nearest integer
                        &lt;/li&gt;
                        &lt;li&gt;
                          If the string variable given does not contain numeric characters, a NaN value is returned. You can outright test for a NaN value if you want to tell the user to enter a number.
                        &lt;/li&gt;
                      &lt;/ol&gt;
                      &lt;p&gt;
                        Let's create a sample script that shows how to use this function.
                      &lt;/p&gt;
                      &lt;h5 class="entry-subtitle2"&gt;
                        Using toNumber to check for user errors
                      &lt;/h5&gt;
&lt;pre class="code-block"&gt;// Ask the user to enter a number
var userNum = prompt("Type a number:");

// Convert what the user typed into a number
var num = &lt;strong&gt;toNumber(userNum)&lt;/strong&gt;;

if (isNaN(num)) {
  // Error: User typed no numeric characters
  alert("Only numeric characters are allowed");
} else {
  // User typed at least one number, now show the sum
  num = num + 8;
  alert("The sum is " + num);
}&lt;/pre&gt;
                      &lt;p&gt;
                        This shows the basic process for taking data from the user, cleaning it, and detecting possible errors.
                      &lt;/p&gt;
                      &lt;ol class="paragraph"&gt;
                        &lt;li&gt;
                          The variable &lt;code&gt;userNum&lt;/code&gt; is gotten from the user by way of the &lt;code&gt;prompt&lt;/code&gt; function. The &lt;code&gt;prompt&lt;/code&gt; function returns a string of what the user typed into the &lt;code&gt;prompt&lt;/code&gt; pop up box.
                        &lt;/li&gt;
                        &lt;li&gt;
                          We pass the &lt;code&gt;userNum&lt;/code&gt; variable to the &lt;code&gt;toNumber&lt;/code&gt; function.
                        &lt;/li&gt;
                        &lt;li&gt;
                          The &lt;code&gt;toNumber&lt;/code&gt; function returns a value, and is assigned to the &lt;code&gt;num&lt;/code&gt; variable.
                        &lt;/li&gt;
                        &lt;li&gt;
                          If the &lt;code&gt;num&lt;/code&gt; variable is equal to null, then the user didn't type in any numeric characters. Show an error message.
                        &lt;/li&gt;
                        &lt;li&gt;
                          Otherwise, the &lt;code&gt;num&lt;/code&gt; variable is a number, and we can show the sum.
                        &lt;/li&gt;
                      &lt;/ol&gt;
                      
                      &lt;h6 class="entry-subtitle2"&gt;
                        Drawbacks to the toNumber() function
                      &lt;/h6&gt;
                      
                      &lt;p&gt;At first this function seems like a great idea &amp;#8212; remove all non-numeric characters from the string, and then convert it to a number. What if the user accidentally types "5/8" when they meant to type in "5.8"? The &lt;code&gt;toNumber&lt;/code&gt; function would return the number 58, which is vastly larger than the 5.8 the user intended on entering. It's up to you as the programmer to decide if this fault tolerance is acceptable in your script. While posting on WebDeveloper forums, I got involved in a discussion about &lt;a href="http://www.webdeveloper.com/forum/showthread.php?t=171066" target="_blank"&gt;converting strings to numbers&lt;/a&gt;. In order to reduce the impact of user errors on your script, the following basic algorithm is recommended when converting strings to numbers:&lt;/p&gt;
                      
                      &lt;ol&gt;
                        &lt;li&gt;Convert the string to a number first. Use the &lt;code&gt;Number()&lt;/code&gt; function.&lt;/li&gt;
                        &lt;li&gt;Test the converted number to ensure it is actually a number using the &lt;code&gt;isNaN()&lt;/code&gt; function.&lt;/li&gt;
                        &lt;li&gt;If the number is Not A Number, alert the user to his or her error and stop processing.&lt;/li&gt;
                        &lt;li&gt;If the number is a number, then continue processing.&lt;/li&gt;
                      &lt;/ol&gt;
                      
                      &lt;h5 class="entry-subtitle2"&gt;
                        Using isNaN() to detect non-numbers
                      &lt;/h5&gt;
                      &lt;p&gt;
                        The function definition for &lt;code&gt;toNumber&lt;/code&gt; introduced us to a new number-related function: &lt;code&gt;isNaN&lt;/code&gt;. The &lt;code&gt;isNaN&lt;/code&gt; function stands for "IS Not A Number" and is a native function to JavaScript. It takes a string or number as a parameter and will return true if any non-numeric characters are found in the case of a string, or if the number passed is a &lt;code&gt;NaN&lt;/code&gt; value. In addition, if you were to use the &lt;code&gt;Number&lt;/code&gt;, &lt;code&gt;parseFloat&lt;/code&gt; or &lt;code&gt;parseInt&lt;/code&gt; functions to convert a string to a number, and a &lt;code&gt;NaN&lt;/code&gt; value is returned by any of those functions, &lt;code&gt;isNaN&lt;/code&gt; will return true.
                      &lt;/p&gt;
                      &lt;p&gt;
                        The &lt;code&gt;isNaN&lt;/code&gt; function is complimentary to &lt;code&gt;parseFloat&lt;/code&gt; and &lt;code&gt;parseInt&lt;/code&gt;, and is a direct compliment to &lt;code&gt;Number&lt;/code&gt;. When the &lt;code&gt;Number&lt;/code&gt; function returns an actual number, the &lt;code&gt;isNaN&lt;/code&gt; function returns false. When the &lt;code&gt;Number&lt;/code&gt; function returns a &lt;code&gt;NaN&lt;/code&gt; value, the &lt;code&gt;isNaN&lt;/code&gt; function returns true. Be aware that there are times when a string passed to &lt;code&gt;isNaN&lt;/code&gt; will return true, meaning the string is not a number, when that same string passed to either &lt;code&gt;parseFloat&lt;/code&gt; or &lt;code&gt;parseInt&lt;/code&gt; will return a number. &lt;strong&gt;Always convert strings to numbers first, then test using &lt;code&gt;isNaN&lt;/code&gt;.&lt;/strong&gt;
                      &lt;/p&gt;
                      &lt;h6 class="code-label"&gt;
                        How isNaN reacts to various input
                      &lt;/h6&gt;
&lt;pre class="code-block"&gt;var num1 = isNaN("2.25");
var num2 = isNaN("Price: $2.25");
var num3 = isNaN("three");
var num4 = isNaN("200.8 million dollars");
var num5 = &lt;strong&gt;parseFloat("no numbers")&lt;/strong&gt;; // Returns NaN value

alert(num1); // Shows false
alert(num2); // Shows true
alert(num3); // Shows true
alert(num4); // Shows true
alert(&lt;strong&gt;isNaN(num5)&lt;/strong&gt;); // Shows true&lt;/pre&gt;
                      &lt;p&gt;
                        If you don't want to use the &lt;code&gt;toNumber&lt;/code&gt; function above, use the &lt;code&gt;Number&lt;/code&gt; function to convert a string to a number, then use the &lt;code&gt;isNaN&lt;/code&gt; function to check for a &lt;code&gt;NaN&lt;/code&gt; value.
                      &lt;/p&gt;
                      &lt;h6 class="code-label"&gt;
                        Using isNaN to check for user errors
                      &lt;/h6&gt;
&lt;pre class="code-block"&gt;var userNum = prompt("Enter a number:");
var num = Number(userNum);

if (&lt;strong&gt;isNaN(num)&lt;/strong&gt;) {
  alert("Only enter numeric characters.");
} else {
  num = num + 8;
  alert("The sum is " + num);
}&lt;/pre&gt;
                      &lt;p&gt;
                        We've learned several ways to convert strings to numbers and account for user errors. We know that &lt;code&gt;parseFloat&lt;/code&gt; gives us a floating point number, and &lt;code&gt;parseInt&lt;/code&gt; gives us an integer, but &lt;code&gt;parseInt&lt;/code&gt; drops the decimal all together. The number 8.9 becomes 8, when it should be 9 when rounded to an integer. We need a way to create a rounded integer, and the &lt;code&gt;Math&lt;/code&gt; object provides us with a &lt;code&gt;round&lt;/code&gt; function.
                      &lt;/p&gt;
                      &lt;h5 class="entry-subtitle2"&gt;
                        Rounding numbers properly using Math.round
                      &lt;/h5&gt;
                      &lt;p&gt;
                        Any floating point number whose decimal is less than .5 must be rounded down. If the decimal is .5 or greater, the number should be rounded up. This was something we learned in grade school, but the &lt;code&gt;parseInt&lt;/code&gt; function failed that class. It just drops the decimal place all together. Let's use &lt;code&gt;Math.round&lt;/code&gt; instead.
                      &lt;/p&gt;
&lt;pre class="code-block"&gt;var num1 = Math.round(3.75);
var num2 = Math.round(3.33);

alert(num1); // Shows the number 4
alert(num2); // Shows the number 3&lt;/pre&gt;
                      &lt;p&gt;
                        Since the decimal in 3.75 is greater-than or equal-to .5, the &lt;code&gt;Math.round&lt;/code&gt; function returns the integer number 4. The number 3.33 has a decimal less than .5, so the &lt;code&gt;Math.round&lt;/code&gt; function returns the integer number 3. &lt;code&gt;Math.round&lt;/code&gt; only returns integers, however. If you want to round a number to a certain decimal place, we've got to use a native function to all &lt;code&gt;Number&lt;/code&gt; variables in JavaScript, which we will use in our next example.
                      &lt;/p&gt;
                      &lt;h5 class="entry-subtitle2"&gt;
                        A simple form to calculate the tax
                      &lt;/h5&gt;
                      &lt;p&gt;
                        We've explored several methods of converting strings to numbers, and dealing with invalid data. Now let's create a practical example using the methods outlined above, and introduce one more method for formatting the display of numbers. First, let's create our HTML form:
                      &lt;/p&gt;
                      &lt;h6 class="code-label"&gt;
                        Markup for our tax form
                      &lt;/h6&gt;
&lt;pre class="code-block"&gt;&amp;lt;form method="get" action="" id="frmTax"&amp;gt;
  Price: &amp;lt;input type="text" name="price" value=""&amp;gt;
  &amp;lt;br&amp;gt;
  Tax Rate: &amp;lt;input type="text" name="taxRate" value="0.06"&amp;gt;
  &amp;lt;br&amp;gt;
  &amp;lt;input type="button" value="Calculate Tax"
      onclick="calcTax(this.form)"&amp;gt;
&amp;lt;/form&amp;gt;&lt;/pre&gt;
                      &lt;p&gt;
                        It's a pretty simple form. Before some of you scream, "It's not accessible! Burn in Hell!" know that this is just a simple example. Web accessibility is beyond the scope of this tutorial. We've got two text fields: One for the price, and another for the tax rate. Lastly, we have a button that calls the calcTax function onclick, and passes a Document Object Model node reference to the FORM tag.
                      &lt;/p&gt;
                      &lt;h6 class="code-label"&gt;
                        Example 1: Function definition for calcTax, using toNumber()
                      &lt;/h6&gt;
&lt;pre class="code-block"&gt;function calcTax(form) {
  var price = &lt;strong&gt;toNumber(form.elements["price"].value)&lt;/strong&gt;;
  var taxRate = &lt;strong&gt;toNumber(form.elements["taxRate"].value)&lt;/strong&gt;;
  var total = 0;
 
  if (&lt;strong&gt;isNaN(price)&lt;/strong&gt;) {
    alert("Only enter numeric characters for the price");
    return;
  } else if (&lt;strong&gt;isNaN(taxRate)&lt;/strong&gt;) {
    alert("Only enter numeric characters for the tax rate");
    return;
  } else {
    total = price + (price * taxRate);
    alert("The total price is: $" + &lt;strong&gt;total.toFixed(2)&lt;/strong&gt;);
  }
}&lt;/pre&gt;
                      &lt;h6 class="code-label"&gt;
                        Example 2: Function definition for calcTax, using native functions
                      &lt;/h6&gt;
&lt;pre class="code-block"&gt;function calcTax(form) {
  var price = &lt;strong&gt;Number(form.elements["price"].value)&lt;/strong&gt;;
  var taxRate = &lt;strong&gt;Number(form.elements["taxRate"].value)&lt;/strong&gt;;
  var total = 0;
 
  if (&lt;strong&gt;isNaN(price)&lt;/strong&gt;) {
    alert("Only enter numeric characters for the price");
    return;
  } else if (&lt;strong&gt;isNaN(taxRate)&lt;/strong&gt;) {
    alert("Only enter numeric characters for the tax rate");
    return;
  } else {
    total = price + (price * taxRate);
    alert("The total price is: $" + &lt;strong&gt;total.toFixed(2)&lt;/strong&gt;);
  }
}&lt;/pre&gt;
                      &lt;p&gt;
                        Now is a good time to note that &lt;strong&gt;the values of form fields are always strings&lt;/strong&gt;. A user might type a number into a text field, but JavaScript still sees it as a string, which is where the &lt;code&gt;toNumber&lt;/code&gt;, &lt;code&gt;isNaN&lt;/code&gt;, &lt;code&gt;Number&lt;/code&gt;, &lt;code&gt;parseFloat&lt;/code&gt; and &lt;code&gt;parseInt&lt;/code&gt; functions come into play. A closer look at both examples shows few differences in how they are written. The main difference is the level of tolerance for user generated errors. In Example 1, the &lt;code&gt;toNumber&lt;/code&gt; function is used. This function removes all non-numeric characters from the string. If a user accidentally types a non numeric character before any numeric characters in one of the text boxes, the &lt;code&gt;toNumber&lt;/code&gt; function is able to recover from that and still return a number.
                      &lt;/p&gt;
                      &lt;p&gt;
                        In Example 2, if the user enters even one non-numeric character before a numeric character in one of the text fields, the &lt;code&gt;calcTax&lt;/code&gt; function will alert the user of an error. In each example, the line of code with the &lt;code&gt;alert()&lt;/code&gt; function call contains another golden nugget for working with numbers: the &lt;code&gt;toFixed&lt;/code&gt; method of all &lt;code&gt;Number&lt;/code&gt; variables.
                      &lt;/p&gt;
                      &lt;h6 class="entry-subtitle2"&gt;
                        Using the toFixed method to format numbers
                      &lt;/h6&gt;
                      &lt;p&gt;
                        This function is available for any &lt;code&gt;Number&lt;/code&gt; variable in JavaScript, and allows you to specify how many decimal places you want to show. This function returns a string, and so most times is only usefull for displaying output to a user. It takes one parameter, an integer number of how many decimal places should be displayed.
                      &lt;/p&gt;
&lt;pre class="code-block"&gt;var num = 8.75249;

alert(num.toFixed(0)); // Shows the string 9
alert(num.toFixed(1)); // Shows the string 8.8
alert(num.toFixed(2)); // Shows the string 8.75
alert(num.toFixed(3)); // Shows the string 8.752
alert(num.toFixed(4)); // Shows the string 8.7525&lt;/pre&gt;
                      &lt;p&gt;
                        The &lt;code&gt;toFixed&lt;/code&gt; function works similar to the &lt;code&gt;Math.round&lt;/code&gt; function. In the first example, passing zero to &lt;code&gt;toFixed&lt;/code&gt; returns 9, which is the same number that &lt;code&gt;Math.round&lt;/code&gt; would return. The difference here is anything the &lt;code&gt;toFixed&lt;/code&gt; function returns is a string, not a number.
                      &lt;/p&gt;
                      &lt;p&gt;
                        In the second example, the number 1 is passed, so only one decimal place is shown. The decimal place just after .7, is .05. This .05 is rounded up to .1, and added to .7 to give a final string of "8.8". There may be a time, however, when you need to round a number to a certain number of decimal places and still have it be a number.
                      &lt;/p&gt;
                      &lt;h5 class="entry-subtitle2"&gt;
                        The round() function
                      &lt;/h5&gt;
                      &lt;p&gt;
                        There is no native &lt;code&gt;round&lt;/code&gt; function in JavaScript that takes a number, rounds it to a certain number of decimal places, then returns a number. We'll call this function &lt;code&gt;round()&lt;/code&gt;.
                      &lt;/p&gt;
                      &lt;h6 class="code-label"&gt;
                        Function definition for round()
                      &lt;/h6&gt;
                      &lt;div class="expando expando-quarter"&gt;
&lt;pre class="code-block"&gt;/**
 * round    Rounds a number to X decimal places
 * @param   number (req)      Number to round. May also be string
 * @param   int (opt)         Number of decimal places. Optional.
 * @return  mixed             Null if NaN, or the rounded number
 */
function round(num, decimals) {
  var multiplier = Math.pow(10, decimals);
  if (typeof(num) != "number") {
    return null;
  }
  if (typeof(decimals) != "number") {
    var decimals = -1;
  }
  if (decimals &amp;gt; 0) {
    return Math.round(num * multiplier) / multiplier;
  } else if (decimals == 0) {
    return Math.round(num);
  } else {
    return num;
  }
}&lt;/pre&gt;
                        &lt;span class="corner corner-top"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
                        &lt;span class="corner corner-bottom"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
                      &lt;/div&gt;
                      &lt;p&gt;
                        The &lt;code&gt;round()&lt;/code&gt; function takes up to two parameters. The first is the number that should be rounded. The optional second parameter is the number of decimal places that should be rounded to. If this second parameter is omitted, the full floating point number is returned. If zero is passed as the second parameter, then the number is rounded up or down properly to an integer. If the second parameter is 1 or more, then the number is rounded to that many decimal places. The function returns an actual number, but if you give the &lt;code&gt;round()&lt;/code&gt; function invalid data, null is returned.
                      &lt;/p&gt;
                      &lt;h5 class="entry-subtitle2"&gt;
                        Problems with round()
                      &lt;/h5&gt;
                      &lt;p&gt;
                        Normally you should only round a number to a decimal place when ouputing the number to the user. The function you'd want to use is the &lt;code&gt;toFixed&lt;/code&gt; method of the &lt;code&gt;Number&lt;/code&gt; class. If a calculation algorithm explicitly calls for a rounded number, then using the &lt;code&gt;round()&lt;/code&gt; function above would be acceptable. If your algorithm does not explicitly call for a rounded number, then only round the number when outputing it to the user.
                      &lt;/p&gt;
                      &lt;h5 class="entry-subtitle2"&gt;
                        Preventing user number entry errors with textFieldToNumber
                      &lt;/h5&gt;
                      &lt;p&gt;
                        So far we've discussed converting strings to numbers, and accounting for user errors, but wouldn't it be nice to have a function that prevents user errors from ever occuring? Let's create one more function that cleans non-numeric characters from a string, and then apply it to a form text field.
                      &lt;/p&gt;
                      &lt;div class="expando expando-quarter"&gt;
&lt;pre class="code-block"&gt;function textFieldToNumber(el) {
  el.value = el.value.replace(/[^0-9-.]/g, "");
  el = null;
}&lt;/pre&gt;
                        &lt;span class="corner corner-top"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
                        &lt;span class="corner corner-bottom"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
                      &lt;/div&gt;
                      &lt;p&gt;
                        It's a pretty simple function. It strips out non numeric characters with a regular expression and puts the stripped down string back into the text field. &lt;strong&gt;Putting a number into a form field automatically converts it to a string.&lt;/strong&gt; As you recall from earlier, form field values only contain strings. Next, we just need to attach the &lt;code&gt;textFieldToNumber&lt;/code&gt; function to a form field.
                      &lt;/p&gt;
                      &lt;div class="expando expando-quarter"&gt;
&lt;pre class="code-block"&gt;&amp;lt;form action="" method="get"&amp;gt;

&amp;lt;input type="text" &lt;strong&gt;onblur="textFieldToNumber(this);"&lt;/strong&gt; name="age"&amp;gt;

&amp;lt;/form&amp;gt;&lt;/pre&gt;
                        &lt;span class="corner corner-top"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
                        &lt;span class="corner corner-bottom"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
                      &lt;/div&gt;
                      &lt;p&gt;
                        When the user presses the tab key or clicks off the form field, the onblur event fires, and then executes the &lt;code&gt;textFieldToNumber&lt;/code&gt; function. A document object model node reference to the form field is passed to the function using the keyword &lt;code&gt;this&lt;/code&gt;. The function removes any non numeric characters from the form field value, and then puts the pure number back in the form field. &lt;strong&gt;Since JavaScript can be disabled, make sure any server side script that receives data from your form double checks the input.&lt;/strong&gt;
                      &lt;/p&gt;
                      &lt;h5 class="entry-subtitle2"&gt;
                        A Quick Recap
                      &lt;/h5&gt;
                      &lt;p&gt;
                        We've gone over a lot so far. Numbers in JavaScript are primitive and complex data type. The &lt;code&gt;Number&lt;/code&gt; class has more functions and data members than this tutorial covers. Mathematical operators in JavaScript don't always do math. The addition operator (&lt;code&gt;+&lt;/code&gt;) also joins two strings, and if you try adding a number to a string, the browser automatically converts the number to a string, and then joins the two strings.
                      &lt;/p&gt;
                      &lt;p&gt;
                        We also learned the four main ways of converting strings to numbers: by subtracting a number from a string, using the &lt;code&gt;Number&lt;/code&gt; class constructor, using the &lt;code&gt;parseFloat&lt;/code&gt; function or using the &lt;code&gt;parseInt&lt;/code&gt; function. The &lt;code&gt;parseInt&lt;/code&gt; function needs the radix, or number base, passed to it each time. You might pass it a base 10 number with some funky input and get back a base 16, or hexadecimal number.
                      &lt;/p&gt;
                      &lt;p&gt;
                        The &lt;code&gt;toNumber&lt;/code&gt; function was written to convert strings to numbers in a more flexible manor than &lt;code&gt;parseFloat&lt;/code&gt; and &lt;code&gt;parseInt&lt;/code&gt;. The native &lt;code&gt;isNaN&lt;/code&gt; function can detect if a variable doesn't contain a number value, and is used for detecting user errors in the data. Once valid numbers have been tested for, we touched on how to round numbers using &lt;code&gt;Math.round&lt;/code&gt; and the &lt;code&gt;toFixed&lt;/code&gt; method of the &lt;code&gt;Number&lt;/code&gt; class. We also created a &lt;code&gt;round()&lt;/code&gt; function that returns a number rounded to a certain decimal place, rather than using the &lt;code&gt;toFixed&lt;/code&gt; method which returns a string. Lastly, the custom function &lt;code&gt;textFieldToNumber()&lt;/code&gt; can be attached to a form field and prevents user errors when entering numbers.
                      &lt;/p&gt;
                      &lt;p&gt;
                        There is much more about numbers and JavaScript that this tutorial hasn't covered, however these are the basics and all you should need 90 percent of the time. Other useful resources are listed below:
                      &lt;/p&gt;
                      &lt;h5 class="entry-subtitle2"&gt;
                        More Information on Numbers in JavaScript
                      &lt;/h5&gt;
                      &lt;ul class="paragraph"&gt;
                        &lt;li&gt;
                          &lt;a href="http://www.w3schools.com/js/js_obj_math.asp"&gt;&lt;code&gt;Math&lt;/code&gt; Object Reference&lt;/a&gt; at W3Schools.com
                        &lt;/li&gt;
                        &lt;li&gt;
                          &lt;a href="http://www.w3schools.com/jsref/jsref_obj_number.asp"&gt;&lt;code&gt;Number&lt;/code&gt; Class Reference&lt;/a&gt; at W3Schools.com
                        &lt;/li&gt;
                        &lt;li&gt;
                          &lt;a href="http://www.w3schools.com/jsref/jsref_parseInt.asp"&gt;&lt;code&gt;parseInt&lt;/code&gt; Function Reference&lt;/a&gt; at W3Schools.com
                        &lt;/li&gt;
                        &lt;li&gt;
                          &lt;a href="http://www.w3schools.com/jsref/jsref_parseFloat.asp"&gt;&lt;code&gt;parseFloat&lt;/code&gt; Function Reference&lt;/a&gt; at W3Schools.com
                        &lt;/li&gt;
                        &lt;li&gt;
                          &lt;a href="http://www.ecma-international.org/publications/standards/Ecma-262.htm"&gt;ECMA Script Specification&lt;/a&gt; (Downloadable PDF). ECMA Script is sort of like "Standardardized JavaScript."
                        &lt;/li&gt;
                        &lt;li style="list-style: none"&gt;
                          &lt;ul&gt;
                            &lt;li&gt;
                              &lt;code&gt;parseInt()&lt;/code&gt;: Section 15.1.2.2
                            &lt;/li&gt;
                            &lt;li&gt;
                              &lt;code&gt;parseFloat()&lt;/code&gt;: Section 15.1.2.3
                            &lt;/li&gt;
                            &lt;li&gt;
                              &lt;code&gt;isNaN()&lt;/code&gt;: Section 15.1.2.4
                            &lt;/li&gt;
                            &lt;li&gt;
                              &lt;code&gt;Number()&lt;/code&gt; called as a function: Section 15.7.1
                            &lt;/li&gt;
                            &lt;li&gt;
                              &lt;code&gt;Number()&lt;/code&gt; as class constructor: Section 15.7.2
                            &lt;/li&gt;
                            &lt;li&gt;
                              &lt;code&gt;Math&lt;/code&gt; Object: Section 15.8
                            &lt;/li&gt;
                          &lt;/ul&gt;
                        &lt;/li&gt;
                      &lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1829691255062570719-7070747152112383696?l=fundamentaldisaster.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fundamentaldisaster.blogspot.com/feeds/7070747152112383696/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1829691255062570719&amp;postID=7070747152112383696' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1829691255062570719/posts/default/7070747152112383696'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1829691255062570719/posts/default/7070747152112383696'/><link rel='alternate' type='text/html' href='http://fundamentaldisaster.blogspot.com/2007/11/practical-guide-to-numbers-in.html' title='A Practical Guide To Numbers in JavaScript'/><author><name>Greg Burghardt</name><uri>http://www.blogger.com/profile/14825576215668294298</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1829691255062570719.post-7655122633923214061</id><published>2007-10-17T16:01:00.000-07:00</published><updated>2007-10-19T07:22:51.100-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='forms'/><category scheme='http://www.blogger.com/atom/ns#' term='dom'/><category scheme='http://www.blogger.com/atom/ns#' term='code examples'/><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='web standards'/><category scheme='http://www.blogger.com/atom/ns#' term='HTML'/><title type='text'>JavaScript, DOM, and the Humble FORM</title><content type='html'>&lt;h3 class="post-subtitle"&gt;
  Use standard &lt;abbr title="Document Object Model"&gt;DOM&lt;/abbr&gt; methods and properties to interact with HTML forms.
&lt;/h3&gt;
&lt;p&gt;
  This is a basic tutorial on using JavaScript to interact with forms on a Web page. It covers two methods. The first method is very common, but was first implemented in old browsers. The second method uses standard Document Object Model methods and properties, and is considered best practice.
&lt;/p&gt;
&lt;h4 class="entry-subtitle2"&gt;
  Using document.forms to Get &lt;abbr title="Document Object Model"&gt;DOM&lt;/abbr&gt; References to FORMs
&lt;/h4&gt;
&lt;p&gt;
  Old browsers polluted the &lt;code&gt;document&lt;/code&gt; object with multiple, redundant references to FORM tags. The &lt;code&gt;document.forms&lt;/code&gt; array actually contains two parts. First, it is an integer-indexed array of references to FORM tags, and secondly it is an associative array. Let's take the following HTML as an example:
&lt;/p&gt;
&lt;h5 class="code-label"&gt;
  Example 1
&lt;/h5&gt;
&lt;pre class="code-block"&gt;
&amp;lt;form name="establishment_form"&amp;gt;
  ...
&amp;lt;/form&amp;gt;

&amp;lt;form&amp;gt;
  ...
&amp;lt;/form&amp;gt;
&lt;/pre&gt;
&lt;p&gt;
  In our pretend HTML document, we've got two forms. The first form is given a name and the second form is &lt;em&gt;not&lt;/em&gt; given a name. You can access the Document Object Model nodes that represent those FORM tags like this:
&lt;/p&gt;
&lt;h5 class="code-label"&gt;
  Example 2: Getting &lt;abbr title="Document Object Model"&gt;DOM&lt;/abbr&gt; node references to the two forms in Example 1
&lt;/h5&gt;
&lt;pre class="code-block"&gt;
var form1 = document.forms["establishment_form"];
var form1 = document.forms.establishment_form;
var form1 = document.forms[0];

var form2 = document.forms[1];
&lt;/pre&gt;
&lt;p&gt;
  You'll notice that the first form on the page, which was given a name, can be accessed in three ways: &lt;code&gt;document.forms["establishment_form"]&lt;/code&gt;, &lt;code&gt;document.forms.establishment_form&lt;/code&gt;, and &lt;code&gt;document.forms[0]&lt;/code&gt;. They all represent the same Document Object Model node and the same HTML tag.
&lt;/p&gt;
&lt;p&gt;
  The second form on the page was not given a name, and can only be accessed using &lt;code&gt;document.forms[1]&lt;/code&gt;. Also remember that integer-indexed arrays start with zero, so an index of zero is the first form, and an index of 1 is the second form.
&lt;/p&gt;
&lt;p&gt;
  One more wrench is thrown into this cog wheel since the first form was given a name: It can also be accessed via &lt;code&gt;document.&lt;strong&gt;establishment_form&lt;/strong&gt;&lt;/code&gt;. So a quick recap of how to get a node reference to the first form tag in our HTML example above (example 1).
&lt;/p&gt;
&lt;h5 class="code-label"&gt;
  Example 3: Getting a &lt;abbr title="Document Object Model"&gt;DOM&lt;/abbr&gt; node reference to the first form in Example 1
&lt;/h5&gt;
&lt;pre class="code-block"&gt;
var form1 = document.establishment_form;
var form1 = document.forms["establishment_form"];
var form1 = document.forms.establishment_form;
var form1 = document.forms[0];
&lt;/pre&gt;
&lt;p&gt;
  Yuck. Writing JavaScript for older browsers basically sucks. All of these different methods existed because browser developers couldn't agree on the best way to do things. Now enter Web Standards.
&lt;/p&gt;
&lt;h4 class="entry-subtitle2"&gt;
  Standard Methods for Getting &lt;abbr title="Document Object Model"&gt;DOM&lt;/abbr&gt; Node References to FORMs
&lt;/h4&gt;
&lt;p&gt;
  There are three main ways of getting a reference to a form tag using standard methods. Let's use our HTML code from example 1 again, slightly modified.
&lt;/p&gt;
&lt;h5 class="code-label"&gt;
  Example 4.
&lt;/h5&gt;
&lt;pre class="code-block"&gt;
&amp;lt;form &lt;strong&gt;id="establishment_form"&lt;/strong&gt;&amp;gt;
  ...
&amp;lt;/form&amp;gt;

&amp;lt;form&amp;gt;
  ...
&amp;lt;/form&amp;gt;
&lt;/pre&gt;
&lt;p&gt;
  An Id is used instead of the name attribute. Using an Id is best because it identifies one element on the page. Names can be applied to more than one element, thus the document.forms.&lt;em&gt;form_name&lt;/em&gt; method might reference a different form than you think. Having more than one form with the same name will cause JavaScript to return a reference to the first instance of a form with the given name. Furthermore, if you use Cascading Style Sheets, giving Ids to all of your FORMs allows you to easily style forms individually.
&lt;/p&gt;
&lt;h5 class="code-label"&gt;
  Example 5: Standard &lt;abbr title="Document Object Model"&gt;DOM&lt;/abbr&gt; methods to get references to &lt;code&gt;FORM&lt;/code&gt; tags
&lt;/h5&gt;
&lt;pre class="code-block"&gt;
var form1 = document.getElementById("establishment_form");
var form1 = document.getElementsByTagName("form")[0];

var form2 = document.getElementsByTagName("form")[1];
&lt;/pre&gt;
&lt;p&gt;
  We still have more than one way to grab a reference to the first FORM in Example 4. The advantage of using &lt;code&gt;document.getElementById&lt;/code&gt; over &lt;code&gt;document.getElementsByTagName&lt;/code&gt; is if you ever add a FORM to that page, the index number at which the &lt;code&gt;establishment_form FORM&lt;/code&gt; tag is referenced may change. Using &lt;code&gt;document.getElementById&lt;/code&gt; allows you to physically place that FORM tag anywhere in the HTML document and still be able to grab a reference to that FORM tag without changing your JavaScript. &lt;strong&gt;The &lt;code&gt;document.getElementById&lt;/code&gt; method is recommended for grabbing DOM node references to &lt;code&gt;FORM&lt;/code&gt; tags.&lt;/strong&gt; Now that we have a node reference to our FORM tag, we need node references to the form fields.
&lt;/p&gt;
&lt;h4 class="entry-subtitle2"&gt;
  Getting Node References To Fields Within A Form
&lt;/h4&gt;
&lt;p&gt;
  We'll keep using the HTML from Example 4, and yet again we will expand it.
&lt;/p&gt;
&lt;h5 class="code-label"&gt;
  Example 5: Adding some form fields
&lt;/h5&gt;
&lt;pre class="code-block"&gt;
&amp;lt;form id="establishment_form"&amp;gt;
  &lt;strong&gt;&amp;lt;input type="text" name="title"&amp;gt;
 
   &amp;lt;textarea cols="50" rows="5" name="description"&amp;gt;&amp;lt;/textarea&amp;gt;
 
   &amp;lt;input type="submit" value="Add Establishment"&amp;gt;&lt;/strong&gt;
&amp;lt;/form&amp;gt;
&lt;/pre&gt;
&lt;p&gt;
  We'll forgo the labels for each form field, as they aren't important for this tutorial. Right now we have two form fields and one button. The form fields are given a name, and the button is given no name. Let's see how we can access those form fields with JavaScript. First, let's get a node reference to our form:
&lt;/p&gt;
&lt;pre class="code-block"&gt;
var form = document.getElementById("establishment_form");
&lt;/pre&gt;
&lt;p&gt;
  Now that we have a node reference to our FORM tag, let's grab references to each form field using the deprecated methods first implemented by older browsers:
&lt;/p&gt;
&lt;h5 class="code-label"&gt;
  Example 6: Get DOM node references to form fields the old way
&lt;/h5&gt;
&lt;pre class="code-block"&gt;
// Get a reference to the FORM tag
var form = document.getElementById("establishment_form");

// Use old method of getting references to fields
var title = form.title;
var description = form.description;
&lt;/pre&gt;
&lt;p&gt;
  That wasn't too difficult. When you give a form field a name, the FORM tag gets a property named the same thing as the form field. This is fine and well, but an inherent property of a FORM tag is also called &lt;code&gt;title&lt;/code&gt;. This would be the value of the title attribute of the FORM tag. We have a form field named title, which then overwrites the FORM tag's &lt;code&gt;title&lt;/code&gt; property with a node reference to the form field. That's not so good. Suddenly we have a problem. The name space of the FORM tag is quickly polluted with references to the form fields inside. There is a better way.
&lt;/p&gt;
&lt;h5 class="code-label"&gt;
  Example 7: Get DOM node references to form fields the standard way
&lt;/h5&gt;
&lt;pre class="code-block"&gt;
// Get a reference to the FORM tag
var form = document.getElementById("establishment_form");

// Use standard method for getting references to fields
var title = form.elements["title"];
var description = form.elements["description"];
&lt;/pre&gt;
&lt;p&gt;
  Each FORM tag has a handy property called &lt;code&gt;elements&lt;/code&gt; which holds references to all the form fields. This is a two part property. It contains an integer-indexed array of references to all the form fields, and an associative array of references. Using the &lt;code&gt;elements&lt;/code&gt; property, you can get a reference to the "title" form field in three ways:
&lt;/p&gt;
&lt;pre class="code-block"&gt;
var title = form.elements["title"];
var title = form.elements.title;
var title = form.elements[0];
&lt;/pre&gt;
&lt;p&gt;
  You can supply the name of the form field or the index at which it appears in the FORM tag HTML source code. Since the "title" INPUT tag is the first field in the source code, it resides at &lt;code&gt;form.elements[0]&lt;/code&gt;. Now think about the future. Maybe you rearrange the form somewhere down the line, and the "title" INPUT tag is no longer the first form field. You can no longer access that field in JavaScript with &lt;code&gt;form.elements[0]&lt;/code&gt;, so it's always safest to use the &lt;code&gt;form.elements["field_name"]&lt;/code&gt; syntax for the same reason it's best to use &lt;code&gt;document.getElementById&lt;/code&gt;. &lt;strong&gt;It is considered best practice to use &lt;code&gt;form.elements["field_name"]&lt;/code&gt;.&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
  The table below outlines the properties in the &lt;code&gt;form.elements&lt;/code&gt; property.
&lt;/p&gt;
&lt;table class="dataTable" border="0"&gt;
  &lt;caption&gt;
    Example 8: Properties of form.elements
  &lt;/caption&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;
        Property
      &lt;/th&gt;
      &lt;th&gt;
        Type
      &lt;/th&gt;
      &lt;th&gt;
        Description
      &lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;
        0
      &lt;/td&gt;
      &lt;td&gt;
        object
      &lt;/td&gt;
      &lt;td&gt;
        The "title" form field
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr class="rowB"&gt;
      &lt;td&gt;
        1
      &lt;/td&gt;
      &lt;td&gt;
        object
      &lt;/td&gt;
      &lt;td&gt;
        The "description" form field
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;
        2
      &lt;/td&gt;
      &lt;td&gt;
        object
      &lt;/td&gt;
      &lt;td&gt;
        The submit button
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr class="rowB"&gt;
      &lt;td&gt;
        length
      &lt;/td&gt;
      &lt;td&gt;
        number
      &lt;/td&gt;
      &lt;td&gt;
        The number of form fields or elements in this form
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;
        title
      &lt;/td&gt;
      &lt;td&gt;
        object
      &lt;/td&gt;
      &lt;td&gt;
        The "title" form field
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr class="rowB"&gt;
      &lt;td&gt;
        description
      &lt;/td&gt;
      &lt;td&gt;
        object
      &lt;/td&gt;
      &lt;td&gt;
        The "description" form field
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
  Now let's add form fields with the same name: a group of radio buttons.
&lt;/p&gt;
&lt;h5 class="code-label"&gt;
  Example 9: Adding more than one field with the same name
&lt;/h5&gt;
&lt;pre class="code-block"&gt;
&amp;lt;form id="establishment_form"&amp;gt;
  &amp;lt;input type="text" name="title"&amp;gt;
 
  &amp;lt;textarea cols="50" rows="5" name="description"&amp;gt;&amp;lt;/textarea&amp;gt;
 
  &lt;strong&gt;&amp;lt;input type="radio" name="estab_type" value="General"&amp;gt;
  &amp;lt;input type="radio" name="&lt;/strong&gt;&lt;strong&gt;estab_&lt;/strong&gt;&lt;strong&gt;type" value="Restaurant"&amp;gt;
  &amp;lt;input type="radio" name="&lt;/strong&gt;&lt;strong&gt;estab_&lt;/strong&gt;&lt;strong&gt;type" value="Government"&amp;gt;&lt;/strong&gt;
 
  &amp;lt;input type="submit" value="Add Establishment"&amp;gt;
&amp;lt;/form&amp;gt;
&lt;/pre&gt;
&lt;p&gt;
  We've added a group of radio buttons, all named "estab_type". This changes the object model of the FORM tag.
&lt;/p&gt;
&lt;table class="dataTable" border="0"&gt;
  &lt;caption&gt;
    Example 10: Properties of form.elements
  &lt;/caption&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;
        Property
      &lt;/th&gt;
      &lt;th&gt;
        Type
      &lt;/th&gt;
      &lt;th&gt;
        Description
      &lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;
        0
      &lt;/td&gt;
      &lt;td&gt;
        object
      &lt;/td&gt;
      &lt;td&gt;
        The "title" form field
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr class="rowB"&gt;
      &lt;td&gt;
        &lt;strong&gt;1&lt;/strong&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;strong&gt;object&lt;/strong&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;strong&gt;The first "estab_type" radio button&lt;/strong&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;
        &lt;strong&gt;2&lt;/strong&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;strong&gt;object&lt;/strong&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;strong&gt;The second "estab_type" radio button&lt;/strong&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr class="rowB"&gt;
      &lt;td&gt;
        &lt;strong&gt;3&lt;/strong&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;strong&gt;object&lt;/strong&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;strong&gt;The third "estab_type" radio button&lt;/strong&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;
        &lt;strong&gt;4&lt;/strong&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;strong&gt;object&lt;/strong&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;strong&gt;The "description" form field&lt;/strong&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr class="rowB"&gt;
      &lt;td&gt;
        &lt;strong&gt;5&lt;/strong&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;strong&gt;object&lt;/strong&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;strong&gt;The submit button&lt;/strong&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;
        length
      &lt;/td&gt;
      &lt;td&gt;
        number
      &lt;/td&gt;
      &lt;td&gt;
        The number of form fields or elements in this form (includes all non named elements like buttons)
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr class="rowB"&gt;
      &lt;td&gt;
        title
      &lt;/td&gt;
      &lt;td&gt;
        object
      &lt;/td&gt;
      &lt;td&gt;
        The "title" form field
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;
        &lt;strong&gt;estab_type&lt;/strong&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;strong&gt;array[]&lt;/strong&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;strong&gt;Integer-indexed array of references to each radio button.&lt;/strong&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr class="rowB"&gt;
      &lt;td&gt;
        description
      &lt;/td&gt;
      &lt;td&gt;
        object
      &lt;/td&gt;
      &lt;td&gt;
        The "description" form field
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
  Now you can see why using the &lt;code&gt;form.elements[&lt;em&gt;n&lt;/em&gt;]&lt;/code&gt; syntax isn't the best. The order in which the form field appears in the HTML source determines the index number in the &lt;code&gt;form.elements&lt;/code&gt; array at which a form field resides. The "description" text field went from index 1 to index 4. If you had used &lt;code&gt;form.elements["description"]&lt;/code&gt; to get a reference to the "description" text field, this change to the FORM markup wouldn't have affected your JavaScript.
&lt;/p&gt;
&lt;p&gt;
  Now we've run into another unique case. The &lt;code&gt;form.elements["estab_type"]&lt;/code&gt; property is an array, not a reference to a form field. Remember that we had three radio buttons named "estab_type". The browser accounts for this by mashing references to all three radio buttons in &lt;code&gt;form.elements["estab_type"]&lt;/code&gt;. Let's take a look at the contents of this array.
&lt;/p&gt;
&lt;table class="dataTable" border="0" width="100%"&gt;
  &lt;caption&gt;
    Example 11: Properties of form.elements["estab_type"]
  &lt;/caption&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;
        Property
      &lt;/th&gt;
      &lt;th&gt;
        Type
      &lt;/th&gt;
      &lt;th&gt;
        Description
      &lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;
        0
      &lt;/td&gt;
      &lt;td&gt;
        object
      &lt;/td&gt;
      &lt;td&gt;
        Reference to first "estab_type" radio button
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr class="rowB"&gt;
      &lt;td&gt;
        1
      &lt;/td&gt;
      &lt;td&gt;
        object
      &lt;/td&gt;
      &lt;td&gt;
        Reference to second "estab_type" radio button
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;
        2
      &lt;/td&gt;
      &lt;td&gt;
        object
      &lt;/td&gt;
      &lt;td&gt;
        Reference to third "estab_type" radio button
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr class="rowB"&gt;
      &lt;td&gt;
        length
      &lt;/td&gt;
      &lt;td&gt;
        number
      &lt;/td&gt;
      &lt;td&gt;
        Number of items in this array.
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
  The object model of the &lt;code&gt;form.elements&lt;/code&gt; property then looks like this:
&lt;/p&gt;
&lt;h5 class="code-label"&gt;
  Example 12: Breakdown of the form.elements object model
&lt;/h5&gt;
&lt;pre class="code-block"&gt;
form.elements[0]      // "title" INPUT
form.elements[1]      // "estab_type" radio 1
form.elements[2]      // "estab_type" radio 2
form.elements[3]      // "estab_type" radio 3
form.elements[4]      // "description" TEXTAREA
form.elements[5]      // submit INPUT
form.elements.length  // Number of form elements
form.elements.title   // "title" INPUT

form.elements.estab_type[0]      // "estab_type" radio 1
form.elements.estab_type[1]      // "estab_type" radio 2
form.elements.estab_type[2]      // "estab_type" radio 3
form.elements.estab_type.length  // Number of radio buttons

form.elements.description  // "description" TEXTAREA

// Note: form.elements.estab_type is the same as
// form.elements["estab_type"]
&lt;/pre&gt;
&lt;p&gt;
  Since we can reference form fields by their name and by an index number, we can do bulk processing on a form using JavaScript. It's easy to loop through all the fields in a form.
&lt;/p&gt;
&lt;h5 class="code-label"&gt;
  Example 13: Looping through all the form fields
&lt;/h5&gt;
&lt;pre class="code-block"&gt;
// Get a DOM reference to our form
var form = document.getElementById("establishment_form");

// Loop through all the form fields
for (var i = 0; i &amp;lt; form.elements.length; i++) {
  alert(form.elements[i]);
}
&lt;/pre&gt;
&lt;p&gt;
  Also recall that our "estab_type" radio buttons formed an array in &lt;code&gt;form.elements["estab_type"]&lt;/code&gt;. We can also loop through this with JavaScript:
&lt;/p&gt;
&lt;h5 class="code-label"&gt;
  Example 14: Looping through an array of form fields with the same name
&lt;/h5&gt;
&lt;pre class="code-block"&gt;
// Get a DOM reference to our form
var form = document.getElementById("establishment_form");

// Loop through all the "estab_type" radio buttons
for (var i = 0; i &amp;lt; form.elements["estab_type"].length; i++) {
  alert(form.elements["estab_type"].value);
}
&lt;/pre&gt;
&lt;h4 class="entry-subtitle2"&gt;
  A Quick Recap
&lt;/h4&gt;
&lt;p&gt;
  We've covered how to get a DOM node reference to a FORM tag, and also how to get references to the form fields inside of it. There were two basic methods. One used the API of older browsers, which included &lt;code&gt;document.forms&lt;/code&gt;, and &lt;code&gt;form.&lt;em&gt;field_name&lt;/em&gt;&lt;/code&gt;, and the other utilized standard Document Object Model functions and properties like &lt;code&gt;document.getElementById&lt;/code&gt; and &lt;code&gt;form.elements&lt;/code&gt;. Using the standard DOM properties allows you to change and rearrange your FORM markup down the road with little fear of breaking your JavaScript, and since you are using standard functions and properties, your script will be supported for many years to come.
&lt;/p&gt;
&lt;table class="dataTable" border="0" width="100%"&gt;
  &lt;caption&gt;
    Methods of getting DOM references to FORMs and form fields
  &lt;/caption&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;
        Standard Method (Best Practice)
      &lt;/th&gt;
      &lt;th&gt;
        Old Method (Deprecated)
      &lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;
        document.getElementById("form_id")
      &lt;/td&gt;
      &lt;td&gt;
        document.forms.&lt;em&gt;form_name&lt;/em&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr class="rowB"&gt;
      &lt;td&gt;
        document.getElementById("form_id")
      &lt;/td&gt;
      &lt;td&gt;
        document.&lt;em&gt;form_name&lt;/em&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;
        document.getElementsByTagName("form")[&lt;em&gt;n&lt;/em&gt;]
      &lt;/td&gt;
      &lt;td&gt;
        document.forms[&lt;em&gt;n&lt;/em&gt;]
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr class="rowB"&gt;
      &lt;td&gt;
        form.elements["description"]
      &lt;/td&gt;
      &lt;td&gt;
        form.description
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;
        form.elements.description
      &lt;/td&gt;
      &lt;td&gt;
        form.description
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 class="entry-subtitle2"&gt;
  Additional References
&lt;/h4&gt;
&lt;ul class="paragraph"&gt;
  &lt;li&gt;
    &lt;a href="http://www.w3schools.com/htmldom/dom_obj_document.asp"&gt;&lt;code&gt;document&lt;/code&gt;&lt;/a&gt; Object Reference at W3Schools.com
  &lt;/li&gt;
  &lt;li&gt;
    &lt;a href="http://www.w3schools.com/htmldom/coll_doc_forms.asp"&gt;&lt;code&gt;document.forms&lt;/code&gt;&lt;/a&gt; Object Reference at W3Schools.com
  &lt;/li&gt;
  &lt;li&gt;
    &lt;a href="http://www.w3schools.com/htmldom/dom_obj_form.asp"&gt;Form DOM Reference&lt;/a&gt; at W3Schools.com
  &lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1829691255062570719-7655122633923214061?l=fundamentaldisaster.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fundamentaldisaster.blogspot.com/feeds/7655122633923214061/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1829691255062570719&amp;postID=7655122633923214061' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1829691255062570719/posts/default/7655122633923214061'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1829691255062570719/posts/default/7655122633923214061'/><link rel='alternate' type='text/html' href='http://fundamentaldisaster.blogspot.com/2007/10/javascript-dom-and-humble-form.html' title='JavaScript, DOM, and the Humble FORM'/><author><name>Greg Burghardt</name><uri>http://www.blogger.com/profile/14825576215668294298</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1829691255062570719.post-1451751497943764723</id><published>2007-10-08T11:22:00.001-07:00</published><updated>2007-10-12T06:48:26.370-07:00</updated><title type='text'>iPhone: Killing or Redefining Web Standards?</title><content type='html'>&lt;h3 class="post-subtitle"&gt;
                        The iPhone will be looked upon as the epoch of the truly mobile web. It doesn't support handheld media style sheets and tries to display web sites normally, as well as tailoring them to its lower resolution. The iPhone may destroy a Web standard or cause it to be redefined.
                      &lt;/h3&gt;
                      &lt;p&gt;
                        The World Wide Web Consortium has set up a number of different types of media on which a Web page can be displayed. Chief among them are the "screen" and "handheld" media. Desktop web browsers fall into the "screen" category and things like cellphones and PDAs fall into the "handheld" category. Handheld devices must adapt content designed for the screen media to their less capable displays.
                      &lt;/p&gt;
                      &lt;p&gt;
                        Apple's Safari Web browser on iPhone isn't the first browser that attempts to display Web pages normally. Opera's flavors of mobile browsers do something similar. A while back, I believe around version 7 or 8 of its desktop browser, Opera in mobile mode would try to display a Web page how you'd see it on a desktop computer unless you imported a style sheet for the handheld media. This continues on today as "&lt;a href="http://dev.opera.com/articles/view/evolving-the-internet-on-your-phone-des/"&gt;Small Screen Rendering&lt;/a&gt;" (SSR) and attempts to crunch a web page down in size to fit on a smaller screen.
                      &lt;/p&gt;
                      &lt;p&gt;
                        This seems like a fairly sensible approach. The Opera browser is aware it's on a mobile or handheld device and supports hand held style sheets, but in the absence of hand held style sheets it does it's best to display a Web page not designed for a handheld device. Safari on iPhone basically claims it's a desktop browser. With a little additional markup you can change its behavior, and with a CSS3 media query you can feed that particular flavor of Safari a different style sheet. The common theme here is that mobile browsers, despite what the W3C might have imagined, try to be desktop web browsers first unless an alternative method of styling exists.
                      &lt;/p&gt;
                      &lt;h4 class="post-subtitle2"&gt;
                        The emergence of a two-tiered Mobile Web
                      &lt;/h4&gt;
                      &lt;p&gt;
                        The World Wide Web Consortium envisioned the Web as requiring different styles based on the display capabilities of a device, but getting the same markup. Reality is panning out differently. Web page HTML has been a bitter soup of presentational markup garnished with sparse portions of meaningful tags for many years, and web browsers must display these pages. To make matters worse, most pages are designed for the screen media, or desktop Web browsers as they are more commonly known as. Browser developers seem to be taking one of two paths:
                      &lt;/p&gt;
                      &lt;ul class="paragraph"&gt;
                        &lt;li&gt;
                          Attempt to display the Web page like a normal desktop browser would, and in the presence of some browser-specific markup, use styles catoring to the device. (Safari on iPhone).
                        &lt;/li&gt;
                        &lt;li&gt;
                          If no handheld media style sheets are found, crunch, chew, and rearrange the page to fit the display of the device (Opera Mini and Mobile).
                        &lt;/li&gt;
                      &lt;/ul&gt;
                      &lt;p&gt;
                        The mobile web is becoming two-tiered. This doesn't seem like something the W3C imagined would happen.
                      &lt;/p&gt;
                      &lt;p&gt;
                        Upon reading that &lt;a href="http://developer.apple.com/iphone/designingcontent.html"&gt;Safari on iPhone wouldn't support handheld media style sheets&lt;/a&gt;, I had to wonder if we'd be stuck in a mobile browser war similar to Netscape vs. Internet Explorer at the close of the last century. Looking into it further made me realize that both Opera's and Safari's compromises were out of necessity and shed light on how to realistically create a mobile Web. I'm not sure where the Web Standards explain how handheld browser developers should handle legacy Web pages or pages not designed for handheld devices, but the method for implementing handheld styles is starting to diverge. This could destroy cross-browser functionality, and presents a challenge to the industry on how to handle the non-mobile Web on mobile devices in a standardized fashion.
                      &lt;/p&gt;
                      &lt;p&gt;
                        Even though Safari on iPhone is on a hand held device, there are many reasons that it shouldn't be thrown into the same lot as cell phone browsers. Screen resolution, processor speed, battery life and memory capacity are greater on iPhone, and therefore Safari is more capable. Opera has also divied up its handheld browser into &lt;a href="http://www.opera.com/products/mobile/"&gt;Mini and Mobile versions&lt;/a&gt; assuming Mini will be on cell phones and Mobile will be on technologically beefier personal digital assistants and smart phones. Suddenly the notion of a "screen" and "handheld" web is blurred.
                      &lt;/p&gt;
                      &lt;h4 class="post-subtitle2"&gt;
                        The multi-tiered mobile Web
                      &lt;/h4&gt;
                      &lt;p&gt;
                        In the coming months we may see a plethora of mobile devices with many levels of capabilities &amp;mdash; screen resolutions, color depth, processor speed, memory capacity, plug-in support, battery life &amp;mdash; all these things will improve, but at different rates and on different devices. How can we possibly design for a "mobile web" when we don't know what will be accessing it? Opera's implementation of mobile technology is closest to the spirit of the Web Standards when compared with Safari on iPhone, but design itself is resolution dependent. You need physical limits to implement good design. This is where iPhone's implementation makes the most sense.
                      &lt;/p&gt;
                      &lt;p&gt;
                        On the iPhone, you use a CSS3 media query in which you specify the maximum resolution for the device, and you add a few &lt;code&gt;META&lt;/code&gt; tags to your HTML. I don't believe this meshes well with Web Standards, but makes the most sense design-wise. The iPhone isn't "handheld" or "screen" or "print." It's got a maximum width of 480 pixels in landscape mode. We have 480 pixels of width to design with. Now we have a physical limitation. Now we can truly design effectively. Now there are no standards and we are open to conflicts between different devices and software platforms&amp;mdash; precisely the situation Web Standards have sought to avoid. However, this makes the most sense for design.
                      &lt;/p&gt;
                      &lt;p&gt;
                        There are too many levels of "hand held" or "mobile" devices to realistically mesh them together, and yet they aren't truly "screen" or "desktop" devices. They can't handle reams of JavaScript and dozens of images, but they can handle some. The W3C's media types have gotten us started. Now that we are seeing how the mobile web is developing, it's time to look back and choose a different metric on which to decide how to display content. Pixels count. The W3C has tried hard to make them count less, but in the end that's what really counts. We need a standard on how to decide which resolutions get which styles and functionality. I still don't want to write multiple versions of HTML on one Web site for God knows how many different types of devices when one version should suffice.
                      &lt;/p&gt;
                      &lt;p&gt;
                        I've only just started down the path of designing and coding for the "mobile web," so I've got oodles more questions than answers.
                      &lt;/p&gt;
                      &lt;h4 class="post-subtitle2"&gt;
                        Additional Resources
                      &lt;/h4&gt;
                      &lt;ul class="paragraph"&gt;
                        &lt;li&gt;
                          &lt;a href="http://dev.opera.com/articles/view/evolving-the-internet-on-your-phone-des/"&gt;Evolving the Internet on your phone: Designing web sites with Opera Mini 4 in mind&lt;/a&gt;
                        &lt;/li&gt;
                        &lt;li&gt;
                          &lt;a href="http://dev.opera.com/articles/view/the-phone-factor-2/"&gt;The Phone Factor&lt;/a&gt;
                        &lt;/li&gt;
                        &lt;li&gt;
                          &lt;a href="http://developer.apple.com/iphone/designingcontent.html"&gt;Optimizing Web Applications and Content for iPhone&lt;/a&gt;
                        &lt;/li&gt;
                        &lt;li&gt;
                          &lt;a href="http://developer.apple.com/documentation/iPhone/Conceptual/iPhoneHIG/"&gt;iPhone Human Interface Guidelines&lt;/a&gt;
                        &lt;/li&gt;
                      &lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1829691255062570719-1451751497943764723?l=fundamentaldisaster.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fundamentaldisaster.blogspot.com/feeds/1451751497943764723/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1829691255062570719&amp;postID=1451751497943764723' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1829691255062570719/posts/default/1451751497943764723'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1829691255062570719/posts/default/1451751497943764723'/><link rel='alternate' type='text/html' href='http://fundamentaldisaster.blogspot.com/2007/10/iphone-killing-or-redefining-web.html' title='iPhone: Killing or Redefining Web Standards?'/><author><name>Greg Burghardt</name><uri>http://www.blogger.com/profile/14825576215668294298</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1829691255062570719.post-6350947241777098248</id><published>2007-10-03T21:48:00.000-07:00</published><updated>2007-10-03T21:51:19.694-07:00</updated><title type='text'>New Design Is Live!</title><content type='html'>&lt;h3 class="post-subtitle"&gt;
  Well, the headline pretty much says it all. I've got the new design done.
&lt;/h3&gt;
&lt;p&gt;
  "Wait a tick!" you say. "It doesn't work in Internet Explorer. It looks like rubbish."
&lt;/p&gt;
&lt;p&gt;
  Yes. The design doesn't work in Internet Explorer. Truth be told, it won't ever work in Internet Explorer. That browser is old and outdated. I decided to not support old buggy browsers at all. This design uses CSS 3 styles, and some "real" web browsers don't support that yet (c'mon Opera), but that's only for rounded corners on the boxes in the layout.
&lt;/p&gt;
&lt;p&gt;
  So, this is my new design. This is my playground. I don't want to play with Internet Explorer. Too bad so sad.
&lt;/p&gt;
&lt;h4 class="post-subtitle2"&gt;
  Download a real web browser:
&lt;/h4&gt;
&lt;ul class="paragraph"&gt;
  &lt;li&gt;
    &lt;a href="http://www.getfirefox.com/"&gt;Firefox&lt;/a&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;a href="http://www.opera.com/download/"&gt;Opera&lt;/a&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;a href="http://www.apple.com/safari/"&gt;Safari&lt;/a&gt;
  &lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1829691255062570719-6350947241777098248?l=fundamentaldisaster.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fundamentaldisaster.blogspot.com/feeds/6350947241777098248/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1829691255062570719&amp;postID=6350947241777098248' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1829691255062570719/posts/default/6350947241777098248'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1829691255062570719/posts/default/6350947241777098248'/><link rel='alternate' type='text/html' href='http://fundamentaldisaster.blogspot.com/2007/10/new-design-is-live.html' title='New Design Is Live!'/><author><name>Greg Burghardt</name><uri>http://www.blogger.com/profile/14825576215668294298</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1829691255062570719.post-3596641461713113</id><published>2007-10-01T18:09:00.000-07:00</published><updated>2007-10-01T18:10:35.377-07:00</updated><title type='text'>Pardon My Dust</title><content type='html'>&lt;p&gt;I'm finally putting a real design on this. In the mean time, I call this design "An Ode To Netscape 2." Enjoy. :)&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1829691255062570719-3596641461713113?l=fundamentaldisaster.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fundamentaldisaster.blogspot.com/feeds/3596641461713113/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1829691255062570719&amp;postID=3596641461713113' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1829691255062570719/posts/default/3596641461713113'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1829691255062570719/posts/default/3596641461713113'/><link rel='alternate' type='text/html' href='http://fundamentaldisaster.blogspot.com/2007/10/pardon-my-dust.html' title='Pardon My Dust'/><author><name>Greg Burghardt</name><uri>http://www.blogger.com/profile/14825576215668294298</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1829691255062570719.post-1061998236033406501</id><published>2007-10-01T08:54:00.000-07:00</published><updated>2007-10-03T08:05:22.151-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='free'/><category scheme='http://www.blogger.com/atom/ns#' term='safari'/><category scheme='http://www.blogger.com/atom/ns#' term='iphoneui'/><category scheme='http://www.blogger.com/atom/ns#' term='user interface'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><category scheme='http://www.blogger.com/atom/ns#' term='apple'/><title type='text'>iPhoneUI: Standards-based iPhone CSS styles</title><content type='html'>&lt;h4 class="entry-subtitle"&gt;
                      Download free, quick and easy CSS styles for creating iPhone applications using Apple's design specifications. 
&lt;/h4&gt;
&lt;p&gt;
                        A coworker of mine created his first iPhone web app, &lt;a href="http://www.phpinsider.com/iphone/lease/"&gt;iPhone Lease Calculator&lt;/a&gt;, and needed a visual skin on it. I set out to create simple styles so you can easily implement web apps using &lt;a href="http://developer.apple.com/iphone/designingcontent.html"&gt;Apple's recommended iPhone user interface&lt;/a&gt;. These styles are used for laying out forms, and limited text styles.
                      &lt;/p&gt;
                      &lt;p&gt;
                        There are two main styles, the Edge to Edge design, and the Rounded Corners design.
                      &lt;/p&gt;
                      &lt;h5 class="entry-subtitle2"&gt;
                        Edge-To-Edge Design: Forms
                      &lt;/h5&gt;
&lt;pre class="code-block"&gt;&amp;lt;dl class="edgeToEdge formFields"&amp;gt;
  &amp;lt;dt&amp;gt;
    &amp;lt;label for="txt_name"&amp;gt;Name:&amp;lt;/label&amp;gt;
  &amp;lt;/dt&amp;gt;
  
  &amp;lt;dd&amp;gt;
    &amp;lt;input type="text" name="full_name" value=""&amp;gt;
  &amp;lt;/dd&amp;gt;
&amp;lt;/dl&amp;gt;&lt;/pre&gt;
                      &lt;p&gt;
                        Pretty simple. The edge to edge design is recommended for most forms. It's not too attractive looking and provides maximum readability. I decided that a definition list provides the greatest flexibility in design and the most meaning for the markup.
                      &lt;/p&gt;
                      &lt;p&gt;
                        A gray border is placed below each row. The last row should not have a border, so add the &lt;code&gt;"last"&lt;/code&gt; className to the last &lt;code&gt;DD&lt;/code&gt; tag in the definition list.
                      &lt;/p&gt;
&lt;pre class="code-block"&gt;&amp;lt;dl class="edgeToEdge formFields"&amp;gt;
  &amp;lt;dt&amp;gt;
    &amp;lt;label for="txt_name"&amp;gt;Name:&amp;lt;/label&amp;gt;
  &amp;lt;/dt&amp;gt;
  
  &amp;lt;dd &lt;strong&gt;class="last"&lt;/strong&gt;&amp;gt;
    &amp;lt;input type="text" name="full_name" value=""&amp;gt;
  &amp;lt;/dd&amp;gt;
&amp;lt;/dl&amp;gt;&lt;/pre&gt;
&lt;h5 class="entry-subtitle2"&gt;
Rounded Corners: Forms
&lt;/h5&gt;
&lt;pre class="code-block"&gt;&amp;lt;dl class="&lt;strong&gt;roundedRect&lt;/strong&gt; formFields"&amp;gt;
  &amp;lt;dt&amp;gt;
    &amp;lt;label for="txt_name"&amp;gt;Name:&amp;lt;/label&amp;gt;
  &amp;lt;/dt&amp;gt;
  
  &amp;lt;dd&amp;gt;
    &amp;lt;input type="text" name="full_name" value=""&amp;gt;
  &amp;lt;/dd&amp;gt;
&amp;lt;/dl&amp;gt;&lt;/pre&gt;
&lt;p&gt;
So really not much different here. The rounded corners design uses the same basic markup with the exception of a different &lt;code&gt;className&lt;/code&gt;. This will get the white, rounded corner box. The only thing that's missing is a label:
&lt;/p&gt;
&lt;pre class="code-block"&gt;&lt;strong&gt;&amp;lt;h1 class="roundedRectHead"&amp;gt;
  Enter your name
&amp;lt;/h1&amp;gt;&lt;/strong&gt;

&amp;lt;dl class="roundedRect formFields"&amp;gt;
  ...
&amp;lt;/dl&amp;gt;&lt;/pre&gt;
&lt;p&gt;
While that may work for most uses, &lt;code&gt;FIELDSET&lt;/code&gt;s and &lt;code&gt;LEGEND&lt;/code&gt;s are also very useful on forms.
&lt;/p&gt;
&lt;pre class="code-block"&gt;&amp;lt;fieldset class="roundedRect"&amp;gt;
  
  &amp;lt;legend&amp;gt;Enter your name&amp;lt;/legend&amp;gt;
  
  &amp;lt;dl class="formFields"&amp;gt;
    ...
  &amp;lt;/dl&amp;gt;
  
&amp;lt;/fieldset&amp;gt;&lt;/pre&gt;
&lt;p&gt;
This requires just a slightly different markup structure. The &lt;code&gt;"roundedRect"&lt;/code&gt; className is moved to the &lt;code&gt;FIELDSET&lt;/code&gt; tag, and the &lt;code&gt;DL&lt;/code&gt; tag only has the &lt;code&gt;"formFields"&lt;/code&gt; className.
&lt;/p&gt;
&lt;p&gt;
At some point you'll want buttons on your form.
&lt;/p&gt;
&lt;h5 class="entry-subtitle2"&gt;
Edge-To-Edge: Buttons
&lt;/h5&gt;
&lt;pre class="code-block"&gt;&amp;lt;p class="edgeToEdge formButtons"&amp;gt;
  &amp;lt;input type="submit" value="Submit Name"&amp;gt;
&amp;lt;/p&amp;gt;&lt;/pre&gt;
&lt;h5 class="entry-subtitle2"&gt;
  Rounded Corners: Buttons
&lt;/h5&gt;
&lt;pre class="code-block"&gt;&amp;lt;p class="roundedRect formButtons"&amp;gt;
  &amp;lt;input type="submit" value="Submit Name"&amp;gt;
&amp;lt;/p&amp;gt;&lt;/pre&gt;
&lt;h5 class="entry-subtitle2"&gt;
  Showing Form Submission Results
&lt;/h5&gt;
&lt;p&gt;
  Once the user has submitted the form, you'll want to display some sort of message or result.
&lt;/p&gt;
&lt;pre class="code-block"&gt;&amp;lt;h1 class="roundedRectHead"&amp;gt;
  Your name is:
&amp;lt;/h1&amp;gt;
&amp;lt;p class="roundedRect formResults"&amp;gt;
  John Doe
&amp;lt;/p&amp;gt;&lt;/pre&gt;
&lt;p&gt;
  These styles aren't anything special and just seek to implement Apple's iPhone user interface on a web application viewed in iPhone's Safari web browser. This will integrate your Web application seamlessly into the iPhone's inherent user interface. And as usual, if I change anything, I'll be sure to post it.
&lt;/p&gt;
&lt;ul class="paragraph"&gt;
  &lt;li&gt;
    &lt;a href="http://www.phpinsider.com/css/iPhoneUI.css"&gt;&lt;strong&gt;Download iPhoneUI.css&lt;/strong&gt;&lt;/a&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;a href="http://www.phpinsider.com/iphone/lease/"&gt;&lt;strong&gt;iPhone Lease Calculator&lt;/strong&gt;&lt;/a&gt;
  &lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1829691255062570719-1061998236033406501?l=fundamentaldisaster.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fundamentaldisaster.blogspot.com/feeds/1061998236033406501/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1829691255062570719&amp;postID=1061998236033406501' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1829691255062570719/posts/default/1061998236033406501'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1829691255062570719/posts/default/1061998236033406501'/><link rel='alternate' type='text/html' href='http://fundamentaldisaster.blogspot.com/2007/10/iphoneui-standards-based-iphone-css.html' title='iPhoneUI: Standards-based iPhone CSS styles'/><author><name>Greg Burghardt</name><uri>http://www.blogger.com/profile/14825576215668294298</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1829691255062570719.post-5509883106938926392</id><published>2007-09-28T00:11:00.000-07:00</published><updated>2007-10-03T22:11:52.569-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='texteditor'/><category scheme='http://www.blogger.com/atom/ns#' term='dom'/><category scheme='http://www.blogger.com/atom/ns#' term='free'/><category scheme='http://www.blogger.com/atom/ns#' term='editor'/><category scheme='http://www.blogger.com/atom/ns#' term='webstandards'/><category scheme='http://www.blogger.com/atom/ns#' term='lgpl'/><category scheme='http://www.blogger.com/atom/ns#' term='codeeditor'/><category scheme='http://www.blogger.com/atom/ns#' term='unobtrusive'/><title type='text'>TextEditor: Free Unobtrusive JavaScript Code Editor Supporting Web Standards</title><content type='html'>&lt;h4 class="entry-subtitle"&gt;
  Easily create a JavaScript enhanced code editor with any &lt;code&gt;TEXTAREA&lt;/code&gt; that includes auto-indent, tab stops, auto-complete, &lt;abbr title="eXtensible Hyper Text Markup Language"&gt;XHTML&lt;/abbr&gt; compatibility and more. Did I mention it's free?
&lt;/h4&gt;
&lt;p&gt;
  I've worked with several older web-based content management systems, that store template code in a database. That means writing HTML in a &lt;code&gt;TEXTAREA&lt;/code&gt;. Yuck! Many of them have been updated to include a &lt;abbr title="What You See Is What You Get"&gt;WYSIWYG&lt;/abbr&gt; editor, be it &lt;a href="http://www.ephox.com/solutions/java_developers.html"&gt;Java&lt;/a&gt; or &lt;a href="http://tinymce.moxiecode.com/"&gt;JavaScript&lt;/a&gt;-based. As good as they are, I still yearn for code. Pure, unadulterated, geeky, I'm-in-total-control ... code.
&lt;/p&gt;
&lt;p&gt;
  Even with a fancy &lt;abbr title="What You See Is What You Get"&gt;WYSIWYG&lt;/abbr&gt; editor at my disposal, I turn it off. A plain old &lt;code&gt;TEXTAREA&lt;/code&gt; will suffice, but I miss the coding assistance of a real text editor like &lt;a href="http://chami.com/html-kit/"&gt;HTML Kit&lt;/a&gt;. I want complete control of my code, and I want a smart code editor all on a Web page. So I built one.&lt;/p&gt;
&lt;h5 class="entry-subtitle2"&gt;
  Features of the JavaScript TextEditor:
&lt;/h5&gt;
&lt;ul class="paragraph"&gt;
  &lt;li&gt;
    &lt;strong&gt;U&lt;/strong&gt;&lt;strong&gt;nobtrusive JavaScript&lt;/strong&gt;. No need to clutter up your &lt;abbr title="Hyper Text Markup Language"&gt;HTML&lt;/abbr&gt; with event handlers.
  &lt;/li&gt;
  &lt;li&gt;
    &lt;strong&gt;O&lt;/strong&gt;&lt;strong&gt;bject-oriented JavaScript.&lt;/strong&gt; Helps keep the global JavaScript namespace clean and tidy, and simplifies interacting with the editor using JavaScript.
  &lt;/li&gt;
  &lt;li&gt;
    &lt;strong&gt;Create as many code editors as you want.&lt;/strong&gt; Want more than one code editor on a page? No problem. Have as many as you want.
  &lt;/li&gt;
  &lt;li&gt;
    &lt;strong&gt;Create &lt;/strong&gt;&lt;strong&gt;&lt;abbr title="Hyper Text Markup Language"&gt;HTML&lt;/abbr&gt; tags in upper or lower case.&lt;/strong&gt; The &lt;a href="http://www.w3.org/TR/html4/strict.dtd"&gt;HTML 4.01 doctype&lt;/a&gt; declares &lt;abbr title="Hyper Text Markup Language"&gt;HTML&lt;/abbr&gt; tags in upper case even though they aren't case sensitive. You can have it either way.
  &lt;/li&gt;
  &lt;li&gt;
    &lt;strong&gt;Set tab stops.&lt;/strong&gt; When you press the TAB key, it inserts enough spaces to get to the next tab stop. Nice for indenting code.
  &lt;/li&gt;
  &lt;li&gt;
    &lt;strong&gt;Block Indent.&lt;/strong&gt; Select several lines of code and hit the TAB key to indent all the lines, or hold the Shift key and hit TAB to unindent each line by one tab stop.
  &lt;/li&gt;
  &lt;li&gt;
    &lt;strong&gt;Auto-Indent.&lt;/strong&gt; When you press the ENTER or RETURN keys, the cursor and code is indented automatically to where you were on the previous line.
  &lt;/li&gt;
  &lt;li&gt;
    &lt;strong&gt;Auto-Complete.&lt;/strong&gt; Greatly speed up your coding by typing an &lt;abbr title="Hyper Text Markup Language"&gt;HTML&lt;/abbr&gt; tag name, highlighting it, then holding the Ctrl and Shift keys down and pressing the "&amp;lt;" key. BAM! Automatic opening and closing tags are created, plus commonly used attributes, and applicable child tags.
  &lt;/li&gt;
  &lt;li&gt;
    &lt;strong&gt;&lt;abbr title="eXtensible Hyper Text Markup Language"&gt;XHTML&lt;/abbr&gt; compatible&lt;/strong&gt;. The auto complete feature is &lt;abbr title="eXtensible Hyper Text Markup Language"&gt;XHTML&lt;/abbr&gt; aware.
  &lt;/li&gt;
  &lt;li&gt;
    &lt;strong&gt;Tabify and Detabify.&lt;/strong&gt; Did someone actually use &lt;em&gt;real&lt;/em&gt; TAB characters to indent the code!? *gasp* Functions are included to convert those pesky tabs to tab stops, and then back again. You'll have to provide the button and the onclick, but the function is available.
  &lt;/li&gt;
  &lt;li&gt;
    &lt;strong&gt;Escape and Unescape HTML.&lt;/strong&gt; Does just what it says: Converts "&amp;amp;", "&amp;lt;" and "&amp;gt;" characters to &lt;abbr title="Hyper Text Markup Language"&gt;HTML&lt;/abbr&gt; entities, and you can change them back again. Of course you'll need to supply your own button and onclick, but the function is there.
  &lt;/li&gt;
  &lt;li&gt;
    &lt;strong&gt;Convert newlines to &lt;code&gt;&amp;lt;br&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt;.&lt;/strong&gt; Select a bunch of text, and a function can convert all newline characters to page break and paragraph tags. You'll need to create the button and onclick.
  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
  The JavaScript TextEditor is completely customizable. When creating it, you can pass several options on a case-by-case basis so every editor can be different.
&lt;/p&gt;
&lt;h5 class="entry-subtitle2"&gt;
  Browser support for version 0.1
&lt;/h5&gt;
&lt;p&gt;
  It's an early version and works only in Opera and Firefox on Windows. I tested Safari 3.03 on Windows and found a bug . The Control, Shift and Alt keys do not generate keydown, keypress or keyup events on &lt;code&gt;TEXTAREA&lt;/code&gt;'s, so the auto complete feature doesn't work, but tab stops and auto indent do. I've reported the bug to Apple.
&lt;/p&gt;
&lt;p&gt;
  Mac OS support is upcoming. I need to turn off my PC and fire up my Mac. TextEditor might work on Mac OS right now, but I'll have to double check the keyCodes generated by the &lt;code&gt;event&lt;/code&gt; object so the Control, Shift and Tab keys are captured properly.
&lt;/p&gt;
&lt;p&gt;
  Internet Explorer users? Well. Your browser sucks and doesn't support the standard methods used to manipulate text in the TEXTAREA, but fear not, Internet Explorer support is pending too. But enough yackin', let's see the code:
&lt;/p&gt;
&lt;h5 class="entry-subtitle2"&gt;
  Source code for the JavaScript TextEditor
&lt;/h5&gt;
&lt;p&gt;
  Just click on the box below to select it, then copy.
&lt;/p&gt;
&lt;p class="expando"&gt;
  &lt;textarea name="txt_code" cols="40" rows="30" readonly onclick="this.select();" onfocus="this.select();" class="code-block"&gt;/*

Author: Greg Burghardt
greg [underscore] burghardt [at] yahoo [dot] com
Copyright 2007, Greg Burghardt

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

http://www.gnu.org/licenses/lgpl.txt

*/


/**
 * @author    Greg Burghardt
 * @email     greg [underscore] burghardt [at] yahoo [dot] com
 * @url       fundamentaldisaster.blogspot.com
 * @date      Sept. 26, 2007
 * @version   0.1
 *
 *
 * @constructor   TextEditor
 *    Creates a text editor that contains many of the features a desktop
 *    application has.
 *
 * @param   editor (string or object, required)
 *    Id or node reference to the TEXTAREA used as a code editor.
 *
 * @param   options (object, optional)
 *    An object containing additional configuration options. The options
 *    parameter may contain the following properties and values:
 *
 *    enableAutoIndent (boolean)  Turn auto indenting on or off
 *    tabStop (integer)  Number of space characters each tab is worth.
 *
 *
 * @property  capitalizeTagName (boolean)
 *    HTML tag names will be capitalized when using auto-complete.
 *
 * @property  enableAutoIndent (boolean)
 *    Enable or disable auto indent on the editor.
 *
 * @property  enabled (boolean)
 *    Whether or not the current instance of TextEditor is enabled for the
 *    TEXTAREA.
 *
 * @property  editor (object)
 *    Node reference to the TEXTAREA object that is the code editor.
 *
 * @property  editorLineHeight (number)
 *    The height in pixels of a line of text in the editor. This is only used
 *    for Gecko browsers, which scroll to the top of the TEXTAREA whenever
 *    text is inserted. This allows the JavaScript to scroll down one line
 *    when the user presses the ENTER key.
 *
 * @property  editorMode (string)
 *    Can be "HTML" or "XHTML". When set to XHTML, the auto complete tags are
 *    XHTML compatible.
 *
 * @property  isIE (boolean)
 *    True if the browser is Internet Explorer, false otherwise.
 *
 * @property  isOpera (boolean)
 *    True if the browser is Opera.
 *
 * @property  isSupported (boolean)
 *    True if the browser supports all the API, false otherwise. Current
 *    Internet Explorer is not supported.
 *
 * @property  KEY_CODES (object, constant)
 *    An object containing the keyCode values for various keys on the
 *    keyboard. Initially this property is null, as different browsers on
 *    different operating systems use different values.
 *
 * @property  KEY_CODES_GECKO (object, constant)
 *    The keyCode values known to be used by the Gecko (Firefox) rendering
 *    engine.
 *
 * @property  KEY_CODES_OPERA (object, constant)
 *    The keyCode values known to be used by the Opera browser.
 *
 * @property  KEY_CODES_WEBKIT (object, constant)
 *    The keyCode values known to be used by the Webkit (Safari) rendering
 *    engine.
 *
 * @property  KEY_STATES (object)
 *    Tells when the SHIFT, TAB or CONTROL keys are down.
 *
 * @property  tabStop (integer)
 *    Number of spaces a tab stop should be.
 *
 * @property  TAGS_EMPTY (array, constant)
 *    Array of HTML tags that are empty elements, which have no closing tag
 *    and must be closed with XHTML.
 *
 * @property  TAGS_WITH_OPTIONS (array, constant)
 *    Array of HTML tags and special characters that have additional markup
 *    for the auto-complete.
 *
 * @property  version (float)
 *    The current version of the TextEditor class.
 *
 */
function TextEditor(editor, options) {
  var prop;
  var editorBoxes;
  var i = 0;
  var end = 0;
  if (this.isSupported) {
    
    // Set unique properties
    this.capitalizeTagNames = false;
    this.enableAutoIndent = true;
    this.enabled = false;
    this.editor = typeof(editor) === 'string' ? document.getElementById(editor) : editor;
    this.editorLineHeight = -1;
    this.editorMode = 'HTML';
    this.tabStop = 2;
    
    // Do not support Internet Explorer for right now...
    if (typeof(this.editor.setSelectionRange) === 'function') {
      // Set the options
      if (options) {
        for (prop in options) {
          this[prop] = options[prop];
        }
        this.editorMode = this.editorMode.toUpperCase();
      }
      
      // Assign correct key codes
      if (navigator.userAgent.indexOf('Gecko') &amp;gt; -1 || navigator.userAgent.indexOf('WebKit') &amp;gt; -1) {
        this.KEY_CODES = this.KEY_CODES_GECKO;
      } else if (window.opera || navigator.userAgent.indexof('Opera') &amp;gt; -1) {
        this.KEY_CODES = this.KEY_CODES_OPERA;
      } else {
        this.KEY_CODES = this.KEY_CODES_GECKO;
      }
      
      // Assign event handlers to the editor
      this.editor.onkeydown = this.getEditorKeyDownFn(this);
      this.editor.onkeyup = this.getEditorKeyUpFn(this);
      
      // Attaches functions as a hack to get Opera to disable the TAB key
      if (this.isOpera) {
        this.editor.onblur = this.getEditorBlurFn(this.KEY_CODES.TAB);
        this.editor.onfocus = this.getEditorFocusFn();
      }
      
      this.enabled = true;
    } else {
      this.isSupported = false;
    }
  }
}


TextEditor.prototype = {
  isSupported: !!document.getElementById,
  isIE: document.getElementById &amp;amp;&amp;amp; document.all &amp;amp;&amp;amp; document.selection &amp;amp;&amp;amp; window.ActiveX &amp;amp;&amp;amp; !window.opera ? true : false,
  isOpera: window.opera ? true : false,
  KEY_CODES: null,
  KEY_CODES_GECKO: {
    ANGLE_BRACKET_LEFT: 188,
    ANGLE_BRACKET_RIGHT: 190,
    ENTER: 13,
    ALT: 18,
    CONTROL: 17,
    CURLY_BRACE_LEFT: 219,
    CURLY_BRACE_RIGHT: 221,
    SHIFT: 16,
    TAB: 9
  },
  KEY_CODES_OPERA: {
    ANGLE_BRACKET_LEFT: 44,
    ANGLE_BRACKET_RIGHT: 46,
    ENTER: 13,
    ALT: 18,
    CONTROL: 17,
    CURLY_BRACE_LEFT: 91,
    CURLY_BRACE_RIGHT: 93,
    SHIFT: 16,
    TAB: 9
  },
  KEY_CODES_WEBKIT: {
    ANGLE_BRACKET_LEFT: 188,
    ANGLE_BRACKET_RIGHT: 190,
    ENTER: 13,
    ALT: 18,
    CONTROL: 17,
    CURLY_BRACE_LEFT: 219,
    CURLY_BRACE_RIGHT: 221,
    SHIFT: 16,
    TAB: 9
  },
  KEY_STATES: {
    ALT_DOWN: false,
    CONTROL_DOWN: false,
    SHIFT_DOWN: false
  },
  TAGS_EMPTY: ['base','br','hr','img','input','link','meta','param'],
  TAGS_WITH_OPTIONS: ['a','abbr','acronym','blockquote','button','div','dl','fieldset','form','iframe','img','input','link','label','meta','ol','optgroup','option','param','php','script','select','span','style','table','tbody','td','textarea','tfoot','thead','tr','ul','!','=','%'],
  version: 0.1,
  
  
  /**
   * @class     TextEditor
   *
   * @function  changeEditorMode
   *    Switches the editor mode.
   *
   * @param   currentMode (string, required)
   *    The current mode.
   *
   * @return  string
   *    The new editor mode.
   */
  changeEditorMode: function(currentMode) {
    this.editorMode = currentMode.toUpperCase() === 'XHTML' ? 'HTML' : 'XHTML';
    return this.editorMode;
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  changeTabStop
   *    Changes the tab stop used in the editor.
   *
   * @param   newStop (number, required)
   *    Number of spaces the new tab stop will be.
   *
   * @return  void
   */
  changeTabStop: function(newStop) {
    if (typeof(newStop) === 'number' &amp;amp;&amp;amp; newStop &amp;gt; 0) {
      this.tabStop = newStop;
    }
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  convertToParagraphs
   *    Takes the selected text and converts newlines into paragraphs.
   *
   * @param   void
   *
   * @return  void
   */
  convertToParagraphs: function() {
    var value = this.getSelectedText();
    var start = this.editor.selectionStart;
    
    value = this.nl2p(value);
    
    this.insertText(value);
    this.editor.setSelectionRange(start, start + value.length);
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  createTag
   *    Creates markup tags and sets the cursor.
   *
   * @param   tagName (string, required)
   *    Text to be used as the HTML tag.
   */
  createTag: function(tagName) {
    var tagIndex = this.getIndex(tagName, this.TAGS_WITH_OPTIONS);
    var tagStr = '';
    var tabStop = this.repeatChars(this.tabStop);
    var allCaps = this.editorMode === 'HTML' &amp;amp;&amp;amp; this.capitalizeTagNames ? true : false;
    var emptyTagClose = this.editorMode === 'XHTML' ? ' /&amp;gt;' : '&amp;gt;';
    
    if (this.editorMode === 'HTML' &amp;amp;&amp;amp; this.capitalizeTagNames) {
      tagName = tagName.toUpperCase();
    } else {
      tagName = tagName.toLowerCase();
    }
    
    if (tagIndex === -1) {
      // Tag isn't special, just open and close it.
      if (this.getIndex(tagName, this.TAGS_EMPTY) &amp;lt; 0) {
        tagStr = '&amp;lt;'+tagName+'&amp;gt;|&amp;lt;/'+tagName+'&amp;gt;';
      } else {
        tagStr = '&amp;lt;'+tagName+emptyTagClose+'|';
      }
    } else {
      // The following tags are special cases, additional markup is created
      switch (tagName.toLowerCase()) {
        case 'a':
          tagStr = '&amp;lt;'+tagName+' href=""&amp;gt;|&amp;lt;/a&amp;gt;';
          break;
        
        case 'abbr':
        case 'acronym':
          tagStr = '&amp;lt;'+tagName+' title="|"&amp;gt;&amp;lt;/'+tagName+'&amp;gt;';
          break;
        
        case 'blockquote':
          tagStr = '&amp;lt;'+tagName+' cite=""&amp;gt;|&amp;lt;/'+tagName+'&amp;gt;';
          break;
        
        case 'button':
          tagStr = '&amp;lt;'+tagName+' type="|" value=""&amp;gt;&amp;lt;/'+tagName+'&amp;gt;';
          break;
        
        case 'div':
        case 'span':
          tagStr = '&amp;lt;'+tagName+'|&amp;gt;&amp;lt;/'+tagName+'&amp;gt;';
          break;
        
        case 'dl':
          if (!allCaps) {
            tagStr = '&amp;lt;dl&amp;gt;\n'+tabStop+'&amp;lt;dt&amp;gt;|&amp;lt;/dt&amp;gt;\n'+tabStop+'&amp;lt;dd&amp;gt;&amp;lt;/dd&amp;gt;\n&amp;lt;/dl&amp;gt;';
          } else {
            tagStr = '&amp;lt;DL&amp;gt;\n'+tabStop+'&amp;lt;DT&amp;gt;|&amp;lt;/DT&amp;gt;\n'+tabStop+'&amp;lt;DD&amp;gt;&amp;lt;/DD&amp;gt;\n&amp;lt;/DL&amp;gt;';
          }
          break;
        
        case 'fieldset':
          if (!allCaps) {
            tagStr = '&amp;lt;'+tagName+'&amp;gt;\n'+tabStop+'&amp;lt;legend&amp;gt;|&amp;lt;/legend&amp;gt;\n&amp;lt;/'+tagName+'&amp;gt;';
          } else {
            tagStr = '&amp;lt;'+tagName+'&amp;gt;\n'+tabStop+'&amp;lt;LEGEND&amp;gt;|&amp;lt;/LEGEND&amp;gt;\n&amp;lt;/'+tagName+'&amp;gt;';
          }
          break;
        
        case 'form':
          tagStr = '&amp;lt;'+tagName+' method="post" action="" id=""&amp;gt;|&amp;lt;/'+tagName+'&amp;gt;';
          break;
        
        case 'iframe':
          tagStr = '&amp;lt;'+tagName+' src="|" width="" height="" name="" id="" frameborder="0"&amp;gt;&amp;lt;/'+tagName+'&amp;gt;';
          break;
        
        case 'img':
          tagStr = '&amp;lt;'+tagName+' src="|" width="" height="" alt=""' + emptyTagClose;
          break;
        
        case 'input':
          tagStr = '&amp;lt;'+tagName+' type="|" name="" id="" value=""' + emptyTagClose;
          break;
        
        case 'link':
          tagStr = '&amp;lt;'+tagName+' rel="stylesheet" type="text/css" media="screen" href="|"' + emptyTagClose;
          break;
        
        case 'label':
          tagStr = '&amp;lt;'+tagName+' for=""&amp;gt;|&amp;lt;/'+tagName+'&amp;gt;';
          break;
        
        case 'meta':
          tagStr = '&amp;lt;'+tagName+' name="|" content=""' + emptyTagClose;
          break;
        
        case 'ol':
        case 'ul':
          if (!allCaps) {
            tagStr = '&amp;lt;'+tagName+'&amp;gt;\n'+tabStop+'&amp;lt;li&amp;gt;&amp;lt;/li&amp;gt;|\n&amp;lt;/'+tagName+'&amp;gt;';
          } else {
            tagStr = '&amp;lt;'+tagName+'&amp;gt;\n'+tabStop+'&amp;lt;LI&amp;gt;&amp;lt;/LI&amp;gt;|\n&amp;lt;/'+tagName+'&amp;gt;';
          }
          break;
        
        case 'optgroup':
          if (!allCaps) {
            tagStr = '&amp;lt;'+tagName+' label="|"&amp;gt;\n'+tabStop+'&amp;lt;option value=""&amp;gt;&amp;lt;/option&amp;gt;\n&amp;lt;/'+tagName+'&amp;gt;';
          } else {
            tagStr = '&amp;lt;'+tagName+' label="|"&amp;gt;\n'+tabStop+'&amp;lt;OPTION value=""&amp;gt;&amp;lt;/OPTION&amp;gt;\n&amp;lt;/'+tagName+'&amp;gt;';
          }
          break;
        
        case 'option':
          tagStr = '&amp;lt;'+tagName+' value="|"&amp;gt;&amp;lt;/'+tagName+'&amp;gt;';
          break;
        
        case 'param':
          tagStr = '&amp;lt;'+tagName+' name="|" value=""' + emptyTagClose;
          break;
        
        case 'php':
          tagStr = '&amp;lt;?php|?&amp;gt;';
          break;
        
        case '=':
          tagStr = '&amp;lt;?=|?&amp;gt;';
          break;
        
        case 'script':
          tagStr = tagStr = '&amp;lt;'+tagName+' type="text/javascript"&amp;gt;|&amp;lt;/'+tagName+'&amp;gt;';
          break;
        
        case 'select':
          if (!allCaps) {
            tagStr = '&amp;lt;'+tagName+' name="" id=""&amp;gt;\n'+tabStop+'&amp;lt;option value=""&amp;gt;&amp;lt;/option&amp;gt;|\n&amp;lt;/'+tagName+'&amp;gt;';
          } else {
            tagStr = '&amp;lt;'+tagName+' name="" id=""&amp;gt;\n'+tabStop+'&amp;lt;OPTION value=""&amp;gt;&amp;lt;/OPTION&amp;gt;|\n&amp;lt;/'+tagName+'&amp;gt;';
          }
          break;
        
        case 'style':
          tagStr = '&amp;lt;'+tagName+' type="text/css" media="screen"&amp;gt;|&amp;lt;/'+tagName+'&amp;gt;';
          break;
        
        case 'table':
          tagStr = '&amp;lt;'+tagName+' cellpadding="0" cellspacing="0" border="0"&amp;gt;|&amp;lt;/'+tagName+'&amp;gt;';
          break;
        
        case 'tbody':
          if (!allCaps) {
            tagStr = '&amp;lt;'+tagName+'&amp;gt;\n'+tabStop+'&amp;lt;tr&amp;gt;\n'+tabStop+tabStop+'&amp;lt;td headers=""&amp;gt;&amp;lt;/td&amp;gt;|\n'+tabStop+'&amp;lt;/tr&amp;gt;\n&amp;lt;/'+tagName+'&amp;gt;';
          } else {
            tagStr = '&amp;lt;'+tagName+'&amp;gt;\n'+tabStop+'&amp;lt;TR&amp;gt;\n'+tabStop+tabStop+'&amp;lt;TD headers=""&amp;gt;&amp;lt;/TD&amp;gt;|\n'+tabStop+'&amp;lt;/TR&amp;gt;\n&amp;lt;/'+tagName+'&amp;gt;';
          }
          break;
        
        case 'td':
          tagStr = '&amp;lt;'+tagName+' headers=""&amp;gt;|&amp;lt;/'+tagName+'&amp;gt;';
          break;
        
        case 'textarea':
          tagStr = '&amp;lt;'+tagName+' cols="50" rows="10" name="|" id=""&amp;gt;&amp;lt;/'+tagName+'&amp;gt;';
          break;
        
        case 'tfoot':
          if (!allCaps) {
            tagStr = '&amp;lt;'+tagName+'&amp;gt;\n'+tabStop+'&amp;lt;tr&amp;gt;\n'+tabStop+tabStop+'&amp;lt;th&amp;gt;&amp;lt;/th&amp;gt;|\n'+tabStop+'&amp;lt;/tr&amp;gt;\n&amp;lt;/'+tagName+'&amp;gt;';
          } else {
            tagStr = '&amp;lt;'+tagName+'&amp;gt;\n'+tabStop+'&amp;lt;TR&amp;gt;\n'+tabStop+tabStop+'&amp;lt;TH&amp;gt;&amp;lt;/TH&amp;gt;|\n'+tabStop+'&amp;lt;/TR&amp;gt;\n&amp;lt;/'+tagName+'&amp;gt;';
          }
          break;
        
        case 'thead':
          if (!allCaps) {
            tagStr = '&amp;lt;'+tagName+'&amp;gt;\n'+tabStop+'&amp;lt;tr&amp;gt;\n'+tabStop+tabStop+'&amp;lt;th id=""&amp;gt;&amp;lt;/th&amp;gt;|\n'+tabStop+'&amp;lt;/tr&amp;gt;\n&amp;lt;/'+tagName+'&amp;gt;';
          } else {
            tagStr = '&amp;lt;'+tagName+'&amp;gt;\n'+tabStop+'&amp;lt;TR&amp;gt;\n'+tabStop+tabStop+'&amp;lt;TH id=""&amp;gt;&amp;lt;/TH&amp;gt;|\n'+tabStop+'&amp;lt;/TR&amp;gt;\n&amp;lt;/'+tagName+'&amp;gt;';
          }
          break;
        
        case 'tr':
          if (!allCaps) {
            tagStr = '&amp;lt;'+tagName+'&amp;gt;\n'+tabStop+'&amp;lt;td headers=""&amp;gt;&amp;lt;/td&amp;gt;|\n&amp;lt;/'+tagName+'&amp;gt;';
          } else {
            tagStr = '&amp;lt;'+tagName+'&amp;gt;\n'+tabStop+'&amp;lt;TD headers=""&amp;gt;&amp;lt;/TD&amp;gt;|\n&amp;lt;/'+tagName+'&amp;gt;';
          }
          break;
        
        case '!':
          tagStr = '&amp;lt;!-- | --&amp;gt;';
          break;
        
        case '%':
          tagStr = '&amp;lt;%|%&amp;gt;';
          break;
        
      }
    }
    
    return tagStr;
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  countChars
   *    Counts the number of instances of the given character in the given
   *    string.
   *
   * @param   ch (string, required)
   *    The character to search for
   *
   * @param   str (string, required)
   *    The string to search in.
   *
   * @return  integer
   *    The number of times ch occured in str.
   */
  countChars: function(ch, str) {
    var i = 0;
    var end = str.length;
    var count = 0;
    
    for (i; i &amp;lt; end; i++) {
      if (str.charAt(i) == ch) {
        count++;
      }
    }
    
    return count;
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  destroy
   *    Should be called in window.onunload event to remove common causes of
   *    memory leaks in browsers.
   *
   * @param   void
   *
   * @return  void
   */
  destroy: function() {
    this.editor = null;
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  detabify
   *    Replaces all tab characters with a number of spaces equal to the
   *    tab stop.
   *
   * @param   void
   *
   * @return  void
   */
  detabify: function() {
    var selText = this.getSelectedText();
    var start = this.editor.selectionStart;
    
    selText = this.tab2Tabstop(selText);
    this.insertText(selText, null, null, false);
    this.editor.setSelectionRange(start, start + selText.length);
    this.setFocus();
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  doAutoIndent
   *    Creates the auto-indent when the user presses ENTER.
   *
   * @param   void
   *
   * @return  integer
   *    Number of spaces the auto-indent was.
   */
  doAutoIndent: function() {
    var ch = '';
    var i = 0;
    var indentLength = -1;
    var newlineFound = false;
    var start = this.editor.selectionStart;
    var value = this.editor.value;
    var valueLength = value.length;
    
    if (this.enableAutoIndent) {
      
      if (start === 0) {
        // Cursor is at text beginning, indent length is zero
        indentLength = 0;
      }
      
      // Detect auto indent if not already found
      if (indentLength &amp;lt; 0) {
        
        indentLength = 0;
        
        if (start &amp;gt; 1 &amp;amp;&amp;amp; value.length &amp;gt; 1) {
          // Cursor is at text end
          i = start - 2;
        } else {
          // Cursor is not at newline or end
          i = start;
        }
        
        // Go back to beginning of current line
        while (i &amp;gt; 0 &amp;amp;&amp;amp; !newlineFound) {
          if (value.charAt(i) === '\n') {
            newlineFound = true;
          }
          i--;
        }
        
        if (newlineFound) {
          // Not at beginning of text, go 1 char past newline
          i += 2;
        } else {
          // No newline was found, at begining of text
          i = 0;
        }
        
        // Get the current char
        ch = value.charAt(i);
        
        // Go forward until non white space char is found or cursor is
        // reached, count iterations
        while(i &amp;lt; start &amp;amp;&amp;amp; ch === ' ') {
          indentLength++;
          i++;
          ch = value.charAt(i);
        }
      }
      
      // Insert the text
      if (indentLength &amp;gt; 0) {
        if (start == this.editor.selectionStart) {
          start += indentLength;
        }
        this.insertText(this.repeatChars(indentLength), null, null, false);
        this.editor.setSelectionRange(start, start);
      }
    }
    
    return indentLength;
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  doBlockIndent
   *    Indents a block of text backward or forward.
   *
   * @param   backward (boolean, optional)
   *    Indents text backwards if true, forwards if false. Default is false.
   *
   * @return  void
   */
  doBlockIndent: function(backward) {
    
    // Shared
    var start = start = this.getLineStartPosition(this.editor.value, this.editor.selectionStart);
    var end = this.getLineEndPosition(this.editor.value, this.editor.selectionEnd);
    var ch = this.editor.value.charAt(start);
    var curPos = start;
    var value = '';
    var valueLength = this.editor.value.length;
    
    // Indenting forwards
    var endOffset = 0;
    var tabStopStr = this.repeatChars(this.tabStop);
    
    // Indenting backwards
    var snippetEnd = 0;
    var snippetStr = '';
    var txtLinesLength = 0;
    var txtLines = [];
    var i = 0;
    var numCharsRemoved = 0;
    
    start = this.getLineStartPosition(this.editor.value, start);
    end = this.getLineEndPosition(this.editor.value, end);
    
    this.editor.setSelectionRange(start, end);
    
    value = this.editor.value.substring(start, end);
    
    if (backward) {
      // Indent backwards
      txtLines = value.split('\n');
      txtLinesLength = txtLines.length;
      for (i = 0; i &amp;lt; txtLinesLength; i++) {
        snippetStr = txtLines[i];
        snippetEnd = 0;
        while (snippetEnd &amp;lt; this.tabStop &amp;amp;&amp;amp; snippetStr.charAt(snippetEnd) === ' ') {
          snippetEnd++;
          numCharsRemoved++;
        }
        if (snippetEnd &amp;gt; 0) {
          txtLines[i] = snippetStr.substring(snippetEnd, snippetStr.length);
        }
      }
      
      value = txtLines.join('\n');
      
    } else {
      // Indent forwards
      endOffset += this.countChars('\n', value) * this.tabStop;
      value = value.replace(/\n/g, '\n' + tabStopStr);
      value = tabStopStr + value;
      endOffset += this.tabStop;
    }
    this.insertText(value, null, null, false);
    this.editor.setSelectionRange(start, end + endOffset - numCharsRemoved);
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  editorOnKeyDown
   *    The function executed every time a keyboard button is pressed.
   *
   * @param   e (object, required)
   *    Reference to the event object generated by the keydown event.
   *
   * @return  boolean
   *    If false is returned, the button press event is canceled so
   *    JavaScript can do some custom work. True is returned so the pressed
   *    button acts normally.
   */
  editorOnKeyDown: function(e) {
    var r = true;
    var tagStr = '';
    
    // Hack for Opera so it disables the TAB key
    this.lastKey = e.keyCode;
    
    // Record states of keys on keyboard
    switch(e.keyCode) {
      case this.KEY_CODES.SHIFT:
        this.KEY_STATES.SHIFT_DOWN = true;
        break;
      case this.KEY_CODES.CONTROL:
        this.KEY_STATES.CONTROL_DOWN = true;
        break;
      case this.KEY_CODES.ALT:
        this.KEY_STATES.ALT_DOWN = true;
        break;
    }
    
    // Do actions for specific keys
    switch (e.keyCode) {
      
      case this.KEY_CODES.TAB:
          r = false;
          if (this.editor.selectionStart == this.editor.selectionEnd) {
            // Insert a tab stop
            this.insertText(this.repeatChars(this.getAutoTabLength()), null, null, true);
          } else {
            // Block indent forwards or backwards
            this.doBlockIndent(this.KEY_STATES.SHIFT_DOWN);
          }
        break;
      
      case this.KEY_CODES.ANGLE_BRACKET_LEFT:
        if (this.KEY_STATES.CONTROL_DOWN &amp;amp;&amp;amp; this.KEY_STATES.SHIFT_DOWN) {
          r = false;
          this.insertOpenCloseTags();
        } else if (this.KEY_STATES.CONTROL_DOWN) {
          r = false;
          this.insertOpenTag();
        }
        break;
      
      case this.KEY_CODES.ANGLE_BRACKET_RIGHT:
        if (this.KEY_STATES.CONTROL_DOWN &amp;amp;&amp;amp; this.KEY_STATES.SHIFT_DOWN) {
          r = false;
          this.insertClosedEmptyTag();
        } else if (this.KEY_STATES.CONTROL_DOWN) {
          r = false;
          this.insertCloseTag();
        }
        break;
      
    }
    
    return r;
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  editorOnKeyPressFn
   *    The function executed every time a keyboard button is pressed.
   *
   * @param   e (object, required)
   *    Reference to the event object generated by the keypress event.
   *
   * @return  boolean
   *    If false is returned, the button release event is canceled so
   *    JavaScript can do some custom work. True is returned so the released
   *    button acts normally.
   */
  editorOnKeyPress: function(e) {
    return true;
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  editorKeyUpFn
   *    The function executed every time a keyboard button is released.
   *
   * @param   e (object, required)
   *    Reference to the event object generated by the keyup event.
   *
   * @return  boolean
   *    If false is returned, the button release event is canceled so
   *    JavaScript can do some custom work. True is returned so the released
   *    button acts normally.
   */
  editorKeyUpFn: function(e) {
    var r = true;
    
    // Record states of keys on keyboard
    switch(e.keyCode) {
      case this.KEY_CODES.SHIFT:
        this.KEY_STATES.SHIFT_DOWN = false;
        break;
      case this.KEY_CODES.CONTROL:
        this.KEY_STATES.CONTROL_DOWN = false;
        break;
      case this.KEY_CODES.ALT:
        this.KEY_STATES.ALT_DOWN = false;
        break;
    }
    
    switch (e.keyCode) {
      
      case this.KEY_CODES.ENTER:
        this.doAutoIndent();
        break;
      
    }
    
    return r;
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  escape
   *    Escapes the text selected in the editor.
   *
   * @param   void
   *
   * @return  void
   */
  escape: function() {
    var escapeText = this.getSelectedText();
    var start = this.editor.selectionStart;
    escapeText = this.escapeHTML(escapeText);
    this.insertText(escapeText, null, null, true);
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  escapeHTML
   *    Converts special characters to HTML friendly characters.
   *
   * @param   str (string, required)
   *    The string to escape and make HTML friendly.
   *
   * @return  string
   *    The HTML escaped string.
   */
  escapeHTML: function(str) {
    str = str.replace(/&amp;amp;/g, '&amp;amp;amp;');
    str = str.replace(/&amp;gt;/g, '&amp;amp;gt;');
    str = str.replace(/&amp;lt;/g, '&amp;amp;lt;');
    return str;
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  focus
   *    Sets focus to the editor text field.
   *
   * @param   void
   *
   * @return  void
   */
  focus: function() {
    this.editor.focus();
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  getAutoTabLength
   *    Returns the length of the auto tab when you hit TAB.
   *
   * @param   void
   *
   * @return  integer
   *    The number of spaces for the auto tab.
   */
  getAutoTabLength: function() {
    var start = this.editor.selectionStart;
    var allText = this.editor.value;
    var lineStart = this.getLineStartPosition(allText, start);
    var lineOffset = start - lineStart;
    var indentLength = start - lineStart;
    var indentModulus = indentLength % this.tabStop;
    
    if (indentModulus === 0) {
      return this.tabStop;
    } else {
      return indentModulus;
    }
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  getComputedStyle
   *    Used to get the computed style of an element. This is only used in a
   *    hack to get Gecko browsers to refrain from scrolling the editor back
   *    to the top when text is inserted into the editor.
   *
   * @param   el (object, required)
   *    The DOM object to get the computed style of.
   *
   * @param   prop (string, required)
   *    The style property you want the value for.
   *
   * @return  variable
   *    The value of the property, most likely a string, or null if this
   *    function is not properly supported.
   */
  getComputedStyle: function(el, prop) {
    var val = null;
    if (document.defaultView &amp;amp;&amp;amp; document.defaultView.getComputedStyle) {
      val = document.defaultView.getComputedStyle(el, null)[prop];
    }
    return val;
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  getIndex
   *    Looks for the needle in the haystack and returns its index.
   *
   * @param   needle (variable, required)
   *    The value to look for.
   *
   * @param   haystack (array, required)
   *    The array in which to search.
   *
   * @return  integer
   *    The index at which the needle was found, or -1 if not found.
   */
  getIndex: function(needle, haystack) {
    var i = 0;
    var end = haystack.length;
    for (i; i &amp;lt; end; i++) {
      if (haystack[i] == needle) {
        return i;
      }
    }
    return -1;
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  getEditorBlurFn
   *    The onblur event handler for the editor TEXTAREA. This is used in
   *    conjunction with a small hack that allows Opera to "disable" the
   *    tab key.
   *
   * @param   void
   *
   * @return  void
   */
  getEditorBlurFn: function(TAB_KEY) {
    function doBlur(e) {
      if (!e) {
        e = window.event;
      }
      if (this.lastKey == TAB_KEY) {
        this.focus();
      }
    }
    return doBlur;
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  getEditorFocusFn
   *    The onfocus event handler for the editor TEXTAREA. This is used in
   *    conjunction with a small hack that allows Opera to "disable" the
   *    tab key.
   *
   * @param   void
   *
   * @return  void
   */
  getEditorFocusFn: function() {
    function doFocus(e) {
      this.lastKey = null;
    }
    return doFocus;
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  getEditorKeyDownFn
   *    Returns a function object executed every time a key is pressed down
   *    while the editor text box has focus.
   *
   * @param   instance (object, required)
   *    The current instance of this class.
   *
   * @return  function
   *    The function to be executed onkeydown. False is returned by the inner
   *    function for the cases where the default browser action for that
   *    pressed key should be canceled. Otherwise, true is returned so the
   *    default browser action for that key goes through.
   */
  getEditorKeyDownFn: function(instance) {
    function doKeyDown(e) {
      if (!e) {
        e = window.event;
      }
      this.lastKey = e.keyCode;
      return instance.editorOnKeyDown(e);
    }
    return doKeyDown;
  },
  
  
  
  /**
   * @class     TextEditor
   *
   * @function  getEditorKeyPressFn
   *    Returns a function object executed every time a key is pressed while
   *    the editor text box has focus.
   *
   * @param   instance (object, required)
   *    The current instance of this class.
   *
   * @return  function
   *    The function to be executed onkeypress. False is returned by the
   *    inner function for the cases where the default browser action for
   *    that pressed key should be canceled. Otherwise, true is returned so
   *    the default browser action for that key goes through.
   */
  getEditorKeyPressFn: function(instance) {
    function doKeyPress(e) {
      if (!e) {
        e = window.event;
      }
      return instance.editorOnKeyPress(e);
    }
    return doKeyPress;
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  getEditorKeyUpFn
   *    Returns a function object executed every time a key is released while
   *    the editor text box has focus.
   *
   * @param   instance (object, required)
   *    The current instance of this class.
   *
   * @return  function
   *    The function to be executed onkeyup. False is returned by the inner
   *    function for the cases where the default browser action for that
   *    pressed key should be canceled. Otherwise, true is returned so the
   *    default browser action for that key goes through.
   */
  getEditorKeyUpFn: function(instance) {
    function doEditorKeyUp(e) {
      var r = true;
      if (!e) {
        e = window.event;
      }
      instance.editorKeyUpFn(e);
    }
    return doEditorKeyUp;
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  getEditorLineHeight
   *    Returns the font size of the editor in pixels.
   *
   * @param   void
   *
   * @return  number
   *    The font size in pixels.
   */
  getEditorLineHeight: function() {
    if (this.editorLineHeight &amp;lt; 0 &amp;amp;&amp;amp; this.editorLineHeight != null) {
      this.editorLineHeight = parseFloat(this.getComputedStyle(this.editor, 'fontSize')) * 1.25;
    }
    return this.editorLineHeight;
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  getLineEndPosition
   *    Returns the position of the end of the current line of text. A line
   *    of text ends with a newline character or the end of the string.
   *
   * @param   str (string, required)
   *    The string in which to find the beginning of the text line.
   *
   * @param   position (integer, required)
   *    The position at which to start searching.
   *
   * @return  integer
   *    Position at which the line ending was found.
   */
  getLineEndPosition: function(str, position) {
    var curPos = position;
    var strEnd = str.length;
    var curChar = str.charAt(curPos);
    
    if (curPos &amp;gt;= strEnd) {
      return strEnd;
    } else if (curChar === '\n' || curChar === '\r') {
      return curPos;
    } else {
      while (curPos &amp;lt; strEnd) {
        curChar = str.charAt(curPos);
        if (curChar === '\n' || curChar === '\r') {
          return curPos;
        }
        curPos++;
      }
      return curPos;
    }
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  getLineStartPosition
   *    Returns the position of the beginning of the current line of text. A
   *    line of text begins with a non-newline character.
   *
   * @param   str (string, required)
   *    The string in which to find the beginning of the text line.
   *
   * @param   position (integer, required)
   *    The position at which to start searching.
   *
   * @return  integer
   *    Position at which the line beginning was found.
   */
  getLineStartPosition: function(str, position) {
    var curPos = position;
    var lineStartPos = 0;
    var curChar = str.charAt(curPos);
    
    if (curPos &amp;lt; 1) {
      lineStartPos = 0;
    } else if (curChar === '\n' || curChar === '\r') {
      curPos--;
    }
    
    while (curPos &amp;gt; 0) {
      curChar = str.charAt(curPos);
      if (curChar === '\n' || curChar === '\r') {
        lineStartPos = curPos + 1;
        break;
      }
      curPos--;
    }
    
    if (curPos &amp;lt; 1) {
      lineStartPos = 0;
    }
    
    return lineStartPos;
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  getSelectedText
   *    Gets the text currently selected in the editor.
   *
   * @param   void
   *
   * @return  string
   *    The selected text, or empty string of not text is selected.
   */
  getSelectedText: function() {
    if (this.editor.selectionStart &amp;lt; this.editor.selectionEnd) {
      return this.editor.value.substring(this.editor.selectionStart, this.editor.selectionEnd);
    } else {
      return '';
    }
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  insertClosedEmptyTag
   *    Use the highlighted text as the tag name for an empty element closed
   *    XHTML-style, i.e. "br" becomes "&amp;lt;br /&amp;gt;". 
   *
   * @param   void
   *
   * @return  void
   */
  insertClosedEmptyTag: function() {
    var start = this.editor.selectionStart;
    var tag = this.getSelectedText();
    this.insertText('&amp;lt;' + tag + ' /&amp;gt;', null, null, false);
    this.editor.selectionStart += tag.length + 1;
    this.editor.selectionEnd = this.editor.selectionStart;
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  insertCloseTag
   *    Use the highlighted text as a closing HTML tag.
   *
   * @param   void
   *
   * @return  void
   */
  insertCloseTag: function() {
    var start = this.editor.selectionStart;
    var tag = this.getSelectedText();
    if (this.editorMode === 'HTML' &amp;amp;&amp;amp; this.capitalizeTagNames) {
      tag = tag.toUpperCase();
    }
    this.insertText('&amp;lt;/' + tag + '&amp;gt;', null, null, false);
    this.editor.selectionStart += tag.length + 3;
    this.editor.selectionEnd = this.editor.selectionStart;
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  insertOpenCloseTags
   *    Use the highlighted text as the opening and closing HTML tags.
   *
   * @param   void
   *
   * @return  void
   */
  insertOpenCloseTags: function() {
    var tagStr = this.createTag(this.getSelectedText());
    var cursorIndex = tagStr.indexOf('|');
    var start = this.editor.selectionStart;
    tagStr = tagStr.replace('|', '');
    this.insertText(tagStr, null, null, false);
    this.editor.setSelectionRange(start + cursorIndex, start + cursorIndex);
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  insertOpenTag
   *    Use the highlighted text as the opening tag.
   *
   * @param   void
   *
   * @return  void
   */
  insertOpenTag: function() {
    var start = this.editor.selectionStart;
    var tag = this.getSelectedText();
    if (this.editorMode === 'HTML' &amp;amp;&amp;amp; this.capitalizeTagNames) {
      tag = tag.toUpperCase();
    }
    this.insertText('&amp;lt;' + tag + '&amp;gt;', null, null, false);
    this.editor.setSelectionRange(this.editor.selectionStart + tag.length + 1, this.editor.selectionStart);
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  insertText
   *    Inserts the given text at the cursor in the editor text box. If text
   *    is selected in the editor, the selected text is replaced by the
   *    string given here.
   *
   * @param   str (string, required)
   *    The text to be inserted.
   *
   *
   * @param   start (integer, optional)
   *    Index number in the string at which to start inserting text.
   *
   * @param   end (integer, optional)
   *    Index number of the end of the selection
   *
   * @return  void
   */
  insertText: function(str, start, end, setCursor) {
    var allText = this.editor.value;
    var allTextPrefix = '';
    var allTextSuffix = '';
    var scrollTop = this.editor.scrollTop;
    
    if (start == null) {
      var start = this.editor.selectionStart;
    }
    if (end == null) {
      var end = this.editor.selectionEnd;
    }
    if (setCursor == null) {
      var setCursor = true;
    }
    
    if (start &amp;gt; 0) {
      allTextPrefix = allText.substring(0, start);
    }
    if (end &amp;lt; allText.length) {
      allTextSuffix = allText.substring(end, allText.length);
    }
    
    this.editor.value = allTextPrefix + str + allTextSuffix;
    
    if (setCursor) {
      // If text was selected, reselect the inserted text
      if (start == end) {
        start = end = start + str.length;
      } else {
        end = start + str.length;
      }
      this.editor.setSelectionRange(start, end);
    }
    
    
    // Hack so Gecko browsers don't scroll to top after text is inserted
    if (this.editor.scrollTop === 0 &amp;amp;&amp;amp; this.editor.scrollHeight &amp;gt; this.editor.clientHeight) {
      if (str.indexOf('\n') &amp;gt; -1) {
        this.editor.scrollTop = scrollTop + this.getEditorLineHeight();
      } else {
        this.editor.scrollTop = scrollTop;
      }
    }
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  nl2br
   *    Converts all newline characters to &amp;lt;br&amp;gt; tags
   *
   * @param   str (string, required)
   *    The string in which all \n are replaced with &amp;lt;br&amp;gt;
   *
   * @param   br (string, optional)
   *    The &amp;lt;br&amp;gt; tag to use. If this is left off, then it will auto-create
   *    the &amp;lt;br&amp;gt; tag taking XHTML compatibility into account, and capitalizing
   *    the tag name if need be.
   *
   * @return  string
   *    The string with newlines converted to &amp;lt;br&amp;gt; tags
   */
  nl2br: function(str, br) {
    if (!br) {
      var br = '&amp;lt;br' + (this.editorMode === 'XHTML' ? ' /&amp;gt;' : '&amp;gt;');
    }
    if (str !== '') {
      return str.replace(/\n/g, br+'\n');
    } else {
      return '';
    }
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  nl2p
   *    Converts double newlines into paragraphs and single newlines into
   *    &amp;lt;br&amp;gt; tags.
   *
   * @param   str (string, required)
   *    The string in which to insert the &amp;lt;p&amp;gt; and &amp;lt;br&amp;gt; tags.
   *
   * @return  string
   *    The string with the &amp;lt;p&amp;gt; and &amp;lt;br&amp;gt; tags inserted.
   */
  nl2p: function(str) {
    var paragraphs = [];
    var br = '&amp;lt;br' + (this.editorMode === 'XHTML' ? ' /&amp;gt;' : '&amp;gt;');
    var i = 0;
    var end = 0;
    if (typeof(str) === 'string' &amp;amp;&amp;amp; str.length &amp;gt; 0) {
      paragraphs = str.split('\n\n');
      end = paragraphs.length;
      while (i &amp;lt; end) {
        if (paragraphs[i] !== '') {
          paragraphs[i] = this.createTag('p').replace('|', this.nl2br(paragraphs[i], br));
        } else {
          paragraphs[i] = this.createTag('p').replace('|', '&amp;amp;nbsp;');
        }
        if (i &amp;lt; end - 1) {
          paragraphs[i] += '\n\n';
        }
        i++;
      }
      str = paragraphs.join('');
    } else {
      str = '';
    }
    return str;
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  repeatChars
   *    Creates the tab stop when you hit tab.
   *
   * @param   numChars (integer, required)
   *    Number of characters to repeat.
   *
   * @param   ch (string, optional)
   *    The character or string to repeat. Default is a keyboard space.
   *
   * @return  string
   *    The tab stop measured in number of spaces.
   */
  repeatChars: function(numChars, ch) {
    var i = 0;
    var str = '';
    if (!ch) {
      ch = ' ';
    }
    while (i &amp;lt; numChars) {
      str += ch;
      i++;
    }
    return str;
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  selectCurrentLine
   *    Selects the current line of text in the editor.
   *
   * @param   void
   *
   * @return  void
   */
  selectCurrentLine: function() {
    var start = this.getLineStartPosition(this.editor.value, this.editor.selectionStart);
    var end = this.getLineEndPosition(this.editor.value, this.editor.selectionEnd);
    
    this.editor.setSelectionRange(start, end)
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  setFocus
   *    Sets focus to the code editor.
   *
   * @param   void
   *
   * @return  void
   */
  setFocus: function() {
    this.editor.focus();
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  tab2Tabstop
   *    Turns tabs into numbers of spaces equal to the tab stop.
   *
   * @param   str (string, required)
   *    The string to replace tabs with tab stops.
   *
   * @return  string
   *    The string with tabs replaced with tab stops.
   */
  tab2Tabstop: function(str) {
    var tabStopStr = this.repeatChars(this.tabStop);
    return str.replace(/\t/g, tabStopStr);
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  tabify
   *    Replaces numbers of spaces equal to the tab stop with tab characters.
   *
   * @param   void
   *
   * @return  void
   */
  tabify: function() {
    var selText = this.getSelectedText();
    var start = this.editor.selectionStart;
    
    selText = this.tabstop2Tab(selText);
    this.insertText(selText, null, null, false);
    this.editor.setSelectionRange(start, start + selText.length);
    this.setFocus();
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  tabify
   *    Turns numbers of spaces equal to the tab stop with tab characters.
   *
   * @param   str (string, required)
   *    The string to replace tab stops with tabs.
   *
   * @return  string
   *    The string with tab stops replaced with tabs.
   */
  tabstop2Tab: function(str) {
    var tabStopStr = this.repeatChars(this.tabStop);
    return str.replace(new RegExp(tabStopStr, 'g'), '\t');
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  unescape
   *    Unescapes the text selected in the editor.
   *
   * @param   void
   *
   * @return  void
   */
  unescape: function() {
    var escapeText = this.getSelectedText();
    var start = this.editor.selectionStart;
    escapeText = this.unescapeHTML(escapeText);
    this.insertText(escapeText, null, null, true);
  },
  
  
  /**
   * @class     TextEditor
   *
   * @function  unescapeHTML
   *    Converts escaped special characters back to HTML.
   *
   * @param   str (string, required)
   *    The string to unescape.
   *
   * @return  string
   *    The unescaped string.
   */
  unescapeHTML: function(str) {
    str = str.replace(/&amp;amp;gt;/g, '&amp;gt;');
    str = str.replace(/&amp;amp;lt;/g, '&amp;lt;');
    str = str.replace(/&amp;amp;amp;/g, '&amp;amp;');
    return str;
  }
  
};
&lt;/textarea&gt;
&lt;/p&gt;
&lt;h5 class="entry-subtitle2"&gt;
  Implementing the TextEditor
&lt;/h5&gt;
&lt;p&gt;
  Save the JavaScript code above as &lt;code&gt;TextEditor.js&lt;/code&gt; and include it in the &lt;code&gt;HEAD&lt;/code&gt; of any page you want JavaScript enhanced &lt;code&gt;TEXTAREA&lt;/code&gt;'s.
&lt;/p&gt;
&lt;pre class="code-block"&gt;
&amp;lt;script type="text/javascript"
src="TextEditor.js"&amp;gt;&amp;lt;/script&amp;gt;
&lt;/pre&gt;
&lt;p&gt;
  Next, you will need a &lt;code&gt;TEXTAREA&lt;/code&gt;:
&lt;/p&gt;
&lt;pre class="code-block"&gt;
&amp;lt;textarea name="body" cols="65" rows="20"
id="body_source"&amp;gt;&amp;lt;/textarea&amp;gt;
&lt;/pre&gt;
&lt;p&gt;
  Lastly, you'll need a bit of JavaScript in the &lt;code&gt;HEAD&lt;/code&gt; of your &lt;abbr title="Hyper Text Markup Language"&gt;HTML&lt;/abbr&gt; document to get things rolling:
&lt;/p&gt;
&lt;pre class="code-block"&gt;
&amp;lt;script type="text/javascript"&amp;gt;
window.onload = function() {
window.CodeEditor = new TextEditor("body_source");
};
&amp;lt;/script&amp;gt;
&lt;/pre&gt;
&lt;p&gt;
  You can then access that instance of the TextEditor with the global JavaScript variable &lt;code&gt;CodeEditor&lt;/code&gt;.
&lt;/p&gt;
&lt;pre class="code-block"&gt;
alert(CodeEditor.version);
&lt;/pre&gt;
&lt;h5 class="entry-subtitle2"&gt;
  Future development of TextEditor
&lt;/h5&gt;
&lt;p&gt;
  In stock for the first full release, version 1.0, is support for Mac OS and Linux. Next up for version 2.0 is support for Internet Explorer 5.5 and newer. I will also be writing an add-on class to create a user interface for TextEditor, which will create a semi-&lt;abbr title="What You See Is What You Get"&gt;WYSIWYG&lt;/abbr&gt; interface. Think the point and click BB Code editors you see in popular forum software, meets Dreamweaver &amp;mdash; and all in your Web browser. Since the basic functionality of the code editor is separate from the user interface, you can have just the code editor, or a full-blown point and click code editor. Upcoming features are:
&lt;/p&gt;
&lt;ul class="paragraph"&gt;
  &lt;li&gt;
    Mac OS and Linux browser support
  &lt;/li&gt;
  &lt;li&gt;
    Internet Explorer support
  &lt;/li&gt;
  &lt;li&gt;
    Point and click user interface to assist coding
  &lt;/li&gt;
  &lt;li&gt;
    Full documentation
  &lt;/li&gt;
  &lt;li&gt;
    Downloadable JavaScript files: Uncompressed with documentation, uncompressed without documentation, packed, obfuscated, and both packed and obfuscated.
  &lt;/li&gt;
  &lt;li&gt;
    Live preview. Will not require &lt;abbr title="Asynchronous Javascript And Xml"&gt;AJAX&lt;/abbr&gt;.
  &lt;/li&gt;
&lt;/ul&gt;
&lt;h5 class="entry-subtitle2"&gt;
  Who can use TextEditor
&lt;/h5&gt;
&lt;p&gt;
  This script is released under the &lt;abbr title="Lesser General Public License"&gt;LGPL&lt;/abbr&gt; license and is free for commercial and non-commercial use. This is still in development so check back again for updates. Any updates to this script will be posted on this blog post.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1829691255062570719-5509883106938926392?l=fundamentaldisaster.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fundamentaldisaster.blogspot.com/feeds/5509883106938926392/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1829691255062570719&amp;postID=5509883106938926392' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1829691255062570719/posts/default/5509883106938926392'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1829691255062570719/posts/default/5509883106938926392'/><link rel='alternate' type='text/html' href='http://fundamentaldisaster.blogspot.com/2007/09/texteditor-free-unobtrusive-javascript.html' title='TextEditor: Free Unobtrusive JavaScript Code Editor Supporting Web Standards'/><author><name>Greg Burghardt</name><uri>http://www.blogger.com/profile/14825576215668294298</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1829691255062570719.post-4601590783388148480</id><published>2007-09-19T19:12:00.000-07:00</published><updated>2007-10-03T22:14:39.712-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='noob'/><category scheme='http://www.blogger.com/atom/ns#' term='firstpost'/><category scheme='http://www.blogger.com/atom/ns#' term='aboutme'/><title type='text'>My First Post!</title><content type='html'>&lt;p&gt;It's my first post! I just got this thrown together, so you'll have to forgive the default template design and the utter bullshit that is this post.&lt;/p&gt;

&lt;p&gt;When I'm done being a total geek with my latest JavaScript project, I'll post something more. I'm a front end Web developer by trade, but dabble in PHP and Perl. If it's about CSS, JavaScript or HTML, and any associated browser bugs, there's a good chance I know it, I've done it, ran into it, or am capable of pulling my hair out upon discovering it.&lt;/p&gt;

&lt;p&gt;Until next time, you stay classy... Internet.&lt;/p&gt;

&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;

&lt;p&gt;*Note to self... don't ever close another post with the previous sentence...*&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1829691255062570719-4601590783388148480?l=fundamentaldisaster.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1829691255062570719/posts/default/4601590783388148480'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1829691255062570719/posts/default/4601590783388148480'/><link rel='alternate' type='text/html' href='http://fundamentaldisaster.blogspot.com/2007/09/my-first-post.html' title='My First Post!'/><author><name>Greg Burghardt</name><uri>http://www.blogger.com/profile/14825576215668294298</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry></feed>
