Changeset 558


Ignore:
Timestamp:
Jun 11, 2010, 4:00:10 PM (9 years ago)
Author:
roberth
Message:

Improved template editor , stringlists and ontologyfields can be edited and extra checks are built in.

Location:
trunk
Files:
4 added
12 edited
1 copied

Legend:

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

    r556 r558  
    1818import cr.co.arquetipos.crypto.Blowfish
    1919import grails.converters.*
     20import java.lang.reflect.*;
    2021
    2122class TemplateEditorController {
     
    5960        def selectedTemplate = params.template;
    6061        def template = null;
     62                def domainFields = null;
    6163
    6264        if( selectedTemplate ) {
    6365            template = Template.get( selectedTemplate );
     66
     67                        // Find the domain classes for this template/entity
     68                        // See http://www.javaworld.com/javaworld/javaqa/1999-07/06-qa-invoke.html
     69                        Method m = template.entity.getDeclaredMethod("giveDomainFields", null);
     70                        domainFields = m.invoke( null, null );
    6471        } else {
    6572                        redirect(action:"index",params:[entity:params.entity])
     
    8491            encryptedEntity: params.entity,
    8592            fieldTypes: TemplateFieldType.list(),
     93                        ontologies: Ontology.list(),
    8694            humanReadableEntity: humanReadableEntity,
    8795
    8896            template: template,
    89                         allFields: allFields
     97                        allFields: allFields,
     98                        domainFields: domainFields
    9099        ];
    91100
     
    124133        if (template.save(flush: true)) {
    125134
    126                         def html = g.render( template: 'elements/liTemplateEditable', model: [template: template] );
     135                        def html = g.render( template: 'elements/liTemplate', model: [template: template] );
    127136                        def output = [ id: template.id, html: html ];
    128137                        render output as JSON;
     
    166175        template.properties = params
    167176        if (!template.hasErrors() && template.save(flush: true)) {
    168                         def html = g.render( template: 'elements/liTemplateEditable', model: [template: template] );
     177                        def html = g.render( template: 'elements/liTemplate', model: [template: template] );
    169178                        def output = [ id: template.id, html: html ];
    170179                        render output as JSON;
     
    206215    }
    207216
    208 
    209 
    210 
    211217    /**
    212218     * Creates a new template field using a AJAX call
     
    246252                }
    247253
     254                // See whether this exists as domain field. If it does, raise an error
     255                Method m = template.entity.getDeclaredMethod("giveDomainFields", null);
     256                def domainFields = m.invoke( null, null );
     257                if( domainFields.find { it.name.toLowerCase() == params.name.toLowerCase() } ) {
     258                        response.status = 500;
     259                        render "All templates for entity " + template.entity + " contain a domain field with name " + params.name + ". You can not create a field with this name.";;
     260                        return;
     261                }
     262
     263                // If this field is type stringlist, we have to prepare the parameters
     264                if( params.type.toString() == 'STRINGLIST' ) {
     265                        def listEntries = [];
     266                        params.listEntries.eachLine {
     267                                // Search whether a listitem with this name already exists.
     268                                // if it does, use that one to prevent pollution of the database
     269                                def name = it.trim();
     270                                def listitem = TemplateFieldListItem.findByName( name );7
     271                                if( !listitem ) {
     272                                        listitem = new TemplateFieldListItem( name: name )
     273                                }
     274                                listEntries.add( listitem );
     275                        }
     276
     277                        params.listEntries = listEntries;
     278                } else {
     279                        params.remove( 'listEntries' );
     280                }
     281
     282                // If this field isnot a ontologyterm, we should remove the ontologies
     283                if( params.type.toString() != 'ONTOLOGYTERM' ) {
     284                        params.remove( 'ontologies' );
     285                }
     286
    248287                // Create the template field and add it to the template
    249288                def templateField = new TemplateField( params );
    250289        if (templateField.save(flush: true)) {
    251290
    252                         def html = g.render( template: 'elements/liFieldNotInUse', model: [templateField: templateField, fieldTypes: TemplateFieldType.list()] );
     291                        def html = g.render( template: 'elements/available', model: [templateField: templateField, ontologies: Ontology.list(), fieldTypes: TemplateFieldType.list()] );
    253292                        def output = [ id: templateField.id, html: html ];
    254293                        render output as JSON;
     
    289328            }
    290329        }
    291         templateField.properties = params
     330
     331                // If this field is type stringlist or ontology, we have to prepare the parameters
     332                if( params.type.toString() == 'STRINGLIST' ) {
     333                        def listEntries = [];
     334                        params.listEntries.eachLine {
     335                                // Search whether a listitem with this name already exists.
     336                                // if it does, use that one to prevent pollution of the database
     337                                def name = it.trim();
     338                                def listitem = TemplateFieldListItem.findByName( name );7
     339                                if( !listitem ) {
     340                                        listitem = new TemplateFieldListItem( name: name )
     341                                }
     342                                listEntries.add( listitem );
     343                        }
     344
     345                        params.listEntries = listEntries;
     346                } else {
     347                        params.remove( 'listEntries' );
     348                }
     349
     350                // If this field is a ontologyterm, we add ontology objects
     351                if( params.type.toString() == 'ONTOLOGYTERM' && params.ontologies ) {
     352                        params.ontologies = Ontology.getAll( params.ontologies.collect { Integer.parseInt( it ) } );
     353                } else {
     354                        params.remove( 'ontologies' );
     355                }
     356
     357                // Set all parameters
     358                templateField.properties = params
    292359        if (!templateField.hasErrors() && templateField.save(flush: true)) {
    293                         def html = g.render( template: 'elements/liField', model: [templateField: templateField, fieldTypes: TemplateFieldType.list()] );
     360                        def html = g.render( template: 'elements/available', model: [templateField: templateField, ontologies: Ontology.list(), fieldTypes: TemplateFieldType.list()] );
    294361                        def output = [ id: templateField.id, html: html ];
    295362                        render output as JSON;
     
    364431            return;
    365432        }
     433
     434                // If the template is in use, only non-required fields can be added
     435                if( template.inUse() && templateField.required ) {
     436                        response.status = 500;
     437                        render 'Only non-required fields can be added to templates that are in use.'
     438                        return;
     439                }
     440
     441                // All field names within a template should be unique
     442                if( template.fields.find { it.name.toLowerCase() == templateField.name.toLowerCase() } ) {
     443                        response.status = 500;
     444                        render 'This template already contains a field with name ' + templateField.name + '. Field names should be unique within a template.'
     445                        return;
     446                }
     447
    366448                if( !params.position || Integer.parseInt( params.position ) == -1) {
    367449                        template.fields.add( templateField )
     
    369451                        template.fields.add( Integer.parseInt( params.position ), templateField )
    370452                }
    371 
    372                 def html = g.render( template: 'elements/liFieldSelected', model: [templateField: templateField, template: template, fieldTypes: TemplateFieldType.list()] );
     453                template.save(flush:true);
     454
     455                def html = g.render( template: 'elements/selected', model: [templateField: templateField, template: template, ontologies: Ontology.list(), fieldTypes: TemplateFieldType.list()] );
    373456                def output = [ id: templateField.id, html: html ];
    374457                render output as JSON;
    375458    }
    376 
    377459
    378460    /**
     
    411493        }
    412494
     495                // If the template is in use, field can not be removed
     496                if( template.inUse() ) {
     497                        response.status = 500;
     498                        render 'No fields can be removed from templates that are in use.'
     499                        return;
     500                }
     501
    413502                // Delete the field from this template
    414503        def currentIndex = template.fields.indexOf( templateField );
    415504        template.fields.remove( currentIndex );
    416                 template.save();
    417 
    418 
    419                 def html = g.render( template: 'elements/liField', model: [templateField: templateField, fieldTypes: TemplateFieldType.list()] );
     505                template.save(flush:true);
     506
     507
     508                def html = g.render( template: 'elements/available', model: [templateField: templateField, ontologies: Ontology.list(), fieldTypes: TemplateFieldType.list()] );
    420509                def output = [ id: templateField.id, html: html ];
    421510                render output as JSON;
     
    462551        def moveField = template.fields.remove( currentIndex );
    463552        template.fields.add( Integer.parseInt( params.position ), moveField );
    464 
    465                 def html = g.render( template: 'elements/liFieldSelected', model: [templateField: templateField, template: template, fieldTypes: TemplateFieldType.list()] );
     553                template.save(flush:true);
     554
     555                def html = g.render( template: 'elements/selected', model: [templateField: templateField, template: template, fieldTypes: TemplateFieldType.list()] );
    466556                def output = [ id: templateField.id, html: html ];
    467557                render output as JSON;
     
    485575                render templateField.numUses();
    486576        }
     577
     578        /**
     579         * Adds a ontolgy based on the ID given
     580         *
     581         * @param       ncboID
     582         * @return      JSON    Ontology object
     583         */
     584        def addOntologyById = {
     585                def id = params.ncboID;
     586
     587                if( !id ) {
     588                        response.status = 500;
     589                        render 'No ID given'
     590                        return;
     591                }
     592
     593                if( Ontology.findByNcboId( Integer.parseInt(  id ) ) ) {
     594                        response.status = 500;
     595                        render 'This ontology was already added to the system';
     596                        return;
     597                }
     598
     599                def ontology = null;
     600
     601                try {
     602                        ontology = dbnp.data.Ontology.getBioPortalOntology( id );
     603                } catch( Exception e ) {
     604                        response.status = 500;
     605                        render e.getMessage();
     606                        return;
     607                }
     608
     609                if( !ontology ) {
     610                        response.status = 404;
     611                        render 'Ontology with ID ' + id + ' not found';
     612                        return;
     613                }
     614
     615                // Validate ontology
     616                if (!ontology.validate()) {
     617                        response.status = 500;
     618                        render ontology.errors.join( '; ' );
     619                        return;
     620                }
     621
     622                // Save ontology and render the object as JSON
     623                ontology.save(flush: true)
     624                render ontology as JSON
     625        }
     626
     627        /**
     628         * Adds a ontolgy based on the ID given
     629         *
     630         * @param       ncboID
     631         * @return      JSON    Ontology object
     632         */
     633        def addOntologyByTerm = {
     634                def id = params.termID;
     635
     636                if( !id ) {
     637                        response.status = 500;
     638                        render 'No ID given'
     639                        return;
     640                }
     641
     642                def ontology = null;
     643
     644                try {
     645                        ontology = dbnp.data.Ontology.getBioPortalOntologyByTerm( id );
     646                } catch( Exception e ) {
     647                        response.status = 500;
     648                        render e.getMessage();
     649                        return;
     650                }
     651
     652                if( !ontology ) {
     653                        response.status = 404;
     654                        render 'Ontology form term ' + id + ' not found';
     655                        return;
     656                }
     657
     658                // Validate ontology
     659                if (!ontology.validate()) {
     660                        response.status = 500;
     661                        render ontology.errors.join( '; ' );
     662                        return;
     663                }
     664
     665                // Save ontology and render the object as JSON
     666                ontology.save(flush: true)
     667                render ontology as JSON
     668        }
     669
    487670
    488671    /**
  • trunk/grails-app/domain/dbnp/data/Ontology.groovy

    r552 r558  
    5757                );
    5858        }
     59
     60        static Ontology getBioPortalOntologyByTerm(String termId) {
     61                // Get ontology from BioPortal via Ontocat
     62                // TODO: maybe make a static OntologyService instance to be more efficient, and decorate it with caching?
     63                uk.ac.ebi.ontocat.OntologyService os = new uk.ac.ebi.ontocat.bioportal.BioportalOntologyService()
     64                uk.ac.ebi.ontocat.OntologyTerm term = os.getTerm( termId );
     65                println( term );
     66                uk.ac.ebi.ontocat.Ontology o = os.getOntology( term.getOntologyAccession() );
     67                println( o );
     68
     69                // Instantiate and return Ontology object
     70                new dbnp.data.Ontology(
     71                        name: o.label,
     72                        description: o.description,
     73                        url: o.properties['homepage'] ?: "http://bioportal.bioontology.org/ontologies/${o.id}",
     74                        versionNumber: o.versionNumber,
     75                        ncboId: o.ontologyAccession,
     76                        ncboVersionedId: o.id
     77                );
     78        }
    5979}
  • trunk/grails-app/views/templateEditor/elements/_available.gsp

    r556 r558  
    1 <li class="ui-state-default" id="templateField_${it.id}">
    2     <g:render template="elements/liField" model="['templateField': it, 'fieldTypes': fieldTypes]"/>
     1<li class="ui-state-default <g:if test="${templateField.required}">required</g:if>" id="templateField_${templateField.id}">
     2    <g:render template="elements/liField" model="['templateField': templateField, 'ontologies': ontologies, 'fieldTypes': fieldTypes]"/>
    33</li>
  • trunk/grails-app/views/templateEditor/elements/_disabledFieldForm.gsp

    r555 r558  
    1         <label for="name">Name:</label> <g:textField name="name" value="${templateField?.name}" /><br />
    2         <label for="type">Type:</label> <g:select from="${fieldTypes}" name="type" value="${templateField?.type}" /><br />
    3         <label for="unit">Unit:</label> <g:textField name="unit" value="${templateField?.unit}" /><br />
    4         <label for="comment">Comment:</label> <g:textArea name="comment" value="${templateField?.comment}" /><br />
    5         <label for="required">Required:</label> <g:checkBox name="required" value="${templateField?.required}" /><br />
     1        <label for="name">Name:</label> <g:textField disabled="disabled" name="name" value="${templateField?.name}" /><br />
     2        <label for="type">Type:</label> <g:textField disabled="disabled" name="type" value="${templateField?.type}" /><br />
     3
     4        <div class="extra stringlist_options" <g:if test="${templateField?.type.toString() == 'STRINGLIST'}">style='display: block;'</g:if>>
     5          <label for="type">Items:</label>
     6                <g:textArea name="listEntries" disabled="disabled" value="${templateField?.listEntries?.name?.join( '\n' )}" />
     7        </div>
     8        <div class="extra ontologyterm_options" <g:if test="${templateField?.type.toString() == 'ONTOLOGYTERM'}">style='display: block;'</g:if>>
     9          <label for="type">Ontology:</label> <g:textArea name="ontology" disabled="disabled" value="${templateField?.ontologies?.name?.join( '\n' )}" /><br />
     10        </div>
     11       
     12        <label for="unit">Unit:</label> <g:textField disabled="disabled" name="unit" value="${templateField?.unit}" /><br />
     13        <label for="comment">Comment:</label> <g:textArea disabled="disabled" name="comment" value="${templateField?.comment}" /><br />
     14        <label for="required">Required:</label> <input type="checkbox" disabled <g:if test="${templateField?.required}">checked</g:if><br />
  • trunk/grails-app/views/templateEditor/elements/_fieldForm.gsp

    r544 r558  
    11        <label for="name">Name:</label> <g:textField name="name" value="${templateField?.name}" /><br />
    2         <label for="type">Type:</label> <g:select from="${fieldTypes}" name="type" value="${templateField?.type}" /><br />
     2        <label for="type">Type:</label> <g:select from="${fieldTypes}" name="type" value="${templateField?.type}" onChange="showExtraFields( ${templateField ? templateField.id : '\'new\''} );" /><br />
     3
     4        <div class="extra stringlist_options" <g:if test="${templateField?.type.toString() == 'STRINGLIST'}">style='display: block;'</g:if>>
     5          <label for="type">Items (every item on a new line):</label>
     6                <g:textArea name="listEntries" value="${templateField?.listEntries?.name?.join( '\n' )}" />
     7        </div>
     8        <div class="extra ontologyterm_options" <g:if test="${templateField?.type.toString() == 'ONTOLOGYTERM'}">style='display: block;'</g:if>>
     9          <label for="type">Ontology:<br /><br /><a href="#" style="text-decoration: underline;" onClick="openOntologyDialog();">Add new</a></label>
     10                <g:select multiple="yes" size="5" from="${ontologies}" class="ontologySelect" optionValue="name" optionKey="id" name="ontologies" id="ontologies_${templateField?.id}" value="${templateField?.ontologies}" /><br />
     11        </div>
     12
    313        <label for="unit">Unit:</label> <g:textField name="unit" value="${templateField?.unit}" /><br />
    414        <label for="comment">Comment:</label> <g:textArea name="comment" value="${templateField?.comment}" /><br />
  • trunk/grails-app/views/templateEditor/elements/_liField.gsp

    r556 r558  
    11<g:if test="${templateField.inUse()}">
    2         <g:render template="elements/liFieldInUse" model="['templateField': templateField, 'fieldTypes': fieldTypes]"/>
     2        <g:render template="elements/liFieldInUse" model="['templateField': templateField, 'ontologies': ontologies, 'fieldTypes': fieldTypes]"/>
    33</g:if>
    44<g:else>
    5         <g:render template="elements/liFieldNotInUse" model="['templateField': templateField, 'fieldTypes': fieldTypes]"/>
     5        <g:render template="elements/liFieldNotInUse" model="['templateField': templateField, 'ontologies': ontologies, 'fieldTypes': fieldTypes]"/>
    66</g:else>
  • trunk/grails-app/views/templateEditor/elements/_liFieldInUse.gsp

    r556 r558  
    11<g:set var="numUses" value="${templateField.numUses()}" />
    22<span class="listButtons">
    3   <img class="disabled" src="${createLinkTo( dir: 'images', file: 'icons/famfamfam/application_edit.png')}" alt="Editing not possible. Field is used in ${numUses} templates." title="Editing not possible. Field is used in ${numUses} templates.">
     3  <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">
    44  <img class="disabled" src="${createLinkTo( dir: 'images', file: 'icons/famfamfam/delete.png')}" alt="Deleting this field is not possible. Field is used in ${numUses} templates." title="Deleting this field is not possible. Field is used in ${numUses} templates.">
    5   <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  <img onClick="addTemplateField( ${templateField.id}, null, true );" src="${createLinkTo( dir: 'images', file: 'icons/famfamfam/add.png')}" alt="Add field to template" title="Add field to template">
    66</span>
    77
     
    99    (<g:if test="${templateField.unit}">${templateField.unit}, </g:if><g:render template="elements/${templateField.type.toString().toLowerCase().replaceAll(/ /,'_')}" model="[templateField: templateField]"/>)
    1010   
     11<form class="templateField_form" id="templateField_${templateField.id}_form" action="updateField">
     12        <g:hiddenField name="id" value="${templateField.id}" />
     13        <g:hiddenField name="version" value="${templateField.version}" />
     14        <p class="noEditsPossible">Editing not possible. Field is used in ${numUses} template(s).</p>
     15        <g:render template="elements/disabledFieldForm" model="['templateField': templateField, 'ontologies': ontologies, 'fieldTypes': fieldTypes]"/>
     16        <div class="templateFieldButtons">
     17                <input type="button" value="Close" onClick="hideTemplateFieldForm( ${templateField.id} );">
     18        </div>
     19</form>
    1120
  • trunk/grails-app/views/templateEditor/elements/_liFieldNotInUse.gsp

    r556 r558  
    22  <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">
    33  <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">
     4  <img onClick="addTemplateField( ${templateField.id}, null, true );" src="${createLinkTo( dir: 'images', file: 'icons/famfamfam/add.png')}" alt="Add field to template" title="Add field to template">
    55</span>
    66
     
    1111        <g:hiddenField name="id" value="${templateField.id}" />
    1212        <g:hiddenField name="version" value="${templateField.version}" />
    13         <g:render template="elements/fieldForm" model="['templateField': templateField, 'fieldTypes': fieldTypes]"/>
     13        <g:render template="elements/fieldForm" model="['templateField': templateField, 'ontologies': ontologies, 'fieldTypes': fieldTypes]"/>
    1414        <div class="templateFieldButtons">
    1515                <input type="button" value="Save" onClick="updateTemplateField( ${templateField.id} );">
  • trunk/grails-app/views/templateEditor/elements/_selected.gsp

    r556 r558  
    1 <li class="ui-state-default <g:if test="${template.inUse()}">inUse</g:if>" id="templateField_${it.id}">
    2     <g:render template="elements/liFieldSelected" model="['templateField': it, 'template': template, 'fieldTypes': fieldTypes]"/>
     1<li class="ui-state-default  <g:if test="${templateField.required}">required</g:if>" id="templateField_${templateField.id}">
     2    <g:render template="elements/liFieldSelected" model="['templateField': templateField, 'template': template, 'fieldTypes': fieldTypes]"/>
    33</li>
  • trunk/grails-app/views/templateEditor/index.gsp

    r556 r558  
    3232                                <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>
    3333                                <g:each in="${templates}" var="currentTemplate">
    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>
     34                                  <g:render template="elements/liTemplate" model="['template': currentTemplate]"/>
    4235                                </g:each>
    4336                        </ul>
  • trunk/grails-app/views/templateEditor/template.gsp

    r556 r558  
    2121                <script src="${createLinkTo(dir: 'js', file: 'templateEditor.js')}" type="text/javascript"></script>
    2222                <link rel="stylesheet" href="${createLinkTo(dir: 'css', file: 'templateEditor.css')}" />
     23                <g:if env="production">
     24                  <script type="text/javascript" src="${resource(dir: 'js', file: 'ontology-chooser.min.js')}"></script>
     25                </g:if><g:else>
     26                  <script type="text/javascript" src="${resource(dir: 'js', file: 'ontology-chooser.js')}"></script>
     27                </g:else>
    2328        </head>
    2429        <body>
     
    2934                                $("#selectedTemplateFields").sortable({
    3035                                        placeholder: 'ui-state-highlight',
     36                                        items: 'li:not(.domain)',
    3137                                        cancel: '.empty, input, select, button, textarea, form, label',
    3238                                        connectWith: '.templateFields',
    3339                                        update: updateTemplateFieldPosition,
     40                                        receive: addTemplateFieldEvent,
    3441                                        remove: removeTemplateFieldEvent,
    35                                         receive: addTemplateFieldEvent
     42                                        start: savePosition
    3643                                }).disableSelection();
    3744
     
    4047                                        placeholder: 'ui-state-highlight',
    4148                                        cancel: '.empty, input, select, button, textarea, form, label',
    42                                         connectWith: '.templateFields'
     49                                        connectWith: '.templateFields',
     50                                        start: savePosition
    4351                                }).disableSelection();
    44                                
     52
     53
     54                                $("#ontologyDialog").dialog({
     55                                  autoOpen: false,
     56                                  title: 'Search for ontology',
     57                                  height: 290,
     58                                  width: 350,
     59                                  modal: true,
     60                                  buttons: {
     61                                          'Add': addOntology,
     62                                          Cancel: function() {
     63                                                  $(this).dialog('close');
     64                                          }
     65                                  },
     66                                  close: function() {
     67                                  }
     68
     69                                });
     70
    4571                        });
    4672                </script>
     
    5682
    5783                                <p>Currently, this template contains the following fields. Drag fields to reorder. Drag fields to the list of available fields to remove the field from the template.</p>
    58                                 <ol id="selectedTemplateFields" class="templateFields">
     84                                <ol id="domainFields" class="templateFields <g:if test="${template.inUse()}">inUse</g:if>">
     85                                        <g:render template="elements/domainField" var="domainField" collection="${domainFields}" model="['template':template]"/>
     86                                </ol>
     87                                <ol id="selectedTemplateFields" class="templateFields <g:if test="${template.inUse()}">inUse</g:if>">
     88                                        <g:render template="elements/selected" var="templateField" collection="${template.fields}" model="['template':template]"/>
    5989                                        <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. Drag a field to this list or use the 'Add field button'.</li>
    60                                         <g:render template="elements/selected" collection="${template.fields}" model="['template':template]"/>
    6190                                </ol>
    6291                        </div>
     
    6796                                <ol id="availableTemplateFields" class="templateFields">
    6897                                        <li class="empty ui-state-default" <g:if test="${allFields.size() > template.fields.size()}">style='display: none;'</g:if>>There are no additional fields that can be added. Use the 'Create new field' button to create new fields.</li>
    69                                         <g:render template="elements/available" collection="${allFields - template.fields}" />
     98                                        <g:render template="elements/available" var="templateField" collection="${allFields - template.fields}" />
    7099                                </ol>
    71100
     
    87116                </g:if>
    88117
     118                <div id="ontologyDialog">
     119                  <g:render template="ontologyDialog" />
     120                </div>
    89121
    90122        </body>
  • trunk/web-app/css/templateEditor.css

    r556 r558  
    3838.templateFields .empty { opacity: 0.6; padding: 5px 25px; }
    3939
     40/* Domain fields should be yellow */
     41.templateFields .domain { background: #FFFFEA; border-color: #EAEAAE; padding-left: 23px; color: #8F8408; }
     42
    4043/* The position where an item can be dropped in the available list will be red */
    4144#availableTemplateFields .ui-state-highlight { background: #FFD6D6; border-color: #EAAEAE; }
     
    4548.templateField_form .templateFieldButtons { margin-top: 8px; padding-top: 8px; border-top: 1px solid #BBD; }
    4649.templateField_form label { width: 80px; float: left; display: block; }
    47 .templateField_form textarea {width: 145px; height: 100px;  }
     50.templateField_form textarea {width: 205px; height: 100px;  }
    4851.templateField_form input[type=text],
    49 .templateField_form select {width: 145px; }
     52.templateField_form select {width: 205px; }
     53
     54#step3_availableFields .templateField_form p.noEditsPossible {height: auto; margin: 4px 0; padding: 4px; background: #FFD6D6; border: 1px solid #EAAEAE; color: #660000; }
     55.templateField_form .extra { display: none; }
     56
    5057
    5158/* Add new form */
     
    7481        margin-left: 10px; margin-right: 10px;
    7582}
     83
     84/* Add Ontology dialog */
     85#addOntology { list-style-type: none; padding-left: 0; }
     86#addOntology li { list-style-type: none; margin: 8px 0; padding-left: 20px; }
     87#addOntology li input.text { margin-top: 5px; }
     88#addOntology li .check { float: left; margin-left: -15px; margin-top: 2px; }
     89
  • trunk/web-app/js/templateEditor.js

    r556 r558  
    1313 */
    1414
     15// Flag to keep track of whether a form is opened or not
    1516var formOpened = false;
     17
     18// Contains information about the original position of an item, when it is being dragged
     19var currentSort = null;
    1620
    1721/*************************************
     
    121125function addTemplateListItem( id, newHTML ) {
    122126        // 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 );
     127        var li = $( newHTML );
    129128
    130129        // Append the listitem to the list
     
    138137function updateTemplateListItem( id, newHTML ) {
    139138        var li = $( '#template_' + id );
    140         li.html( newHTML );
     139        li.replaceWith( newHTML );
    141140}
    142141
     
    197196}
    198197
    199 
    200 
    201198/**
    202199 * Adds a new template field using AJAX
     
    242239        }
    243240    });
     241}
     242
     243/**
     244 * Deletes a template field using AJAX
     245 */
     246function deleteTemplateField( id ) {
     247    // Delete the field
     248    $.ajax({
     249        url:        baseUrl + '/templateEditor/deleteField',
     250        data:       'templateField=' + id,
     251        type:       "POST",
     252        success:    function(data, textStatus, request) {
     253                        // Put the new HTML into the list item
     254                        deleteFieldListItem( id );
     255
     256                        showHideEmpty( '#availableTemplateFields' );
     257        },
     258        error:      function( request ) {
     259            alert( "Could not delete template field: " + request.responseText );
     260        }
     261    });
     262
     263        return true;
    244264}
    245265
     
    288308        },
    289309        error: function( request ) {
    290             alert( "Could not move template field: " + request.responseText );
     310                        undoMove();
     311                        alert( "Could not move template field: " + request.responseText );
    291312        }
    292313    });
     
    313334 * Adds a new template field to the template using AJAX
    314335 */
    315 function addTemplateField( id, newposition ) {
     336function addTemplateField( id, newposition, moveAfterwards ) {
    316337        if( newposition == null ) {
    317338                newposition = -1;
    318339        }
     340
     341        if( moveAfterwards == null ) {
     342                moveAfterwards = false;
     343        }
     344
    319345        var templateId = $('#templateSelect').val();
    320346
     
    329355                        updateFieldListItem( id, data.html );
    330356
     357                        if( moveAfterwards ) {
     358                                moveFieldListItem( id, '#selectedTemplateFields' );
     359                        }
     360
    331361                        showHideEmpty( '#selectedTemplateFields' );
    332362                        showHideEmpty( '#availableTemplateFields' );
    333363        },
    334364        error:      function( request ) {
     365                        // Send the item back (if it has been moved )
     366                        if( !moveAfterwards ) {
     367                                undoMove();
     368                        }
     369
    335370            alert( "Could not add template field: " + request.responseText );
    336371        }
    337372    });
     373
     374        return true;
    338375}
    339376
     
    346383    var id = item_id.substring( item_id.lastIndexOf( '_' ) + 1 );
    347384
    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         }
     385        return removeTemplateField( id );
    356386}
    357387
     
    359389 * Removes a template field from a template using AJAX
    360390 */
    361 function removeTemplateField( id ) {
     391function removeTemplateField( id, moveAfterwards ) {
     392
     393        if( moveAfterwards == null ) {
     394                moveAfterwards = false;
     395        }
     396
    362397        var templateId = $('#templateSelect').val();
    363398
     
    371406                        updateFieldListItem( id, data.html );
    372407
     408                        if( moveAfterwards ) {
     409                                moveFieldListItem( id, '#availableTemplateFields' );
     410                        }
     411
    373412                        showHideEmpty( '#selectedTemplateFields' );
    374413                        showHideEmpty( '#availableTemplateFields' );
     
    376415        },
    377416        error:      function( request ) {
    378             alert( "Could not delete template field: " + request.responseText );
     417                        if( !moveAfterwards ) {
     418                                undoMove();
     419                        }
     420
     421                        alert( "Could not delete template field: " + request.responseText );
    379422        }
    380423    });
     
    383426}
    384427
    385 /**
    386  * Deletes a template field using AJAX
    387  */
    388 function deleteTemplateField( id ) {
    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 }
    407428
    408429// Adds a new listitem when a field has been added
    409430function addFieldListItem( id, newHTML ) {
    410431        // Create a new listitem
    411         var li = $( '<li></li>' );
    412         li.attr( 'id', 'templateField_' + id );
    413         li.addClass( "ui-state-default" );
    414        
    415         // Insert the right HTML
    416         li.html( newHTML );
     432        var li = $( newHTML );
    417433
    418434        // Append the listitem to the list
     
    426442function updateFieldListItem( id, newHTML ) {
    427443        var li = $( '#templateField_' + id );
    428         li.html( newHTML );
     444        li.replaceWith( newHTML );
    429445}
    430446
     
    445461        $( toSelector ).append( li );
    446462}
     463
     464/**
     465 * Saves the original position of a sortable LI, in order to be able to undo the move event later on
     466 * This function is called on start event of the sortable lists
     467 */
     468function savePosition( event, ui ) {
     469        currentSort = {
     470                id:   ui.item.attr( 'id' ),
     471                parent: ui.item.context.parentNode,
     472                previous: ui.item.context.previousElementSibling,
     473                index: ui.item.index()
     474        }
     475}
     476
     477/**
     478 * Undoes the move of an item, when an ajax call has failed
     479 */
     480function undoMove() {
     481        if( currentSort ) {
     482                var item = $( '#' + currentSort.id );
     483                item.remove();
     484                item.insertAfter( currentSort.previous );
     485        }
     486}
     487
     488/**
     489 * Shows and hides the right 'extra' divs in the field form.
     490 *
     491 * These fields show extra input fields for stringlist and ontology fields
     492 *
     493 * @param       id      ID of the templateField
     494 */
     495function showExtraFields( id ) {
     496        // Find the current selected fieldtype
     497        var fieldType = $( '#templateField_' + id + '_form select[name=type]' ).val();
     498
     499        // Hide all extra forms, and show the right one
     500        $( '#templateField_' + id + '_form .extra' ).hide();
     501        $( '#templateField_' + id + '_form .' + fieldType.toLowerCase() + '_options' ).show();
     502}
     503
    447504
    448505/**
     
    457514        }
    458515}
     516
     517/************************************
     518 *
     519 * Functions for selecting ontologies
     520 *
     521 */
     522
     523function openOntologyDialog() {
     524        $('#ontologyDialog').dialog('open');
     525}
     526
     527function addOntology() {
     528        // Add ontology using AJAX
     529        var url; var data;
     530
     531    // Create a URL to call and call it
     532        if( $( '#ncboID' ).val() ) {
     533            url = baseUrl + '/templateEditor/addOntologyById';
     534                data = 'ncboID=' + $( '#ncboID' ).val();
     535                $( '#ncbo_spinner' ).show();
     536        } else {
     537            url = baseUrl + '/templateEditor/addOntologyByTerm';
     538                data = 'termID=' + $( '#termID' ).val();
     539                $( '#term_spinner' ).show();
     540        }
     541
     542    // Move the item
     543    $.ajax({
     544        url: url,
     545                data: data,
     546                dataType: 'json',
     547                type: 'POST',
     548        success: function(data, textStatus, request) {
     549                        updateOntologyLists( data )
     550                        $( '#term_spinner' ).hide();
     551                        $( '#ncbo_spinner' ).hide();
     552
     553                        $('#ontologyDialog').dialog('close');
     554        },
     555        error: function( request ) {
     556                        alert( "Could not add ontology: " + request.responseText );
     557                        $( '#term_spinner' ).hide();
     558                        $( '#ncbo_spinner' ).hide();
     559                        $('#ontologyDialog').dialog('close');
     560        }
     561    });
     562}
     563
     564function updateOntologyLists( newObject ) {
     565        $( '.ontologySelect' ).append( '<option value="' + newObject.id + '">' + newObject.name + '</option>');
     566}
Note: See TracChangeset for help on using the changeset viewer.