Handling the back button click action using JavaScript (in pages with fragment identifiers) to route the request to another page

So there is this new issue at work where the browser back button is not behaving as desired. The idea is that when the user clicks the browser back button on any page, the user should be routed to the default login page. As much as that sounds like a symptom of an inherently fundamental fault, I feel it is much better than what most other sites do – disable the back button altogether (which can be circumvented of course).

The product in question is a standard JSP-based web application with the normal JS+CSS++HTML client-side stack. The layout is pretty simple – there is a main Login Page, and then the user is presented with a navigation pane on the left-hand side, and with a main page displaying the results of the various options presented in the navigation pane. The idea is that whenever a user clicks on the back button from any page, he or she should be presented with the Login Page. Easier said than done! First of all, there is no real event associated with the browser back button click (or a lot of other browser actions for that matter) in JavaScript. There are plenty of hacks that can be done to achieve most use cases. In this specific case though, the problem was a specific option on the navigation pane – the ‘Inventory’ option, which simply displays various objects as hyperlinks in the main pane. Upon clicking any of these objects, the URL uses fragment identifiers (of the format: http://<host>:<port>/<main-url>#detailedInfo. This practically messes up the aforementioned hacks (using iframes, polling of hash changes, onbeforeunload, onunload, etc). Since the history object of the browser still contains the same base URL for both the main pane as well as the fragment identifier, options such as using iframes and onbeforeunload/onunload events fail completely. Also, using hash changes (either polling or using the basic window.onhashchange event) also do not solve the problem since the URL hash does change even on clicking the anchor for the fragment identifer (which is not desirable) as well as on clicking the back button (or the alt-leftarrow combination). However, unlike the many trolls that abound the various forums online, I present to you an actual solution to the problem at hand, which may be customized to suit any specific situation as the case may be.

For my demo, I have created a base page – Page1.html which simulates the main page. Page2.html contains the logic for detecting back-button clicks (note that since the forward button is not enabled, that case does not pose a problem. Also, the advantage with this method is that refreshing the page does not cause any unexpected or anomalous behavior either). I have also created another page, Login.html which simply simulates the default Login Page.

1. Page1.html

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="utf-8"/>
		<title>Page 1</title>
	</head>
	<body>
		<h1>Welcome to the Main page</h1>
		<a href="Page2.html">Page 2</a>
	</body>
</html>

2. Page2.html

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="utf-8"/>
		<title>Page 2</title>
		<script type="text/javascript">
			var origURL = window.document.location.href;
			var origFileName = origURL.substring(origURL.lastIndexOf("/") + 1, origURL.length);
	        </script>
	</head>
	<body>
		<h1>Welcome to the Details  page</h1>
		<a href="#detailedInfo">Details</a>
		<p id="details">Details here!</a></p>
		<script type="text/javascript">
			window.onhashchange= function() {
				var url = window.document.location.href;
				var fileName = url.substring(url.lastIndexOf("/") + 1, url.length);
			
                        	if(fileName.search(origFileName) != -1) 
                                    && fileName.search("#detailedInfo") != -1) {
                                           // Do nothing.
					} else {
                                                //This would be a proper URL when deployed on a Web Server.
						window.location.replace("Login.html");
					}
			}
		</script>
	</body>
</html>

3. Login.html

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="utf-8"/>
		<title>Login Page</title>
	</head>
	<body>
		<h1>Welcome to the login page</h1>
	</body>
</html>

Explanation: The logic here hinges upon the fact that most modern browsers (this code has been tested on Firefox 18.0.1, Chrome 24.0.1312.57, Opera 12.00, and Internet Explorer 9) support the window.onhashchange event. This event is basically generated when the location hash (in simple terms, the hash of the URL of the current window) changes. Thankfully, this also includes the case where the fragment id of the anchor target is appended to the main URL.

Thus, in Page2.html, I simply get a handle to the original page name when I enter the page, and the check if the new page name (that includes the fragment identifier) contains the original page name as well as the fragment identifier. If so, it means that we are still on the same page, and so we do nothing. Otherwise, it means that the back button has been clicked (or invoked through history.back(), or through the keyboard action – alt+ left arrow). In this case, we simply change the location of the current window to the Login Page. And that’s it!

P.S: The fragment identifier, #detailedInfo has been hardcoded in this snippet, but it need not be so. We can simply check for the main page, and any fragment identifier, to ascertain if we are still on the same page or not. Note that this is a very specific case – any other situations beyond this case have to be handled in their own right.

P.P.S: While Firefox supports the “contains” method (in the style of Java) for searching substring matches in string objects, all the other browsers support the “search” method, including Firefox itself! So this snippet works uniformly across all browsers.

Advertisements
Handling the back button click action using JavaScript (in pages with fragment identifiers) to route the request to another page

Configuring Eclipse to run standalone JavaScript files (Using Node.js/Google V8 Engine)

I recently started studying JavaScript in greater detail so that I could work on some side projects of my own. My new found interest was sparked in a large part by the wonderful server-side JavaScript framework, Node.js. However, while working through the various tutorials that I had collected for the same, it became painfully evident that creating anything non-trivial in standalone JavaScript was a pain in the proper place. This is hardly surprising since the entire life-cycle of JavaScript has been primarily within the confines of the browser. However, becoming swiftly tired of embedding snippets of code within the <script> tags in HTML pages to test out various concepts of the language, I began looking for alternatives.

The first obvious choice was the excellent Firefox Scratchpad (Tools->Web Developer->Scratchpad. I am using Firefox 16.0.2, but this has been always the location of Scratchpad ever since I can remember). This is a wonderful piece of software that works for most of the scenarios while learning JavaScript, but falls short in terms of useful options such as debug options, or linking script files together in a modular fashion.

The next option that I evaluated was the eval support provided by Firebug. This is a far more advanced tool than Scratchpad, but again, when the size and complexity of the code goes beyond a certain point, it is essentially doing something that it was not designed to do.

What I really wanted in this specific case was complete IDE support for executing JavaScript projects. Ideally, I would like to use Eclipse as the IDE, with a JavaScript perspective for all the formatting and validation bits, and link an external tool to execute the script files. Getting the JavaScript perspective to work on the version of Eclipse that I am using, Juno was a breeze. The latter part – getting some suitable engine to run standalone JavaScript code, and getting it to work with Eclipse was the harder bit. Having begun tinkering with Node.js, I saw that their engine basically was a wrapper around Google’s V8 JavaScript Engine. So now I had two options: follow the elaborate set of steps listed out on that site, and generate binaries using Visual Studio (while hoping for the best), or I could simply use Node.js’s own executable wrapper! A little bit of Googling, and I found the following site – http://www.epic-ide.org/running_perl_scripts_within_eclipse/entry.htm, which made life much easier for me. The example given is for Perl, but the steps work perfectly for JavaScript as well.

Steps to configure Eclipse to work with Node.js’s JavaScript engine

1. Open the ‘External Tools’ window (Run->External Tools->External Tools Configuration)

1

2. In the ‘Name’ field, enter a name for the new configuration (such as ‘JavaScript_Configuration’)

2

3. In the ‘Location’ field, enter the path to the windows executable (C:\WINDOWS\system32\cmd.exe on my Windows 7 machine)

3

4. In the ‘Working Directory’ field, enter ‘C:\WINDOWS\system32’. This is because we are referring to the executable in the ‘Location’ field as ‘cmd.exe’, for which this is the working directory.

4

5. In the ‘Arguments’ field, we need to add the following string:

/C “cd ${container_loc} && node ${resource_name}”

5

Obviously, the ‘/C’ at the beginning of the line is the flag that requests the cmd.exe tool to execute the supplied string, and then terminate. The ${container_loc} field refers to the absolute path of the currently selected resource’s (JavaScript script file in this case) parent, and the ${resource_name} variable corresponds to the name of the currently selected resource (the JavaScript script file). Check out this site for more variables associated with the External Tools configuration – http://help.eclipse.org/juno/index.jsp?topic=%2Forg.eclipse.platform.doc.user%2Fconcepts%2Fconcepts-exttools.htm.

Of course, we assume here that the “node” executable is available through Windows’ PATH environment variable.
And that’s it, we’re done! To check that everything is working as expected, I create a sample file, test.js in a new JavaScript project, which contains the following simple code snippet:

(function() {
console.log(“Hello, World!”);
})();

When we execute this file (using Run->External Tools->JavaScript_Configuration), we see that it works perfectly!

6

And of course, this approach can be applied to various other languages that are not supported by default by Eclipse, or for which there is no suitable Eclipse plugin available.

Configuring Eclipse to run standalone JavaScript files (Using Node.js/Google V8 Engine)