My latest million dollar idea

January 30th, 2005

These ideas come to me at the oddest times, thoughts about how to make the world just a little better, or more often, how to make a piece of technology a bit more fun. My latest one happened when I was at MASS MoCA with a few friends. We were in a dark room where there was a video playing of a car full of fireworks exploding super-imposed over Times Square. At the end of the video it faded to black before repeating. But the room was still lit by the LCD projectors that couldn’t quite do “black.”

My million dollar idea would make LCD projectors go all the way black. It seems like a simple task, yet hasn’t been done to my knowledge.

If anyone manages to use this theory, I’d appreciate some credit, or royalties, though I know that by putting this out on my public blog, for all 2 readers to read, I’m essentially giving my idea away.

Here it goes.

Take an idea like those sunglasses that get darker when you walk outside and lighter when you go inside. As far as I know those are just a photo sensitive skin placed on the lens. If there were a way to tell those glasses to go totally dark immediately or totally light immediately you have just created an electronic shutter. All you need is some material that when electrically activated (or deactivated) goes completely opaque. Then you simply have to test the incoming signal to the projector and see if it is supposed to turn on any of its pixels. If the answer is no, then you activate the shutter. If a single pixel is supposed to be on, then you deactivate it. The benefit over a real shutter is simply that it shouldn’t increase the internal heat inside the projector where a physical barrier would.

Alright, time for bed for me, I’ll see if this still looks good in the morning.

Rediscovering JavaScript

January 30th, 2005

It’s been a long time since I played around with JavaScript. I was pretty much under the impression it was dead and basically made editing pages more difficult. When I would go back and try and update pages that I had written long ago with a smattering of script in the header, and some strewn throughout to make things happen, I basically found that it was just too much work for the benefit it provided. With CSS I could accomplish 90% of what I used to do with JavaScript and it was much easier to read and maintain.

I think I’m a born again JavaScript fiend. After recently discovering the great site Unobtrusive Javascript, I’m once again sold. This site makes it easy to separate the script from the CSS from the HTML, and all work harmoniously together.

After playing around with their method of separating CSS and JS from the HTML I was finally able to elegantly solve an issue I’ve been wanting a solution to for years. I love how gmail does the whole stack of cards thing with your email. But more than that I love how they show and hide parts of the page arbitrarily. When you are reading a message there is a nice little reply box down at the bottom that when you put your cursor in to write a reply gets bigger, but doesn’t refresh the page so you can continue to type. And when you want to look back through some old messages all you do is click on the stack of cards and viola there you go, your old messages are right there.

My dilemma was more simplistic. I need to make a large form that I wanted to display on a single page, but not force people to scroll down through the whole thing, and I didn’t want people to have to click through sections of it because I want people to go right where they need to go without having to navigate a menu if they don’t want to. And I wanted to allow people to check over the entire form before submitting it, so they could fill in the whole thing at once if they wanted to, or could submit just parts, and through the wonders of MYSQL they could come back later and finish up.

The solution I had in mind was to show the headings for the sections of the form, and then allow people to click on the header to expand or collapse the section of the form. In addition I wanted a way to expand and collapse the whole form so that if you wanted to jump around from one section to another you could with minimal scrolling.

JavaScript to the rescue.

Using the basic function provided by the fine folks over at Unobtrusive Javascript I was able to make a page where all h2 tags turn into buttons that expand and contract their sibling divs. Then after some trial and error as I got my mind wrapped around what they were doing, I was able to take h3 tags and make them expand and contract all of the divs that immediately proceed h2 tags. The beauty is that all the CSS and all of the JavaScript are in their own files, no body tag onload() functions, no extra classes or id’s even. When CSS is needed for a specific application it is called and generated by the javascript, and the javacript file itself tells the HTML page to load it when the window loads, so all you have to change in your HTML is to include a single line telling it where to find the JavaScript file.

Alright, enough talk here are the three files: (note this is part of a php file so the values for the form fields are self populating with php code, get rid of it if you don’t want this.)

First the HTML File:

<html>
<head>
</head>
<body>
<h3>Collapse All Sections</h3>
<form action="processupdates.php" method="post">
<h2>Personal Inforamtion</h2>
<div>
<label for="FirstName">First Name: </label>
<input type="text" id="FirstName" name="FirstName" value="First" size="30" maxlength="60" tabindex="1"/>
<label for="LastName">Last Name: </label>
<input type="text" id="LastName" name="LastName" value="last" size="30" maxlength="60" tabindex="2"/>
</div>
<h2>Other Inforamtion</h2>
<div>
<label for="FirstName">First Name: </label>
<input type="text" id="FirstName" name="FirstName" value="<? echo $line["FirstName"]; ?/>" size="30" maxlength="60" tabindex="1">
<label for="LastName">Last Name: </label>
<input type="text" id="LastName" name="LastName" value="<? echo $line["LastName"]; ?/>" size="30" maxlength="60" tabindex="2">
</div>
<h2>More Inforamtion</h2>
<div>
<label for="FirstName">First Name: </label>
<input type="text" id="FirstName" name="FirstName" value="<? echo $line["FirstName"]; ?/>" size="30" maxlength="60" tabindex="1">
<label for="LastName">Last Name: </label>
<input type="text" id="LastName" name="LastName" value="<? echo $line["LastName"]; ?/>" size="30" maxlength="60" tabindex="2">
</div>
<br />
<input type="submit" id="Save Application" value="submit"/>
</form>
<h3>Collapse All Sections</h3>
</body>
</html>

Next the CSS:

body{
background:#f8f8f8;
color:#333;
font-family:Arial, Helvetica, sans-serif;
}
h2{
font-size:110%;
font-weight:normal;
width: 40em;
}
h3{
font-size:110%;
font-weight:normal;
width: 40em;
}
.hidden{
display:none;
}
.shown{
display:block;
}
.trigger{
background:#ccf;
cursor:n-resize;
}
.open{
background:#66f;
cursor:s-resize;
}
.hover{
background:#99c;
}

Finally the JavaScript:

function collapse()
{
//Collapses and expands siblings of h2 tags in html file
if(!document.createTextNode){return;}
var heads=document.getElementsByTagName('h2');
for(var i=0;i<heads .length;i++)
{
//Figure out what should be opened and closed.
var tohide=heads[i].nextSibling;
while(tohide.nodeType!=1)
{
tohide=tohide.nextSibling;
}
//open all parts that should be open, and set their parents to be ready to close them
cssjs('add',tohide,'shown')
cssjs('add',heads[i],'trigger')
heads[i].tohide=tohide;
//Make them act more like links so the user gets a response
heads[i].onmouseover=function()
{
cssjs('add',this,'hover');
}
heads[i].onmouseout=function()
{
cssjs('remove',this,'hover');
}
heads[i].onclick=function()
{
if(cssjs('check',this.tohide,'hidden'))
{
cssjs('swap',this,'trigger','open');
cssjs('swap',this.tohide,'hidden','shown');
} else {
cssjs('swap',this,'open','trigger');
cssjs('swap',this.tohide,'shown','hidden');
}
}
}
var mainhead=document.getElementsByTagName('h3');
for(var i=0;i<mainhead.length;i++)
{
//run through and make h3's into close and open all links
cssjs('add',mainhead[i],'trigger');
this.innerHTML = 'Collapse all Sections';
mainhead[i].onmouseover=function()
{
cssjs('add',this,'hover');
}
mainhead[i].onmouseout=function()
{
cssjs('remove',this,'hover');
}
mainhead[i].onclick=function()
{
heads=document.getElementsByTagName('h2');
if(cssjs('check',this,'trigger'))
//This runs through and opens all sections cleaning up the h2's so that they are ready to close again
{
for(var j=0;j<heads.length;j++)
{
if(cssjs('check',heads[j],'trigger'))
{
cssjs('swap',heads[j],'trigger','open');
cssjs('swap',heads[j].tohide,'hidden','shown');
}
}
for(var l=0;l<mainhead.length;l++)
{
//Makes sure that all h3s are ready to close the sections
mainhead[l].innerHTML = 'Expand all Sections';
cssjs('swap',mainhead[l],'trigger','open');
}
} else {
//This runs through and closes all sections cleaning up the h2's so that they are ready to open again
for(var k=0;k<heads.length;k++)
{
if(cssjs('check',heads[k],'open'))
{
cssjs('swap',heads[k],'open','trigger');
cssjs('swap',heads[k].tohide,'shown','hidden');
}
}
for(var m=0;m<mainhead.length;m++)
{
//Makes sure that all h3s are ready to re-open the sections
cssjs('swap',mainhead[m],'open','trigger');
mainhead[m].innerHTML = 'Collapse all Sections';
}
}
}
}
}
function cssjs(a,o,c1,c2)
{
//Applies action a to object o by adding, removing, swapping, or checking for classes c1 or c2.
switch (a){
case 'swap':
o.className=!cssjs('check',o,c1)?o.className.replace(c2,c1):o.className.replace(c1,c2);
break;
case 'add':
if(!cssjs('check',o,c1)){o.className+=o.className?' '+c1:c1;}
break;
case 'remove':
var rep=o.className.match(' '+c1)?' '+c1:c1;
o.className=o.className.replace(rep,'');
break;
case 'check':
return new RegExp('b'+c1+'b').test(o.className)
break;
}
}
//make it all happen when the page loads
window.onload=collapse;