Changeset 556


Ignore:
Timestamp:
Jun 10, 2010, 4:45:53 PM (9 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
Files:
9 added
8 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>
  • trunk/test/unit/dbnp/studycapturing/TemplateFieldTests.groovy

    r507 r556  
    2828            );
    2929
     30                // Add static methods to Template
     31                mockDomain( Template, [testTemplate] );
     32                mockDomain( TemplateField, testTemplate.fields );
     33
    3034        this.testEvent = new Event(
    3135                template: testTemplate,
    3236                startTime: 3600,
    3337                endTime: 7200
    34         )
     38        );
     39
     40                mockDomain( Event, [testEvent] );
     41                this.testEvent.save();
    3542    }
    3643
     
    3845        super.tearDown()
    3946    }
     47
     48        void testInUse() {
     49               
     50                // All template fields in the testTemplate are in use (even in use on a object)
     51                assert testEvent.template.fields.size() == 3;
     52                testEvent.template.fields.each {
     53                        if( it != null ) {
     54                                assert it.inUse();
     55                        }
     56                }
     57
     58                // Create 2 template fields and use the first in a template, the second is not used
     59                TemplateField t1 = new TemplateField(
     60                                                                name: 'test1',
     61                                                                type: TemplateFieldType.DATE,
     62                                                                entity: dbnp.studycapturing.Event
     63                                                        ).save();
     64                TemplateField t2 = new TemplateField(
     65                                                                name: 'test2',
     66                                                                type: TemplateFieldType.DATE,
     67                                                                entity: dbnp.studycapturing.Event
     68                                                        ).save();
     69
     70                mockDomain( TemplateField, [t1, t2] );
     71
     72        def template1 = new Template(
     73                name: 'Template for testing inUse',
     74                entity: dbnp.studycapturing.Event,
     75                fields: [
     76                                        t1
     77                ]
     78            ).save();
     79
     80                assert t1.inUse();
     81                assert !t2.inUse();
     82
     83        }
    4084
    4185    void testRelTimeFieldCreation() {
  • trunk/test/unit/dbnp/studycapturing/TemplateTests.groovy

    r496 r556  
    1212    }
    1313
    14     void testSomething() {
     14    void testInUse() {
     15                Template t1 = new Template( entity: dbnp.studycapturing.Subject );
     16                Template t2 = new Template( entity: dbnp.studycapturing.Subject );
     17                Template t3 = new Template( entity: dbnp.studycapturing.Subject );
     18
     19                Subject s1 = new Subject( template: t1 );
     20                Subject s2 = new Subject( template: t1 );
     21                Subject s3 = new Subject( template: t2 );
     22
     23                mockDomain(Template, [t1, t2, t3 ])
     24                mockDomain(Subject, [ s1, s2, s3] )
     25
     26                assert t1.inUse();
     27                assert t2.inUse();
     28                assert !t3.inUse();
    1529
    1630    }
  • trunk/web-app/css/templateEditor.css

    r544 r556  
    1 #templateFields {
    2     list-style-type: none;
    3     margin: 0;
    4     padding: 0;
    5     width: 400px;
    6 }
    7 #templateFields li {
    8     margin: 0 5px 5px 5px; padding: 5px;
    9 }
    10 html>body #templateFields li {
    11     line-height: 16px; vertical-align: center;
    12 }
    13 .ui-state-highlight {
    14     height: 1.5em; line-height: 1.2em;
    15 }
    16 #templateFields .ui-icon {
    17     display: inline-block;
    18 }
     1/**
     2 * Formatting the template editor with two columns
     3 */
     4.templateEditorStep { float: left; padding: 10px 0px; margin: 0 10px; }
     5.templateEditorStep h3 { margin: 0 0 10px 0; padding-bottom: 10px; border-bottom: 1px solid #BBD; }
     6#step2_selectedFields p, #step3_availableFields p { height: 42px; }
    197
    20 #templateFields .empty { opacity: 0.6; padding: 5px 25px; }
     8#step1_template { width:340px; }
     9#step2_selectedFields { width: 340px; margin-right: 20px; }
     10#step3_availableFields { width: 340px; }
    2111
     12/**
     13 * Formatting the template list and the forms to add/edit them
     14 */
     15
     16#templates  { list-style-type: none; margin: 0; padding: 0; width: 330px; }
     17#templates li { margin: 0 5px 5px 5px; padding: 5px; color: #2779AA; }
     18html>body #templates li { line-height: 16px; vertical-align: center; }
     19
     20/* Butons within a list item */
     21.listButtons { display: block; float: right; }
     22.listButtons img { margin: 0 3px; cursor: pointer; }
     23.listButtons img.disabled { cursor: default; opacity: 0.3; }
     24
     25/**
     26 * Formatting of the template fields and the forms to edit/add them
     27 */
     28.templateFields { list-style-type: none;  margin: 0; padding: 0; width: 330px; }
     29.templateFields li { margin: 0 5px 3px 5px; padding: 3px 5px; }
     30html>body .templateFields li { line-height: 16px; vertical-align: center; }
     31.ui-state-highlight { height: 17px; }
     32.templateFields .ui-icon { display: inline-block; height: 13px; }
     33
     34.templateName { color: #2779AA; }
     35a.switch { font-size: small; color: #68BFEF; text-decoration: none; }
     36
     37/* Box to show a list is empty */
     38.templateFields .empty { opacity: 0.6; padding: 5px 25px; }
     39
     40/* The position where an item can be dropped in the available list will be red */
     41#availableTemplateFields .ui-state-highlight { background: #FFD6D6; border-color: #EAAEAE; }
     42
     43/* Form to edit or add a template field, but also for editing a template itself */
    2244.templateField_form { display: none; margin: 5px; padding-top: 8px; border-top: 1px solid #BBD; }
    2345.templateField_form .templateFieldButtons { margin-top: 8px; padding-top: 8px; border-top: 1px solid #BBD; }
    24 .templateField_form label { width: 100px; float: left; display: block; }
    25 .templateField_form textarea {width: 240px; height: 100px;  }
     46.templateField_form label { width: 80px; float: left; display: block; }
     47.templateField_form textarea {width: 145px; height: 100px;  }
     48.templateField_form input[type=text],
     49.templateField_form select {width: 145px; }
    2650
     51/* Add new form */
    2752#addNew {
    28         width: 388px;
     53        width: 318px;
    2954        line-height: 16px;
    3055        background-color: #EBF9D7;
     
    4065#addNew a {
    4166        display: block;
    42         padding: 7px 25px;
     67        padding: 7px 7px;
    4368        cursor: pointer;
    4469        color:#79AA27;
  • trunk/web-app/js/templateEditor.js

    r544 r556  
    1515var formOpened = false;
    1616
     17/*************************************
     18 *
     19 * Methods for the index page with templates on it
     20 *
     21 *************************************/
     22
     23/**
     24 * Sends the user to the page where the fields of this template can be edited
     25 */
     26function editFields( id ) {
     27        $( '#templateSelect' ).val( id );
     28        $( '#templateChoice' ).submit();
     29}
     30
     31/**
     32 * Shows the form to edit template properties
     33 */
     34function editTemplate( id ) {
     35    // Show the form is this item is not disabled
     36    if( !formOpened ) {
     37        formOpened = true;
     38
     39                // Show the form
     40                $( '#template_' + id + '_form' ).show();
     41        }
     42}
     43
     44/**
     45 * Hides the form to edit a template
     46 */
     47function hideTemplateForm( id ) {
     48    $( '#template_' + id + '_form' ).hide();
     49
     50    formOpened = false;
     51}
     52
     53/**
     54 * Creates a new template using AJAX
     55 */
     56function createTemplate( id ) {
     57    var formEl = $( '#template_' + id + '_form' );
     58
     59    // Update the field
     60    $.ajax({
     61        url:        baseUrl + '/templateEditor/' + formEl.attr( 'action' ),
     62        data:       formEl.serialize(),
     63                dataType:   'json',
     64        type:       "POST",
     65        success:    function(data, textStatus, request) {
     66            hideTemplateForm( id );
     67            addTemplateListItem( data.id, data.html );
     68        },
     69        error:      function( request ) {
     70            alert( "Could not create template: " + request.responseText );
     71        }
     72    });
     73}
     74
     75/**
     76 * Updates the properties of a template using AJAX
     77 */
     78function updateTemplate( id ) {
     79    var formEl = $( '#template_' + id + '_form' );
     80
     81    // Update the field
     82    $.ajax({
     83        url:        baseUrl + '/templateEditor/' + formEl.attr( 'action' ),
     84                dataType: 'json',
     85        data:       formEl.serialize(),
     86        type:       "POST",
     87        success:    function(data, textStatus, request) {
     88            hideTemplateForm( id );
     89            updateTemplateListItem( id, data.html );
     90        },
     91        error:      function( request ) {
     92            alert( "Could not update template: " + request.responseText );
     93        }
     94    });
     95}
     96
     97/**
     98 * Deletes a template field using AJAX
     99 */
     100function deleteTemplate( id ) {
     101    // Update the field
     102    $.ajax({
     103        url:        baseUrl + '/templateEditor/deleteTemplate',
     104        data:       'template=' + id,
     105        type:       "POST",
     106        success:    function(data, textStatus, request) {
     107                        // Remove the list item
     108                        deleteTemplateListItem( id );
     109
     110                        showHideEmpty( '#templates' );
     111        },
     112        error:      function( request ) {
     113            alert( "Could not delete template: " + request.responseText );
     114        }
     115    });
     116
     117        return true;
     118}
     119
     120// Adds a new listitem when a field has been added
     121function addTemplateListItem( id, newHTML ) {
     122        // Create a new listitem
     123        var li = $( '<li></li>' );
     124        li.attr( 'id', 'template_' + id );
     125        li.addClass( "ui-state-default" );
     126
     127        // Insert the right HTML
     128        li.html( newHTML );
     129
     130        // Append the listitem to the list
     131        $( '#templates li:last').after( li );
     132
     133        // Hide the 'empty' listitem, if needed
     134        showHideEmpty( '#templates' );
     135}
     136
     137// Updates the contents of the listitem when something has changed
     138function updateTemplateListItem( id, newHTML ) {
     139        var li = $( '#template_' + id );
     140        li.html( newHTML );
     141}
     142
     143// Removes a listitem when the template field has been deleted
     144function deleteTemplateListItem( id ) {
     145        var li = $( '#template_' + id );
     146        li.remove();
     147
     148        // Show the 'empty' listitem if the last item is deleted
     149        showHideEmpty( '#templates' );
     150}
     151
     152/*************************************
     153 *
     154 * Methods for the template page with templatefields on it
     155 *
     156 *************************************/
     157
    17158/**
    18159 * Is called on double click on a listitem
     
    34175
    35176                // Disable all other listitems
    36                 $( '#templateFields li:not(#' + list_item_id + ')').addClass( 'ui-state-disabled' );
     177                $( '#availableTemplateFields li:not(#' + list_item_id + ')').addClass( 'ui-state-disabled' );
    37178
    38179                if( list_item_id != 'templateField_new' ) {
     
    50191
    51192    // Enable all other listitems
    52     $( '#templateFields li:not(#templateField_' + id + ')').removeClass( 'ui-state-disabled' );
     193    $( '#availableTemplateFields li:not(#templateField_' + id + ')').removeClass( 'ui-state-disabled' );
    53194        $( '#addNew').removeClass( 'ui-state-disabled' );
    54195
    55196    formOpened = false;
     197}
     198
     199
     200
     201/**
     202 * Adds a new template field using AJAX
     203 */
     204function createTemplateField( id ) {
     205    var formEl = $( '#templateField_' + id + '_form' );
     206        var templateId = $('#templateSelect').val();
     207
     208    // Update the field
     209    $.ajax({
     210        url:        baseUrl + '/templateEditor/' + formEl.attr( 'action' ),
     211        data:       "template=" + templateId + "&" + formEl.serialize(),
     212                dataType: 'json',
     213        type:       "POST",
     214        success:    function(data, textStatus, request) {
     215            hideTemplateFieldForm( id );
     216            addFieldListItem( data.id, data.html );
     217        },
     218        error:       function( request ) {
     219            alert( "Could not add template field: " + request.responseText );
     220        }
     221    });
     222}
     223
     224/**
     225 * Updates the properties of a template field using AJAX
     226 */
     227function updateTemplateField( id ) {
     228    var formEl = $( '#templateField_' + id + '_form' );
     229
     230    // Update the field
     231    $.ajax({
     232        url:        baseUrl + '/templateEditor/' + formEl.attr( 'action' ),
     233                dataType: 'json',
     234        data:       formEl.serialize(),
     235        type:       "POST",
     236        success:    function(data, textStatus, request) {
     237            hideTemplateFieldForm( id );
     238            updateFieldListItem( id, data.html );
     239        },
     240        error:      function( request ) {
     241            alert( "Could not update template field: " + request.responseText );
     242        }
     243    });
    56244}
    57245
     
    61249 */
    62250function updateTemplateFieldPosition( event, ui ) {
     251        // If the item is dragged to the 'availableTemplateFIelds list, we should not 'move' it
     252        // Otherwise, when the item is dragged onto the selectedTemplateFields, but the 'sender' is availableTemplateFields,
     253        // the item is added, and does not need to be moved
     254        if(
     255                ui.item.parent().attr( 'id' ) == 'availableTemplateFields' ||
     256                ui.item.parent().attr( 'id' ) == 'selectedTemplateFields' && ui.sender != null && ui.sender.attr( 'id' ) == 'availableTemplateFields'
     257        ) {
     258                // Return true, otherwise the move operation is canceled by jquery
     259                return true;
     260        }
    63261    // Find the new position of the element in the list
    64262    // http://stackoverflow.com/questions/2979643/jquery-ui-sortable-position
    65     var newposition = ui.item.index();
     263    //
     264    // Because there is also a hidden 'empty template' list item in the list,
     265    // the number is decreased by 1
     266    var newposition = ui.item.index() - 1;
    66267
    67268    // Find the ID of the templateField and template
     
    71272
    72273    // Create a URL to call and call it
    73     var url = baseUrl + '/templateEditor/move';
     274    var url = baseUrl + '/templateEditor/moveField';
    74275
    75276    // Disable sorting until this move has been saved (in order to prevent collisions
     
    83284                type: 'POST',
    84285        success: function(data, textStatus, request) {
    85             updateListItem( templateFieldId, data.html );
     286            updateFieldListItem( templateFieldId, data.html );
    86287            $( '#templateFields' ).sortable( 'enable' );
    87288        },
    88         error: function() {
    89             alert( "Could not move template field" );
    90         }
    91     });
    92 }
    93 
    94 /**
    95  * Adds a new template field using AJAX
    96  */
    97 function addTemplateField( id ) {
    98     var formEl = $( '#templateField_' + id + '_form' );
     289        error: function( request ) {
     290            alert( "Could not move template field: " + request.responseText );
     291        }
     292    });
     293}
     294
     295/**
     296 * Adds a new template field to the template using AJAX
     297 */
     298function addTemplateFieldEvent( event, ui ) {
     299    // Find the new position of the element in the list
     300    // http://stackoverflow.com/questions/2979643/jquery-ui-sortable-position
     301    //
     302    // Because there is also a hidden 'empty template' list item in the list,
     303    // the number is decreased by 1
     304    var newposition = ui.item.index() - 1;
     305
     306        var item_id = ui.item.context.id;
     307    var id = item_id.substring( item_id.lastIndexOf( '_' ) + 1 );
     308
     309        return addTemplateField( id, newposition );
     310}
     311
     312/**
     313 * Adds a new template field to the template using AJAX
     314 */
     315function addTemplateField( id, newposition ) {
     316        if( newposition == null ) {
     317                newposition = -1;
     318        }
    99319        var templateId = $('#templateSelect').val();
    100320
    101321    // Update the field
    102322    $.ajax({
    103         url:        baseUrl + '/templateEditor/' + formEl.attr( 'action' ),
    104         data:       "template=" + templateId + "&" + formEl.serialize(),
    105                 dataType: 'json',
    106         type:       "POST",
    107         success:    function(data, textStatus, request) {
    108             hideTemplateFieldForm( id );
    109             addListItem( data.id, data.html );
    110         },
    111         error:      function() {
    112             alert( "Could not add template field" );
    113         }
    114     });
    115 }
    116 
    117 /**
    118  * Updates the properties of a template field using AJAX
    119  */
    120 function updateTemplateField( id ) {
    121     var formEl = $( '#templateField_' + id + '_form' );
    122 
    123     // Update the field
    124     $.ajax({
    125         url:        baseUrl + '/templateEditor/' + formEl.attr( 'action' ),
    126                 dataType: 'json',
    127         data:       formEl.serialize(),
    128         type:       "POST",
    129         success:    function(data, textStatus, request) {
    130             hideTemplateFieldForm( id );
    131             updateListItem( id, data.html );
    132         },
    133         error:      function() {
    134             alert( "Could not update template field" );
    135         }
    136     });
     323        url:        baseUrl + '/templateEditor/addField',
     324        data:       "template=" + templateId + "&templateField=" + id + "&position=" + newposition,
     325                dataType:       'json',
     326        type:       "POST",
     327        success:    function(data, textStatus, request) {
     328                        // Put the new HTML into the list item
     329                        updateFieldListItem( id, data.html );
     330
     331                        showHideEmpty( '#selectedTemplateFields' );
     332                        showHideEmpty( '#availableTemplateFields' );
     333        },
     334        error:      function( request ) {
     335            alert( "Could not add template field: " + request.responseText );
     336        }
     337    });
     338}
     339
     340
     341/**
     342 * Deletes a template field from a template  using AJAX
     343 */
     344function removeTemplateFieldEvent( event, ui ) {
     345    var item_id = ui.item.context.id;
     346    var id = item_id.substring( item_id.lastIndexOf( '_' ) + 1 );
     347
     348        // The field should only be removed when the study is not in use
     349        // If field is used, the li has class 'inUse'
     350        if( !ui.item.hasClass( 'inUse' ) ) {
     351                return removeTemplateField( id );
     352        } else {
     353                alert( "Field can not be removed, because the template is in use." );
     354                return false;
     355        }
     356}
     357
     358/**
     359 * Removes a template field from a template using AJAX
     360 */
     361function removeTemplateField( id ) {
     362        var templateId = $('#templateSelect').val();
     363
     364    // Update the field
     365    $.ajax({
     366        url:        baseUrl + '/templateEditor/removeField',
     367        data:       'template=' + templateId + '&templateField=' + id,
     368        type:       "POST",
     369        success:    function(data, textStatus, request) {
     370                        // Put the new HTML into the list item
     371                        updateFieldListItem( id, data.html );
     372
     373                        showHideEmpty( '#selectedTemplateFields' );
     374                        showHideEmpty( '#availableTemplateFields' );
     375
     376        },
     377        error:      function( request ) {
     378            alert( "Could not delete template field: " + request.responseText );
     379        }
     380    });
     381
     382        return true;
    137383}
    138384
     
    141387 */
    142388function deleteTemplateField( id ) {
    143         var templateId = $('#templateSelect').val();
    144 
    145     // Update the field
    146     $.ajax({
    147         url:        baseUrl + '/templateEditor/delete',
    148         data:       'template=' + templateId + '&templateField=' + id,
    149         type:       "POST",
    150         success:    function(data, textStatus, request) {
    151             hideTemplateFieldForm( id );
    152             deleteListItem( id );
    153         },
    154         error:      function() {
    155             alert( "Could not delete template field" );
    156         }
    157     });
    158 }
    159 
     389    // Delete the field
     390    $.ajax({
     391        url:        baseUrl + '/templateEditor/deleteField',
     392        data:       'templateField=' + id,
     393        type:       "POST",
     394        success:    function(data, textStatus, request) {
     395                        // Put the new HTML into the list item
     396                        deleteFieldListItem( id );
     397
     398                        showHideEmpty( '#availableTemplateFields' );
     399        },
     400        error:      function( request ) {
     401            alert( "Could not delete template field: " + request.responseText );
     402        }
     403    });
     404
     405        return true;
     406}
    160407
    161408// Adds a new listitem when a field has been added
    162 function addListItem( id, newHTML ) {
     409function addFieldListItem( id, newHTML ) {
    163410        // Create a new listitem
    164411        var li = $( '<li></li>' );
     
    170417
    171418        // Append the listitem to the list
    172         $( '#templateFields li:last').after( li );
     419        $( '#availableTemplateFields li:last').after( li );
    173420
    174421        // Hide the 'empty' listitem
    175         $( '#templateFields .empty' ).hide();
     422        showHideEmpty( '#availableTemplateFields' );
    176423}
    177424
    178425// Updates the contents of the listitem when something has changed
    179 function updateListItem( id, newHTML ) {
     426function updateFieldListItem( id, newHTML ) {
    180427        var li = $( '#templateField_' + id );
    181428        li.html( newHTML );
     
    183430
    184431// Removes a listitem when the template field has been deleted
    185 function deleteListItem( id ) {
     432function deleteFieldListItem( id ) {
    186433        var li = $( '#templateField_' + id );
    187434        li.remove();
    188435
    189436        // Show the 'empty' listitem if the last item is deleted
    190         if( $( '#templateFields li:not(.empty)' ).length == 0 ) {
    191                 $( '#templateFields .empty' ).show();
    192         }
    193 
    194 }
     437        showHideEmpty( '#availableTemplateFields' );
     438}
     439
     440// Moves a listitem from one list to another
     441function moveFieldListItem( id, toSelector ) {
     442        var li = $( '#templateField_' + id );
     443        li.remove();
     444
     445        $( toSelector ).append( li );
     446}
     447
     448/**
     449 * Shows or hides the list item, indicating that a list is empty
     450 */
     451function showHideEmpty( selector ) {
     452        // Show the 'empty' listitem if the last item is deleted
     453        if( $( selector + ' li:not(.empty)' ).length == 0 ) {
     454                $( selector + ' .empty' ).show();
     455        } else {
     456                $( selector + ' .empty' ).hide();
     457        }
     458}
Note: See TracChangeset for help on using the changeset viewer.