Savepoints: Go back/forward management

From MozillaWiki
Jump to: navigation, search

This page presents a feature suggestion for Mozilla Firefox.

Preface

All the modern browsers feature 'Go back'/'Go forward' options that allow users to navigate to pages seen previously or (after navigating back) go forth.

With the dynamic content of pages, AJAX calls, DHTML/JS actions, etc, those features are obsolete and useless for many of pages in the world wide web.

This article describes the idea of supporting 'Savepoints'. It is about how to adapt those useless elements when the web content became dynamic.

The web we once knew

Characteristics

  1. Static pages;
  2. Bidirectional navigation: to a new page, back/forward;
  3. Static history and 'Go back'/'Go forward' lists independent from pages' content.

Example

  1. Open page A (back: none, forward: none);
  2. Open page B (back: A, forward: none);
  3. Open page C (back: B, A, forward: none);
  4. Go back to B (back: A, forward: C);
  5. Open page D (back A, B, forward: C)

The web we know now

Characteristics

  1. Dynamic content and structure of a page;
  2. Free navigation: to a new page, back/forward, to a new content or state, using ajax, flash, etc.
  3. But... static history and 'Go back'/'Go forward' lists are still independent from pages' content and dynamic processing.

Example

  1. Open page A (back: none, forward: none);
  2. Open page B (back: A, forward: none);
  3. Open new content B2 on page B (back: A, forward: none); cannot go back to B;
  4. Open page C (back: B, A, forward: none); cannot go back to B2;
  5. Go back to B (back: A, forward: C); cannot go forward to B2.

Conclusion: the history track does not contain the dynamic pages' states. They do not exist in the navigation path.

Potential solutions

  • Pages navigating to themselves, passing proper parameters

Disadvantages: Defeats the purpose or having dynamic content (reloading a page is still required).

  • Saving a state of pages in sessions/cookies

Disadvantages: Users are not able to bookmark or pass a link to a page in current state to anyone without a page providing such a link explicitly.

Proposed solution

Fundamental requirements

  1. Pages cannot have any access to browsers' history for security reasons.
  2. Users have to be able to disable the option if they wish.
  3. Solution has to be fully compatible with existing web standards and behave properly in existing browsers.
  4. Page should be able to decide whether it is the right time to save a point worth returning to and label it for a user.
  5. Only user has the right to decide whether to return to a saved point.
  6. Multi-step pages (wizards, etc) should be able to remove unavailable steps from history to prevent from suggesting them to a users.
  7. Both a server and a client should be able to restore a page to a specified state, depending on developer's choice.

Solution

Browsers could expose a simple function to let the JavaScript code create a savepoint.

Example snippet

 // when not supported or disabled, returns false
 // (if disabled, a savePoint function could also do simply nothing)
 if (window.savePoint)
 {
 	window.savePoint(label, queryStringParams, mergeGroup);
 }
label
Corresponds to a title; text presented for a link in the history or bookmarks. This parameter is represents user-visible title of a page in a saved state. After saving (and opening a state of a page) title bar would not use HTML title anymore but the one specified as a label.
queryStringParams
Custom parameters of the current page allowing a server or a client to generate its saved state. This parameter contains query string parameters that will be user for a link. Page should not be allowed to provide a whole URL. The current URL with additional parameters (if speficied at all) will be used as a link.
mergeGroup
A custom text identifier of a merge group or null if none. A parameter lets page manage previous states. When a mergeGroup is null a new save point will be added to a back/forward history, unless a label is empty - this will result in removing all the savepoints of a page. If a mergeGroup contains not null text identifier, all the states with that identifier are removed from a history and - when a label is not null - a new save point will be created. This way page can add new save points, remove chosen or all previous states without accessing browser's history content.

Sample page

The following code shows a simple page with two headers each of them including some text (many FAQ pages use similar structure for instance). When a user clicks a header, all other descriptions are folded and only the selected one is presented.

When a user clicks a header, page tries to create a save point with one parameter which representing a clicked header so the user can return to a previous state (for instance a previous text he/she read before).

This is also an example of client-side code restoring the state of a page. In current browsers code works prefectly because the condition checking a function existance returns false. However it is possible to see the behavior of a page passing a parameter which from an address bar. With the requested feature implemented, a browser would do the same but without users interaction.

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
 <head>
 	<title>Test</title>
 	<script type="text/javascript">
 	/* <![CDATA[ */
 		function show(which)
 		{
 			document.getElementById('p1').style.display =
 				(which == 1 ? 'block' : 'none');
 			document.getElementById('p2').style.display =
 				(which == 2 ? 'block' : 'none');
 			if (window.savePoint)
 			{
 				window.savePoint('Header ' + which, 'which=' + which, null);
 			}
 		}		
 		function getPresented()
 		{
 			parameters = window.location.search.substring(1).split("&");
 			for (var i = 0; i < parameters.length; i++)
 			{
 				pair = parameters[i].split("=");
 				if (pair[0] == 'which')
 				{
 					return parseInt(pair[1]);
 				}
 			}
 			return 1;
 		}
 	/* ]]> */
 	</script>
 </head>
 <body onload="show(getPresented());">
 	<h1 onclick="show(1);">Header 1</h1><p id="p1">Text 1</p>
 	<h1 onclick="show(2);">Header 2</h1><p id="p2" style="display: none;">Text 2</p>
 </body>
 </html>