Prototype Element Update Confusion
At work we are currently working on reimplementing a piece of software called SNEEP. SNEEP is a plugin for repository software called EPrints which is developed at the University of Southampton. According to the Registry of Open Access Repositories (ROAR) EPrints currently has 333 installations around the world as of 6th August 2009. As part of the SNEEP plugin we have been adding in the ability to edit comments and notes using AJAX meaning that users don’t have to leave the deposit page to author their comments or notes.
EPrints comes with the Prototype and Scriptaculous JavaScript libraries installed so we had to use these as opposed to my regular choice of jQuery. Owing to the static approach used for generating the document views in EPrints we had to inject the whole comments section of the document using AJAX. We did this by having the server generate the DOM and then sending it back to the browser which injects it into the page. This way the page can dynamically load the comments box depending on if a user is logged in or not.
Initially we managed to get the code running with Firefox and Safari but we had no joy with the code in IE. Here is some of the code that was originally used.
1 function sneepCommentFormInit(transport) {
2 // Load in the HTML generated by the server side script
3 $('ep_sneep_main').update(transport.responseText);
4 // If the server sent back a form so the user can write a new comment
5 // then we need to remove the old submit button and add one which is
6 // attached to one of our JavaScript functions.
7 $$('.ep_sneep_comment_form_container').each(function(element) {
8 var submitButton = document.createElement('input');
9 submitButton.writeAttribute('type', 'button');
10 submitButton.writeAttribute('id', 'sneep_comment_submit');
11 submitButton.writeAttribute('value', $('sneep_comment_submit').readAttribute('value'));
12 submitButton.observe('click', sneepCommentFormSubmit);
13 $('sneep_comment_submit').remove();
14 element.appendChild(submitButton);
15 var inputcallback = document.createElement('input');
16 inputcallback.writeAttribute('type', 'hidden');
17 inputcallback.writeAttribute('name', 'callback');
18 inputcallback.writeAttribute('value', '1');
19 element.appendChild(inputcallback);
20 });
21 }
22
23 Event.observe(window, 'load', function() {
24 var rm = window.location.href.match(/(https?:\/\/.*)\/(\d+)\/?/);
25 if (rm != null) {
26 new Ajax.Request(rm[1]+'/cgi/sneep/view_sneep?eprintid='+rm[2]+'&type=comment', {
27 method: 'get',
28 onCreate: function() {
29 // Put up a loading message
30 },
31 onComplete: sneepCommentFormInit
32 });
33 }
34 });
The problem appeared to be that IE does not finish loading the updated content before attempting to add the hidden field and attaching a new submit button which calls our client side method rather than allowing the form to submit straight back to the server.
The solution we chose for this issue was to modify the initial on load function in the following way;
1 Event.observe(window, 'load', function() {
2 var rm = window.location.href.match(/(https?:\/\/.*)\/(\d+)\/?/);
3 if (rm != null) {
4 new Ajax.Request(rm[1]+'/cgi/sneep/view_sneep?eprintid='+rm[2]+'&type=comment', {
5 method: 'get',
6 onCreate: function() {
7 // Put up a loading message
8 },
9 onComplete: function(transport) {
10 $('ep_sneep_main').update(transport.responseText+
11 '<script type=\'text/javascript\'>'+
12 'sneepCommentFormInit();'+
13 '</script>');
14 }
15 });
16 }
17 });
Basically in this code we removed the code from sneepCommentFormInit() that handles the returned text and put it inside the anonymous onComplete method. We also appended some JavaScript that gets executed as soon as it is evaluated. This means that the form initialization code is only run once all of the HTML has been interpreted and loaded meaning that IE now has the submit intercept function correctly attached.