Changeset 1184


Ignore:
Timestamp:
Nov 22, 2010, 7:07:34 PM (12 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
File:
1 edited

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}
Note: See TracChangeset for help on using the changeset viewer.