17
Vote

MaskedEdit "backspace" problem with safari and chrome -- here's the fix!

description

"backspace" does not work with the MaskedEditExtender in safari and chrome

it even fails on http://www.asp.net/ajax/ajaxcontroltoolkit/Samples/MaskedEdit/MaskedEdit.aspx

the fix is easy. in the current source code of MaskedEditBehavior.js about line 890 you have this:
    if (Sys.Browser.agent == Sys.Browser.InternetExplorer || evt.type == "keypress")  
    {
        if (scanCode == 8) // BackSpace
     ...
the code should be:
    if (Sys.Browser.agent == Sys.Browser.InternetExplorer || evt.type == "keydown")  
    {
        if (scanCode == 8) // BackSpace
     ...

I would like to take credit, but i found it here:
 http://www.timgittos.com/archives/safari-and-firing-keypress-events-with-backspace/ 
I have compiled and tested it.. works fine

somebody please make the change to the golden source so I dont have to download/fix/ and copile the whole thing every time you come out with a new release...

thanks
jd

file attachments

comments

bocca wrote Oct 18, 2011 at 7:43 AM

In fact, the problem is not only for backspace, but for other keys as del, start or end. A solution is replacing all ocurrences of (evt.type == "keypress") with (evt.type == "keypress" || evt.type == "keydown").

If you cannot/don't want to modify source code, add the following javascritpt snipper somewhere after the inclusion of the combined scripts of AjaxControlToolkit (tested with 4.1.50401.0 binaries):

try { p = Sys.Extended.UI.MaskedEditBehavior.prototype; } catch (e) { p = null; }
if (p != null) {
p._ExecuteNav = new Function("g", "h",
    'var c=-1,e=" ",a="",b=false,d=true,p="keypress",s="keydown";' +
    funcbody(p._ExecuteNav)
    .replaceAll('g.type==p', '(g.type==p||g.type==s)'));
}

bocca wrote Oct 18, 2011 at 7:44 AM

Functions used:

if (String.prototype.replaceAll == null) String.prototype.replaceAll = function (s, r) {
var x = "", i = this.indexOf(s, 0), k = 0;
while (i >= 0) {
    x += this.substring(k, i) + r;
    k = i + s.length;
    i = this.indexOf(s, k);
}
return x + this.substring(k, this.length);
}

function funcbody(f) {
var s = f.toString();
return s.substring(s.indexOf('{'));
}

cobrabr wrote Nov 18, 2011 at 8:29 PM

Adding my +1 to this issue. It really renders MaskedEdit annoying to use with WebKit browsers, to say the least.

BTW, thanks for the quickfix snippet, bocca. :D

caesarm wrote Sep 26, 2012 at 5:33 PM

Another method to fix this.

This will wrap the original _ExecuteNav function and simply replace the event.type == 'keydown' with 'keypress', call the original function, then restore the event.type. This will also work on both debug and release builds without any changes.

Add the MaskedEditFix.js to your project. I included the MaskedEditFix.debug.js version for reference but it is not needed.

Add code to your page init event to load the script file.

(VB.Net)
Private Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init
        If Page.ClientScript.IsStartupScriptRegistered(Me.GetType, "MaskedEditFix") = False Then
            Page.ClientScript.RegisterStartupScript(Me.GetType, "MaskedEditFix", String.Format("<script type='text/javascript' src='{0}'></script>", Page.ResolveUrl("~/Js/MaskedEditFix.js")))
        End If
End Sub

I used the RegisterStartupScript method to load the script at the end of the document so the masked edit control will load first which is necessary.
Hope this helps someone.

allende wrote Oct 5, 2012 at 6:45 PM

Thanks caeser, it works.

evanlill wrote Jun 19, 2013 at 1:59 PM

Hi, I've used the code above but it simply does not seem to work.
Do I need to add the Jquery.js to my project?

thierry_s wrote Sep 30, 2013 at 10:28 AM

Impact = Low ? if a user can't use arrows, backspace or delete character in a textbox (albeit with a masked edit extender), that's pretty high impact. Plus, given the millions of people using Chrome, it potentially impacts a lot of people.

Thanks bocca.

The downside to this is that it runs on everypage load where you use the masked edit extender (it's not cached either). The upside is that it doesn't require recompiling the ajax toolkit, and that is great.

evanlill, if it doesn't work, maybe you just need to have the 2 code blocks from bocca "functions used" BEFORE the other code block? funcbody and replaceAll must be defined before running it, in this order:
        if (String.prototype.replaceAll == null) {
            String.prototype.replaceAll = function (s, r) {
                var x = "", i = this.indexOf(s, 0), k = 0;
                while (i >= 0) {
                    x += this.substring(k, i) + r;
                    k = i + s.length;
                    i = this.indexOf(s, k);
                }
                return x + this.substring(k, this.length);
            };
        }

        function funcbody(f) {
            var s = f.toString();
            return s.substring(s.indexOf('{'));
        }
        
        try { p = Sys.Extended.UI.MaskedEditBehavior.prototype; }
        catch (e) { p = null; }
        if (p != null) {
            p._ExecuteNav = new Function("g", "h",
                'var c=-1,e=" ",a="",b=false,d=true,p="keypress",s="keydown";' +
                    funcbody(p._ExecuteNav)
                        .replaceAll('g.type==p', '(g.type==p||g.type==s)'));
        }