Prototype, tinyMCE, ‘too much recursion’

If you happen to be using TinyMCE and the Prototype library together and you’re getting a ‘too much recursion’ error in FireFox, make sure to upgrade to the latest version of Prototype, which at the time of this post is version 1.5.0. Near as I can tell, the only way to get version 1.5.0 is to either a) check it out of the subversion repository or b) download script.aculo.us, which contains version 1.5.0 in the lib directory of the distribution.

I think the ‘too much recursion’ Prototype / TinyMCE problem happens because Prototype stores a copy of the Array reverse function in a property called _reverse:

Array.prototype._reverse = Array.prototype.reverse;

and then redefines the reverse function, adding a argument ‘inline’:

reverse: function(inline) {
  return (inline !== false ? this : this.toArray())._reverse();
}

Somehow (and I’m not sure how this would happen) the copy happens again, which means that _reverse() would point to the redefined reverse() method function, which of course points to _reverse(), which leads to a infinite loop. Hence, ‘too much recursion’.

Regardless, the changelog from latest version of Prototype has a pointer to issue #3951 (but it doesn’t appear that the issues are public): in short, version 1.5.0 of Prototype does a check to make sure that _reverse() hasn’t been defined:

if (!Array.prototype._reverse)
  Array.prototype._reverse = Array.prototype.reverse;

In related news, if you’re using script.aculo.us with TinyMCE, make sure to embed the script.aculo.us js after the TinyMCE js.

Can’t add hyperlink with onclick to IE using DOM

Last week I was attempting to dynamically add hyperlinks that contained an onclick event to a document. The hyperlink, when written to the browser, would look something like this:

<a href="#" onclick="fireEvent(); return false;">fire away!</a>

and I was using code that looked something like this to produce the links (and yes, I know about real links):

<script>
function createLink(id) {
  var node = document.getElementById(id);
  var aNode = document.createElement("a");
  node.appendChild(aNode);
  aNode.setAttribute("href","#");
  aNode.setAttribute("onclick", "fireEvent(); return false;");
  aNode.appendChild(document.createTextNode("fire away!"));
}
function fireEvent() {
  alert('fire!');
}
</script>
<a href="#" onclick="createLink('mytable'); return false;">create link</a>
<table cellpadding="0" cellspacing="0" border="0" width="100%">
<tbody>
<tr>
  <td id="mytable"></td>
</tr>
</tbody>
</table>

Running the above code in Firefox worked fine, the fireEvent() method was invoked when you clicked the ‘fire away!’ link. The same exact code in IE didn’t work. Instead, it appeared that IE completely ignored the onclick event and just went with the value of the href attribute. The simple workaround, in this case at least, was to use the innerHTML property of the cell I was adding the link to, so the createLink() function became:

function createLink(id) {
  var node = document.getElementById(id);
  node.innerHTML = '<a href="#" onclick="fireEvent(); return false;">fire away!</a>';
}

Am I wrong in thinking that this is a bug?

Related:

Early event handlers
Javascript: createElement, innerHTML and IE security zones
can’t put a row into a table in IE using DOM methods


Updated 7/3/2006: My boss Bill sent a note mentioned the behaviors library which uses AOP techniques to reduce what the author calls ‘scattering’ and ‘tangling’ and would may also be a solution to the problem mentioned above.

Using a HOSTS file on OS X

In the Windows world it’s a reasonably straightforward process to add pseudo domain names using the HOSTS file usually located in c:\windows\system32\drivers\etc\. Open the file, add a name / IP address entry, save the changes and you’re off and running. It’s slightly more involved on OS X as this site details. OS X uses lookupd to do name resolution and by default (at least on my machine) it is configured to look to a DNS server before referencing the local HOSTS file, which is not how Windows works. Turns out it’s reasonably easy to change (as detailed on the macwrite.com link mentioned above):

cd /etc
sudo mkdir lookupd
cd lookupd
ls
cp hosts hosts.original
sudo echo LookupOrder Cache FF NI DNS DS > hosts
sudo kill -HUP 'cat /var/run/lookupd.pid'

After that’s done, you can add / delete / modify domain name to IP address mappings using the NetInfo Manager tool.

Links: 5-26-2006