source: trunk/web-app/js/ontology-chooser.js @ 597

Last change on this file since 597 was 597, checked in by duh, 9 years ago
  • improved ontology chooser

-- the button (showHide element) did not hide when a search did not yield results
-- the ontology chooser ignores shortcut form submits by ignoring the ENTER key

  • Property svn:keywords set to Date Author Rev
File size: 7.7 KB
Line 
1/**
2 * Ontology chooser JavaScript class
3 *
4 * NCBO wrote it's own cross-site form completion utility
5 * utilizing it's json webservice. However, the service is
6 * no proper json service as it does not return proper json
7 * objects (just a self designed string using | for value
8 * breaks and ~!~ for line breaks. Also, their implementation
9 * conflicts with the table editor. Therefore, I wrote this
10 * cleaner implementation using jquery-ui's autocomplete
11 * functionality.
12 *
13 * Usage:
14 * ------
15 * <input type="text" name="..." rel="ontology-all-name" />
16 *
17 * Where the 'rel' value is the similar as the 'class' value in
18 * the NCBO documentation (bp_form_complete-all-name) but here
19 * we use 'ontology' instead of 'bp_form_complete' to
20 * identify ontology fields.
21 *
22 * @author      Jeroen Wesbeek
23 * @since       20100312
24 * @package     wizard
25 * @requires    jquery, jquery-ui
26 * @see         http://bioportal.bioontology.org/ontologies/
27 * @see         http://bioportal.bioontology.org/search/json_search/?q=musculus
28 *
29 * Revision information:
30 * $Rev: 597 $
31 * $Author: duh $
32 * $Date: 2010-06-21 09:20:04 +0000 (ma, 21 jun 2010) $
33 */
34function OntologyChooser() {
35}
36OntologyChooser.prototype = {
37    cache   : [],           // ontology cache
38    options : {
39        minLength   : 3,    // minimum input length before launching Ajax request
40        showHide    : null, // show / hide this DOM element on select/deselect autocomplete results
41        spinner     : '../images/spinner.gif'
42    },
43
44    /**
45     * initialize object
46     */
47    init: function(options) {
48        var that = this;
49
50        // set class parameters
51        if (options) {
52            $.each(options, function(key,value) {
53                that.options[key] = value;
54            });
55        }
56
57        // hide showHide div?
58        if (this.options.showHide) {
59            this.options.showHide.hide();
60        }
61
62        // find all ontology elements
63        $("input[rel*='ontology']").each(function() {
64            that.initAutocomplete(this);
65        });
66    },
67
68    /**
69     * initialize the ontology autocomplete
70     * @param element
71     */
72    initAutocomplete: function(element) {
73        var that = this
74        var inputElement = $(element);
75        var selected = false;
76
77        // determine what ontology to use
78        var values = inputElement.attr('rel').split("-");
79        var ontology_id = values[1];
80        var target_property = values[2];
81        if (ontology_id == "all") { ontology_id = ""; }
82
83        // ignore ENTER key in inputElement so the form cannot
84        // be submitted by pressing the ENTER key
85        inputElement.bind('keypress', function(e) {
86            if (e.keyCode == 13) return false;
87        });
88
89        // http://bioportal.bioontology.org/search/json_search/?q=musculus
90        inputElement.autocomplete({
91            minLength: that.options.minLength,
92            delay: 300,
93            search: function(event, ui) {
94                if (that.options.spinner) {
95                    inputElement.css({ 'background': 'url(' + that.options.spinner + ') no-repeat right top' });
96                }
97                selected = false;
98            },
99            source: function(request, response) {
100                var q = $.trim(request.term);
101                var url = "http://bioportal.bioontology.org/search/json_search/"+ontology_id+"?q=" + request.term + "&response=json&callback=?";
102
103                // got cache?
104                if (that.cache[ q ]) {
105                    // hide spinner
106                    inputElement.css({ 'background': 'none' });
107
108                    // yeah, lucky us! ;-P
109                    response(that.cache[ q ]);
110                } else {
111                    // nope, fetch it from NCBO
112                    $.getJSON(url, function(data) {
113                        // parse result data
114                        var result = that.parseData(data.data);
115
116                        // cache results
117                        that.cache[ q ] = result;
118
119                        // hide spinner
120                        inputElement.css({ 'background': 'none' });
121
122                        // hide button?
123                        if (!data.data && that.options.showHide) {
124                            that.options.showHide.hide();   
125                        }
126
127                        // response callback
128                        response(that.parseData(data.data));
129                    });
130                }
131            },
132            select: function(event, ui) {
133                // mark that the user selected a suggestion
134                selected = true;
135
136                // option selected, set hidden fields
137                var element = inputElement;
138
139                // set hidden fields
140                that.setInputValue(element, 'concept_id', ui.item.concept_id);
141                that.setInputValue(element, 'ontology_id', ui.item.ontology_id);
142                that.setInputValue(element, 'full_id', ui.item.full_id);
143
144                // remove error class (if present)
145                element.removeClass('error');
146
147                // show showHide element if set
148                if (that.options.showHide) {
149                    that.options.showHide.show();
150                }
151            },
152            close: function(event, ui) {
153                // check if the user picked something from the ontology suggestions
154                if (!selected) {
155                    // no he didn't, clear the field(s)
156                    var element = inputElement;
157
158                    // set fields
159                    inputElement.val('');
160                    that.setInputValue(element, 'concept_id', '');
161                    that.setInputValue(element, 'ontology_id', '');
162                    that.setInputValue(element, 'full_id', '');
163
164                    // add error class
165                    element.addClass('error');
166                }
167            }
168
169        });
170    },
171
172    /**
173     * Set the value of a particular DOM element
174     * @param inputElement
175     * @param name
176     * @param value
177     */
178    setInputValue: function(inputElement, name, value) {
179        var elementName = inputElement.attr('name') + '-' + name;
180        var searchElement = inputElement.parent().find("input[name='" + elementName + "']");
181
182        // got a text/hidden field in the DOM?
183        if (searchElement.size() > 0) {
184            // yeah, set it
185            $(searchElement[0]).val(value);
186        } else {
187            // no, dynamically insert it after the input element
188            inputElement.after('<input type="hidden" name="' + elementName + '" value="' + value + '"/>');
189        }
190    },
191
192    /**
193     * Parse the result data
194     *
195     * Data is in the following format:
196     * Mus musculus musculus|birnlex_161|preferred name|29684|http://bioontology.org/projects/ontologies/birnlex#birnlex_161|Mus musculus musculus|Mus musculus musculus|BIRNLex~!~
197     *
198     * Where | codes for a column break, and ~!~ for
199     * a line break
200     *
201     * @param data
202     * @return array
203     */
204    parseData: function(data) {
205        var parsed = [];
206        var rows = data.split('~!~');
207
208        for (var i=0; i<rows.length; i++) {
209            var row = $.trim(rows[i]);
210            if (row) {
211                var cols = row.split('|');
212
213                parsed[ parsed.length ] = {
214                    value           : cols[0],
215                    label           : cols[0] + ' <span class="about">(' + cols[2] + ')</span> <span class="from">from: ' + cols[ (cols.length-1) ] + '</span>',
216                    preferred_name  : cols[0],  // e.g. Mus musculus musculus
217                    concept_id      : cols[1],  // e.g. birnlex_161
218                    ontology_id     : cols[3],  // e.g. 29684
219                    full_id         : cols[4]   // e.g. http://bioontology.org/projects/ontologies/birnlex#birnlex_161
220                }
221            }
222        }
223
224        return parsed;
225    }
226}
Note: See TracBrowser for help on using the repository browser.