Index: trunk/grails-app/controllers/EntryDetailedController.groovy
===================================================================
--- trunk/grails-app/controllers/EntryDetailedController.groovy	(revision 858)
+++ trunk/grails-app/controllers/EntryDetailedController.groovy	(revision 859)
@@ -10,5 +10,5 @@
 
     // the delete, save and update actions only accept POST requests
-    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST', ajaxCreate:'POST', ajaxSave:'POST']
 
     def list = {
@@ -106,7 +106,6 @@
     def ajaxCreate = {
         if(!params.taskId || !params.entryTypeId) {
-            response.status = 403
             params.errorMessage = g.message(code: "entry.create.no.params.ajax")
-            render(template: "/shared/messages")
+            render(contentType:"text/json", status: 403, template: "/shared/messages")
             return
         }
@@ -115,7 +114,6 @@
 
         if(!taskInstance) {
-            response.status = 403
             params.errorMessage = g.message(code:"default.not.found", args:['Task',params.taskId])
-            render(template: "/shared/messages")
+            render(contentType:"text/json", status: 403, template: "/shared/messages")
             return
         }
@@ -123,7 +121,6 @@
         // Check for Complete task.
         if(taskInstance.taskStatus.id == 3) {
-            response.status = 403
             params.errorMessage = g.message(code:"task.operationNotPermittedOnCompleteTask")
-            render(template: "/shared/messages")
+            render(contentType:"text/json", status: 403, template: "/shared/messages")
             return
         }
@@ -133,6 +130,13 @@
         entryInstance.task = taskInstance
         entryInstance.entryType = EntryType.read(params.entryTypeId)
-        render(template: "create", model: ['entryInstance': entryInstance])
-    }
+        def model = ['entryInstance': entryInstance]
+
+        render(contentType:"text/json") {
+            updates = array {
+                element([ mode: 'replace', target:"$params.target", content: g.render(template: 'create', model:model) ])
+            }
+        }
+
+    } // ajaxCreate
 
     def ajaxSave = {
@@ -142,22 +146,25 @@
         if(!result.error) {
             def entryList = Entry.withCriteria {
-                                                                eq("entryType", result.entryInstance.entryType)
-                                                                task {
-                                                                    idEq(result.taskId)
-                                                                }
-                                                        }
-            render(template: "list", model: ['entryList': entryList])
-            return
-        }
-
-        if(result.error.code != "default.create.failure") {
-            response.status = 403
+                                            eq("entryType", result.entryInstance.entryType)
+                                            task {
+                                                idEq(result.taskId)
+                                            }
+                                    }
+
+            def model = ['entryList': entryList]
+
+            render(contentType:"text/json") {
+                updates = array {
+                    element([ mode: 'replace', target:"$params.target", content: g.render(template: 'list', model:model) ])
+                }
+            }
+            return
+        }
+
+        if(result.error.code != "default.create.failure")
             params.errorMessage = g.message(code: result.error.code)
-            render(template: "/shared/messages")
-            return
-        }
-
-        response.status = 403
-        render(template: "create", model: ['entryInstance': result.entryInstance])
+
+        def model = ['entryInstance': result.entryInstance]
+        render(contentType:"text/json", status: 403, template: "create", model: model)
     } // ajaxSave
 
Index: trunk/grails-app/views/taskDetailed/_showProcedureTab.gsp
===================================================================
--- trunk/grails-app/views/taskDetailed/_showProcedureTab.gsp	(revision 858)
+++ trunk/grails-app/views/taskDetailed/_showProcedureTab.gsp	(revision 859)
@@ -46,7 +46,8 @@
                             value="Add PM Entry"
                             onclick="getCreateEntryForm(jQuery('#pmEntryContainer'),
-                                                                                jQuery('#createPMEntryContainer'),
                                                                                 jQuery('#pmEntryButton'),
-                                                                                {taskId: ${taskInstance?.id}, entryTypeId: 6})" />
+                                                                                {target: '#createPMEntryContainer',
+                                                                                taskId: ${taskInstance?.id},
+                                                                                entryTypeId: 6})" />
             </span>
         </div>
Index: trunk/grails-app/views/taskDetailed/_showTaskTab.gsp
===================================================================
--- trunk/grails-app/views/taskDetailed/_showTaskTab.gsp	(revision 858)
+++ trunk/grails-app/views/taskDetailed/_showTaskTab.gsp	(revision 859)
@@ -231,7 +231,8 @@
                         value="Add Fault"
                         onclick="getCreateEntryForm(jQuery('#entryFaultContainer'),
-                                                                            jQuery('#createEntryFaultContainer'),
                                                                             jQuery('#entryFaultButton'),
-                                                                            {taskId: ${taskInstance?.id}, entryTypeId: 1})" />
+                                                                            {target: '#createEntryFaultContainer',
+                                                                            taskId: ${taskInstance?.id},
+                                                                            entryTypeId: 1})" />
         </span>
     </div>
@@ -260,7 +261,8 @@
                         value="Add Cause"
                         onclick="getCreateEntryForm(jQuery('#entryCauseContainer'),
-                                                                            jQuery('#createEntryCauseContainer'),
                                                                             jQuery('#entryCauseButton'),
-                                                                            {taskId: ${taskInstance?.id}, entryTypeId: 2})" />
+                                                                            {target: '#createEntryCauseContainer',
+                                                                            taskId: ${taskInstance?.id},
+                                                                            entryTypeId: 2})" />
         </span>
     </div>
@@ -289,7 +291,8 @@
                         value="Add Work Done"
                         onclick="getCreateEntryForm(jQuery('#workDoneContainer'),
-                                                                            jQuery('#createWorkDoneContainer'),
                                                                             jQuery('#workDoneButton'),
-                                                                            {taskId: ${taskInstance?.id}, entryTypeId: 3})" />
+                                                                            {target: '#createWorkDoneContainer',
+                                                                            taskId: ${taskInstance?.id},
+                                                                            entryTypeId: 3})" />
         </span>
     </div>
Index: trunk/web-app/js/application.js
===================================================================
--- trunk/web-app/js/application.js	(revision 858)
+++ trunk/web-app/js/application.js	(revision 859)
@@ -19,5 +19,52 @@
 }
 
-function errorIndication() {
-    return jQuery('#jQueryAjaxDefaultError').clone();
+function errorIndication(jqXHR, textStatus, errorThrown) {
+    return jQuery('#jQueryAjaxDefaultError').clone().append('Status:'+jqXHR.status+', '+textStatus+'.');
 }
+
+// Apply updates to multiple page elements.
+// @json JSON response object from an ajax request.
+// @json.updates Array of element updates to apply.
+// @element.mode The update mode: execute or replace, prepend, append.
+// @element.script Script to execute, if execute mode.
+// @element.target jQuery target selector, if update mode.
+// @element.content Content to update target with, if update mode.
+function applyElementUpdates(json) {
+    var updates;
+    var script;
+
+    if(json.updates) {
+        updates = json.updates;
+        var element;
+        var scripts = new Array();
+
+        for(element in updates) {
+            element = updates[element];
+
+            switch(element.mode) {
+                case 'execute':
+                    scripts.push(element.script);
+                    break;
+                case 'replace':
+                    jQuery(element.target).html(element.content);
+                    break;
+                case 'prepend':
+                    jQuery(element.target).prepend(element.content);
+                    break;
+                case 'append':
+                    jQuery(element.target).append(element.content);
+                    break;
+            }
+        }
+
+        // Run scripts.
+        for(script in scripts) {
+            script = scripts[script];
+            eval(script);
+        }
+
+    } // if(json.updates)
+} // applyElementUpdates
+
+
+
Index: trunk/web-app/js/taskShow.js
===================================================================
--- trunk/web-app/js/taskShow.js	(revision 858)
+++ trunk/web-app/js/taskShow.js	(revision 859)
@@ -1,28 +1,33 @@
 
-// Load data into createContainer and register events.
-function loadCreateContainer(data, createContainer, listContainer, button) {
-        // Load the response data and show container.
-        createContainer.html(data).slideDown(800);
-        // Scroll the window.
-        jQuery('html,body').animate({scrollTop: createContainer.offset().top - 70}, 900, function() {
-            createContainer.find(':input[name="comment"]').focus();
-        });
-        // Register 'submit_*' input button click handlers.
-        createContainer.find('input[name^="submit_"]').click(function(){
-            createContainer.find(':input[name="submitAction"]').val(jQuery(this).attr('name'));
-            createContainer.find('form:first').submit();
-        });
-        // Hijack form submit to use our function.
-        var eventData = {listContainer:listContainer, createContainer:createContainer, button:button};
-        createContainer.find('form:first').submit(eventData, submitCreateEntryForm);
-        // Register the close img click handler.
-        createContainer.find('.pane_close img').click(function(){
-            createContainer.slideUp(600);
-            button.show(600, function() {
-                if(jQuery.browser.msie) {
-                    jQuery(this).get(0).style.removeAttribute('filter'); // Remove blur/fuzzy text in IE.
-                }
-            });
-        });
+function showButton(button) {
+    button.show(600, function() {
+        if(jQuery.browser.msie) {
+            jQuery(this).get(0).style.removeAttribute('filter'); // Remove blur/fuzzy text in IE.
+        }
+    });
+}
+
+function createEntryFormInit(target, listContainer, button) {
+
+    // Show.
+    target.slideDown(800);
+    // Scroll the window.
+    jQuery('html,body').animate({scrollTop: target.offset().top - 70}, 900, function() {
+        target.find(':input[name="comment"]').focus();
+    });
+    // Register 'submit_*' input button click handlers.
+    target.find('input[name^="submit_"]').click(function(){
+        target.find(':input[name="submitAction"]').val(jQuery(this).attr('name'));
+        target.find('form:first').submit();
+    });
+    // Redirect form submit to use our function.
+    var eventData = {listContainer:listContainer, source:target, button:button};
+    target.find('form:first').submit(eventData, submitCreateEntryForm);
+    // Register the close img click handler.
+    target.find('.pane_close img').click(function(){
+        target.slideUp(600);
+        showButton(button);
+    });
+
 }
 
@@ -34,30 +39,27 @@
     event.preventDefault();
     var listContainer = event.data.listContainer;
-    var createContainer = event.data.createContainer;
+    var source = event.data.source;
     var button = event.data.button;
-    var form = createContainer.find('form:first');
+    var form = source.find('form:first');
 
     // On success reload listContainer.
-    function success(data, textStatus, jqXHR){
-        createContainer.hide();
-        listContainer.html(data);
-        button.show(600, function() {
-            if(jQuery.browser.msie) {
-                jQuery(this).get(0).style.removeAttribute('filter'); // Remove blur/fuzzy text in IE.
-            }
-        });
+    function success(data, textStatus, jqXHR) {
+        source.hide();
+        applyElementUpdates(data);
+        showButton(button);
     }
 
     // On create failure controller sets 403 and returns the form template.
-    function error(jqXHR, textStatus, errorThrown){
-        if(jqXHR.status == 403 && jqXHR.responseText){
-            loadCreateContainer(jqXHR.responseText, createContainer, listContainer, button);
+    function error(jqXHR, textStatus, errorThrown) {
+        if(jqXHR.status == 403 && jqXHR.responseText) {
+            source.html(jqXHR.responseText);
+            createEntryFormInit(source, listContainer, button);
         }
         else {
-            createContainer.html(savedHtml);
-            createContainer.prepend(errorIndication().show()).slideDown(600);
+            source.html(savedHtml);
+            source.prepend(errorIndication(jqXHR, textStatus, errorThrown).show()).slideDown(600);
             // Scroll the window.
-            jQuery('html,body').animate({scrollTop: createContainer.offset().top - 70}, 900, function() {
-                createContainer.find(':input[name="comment"]').focus();
+            jQuery('html,body').animate({scrollTop: source.offset().top - 70}, 900, function() {
+                source.find(':input[name="comment"]').focus();
             });
         }
@@ -65,10 +67,14 @@
 
     // Start.
-    var savedHtml = createContainer.children().detach();
-    createContainer.html(loadingIndication().show()).slideDown(600);
+    var savedHtml = source.children().detach();
+    var params = form.serializeArray();
+    params.push({name:'target', value:listContainer.selector});
+    source.html(loadingIndication().show()).slideDown(600);
 
     jQuery.ajax({
         url: actionUrl,
-        data: form.serializeArray(),
+        data: params,
+        type: 'POST',
+        dataType: 'json',
         success: success,
         error: error
@@ -78,38 +84,38 @@
 // Get a create Entry form via AJAX.
 // @listContainer Container object to reload list into.
-// @createContainer Container object to load response into.
 // @button Button object used to trigger this function.
 // @params Params map to pass to actionUrl.
-function getCreateEntryForm(listContainer, createContainer, button, params) {
+// @params.target Selector indicating target to load response into.
+function getCreateEntryForm(listContainer, button, params) {
 
     var actionUrl = getContextPath()+"/entryDetailed/ajaxCreate/";
+    var target = jQuery(params.target);
 
-    // On success load createContainer.
-    function success(data, textStatus, jqXHR){
-        loadCreateContainer(data, createContainer, listContainer, button);
+    // On success load target.
+    function success(data, textStatus, jqXHR) {
+        applyElementUpdates(data);
+        createEntryFormInit(target, listContainer, button);
     }
 
     // On error show controller responseText or show default error.
-    function error(jqXHR, textStatus, errorThrown){
-        if(jqXHR.status == 403 && jqXHR.responseText){
-            loadCreateContainer(jqXHR.responseText, createContainer, listContainer, button);
+    function error(jqXHR, textStatus, errorThrown) {
+        if(jqXHR.status == 403 && jqXHR.responseText) {
+            target.html(jqXHR.responseText);
         }
         else {
-            createContainer.html(errorIndication().show()).slideDown(600);
+            target.html(errorIndication(jqXHR, textStatus, errorThrown).show());
         }
-        button.show(600, function() {
-            if(jQuery.browser.msie) {
-                jQuery(this).get(0).style.removeAttribute('filter'); // Remove blur/fuzzy text in IE.
-            }
-        });
+        showButton(button);
     }
 
     // Start.
     button.hide(600);
-    createContainer.html(loadingIndication().show()).slideDown(600);
+    target.html(loadingIndication().show()).slideDown(600);
 
     jQuery.ajax({
         url: actionUrl,
         data: params,
+        type: 'POST',
+        dataType: 'json',
         success: success,
         error: error
