Changeset 518
- Timestamp:
- Jun 3, 2010, 12:27:08 PM (13 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/grails-app/controllers/dbnp/studycapturing/PublicationController.groovy
r496 r518 144 144 } 145 145 } 146 147 /** 148 * Searches for an ID in the current database, based on the pubMedID 149 * If the publication is not found in the database, it is added 150 */ 151 def getID = { 152 // Find the ID 153 def pubMedID = params.get( 'publication-pubMedID' ); 154 if( pubMedID ) { 155 def publication = Publication.findByPubMedID( pubMedID ); 156 if( !publication ) { 157 publication = new Publication( 158 title: params.get( 'publication-title' ), 159 authorsList: params.get( 'publication-authorsList' ), 160 pubMedID: params.get( 'publication-pubMedID' ), 161 DOI: params.get( 'publication-doi' ) 162 ).save(flush:true); 163 } 164 165 // Return the ID 166 render publication.id; 167 } else { 168 response.status = 500; 169 render "No pubMedID found in request"; 170 } 171 } 146 172 } -
trunk/grails-app/controllers/dbnp/studycapturing/WizardController.groovy
r512 r518 133 133 success() 134 134 }.to "study" 135 135 on("switchTemplate") { 136 136 flash.values = params 137 137 … … 604 604 } 605 605 606 // handle Publications 607 handlePublications(flow, flash, params) 608 606 609 // validate study 607 610 if (flow.study.validate()) { … … 614 617 } 615 618 } 619 620 /** 621 * re-usable code for handling publications form data in a web flow 622 * @param Map LocalAttributeMap (the flow scope) 623 * @param Map localAttributeMap (the flash scope) 624 * @param Map GrailsParameterMap (the flow parameters = form data) 625 * @returns boolean 626 */ 627 def handlePublications(flow, flash, params) { 628 // create study instance if we have none 629 if (!flow.study) flow.study = new Study(); 630 if (!flow.study.publications ) flow.study.publications = []; 631 632 // Check the ids of the pubblications that should be attached 633 // to this study. If they are already attached, keep 'm. If 634 // studies are attached that are not in the selected (i.e. the 635 // user deleted them), remove them 636 def publicationIDs = params.get( 'publication_ids' ); 637 if( publicationIDs ) { 638 // Find the individual IDs and make integers 639 publicationIDs = publicationIDs.split(',').collect { Integer.parseInt( it, 10 ) }; 640 641 // First remove the publication that are not present in the array 642 flow.study.publications.removeAll { publication -> !publicationIDs.find { id -> id == publication.id } } 643 644 // Add those publications not yet present in the database 645 publicationIDs.each { id -> 646 if( !flow.study.publications.find { publication -> id == publication.id } ) { 647 def publication = Publication.get( id ); 648 if( publication ) { 649 flow.study.addToPublications( publication ); 650 } else { 651 println( 'Publication with ID ' + id + ' not found in database.' ); 652 } 653 } 654 } 655 656 } else { 657 println( 'No publications selected.') 658 flow.study.publications.clear(); 659 } 660 661 } 662 616 663 617 664 /** -
trunk/grails-app/domain/dbnp/studycapturing/Publication.groovy
r496 r518 46 46 */ 47 47 48 class Publication {48 class Publication implements Serializable { 49 49 50 50 String title -
trunk/grails-app/taglib/dbnp/studycapturing/WizardTagLib.groovy
r507 r518 983 983 } 984 984 } 985 986 def PublicationSelectElement = { attrs, body -> 987 988 attrs.description = 'Publications'; 989 // render list with publications currently available 990 baseElement.call( 991 '_publicationList', 992 attrs, 993 body 994 ) 995 996 attrs.description = ''; 997 998 // render 'Add publication button' 999 baseElement.call( 1000 '_publicationAddButton', 1001 attrs, 1002 body 1003 ) 1004 } 1005 1006 /** 1007 * Renders a input box for publications 1008 */ 1009 def publicationSelect = { attrs, body -> 1010 if( attrs.get( 'value' ) == null ) { 1011 attrs.value = []; 1012 } 1013 if( attrs.get( 'description' ) == null ) { 1014 attrs.description = ''; 1015 } 1016 out << '<form id="' + attrs.name + '_form">'; 1017 out << textField( 1018 name: attrs.get( "name" ), 1019 value: '', 1020 rel: 'publication-pubmed', 1021 style: 'width: 400px;' 1022 ); 1023 out << '</form>'; 1024 out << '<script type="text/javascript">'; 1025 out << ' iField = $( "#' + attrs.get( 'name' ) + '" );'; 1026 out << ' new PublicationChooser().initAutocomplete( iField );'; 1027 out << '</script>'; 1028 } 1029 1030 def _publicationList = { attrs, body -> 1031 def display_none = 'none'; 1032 if( !attrs.get( 'value' ) || attrs.get( 'value' ).size() == 0 ) { 1033 display_none = 'inline'; 1034 } 1035 1036 // Add a unordered list 1037 out << '<ul class="publication_list" id="' + attrs.name + '_list">'; 1038 1039 out << '<li>'; 1040 out << '<span class="publication_none" id="' + attrs.name + '_none" style="display: ' + display_none + ';">'; 1041 out << 'No publications selected'; 1042 out << '</span>'; 1043 out << '</li>'; 1044 1045 out << '</ul>'; 1046 1047 // Add the publications using javascript 1048 out << '<script type="text/javascript">' 1049 if( attrs.get( 'value' ) && attrs.get( 'value' ).size() > 0 ) { 1050 def i = 0; 1051 attrs.get( 'value' ).each { 1052 out << 'showPublication( '; 1053 out << ' "' + attrs.name + '",'; 1054 out << ' ' + it.id + ','; 1055 out << ' "' + it.title + '",'; 1056 out << ' "' + it.authorsList + '",'; 1057 out << ' ' + i++; 1058 out << ');'; 1059 } 1060 } 1061 out << '</script>'; 1062 1063 def ids; 1064 if( attrs.get( 'value' ) && attrs.get( 'value' ).size() > 0 ) { 1065 ids = attrs.get( 'value' ).id.join( ',' ) 1066 } else { 1067 ids = ''; 1068 } 1069 out << '<input type="hidden" name="' + attrs.name + '_ids" value="' + ids + '" id="' + attrs.name + '_ids" value="' + ids + '">'; 1070 } 1071 1072 def _publicationAddButton = { attrs, body -> 1073 1074 // Output the dialog for the publications 1075 out << '<div id="' + attrs.name + '_dialog">'; 1076 out << publicationSelect( attrs, body ); 1077 out << '</div>'; 1078 out << '<script type="text/javascript">'; 1079 out << ' $("#' + attrs.name + '_dialog").dialog({'; 1080 out << ' title : "Add publication",'; 1081 out << ' autoOpen: false,'; 1082 out << ' width : 800,'; 1083 out << ' height : 400,'; 1084 out << ' modal : true,'; 1085 out << ' position: "center",'; 1086 out << ' buttons : {'; 1087 out << ' Add : function() { addPublication( "' + attrs.name + '" ); $(this).dialog("close"); },'; 1088 out << ' Close : function() { $(this).dialog("close"); }'; 1089 out << ' },'; 1090 out << ' close : function() {'; 1091 out << ' /* closeFunc(this); */'; 1092 out << ' }'; 1093 out << ' }).width(790).height(400);'; 1094 out << '</script>'; 1095 1096 out << '<input type="button" onClick="var field = $( \'#' + attrs.name + '\' ); field.autocomplete( \'close\' ); field.val( \'\' );$( \'#' + attrs.name + '_dialog\' ).dialog( \'open\' ); field.focus();" value="Add Publication">'; 1097 } 1098 985 1099 } -
trunk/grails-app/views/publication/add.gsp
r496 r518 22 22 <script type="text/javascript" src="${resource(dir: 'js', file: 'publication-chooser.pubmed.js')}"></script> 23 23 <script type="text/javascript" src="${resource(dir: 'js', file: 'publication-chooser.programminglanguages.js')}"></script> 24 24 <script type="text/javascript"> 25 PublicationChooser.prototype.availableDBs[ "pubmed" ].select = selectPubMedAdd; 26 PublicationChooser.prototype.availableDBs[ "pubmed" ].close = closePubMedAdd; 27 </script> 25 28 </head> 26 29 <body> 27 28 <g:form action="createFromPubmed">29 <g:textField name="publication" rel="publication-pubmed" style="width:300px;"/>30 <g:submitButton name="add" value="Add publication" />31 </g:form>32 33 30 <p> 31 Search for a publication on pubmed. You can search on a part of the title or authors. 32 </p> 33 <g:form action="createFromPubmed"> 34 <g:textField name="publication" rel="publication-pubmed" style="width:500px;"/> 35 <!-- <g:submitButton name="add" value="Add publication" /> --> 36 </g:form> 34 37 35 38 ${errors} -
trunk/grails-app/views/wizard/index.gsp
r507 r518 23 23 <script type="text/javascript" src="${resource(dir: 'js', file: 'table-editor.min.js')}"></script> 24 24 <script type="text/javascript" src="${resource(dir: 'js', file: 'ontology-chooser.min.js')}"></script> 25 <script type="text/javascript" src="${resource(dir: 'js', file: 'publication-chooser.js')}"></script> 26 <script type="text/javascript" src="${resource(dir: 'js', file: 'publication-chooser.pubmed.js')}"></script> 25 27 <script type="text/javascript" src="${resource(dir: 'js', file: 'SelectAddMore.min.js')}"></script> 26 28 <script type="text/javascript" src="${resource(dir: 'js', file: 'timepicker-0.2.1.min.js')}"></script> … … 33 35 <script type="text/javascript" src="${resource(dir: 'js', file: 'table-editor.js')}"></script> 34 36 <script type="text/javascript" src="${resource(dir: 'js', file: 'ontology-chooser.js')}"></script> 37 <script type="text/javascript" src="${resource(dir: 'js', file: 'publication-chooser.js')}"></script> 38 <script type="text/javascript" src="${resource(dir: 'js', file: 'publication-chooser.pubmed.js')}"></script> 35 39 <script type="text/javascript" src="${resource(dir: 'js', file: 'SelectAddMore.js')}"></script> 36 40 <script type="text/javascript" src="${resource(dir: 'js', file: 'timepicker-0.2.1.js')}"></script> -
trunk/grails-app/views/wizard/pages/_study.gsp
r455 r518 30 30 </wizard:templateElement> 31 31 <g:if test="${study}"><wizard:templateElements entity="${study}" /></g:if> 32 33 <wizard:publicationSelectElement name="publication" value="${study?.publications}" /> 34 32 35 </wizard:pageContent> -
trunk/web-app/css/wizard.css
r507 r518 348 348 color: red; 349 349 } 350 } 350 351 .wizard ul.publication_list { 352 list-style-type: none; 353 margin: -10px 0 0 255px; 354 padding: 0; 355 } 356 357 .wizard ul.publication_list li { 358 margin-left: 0px; 359 padding: 4px 6px; 360 } 361 362 .wizard ul.publication_list li.even { 363 background-color: #F0F0F0; 364 } 365 .wizard ul.publication_list li.odd { 366 background-color: #F8F8F8; 367 } 368 369 .wizard ul.publication_list li .delete_button { float: right; margin-left: 10px; } 370 .wizard ul.publication_list li .authors { font-size: 10px; margin-top: 3px; color: #333; } -
trunk/web-app/js/publication-chooser.js
r496 r518 149 149 * initialize object 150 150 */ 151 PublicationChooser.init = function( ) {151 PublicationChooser.init = function( events ) { 152 152 // find all ontology elements 153 153 $("input[rel*='publication']").each(function() { 154 new PublicationChooser().initAutocomplete( this);154 new PublicationChooser().initAutocomplete( this, events ); 155 155 }); 156 156 }; … … 159 159 minLength : 3, // minimum input length before launching Ajax request 160 160 cache : [], // ontology cache 161 maxResults : 10,// Max number of results retrieved161 maxResults : 8, // Max number of results retrieved 162 162 database : '', // Default database to be used. As for now, also the only possible database 163 163 availableDBs : {}, // Available databases, filled by extensions. Key is databasename and value is reference to method to be called 164 events : {}, // Stores the events to fire 164 165 165 166 /** … … 167 168 * @param element 168 169 */ 169 initAutocomplete: function( element) {170 initAutocomplete: function( element, customEvents ) { 170 171 var that = this 171 172 var inputElement = $(element); 172 173 var selected = false; 173 174 175 // Add spinner element 176 if( !baseUrl ) { 177 var baseUrl = '..'; 178 } 179 var imgEl = document.createElement( 'img' ); 180 imgEl.setAttribute( 'id', inputElement.attr( 'id' ) + '_spinner' ); 181 imgEl.setAttribute( 'src', baseUrl + '/images/spinner.gif' ); 182 imgEl.setAttribute( 'style', 'margin-left: 5px;'); 183 184 // Add the element next to the input box 185 inputElement.after( imgEl ); 186 $( imgEl ).hide(); 187 174 188 // determine what database to use 175 189 var values = inputElement.attr('rel').split("-"); 190 191 // Check which database the user wants 176 192 if( values.length > 1 ) { 177 193 // check for supported databases 178 194 if( this.availableDBs[ values[ 1 ] ] ) { 179 195 this.database = values[1]; 196 this.events = this.availableDBs[ this.database ]; 180 197 } else { 181 alert( 'Database ' + values[1] + ' not supported. Using default: ' + this.database ); 198 this.database = values[1] + " (custom)"; 199 this.events = {}; 182 200 } 201 } else { 202 this.database = "(custom)"; 203 this.events = {}; 204 } 205 206 // Add custom events to this object 207 if( customEvents ) { 208 $.each( customEvents, function( id, func ) { 209 that.events[ id ] = func; 210 }) 211 } 212 213 // If no 'source' function is defined, nothing can be searched for 214 if( !this.events[ 'source' ]) { 215 alert( 'Database ' + this.database + ' not supported. Using none.' ); 183 216 } 184 217 … … 189 222 inputElement.autocomplete({ 190 223 minLength: that.minLength, 191 delay: 400,224 delay: 300, 192 225 193 226 source: function(request, response) { … … 199 232 response(that.cache[ that.database ][ q ]); 200 233 } else { 201 if( that.database != "" && that. availableDBs[ that.database ] && that.availableDBs[ that.database ][ 'source' ] ) {202 that.availableDBs[ that.database ][ 'source' ]( that, q, response );234 if( that.database != "" && that.events[ 'source' ] ) { 235 that.events[ 'source' ]( that, q, response ); 203 236 } 204 237 } … … 206 239 search: function(event, ui ) { 207 240 that.selected = false; 241 $( '#' + inputElement.attr( 'id' ) + '_spinner' ).show(); 242 }, 243 open: function(event, ui ) { 244 $( '#' + inputElement.attr( 'id' ) + '_spinner' ).hide(); 208 245 }, 209 246 select: function(event, ui) { … … 211 248 that.selected = true; 212 249 213 if( that.database != "" && that. availableDBs[ that.database ] && that.availableDBs[ that.database ][ 'select' ] ) {214 that. availableDBs[ that.database ][ 'select' ]( that, inputElement, event, ui );250 if( that.database != "" && that.events[ 'select' ] ) { 251 that.events[ 'select' ]( that, inputElement, event, ui ); 215 252 } 216 253 }, 217 254 close: function(event, ui) { 218 255 if( !that.selected ) { 219 if( that.database != "" && that.availableDBs[ that.database ] && that.availableDBs[ that.database ][ 'close' ] ) { 220 that.availableDBs[ that.database ][ 'close' ]( that, inputElement, event, ui ); 256 if( that.database != "" && that.events[ 'close' ] ) { 257 that.events[ 'close' ]( that, inputElement, event, ui ); 258 } 259 260 if( inputElement.closePublication ) { 261 inputElement.closePublication( that, event, ui ); 221 262 } 222 263 } -
trunk/web-app/js/publication-chooser.pubmed.js
r496 r518 4 4 var terms = searchterm.split( " " ); 5 5 for( var i = 0; i < terms.length; i++ ) { 6 searchFor[ searchFor.length ] = "(" + terms[i].trim() + "[title]" + " OR " + terms[i].trim() + "[author]" + ")";6 searchFor[ searchFor.length ] = "(" + $.trim( terms[i] ) + "[title]" + " OR " + $.trim( terms[i] ) + "[author]" + ")"; 7 7 } 8 8 … … 38 38 }; 39 39 40 selectPubMed = function( chooserObject, inputElement, event, ui ) { 40 // Handler that handles the select of a publication 41 selectPubMedAdd = function( chooserObject, inputElement, event, ui ) { 41 42 42 43 // option selected, set hidden fields … … 52 53 element.removeClass('error'); 53 54 }; 54 closePubMed = function( chooserObject, inputElement, event, ui ) { 55 56 // Handler that handles the closing of the autocomplete 57 closePubMedAdd = function( chooserObject, inputElement, event, ui ) { 55 58 // no he didn't, clear the field(s) 56 59 var element = inputElement; … … 116 119 } 117 120 121 // Only the source method should be used for all pubmed autocompletes 122 // The select and close handlers that are defined here, should only be used 123 // on the add publication page. They can be overridden in the initialization 124 // of the publication chooser class 118 125 PublicationChooser.prototype.availableDBs[ "pubmed" ] = { 119 126 'source': sourcePubMed, 120 'select': selectPubMed ,121 'close': closePubMed 127 'select': selectPubMedAdd, 128 'close': closePubMedAdd 122 129 }; 130 -
trunk/web-app/js/wizard.js
r507 r518 351 351 return '<a target="_blank" href="' + baseUrl + '/file/get/' + filename + '">' + filename + '</a>'; 352 352 } 353 354 function addPublication( element_id ) { 355 /* Find publication ID and add to form */ 356 jQuery.ajax({ 357 type:"GET", 358 url: baseUrl + "/publication/getID?" + $("#" + element_id + "_form").serialize(), 359 success: function(data,textStatus){ 360 var id = parseInt( data ); 361 362 // Put the ID in the array, but only if it does not yet exist 363 var ids = getPublicationIds( element_id ); 364 365 if( $.inArray(id, ids ) == -1 ) { 366 ids[ ids.length ] = id; 367 $( '#' + element_id + '_ids' ).val( ids.join( ',' ) ); 368 369 // Show the title and a remove button 370 showPublication( element_id, id, $("#" + element_id + "_form").find( '[name=publication-title]' ).val(), $("#" + element_id + "_form").find( '[name=publication-authorsList]' ).val(), ids.length - 1 ); 371 372 // Hide the 'none box' 373 $( '#' + element_id + '_none' ).css( 'display', 'none' ); 374 } 375 }, 376 error:function(XMLHttpRequest,textStatus,errorThrown){ alert( "Publication could not be added." ) } 377 }); return false; 378 } 379 380 function removePublication( element_id, id ) { 381 var ids = getPublicationIds( element_id ); 382 if( $.inArray(id, ids ) != -1 ) { 383 // Remove the ID 384 ids.splice($.inArray(id, ids ), 1); 385 $( '#' + element_id + '_ids' ).val( ids.join( ',' ) ); 386 387 // Remove the title from the list 388 var li = $( "#" + element_id + '_item_' + id ); 389 if( li ) { 390 li.remove(); 391 } 392 393 // Show the 'none box' if needed 394 if( ids.length == 0 ) { 395 $( '#' + element_id + '_none' ).css( 'display', 'inline' ); 396 } 397 398 } 399 } 400 401 function getPublicationIds( element_id ) { 402 var ids = $( '#' + element_id + '_ids' ).val(); 403 if( ids == "" ) { 404 return new Array(); 405 } else { 406 ids_array = ids.split( ',' ); 407 for( var i = 0; i < ids_array.length; i++ ) { 408 ids_array[ i ] = parseInt( ids_array[ i ] ); 409 } 410 411 return ids_array; 412 } 413 } 414 415 function showPublication( element_id, id, title, authors, nr ) { 416 var deletebutton = document.createElement( 'img' ); 417 deletebutton.setAttribute( 'class', 'famfamfam delete_button' ); 418 deletebutton.setAttribute( 'alt', 'remove this publication' ); 419 deletebutton.setAttribute( 'src', baseUrl + '/images/icons/famfamfam/delete.png' ); 420 deletebutton.setAttribute( 'onClick', 'removePublication( "' + element_id + '", ' + id + ' ); return false;' ); 421 deletebutton.setAttribute( 'style', 'cursor: pointer;' ); 422 423 var titleDiv = document.createElement( 'div' ); 424 titleDiv.setAttribute( 'class', 'title' ); 425 titleDiv.appendChild( document.createTextNode( title ) ); 426 427 var authorsDiv = document.createElement( 'div' ); 428 authorsDiv.setAttribute( 'class', 'authors' ); 429 authorsDiv.appendChild( document.createTextNode( authors ) ); 430 431 var li = document.createElement( 'li' ); 432 li.setAttribute( 'id', element_id + '_item_' + id ); 433 li.setAttribute( 'class', nr % 2 == 0 ? 'even' : 'odd' ); 434 li.appendChild( deletebutton ); 435 li.appendChild( titleDiv ); 436 li.appendChild( authorsDiv ); 437 438 $( '#' + element_id + '_list' ).append( li ); 439 }
Note: See TracChangeset
for help on using the changeset viewer.