Changeset 1184

Show
Ignore:
Timestamp:
22-11-10 19:07:34 (3 years ago)
Author:
work@…
Message:

- extended the ontology chooser with copy / paste support. When you have selected a term from an ontology you can now copy it, and paste it in other ontology fields that accept the same ontology (ncboId) or all ontologies. Partly fixes issue #178

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • trunk/web-app/js/ontology-chooser.js

    r1156 r1184  
    2424 * in your page! 
    2525 * 
    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 
     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 
    3232 * 
    3333 * Revision information: 
     
    3939} 
    4040OntologyChooser.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('|'); 
    223274 
    224275                                // If we search in a single ontology, the json doesn't return the 
    225276                                // NCBO id in the 8th column (probably because we already know the NCBO id) 
    226277                                var ncbo_id; 
    227                                 if( cols.length > 8 ) { 
     278                                if (cols.length > 8) { 
    228279                                        ncbo_id = cols[8]; 
    229280                                } else { 
     
    231282                                } 
    232283 
    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        } 
    247342}