views:

164

answers:

3

Monring all,

It early Monday morning and I'm struggling to understand why the followng line works in IE and not in FF.

<a class="button" href="#" onclick="setMaintenanceMode(false);">disable</a>

In both IE and FF the URL when you hover over the button is...

http://localhost:8080/mainapp/secure/gotoDevice.action?hardwareId=1&amp;storeCode=2571#

When the button is clicked, the following method is called...

function setMaintenanceMode(enabled) {
    var url = '<s:url action="secure/setMaintenanceMode"/>' + '&ModeEnabled=' + enabled;
    document.location.href = url;
}

The URL that docuement is sent to is (in both browsers)...

/mainapp/secure/gotoDevice.action?hardwareId=1&amp;storeCode=2571&ModeEnabled=false

The problem is that in IE the method on the struts action 'setSetCode()' is called, but from FF its not! If I remove the hash ahref above FF works, but IE doesn't (href="#").

I've tried changing the '&ModeEnabled=' to '&amp;ModeEnabled=', but no success. I've looked on google and the struts forum, but no success.

I'm tempted to rip out all the ahref's and replace them with Dojo buttons and see if that works, but before I do, I just wondered if anyone could shead some light on why.

My guess is that ahref is the wrong thing to use, but why?

If anyone could help me understand why though it would be appreciated.

Thanks Jeff Porter

EDIT: The return false is part of the solution. The problem seems to be that the url..

/mainApp/secure/setMaintenanceMode.action?hardwareId=5&amp;storeCode=2571&ModeEnabled=true

has the &amp; inside it, if I go to this url as it is, then it works in IE, but not in FF.

if I change both to be & then it works in IE & FF.

if I change both to be &amp; then it still works in IE but not FF.

Any ideas?

Note:

Seems that struts 2.0.9 does not support the property escapeAmp on the <s:url tag:

By default request parameters will be separated using escaped ampersands (i.e., &amp;). This is necessary for XHTML compliance, however, when using the URL generated by this tag with the <s:property> tag, the escapeAmp attribute should be used to disable ampersand escaping.

soultion: return false on the onclick and upgrade to new struts + set escapeAmp param. else, url = url.replace("&amp;", "&");.

+2  A: 

Try returning false from the javascript method

function setMaintenanceMode(enabled) { var url = '' + '&ModeEnabled=' + enabled; document.location.href = url; return false; }

disable

This should stop the javascript onclick event reaching the browser.

Steve McDowell
Not unless you `return setMaintenanceMode(...`
Anonymous
+2  A: 

onclick="setMaintenanceMode(false); return false;"

The onclick is working, but then the href does immediately, as well. You need to return false from the click handler to signal that href should not be followed.

IE likely guesses at what you mean, and does the wrong thing.

Anonymous
I think you are both correct, but that is not the complete solution.Please see my new comments in the question.
jeff porter
If the ampersand appears in your HTML, it needs to appear as the HTML entity. If it's instead in a separate file loaded with script src="", it should not be so escaped. I think there's some case in between for XHTML with CDATA blocks, but that wouldn't work in a tag-soup parser. For consistent results, put the code with the ampersand in a separate, non-HTML file.
Anonymous
You could also try to use a different character than the ampersand for separating fields in the query string. The semicolon (;) is a common second choice. Most big, generic web applications understand what it means, because it's in the RFC (see http://en.wikipedia.org/wiki/Query_string#Structure and the references therein)
Anonymous
A: 

the URL has the &amp; inside it, if I go to this url as it is, then it works in IE, but not in FF.

I doubt it – it shouldn't work in either. It's not browser-dependent, but server-dependent.

The string a=b&amp;c=d is split into parameters by the server framework. Servlet requires that only & be used to separate parameters, so it will return a=b and amp;c=d. The latter parameter obviously won't be recognised by the application which is expecting c.

The HTML specification for various reasons strongly recommends that ; also be allowed as a separator, in which case you'd get a=b, a stray amp which without an equals sign would be meaningless and discarded, and c=d. So despite the mis-encoding of the ampersand it would still work. Unfortunately, Servlet ignores this recommendation.

By default request parameters will be separated using escaped ampersands (i.e., &amp;).

Oh dear! How unfortunate. You shouldn't escape ampersands at the point of joining parameters into a URL. You should simply join the parameters with a single ampersand, and then, if you need to put the finished URL into an attribute value of text content, HTML-encode the entire URL. Struts's default behaviour is simply wrong here.

In your case you are not outputting the URL to an attribute value or text content, you're writing it into a string literal in a script block:

var url = '<s:url action="secure/setMaintenanceMode"/>' + '&ModeEnabled=' + enabled;

In a script block in old-school HTML, HTML-escaping does not apply. (In XHTML in native XML it does, but let's not think about that yet.)

However, you still do need to think about JavaScript escapes. For example what if there were an apostrophe in the setMaintenanceMode link? It would break the string. Or if somehow you had a </ sequence in the string it'd break the entire script block.

What you really want to be doing is making the URL (without any ampersand-escaping), and then use a JavaScript string literal backslash-escape on it. Best would be to use an existing JSON encoder which will turn any Java value into a JavaScript literal, putting the surrounding quotes in for you too if it's a string. You can also on most JSON encoders tell it to JS-escape the < and & characters, which means not having to worry about XHTML parsing if you decided to serve the page as XML in the future.

I'm tempted to rip out all the ahref's and replace them with buttons

Well certainly if you have a thing you click on that isn't a link to another location, but simply does something to the page via script, then that's not a link really, and you'd be much better off marking it up as a <button> or <input type="button">, and using CSS to restyle it not to look like a button if you don't want it to.

However (again), this all seems rather pointless, as at the moment you are replacing the behaviour of a link with behaviour that just like a link only not as flexible. What's wrong with simply:?

<a href="/mainApp/secure/setMaintenanceMode.action?hardwareId=5&amp;storeCode=2571&amp;ModeEnabled=false">disable</a>
bobince