Recently I changed all the buttons of the website I am developing right now for linkButtons. I was searching for some hover behaviour cross-browser compatibility. As you may know, the greatest web depeloper’s friend, a.k.a. Internet Explorer 6, does not support the hover CSS pseudo-class but in<a> tags. And this is a shame because all the hover effects in buttons will never work in IE6 unless you do the old javascript image source trick, and we don’t want to use it because we love CSS and, besides that, the user experience is better without that old javascript.

So, that’s it, then we need to change all buttons and imageButtons for linkButtons, that’s all. Unfortunately, this is not such an easy thing if you have panels which implement the defaultButton property. If you use IE6 or any of its younger brothers you will not notice anything but if you dare -oh poor boy!- to use Firefox then you will surely notice that your beloved defaultButton property does not work at all!!

What’s happening here?

Basically, we got a javascript issue in here. Whenever you have a panel implementing default button you got this thing rendered in your HTML:

<div id="panelClientId" onkeypress="javascript:return WebForm_FireDefaultButton(event, 'idOfyourButton')">
</div>

and this is the WebForm_FireDefaultButton function:

function WebForm_FireDefaultButton(event, target) {
    if (event.keyCode == 13 && !(event.srcElement && (event.srcElement.tagName.toLowerCase() == "textarea"))) {
        var defaultButton;
        if (__nonMSDOMBrowser) {
            defaultButton = document.getElementById(target);
        }
        else {
            defaultButton = document.all[target];
        }
        if (defaultButton && typeof(defaultButton.click) != "undefined") {
            defaultButton.click();
            event.cancelBubble = true;
            if (event.stopPropagation) event.stopPropagation();
            return false;
        }
    }
    return true;
}

The problem here is that click attribute only exists in Internet Explorer. You can try this at home by copying this html below to a blank html file and run it in Internet Explorer and Firefox. As you will see, the click attribute is only set in IE.

<a onclick="javascript:alert('hello world');return false;" id="lnk" href="http://www.codecoding.com">hello</a>
<script type="text/javascript">
	var o=document.getElementById('lnk');
	alert(o.click);
	alert(o.onclick);
	try{
		o.click();
	}catch(e){
		alert("click? what's this");
	}
	o.onclick();
</script>

Maybe the problem should be solved by correctly implementing the WebForm_FireDefaultButton by the asp.net team but we will try another approach: we are going to implement a new class extending the linkButton behaviour to generate this click attribute when it gets rendered and then do a tag mapping for all the linkbutton classes in our project.

Here you can see the code of our class:

''' <summary>
''' This is a fixed linkbutton class that allows default button behavior in firefox
''' </summary>
''' <remarks></remarks>
Public Class LinkButtonExtended
    Inherits LinkButton

    Protected Function BuildScriptString() As String
        Dim sb As New StringBuilder
        With sb
            .AppendLine("function addClickLinkButton(id) {")
            .AppendLine("var b = document.getElementById(id);")
            .AppendLine("if (b && typeof(b.click) == 'undefined') {")
            .AppendLine("b.click = function() {")
            .AppendLine("var result = true;")
            .AppendLine("if (b.onclick) result = b.onclick();")
            .AppendLine("if (typeof(result) == 'undefined' || result){eval(b.getAttribute('href'));}")
            .AppendLine("}")
            .AppendLine("}")
            .AppendLine("}")
        End With
        Return sb.ToString()
    End Function

    Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
        MyBase.OnLoad(e)
        'first we register the function
        Page.ClientScript.RegisterStartupScript(Me.GetType(), "addClickLinkButton", BuildScriptString(), True)
        'then we call it at startup to set the click attribute
        'but first we look for any scriptmanager in page.
        Dim ajaxUsed As Boolean
        Dim scm As ScriptManager = ScriptManager.GetCurrent(Page)
        If (scm IsNot Nothing AndAlso scm.SupportsPartialRendering) Then ajaxUsed = True
        Dim finalScriptCall As String
        'normal call
        Dim normalScript As String = String.Format("addClickLinkButton('{0}');", ClientID)
        finalScriptCall = normalScript
        'ajax call if needed
        If ajaxUsed = True Then
            Dim ajaxScript As New StringBuilder
            With ajaxScript
                .AppendLine("Sys.WebForms.PageRequestManager.getInstance()
.add_endRequest(function(){")
                .AppendLine(normalScript)
                .AppendLine("})")
            End With
            finalScriptCall &= ajaxScript.ToString()
        End If
        'startup
        Page.ClientScript.RegisterStartupScript(Me.GetType, "click_" & ClientID, finalScriptCall, True)
    End Sub

End Class

And for the tag mapping you can take a look at this post.

<pages>
      <tagMapping>
         <add  tagType="System.Web.UI.WebControls.LinkButton" mappedTagType="Codecoding.LinkButtonExtended" />
      </tagMapping>
</pages>