this.prepend = function(string, elem) {
var content = elem.innerHTML;
content = string + content;
elem.innerHTML = content;
}
Never do this.
You're taking the DOM content of the elem
(the growlList), serialising it to a new HTML string, prepending some HTML content, and parsing the joined HTML back into completely new DOM nodes. This loses all non-HTML-serialisable content, such as form field values, event handlers and JavaScript references. The animation still has a reference to the old HTMLElement node, which is no longer in the DOM, having been replaced by newly-parsed-from-content
elements.
Indeed, you usually want to avoid generating HTML strings at all:
growl = '<li id="' + gid + '" class="' + className + ' growl" style="display: none"><span class="close" title="close">x</span><h2>' + heading + '</h2><div class="growlContent">' + content + '</div></li>',
Any unescaped HTML-special characters in that content and you've broken your markup at best. At worst, the data comes from a malicious user and you've given yourself an XSS security hole.
Instead, use DOM-style methods, eg:
var span= document.createElement('span');
span.className=span.title= 'close';
span.appendChild(document.createTextNode('x'));
var h2= document.createElement('h2');
h2.appendChild(document.createTextNode(heading));
var div= document.createElement('div');
div.className= 'growlContent';
div.appendChild(document.createTextNode(content))
var li= document.createElement('li');
li.id= gid;
li.className= className;
li.appendChild(span);
li.appendChild(h2);
li.appendChild(div);
gl.insertBefore(li, gl.firstChild);
This is quite wordy, but it's easy to write a helper function to cut down on typing, eg:
gl.insertBefore(el('li', {id: gid, className: className), [
el('span', {className: 'close', title: 'close'}, 'x'),
el('h2', {}, heading),
el('div', {className: 'growlContent'}, content)
]), gl.firstChild);
// Element creation convenience function
//
function el(tag, attrs, content) {
var el= document.createElement(tag);
if (attrs!==undefined)
for (var k in attrs)
if (attrs.hasOwnProperty(k))
el[k]= attrs[k];
if (content!==undefined) {
if (typeof(content)==='string')
el.appendChild(document.createTextNode(content));
else
for (var i= 0; i<content.length; i++)
el.appendChild(content[i]);
}
return el;
};