Keeping the Web in Web 2.0
Designing user interaction for web applications
CHI 2008, April 5-10, Florence, Italy
Copyright is held by the author/owner(s)
ACM 08/0004
The Plan
Part 1: Introduction, Examples, and Theory
- Analysis of application state and its representation in
browser history and bookmarks.
- A conceptual framework for designing application state in
Ajax applications.
Part 2: Practice
- Illustration through examples.
- Casual introduction to the Javascript programming
language.
- Equally casual introduction to DHTML: HTML Document
Object Model (DOM) and event handling.
The Web Application Revolution, 1:
HTML, HTTP, URLs
Web pages replace the GUI of applications.
Advantages:
- Ubiquitous availability.
- Improved scalability because of stateless
application-layer protocol.
Disadvantages:
- Higher latency, less sophisticated interaction and
visual quality.
- Architectural difficulties because of poorly understood
statelessness of the protocol; a.k.a. server-side session
state.
Emergent Advantages of Web Applications
Two more properties of Web Application UIs emerged as
important:
- Generic unlimited undo: browser history.
- Navigate by Back, Forward, and
Go/Go to.
- Generic application state migration: bookmarks.
- Restore by loading from the bookmark URL.
The Web Application Revolution, 2:
Ajax
Ajax — Asynchronous Javascript
And XML
...but not really:
- CSS — Cascading Style Sheets
- DOM — Document Object Model
- data structure and API for structured text.
- JavaScript
- a nice language with an undeserved bad reputation.
- HTTP — Hypertext Transfer Protocol
- application communication with the server.
- Data Transfer Format
- XML, JavaScript object literals (JSON), etc.
Altogether, a powerful programming paradigm for web
applications.
The Web Application Revolution, 2:
Ajax
Application maintains specific interaction state on the
client side.
Advantages:
- Sophisticated UI, like desktop applications.
- Ubiquitous availability of classic web applications is
maintained.
Disadvantages:
- Browser history and bookmarks of classic web
applications are broken if not implemented
specifically.
For every problem, there is a solution that is easy
to understand, simple to implement, and wrong.
History versus Bookmarks, 1
Experiment:
- Load a page. »
- Scroll down.
- Go to another page. »
- Go back to the previous page.
Result:
- The scroll position is restored.
History versus Bookmarks, 2
Experiment:
- Load a page. »
- Scroll down.
- Bookmark it.
- Load the bookmarked page.
Result:
- You are at the top of the bookmarked page.
Conclusion:
- Some elements of state (such as scroll) are stored in
browser history but not represented in a bookmark.
Clicking versus Scrolling, 1
Experiment:
- Load a page. »
- Scroll down.
- Go back.
Result:
- You returned to the previous page.
Clicking versus Scrolling, 2
Experiment:
- Load a page with anchors. »
- Follow a link to an anchor on the same page. »
- Note that the URL has changed.
- Go back.
Result:
- You returned to the top of the same page.
Conclusion:
- A change to some elements of state change creates a new
browser history entry (e.g. page URL); changes to other
elements don't (scroll).
- Similar changes in view can be caused by changes in
different state elements (fragment identifier in the URL
vs. scroll).
Google Maps
Experiment:
- Load Google Maps. »
- Load a place, e.g. [Rome].
- Pan the map.
- Load another place, e.g. [Florence].
- Change the map type to [Terrain].
- Go back.
Result:
- You are back at the first location, as you left it after
panning, with the original map type.
Conclusion:
- Search in Google Maps behaves like a loading a new
page.
- Panning and map type changing behave like scroll.
Chatbox in Google Docs
Experiment:
- Go to Google Docs. »
- Open a spreadsheet.
- Open the [Discuss] pane.
- Leave the page. »
- Come back.
Result:
- The [Discuss] pane is closed.
Inbox in Google Mail
Experiment:
- Load GMail. »
- View inbox, note last conversation on first page.
- Go to second page.
- From another window, send a message to yourself. »
- Go back to first page.
Result:
- New message appears at top of first page, previously
last one moves to next page.
There is nothing more practical than a good theory.
Summary of Observations
- Only some elements of interaction state are recorded in
browser history.
- Only some elements are recorded in bookmarks.
- Only some state changes create history.
- When one element changes, it may reset other elements to
their default values (it's said to dominate
those).
- The default value of one element may depend on the value
of another.
- External factors can change the application state.
Classes of Interaction State Elements, 1
Hard State
- Change creates history entry.
Soft State
- Change is recorded in history, but doesn't
create new entry.
Transient State
External state
- Not recorded in history either, but recorded elsewhere.
Classes of Interaction State Elements, 2
History State versus Bookmarked State
| Class |
Preserved in |
| History Navigation |
Bookmarks |
| Hard |
Yes |
Yes |
| Soft |
Yes |
Maybe |
| Transient |
Maybe |
No |
| External |
No |
No |
Notes
- Versions of external state may have URLs.
- Navigation within the application may behave differently
than navigation away from the application and back.
Designing Application State
- In classic web applications, design decisions are built
into the browser.
- In Ajax web applications, they are explicit choices by
the developer:
- Identify state elements.
- Assign them to application state classes.
- Decide their default values and dominance
relationships.
- Decide how to implement them (next section).
What we've learned — Part 1
- A brief history of web applications.
- A vocabulary for interaction design in web
applications.
- This analysis of application state defines the
behavior of the application in a language that is precise
and that (we assert) is clear to both designers and
developers.
Upcoming: A Toy Application
In theory, there is no difference between theory and
practice.
The Plan
Part 1: Introduction, Examples, and Theory
- Analysis of application state and its representation in
browser history and bookmarks.
- A conceptual framework for designing application state in
Ajax applications.
Part 2: Practice
- Illustration through examples.
- Casual introduction to the Javascript programming
language.
- Equally casual introduction to DHTML: HTML Document
Object Model (DOM) and event handling.
Recap: Classes of Interaction State Elements
Hard State
- Change creates history entry.
Soft State
- Change is recorded in history, but doesn't
create new entry.
Transient State
External state
- Not recorded in history either, but recorded elsewhere.
About the Code Snippets
Notes:
- They all work.
- But they may require some massaging to fit your
application.
- Comments omitted from slides for brevity; but they are
included in the actual files.
What we will encounter in the snippets:
- JavaScript,
- Document Object Model (DOM),
- History and Bookmarks specifically.
Code Abbreviations
state_base.js
// Fetch a pointer to a DOM element by id.
function $(id) {
return document.getElementById(id);
}
state_iframe.js
// Fetch the query part of the page URL.
function urlQuery(window) {
return window.location.search.substring(1);
}
state_base.js
function objectSetInterval(instance, method, interval) {
window.setInterval(function() {
method.apply(instance);
}, interval);
}
About the DOM
Document Object Model (DOM): an object-oriented
Application Programming Interface (API) for
- HTML, CSS, URLs,
- the browser,
- user interaction.
User interaction is modeled by DOM Events:
load, beforeunload,
unload,
click, dblclick,
submit,
mousemove, mouseover,
mouseout,
focus, blur,
keydown, keyup,
keypress,
change,
- about 100 overall.
A Toy Application
http://ajaxchi.googlepages.com/
»
colortoy.html: Defines UI, loads code,
initializes application.
colortoy.js: Implements application
logic.
colortoy.css: Defines UI appearance.
A Toy Application: HTML
colortoy.html
<head>
<script src="colortoy.js"></script>
<script>
var colorToy = new ColorToy;
</script>
</head>
<body>
<table><tr><td><div>
<select onchange="colorToy.change(this)">
<option value="white">white</option>
...
</select>
</div></td></tr></table>
</body>
A Toy Application: onchange handler
colortoy.js
ColorToy.prototype.change = function(select) {
var color = select.options[select.selectedIndex].value;
select.parentNode.style.backgroundColor = color;
if (this.changeHandler_ && select.id) {
this.changeHandler_(select.id, color);
}
};
Statement of the Problem
Challenge:
- History: Store application state in browser
history, and restore it on history navigation events.
- Bookmarks: Store application state in a URL, and
restore it when the URL is loaded into the browser.
Tasks:
- Record hard and soft state changes in browser
history.
- Restore application state from browser history.
- Represent application state as a bookmark URL.
- Initialize application state from a URL.
Notes
Prerequisites
- Application state can be represented as a URL.
- Application state changes can be intercepted.
- Application can be initialized into state represented
by URL.
Implementation methods
- URL fragment identifier method.
- Hidden iframe method (covered in the notes).
Implementation considerations (not covered)
- Initialize application state from external data.
- Consistent behavior across browsers.
URL Fragment Identifier Method
What we abuse leverage:
- URLs may refer not just to documents, but to a place in
a document, using the fragment identifier part.
http://en.wikipedia.org/wiki/Google#History
»
- In HTML, fragments are designated by the
name attribute of the A element.
<a name="History">
- Loading a fragment of the current HTML document will
scroll the view to show the fragment, but it
will not reload the document or reinitialize the
DOM.
URL Fragment Identifier Method
Principle
- Encode current state into fragment id part of page
URL.
- We can change the page URL in a way that creates a
history entry (for hard state changes) or not (for soft
state changes).
Consequences
- Page URL and thus current state can be bookmarked
directly.
- History navigation changes URL.
- Page state initialization from bookmark URL must happen
on client, because URL fragment part isn't sent to
server.
- Setting the URL fragment id doesn't cause server
interaction, so the application is responsible for any data
transfer.
Example
http://ajaxchi.googlepages.com/
»
colortoy_hash.html: Defines UI,
loads code, initializes application.
state_base.js: Generic state manager.
state_hash.js: Specific state
manager to store state in URL fragment.
colortoy.js
colortoy_state.js: Ties application
logic to state management (both ways).
colortoy.css
Implementation Details
- History navigation will change URL, but doesn't fire
onload event, because, alas, the page isn't reloaded. Thus,
need to poll.
- Poll needs to be disabled while the URL is being
updated, or the state change needs to be caused by
the state update.
- HTML page scrolls to anchor when page URL is set to a
fragment id part that corresponds to the anchor. If there is
no such anchor, URL change isn't recorded in browser
history.
- Size of anchor is limited to about 4k.
- Setting URL always causes an audible click in Internet
Explorer, even when it doesn't load any page.
Record State Changes
state_hash.js
StateHash.prototype.record = function(name, value, hard) {
var state = State.decode(location.hash.substring(1));
state[name] = value;
var stateUrl = State.encode(state);
this.currentHash_ = "#" + stateUrl;
if (hard) {
location.href = this.currentHash_;
} else {
location.replace(this.currentHash_);
}
}
This also creates a bookmark URL.
Record State Changes (IE6)
example_hash.js
StateHash.prototype.record = function(name, value, hard) {
var state = State.decode(location.hash.substring(1));
state[name] = value;
var stateUrl = State.encode(state);
this.currentHash_ = "#" + stateUrl;
var a = document.createElement('A');
a.style.position = 'absolute';
a.style.top = getScrollTop(window) + 'px';
a.name = stateUrl;
document.body.appendChild(a);
if (hard) {
location.href = this.currentHash_;
} else {
location.replace(this.currentHash_);
}
document.body.removeChild(a);
}
Encode State in URL Parameters
state_base.js
State.encode = function(state) {
var params = [];
for (var i in state) {
if (state.hasOwnProperty(i)) {
var value = state[i];
if (value != null) {
params.push(encodeURIComponent(name) + "=" +
encodeURIComponent(value));
}
}
}
return params.join("&");
};
Decode State From URL Parameters
state_base.js
State.decode = function(encoded) {
var params = encoded.split("&");
var state = {};
for (var i = 0; i < params.length; i++) {
var nameValue = params[i].split("=");
if (nameValue[0]) {
state[decodeURIComponent(nameValue[0])] =
decodeURIComponent(nameValue[1]);
}
}
return state;
};
Restore State from Browser History
state_hash.js
StateHash.prototype.detectHistoryNavigation_ = function(load) {
objectSetInterval(this, function() {
if (location.hash != this.currentHash_) {
this.currentHash_ = location.hash;
var state = State.decode(this.currentHash_);
load(state);
}
}, 50);
};
This also restores application state from URL.
Hidden Iframe Method
What we abuse leverage:
IFRAME is an HTML element that shows
another document embedded in the view of the main HTML
document.
- Navigation from the embedded HTML document works
normally, and thus creates browser history entries, without
the embedding document being reloaded. (Note that this
breaks bookmarking by URL.)
- CSS can be used to make elements invisible.
- IFRAMEs are exposed in the DOM and thus documents in
them can be loaded by a script.
- The query part of the URL of a static page is usually
ignored, e.g.
http://chi2008.org/?foo=bar
»
- The value of an input is preserved over navigation.
Hidden Iframe Method
Principle
- Create a hidden iframe and load a document.
- Store hard & soft state in query parameters of iframe
URL.
- Hard vs. soft state changes distinguished by assigning
vs. replacing the URL.
- Or store soft state in an input field in the
iframe.
Consequences
- Changing hard state creates history entry.
- Changing soft state either way doesn't.
- Changing state with server interaction can be used to
transfer data to and from server.
- Bookmark URL is not directly available; bookmark link
needs to be provided explicitly,
a.k.a. permalink.
Example
http://ajaxchi.googlepages.com/
»
colortoy_iframe.html: Defines UI,
loads code, initializes application.
state_base.js
state_iframe.js: Specific state
manager to store state in hidden iframe.
state_iframe.html: HTML document
loaded in the hidden iframe.
colortoy.js
colortoy_state.js
colortoy.css
Implementation Details
- Detect history navigation from onload event of the
hidden iframe.
- Encoded state is available in browser and on server,
thus initialization from bookmark URL can happen on client
or on server.
- Application with only server-independent soft state
and no hard state can avoid the iframe and put a
hidden input in the main page.
For more, see the additional
slides.
What we've learned — Part 2
- JavaScript, DOM, CSS
- Browser Quirks
- Two methods for history and bookmark implementation.
- Elements of Ajax architecture.
Page Reload
- Input field values are reset or not.
- Hidden iframe urls are reset or not.
- Depends on:
- browser (wildly variant w.r.t. vendor, operating
system, and version),
- reload mode ("hard" versus "soft" reload),
- page details.
Updating External State
- Poll.
- Push through a persistent HTTP connection.
- Piggyback on background server transfer, likely in
combination with polling.
- Outside connection, e.g. from flash or java applet.
In our demo, we just store the external state in the
browser cookie, so that it will be available in all windows
of the same browser. But it isn't really external.
More design problems
- Bookmarks of list pages, of variable content, or of
variable page size.
- Bookmarking steps in a multi-step dialog.
- You decide the semantics and hence the structure of
application state.