PDA

View Full Version : [OPEN] Solution to FF4/FF5 "regular expression too complex" with Ext JS 4



stevil
27 Jun 2011, 7:59 AM
Firefox 4 seems to have a bug that's tripped by the loadScripts functionality in Ext.core.Element.update().

In Ext JS 4, it seems that a more "clever" regex is used to isolate scripts from HTML markup. Great, but the regex trips up Firefox's regex engine with large DOM.

I've not filed this under Bugs, as I think we're really just tripping over a browser problem. If anyone at Sencha disagrees, I'll be happy to file a bug. Until then, I'd just as soon not waste your time.

The following workaround takes the tokenizing approach from Ext 2.x, and merges it into the current Element update() method. There's a similar workaround in the 3.x forums, but 1) I wanted to preserve as much of the 4.0 update() code as possible, and 2) Ext.override is not supported on Ext.core.Element, due to it's ancestry.




// no need to inflict this on other browsers
if (Ext.isGecko) {
Ext.core.Element.prototype.update = function (html, loadScripts, callback) {
var me = this,
id,
dom,
interval;

if (!me.dom) {
return me;
}
html = html || '';
dom = me.dom;

if (loadScripts !== true) {
dom.innerHTML = html;
Ext.callback(callback, me);
return me;
}

id = Ext.id();
html += '<span id="' + id + '"></span>';

// Ext JS 2.X script isolator
var tokenizeScripts = function (str) {
var result = {
scripts: [],
other: []
};
var outIdx = 0;
var matchStart, matchEnd, token;
var reStart = /<script.*?>/ig;
var reEnd = /<\/script>/ig;
while (matchStart = reStart.exec(str)) {
token = str.substring(outIdx, reStart.lastIndex - matchStart[0].length);
if (token.length > 0) result.other.push(token);
reEnd.lastIndex = reStart.lastIndex;
if (matchEnd = reEnd.exec(str)) {
var endIndex = reEnd.lastIndex - matchEnd[0].length;
token = str.substring(reStart.lastIndex, endIndex);
result.scripts.push([matchStart[0], token]);
reStart.lastIndex = reEnd.lastIndex;
outIdx = reEnd.lastIndex;
}
}
token = str.substring(outIdx);
if (token.length > 0) result.other.push(token);
return result;
};

interval = setInterval(function () {
if (!document.getElementById(id)) {
return false;
}
clearInterval(interval);
var DOC = document,
hd = DOC.getElementsByTagName("head")[0],
srcRe = /\ssrc=([\'\"])(.*?)\1/i,
typeRe = /\stype=([\'\"])(.*?)\1/i,
match,
attrs,
srcMatch,
typeMatch,
el,
s;

var hd = document.getElementsByTagName("head")[0];
var tokens = tokenizeScripts(html);

for (var i = 0; i < tokens.scripts.length; i++) {
var start = tokens.scripts[i][0];
var content = tokens.scripts[i][1];
var srcMatch = start ? start.match(srcRe) : false;
if (srcMatch && srcMatch[2]) {
var s = document.createElement("script");
s.src = srcMatch[2];
var typeMatch = start.match(typeRe);
if (typeMatch && typeMatch[2]) {
s.type = typeMatch[2];
}
hd.appendChild(s);
} else if (content && content.length > 0) {
if (window.execScript) {
window.execScript(content);
} else {
window.eval(content);
}
}
}


el = DOC.getElementById(id);
if (el) {
Ext.removeNode(el);
}
Ext.callback(callback, me);
}, 20);

var tokens = tokenizeScripts(html);
dom.innerHTML = tokens.other.join('');

return me;
};
}



I've run this on some fairly gnarly HTML/script markup in my application, and it works well so far.

Hope someone else finds this useful!

stevil
P.S. thanks to @jweber for this idea from Ext JS 3.x!

mitchellsimoens
27 Jun 2011, 8:12 AM
Reported! Also updated the title to include FF5

edspencer
1 Jul 2011, 12:21 PM
I don't really understand what the actual bug is here... could you update this with the template (http://www.sencha.com/forum/showthread.php?138165-How-to-report-a-bug)?

stevil
1 Jul 2011, 1:57 PM
I didn't create the bug report - it was originally a report of a workaround to a problem, and Mitchell moved it over here. That's why it's not in the template - I can get that done over the weekend, I believe.

Long story short - there are some HTML script tags that are long/complicated enough to blow up your script isolating Regex in ElementLoader, but only in FF 4 and up.

My workaround (which I'll post in the bug report), merges the old style Regex script isolator from 2.X into the current ElementLoader update() method.

stevil