Merge branch 'topic/stock_detail_page'
[sgn.git] / cgi-bin / chado / Ontology.pl
blobfe117e74eedffca3f018578e5017d7ef6c5a4dd2
1 #!/usr/bin/perl
3 use strict;
4 use warnings;
6 use CXGN::Chado::Cvterm;
7 use CXGN::Page;
9 my $page = CXGN::Page->new('SGN Ontology Browser', 'Jessica Reuter');
10 $page->header( "SGN Ontology Browser", "SGN Ontology Browser" );
12 load_ontology();
14 $page->footer();
16 ###############################################################################
17 ############################## SUBROUTINE ###################################
18 ####################### Perl Wrapper of JavaScript ############################
19 ###############################################################################
21 sub load_ontology {
22 print "Please scan through the available SGN ontologies to find terms.<br/>";
23 print "To search for a specific term, please enter the qualified name (database and accession) below.";
24 print " When finished, click \"Get Term\".<br/><br/>";
26 print "<i>There may be short delays while tree nodes are being processed or searches are being conducted.";
27 print " Please wait (do not click nodes multiple times), and the requested content will load momentarily.";
28 print "</i><br/><br/><br/>";
30 print <<EOJS;
31 <form name="ontologies" onSubmit='return false;'>
32 Enter term here: <input type='text' id='termSelect'>
33 <input type='button' onclick='specific( "termSelect" )' value='Get Term'/>
34 <div id='notice'></div><br/>
36 <input type='button' onclick='roots( "GO", this );node( this )' value='+' id='go' style="font-family:mono"/>
37 GO (Gene Ontology)<div id='GO'></div><br/>
39 <input type='button' onclick='roots( "PO", this );node( this )' value='+' id='po' style="font-family:mono"/>
40 PO (Plant Ontology)<div id='PO'></div><br/>
42 <input type='button' onclick='roots( "SO", this );node( this )' value='+' id='so' style="font-family:mono"/>
43 SO (Sequence Ontology)<div id='SO'></div><br/>
45 <input type='button' onclick='roots( "SP", this );node( this )' value='+' id='sp' style="font-family:mono"/>
46 SP (Solanaceae Phenotype Ontology)<div id='SP'></div><br/>
48 <input type='button' onclick='roots( "PATO", this );node( this )' value='+' id='pato' style="font-family:mono"/>
49 PATO (Phenotype and Trait Ontology)<div id='PATO'></div><br/>
51 </form>
53 <script language="javascript" type="text/javascript">
54 // Show the roots of a particular ontology
55 function roots( rootType, button ) {
56 var rootRequest;
58 try {
59 rootRequest = new XMLHttpRequest();
60 } catch (e) {
61 try {
62 rootRequest = new ActiveXObject("Msxml2.XMLHTTP");
63 } catch (e) {
64 try {
65 rootRequest = new ActiveXObject("Microsoft.XMLHTTP");
66 } catch (e) {
67 alert("The ontology browser could not run!");
68 return false;
73 rootRequest.onreadystatechange = function() {
74 if(rootRequest.readyState == 4) {
75 var display = document.getElementById( rootType );
76 if( button.value == "\\u2014" ) {
77 var text = String(rootRequest.responseText);
78 text = addHTML( text, "root" );
79 text = makeIndent( text, "root" );
80 display.innerHTML = text;
81 } else {
82 display.innerHTML = "";
87 var queryString = "?cv_accession=GO:0000001&action=" +
88 escape( rootType ) + "&indent=0";
89 // Technically when finding roots, the ID is not important, but a
90 // valid GO ID is included in the query string so argument encoding
91 // works. (the term just happens to be mitochondrion inheritance)
93 rootRequest.open("GET",
94 "/chado/ontology_browser_ajax.pl" + queryString,
95 true);
96 rootRequest.send(null);
99 // Show the children of a term
100 function children( accession, button, indent, theDiv ) {
101 var childRequest;
103 try {
104 childRequest = new XMLHttpRequest();
105 } catch (e) {
106 try {
107 childRequest = new ActiveXObject("Msxml2.XMLHTTP");
108 } catch (e) {
109 try {
110 childRequest = new ActiveXObject("Microsoft.XMLHTTP");
111 } catch (e) {
112 alert("The ontology browser could not run!");
113 return false;
118 childRequest.onreadystatechange = function() {
119 if(childRequest.readyState == 4) {
120 var display = document.getElementById( theDiv );
121 if( button.value == "\\u2014" ) {
122 var text = String(childRequest.responseText);
123 text = addHTML( text, "children" );
124 text = makeIndent( text, "children" );
125 display.innerHTML = text;
126 } else {
127 display.innerHTML = "";
131 var queryString = "?cv_accession=" + accession + "&action=children" + "&indent=" + indent;
133 childRequest.open("GET",
134 "/chado/ontology_browser_ajax.pl" + queryString,
135 true);
136 childRequest.send(null);
139 // Show trace for specific terms
140 function specific( accessor ) {
141 var term = document.getElementById( accessor ).value;
142 var database = term.substring( 0, 2 );
143 var specificRequest;
145 try {
146 specificRequest = new XMLHttpRequest();
147 } catch (e) {
148 try {
149 specificRequest = new ActiveXObject("Msxml2.XMLHTTP");
150 } catch (e) {
151 try {
152 specificRequest = new ActiveXObject("Microsoft.XMLHTTP");
153 } catch (e) {
154 alert("The ontology browser could not run!");
155 return false;
160 specificRequest.onreadystatechange = function() {
161 if(specificRequest.readyState == 4) {
162 var text = specificRequest.responseText;
164 // If the term exists in the database, show its path
165 if( text.indexOf( "</term>" ) != -1 ) {
166 var display = document.getElementById( String(database).toUpperCase() );
167 text = text.replace( /\"/g, "'" );
168 text = addHTML( text, "specific" );
169 text = makeIndent( text, "specific" );
170 display.innerHTML = text;
173 // If an error occurs, the term is obsolete, or it does not exist, notify the user
174 else {
175 text = text.replace( /\\n/g, "" );
176 if( text.indexOf( "obsolete" ) == -1 ) {
177 if( text.indexOf( "<scrap></scrap>" ) != -1 ) {
178 alert( "This term does not exist in the SGN ontologies." );
179 } else {
180 alert( "The ontology browser has encountered an unexpected error.\\n" +
181 "Please try your query again." );
182 document.getElementById('notice').innerHTML=text;
186 else {
187 alert( "The term you searched for is obsolete.\\n" +
188 "Please browse the ontology to find a suitable replacement." );
194 var queryString = "?cv_accession=" + term + "&action=specific&indent=0";
196 specificRequest.open("GET",
197 "/chado/ontology_browser_ajax.pl" + queryString,
198 true);
199 specificRequest.send(null);
202 // Handle expansion and collapse state of buttons while scanning
203 function node( button ) {
204 var value = button.value;
205 if( value == "+" ) {
206 button.value = "\\u2014";
207 } else {
208 button.value = "+";
212 // Add HTML code to the text
213 function addHTML( text, htmlType ) {
214 var htmlText = "";
216 // If finding a specific path for an empty div or divs
217 if( htmlType == "specific" ) {
218 var pattern = /<term.*/g;
219 var resultArray;
220 var result;
221 var resultHTML;
222 var preliminaryHTML = text;
224 // Add buttons and initial div tags to the text
225 while((resultArray = pattern.exec(text)) != null ) {
226 // For each term, go through its attributes and extract them for use
227 result = resultArray[0];
229 // Get the number of children of the term
230 var childPattern = /children='.*' d/;
231 var childResultArray = childPattern.exec(result);
232 var childResult = childResultArray[0];
233 var child = childResult.substring( childResult.indexOf("'") + 1, childResult.lastIndexOf("'") );
235 // Get the div id related to the term
236 var divPattern = /divID='.*' id/;
237 var divResultArray = divPattern.exec(result);
238 var divResult = divResultArray[0];
239 var div = divResult.substring( divResult.indexOf("'") + 1, divResult.lastIndexOf("'") );
241 // Get the id of the term
242 var idPattern = /id='.*' in/;
243 var idResultArray = idPattern.exec(result);
244 var idResult = idResultArray[0];
245 var id = idResult.substring( idResult.indexOf("'") + 1, idResult.lastIndexOf("'") );
247 // Get the indent level of the term
248 var indentPattern = /indent='.*'/;
249 var indentResultArray = indentPattern.exec(result);
250 var indentResult = indentResultArray[0];
251 var indent = indentResult.substring( indentResult.indexOf("'") + 1, indentResult.lastIndexOf("'") );
253 // Select proper button for the term
254 var properButton;
255 if( child != 0 ) {
256 var variables = "'children( " + '"' + id + '"' + ", this, " + indent + ", " +
257 '"' + div + '"' + " );node( this )'";
258 properButton = "<input type='button' " +
259 "onclick=" + variables + "value='+' style=\'font-family:mono\' /> ";
260 } else {
261 properButton = "<input type='button' value='*' " +
262 "style='font-family:mono' disabled='disabled' /> ";
265 // Add beginning of div to the term
266 var divStart = "<div id='" + div + "'>";
268 // Construct and add the result to the new HTML text
269 var originalText = preliminaryHTML.substring( preliminaryHTML.indexOf( "<specific>" ),
270 preliminaryHTML.indexOf( "</specific>" ) + 11 );
271 resultHTML = preliminaryHTML.replace( result, properButton + result + "<br/>" + divStart );
272 preliminaryHTML = resultHTML;
274 htmlText = preliminaryHTML;
276 // Add end tags that make divs nested
277 var tagPattern = /<term.*term><br.*\'>/g;
278 var tagResultArray;
279 var tagResult;
281 while( (tagResultArray = tagPattern.exec(preliminaryHTML)) != null ) {
282 var unchangedTag = tagResultArray[0];
283 tagResult = tagResultArray[0];
285 var internalPattern = /<div id.*>/;
286 var internalResultArray = internalPattern.exec(tagResult);
287 var internalResult = internalResultArray[0];
288 var divNumber = parseInt( internalResult.substring( internalResult.indexOf( "'" ) + 1,
289 internalResult.indexOf( "-" ) ) );
291 if( divNumber > 1 ) {
292 for( var i = 1; i < divNumber; i++ ) {
293 tagResult = tagResult + "</div>";
294 if( i == divNumber - 1 ) {
295 tagResult = tagResult + "<div/>";
298 } else {
299 tagResult = tagResult + "</div><div/>";
302 htmlText = htmlText.replace( unchangedTag, tagResult );
305 var divEnd = htmlText.lastIndexOf( "</div>" ) + 6;
306 var divBegin = htmlText.lastIndexOf( "'><" ) + 2;
307 var lastDivString = htmlText.substring( divBegin, divEnd );
309 if( divNumber != 1 ) {
310 htmlText = htmlText.replace( lastDivString, "</div>" + lastDivString );
314 // If browsing with no specific path, HTML is formatted for a flat list in an empty div
315 else {
316 var pattern = /<term.*term>/g;
317 var resultArray;
318 var result;
319 var resultHTML;
321 while((resultArray = pattern.exec(text)) != null ) {
322 // For each term, go through its attributes and extract them for use
323 result = resultArray[0];
325 // Get the number of children of the term
326 var childPattern = /children='.*' d/;
327 var childResultArray = childPattern.exec(result);
328 var childResult = childResultArray[0];
329 var child = childResult.substring( childResult.indexOf("'") + 1, childResult.lastIndexOf("'") );
331 // Get the div id related to the term
332 var divPattern = /divID='.*' id/;
333 var divResultArray = divPattern.exec(result);
334 var divResult = divResultArray[0];
335 var div = divResult.substring( divResult.indexOf("'") + 1, divResult.lastIndexOf("'") );
337 // Get the id of the term
338 var idPattern = /id='.*' in/;
339 var idResultArray = idPattern.exec(result);
340 var idResult = idResultArray[0];
341 var id = idResult.substring( idResult.indexOf("'") + 1, idResult.lastIndexOf("'") );
343 // Get the indent level of the term
344 var indentPattern = /indent='.*'/;
345 var indentResultArray = indentPattern.exec(result);
346 var indentResult = indentResultArray[0];
347 var indent = indentResult.substring( indentResult.indexOf("'") + 1, indentResult.lastIndexOf("'") );
349 // Select proper button for the term
350 var properButton;
351 if( child != 0 ) {
352 var variables = "'children( " + '"' + id + '"' + ", this, " + indent + ", " +
353 '"' + div + '"' + " );node( this )'";
354 properButton = "<input type='button' " +
355 "onclick=" + variables + " value='+' style=\'font-family:mono\' /> ";
356 } else {
357 properButton = "<input type='button' value='*'" +
358 " style='font-family:mono' disabled='disabled' /> ";
361 // Construct div
362 var constructedDiv = "<div id='" + div + "'></div>";
364 // Construct and append the result to the new HTML text
365 resultHTML = properButton + result + "<br/>" + constructedDiv;
366 htmlText = htmlText + resultHTML;
369 return htmlText;
372 // Handle indentation
373 function makeIndent( text, queryType ) {
374 var indentPlace = indentPlace = text.indexOf( "indent" ) + 8;
375 var buttonIndex = text.indexOf( "<input" );
376 var textLength = text.length;
378 // If searching for a specific path, indents are dynamic, dependent on each particular term
379 if( queryType == "specific" ) {
380 while( indentPlace < textLength ) {
381 var indent = text.substring( indentPlace, text.indexOf( "\'", indentPlace ) );
383 var beforeButton = text.substring( 0, buttonIndex );
384 var afterButton = text.substring( buttonIndex );
386 var indentString = "";
387 for( var counter = 1; counter <= indent; counter++ ) {
388 indentString = indentString + "----";
390 indentString = "<tab style='font-family:mono; color:white'>" + indentString + "</tab>";
392 indent = parseInt( indent );
394 text = beforeButton + indentString + afterButton;
395 buttonIndex = text.indexOf( "<input", buttonIndex + indentString.length + 1 );
396 indentPlace = text.indexOf( "indent='", buttonIndex ) + 8;
397 if( buttonIndex == -1 ) {
398 break;
401 textLength = text.length;
403 return text;
406 // If browsing with no specific path, indent is static in a flat list
407 else {
408 var indent = text.substring( indentPlace, text.indexOf( "\'", indentPlace ) );
410 var indentString = "";
411 for( var counter = 1; counter <= indent; counter++ ) {
412 indentString = indentString + "----";
414 indentString = "<tab style='font-family:mono; color:white'>" + indentString + "</tab>";
415 indentString = indentString + "<input";
417 return text.replace( /\<input/g, indentString );
420 </script>
421 EOJS