Changeset 1184
- Timestamp:
- Nov 22, 2010, 7:07:34 PM (12 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/web-app/js/ontology-chooser.js
r1156 r1184 24 24 * in your page! 25 25 * 26 * @author 27 * @since 28 * @package 29 * @requires 30 * @see 31 * @see 26 * @author Jeroen Wesbeek 27 * @since 20100312 28 * @package wizard 29 * @requires jquery, jquery-ui 30 * @see http://bioportal.bioontology.org/ontologies/ 31 * @see http://bioportal.bioontology.org/search/json_search/?q=musculus 32 32 * 33 33 * Revision information: … … 39 39 } 40 40 OntologyChooser.prototype = { 41 cache : [], // ontology cache 42 options : { 43 minLength : 3, // minimum input length before launching Ajax request 44 showHide : null, // show / hide this DOM element on select/deselect autocomplete results 45 spinner : '../images/spinner.gif' 46 }, 47 48 /** 49 * initialize object 50 */ 51 init: function(options) { 52 var that = this; 53 54 // set class parameters 55 if (options) { 56 $.each(options, function(key,value) { 57 that.options[key] = value; 58 }); 59 } 60 61 // hide showHide div? 62 if (this.options.showHide) { 63 this.options.showHide.hide(); 64 } 65 66 // find all ontology elements 67 $("input[rel*='ontology']").each(function() { 68 that.initAutocomplete(this); 69 }); 70 }, 71 72 /** 73 * initialize the ontology autocomplete 74 * @param element 75 */ 76 initAutocomplete: function(element) { 77 var that = this 78 var inputElement = $(element); 79 var selected = false; 80 81 // determine what ontology to use 82 var values = inputElement.attr('rel').split("-"); 83 var ontology_id = values[1]; 84 var target_property = values[2]; 85 if (ontology_id == "all") { ontology_id = ""; } 86 87 // handle keypresses 88 inputElement.bind('keypress', function(e) { 89 // ignore ENTER key in inputElement so the form cannot 90 // be submitted by pressing the ENTER key 91 if (e.keyCode == 13) return false; 92 93 // when a user uses the backspace the showHide element 94 // (normally the button) gets hidden 95 if (e.keyCode == 8 && that.options.showHide) that.options.showHide.hide(); 96 }); 97 98 // http://bioportal.bioontology.org/search/json_search/?q=musculus 99 inputElement.autocomplete({ 100 minLength: that.options.minLength, 101 delay: 300, 102 search: function(event, ui) { 103 if (that.options.spinner) { 104 inputElement.css({ 'background': 'url(' + that.options.spinner + ') no-repeat right top' }); 105 } 106 selected = false; 107 }, 108 source: function(request, response) { 109 var q = $.trim(request.term); 110 var url = "http://bioportal.bioontology.org/search/json_search/"+ontology_id+"?q=" + request.term + "&response=json&callback=?"; 111 112 // got cache? 113 if (that.cache[ q ]) { 114 // hide spinner 115 inputElement.css({ 'background': 'none' }); 116 117 // yeah, lucky us! ;-P 118 response(that.cache[ q ]); 119 } else { 120 // nope, fetch it from NCBO 121 $.getJSON(url, function(data) { 122 // parse result data 123 var result = that.parseData(data.data, ontology_id); 124 125 // cache results 126 that.cache[ q ] = result; 127 128 // hide spinner 129 inputElement.css({ 'background': 'none' }); 130 131 // hide button? 132 if (!data.data && that.options.showHide) { 133 that.options.showHide.hide(); 134 } 135 136 // response callback 137 response(result); 138 }); 139 } 140 }, 141 select: function(event, ui) { 142 // mark that the user selected a suggestion 143 selected = true; 144 145 // option selected, set hidden fields 146 var element = inputElement; 147 148 // set hidden fields 149 that.setInputValue(element, 'concept_id', ui.item.concept_id); 150 that.setInputValue(element, 'ontology_id', ui.item.ontology_id); 151 that.setInputValue(element, 'ncbo_id', ui.item.ncbo_id); 152 that.setInputValue(element, 'full_id', ui.item.full_id); 153 154 // remove error class (if present) 155 element.removeClass('error'); 156 157 // show showHide element if set 158 if (that.options.showHide) { 159 that.options.showHide.show(); 160 } 161 }, 162 close: function(event, ui) { 163 // check if the user picked something from the ontology suggestions 164 if (!selected) { 165 // no he didn't, clear the field(s) 166 var element = inputElement; 167 168 // set fields 169 inputElement.val(''); 170 that.setInputValue(element, 'concept_id', ''); 171 that.setInputValue(element, 'ontology_id', ''); 172 that.setInputValue(element, 'ncbo_id', ''); 173 that.setInputValue(element, 'full_id', ''); 174 175 // add error class 176 element.addClass('error'); 177 } 178 }, 179 html: true 180 }); 181 }, 182 183 /** 184 * Set the value of a particular DOM element 185 * @param inputElement 186 * @param name 187 * @param value 188 */ 189 setInputValue: function(inputElement, name, value) { 190 var elementName = inputElement.attr('name') + '-' + name; 191 var searchElement = inputElement.parent().find("input[name='" + elementName + "']"); 192 193 // got a text/hidden field in the DOM? 194 if (searchElement.size() > 0) { 195 // yeah, set it 196 $(searchElement[0]).val(value); 197 } else { 198 // no, dynamically insert it after the input element 199 inputElement.after('<input type="hidden" name="' + elementName + '" value="' + value + '"/>'); 200 } 201 }, 202 203 /** 204 * Parse the result data 205 * 206 * Data is in the following format: 207 * Mus musculus musculus|birnlex_161|preferred name|29684|http://bioontology.org/projects/ontologies/birnlex#birnlex_161|Mus musculus musculus|Mus musculus musculus|BIRNLex~!~ 208 * 209 * Where | codes for a column break, and ~!~ for 210 * a line break 211 * 212 * @param data 213 * @return array 214 */ 215 parseData: function(data, ontology_ids) { 216 var parsed = []; 217 var rows = data.split('~!~'); 218 219 for (var i=0; i<rows.length; i++) { 220 var row = $.trim(rows[i]); 221 if (row) { 222 var cols = row.split('|'); 41 cache : [], // ontology cache 42 ctrl : false, // work variable to search for copy/paste events 43 noSearch : false, // work variable to disable/enable autocomplete search 44 clipboard : [], // a clipboard to contain copied ontologies 45 options : { 46 minLength : 3, // minimum input length before launching Ajax request 47 showHide : null, // show / hide this DOM element on select/deselect autocomplete results 48 spinner : '../images/spinner.gif' 49 }, 50 51 /** 52 * initialize object 53 */ 54 init: function(options) { 55 var that = this; 56 57 // set class parameters 58 if (options) { 59 $.each(options, function(key, value) { 60 that.options[key] = value; 61 }); 62 } 63 64 // hide showHide div? 65 if (this.options.showHide) { 66 this.options.showHide.hide(); 67 } 68 69 // find all ontology elements 70 $("input[rel*='ontology']").each(function() { 71 that.initAutocomplete(this); 72 }); 73 }, 74 75 /** 76 * initialize the ontology autocomplete 77 * @param element 78 */ 79 initAutocomplete: function(element) { 80 var that = this 81 var inputElement = $(element); 82 var selected = false; 83 84 // determine what ontology to use 85 var values = inputElement.attr('rel').split("-"); 86 var ontology_id = values[1]; 87 var target_property = values[2]; 88 if (ontology_id == "all") { 89 ontology_id = ""; 90 } 91 92 // handle ctrl or apple keys (to find ctrl-escape / ctrl-paste) 93 inputElement.bind('keydown', function(e) { 94 // check if ctrl-key or apple cmd key is pressed 95 // to start capturing copy events 96 if (e.keyCode == 17 || e.keyCode == 224) that.ctrl = true; 97 98 // ignore ENTER key in inputElement so the form cannot 99 // be submitted by pressing the ENTER key 100 if (e.keyCode == 13) return false; 101 102 // when a user uses the backspace the showHide element 103 // (normally the button) gets hidden 104 if (e.keyCode == 8 && that.options.showHide) that.options.showHide.hide(); 105 106 // check for 'copy' event 107 if (e.keyCode == 67 && that.ctrl) return that.copy(inputElement); 108 109 // check for 'paste' event 110 if (e.keyCode == 86 && that.ctrl) return that.paste(inputElement); 111 }); 112 113 // check if ctrl-key is released 114 inputElement.bind('keyup', function(e) { 115 // check if ctrl-key or apple cmd key is released 116 // to start capturing paste events 117 if (e.keyCode == 17 || e.keyCode == 224) that.ctrl = false; 118 }); 119 120 // http://bioportal.bioontology.org/search/json_search/?q=musculus 121 inputElement.autocomplete({ 122 minLength: that.options.minLength, 123 delay: 300, 124 search: function(event, ui) { 125 // check if we need to skip searching, generally 126 // after a paste event 127 if (that.noSearch) { 128 // yeah, skip search and reset value 129 that.noSearch = false; 130 return false; 131 } 132 133 // set the spinner 134 if (that.options.spinner) { 135 inputElement.css({ 'background': 'url(' + that.options.spinner + ') no-repeat right top' }); 136 } 137 selected = false; 138 }, 139 source: function(request, response) { 140 var q = $.trim(request.term); 141 var url = "http://bioportal.bioontology.org/search/json_search/" + ontology_id + "?q=" + request.term + "&response=json&callback=?"; 142 143 // got cache? 144 if (that.cache[ q ]) { 145 // hide spinner 146 inputElement.css({ 'background': 'none' }); 147 148 // yeah, lucky us! ;-P 149 response(that.cache[ q ]); 150 } else { 151 // nope, fetch it from NCBO 152 $.getJSON(url, function(data) { 153 // parse result data 154 var result = that.parseData(data.data, ontology_id); 155 156 // cache results 157 that.cache[ q ] = result; 158 159 // hide spinner 160 inputElement.css({ 'background': 'none' }); 161 162 // no results? 163 if (!data.data) { 164 // hide showHide element? 165 if (that.options.showHide) that.options.showHide.hide(); 166 167 // clear hidden fields 168 that.setInputValue(inputElement, 'concept_id', null); 169 that.setInputValue(inputElement, 'ontology_id', null); 170 that.setInputValue(inputElement, 'ncbo_id', null); 171 that.setInputValue(inputElement, 'full_id', null); 172 } 173 174 // response callback 175 response(result); 176 }); 177 } 178 }, 179 select: function(event, ui) { 180 // mark that the user selected a suggestion 181 selected = true; 182 183 // option selected, set hidden fields 184 var element = inputElement; 185 186 // set hidden fields 187 that.setInputValue(element, 'concept_id', ui.item.concept_id); 188 that.setInputValue(element, 'ontology_id', ui.item.ontology_id); 189 that.setInputValue(element, 'ncbo_id', ui.item.ncbo_id); 190 that.setInputValue(element, 'full_id', ui.item.full_id); 191 192 // remove error class (if present) 193 element.removeClass('error'); 194 195 // show showHide element if set 196 if (that.options.showHide) { 197 that.options.showHide.show(); 198 } 199 }, 200 close: function(event, ui) { 201 // check if the user picked something from the ontology suggestions 202 if (!selected) { 203 // no he didn't, clear the field(s) 204 var element = inputElement; 205 206 // set fields 207 inputElement.val(''); 208 that.setInputValue(element, 'concept_id', ''); 209 that.setInputValue(element, 'ontology_id', ''); 210 that.setInputValue(element, 'ncbo_id', ''); 211 that.setInputValue(element, 'full_id', ''); 212 213 // add error class 214 element.addClass('error'); 215 } 216 }, 217 html: true 218 }); 219 }, 220 221 /** 222 * Set the value of a particular DOM element 223 * @param inputElement 224 * @param name 225 * @param value 226 */ 227 setInputValue: function(inputElement, name, value) { 228 var elementName = inputElement.attr('name') + '-' + name; 229 var searchElement = inputElement.parent().find("input[name='" + elementName + "']"); 230 231 // got a text/hidden field in the DOM? 232 if (searchElement.size() > 0) { 233 // yeah, set it 234 $(searchElement[0]).val(value); 235 } else { 236 // no, dynamically insert it after the input element 237 inputElement.after('<input type="hidden" name="' + elementName + '" value="' + value + '"/>'); 238 } 239 }, 240 241 /** 242 * Get the value of a particular DOM element 243 * @param inputElement 244 * @param name 245 */ 246 getInputValue: function(inputElement, name) { 247 var elementName = inputElement.attr('name') + '-' + name; 248 var searchElement = inputElement.parent().find("input[name='" + elementName + "']"); 249 250 // got a text/hidden field in the DOM? 251 return (searchElement.size() > 0) ? $(searchElement[0]).val() : ''; 252 }, 253 254 /** 255 * Parse the result data 256 * 257 * Data is in the following format: 258 * Mus musculus musculus|birnlex_161|preferred name|29684|http://bioontology.org/projects/ontologies/birnlex#birnlex_161|Mus musculus musculus|Mus musculus musculus|BIRNLex~!~ 259 * 260 * Where | codes for a column break, and ~!~ for 261 * a line break 262 * 263 * @param data 264 * @return array 265 */ 266 parseData: function(data, ontology_ids) { 267 var parsed = []; 268 var rows = data.split('~!~'); 269 270 for (var i = 0; i < rows.length; i++) { 271 var row = $.trim(rows[i]); 272 if (row) { 273 var cols = row.split('|'); 223 274 224 275 // If we search in a single ontology, the json doesn't return the 225 276 // NCBO id in the 8th column (probably because we already know the NCBO id) 226 277 var ncbo_id; 227 if ( cols.length > 8) {278 if (cols.length > 8) { 228 279 ncbo_id = cols[8]; 229 280 } else { … … 231 282 } 232 283 233 parsed[ parsed.length ] = { 234 value : cols[0], 235 label : cols[0] + ' <span class="about">(' + cols[2] + ')</span> <span class="from">from: ' + cols[ (cols.length-2) ] + '</span>', 236 preferred_name : cols[0], // e.g. Mus musculus musculus 237 concept_id : cols[1], // e.g. birnlex_161 238 ontology_id : cols[3], // e.g. 29684 239 full_id : cols[4], // e.g. http://bioontology.org/projects/ontologies/birnlex#birnlex_161 240 ncbo_id : ncbo_id // e.g. 1494 241 } 242 } 243 } 244 245 return parsed; 246 } 284 parsed[ parsed.length ] = { 285 value : cols[0], 286 label : cols[0] + ' <span class="about">(' + cols[2] + ')</span> <span class="from">from: ' + cols[ (cols.length - 2) ] + '</span>', 287 preferred_name : cols[0], // e.g. Mus musculus musculus 288 concept_id : cols[1], // e.g. birnlex_161 289 ontology_id : cols[3], // e.g. 29684 290 full_id : cols[4], // e.g. http://bioontology.org/projects/ontologies/birnlex#birnlex_161 291 ncbo_id : ncbo_id // e.g. 1494 292 } 293 } 294 } 295 296 return parsed; 297 }, 298 299 /** 300 * an ontology field is being copied, store all copied data 301 * in the clipboard 302 * @param inputElement source input element 303 */ 304 copy: function(inputElement) { 305 this.clipboard = { 306 sourceValue : $(inputElement).val(), 307 concept_id : this.getInputValue(inputElement, 'concept_id'), 308 ontology_id : this.getInputValue(inputElement, 'ontology_id'), 309 ncbo_id : this.getInputValue(inputElement, 'ncbo_id'), 310 full_id : this.getInputValue(inputElement, 'full_id') 311 } 312 return false; 313 }, 314 315 /** 316 * paste an copied ontology (if present) 317 * @param inputElement target input element 318 */ 319 paste: function(inputElement) { 320 // can we paste an ontology? 321 if (this.clipboard.sourceValue && 322 this.clipboard.concept_id && 323 this.clipboard.ncbo_id && 324 this.clipboard.full_id) { 325 326 // check if this target ontology field can accept this copied ontology 327 var pattern = new RegExp(this.clipboard.ncbo_id); 328 if (inputElement.attr('rel').match(pattern) || inputElement.attr('rel').match(/all/)) { 329 // yes, disable search 330 this.noSearch = true; 331 332 // paste values 333 $(inputElement).val(this.clipboard.sourceValue); 334 this.setInputValue(inputElement, 'concept_id', this.clipboard.concept_id); 335 this.setInputValue(inputElement, 'ontology_id', this.clipboard.ontology_id); 336 this.setInputValue(inputElement, 'ncbo_id', this.clipboard.ncbo_id); 337 this.setInputValue(inputElement, 'full_id', this.clipboard.full_id); 338 } 339 } 340 return false; 341 } 247 342 }
Note: See TracChangeset
for help on using the changeset viewer.