Changeset 859


Ignore:
Timestamp:
Mar 13, 2011, 12:05:16 AM (14 years ago)
Author:
gav
Message:

Rework entry create and save ajax to allow multiple page element updates with JSON.

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/grails-app/controllers/EntryDetailedController.groovy

    r838 r859  
    1010
    1111    // the delete, save and update actions only accept POST requests
    12     static allowedMethods = [delete:'POST', save:'POST', update:'POST']
     12    static allowedMethods = [delete:'POST', save:'POST', update:'POST', ajaxCreate:'POST', ajaxSave:'POST']
    1313
    1414    def list = {
     
    106106    def ajaxCreate = {
    107107        if(!params.taskId || !params.entryTypeId) {
    108             response.status = 403
    109108            params.errorMessage = g.message(code: "entry.create.no.params.ajax")
    110             render(template: "/shared/messages")
     109            render(contentType:"text/json", status: 403, template: "/shared/messages")
    111110            return
    112111        }
     
    115114
    116115        if(!taskInstance) {
    117             response.status = 403
    118116            params.errorMessage = g.message(code:"default.not.found", args:['Task',params.taskId])
    119             render(template: "/shared/messages")
     117            render(contentType:"text/json", status: 403, template: "/shared/messages")
    120118            return
    121119        }
     
    123121        // Check for Complete task.
    124122        if(taskInstance.taskStatus.id == 3) {
    125             response.status = 403
    126123            params.errorMessage = g.message(code:"task.operationNotPermittedOnCompleteTask")
    127             render(template: "/shared/messages")
     124            render(contentType:"text/json", status: 403, template: "/shared/messages")
    128125            return
    129126        }
     
    133130        entryInstance.task = taskInstance
    134131        entryInstance.entryType = EntryType.read(params.entryTypeId)
    135         render(template: "create", model: ['entryInstance': entryInstance])
    136     }
     132        def model = ['entryInstance': entryInstance]
     133
     134        render(contentType:"text/json") {
     135            updates = array {
     136                element([ mode: 'replace', target:"$params.target", content: g.render(template: 'create', model:model) ])
     137            }
     138        }
     139
     140    } // ajaxCreate
    137141
    138142    def ajaxSave = {
     
    142146        if(!result.error) {
    143147            def entryList = Entry.withCriteria {
    144                                                                 eq("entryType", result.entryInstance.entryType)
    145                                                                 task {
    146                                                                     idEq(result.taskId)
    147                                                                 }
    148                                                         }
    149             render(template: "list", model: ['entryList': entryList])
    150             return
    151         }
    152 
    153         if(result.error.code != "default.create.failure") {
    154             response.status = 403
     148                                            eq("entryType", result.entryInstance.entryType)
     149                                            task {
     150                                                idEq(result.taskId)
     151                                            }
     152                                    }
     153
     154            def model = ['entryList': entryList]
     155
     156            render(contentType:"text/json") {
     157                updates = array {
     158                    element([ mode: 'replace', target:"$params.target", content: g.render(template: 'list', model:model) ])
     159                }
     160            }
     161            return
     162        }
     163
     164        if(result.error.code != "default.create.failure")
    155165            params.errorMessage = g.message(code: result.error.code)
    156             render(template: "/shared/messages")
    157             return
    158         }
    159 
    160         response.status = 403
    161         render(template: "create", model: ['entryInstance': result.entryInstance])
     166
     167        def model = ['entryInstance': result.entryInstance]
     168        render(contentType:"text/json", status: 403, template: "create", model: model)
    162169    } // ajaxSave
    163170
  • trunk/grails-app/views/taskDetailed/_showProcedureTab.gsp

    r833 r859  
    4646                            value="Add PM Entry"
    4747                            onclick="getCreateEntryForm(jQuery('#pmEntryContainer'),
    48                                                                                 jQuery('#createPMEntryContainer'),
    4948                                                                                jQuery('#pmEntryButton'),
    50                                                                                 {taskId: ${taskInstance?.id}, entryTypeId: 6})" />
     49                                                                                {target: '#createPMEntryContainer',
     50                                                                                taskId: ${taskInstance?.id},
     51                                                                                entryTypeId: 6})" />
    5152            </span>
    5253        </div>
  • trunk/grails-app/views/taskDetailed/_showTaskTab.gsp

    r846 r859  
    231231                        value="Add Fault"
    232232                        onclick="getCreateEntryForm(jQuery('#entryFaultContainer'),
    233                                                                             jQuery('#createEntryFaultContainer'),
    234233                                                                            jQuery('#entryFaultButton'),
    235                                                                             {taskId: ${taskInstance?.id}, entryTypeId: 1})" />
     234                                                                            {target: '#createEntryFaultContainer',
     235                                                                            taskId: ${taskInstance?.id},
     236                                                                            entryTypeId: 1})" />
    236237        </span>
    237238    </div>
     
    260261                        value="Add Cause"
    261262                        onclick="getCreateEntryForm(jQuery('#entryCauseContainer'),
    262                                                                             jQuery('#createEntryCauseContainer'),
    263263                                                                            jQuery('#entryCauseButton'),
    264                                                                             {taskId: ${taskInstance?.id}, entryTypeId: 2})" />
     264                                                                            {target: '#createEntryCauseContainer',
     265                                                                            taskId: ${taskInstance?.id},
     266                                                                            entryTypeId: 2})" />
    265267        </span>
    266268    </div>
     
    289291                        value="Add Work Done"
    290292                        onclick="getCreateEntryForm(jQuery('#workDoneContainer'),
    291                                                                             jQuery('#createWorkDoneContainer'),
    292293                                                                            jQuery('#workDoneButton'),
    293                                                                             {taskId: ${taskInstance?.id}, entryTypeId: 3})" />
     294                                                                            {target: '#createWorkDoneContainer',
     295                                                                            taskId: ${taskInstance?.id},
     296                                                                            entryTypeId: 3})" />
    294297        </span>
    295298    </div>
  • trunk/web-app/js/application.js

    r825 r859  
    1919}
    2020
    21 function errorIndication() {
    22     return jQuery('#jQueryAjaxDefaultError').clone();
     21function errorIndication(jqXHR, textStatus, errorThrown) {
     22    return jQuery('#jQueryAjaxDefaultError').clone().append('Status:'+jqXHR.status+', '+textStatus+'.');
    2323}
     24
     25// Apply updates to multiple page elements.
     26// @json JSON response object from an ajax request.
     27// @json.updates Array of element updates to apply.
     28// @element.mode The update mode: execute or replace, prepend, append.
     29// @element.script Script to execute, if execute mode.
     30// @element.target jQuery target selector, if update mode.
     31// @element.content Content to update target with, if update mode.
     32function applyElementUpdates(json) {
     33    var updates;
     34    var script;
     35
     36    if(json.updates) {
     37        updates = json.updates;
     38        var element;
     39        var scripts = new Array();
     40
     41        for(element in updates) {
     42            element = updates[element];
     43
     44            switch(element.mode) {
     45                case 'execute':
     46                    scripts.push(element.script);
     47                    break;
     48                case 'replace':
     49                    jQuery(element.target).html(element.content);
     50                    break;
     51                case 'prepend':
     52                    jQuery(element.target).prepend(element.content);
     53                    break;
     54                case 'append':
     55                    jQuery(element.target).append(element.content);
     56                    break;
     57            }
     58        }
     59
     60        // Run scripts.
     61        for(script in scripts) {
     62            script = scripts[script];
     63            eval(script);
     64        }
     65
     66    } // if(json.updates)
     67} // applyElementUpdates
     68
     69
     70
  • trunk/web-app/js/taskShow.js

    r851 r859  
    11
    2 // Load data into createContainer and register events.
    3 function loadCreateContainer(data, createContainer, listContainer, button) {
    4         // Load the response data and show container.
    5         createContainer.html(data).slideDown(800);
    6         // Scroll the window.
    7         jQuery('html,body').animate({scrollTop: createContainer.offset().top - 70}, 900, function() {
    8             createContainer.find(':input[name="comment"]').focus();
    9         });
    10         // Register 'submit_*' input button click handlers.
    11         createContainer.find('input[name^="submit_"]').click(function(){
    12             createContainer.find(':input[name="submitAction"]').val(jQuery(this).attr('name'));
    13             createContainer.find('form:first').submit();
    14         });
    15         // Hijack form submit to use our function.
    16         var eventData = {listContainer:listContainer, createContainer:createContainer, button:button};
    17         createContainer.find('form:first').submit(eventData, submitCreateEntryForm);
    18         // Register the close img click handler.
    19         createContainer.find('.pane_close img').click(function(){
    20             createContainer.slideUp(600);
    21             button.show(600, function() {
    22                 if(jQuery.browser.msie) {
    23                     jQuery(this).get(0).style.removeAttribute('filter'); // Remove blur/fuzzy text in IE.
    24                 }
    25             });
    26         });
     2function showButton(button) {
     3    button.show(600, function() {
     4        if(jQuery.browser.msie) {
     5            jQuery(this).get(0).style.removeAttribute('filter'); // Remove blur/fuzzy text in IE.
     6        }
     7    });
     8}
     9
     10function createEntryFormInit(target, listContainer, button) {
     11
     12    // Show.
     13    target.slideDown(800);
     14    // Scroll the window.
     15    jQuery('html,body').animate({scrollTop: target.offset().top - 70}, 900, function() {
     16        target.find(':input[name="comment"]').focus();
     17    });
     18    // Register 'submit_*' input button click handlers.
     19    target.find('input[name^="submit_"]').click(function(){
     20        target.find(':input[name="submitAction"]').val(jQuery(this).attr('name'));
     21        target.find('form:first').submit();
     22    });
     23    // Redirect form submit to use our function.
     24    var eventData = {listContainer:listContainer, source:target, button:button};
     25    target.find('form:first').submit(eventData, submitCreateEntryForm);
     26    // Register the close img click handler.
     27    target.find('.pane_close img').click(function(){
     28        target.slideUp(600);
     29        showButton(button);
     30    });
     31
    2732}
    2833
     
    3439    event.preventDefault();
    3540    var listContainer = event.data.listContainer;
    36     var createContainer = event.data.createContainer;
     41    var source = event.data.source;
    3742    var button = event.data.button;
    38     var form = createContainer.find('form:first');
     43    var form = source.find('form:first');
    3944
    4045    // On success reload listContainer.
    41     function success(data, textStatus, jqXHR){
    42         createContainer.hide();
    43         listContainer.html(data);
    44         button.show(600, function() {
    45             if(jQuery.browser.msie) {
    46                 jQuery(this).get(0).style.removeAttribute('filter'); // Remove blur/fuzzy text in IE.
    47             }
    48         });
     46    function success(data, textStatus, jqXHR) {
     47        source.hide();
     48        applyElementUpdates(data);
     49        showButton(button);
    4950    }
    5051
    5152    // On create failure controller sets 403 and returns the form template.
    52     function error(jqXHR, textStatus, errorThrown){
    53         if(jqXHR.status == 403 && jqXHR.responseText){
    54             loadCreateContainer(jqXHR.responseText, createContainer, listContainer, button);
     53    function error(jqXHR, textStatus, errorThrown) {
     54        if(jqXHR.status == 403 && jqXHR.responseText) {
     55            source.html(jqXHR.responseText);
     56            createEntryFormInit(source, listContainer, button);
    5557        }
    5658        else {
    57             createContainer.html(savedHtml);
    58             createContainer.prepend(errorIndication().show()).slideDown(600);
     59            source.html(savedHtml);
     60            source.prepend(errorIndication(jqXHR, textStatus, errorThrown).show()).slideDown(600);
    5961            // Scroll the window.
    60             jQuery('html,body').animate({scrollTop: createContainer.offset().top - 70}, 900, function() {
    61                 createContainer.find(':input[name="comment"]').focus();
     62            jQuery('html,body').animate({scrollTop: source.offset().top - 70}, 900, function() {
     63                source.find(':input[name="comment"]').focus();
    6264            });
    6365        }
     
    6567
    6668    // Start.
    67     var savedHtml = createContainer.children().detach();
    68     createContainer.html(loadingIndication().show()).slideDown(600);
     69    var savedHtml = source.children().detach();
     70    var params = form.serializeArray();
     71    params.push({name:'target', value:listContainer.selector});
     72    source.html(loadingIndication().show()).slideDown(600);
    6973
    7074    jQuery.ajax({
    7175        url: actionUrl,
    72         data: form.serializeArray(),
     76        data: params,
     77        type: 'POST',
     78        dataType: 'json',
    7379        success: success,
    7480        error: error
     
    7884// Get a create Entry form via AJAX.
    7985// @listContainer Container object to reload list into.
    80 // @createContainer Container object to load response into.
    8186// @button Button object used to trigger this function.
    8287// @params Params map to pass to actionUrl.
    83 function getCreateEntryForm(listContainer, createContainer, button, params) {
     88// @params.target Selector indicating target to load response into.
     89function getCreateEntryForm(listContainer, button, params) {
    8490
    8591    var actionUrl = getContextPath()+"/entryDetailed/ajaxCreate/";
     92    var target = jQuery(params.target);
    8693
    87     // On success load createContainer.
    88     function success(data, textStatus, jqXHR){
    89         loadCreateContainer(data, createContainer, listContainer, button);
     94    // On success load target.
     95    function success(data, textStatus, jqXHR) {
     96        applyElementUpdates(data);
     97        createEntryFormInit(target, listContainer, button);
    9098    }
    9199
    92100    // On error show controller responseText or show default error.
    93     function error(jqXHR, textStatus, errorThrown){
    94         if(jqXHR.status == 403 && jqXHR.responseText){
    95             loadCreateContainer(jqXHR.responseText, createContainer, listContainer, button);
     101    function error(jqXHR, textStatus, errorThrown) {
     102        if(jqXHR.status == 403 && jqXHR.responseText) {
     103            target.html(jqXHR.responseText);
    96104        }
    97105        else {
    98             createContainer.html(errorIndication().show()).slideDown(600);
     106            target.html(errorIndication(jqXHR, textStatus, errorThrown).show());
    99107        }
    100         button.show(600, function() {
    101             if(jQuery.browser.msie) {
    102                 jQuery(this).get(0).style.removeAttribute('filter'); // Remove blur/fuzzy text in IE.
    103             }
    104         });
     108        showButton(button);
    105109    }
    106110
    107111    // Start.
    108112    button.hide(600);
    109     createContainer.html(loadingIndication().show()).slideDown(600);
     113    target.html(loadingIndication().show()).slideDown(600);
    110114
    111115    jQuery.ajax({
    112116        url: actionUrl,
    113117        data: params,
     118        type: 'POST',
     119        dataType: 'json',
    114120        success: success,
    115121        error: error
Note: See TracChangeset for help on using the changeset viewer.