Changeset 556 for trunk/grails-app


Ignore:
Timestamp:
Jun 10, 2010, 4:45:53 PM (10 years ago)
Author:
roberth
Message:

Improved the TemplateEditor? again: templates can be created and removed and some checks were built in to ensure that the same fields in different templates point to the same TemplateField? object.

Location:
trunk/grails-app
Files:
8 added
4 edited
2 moved

Legend:

Unmodified
Added
Removed
  • trunk/grails-app/controllers/dbnp/studycapturing/TemplateEditorController.groovy

    r544 r556  
    2828    def index = {
    2929        // Check whether a right entity is given
    30         _checkEntity();
     30        if( !_checkEntity() ) {
     31                        return
     32                }
    3133
    3234        // fetch all templates for this entity
    3335        def templates = Template.findAllByEntity(entity)
    3436
    35         // Check whether a template is already selected
     37                // Generate a human readable entity name
     38                def parts = entityName.tokenize( '.' );
     39                def humanReadableEntity = parts[ parts.size() - 1 ];
     40
     41        return [
     42            entity: entity,
     43            templates: templates,
     44            encryptedEntity: params.entity,
     45            humanReadableEntity: humanReadableEntity,
     46        ];
     47    }
     48
     49        /**
     50         * Shows the editing of a template
     51         */
     52        def template = {
     53        // Check whether a right entity is given
     54        if( !_checkEntity() ) {
     55                        return
     56                }
     57
     58        // Check whether a template is selected. If not, redirect the user to the index
    3659        def selectedTemplate = params.template;
    3760        def template = null;
     
    3962        if( selectedTemplate ) {
    4063            template = Template.get( selectedTemplate );
    41         }
     64        } else {
     65                        redirect(action:"index",params:[entity:params.entity])
     66                        return;
     67                }
     68
     69        // fetch all templates for this entity
     70        def templates = Template.findAllByEntity(entity)
     71
     72                // Generate a human readable entity name
     73                def parts = entityName.tokenize( '.' );
     74                def humanReadableEntity = parts[ parts.size() - 1 ];
     75
     76
     77
     78                // Find all available fields
     79                def allFields = TemplateField.findAllByEntity( entity ).sort { a, b -> a.name <=> b.name }
    4280
    4381        return [
     
    4684            encryptedEntity: params.entity,
    4785            fieldTypes: TemplateFieldType.list(),
    48            
    49             template: template
     86            humanReadableEntity: humanReadableEntity,
     87
     88            template: template,
     89                        allFields: allFields
    5090        ];
    51     }
     91
     92        }
     93
    5294
    5395    /**
     
    61103
    62104    /**
    63      * Adds a new template field using a AJAX call
     105     * Creates a new template using a AJAX call
     106         *
     107         * @return                      JSON object with two entries:
     108         *                                              id: [id of this object]
     109         *                                              html: HTML to replace the contents of the LI-item that was updated.
     110         *                                      On error the method gives a HTTP response status 500 and the error
     111     */
     112    def createTemplate = {
     113                // Decode the entity
     114        if( !_checkEntity() ) {
     115                        response.status = 500;
     116                        render "Incorrect entity given";
     117                        return;
     118                }
     119
     120                params.entity = entity;
     121
     122                // Create the template field and add it to the template
     123                def template = new Template( params );
     124        if (template.save(flush: true)) {
     125
     126                        def html = g.render( template: 'elements/liTemplateEditable', model: [template: template] );
     127                        def output = [ id: template.id, html: html ];
     128                        render output as JSON;
     129
     130            //render '';
     131        } else {
     132            response.status = 500;
     133            render 'Template could not be created because errors occurred.';
     134            return
     135        }
     136    }
     137
     138    /**
     139     * Updates a selected template using a AJAX call
     140         *
     141         * @param id    ID of the template to update
     142         * @return              JSON object with two entries:
     143         *                                      id: [id of this object]
     144         *                                      html: HTML to replace the contents of the LI-item that was updated.
     145         *                              On error the method gives a HTTP response status 500 and the error
     146     */
     147    def updateTemplate = {
     148        // Search for the template field
     149        def template = Template.get( params.id );
     150        if( !template ) {
     151            response.status = 404;
     152            render 'Template not found';
     153            return;
     154        }
     155
     156        // Update the field if it is not updated in between
     157        if (params.version) {
     158            def version = params.version.toLong()
     159            if (template.version > version) {
     160                response.status = 500;
     161                render 'Template was updated while you were working on it. Please reload and try again.';
     162                return
     163            }
     164        }
     165
     166        template.properties = params
     167        if (!template.hasErrors() && template.save(flush: true)) {
     168                        def html = g.render( template: 'elements/liTemplateEditable', model: [template: template] );
     169                        def output = [ id: template.id, html: html ];
     170                        render output as JSON;
     171        } else {
     172            response.status = 500;
     173            render 'Template was not updated because errors occurred.';
     174            return
     175        }
     176    }
     177
     178    /**
     179     * Deletes a template using a AJAX call
     180     *
     181         * @param template              ID of the template to move
     182         * @return                              JSON object with one entry:
     183         *                                                      id: [id of this object]
     184         *                                              On error the method gives a HTTP response status 500 and the error
     185     */
     186    def deleteTemplate = {
     187        // Search for the template field
     188        def  template = Template.get( params.template );
     189        if( !template ) {
     190            response.status = 404;
     191            render 'Template not found';
     192            return;
     193        }
     194
     195        // Delete the template field
     196                try {
     197                        template.delete(flush: true)
     198
     199                        def output = [ id: template.id ];
     200                        render output as JSON;
     201                }
     202                catch (org.springframework.dao.DataIntegrityViolationException e) {
     203            response.status = 500;
     204            render 'Template could not be deleted: ' + e.getMessage();
     205                }
     206    }
     207
     208
     209
     210
     211    /**
     212     * Creates a new template field using a AJAX call
    64213         *
    65214         * @param template      ID of the template to add a field to
     
    69218         *                                      On error the method gives a HTTP response status 500 and the error
    70219     */
    71     def addField = {
     220    def createField = {
    72221        // Search for the template
    73222        def template = Template.get( params.template );
     
    78227            return;
    79228        }
     229
     230                // Decode the entity, in order to set a good property
     231        if( !_checkEntity() ) {
     232                        response.status = 500;
     233                        render "Incorrect entity given";
     234                        return;
     235                }
     236
     237                params.entity = entity;
     238
     239                // See whether this field already exists. It is checked by name, type and unit and entity
     240                // The search is done using search by example (see http://grails.org/DomainClass+Dynamic+Methods, method find)
     241                def uniqueParams = [ name: params.name, type: params.type, unit: params.unit, entity: params.entity ];
     242                if( TemplateField.find( new TemplateField( uniqueParams ) ) ) {
     243                        response.status = 500;
     244                        render "A field with this name, type and unit already exists.";
     245                        return;
     246                }
    80247
    81248                // Create the template field and add it to the template
    82249                def templateField = new TemplateField( params );
    83250        if (templateField.save(flush: true)) {
    84                         template.fields.add( templateField );
    85 
    86                         def html = g.render( template: 'elements/liContent', model: [templateField: templateField, fieldTypes: TemplateFieldType.list()] );
     251
     252                        def html = g.render( template: 'elements/liFieldNotInUse', model: [templateField: templateField, fieldTypes: TemplateFieldType.list()] );
    87253                        def output = [ id: templateField.id, html: html ];
    88254                        render output as JSON;
     
    91257        } else {
    92258            response.status = 500;
    93             render 'TemplateField could not be added because errors occurred.';
     259            render 'TemplateField could not be created because errors occurred.';
    94260            return
    95261        }
     
    105271         *                              On error the method gives a HTTP response status 500 and the error
    106272     */
    107     def update = {
     273    def updateField = {
    108274        // Search for the template field
    109275        def templateField = TemplateField.get( params.id );
     
    125291        templateField.properties = params
    126292        if (!templateField.hasErrors() && templateField.save(flush: true)) {
    127                         def html = g.render( template: 'elements/liContent', model: [templateField: templateField, fieldTypes: TemplateFieldType.list()] );
     293                        def html = g.render( template: 'elements/liField', model: [templateField: templateField, fieldTypes: TemplateFieldType.list()] );
    128294                        def output = [ id: templateField.id, html: html ];
    129295                        render output as JSON;
     
    136302
    137303    /**
    138      * Deletes a selected template field from the template using a AJAX call
     304     * Deletes a template field using a AJAX call
     305     *
     306         * @param templateField ID of the templatefield to move
     307         * @return                              JSON object with one entry:
     308         *                                                      id: [id of this object]
     309         *                                              On error the method gives a HTTP response status 500 and the error
     310     */
     311    def deleteField = {
     312        // Search for the template field
     313        def  templateField = TemplateField.get( params.templateField );
     314        if( !templateField ) {
     315            response.status = 404;
     316            render 'TemplateField not found';
     317            return;
     318        }
     319
     320        // Delete the template field
     321                try {
     322                        templateField.delete(flush: true)
     323
     324                        def output = [ id: templateField.id ];
     325                        render output as JSON;
     326                }
     327                catch (org.springframework.dao.DataIntegrityViolationException e) {
     328            response.status = 500;
     329            render 'TemplateField could not be deleted: ' + e.getMessage();
     330                }
     331    }
     332
     333    /**
     334     * Adds a new template field to a template using a AJAX call
     335         *
     336         * @param template      ID of the template to add a field to
     337         * @return                      JSON object with two entries:
     338         *                                              id: [id of this object]
     339         *                                              html: HTML to replace the contents of the LI-item that was updated.
     340         *                                      On error the method gives a HTTP response status 404 or 500 and the error
     341     */
     342    def addField = {
     343        // Search for the template
     344        def template = Template.get( params.template );
     345
     346        if( !template ) {
     347            response.status = 404;
     348            render 'Template not found';
     349            return;
     350        }
     351
     352        // Search for the template field
     353        def templateField = TemplateField.get( params.templateField );
     354        if( !templateField ) {
     355            response.status = 404;
     356            render 'TemplateField does not exist';
     357            return;
     358        }
     359
     360        // The template field should exist within the template
     361        if( template.fields.contains( templateField ) ) {
     362            response.status = 500;
     363            render 'TemplateField is already found within template';
     364            return;
     365        }
     366                if( !params.position || Integer.parseInt( params.position ) == -1) {
     367                        template.fields.add( templateField )
     368                } else {
     369                        template.fields.add( Integer.parseInt( params.position ), templateField )
     370                }
     371
     372                def html = g.render( template: 'elements/liFieldSelected', model: [templateField: templateField, template: template, fieldTypes: TemplateFieldType.list()] );
     373                def output = [ id: templateField.id, html: html ];
     374                render output as JSON;
     375    }
     376
     377
     378    /**
     379     * Removes a selected template field from the template using a AJAX call
    139380         *
    140381         * @param templateField ID of the field to update
    141382         * @param template              ID of the template for which the field should be removed
    142          * @return                              Status code 200 on success, 500 otherwise
    143      */
    144     def delete = {
     383         * @return                              JSON object with two entries:
     384         *                                                      id: [id of this object]
     385         *                                                      html: HTML to replace the contents of the LI-item that was updated.
     386         *                                              On error the method gives a HTTP response status 404 or 500 and the error
     387     */
     388    def removeField = {
    145389        // Search for the template
    146390        def template = Template.get( params.template );
     
    171415        template.fields.remove( currentIndex );
    172416                template.save();
    173                 render '';
    174 
    175                 /*
    176                  *try {
    177                         templateField.delete(flush: true)
    178                         render "";
    179                         return;
    180                 } catch (org.springframework.dao.DataIntegrityViolationException e) {
    181                         response.status = 500;
    182                         render "Templatefield not deleted: " + e.getMessage();
    183                         return;
    184                 }
    185                 */
     417
     418
     419                def html = g.render( template: 'elements/liField', model: [templateField: templateField, fieldTypes: TemplateFieldType.list()] );
     420                def output = [ id: templateField.id, html: html ];
     421                render output as JSON;
    186422    }
    187423
     
    197433         *                                              On error the method gives a HTTP response status 500 and the error
    198434     */
    199     def move = {
     435    def moveField = {
    200436        // Search for the template
    201437        def template = Template.get( params.template );
     
    227463        template.fields.add( Integer.parseInt( params.position ), moveField );
    228464
    229                 def html = g.render( template: 'elements/liContent', model: [templateField: templateField, fieldTypes: TemplateFieldType.list()] );
     465                def html = g.render( template: 'elements/liFieldSelected', model: [templateField: templateField, template: template, fieldTypes: TemplateFieldType.list()] );
    230466                def output = [ id: templateField.id, html: html ];
    231467                render output as JSON;
    232468    }
     469
     470        /**
     471         * Checks how many template use a specific template field
     472         *
     473         * @param       id      ID of the template field
     474         * @return      int     Number of uses
     475         */
     476        def numFieldUses = {
     477        // Search for the template field
     478        def  templateField = TemplateField.get( params.id );
     479        if( !templateField ) {
     480            response.status = 404;
     481            render 'TemplateField not found';
     482            return;
     483        }
     484
     485                render templateField.numUses();
     486        }
    233487
    234488    /**
     
    252506        if( !entity ) {
    253507            error();
    254             retur; false
     508            return false
    255509        }
    256510
  • trunk/grails-app/domain/dbnp/studycapturing/Template.groovy

    r550 r556  
    11package dbnp.studycapturing
     2import java.lang.reflect.Method
    23
    34/**
     
    9697
    9798        /**
     99         * Checks whether this template is used by any object
     100         *
     101         * @returns             true iff this template is used by any object, false otherwise
     102         */
     103        def inUse() {
     104                return (numUses() > 0 );
     105        }
     106
     107        /**
     108         * The number of objects that use this template
     109         *
     110         * @returns             the number of objects that use this template.
     111         */
     112        def numUses() {
     113                // This template can only be used in objects of the right entity. Find objects of that
     114                // entity and see whether they use this method.
     115                //
     116                // Unfortunately, due to the grails way of creating classes, we can not use reflection for this
     117                def elements;
     118                switch( this.entity ) {
     119                        case Event:
     120                                elements = Event.findAllByTemplate( this ); break;
     121                        case Sample:
     122                                elements = Sample.findAllByTemplate( this ); break;
     123                        case Study:
     124                                elements = Study.findAllByTemplate( this ); break;
     125                        case Subject:
     126                                elements = Subject.findAllByTemplate( this ); break;
     127                        default:
     128                                return 0;
     129                }
     130
     131                return elements.size();
     132        }
     133
     134        /**
    98135         * overloading the findAllByEntity method to make it function as expected
    99136         * @param Class entity (for example: dbnp.studycapturing.Subject)
  • trunk/grails-app/domain/dbnp/studycapturing/TemplateField.groovy

    r550 r556  
    5353                return name.toLowerCase().replaceAll("([^a-z0-9])", "_")
    5454        }
     55
     56        /**
     57         * overloading the findAllByEntity method to make it function as expected
     58         * @param Class entity (for example: dbnp.studycapturing.Subject)
     59         * @return ArrayList
     60         */
     61        public static findAllByEntity(java.lang.Class entity) {
     62                def results = []
     63                // 'this' should not work in static context, so taking Template instead of this
     64                TemplateField.findAll().each() {
     65                        if (entity.equals(it.entity)) {
     66                                results[results.size()] = it
     67                        }
     68                }
     69
     70                return results
     71        }
     72
     73        /**
     74         * Checks whether this template field is used in a template
     75         *
     76         * @returns             true iff this template field is used in a template (even if the template is never used), false otherwise
     77         */
     78        def inUse() {
     79                return numUses() > 0;
     80        }
     81
     82        /**
     83         * The number of templates that use this template
     84         *
     85         * @returns             the number of templates that use this template.
     86         */
     87        def numUses() {
     88                def templates = Template.findAll();
     89                def elements;
     90                if( templates && templates.size() > 0 ) {
     91                        elements = templates.findAll { template -> template.fields.contains( this ) };
     92                } else {
     93                        return 0;
     94                }
     95
     96                return elements.size();
     97        }
     98
     99
    55100}
  • trunk/grails-app/views/templateEditor/elements/_available.gsp

    r544 r556  
    11<li class="ui-state-default" id="templateField_${it.id}">
    2         <g:render template="elements/liContent" model="['templateField': it, 'fieldTypes': fieldTypes]"/>
     2    <g:render template="elements/liField" model="['templateField': it, 'fieldTypes': fieldTypes]"/>
    33</li>
  • trunk/grails-app/views/templateEditor/elements/_liFieldNotInUse.gsp

    r544 r556  
    1 <a class="title" href="#" onClick="showTemplateFieldForm( 'templateField_' + ${templateField.id}); this.blur(); return false;">
    2         <span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
    3         <b>${templateField.name}</b>
    4         (<g:render template="elements/${templateField.type.toString().toLowerCase().replaceAll(/ /,'_')}" />)
    5 </a>
     1<span class="listButtons">
     2  <img onClick="showTemplateFieldForm( 'templateField_' + ${templateField.id}); this.blur(); return false;" src="${createLinkTo( dir: 'images', file: 'icons/famfamfam/application_edit.png')}" alt="Edit template field properties" title="Edit template field properties">
     3  <img onClick="if( confirm( 'Are you sure?' ) ) { deleteTemplateField( ${templateField.id} ); }" src="${createLinkTo( dir: 'images', file: 'icons/famfamfam/delete.png')}" alt="Delete this template field" title="Delete this template field">
     4  <img onClick="addTemplateField( ${templateField.id} ); moveFieldListItem( ${templateField.id}, '#selectedTemplateFields' );" src="${createLinkTo( dir: 'images', file: 'icons/famfamfam/add.png')}" alt="Add field to template" title="Add field to template">
     5</span>
    66
    7 <form class="templateField_form" id="templateField_${templateField.id}_form" action="update">
     7<b>${templateField.name}</b>
     8(<g:if test="${templateField.unit}">${templateField.unit}, </g:if><g:render template="elements/${templateField.type.toString().toLowerCase().replaceAll(/ /,'_')}" model="[templateField: templateField]" />)
     9
     10<form class="templateField_form" id="templateField_${templateField.id}_form" action="updateField">
    811        <g:hiddenField name="id" value="${templateField.id}" />
    912        <g:hiddenField name="version" value="${templateField.version}" />
     
    1114        <div class="templateFieldButtons">
    1215                <input type="button" value="Save" onClick="updateTemplateField( ${templateField.id} );">
    13                 <input type="button" value="Delete" onClick="deleteTemplateField( ${templateField.id} );">
    1416                <input type="button" value="Close" onClick="hideTemplateFieldForm( ${templateField.id} );">
    1517        </div>
  • trunk/grails-app/views/templateEditor/index.gsp

    r544 r556  
    2424        <body>
    2525
    26                 <script type="text/javascript">
    27                         $(function() {
    28                                 $("#templateFields").sortable({
    29                                         placeholder: 'ui-state-highlight',
    30                                         cancel: '.empty',
     26                <div class="templateEditorStep" id="step1_template">
     27                        <h3>Select template</h3>
     28                        <p>Showing templates for <b>${humanReadableEntity}</b>.</p>
     29                        <p>Please select a template to edit or create a new template</p>
    3130
    32                                         update: updateTemplateFieldPosition
    33                                 });
    34                                 $("#templateFields").disableSelection();
    35                                 //$('#templateFields li').bind('dblclick', showTemplateFormEvent);
    36                         });
    37                 </script>
    38 
    39                 <p>Please select a template to edit or create a new template</p>
    40                 <g:form action="index" name="templateChoice">
    41                         <g:hiddenField name="entity" value="${encryptedEntity}" />
    42                         <select name="template" id="templateSelect" onChange="this.form.submit();">
    43                                 <option value=""></option>
     31                        <ul id="templates">
     32                                <li class="empty ui-state-default" <g:if test="${templates.size() > 0 }">style='display: none;'</g:if>>There are no templates for ${humanReadableEntity}. Use the 'Add template' button to add fields.</li>
    4433                                <g:each in="${templates}" var="currentTemplate">
    45                                         <g:if test="${currentTemplate.id==template?.id}">
    46                                                 <option selected value="${currentTemplate.id}">${currentTemplate.name}</option>
    47                                         </g:if>
    48                                         <g:else>
    49                                                 <option value="${currentTemplate.id}">${currentTemplate.name}</option>
    50                                         </g:else>
     34                                        <li id="template_${currentTemplate.id}"class="ui-state-default">
     35                                          <g:if test="${currentTemplate.inUse()}">
     36                                                <g:render template="elements/liTemplateNonEditable" model="['template': currentTemplate]"/>
     37                                          </g:if>
     38                                          <g:else>
     39                                                <g:render template="elements/liTemplateEditable" model="['template': currentTemplate]"/>
     40                                          </g:else>
     41                                        </li>
    5142                                </g:each>
    52                         </select>
    53                 </g:form>
    54 
    55                 <g:if test="${template}">
    56                         <p>Currently, this template contains the following fields. Drag fields to reorder and double click fields to edit.</p>
    57                         <ul id="templateFields">
    58                                 <li class="empty ui-state-default" <g:if test="${template.fields?.size() > 0 }">style='display: none;'</g:if>>This template does not yet contain any fields. Use the 'Add new field' button to add fields.</li>
    59                                 <g:render template="elements/all" collection="${template.fields}" />
    6043                        </ul>
    6144
    6245                        <div id="addNew">
    63                                 <a href="#" onClick="showTemplateFieldForm( 'templateField_new' ); this.blur(); return false;">
    64                                         <b>Add new field</b>
     46                                <a href="#" onClick="editTemplate( 'new' ); this.blur(); return false;">
     47                                        <b>Create new template</b>
    6548                                </a>
    6649
    67                                 <form class="templateField_form" id="templateField_new_form" action="addField">
    68                                         <g:render template="elements/fieldForm" model="['templateField': null, 'fieldTypes': fieldTypes]"/>
     50                                <form class="templateField_form" id="template_new_form" action="createTemplate">
     51                                        <g:hiddenField name="entity" value="${encryptedEntity}" />
     52                                        <g:render template="elements/templateForm" model="['template': null]"/>
    6953                                        <div class="templateFieldButtons">
    70                                                 <input type="button" value="Save" onClick="addTemplateField( 'new' );">
    71                                                 <input type="button" value="Cancel" onClick="hideTemplateFieldForm( 'new' );">
     54                                                <input type="button" value="Save" onClick="createTemplate( 'new' );">
     55                                                <input type="button" value="Cancel" onClick="hideTemplateForm( 'new' );">
    7256                                        </div>
    7357                                </form>
    7458                        </div>
    75                 </g:if>
     59
     60                        <g:form action="template" name="templateChoice" method="GET">
     61                                <g:hiddenField name="entity" value="${encryptedEntity}" />
     62                                <input type="hidden" name="template" id="templateSelect" value="${template?.id}">
     63                        </g:form>
     64                </div>
    7665
    7766        </body>
Note: See TracChangeset for help on using the changeset viewer.