Monday, July 11, 2011

Html Select width problem in IE : workaround using JQuery

Setting the fixed width of a <select> element in Internet Explorer will cause all of the select options that are wider than the select's set width to be cropped.

If you set a static width on the <select> element, any <option> elements that are wider get cut of in IE. There is no good CSS solution for this.

So here are some workarounds to rsolve the problem.

Keep the static width on the select element by default, but when moused over in IE, change the width to "auto". And then put it back to static width when moused out.

onmouseover="autoWidth(this)"
onblur="resetWidth(this)"
So when a user clicks on the select the width will automatically expand, and user moves out of the select box, the width will be reset to original.

But the problem with this approach is the original size of the select box is not maintained and the width of the box expands, thus causes the page look and feel collapse.

It has been tackled with JavaScript a number of ways. but nothing suits to the problem.

So tried in a jQuery way of solving the Problem.

$(function() {
 
  if(browser.isIE){  
    $("#select")
        .mouseover(function(){
            $(this)
                .data("origWidth", $(this).css("width"))
                .css("width", "auto");
        })
        .mouseout(function(){
            $(this).css("width", $(this).data("origWidth"));
        }); 
    }
});

   1. When mouse pointer goes over select element, keep track of the original width, then set it to "auto".

   2. When mouse pointer leaves, set width back to original width.

But again the problem of page collapse and not consistent...oops!

There is a jQuery plugin proposes a work around.

http://www.jainaewen.com/files/javascript/jquery/ie-select-width/

Download this Plugin and add it to your class path, and call the function.. thats it..

<script type="text/javascript" src="/js/jquery/plugins/jquery.ie-select-width.min.js">&#xa0;</script>
  <script type="text/javascript" language="JavaScript">
    //Workaround for IE html select issue(Width of the dropdown is not expanding w.r.t to the content width.)
    var $j = jQuery.noConflict();
    $j(document).ready(function() {
        if (browser.isIE) {
         $j('select[name*=xxxxx]').ieSelectWidth({});
        }
    });
  </script>

Applying this plugin makes the select element in Internet Explorer appear to work as it would work in Firefox, Opera etc...

However I noticed this works exactly as FF on IE versions 8 & 9, but in 6 & 7 the width of the dropdown also expands to the max width of the options but solves the Problem.

Struts Custom tag to support JSTL functions

The Struts Taglib component provides a set of JSP custom tag libraries that help developers create interactive form-based applications. There are tags to help with everything from displaying error messages to dealing with nested ActionForm beans.

Struts Taglib is composed of four distinct tag libraries: Bean, HTML, Logic, and Nested.
Bean  :   The bean tags are useful in defining new beans (in any scope) from a variety of possible sources, as well as a tag to render a particular bean (or bean property) to the output response.
HTML :    The HTML tags are used to create input forms, as well as other tags generally useful in the creation of HTML-based user interfaces. The output is HTML 4.01 compliant or XHTML 1.0 when in XHTML mode.
Logic   :  The Logic tags that are useful in managing conditional generation of output text, looping over object collections for repetitive generation of output text, and application flow management
Nested  :   The Nested tags extend the base Struts tags to allow them to relate to each other in a nested nature. The fundamental logic of the original tags doesn't change, except in that all references to beans and bean properties will be managed in a nested context.

A 'custom' tag is something which a browser will not understand, because it is not a pre-defined HTML tag. you need to write/tell the browser so that it understands what it is supposed to do.
A custom tag, is thus, a tag, you write in your Java Server Page. When the jsp compiler encounters that tag, it knows what to do with it. It generates the proper HTML after doing whatever it is supposed to do.

Custom Tag

   1. Write the tag handler class.
   2. Create the tag library descriptor (TLD).
   3. Make the TLD file and handler classes accessible.
   4. Reference the tag library.
   5. Use the tag in a JSP page.      

        * Tag Handlers implement one of three interfaces:

1.  Tag
    Implement the javax.servlet.jsp.tagext.Tag interface if you are creating a custom tag that does not need access to its interface. The API also provides a convenience class TagSupport that implements the Tag interface and provides default empty methods for the methods defined in the interface.

2.  BodyTag
    Implement the javax.servlet.jsp.tagext.BodyTag interface if your custom tag needs to use a body. The API also provides a convenience class BodyTagSupport that implements the BodyTag interface and provides default empty methods for the methods defined in the interface. Because BodyTag extends Tag it is a super set of the interface methods.

3.  IterationTag
    Implement the javax.servlet.jsp.tagext.IterationTag interface to extend Tag by defining an additional method doAfterBody() that controls the reevaluation of the body.
Sample Java program implements Custom Tag.
package com.xyz.CustomTag;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.BodyContent;
import javax.servlet.jsp.tagext.BodyTag;
import javax.servlet.jsp.tagext.Tag;

public class DateTag implements BodyTag {
    private PageContext pc = null;
    private Tag parent = null;
    private BodyContent bd = null;
    private boolean showInUpperCase;

    public boolean isShowInUpperCase() {
        return showInUpperCase;
    }

    public void setShowInUpperCase(boolean showInUpperCase) {
        this.showInUpperCase = showInUpperCase;
    }

    @Override
    public void doInitBody() throws JspException {

    }

    @Override
    public void setBodyContent(BodyContent arg0) {
        bd = arg0;

    }

    @Override
    public int doAfterBody() {
        try {
            String bodyString = bd.getString();
            JspWriter out = bd.getEnclosingWriter();
            SimpleDateFormat simDate = new SimpleDateFormat("dd-MM-yyyy");
            out.print((bodyString + simDate.format(new Date())).toUpperCase());
           
            bd.clear(); // empty buffer for next evaluation
        } catch (IOException e) {
            System.out.println("Error in BodyContentTag.doAfterBody()" + e.getMessage());
           
        } // end of catch

        return SKIP_BODY;
    }

    @Override
    public int doEndTag() throws JspException {
        return EVAL_PAGE;
    }

    @Override
    public int doStartTag() throws JspException {
        return EVAL_BODY_AGAIN;
    }

    @Override
    public Tag getParent() {
        return parent;
    }

    @Override
    public void release() {
        pc = null;
        parent = null;

    }

    @Override
    public void setPageContext(PageContext arg0) {
        pc = arg0;
    }

    @Override
    public void setParent(Tag arg0) {
        parent = arg0;
    }

}
         
     * Write a tag library descriptor.

      that will contain the mappings between our custom tag and the Java class (or classes) that will handle it. This library is defined within an XML document called a tag library descriptor (TLD). We'll call the TLD for our DateTag example DateTagLib.tld. Note that ".tld" is the standard extension for such files.
            <?xml version="1.0" encoding="ISO-8859-1" ?>
            <taglib>
                <tlibversion>1.0</tlibversion>
                <info>A simple tag library</info>

            <tag>
                <name>displayDate</name>
                <tagclass>myTags.DateTag</tagclass>
                <bodycontent>empty</bodycontent>
               <info>Display Date</info>
            </tag>
          </taglib>
      Although not mandatory, the TLD file is usually placed under WEB-INF/tlds/.

     * Reference the Library    

    * Declare the TLD in the web.xml file. web.xml is the standard descriptor file for any web application. The TLD is declared like:
      <webapp>
         ....
         <taglib>
            <taglib-uri>DateTag</taglib-uri>
            <taglib-location>/WEB-INF/tlds/DateTagLib.tld</taglib-location>
         </taglib>
      </webapp>
Using a Custom Tag in your page

Now that the custom tag is built and deployed, it can be used in a JSP by:
    * Declaring the TLD as a directive:
      <@ taglib uri="DateTag" prefix="test" %>
    * Using a tag "displayDate", which is a part of the TLD, in the JSP page:

      <test:displayDate attr1="value1" attr2="value2" />
As soon as the runtime encounters the "test" tag, it knows a tag in that library is going to be used. In the above example, "displayDate" in the library is used. When the runtime parses "<test:displayDate", the method of "displayDate" is triggered.

JSTL Functions 
JSTL functions are supported from version 1.1.

If you are in version 1.0 here is the steps to upgrade.

1. Reference the correct servlet specification in your deployment descriptor:

      <?xml version="1.0"?>
      <web-app version="2.4"
       xmlns="http://java.sun.com/xml/ns/j2ee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
   2. Reference the correct JSTL uri in your JSP:
      change

      <%@ taglib uri='http://java.sun.com/jstl/core' prefix='c'%>
      to
      <%@ taglib uri='http://java.sun.com/jsp/jstl/core' prefix='c'%>

And ofcourse upgrade the JSTL jar in your class path.

The JSTL 1.1. library provides inbuilt function support .. refer http://download.oracle.com/docs/cd/E17802_01/products/products/jsp/jstl/1.1/docs/tlddocs/fn/tld-summary.html

<%@ taglib uri="http://java.sun.com/jsp/jstl/core"
     prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions"
    prefix="fn" %>
<html>
<body>
<c:if test="${fn:length(param.username) > 0}" >
  <%@include file="response.jsp" %>
</c:if>
</body>
</html>

Use a Custom Tag with function support from Apache commons-lang.
Defining a Tag function in a web app

The TLD File

<!-- WEB-INF/tld/commons-lang.tld -->
<?xml version="1.0" encoding="UTF-8" ?>
<taglib xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
        version="2.1">
    <description>Tags used escape characters</description>
    <display-name>escape tags</display-name>
    <tlib-version>1.0</tlib-version>
    <short-name>escape</short-name>
    <uri>http://commons.apache.org/lang/StringEscapeUtils</uri>
    <function>
        <description>Escapes the characters in a String using HTML entities.</description>
        <name>html</name>
        <function-class>org.apache.commons.lang.StringEscapeUtils</function-class>
        <function-signature>java.lang.String escapeHtml(java.lang.String)</function-signature>
    </function>
    <function>
        <description>Escapes the characters in a String using JavaScript String rules.</description>
        <name>javaScript</name>
        <function-class>org.apache.commons.lang.StringEscapeUtils</function-class>
        <function-signature>java.lang.String escapeJavaScript(java.lang.String)</function-signature>
    </function>
    <function>
        <description>Escapes the characters in a String using XML entities.</description>
        <name>xml</name>
        <function-class>org.apache.commons.lang.StringEscapeUtils</function-class>
        <function-signature>java.lang.String escapeXml(java.lang.String)</function-signature>
    </function>
</taglib>

The JSP

Somewhere near the top of the file.

<%@ taglib prefix="lang" uri="/WEB-INF/tld/commons-lang.tld"%>

...

// example of escaping for javascript

img.description = '${escape:javaScript(xxxxx)}';

// example of escaping an html attribute

title="${escape:html(pic.description)} ${escape:html(xxxxxx)}"
... />

Friday, July 1, 2011

Struts html:form with focus element creates JS error on IE

The built in struts <html:form ...  focus="[elementname]"> functionality automatically generates this X-browser
javascript.

you can see this on your browser at the end of form element.

<script type="text/javascript" language="JavaScript">
 <!--
 var focusControl = document.forms["component"].elements["contents"];
 if (focusControl.type != "hidden") {
 focusControl.focus();
 }
 // -->
</script>

With this, Internet Explorer (version 6, 7 and 8) generates the following error:

"Can't move focus to the control because it is invisible, not enabled, or of a type that does not accept the focus."

The problem seems to be that for some very odd reason the javascript is being called before the element is available.

So, to comeout of this, I had removed the struts generated focus field(form tag) and added a own script., below the form with a try/catch.

Something like this..

 </html:form>
-
+<script type="text/javascript" language="JavaScript">
+<!--
+ var focusControl = document.forms["component"].elements['<c:out value="${focus}"/>'];
+ try{
+ if (focusControl.type != "hidden")
+  focusControl.focus();
+ }catch(er){
+  //Fix for IE focus problem.
+ }
+//-->
+</script>

Now the error goes off...