Index: trunk/grails-app/controllers/EntryDetailedController.groovy
===================================================================
--- trunk/grails-app/controllers/EntryDetailedController.groovy	(revision 832)
+++ trunk/grails-app/controllers/EntryDetailedController.groovy	(revision 833)
@@ -31,8 +31,8 @@
         if(entryInstance) {
             if(entryInstance.enteredBy.loginName == authService.currentUser.loginName) {
-                def taskID = entryInstance.task.id
+                def taskId = entryInstance.task.id
                 entryInstance.delete(flush:true)
                 flash.message = "Entry ${params.id} deleted"
-                redirect(controller: 'taskDetailed', action: 'show', id: taskID)
+                redirect(controller: 'taskDetailed', action: 'show', id: taskId)
             }
             else {
@@ -94,6 +94,7 @@
     def ajaxCreate = {
         if(!params.taskId || !params.entryTypeId) {
-            flash.message = g.message(code:"entry.create.no.params")
-            redirect(controller:"taskDetailed", action:"search")
+            response.status = 403
+            params.errorMessage = g.message(code: "entry.create.no.params.ajax")
+            render(template: "/shared/messages")
             return
         }
@@ -102,6 +103,7 @@
 
         if(!taskInstance) {
-            flash.message = g.message(code:"task.notFound")
-            redirect(controller:"taskDetailed", action:"search")
+            response.status = 403
+            params.errorMessage = g.message(code:"default.not.found", args:['Task',params.taskId])
+            render(template: "/shared/messages")
             return
         }
@@ -109,9 +111,11 @@
         // Check for Complete task.
         if(taskInstance.taskStatus.id == 3) {
-            flash.errorMessage = g.message(code:"task.operationNotPermittedOnCompleteTask")
-            redirect(controller:"taskDetailed", action:"show", id: taskInstance.id)
+            response.status = 403
+            params.errorMessage = g.message(code:"task.operationNotPermittedOnCompleteTask")
+            render(template: "/shared/messages")
             return
         }
 
+        // Success.
         def entryInstance = new Entry()
         entryInstance.task = taskInstance
@@ -119,4 +123,30 @@
         render(template: "create", model: ['entryInstance': entryInstance])
     }
+
+    def ajaxSave = {
+        def result = taskService.saveEntry(params)
+
+        // Success.
+        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
+            params.errorMessage = g.message(code: result.error.code)
+            render(template: "/shared/messages")
+            return
+        }
+
+        response.status = 403
+        render(template: "create", model: ['entryInstance': result.entryInstance])
+    } // ajaxSave
 
     def create = {
Index: trunk/grails-app/controllers/TaskDetailedController.groovy
===================================================================
--- trunk/grails-app/controllers/TaskDetailedController.groovy	(revision 832)
+++ trunk/grails-app/controllers/TaskDetailedController.groovy	(revision 833)
@@ -424,4 +424,9 @@
                                                         }
 
+            def entryPMList = Entry.withCriteria {
+                                                                eq("entryType", EntryType.get(6))
+                                                                eq("task", taskInstance)
+                                                        }
+
             def subTaskInstanceList = Task.findAllByParentTaskAndTrash(taskInstance, false, params)
             def subTaskInstanceTotal = Task.countByParentTaskAndTrash(taskInstance, false)
@@ -450,4 +455,5 @@
                             entryCauseList: entryCauseList,
                             entryWorkDoneList: entryWorkDoneList,
+                            entryPMList: entryPMList,
                             taskProcedureRevision: taskProcedureRevision,
                             taskProcedureExits: taskProcedureExits,
Index: trunk/grails-app/i18n/messages.properties
===================================================================
--- trunk/grails-app/i18n/messages.properties	(revision 832)
+++ trunk/grails-app/i18n/messages.properties	(revision 833)
@@ -176,4 +176,5 @@
 
 entry.create.no.params=Please select a task, then add an entry.
+entry.create.no.params.ajax=Incorrect params supplied.
 
 taskRecurringSchedule.notFound=Could not complete operation, recurring schedule not found.
Index: trunk/grails-app/views/entryDetailed/_create.gsp
===================================================================
--- trunk/grails-app/views/entryDetailed/_create.gsp	(revision 832)
+++ trunk/grails-app/views/entryDetailed/_create.gsp	(revision 833)
@@ -1,4 +1,14 @@
 
-    <g:form action="save" method="post" >
+
+    <g:render template="/shared/messages" />
+    <g:hasErrors bean="${entryInstance}">
+        <div class="errors">
+            <g:renderErrors bean="${entryInstance}" as="list" />
+        </div>
+    </g:hasErrors>
+    <div class="pane_close">
+        <img  src="${resource(dir:'images/skin',file:'cross.png')}" alt="Close" title="Close"/>
+    </div>
+    <g:form action="ajaxSave" method="post" name="createEntryForm">
         <g:hiddenField name="task.id" value="${entryInstance.task.id}" />
         <g:hiddenField name="entryType.id" value="${entryInstance.entryType.id}" />
Index: trunk/grails-app/views/taskDetailed/_showProcedureTab.gsp
===================================================================
--- trunk/grails-app/views/taskDetailed/_showProcedureTab.gsp	(revision 832)
+++ trunk/grails-app/views/taskDetailed/_showProcedureTab.gsp	(revision 833)
@@ -25,5 +25,18 @@
         <br />
 
-        <div id="pmEntryContainer"></div>
+        <div id="pmEntryContainer">
+            <g:if test="${entryPMList.isEmpty()}">
+                <h1>No PM Entries</h1>
+                <br />
+            </g:if>
+            <g:else>
+                <g:render template="/entryDetailed/list"
+                                    model="['entryList':entryPMList]" />
+            </g:else>
+        </div>
+
+        <br />
+
+        <div id="createPMEntryContainer" style="display:none;"></div>
 
         <div style="text-align:right;" id="pmEntryButton">
@@ -32,8 +45,10 @@
                             class="add"
                             value="Add PM Entry"
-                            onclick="loadEntryForm(jQuery('#pmEntryContainer'),
-                                                                    jQuery('#pmEntryButton'),
-                                                                    {taskId: ${taskInstance?.id}, entryTypeId: 6})" />
+                            onclick="getCreateEntryForm(jQuery('#pmEntryContainer'),
+                                                                                jQuery('#createPMEntryContainer'),
+                                                                                jQuery('#pmEntryButton'),
+                                                                                {taskId: ${taskInstance?.id}, entryTypeId: 6})" />
             </span>
         </div>
+
     </g:else>
Index: trunk/grails-app/views/taskDetailed/_showTaskTab.gsp
===================================================================
--- trunk/grails-app/views/taskDetailed/_showTaskTab.gsp	(revision 832)
+++ trunk/grails-app/views/taskDetailed/_showTaskTab.gsp	(revision 833)
@@ -230,5 +230,5 @@
                 <tbody>
                     <g:each in="${entryFaultList}" status="i" var="entry">
-                            <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}"/>
+                            <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
 
                                 <td style="width:65%" onclick='window.location = "${request.getContextPath()}/entryDetailed/edit/${entry.id}"'>
@@ -300,5 +300,5 @@
                 <tbody>
                     <g:each in="${entryCauseList}" status="i" var="entry">
-                            <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}"/>
+                            <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
 
                                 <td style="width:65%" onclick='window.location = "${request.getContextPath()}/entryDetailed/edit/${entry.id}"'>
@@ -339,61 +339,28 @@
     <br />
 
-    <g:if test="${entryWorkDoneList.isEmpty()}">
-        <h1>No Work Done</h1>
-        <br />
-    </g:if>
-    <g:else>
-        <div class="list">
-            <h1>Work Done</h1>
-            <table>
-                <thead>
-                    <tr>
-                        <th>Comment</th>
-                        <th>Date Done</th>
-                        <th>Duration</th>
-                        <th>Entered By</th>
-                        <th></th>
-                    </tr>
-                </thead>
-                <tbody>
-                    <g:each in="${entryWorkDoneList}" status="i" var="entry">
-                            <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}"/>
-
-                                <td width="65%" onclick='window.location = "${request.getContextPath()}/entryDetailed/edit/${entry.id}"'>
-                                    ${entry.comment.encodeAsHTML()}
-                                </td>
-
-                                <td onclick='window.location = "${request.getContextPath()}/entryDetailed/edit/${entry.id}"'>
-                                    <g:formatDate date="${entry.dateDone}" format="EEE, dd-MMM-yyyy"/>
-                                </td>
-
-                                <td onclick='window.location = "${request.getContextPath()}/entryDetailed/edit/${entry.id}"'>
-                                    ${entry.durationHour}:${entry.durationMinute}
-                                </td>
-
-                                <td onclick='window.location = "${request.getContextPath()}/entryDetailed/edit/${entry.id}"'>
-                                    ${entry.enteredBy.encodeAsHTML()}
-                                </td>
-
-                                <td class="notClickable">
-                                    <g:link controller="entryDetailed" action="edit" id="${entry.id}">
-                                        <img  src="${resource(dir:'images/skin',file:'database_edit.png')}" alt="Edit" title="Edit" />
-                                    </g:link>
-                                </td>
-
-                            </tr>
-                    </g:each>
-                </tbody>
-            </table>
-        </div>
-    </g:else>
-
-    <div class="buttons">
-        <g:form controller="entryDetailed">
-            <g:hiddenField name="taskInstance.id" value="${taskInstance?.id}" />
-            <g:hiddenField name="entryType.id" value="3" />
-            <span class="button">
-                <g:actionSubmit value="Add Work Done" action="create"  class="add"/>
-            </span>
-        </g:form>
-    </div>
+    <div id="workDoneContainer">
+        <g:if test="${entryWorkDoneList.isEmpty()}">
+            <h1>No Work Done</h1>
+            <br />
+        </g:if>
+        <g:else>
+            <g:render template="/entryDetailed/list"
+                                model="['entryList':entryWorkDoneList]" />
+        </g:else>
+    </div>
+
+    <br />
+
+    <div id="createWorkDoneContainer" style="display:none;"></div>
+
+    <div style="text-align:right;" id="workDoneButton">
+        <span class="buttons">
+            <input type="button"
+                        class="add"
+                        value="Add Work Done"
+                        onclick="getCreateEntryForm(jQuery('#workDoneContainer'),
+                                                                            jQuery('#createWorkDoneContainer'),
+                                                                            jQuery('#workDoneButton'),
+                                                                            {taskId: ${taskInstance?.id}, entryTypeId: 3})" />
+        </span>
+    </div>
Index: trunk/web-app/css/main.css
===================================================================
--- trunk/web-app/css/main.css	(revision 832)
+++ trunk/web-app/css/main.css	(revision 833)
@@ -751,4 +751,5 @@
     right: 5px;
     padding: 5px;
+    cursor: pointer;
 }
 
Index: trunk/web-app/js/taskShow.js
===================================================================
--- trunk/web-app/js/taskShow.js	(revision 832)
+++ trunk/web-app/js/taskShow.js	(revision 833)
@@ -1,21 +1,83 @@
 
-// Load an Entry from via AJAX.
-// @container Container object to load response into.
+// 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}, 900, function() {
+            createContainer.find(':input[name="comment"]').focus();
+        });
+        // 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);
+        });
+}
+
+// Submit a create Entry form via AJAX.
+function submitCreateEntryForm(event) {
+
+    var actionUrl = getContextPath()+"/entryDetailed/ajaxSave/";
+
+    event.preventDefault();
+    var listContainer = event.data.listContainer;
+    var createContainer = event.data.createContainer;
+    var button = event.data.button;
+    var form = createContainer.find('form:first');
+
+    // On success reload listContainer.
+    function success(data, textStatus, jqXHR){
+        createContainer.hide();
+        listContainer.html(data);
+        button.show(600);
+    }
+
+    // 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);
+        }
+        else {
+            createContainer.html(errorIndication().show()).slideDown(600);
+        }
+        button.show(600);
+    }
+
+    // Start.
+    createContainer.html(loadingIndication().show()).slideDown(600);
+
+    jQuery.ajax({
+        url: actionUrl,
+        data: form.serializeArray(),
+        success: success,
+        error: error
+    });
+}
+
+// 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.
-// @args Params map to pass to actionUrl.
-function loadEntryForm(container, button, params) {
+// @params Params map to pass to actionUrl.
+function getCreateEntryForm(listContainer, createContainer, button, params) {
 
     var actionUrl = getContextPath()+"/entryDetailed/ajaxCreate/";
 
+    // On success load createContainer.
     function success(data, textStatus, jqXHR){
-        container.html(data);
-        jQuery('html,body').animate({scrollTop: container.offset().top}, 800, function() {
-            container.css("border", "1px solid #006DBA");
-            container.find(':input[name="comment"]').focus();
-        });
+        loadCreateContainer(data, createContainer, listContainer, button);
     }
 
+    // On error show controller responseText or show default error.
     function error(jqXHR, textStatus, errorThrown){
-        container.html(errorIndication().slideDown(600));
+        if(jqXHR.status == 403 && jqXHR.responseText){
+            loadCreateContainer(jqXHR.responseText, createContainer, listContainer, button);
+        }
+        else {
+            createContainer.html(errorIndication().show()).slideDown(600);
+        }
         button.show(600);
     }
@@ -23,5 +85,5 @@
     // Start.
     button.hide(600);
-    container.html(loadingIndication().slideDown(600));
+    createContainer.html(loadingIndication().show()).slideDown(600);
 
     jQuery.ajax({
@@ -32,2 +94,3 @@
     });
 }
+
