Showing posts with label AJAX. Show all posts
Showing posts with label AJAX. Show all posts

Wednesday, April 08, 2009

IE8 Compatibility Issues and working around them for HTML, Java and GWT

Keywords:
IE8 compatibility X-UA-Compatible java filter http-equiv GWT "links not working" broken EmulateIE7 compliance

Problem:
You're either certain your website/webapp is broken in IE8 or suspect it might be. What can you do?

For browsers such as firefox and IE7, you used the DOCTYPE switch to indicate if it should treat your page as being in "standards" mode or "quirks" mode. As discussed on A List Apart "standards" is open to interpretation and even if the page didn't fully comply with the standard it referenced, it could expect the browser to have a reasonable crack at letting it work.

Not any more. IE8 renders all pages in standards mode by default and it's interpretation is as far as I can tell, stricter than any other browser. In this mode, many HTML, CSS and javascript/DOM elements (that were introduced by older versions IE! - and in some cases understood by other browsers such as firefox) are not just deprecated, they're completely not there - meaning any reference to them will in most cases stop the page/application working in the browser. When this happens, the page layout may be askew, links may stop working and miscellaneous javascript errors will be flagged in the status bar.

If you're not sure if your webpage/webapp is strictly standards compliant, it most probably isn't.

GWT is effected - see Dan Moore's post and GWT Issue #3329.

Solution:
IE8 users can make broken pages work again by opting-out of the "most strict" standards treatment on a site-by-site basis using the "Compatibility View" button but you can save them the trouble by using a new http-header tag X-UA-Compatible.

The A List Apart article above describes the merits of being able to target specific versions (and the comments seem to mostly disagree :) but in the majority of cases I imagine you just want the page to be treated the way IE7 did - "standards" mode (with "flexibility") for pages that require it and "quirks" mode for all others. So use the "IE=EmulateIE7" value by either:

  1. making the server side code add this http header to every response
    X-UA-Compatible: IE=EmulateIE7

  2. or add the following meta tag to the <head> element of the page (which is essentially the equivalent to setting values on the http response)
    <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
    


You can cover the entire java web application by defining a filter as documented by Mark McLaren:
    public void doFilter(ServletRequest request, 
                         ServletResponse response, 
                         FilterChain chain)
            throws IOException, ServletException {
        if (response instanceof HttpServletResponse) {
            ((HttpServletResponse) response).setHeader("X-UA-Compatible", "IE=EmulateIE7");
        }
        chain.doFilter(request, response);
    }


Apache hosted sites can be covered by using mod_headers. For example, assuming you have the module loaded, add the following to the httpd.conf file:
Header add X-UA-Compatible "IE=EmulateIE7" 



Notes:
Having trouble installing the release version of IE8? (for goodness sake, just get firefox :) But, if you really do want to get it working for yourself see Internet Explorer 8 is not supported on this operating system for a discussion of common issues.

Friday, January 16, 2009

GWT Button acts as a submit in WebKit browsers

Keywords:
HTML button element form WebKit Chrome Safari iPhone

Problem:
In WebKit browsers, the Button widget in a GWT application seems to always act as a submit, regardless of event sinking (via ClickListener) behaviour added to it.

In Firefox (and IE!) the button works fine - that is the 'onclick' behaviour added to the widget via the GWT listening architecture is executed and the page is not submitted.

Solution:
A clue to the solution is in the code for the GWT Button (thank goodness for source code - see Button.adjustType(Element button)).

It seems to be a work around for Firefox. The W3C spec states that the default value for button type is 'submit'. Firefox does this explicitly in the DOM and when detected, this is fixed by the GWT JSNI (JavaScript Native Interface) code.

It would seem that for WebKit browsers this default is enforced but not made explicit in the DOM so this GWT snippet does not get a chance to resolve the issue. The work around is to always be explicit about the button type (as recommended in W3Schoools).

You do this in GWT as follows:
     Button b = new Button("click here");
     DOM.setElementAttribute(b.getElement(), "type", "button");

Tuesday, May 13, 2008

get/decode/unescape parameters from URL using Javascript

Keywords:
GET decode unescape request parameter param URL javascript

Problem:
You need to get at the (GET) parameters in the URL of the window with some client-slide javascript. There's no built in mechanism to access these by name in an unencoded way so it would seem you have to parse the window location ... this must have been done by some one before.

Solution:
Found two good blogs that discuss this:

  1. Get URL Parameters Using Javascript - uses regular expressions

  2. Get parameters from URL with JavaScript - uses substrings from the location.search (ie the query portion of the URL)


I found the second approach easier to read, but both miss unescaping the parameter value once obtained ... there's a built in function for that. So here's what I've used:
<script type="text/javascript">
/*
 * Retrieves the query parameter with the given parameter name or empty 
 * string if not defined
 * 
 * @param parameter name of the parameter to retrieve
 */
function queryParam(parameter) {
    var searchString = top.location.search;
    searchString = searchString.substring(1);// ommit the leading '?'

    var paramValue = '';
    var params = searchString.split('&');
    for (i=0; i<params.length;i++) {
        var paramPair = params[i];
        var eqlIndex = paramPair.indexOf('=');
        var paramName = paramPair.substring(0,eqlIndex);
        
        if (paramName == parameter) {
            paramValue = unescape(paramPair.substring(eqlIndex+1));
            return paramValue;
        }
    }
    return paramValue;
}
</script>


So from a URL http://www.example.com/formprocess?name=Fred%20Bloggs&date=01%2f01%2f2008
You can get the unescaped parameter values via:
var name = queryParam('name'); // 'Fred Bloggs'
var date = queryParam('date'); // '01/01/2008' 


Notes:
This doesn't handle multi-valued parameters ... the first (regex) blog post has some comments on how to handle this.

Thursday, June 28, 2007

IE ignores inline script added to DOM

Keywords:
internet explorer GWT DHTML AJAX inline javascript "Object expected"

Problem:
I've got javascript code (GWT in this case) that adds an inline script to the DOM:
   <input ... onClick="myFunction()"/>
   <script type="text/javascript">
       function myFunction() {
           ... do stuff
       }
   </script>


If this code was on the page from the beginning, the event call to the function works fine. When this HTML is added to the page after it's loaded it appears the function call from the event fails.

IE Error (from the bottom left "! Done" in the status bar):

Line: 1
Char: 1
Error: Object expected


Further frustration - it works fine in Firefox.

Solution:
Aside: I haven't actually worked out why, but in GWT, if you use the method in a FlexTable setHTML the javascript will also not work in Firefox - you need to use setWidget(..).

Internet Explorer will not compile inline javascript code added to the DOM after the page has been loaded. What IE is trying to tell me in its cryptic error message is it's trying to call the function but can't find it.


Notes:
A good example of how to "smuggle" javascript into the DOM via img onLoad - Have Your DOM and Script It Too.

Wednesday, March 14, 2007

Structured data to GWT component with JSON

Keywords:
GWT JSON stuctured initialisation data

Problem:
In a previous post I described using the internationalisation Dictionary class to pass in initialisation data. But what if the data is more complex than key-value pairs? You could define a dictionary value as being a delimited (e.g. space or comma separated) list of tokens but is there an easier way of getting in basic structured data without writing your own parser?

Solution:
JavaScript Object Notation (JSON) is a ".. text-based, human-readable format for representing objects and other data structures" (definition from wikipedia - the article includes a good introduction with examples). GWT supports reading and producing data in this format via the com.google.gwt.json.client package. For data interchange I think your still better off using a GWT remote service and sending your beans to it (let GWT handle the encoding/decoding) but for the host page giving data to the component JSON comes into its own.

Step 1


In the host page, define a dictionary as before but the value (or values) is/are now JSON strings rather than plain strings. In this example I'm creating an array of objects, each object having a property "id" and optionally a property "label" (it's got to be on one line as far as I can tell for the dictionary to allow it):
showHide: "[{\"id\": \"A\", \"label\": \"see A detail?\"}, {\"id\": \"B\", \"label\": \"include B detail?\"}, {\"id\": \"C\"}]"

Step 2


In the GWT component, use the dictionary to get at the JSON string. Then use the JSONParser to convert this to a JSON instance - in this example a JSONArray of JSONObjects. For a JSONObject you can get at each of its properties like you would a map via the get(String key) method.
public void onModuleLoad() {
    Dictionary properties = Dictionary.getDictionary("ModuleProperties");
  
    String showHideConfigString = properties.get("showHide");
    JSONArray showHideConfigs = (JSONArray)JSONParser.parse(showHideConfigString);
    
    List panels = new ArrayList();
    for (int i = 0; i < showHideConfigs.size(); i++) {
        JSONObject config = (JSONObject)showHideConfigs.get(i);
        
        JSONString idValue = (JSONString) config.get("id");
        String id = idValue.stringValue();
        
        JSONString labelValue = (JSONString) config.get("label");
        String label = (labelValue == null)? "include?" : labelValue.stringValue();
        
        // ... now we can do stuff with the data
        ShowHidePanel showHidePanel = new ShowHidePanel(label, id);
        RootPanel.get(id).add(showHidePanel);
        panels.add(showHidePanel);
    }
    
    // ... etc


Notes:
Someone asked me via comments how would you handle request parameters ... it's up to you to make something that can process the request parameters (CGI, java servlet, ASP?) and write a host page containing the data from the request params for the GWT component to then have access to them.

For many this will be obvious, but I felt bad for not including their comment ... but I don't want questions on the blog. Hope that helps.

If the data is more complex/rich than what JSON allows, there's XML.

Tuesday, January 23, 2007

GWT POST request doesn't include parameters

Keywords:
GWT POST request parameters HTTP HTML RequestBuilder AJAX

Problem:
Following the GWT documentation for making a http-post but it's not clear what the post data should look like if you want it to include form parameters. The newer documentation for com.google.gwt.http.client has a bit more detail but the server side code processing the request (a java servlet) says there's no parameters in the request.

Solution:
It's not in the documentation, but if you want to post form data you must set the "Content-type" header value in the request to "application/x-www-form-urlencoded"

For Example:
StringBuffer postData = new StringBuffer();
// note param pairs are separated by a '&' 
// and each key-value pair is separated by a '='
postData.append(URL.encode("YourParameterName")).append("=").append(URL.encode("YourParameterValue"));
postData.append("&");
postData.append(URL.encode("YourParameterName2")).append("=").append(URL.encode("YourParameterValue2"));

RequestBuilder builder = new RequestBuilder(RequestBuilder.POST, "/yourserver/formprocessor"));
builder.setHeader("Content-type", "application/x-www-form-urlencoded");
try {
  builder.sendRequest(postData.toString(), this /* or other RequestCallback impl*/);
} catch (RequestException e) {
  // handle this
}


Notes:
This sample chapter from the JavaScript™ Phrasebook is useful: Sending a POST Request

Monday, January 15, 2007

How to give initialisation parameters to a GWT component

Keywords:
GWT init initialisation parameter dynamic config

Problem:
Where you have a servlet, JSP or other technology dynamically producing the HTML "host page" for a GWT component, it makes sense that you may want to parameterise the way the GWT component renders/behaves based on certain initialisation/input parameters.

How do pass parameters into the Module?

Solution:
There is a useful Dictionary facility in the Internationalisation (I18N) module ... it doesn't really have anything to do with Internationalisation but it's in this module because you could get the host page to provide key-to-locale-specific-message mappings to save the Module using any hard coded message text in a specific language.

It's generic enough that you could use it for any mapping of values.

The GWT documentation for Dictionary shows how to import the I18N module to your own module and then load the key-value mappings defined in the host page from your GWT code.

Friday, January 05, 2007

GWT shell resource not found *.nocache.html

Keywords:
GWT AJAX shell resource not found nocache.html cache.html

Problem:
Following the Developer guide for making a GWT UI module. The code compiles fine with the GWT compiler and I now what to test and run using the GWT shell.

It starts up fine but I get the following error in the tree log of the shell when it opens up the HTML test page:
The development shell servlet received a request for
'com.example.gwt.mypackage.client.MyEntryPointClass.nocache.html'
in module 'com.example.gwt.mypackage.MyModuleName'

Solution:
My examplisation of the error message highlights what the problem was ...

The HTML "host page" must reference the module name in the meta tag, not the EntryPoint class or the ".client" package (it should be called .client if you want to use the GWT expectations for where things are). The module name is typically the package name parent of the ".client" package plus the name of the *.gwt.xml config file minus the extension.

Eg:
<meta name='gwt:module' content='com.example.gwt.MyModuleName'/>