The Mutate library provides a uniform API across the various browsers for changing the DOM tree nodes in several ways.
For the remove, replace or update functions, if the FORK.Event object is defined (i.e. event.js has been included in the page), then all event handlers registered through FORK.Event.addListener() will be purged from the DOM nodes to be removed using FORK.Event.purgeElement(). This is to avoid an Internet Explorer memory leak.
The contents of script blocks in the HTML strings added to the page are evaluated using JavaScript's eval(). See the eval script implications for the implications of using eval this way.
This library does not enable the mutation of the option elements within a select element. You should be able to replace an entire select elements. The mutation of select elements will be investigated further for a future Fork release.
Determines if the browser supports the functions in Fork's mutate library. Returns true of so and false otherwise.
if (FORK.Mutate.isSupported()) {
FORK.Mutate.update('foo', 'new content for foo');
} else {
alert('Your browser does not support the Fork mutate library.');
}
The contents of element will be replaced with html. If html contains any JavaScript elements they will be removed and evaluated using JavaScript's eval function. See the general docs for the implications of using eval this way.
"eval" then script blocks in the HTML will be evaluated. If set to "strip" then the script blocks will not be evaluated.var div = document.getElementById('myDiv');
FORK.Mutate.update(div,
'<p>new paragraph</p><script type="text/javascript">alert("hi")</script>');
var str = '<p>new paragraph</p><script type="text/javascript">alert("hi")</script>';
FORK.Mutate.update("myDiv", str, "eval");
var str = '<p>new paragraph</p><script type="text/javascript">alert("hi")</script>';
FORK.Mutate.update("myDiv", str, "strip");
The element will be replaced with html. Otherwise the same as update.
The html will be inserted before element. Otherwise the same as update.
The html will be inserted as the first child of element. Otherwise the same as update.
The html will be inserted as the last child of element. Otherwise the same as update.
The html will be inserted after element. Otherwise the same as update.
The element will be removed from the DOM.
The Fork Mutate library uses eval() to automatically evaluate the contents of any script blocks that exist in the html string being added to the page. (It might be nicer if innerHTML automatically evaluated script blocks being inserted but that isn't the case. Netscape Navigator 6 actually did do this.) The technique of using eval() is a design decision with subtle but important implications that may be important from time to time.
The main issue is the scope of entities (eg. variables or functions) defined in the evaluated script. Because the call to eval() occurs inside a JavaScript function, entities defined in the evaluated script may not persist after eval() returns. If you do want to define global entities you may look at writing something like the following snip inside the code block.
window.foo = 2; // instead of var foo = 2
The Fork Mutate library was designed for working a particular way with Ajax and the server responses. Some people use other techniques and one popular one is to dynamically load script files into a web page.
In many browsers it is possible to dynamically load a JavaScript file which will automatically execute after download. This can be done by writing the following.
var s = document.createElement('script');
s.src = 'path/to/script.js';
document.body.appendChild(s);
The above effectively adds the following HTML to the page
<script src="path/to/script.js"></script>
You might think that you can use the following JavaScript to get the same effect but it is not true
FORK.Mutate.insertBottom(document.body, '<script src="path/to/script.js"></script>')
Because the Fork Mutate functions evaluate the contents of script blocks and ignore src attributes, if you try the above nothing will happen since the script block is empty. You could do the following however and it may be helpful in some situations but wasteful in others.
FORK.Mutate.insertBottom(document.body,
"<script>var s=document.createElement('script');s.src='path/to/script.js'; document.body.appendChild(s);</script>");
If you are dynamically inserting many files you probably would benefit from a little helper function like the following.
function dynamicInsert(url) {
var s = document.createElement('script');
s.src = url;
document.body.appendChild(s);
}
Script insertion as an alternative to using eval() has been attempted by regulars (particularly Randy Webb) on comp.lang.javascript but the technique may have other drawbacks. As of Dec 2006, the test results in many current browsers looks like this technique is usable in many modern browsers.
There are other issues with dynamically loading scripts. One in particular is execution order. I wrote a little script to test order of execution
window.onload = function() {
var s = document.createElement('script');
s.src = 'alertOne.js'; // alert('alertOne.js');
document.body.appendChild(s);
alert('after');
}
In Firefox 1.5 I first see the "after" alert but in Opera 9 first see the "alertOne.js" alert. The order of execution is not guaranteed. So if someone using the mutate functions has script tags with a src attribute and a following script block that depends on that dynamically loaded script then the whole procedure is likely broken.
If you want to dynamically load script files it is not necessarily a bad idea. As always it is necessary to understand what you are doing and the implications. One potentially nice benefit of dynamically loading scripts is that the scripts are executed in the global scope of the page.
There are other even more subtle consequences of using eval() as described. The point of this note is to draw your attention to the fact that the scripts evaluated by the Fork Mutate functions do not execute in the global space like script blocks do when they are served with the initial page. Scripts that are to be run with eval() must be written with care.
eval() just like Fork and none or few people seem to encounter these problems.
API influenced by Prototype