This is my personal blog. The views expressed on these pages are mine alone and not those of my employer.

Thursday, August 25, 2005

See a Sneak Preview of SpaceShipThree

Slashdot is carrying an article on Burt Rutan's SpaceShipThree, which would be an orbital alt.space vehicle. Rutan has been very mum on exactly how he would create an orbital craft, leaving some to wonder if it is possible to affordably achieve orbit rather than simply reaching the edge of space and comming back, as he did in his X Prize winning craft SpaceShipOne.

In the last year a company/design group named t/space has emerged, which NASA is partially funding to study cheaper and easier ways to reach orbit and service the International Space Station.

Most people don't realize that t/space and Burt Rutan are one and the same. t/space has prototyped and is creating an alt.space orbital craft, and has Rutan's design style and fingerprints all over it. I'll bet strong money that the design mapped out by t/space will be what SpaceShipThree basicly is. I've blogged more about this in the past at:

"Alternatives to NASA: Transformational Space"

That blog post points to videos, design documents, and opinions on what might be a preview of a SpaceShipThree-style craft, mapped out by t/space today.

AJAX Tutorial: Saving Session Across Page Loads Without Cookies, On The Client Side

This is a mini-tutorial on saving state across page loads on the client side, without using cookies so as to save large amounts of data beyond cookies size limits.

In AJAX, most of the action occurs inside a single web page. When a page is loaded, a new instance of the JavaScript interpreter is started. When you leave a page, jumping to Google for example, all of your JavaScript objects are completely cleared away; you lose all of your state. If you then hit the back button to go back from Google to your original AJAX application, you will find that the page actually completely reloads, calling your onload listener, and that any JavaScript objects you stored anywhere are gone.

This can be a pain. First, it's something that not all programmers are aware of, which can lead to errors, so it's important to know about. Second, user's see their state completely wiped out; when they go back to their AJAX application with the back button they see the original state of their program, not the last place they left it. Third, this can impact performance, since the AJAX application has to re-retrieve everything from the server rather than use its local state.

Finally, there are some libraries that try to solve the back/forward button issues that store local JavaScript state in order to do so; this means they are clobbered if you leave the page, losing all history state. There are some back/forward button libraries that work without internal state, loading everything from the anchor hash on a URL on each change, but these libraries are restricted in the amount of state information you can represent in a URL. To find a truly robust solution to the back/forward button issue, one that allows for large, sophisticated blocks of state to be passed to programmers on each history change, we must find a way to solve the state problem.

Are there ways to save state on the client between page loads, akin to a user-level session? This is something I have been exploring recently. Note that session level state is different than the holy grail of saving offline information; they are similar, but session level state only lasts for a single instance of the browser. When it is closed state is lost, while permanent offline storage of state is saved forever. I have some ideas on how to solve the offline storage issue that I will explore in future blog posts.

I have been surprised to find two different ways to achieve session level state, each with their own stregnths and weaknesses.

Method number one is to use an iframe in some special ways. First, this iframe must exist on page load (See "AJAX Tutorial: A Tale of Two IFrames (or, How To Control Your Browsers History" for details on the different kinds of iframes):
<html>
<body>
<iframe id="sessionFrame"></iframe>
</body>
</html>
Then, whenever you wish to record state that you want to save, you must write that state into the iframe in the following way, programatically:
var sessionFrame = document.getElementById("sessionFrame");
var doc = sessionFrame.contentDocument;
if (doc == undefined) { // Internet Explorer
doc = sessionFrame.contentWindow.document;
}

doc.open();
doc.write(someNewState);
doc.close();
What this does is to actually write your state into the browser's history queue. The doc.write() business creates an entirely fresh new document each time, which the browser dutifully saves into its history list. As you move around with the back and forward buttons, you will see the iframe update with each state change you have saved into the iframe. Every state change must be done as above, with an open(), write(), and close() sequence to create a fresh document.

The full code is a bit more complicated:
<html>
<head>
<script language="JavaScript">
function initialize() {
if (sessionExists() == false) {
saveState("Hello World 1");
// some browsers need a bit of a timeout
window.setTimeout("saveState('Hello World 2')", 300);
window.setTimeout("saveState('Hello World 3')", 600);
}
}

function getIFrameDocument() {
var historyFrame =
document.getElementById("historyFrame");
var doc = historyFrame.contentDocument;
if (doc == undefined) // Internet Explorer
doc = historyFrame.contentWindow.document;

return doc;
}

function sessionExists() {
var doc = getIFrameDocument();
try {
if (doc.body.innerHTML == "")
return false;
else
return true;
}
catch (exp) {
// sometimes an exception is thrown if a
// value is already in the iframe
return true;
}
}

function saveState(message) {
// get our template that we will
// write into the history iframe
var templateDiv =
document.getElementById("iframeTemplate");
var currentElement = templateDiv.firstChild;

// loop until we get a COMMENT_NODE
while (currentElement &&
currentElement.nodeType != 8) {
currentElement = currentElement.nextSibling;
}
var template = currentElement.nodeValue;

// replace the templated value in the
// constants with our new value
var newContent =
template.replace(/\%message\%/, message);

// now write out the new contents
var doc = getIFrameDocument();
doc.open();
doc.write(newContent);
doc.close();
}
</script>
</head>

<body onload="initialize()">
<div id="iframeTemplate">
<!--
<html>
<body>
<p>%message%</p>
</body>
</html>
-->
</div>

<iframe id="historyFrame"></iframe>
</body>

<html>
In the code above, we use a template to store what we will stick into the iframe (see "DHTML Templates Tutorial" for details on using templates). We also have a new method, sessionExists, that checks to see if we have ever written anything into this iframe before. If a user goes to this page, goes to Google, and then comes back, our page's onload listener will fire. We don't want to rewrite our values into the session, so we must have a way to know if we have ever written anything before. If we have not, then we write our test values in.

In production code you would hide the iframe.

Give the code a try, and feel free to use it (it's under a BSD license). The code writes three state changes into the iframe. Go to another website, such as Google, and then hit the back button to return to the page; you will see that all of the changes we wrote into the iframe persist. If you close the browser you will see they disappear, or if you type the website's address seperate from the history.

A major problem (or strength) with the iframe approach is that it affects the history, which can be a problem since we don't always want to tie session storage to the history.

The other session approach I've found is a crazy hack that I saw used for something else, in Danny Goodman's book JavaScript and DHTML Cookbook. Danny was looking for a way to pass data between frames, and he found that you could persist data by saving them into hidden text fields.

This is a beautiful (and scary) hack that is a solution to our session state. All the browsers I have tried (IE, Firefox, and Safari) persist any text you put into a form field, even if they are hidden. To save state, then, we can simply write it into hidden form fields!

I have done tests with the Lorem Ipsum generator to see how much data I can store in a textarea in Firefox and IE, and I couldn't find the upper bound. I had the generator give me about 1 meg of data, placed it into a textarea, and then moved away from the page and back and the data was still there! The data disappears when you close the browser, but this is perfect for saving our session state.

There is a small footnote, though. Basicly, the form and the textarea field that stores state must exist on page load; they can not be dynamically created through JavaScript, which makes using them a bit more difficult.

Here is some simple sample code that shows how you can persist state into a hidden form:


<html>
<head>
<script language="JavaScript">
function initialize() {
var sessionField =
document.getElementById("sessionField");
var sessionValue = sessionField.value;
if (sessionValue == "empty") {
alert("Storing new session value");
sessionField.value = "Hello World";
}
else {
alert("Old session value: " + sessionValue);
}
}
</script>
</head>

<body onload="initialize()">
<form style="display: none;" id="sessionForm">
<textarea id="sessionField">empty</textarea>
</form>
</body>
</html>


Give the demo a whirl as well. The first time you load the page a popup will appear that we are storing state for the first time. Next, if you reload the page or go to another website and then come back, the popup will reappear but will say that we retrieved the old session value, which is "Hello World".

This code is also free to use, under a BSD license.

This page is powered by Blogger. Isn't yours?

Subscribe to Posts [Atom]