Changeset 544


Ignore:
Timestamp:
Jun 9, 2010, 12:46:22 PM (9 years ago)
Author:
roberth
Message:

Template editor is now able to add, edit, move and delete fields. Also fixed bug #90 (searching publications in IE didn't work because fetching XML from another domain was not allowed)

Location:
trunk
Files:
4 added
8 edited
1 moved

Legend:

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

    r538 r544  
    1717import dbnp.studycapturing.*
    1818import cr.co.arquetipos.crypto.Blowfish
     19import grails.converters.*
    1920
    2021class TemplateEditorController {
     
    5152
    5253    /**
     54     * Shows an error page
     55     *
     56     * TODO: improve the error page
     57     */
     58    def error = {
     59        render( 'view': 'error' );
     60    }
     61
     62    /**
     63     * Adds a new template field using a AJAX call
     64         *
     65         * @param template      ID of the template to add a field to
     66         * @return                      JSON object with two entries:
     67         *                                              id: [id of this object]
     68         *                                              html: HTML to replace the contents of the LI-item that was updated.
     69         *                                      On error the method gives a HTTP response status 500 and the error
     70     */
     71    def addField = {
     72        // Search for the template
     73        def template = Template.get( params.template );
     74
     75        if( !template ) {
     76            response.status = 404;
     77            render 'Template not found';
     78            return;
     79        }
     80
     81                // Create the template field and add it to the template
     82                def templateField = new TemplateField( params );
     83        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()] );
     87                        def output = [ id: templateField.id, html: html ];
     88                        render output as JSON;
     89
     90            //render '';
     91        } else {
     92            response.status = 500;
     93            render 'TemplateField could not be added because errors occurred.';
     94            return
     95        }
     96    }
     97
     98    /**
    5399     * Updates a selected template field using a AJAX call
     100         *
     101         * @param id    ID of the field to update
     102         * @return              JSON object with two entries:
     103         *                                      id: [id of this object]
     104         *                                      html: HTML to replace the contents of the LI-item that was updated.
     105         *                              On error the method gives a HTTP response status 500 and the error
    54106     */
    55107    def update = {
     
    73125        templateField.properties = params
    74126        if (!templateField.hasErrors() && templateField.save(flush: true)) {
    75             render '';
     127                        def html = g.render( template: 'elements/liContent', model: [templateField: templateField, fieldTypes: TemplateFieldType.list()] );
     128                        def output = [ id: templateField.id, html: html ];
     129                        render output as JSON;
    76130        } else {
    77131            response.status = 500;
     
    82136
    83137    /**
    84      * Shows an error page
    85      *
    86      * TODO: improve the error page
    87      */
    88     def error = {
    89         render( 'view': 'error' );
     138     * Deletes a selected template field from the template using a AJAX call
     139         *
     140         * @param templateField ID of the field to update
     141         * @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 = {
     145        // Search for the template
     146        def template = Template.get( params.template );
     147
     148        if( !template ) {
     149            response.status = 404;
     150            render 'Template not found';
     151            return;
     152        }
     153
     154        // Search for the template field
     155        def templateField = TemplateField.get( params.templateField );
     156        if( !templateField ) {
     157            response.status = 404;
     158            render 'TemplateField not found';
     159            return;
     160        }
     161
     162        // The template field should exist within the template
     163        if( !template.fields.contains( templateField ) ) {
     164            response.status = 404;
     165            render 'TemplateField not found within template';
     166            return;
     167        }
     168
     169                // Delete the field from this template
     170        def currentIndex = template.fields.indexOf( templateField );
     171        template.fields.remove( currentIndex );
     172                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                */
    90186    }
    91187
     
    93189     * Moves a template field using a AJAX call
    94190     *
    95      *
     191         * @param template              ID of the template that contains this field
     192         * @param templateField ID of the templatefield to move
     193         * @param position              New index of the templatefield in the array. The index is 0-based.
     194         * @return                              JSON object with two entries:
     195         *                                                      id: [id of this object]
     196         *                                                      html: HTML to replace the contents of the LI-item that was updated.
     197         *                                              On error the method gives a HTTP response status 500 and the error
    96198     */
    97199    def move = {
     
    125227        template.fields.add( Integer.parseInt( params.position ), moveField );
    126228
    127         render "";
     229                def html = g.render( template: 'elements/liContent', model: [templateField: templateField, fieldTypes: TemplateFieldType.list()] );
     230                def output = [ id: templateField.id, html: html ];
     231                render output as JSON;
    128232    }
    129233
    130234    /**
    131235     * Checks whether a correct entity is given
     236         *
     237         * @return      boolean True if a correct entity is given. Returns false and raises an error otherwise
     238         * @see         error()
    132239     */
    133240    def _checkEntity = {
     
    137244        if( !entityName ) {
    138245            error();
    139             return;
     246            return false;
    140247        }
    141248
     
    145252        if( !entity ) {
    146253            error();
    147             return;
     254            retur; false
    148255        }
    149256
     
    154261    /**
    155262     * Checks whether the entity type is given and can be parsed
     263         *
     264         * @return      Name of the entity if parsing is succesful, false otherwise
    156265     */
    157266    def _parseEntityType() {
     
    181290
    182291    /**
    183      * Creates an object of the given entity. Returns false is the entity
    184      *   is not a subclass of TemplateEntity
     292     * Creates an object of the given entity.
     293         *
     294         * @return False if the entity is not a subclass of TemplateEntity
    185295     */
    186296    def _getEntity( entityName ) {
  • trunk/grails-app/controllers/dbnp/studycapturing/WizardController.groovy

    r541 r544  
    11221122                }
    11231123        }
     1124
     1125        /**
     1126         * Proxy for searching PubMed articles (or other articles from the Entrez DB).
     1127         *
     1128         * This proxy is needed because it is not allowed to fetch XML directly from a different
     1129         * domain using javascript. So we have the javascript call a function on our own domain
     1130         * and the proxy will fetch the data from Entrez
     1131         *
     1132         * @since       20100609
     1133         * @param       _utility        The name of the utility, without the complete path. Example: 'esearch.fcgi'
     1134         * @return      XML
     1135         */
     1136        def entrezProxy = {
     1137                // Remove unnecessary parameters
     1138                params.remove( "action" )
     1139                params.remove( "controller" )
     1140
     1141                def url = "http://eutils.ncbi.nlm.nih.gov/entrez/eutils";
     1142                def util = params.remove( "_utility" )
     1143                def paramString = params.collect { k, v -> k + '=' + v.encodeAsURL() }.join( '&' );
     1144
     1145                def fullUrl = url + '/' + util + '?' + paramString;
     1146
     1147                // Return the output of the request
     1148                // render fullUrl;
     1149                render(
     1150                    text:           new URL( fullUrl ).getText(),
     1151                    contentType:    "text/xml",
     1152                    encoding:       "UTF-8"
     1153                );
     1154        }
    11241155}
  • trunk/grails-app/views/templateEditor/elements/_all.gsp

    r538 r544  
    11<li class="ui-state-default" id="templateField_${it.id}">
    2   <span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
    3   <b>${it.name}</b>
    4   (<g:render template="elements/${it.type.toString().toLowerCase().replaceAll(/ /,'_')}" />)
    5 
    6   <form class="templateField_form" id="templateField_${it.id}_form" action="update">
    7     <g:hiddenField name="id" value="${it.id}" />
    8     <g:hiddenField name="version" value="${it.version}" />
    9     <label for="name">Name:</label> <g:textField name="name" value="${it.name}" /><br />
    10     <label for="type">Type:</label> <g:select from="${fieldTypes}" name="type" value="${it.type}" /><br />
    11     <label for="unit">Unit:</label> <g:textField name="unit" value="${it.unit}" /><br />
    12     <label for="comment">Comment:</label> <g:textArea name="comment" value="${it.comment}" /><br />
    13     <label for="required">Required:</label> <g:checkBox name="required" value="${it.required}" /><br />
    14 
    15     <input type="button" value="Save" onClick="updateTemplateField( ${it.id} );">
    16     <input type="button" value="Delete" onClick="">
    17     <input type="button" value="Close" onClick="hideTemplateFieldForm( ${it.id} );">
    18   </form>
     2        <g:render template="elements/liContent" model="['templateField': it, 'fieldTypes': fieldTypes]"/>
    193</li>
  • trunk/grails-app/views/templateEditor/index.gsp

    r538 r544  
    11<%
    22        /**
    3          * Template Editor overview template
    4          *
    5          * @author Jeroen Wesbeek
    6          * @since 20100422
    7          * @package wizard
    8          * @see dbnp.studycapturing.TemplateEditorController
    9          *
    10          * Revision information:
    11          * $Rev: 428 $
    12          * $Author: duh $
    13          * $Date: 2010-05-18 11:09:55 +0200 (di, 18 mei 2010) $
    14          */
     3        * Template Editor overview template
     4        *
     5        * @author Jeroen Wesbeek
     6        * @since 20100422
     7        * @package wizard
     8        * @see dbnp.studycapturing.TemplateEditorController
     9        *
     10        * Revision information:
     11        * $Rev: 428 $
     12        * $Author: duh $
     13        * $Date: 2010-05-18 11:09:55 +0200 (di, 18 mei 2010) $
     14        */
    1515%>
    1616<%@ page contentType="text/html;charset=UTF-8" %>
    1717<html>
    18  <head>
    19   <meta name="layout" content="dialog"/>
    20   <title>template editor</title>
    21   <script src="${createLinkTo(dir: 'js', file: 'templateEditor.js')}" type="text/javascript"></script>
    22   <link rel="stylesheet" href="${createLinkTo(dir: 'css', file: 'templateEditor.css')}" />
    23  </head>
    24  <body>
     18        <head>
     19                <meta name="layout" content="dialog"/>
     20                <title>template editor</title>
     21                <script src="${createLinkTo(dir: 'js', file: 'templateEditor.js')}" type="text/javascript"></script>
     22                <link rel="stylesheet" href="${createLinkTo(dir: 'css', file: 'templateEditor.css')}" />
     23        </head>
     24        <body>
    2525
    26   <script type="text/javascript">
    27          $(function() {
    28                  $("#templateFields").sortable({
    29                          placeholder: 'ui-state-highlight',
    30                          update: updateTemplateFieldPosition
    31                  });
    32                  $("#templateFields").disableSelection();
    33                  $('#templateFields li').bind('dblclick', showTemplateFormEvent);
     26                <script type="text/javascript">
     27                        $(function() {
     28                                $("#templateFields").sortable({
     29                                        placeholder: 'ui-state-highlight',
     30                                        cancel: '.empty',
    3431
    35          });
    36   </script>
     32                                        update: updateTemplateFieldPosition
     33                                });
     34                                $("#templateFields").disableSelection();
     35                                //$('#templateFields li').bind('dblclick', showTemplateFormEvent);
     36                        });
     37                </script>
    3738
    38  <p>Please select a template to edit or create a new template</p>
    39  <g:form action="index" name="templateChoice">
    40     <g:hiddenField name="entity" value="${encryptedEntity}" />
    41     <select name="template" id="templateSelect" onChange="this.form.submit();">
    42       <option value=""></option>
    43       <g:each in="${templates}" var="currentTemplate">
    44         <g:if test="${currentTemplate.id==template?.id}">
    45           <option selected value="${currentTemplate.id}">${currentTemplate.name}</option>
    46         </g:if>
    47         <g:else>
    48           <option value="${currentTemplate.id}">${currentTemplate.name}</option>
    49         </g:else>
    50       </g:each>
    51     </select>
    52  </g:form>
     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>
     44                                <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>
     51                                </g:each>
     52                        </select>
     53                </g:form>
    5354
    54  <g:if test="${template}">
    55   <p>Currently, this template contains the following fields. Drag fields to reorder and double click fields to edit.</p>
    56   <ul id="templateFields">
    57     <g:render template="elements/all" collection="${template.fields}" />
    58   </ul>
    59  </g:if>
     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}" />
     60                        </ul>
    6061
    61  add a new field:
    62  <!-- g:select from="${templateFields}" //-->
    63  
    64  </body>
     62                        <div id="addNew">
     63                                <a href="#" onClick="showTemplateFieldForm( 'templateField_new' ); this.blur(); return false;">
     64                                        <b>Add new field</b>
     65                                </a>
     66
     67                                <form class="templateField_form" id="templateField_new_form" action="addField">
     68                                        <g:render template="elements/fieldForm" model="['templateField': null, 'fieldTypes': fieldTypes]"/>
     69                                        <div class="templateFieldButtons">
     70                                                <input type="button" value="Save" onClick="addTemplateField( 'new' );">
     71                                                <input type="button" value="Cancel" onClick="hideTemplateFieldForm( 'new' );">
     72                                        </div>
     73                                </form>
     74                        </div>
     75                </g:if>
     76
     77        </body>
    6578</html>
  • trunk/web-app/css/templateEditor.css

    r538 r544  
    1818}
    1919
    20 .templateField_form { display: none; }
     20#templateFields .empty { opacity: 0.6; padding: 5px 25px; }
     21
     22.templateField_form { display: none; margin: 5px; padding-top: 8px; border-top: 1px solid #BBD; }
     23.templateField_form .templateFieldButtons { margin-top: 8px; padding-top: 8px; border-top: 1px solid #BBD; }
    2124.templateField_form label { width: 100px; float: left; display: block; }
     25.templateField_form textarea {width: 240px; height: 100px;  }
     26
     27#addNew {
     28        width: 388px;
     29        line-height: 16px;
     30        background-color: #EBF9D7;
     31        border:1px solid #D0EAAE;
     32        color:#79AA27;
     33        font-weight:bold;
     34
     35        margin: 10px 5px;
     36        padding: 0px;
     37}
     38
     39#addNew.ui-state-disabled { opacity:0.35; }
     40#addNew a {
     41        display: block;
     42        padding: 7px 25px;
     43        cursor: pointer;
     44        color:#79AA27;
     45        text-decoration: none;
     46}
     47
     48#addNew form{
     49        margin-left: 10px; margin-right: 10px;
     50}
  • trunk/web-app/js/publication-chooser.js

    r527 r544  
    244244                // check whether there are results or nog
    245245                var improvedResponse = function( objects ) {
    246                     if( objects.length == 0 ) {
     246                    if( objects == null ) {
     247                                                objects = new Array();
     248                                        }
     249                                        if( objects.length == 0 ) {
    247250                        $( '#' + inputElement.attr( 'id' ) + '_spinner' ).hide();
    248251                        $( '#' + inputElement.attr( 'id' ) + '_notfound' ).show();
  • trunk/web-app/js/publication-chooser.pubmed.js

    r527 r544  
     1function _createURL( utility, params ) {
     2        return baseUrl + "/wizard/entrezProxy?_utility=" + utility + "&" + params;
     3}
    14sourcePubMed = function( chooserObject, searchterm, response ) {
    25    // Search for every term in both title and author fields
     
    710    }
    811
    9     var url = "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=pubmed&term=" + searchFor.join( " AND " ) + "&usehistory=y";
     12    // The fetching of the data is done using a proxy, because in IE it is not allowed to retrieve
     13    // XML data from another domain.
     14    var utility = 'esearch.fcgi';
     15    var params = "db=pubmed&term=" + searchFor.join( " AND " ) + "&usehistory=y";
     16    var url = _createURL( utility, params );
    1017
    1118    // Fetch it from Pubmed
     
    1926                var query_key = $("QueryKey", xmlDoc ).text();
    2027
     28                var utility = 'esummary.fcgi';
     29                var params = "db=pubmed&retmax=" + chooserObject.maxResults + "&query_key=" + query_key + "&WebEnv=" + WebEnv;
     30                var url = _createURL( utility, params );
     31
    2132                $.ajax({
    22                     url: "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&retmax=" + chooserObject.maxResults + "&query_key=" + query_key + "&WebEnv=" + WebEnv,
     33                    url: url,
    2334                    dataType: "xml",
    2435                    success: function(summaryResponse) {
     
    3142                        // Return it to jquery
    3243                        response( parsedData );
     44                    },
     45                    error: function() {
     46                            response( null );
    3347                    }
    3448                })
     49            },
     50            error: function() {
     51                response( null );
    3552            }
    3653    })
  • trunk/web-app/js/templateEditor.js

    r538 r544  
    1919 */
    2020function showTemplateFormEvent(e) {
    21     // Show the form is this item is not disabled
    22     if( !formOpened ) {
    23         formOpened = true;
    24         showTemplateFieldForm( e.target.id );
    25     }
     21    showTemplateFieldForm( e.target.id );
    2622}
    2723
     
    3026 */
    3127function showTemplateFieldForm( list_item_id ) {
    32     // Show the form
    33     $( '#' + list_item_id + '_form' ).show();
    34    
    35     // Disable all other listitems
    36     $( '#templateFields li:not(#' + list_item_id + ')').addClass( 'ui-state-disabled' );
     28    // Show the form is this item is not disabled
     29    if( !formOpened ) {
     30        formOpened = true;
    3731
     32                // Show the form
     33                $( '#' + list_item_id + '_form' ).show();
     34
     35                // Disable all other listitems
     36                $( '#templateFields li:not(#' + list_item_id + ')').addClass( 'ui-state-disabled' );
     37
     38                if( list_item_id != 'templateField_new' ) {
     39                        // Disable add new
     40                        $( '#addNew').addClass( 'ui-state-disabled' );
     41                }
     42        }
    3843}
    3944
     
    4651    // Enable all other listitems
    4752    $( '#templateFields li:not(#templateField_' + id + ')').removeClass( 'ui-state-disabled' );
     53        $( '#addNew').removeClass( 'ui-state-disabled' );
    4854
    4955    formOpened = false;
     
    6571
    6672    // Create a URL to call and call it
    67     var url = baseUrl + '/templateEditor/move?template=' + templateId + '&templateField=' + templateFieldId + '&position=' + newposition;
     73    var url = baseUrl + '/templateEditor/move';
    6874
    6975    // Disable sorting until this move has been saved (in order to prevent collisions
     
    7379    $.ajax({
    7480        url: url,
     81                data: 'template=' + templateId + '&templateField=' + templateFieldId + '&position=' + newposition,
     82                dataType: 'json',
     83                type: 'POST',
    7584        success: function(data, textStatus, request) {
     85            updateListItem( templateFieldId, data.html );
    7686            $( '#templateFields' ).sortable( 'enable' );
    7787        },
    7888        error: function() {
    7989            alert( "Could not move template field" );
     90        }
     91    });
     92}
     93
     94/**
     95 * Adds a new template field using AJAX
     96 */
     97function addTemplateField( id ) {
     98    var formEl = $( '#templateField_' + id + '_form' );
     99        var templateId = $('#templateSelect').val();
     100
     101    // Update the field
     102    $.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" );
    80113        }
    81114    });
     
    91124    $.ajax({
    92125        url:        baseUrl + '/templateEditor/' + formEl.attr( 'action' ),
     126                dataType: 'json',
    93127        data:       formEl.serialize(),
    94128        type:       "POST",
    95129        success:    function(data, textStatus, request) {
    96130            hideTemplateFieldForm( id );
    97             updateListItemTitle( id );
     131            updateListItem( id, data.html );
    98132        },
    99133        error:      function() {
     
    103137}
    104138
    105 // Updates the visible text on the listitem when a field is updated
    106 function updateListItemTitle( id ) {
     139/**
     140 * Deletes a template field using AJAX
     141 */
     142function 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
     160
     161// Adds a new listitem when a field has been added
     162function addListItem( id, newHTML ) {
     163        // Create a new listitem
     164        var li = $( '<li></li>' );
     165        li.attr( 'id', 'templateField_' + id );
     166        li.addClass( "ui-state-default" );
     167       
     168        // Insert the right HTML
     169        li.html( newHTML );
     170
     171        // Append the listitem to the list
     172        $( '#templateFields li:last').after( li );
     173
     174        // Hide the 'empty' listitem
     175        $( '#templateFields .empty' ).hide();
     176}
     177
     178// Updates the contents of the listitem when something has changed
     179function updateListItem( id, newHTML ) {
     180        var li = $( '#templateField_' + id );
     181        li.html( newHTML );
     182}
     183
     184// Removes a listitem when the template field has been deleted
     185function deleteListItem( id ) {
     186        var li = $( '#templateField_' + id );
     187        li.remove();
     188
     189        // Show the 'empty' listitem if the last item is deleted
     190        if( $( '#templateFields li:not(.empty)' ).length == 0 ) {
     191                $( '#templateFields .empty' ).show();
     192        }
    107193
    108194}
Note: See TracChangeset for help on using the changeset viewer.