[Bio] / FigKernelPackages / ButtonArray.pm Repository:
ViewVC logotype

Annotation of /FigKernelPackages/ButtonArray.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1 - (view) (download) (as text)

1 : golsen 1.1 # -*- perl -*-
2 :     ########################################################################
3 :     # Copyright (c) 2003-2008 University of Chicago and Fellowship
4 :     # for Interpretations of Genomes. All Rights Reserved.
5 :     #
6 :     # This file is part of the SEED Toolkit.
7 :     #
8 :     # The SEED Toolkit is free software. You can redistribute
9 :     # it and/or modify it under the terms of the SEED Toolkit
10 :     # Public License.
11 :     #
12 :     # You should have received a copy of the SEED Toolkit Public License
13 :     # along with this program; if not write to the University of Chicago
14 :     # at info@ci.uchicago.edu or the Fellowship for Interpretation of
15 :     # Genomes at veronika@thefig.info or download a copy from
16 :     # http://www.theseed.org/LICENSE.TXT.
17 :     ########################################################################
18 :    
19 :     package ButtonArray;
20 :    
21 :     use strict;
22 :    
23 :     #-------------------------------------------------------------------------------
24 :     # Item ordering tool -- GJO:
25 :     #
26 :     # $html = buttonArrayScript();
27 :     #
28 :     # $html = buttonArrayForm( \%formData, \%hiddenData, \%submitData,
29 :     # \@paramNames, \@colHeads, \@itemNames, \@itemIDs
30 :     # );
31 :     #
32 :     # The first function returns an HTML JavaScript to support an array of
33 :     # buttons for selecting the order in which items will be displayed, analyzed,
34 :     # or whatever.
35 :     #
36 :     # The second function returns an HTML FORM with a TABLE of radio buttons
37 :     # for supporting user ordering of items. Only one copy of the script is
38 :     # required to support any number of button arrays (their state data are
39 :     # in the FORM object, not global JavaScript variables).
40 :     #
41 :     # The parameters configure the display and the submitted data.
42 :     #
43 :     # my $formData = { Method => 'post', # or 'get'
44 :     # Action => 'process_it.cgi', # target script
45 :     # EncType => 'multipart/form-data' # control packaging?
46 :     # };
47 :     #
48 :     # my $hiddenData = { info1 => 'My important info', # Whatever needs to send
49 :     # info2 => 'Other data',
50 :     # info3 => [ qw( multiple values for parameter ) ]
51 :     # };
52 :     #
53 :     # my $submitData = { Name => 'SubmitName', # Submit parameter name
54 :     # Value => 'SubmitValue' # Label of submit button
55 :     # };
56 :     #
57 :     # my $paramNames = [ 'first_id', 'second_id', ... ];
58 :     # # URL parameter names for the 1st, 2nd, 3rd, etc.
59 :     # # selected items. They must be unique.
60 :     #
61 :     # my $colHeads = [ '1', '2', ... ];
62 :     # # The table column headings for the selection grid
63 :     #
64 :     # my $itemNames = [ 'Item 1 name', 'Item 2 name', ... ]
65 :     # # The displayed names of the items to be ordered, and
66 :     # # the returned values if itemIDs is not supplied.
67 :     #
68 :     # my $itemIDs = [ 'id1', 'id2', ... ]
69 :     # # Value returned for selected item. Default = itemNames
70 :     #
71 :     #-------------------------------------------------------------------------------
72 :     sub buttonArrayScript
73 :     {
74 :     <<"End_of_Script"
75 :    
76 :     <!-- ===========================================================================
77 :     This script manages a square array (nItem x nItem) of radio buttons
78 :     that is used to order the items in a display. All the buttons in a
79 :     column have the same name (so the browser manages their interactions).
80 :     All the buttons in a row will (typically) have the same value, which can
81 :     be any index, normally the id of a item.
82 :    
83 :     Each button must be inside its own <SPAN ID=formName + "_" + row + "_" + col>
84 :     </SPAN> pair, so that visibility can be controlled. It is assumed that
85 :     initially, no buttons are selected, and only the first column is visible.
86 :     ============================================================================ -->
87 :    
88 :     <SCRIPT Language=JavaScript>
89 :    
90 :     function initializeButtonArray( myForm, nItem )
91 :     {
92 :     myForm.nItem = nItem;
93 :     // rowVal[] = column selected for a item
94 :     myForm.rowVal = new Array( nItem );
95 :     for ( i = 1; i <= nItem; i++ ) { myForm.rowVal[i-1] = 0; }
96 :     // colVal[] = item selected in a column
97 :     myForm.colVal = new Array( nItem );
98 :     for ( i = 1; i <= nItem; i++ ) { myForm.colVal[i-1] = 0; }
99 :     myForm.nSelected = 0;
100 :     }
101 :    
102 :    
103 :     function onClickButtonArray( myForm, row, col )
104 :     {
105 :     // Usually, the selection is in the rightmost visible column:
106 :     var c;
107 :     var r;
108 :     var formName = myForm.name;
109 :     var nItem = myForm.nItem;
110 :    
111 :     if ( col > myForm.nSelected )
112 :     {
113 :     // Entry is in rightmost column. Reveal the whole column:
114 :     for ( r = 1; r <= nItem; r++ )
115 :     {
116 :     if ( myForm.rowVal[r-1] != 0 ) { adjustButtonArrayDisplay( formName, r, col, "inline" ); }
117 :     }
118 :    
119 :     myForm.nSelected++;
120 :     if ( myForm.nSelected == 1 ) { setDisplayState( "submit_" + formName, "inline" ); }
121 :     myForm.rowVal[row-1] = col;
122 :     myForm.colVal[col-1] = row;
123 :    
124 :     // Reveal unselected items in next column:
125 :     c = col + 1;
126 :     if ( c < nItem )
127 :     {
128 :     for ( r = 1; r <= nItem; r++ )
129 :     {
130 :     if ( myForm.rowVal[r-1] == 0 ) { adjustButtonArrayDisplay( formName, r, c, "inline" ); }
131 :     }
132 :     }
133 :     else
134 :     {
135 :     // Penultimate column is special. There is only one unselected
136 :     // genone in last column, so we select it, and reveal the whole
137 :     // column.
138 :     setButtonArrayLastColumm( myForm );
139 :     }
140 :     }
141 :    
142 :     // Selection was not in the rightmost (new) column. We must shuffle the data
143 :     else if ( myForm.rowVal[row-1] == 0 )
144 :     {
145 :     // Item not yet seen, so this is new data
146 :     // Reveal buttons:
147 :     c = myForm.nSelected + 1;
148 :     for ( r = 1; r <= nItem; r++ )
149 :     {
150 :     if ( myForm.rowVal[r-1] != 0 ) { adjustButtonArrayDisplay( formName, r, c, "inline" ); }
151 :     }
152 :    
153 :     // Push existing data to right:
154 :     for ( c = myForm.nSelected; c >= col; c-- )
155 :     {
156 :     r = myForm.colVal[c-1]; // Item in column c
157 :     myForm[nItem*(r-1) + c].checked = true; // Move to c+1
158 :     myForm.colVal[c] = r; // Put in column c+1
159 :     myForm.rowVal[r-1]++;
160 :     }
161 :    
162 :     // Record the new selection:
163 :     myForm.nSelected++;
164 :     myForm.rowVal[row-1] = col;
165 :     myForm.colVal[col-1] = row;
166 :    
167 :     // Reveal yet one more column, or handle last column:
168 :     c = myForm.nSelected + 1;
169 :     if ( c < nItem )
170 :     {
171 :     for ( r = 1; r <= nItem; r++ )
172 :     {
173 :     if ( myForm.rowVal[r-1] == 0 ) { adjustButtonArrayDisplay( formName, r, c, "inline" ); }
174 :     }
175 :     }
176 :     else
177 :     {
178 :     // Penultimate column is special. There is only one unselected
179 :     // genone in last column, so we select it, and reveal the whole
180 :     // column.
181 :     setButtonArrayLastColumm( myForm );
182 :     }
183 :     }
184 :     else if ( myForm.rowVal[row-1] > col )
185 :     {
186 :     // The clicked button is to the left of the current location
187 :     // of the item. We must push data to the right. c is the old
188 :     // column number.
189 :     for ( c = myForm.rowVal[row-1]-1; c >= col; c-- )
190 :     {
191 :     r = myForm.colVal[c-1];
192 :     myForm[nItem*(r-1) + c].checked = true; // Move to c+1
193 :     myForm.colVal[c ] = r;
194 :     myForm.rowVal[r-1]++;
195 :     }
196 :     myForm.rowVal[row-1] = col;
197 :     myForm.colVal[col-1] = row;
198 :     }
199 :     else if ( myForm.rowVal[row-1] < col )
200 :     {
201 :     // The selection point is to the right of the current location
202 :     // of the item. We must push data to the left. c is the old
203 :     // column number.
204 :     for ( c = myForm.rowVal[row-1]+1; c <= col; c++ )
205 :     {
206 :     r = myForm.colVal[c-1];
207 :     myForm[nItem*(r-1) + c-2].checked = true; // Move to c-1
208 :     myForm.colVal[c-2] = r;
209 :     myForm.rowVal[r-1]--;
210 :     }
211 :     myForm.rowVal[row-1] = col;
212 :     myForm.colVal[col-1] = row;
213 :     }
214 :     }
215 :    
216 :    
217 :     function adjustButtonArrayDisplay( formName, row, col, newState )
218 :     {
219 :     setDisplayState( formName + "_" + row + "_" + col, newState );
220 :     }
221 :    
222 :    
223 :     function setDisplayState( myId, newState )
224 :     {
225 :     if ( document.getElementById ) { // this is the way the standards work
226 :     document.getElementById(myId).style.display = newState;
227 :     } else if ( document.all ) { // this is the way old msie versions work
228 :     document.all[myId].style.display = newState;
229 :     } else if ( document.layers ) { // this is the way nn4 works
230 :     document.layers[myId].style.display = newState;
231 :     }
232 :     }
233 :    
234 :    
235 :     function setButtonArrayLastColumm( myForm )
236 :     {
237 :     var nItem = myForm.nItem;
238 :     var c = nItem;
239 :     for ( var r = 1; r <= nItem; r++ )
240 :     {
241 :     adjustButtonArrayDisplay( myForm.name, r, c, "inline" );
242 :     if ( myForm.rowVal[r-1] == 0 )
243 :     {
244 :     myForm.nSelected++;
245 :     myForm.rowVal[r-1] = c;
246 :     myForm.colVal[c-1] = r;
247 :     myForm[ nItem*(r-1) + c-1 ].checked = true;
248 :     }
249 :     }
250 :     }
251 :    
252 :    
253 :     function resetButtonArray( myForm )
254 :     {
255 :     var nItem = myForm.nItem;
256 :     for ( var i = 1; i <= nItem; i++ ) { myForm.rowVal[i-1] = 0; }
257 :     for ( var i = 1; i <= nItem; i++ ) { myForm.colVal[i-1] = 0; }
258 :     for ( var c = 1; c <= nItem; c++ )
259 :     {
260 :     for ( var r = 1; r <= nItem; r++ )
261 :     {
262 :     myForm[ nItem*(r-1) + c-1 ].checked = false;
263 :     adjustButtonArrayDisplay( myForm.name, r, c, ( c == 1 ? "inline" : "none" ) );
264 :     }
265 :     }
266 :     myForm.nSelected = 0;
267 :     setDisplayState( "submit_" + myForm.name, "none" );
268 :     }
269 :    
270 :     </SCRIPT>
271 :    
272 :     End_of_Script
273 :     }
274 :    
275 :    
276 :     { # Bare block to cound forms with button arrays
277 :    
278 :     my $nForms = 0;
279 :    
280 :     sub buttonArrayForm
281 :     {
282 :     my ( $formData, $hiddenData, $submitData, $paramNames, $colHeads, $itemNames, $itemIDs ) = @_;
283 :    
284 :     ref $formData eq 'HASH'
285 :     && ref $paramNames eq 'ARRAY'
286 :     && ref $itemNames eq 'ARRAY'
287 :     && @$paramNames == @$itemNames
288 :     or return '';
289 :    
290 :     ref $itemIDs eq 'ARRAY' && @$itemIDs == @$itemNames
291 :     or $itemIDs = $itemNames;
292 :    
293 :     ref $colHeads eq 'ARRAY' && @$colHeads == @$paramNames
294 :     or $colHeads = [ 1 .. scalar @$paramNames ];
295 :    
296 :     $nForms++;
297 :    
298 :     my ( $name_key ) = grep { lc $_ eq "name" } keys %$formData;
299 :     $name_key ||= "Name";
300 :     my $formName = $formData->{ $name_key };
301 :    
302 :     # Although some things work with "invalid" name, others do not. So ...
303 :    
304 :     if ( $formName !~ /^\w+$/ )
305 :     {
306 :     $formName = "Form$nForms";
307 :     $formData->{ $name_key } = $formName;
308 :     }
309 :    
310 :     my $nItem = @$itemIDs;
311 :     my $nItem1 = $nItem + 1;
312 :    
313 :     my $formextras = join( ' ', map { "$_=\"$formData->{$_}\"" } keys %$formData );
314 :    
315 :     my $html .= <<"End_of_Intro1";
316 :    
317 :     <!-- ===========================================================================
318 :     This FORM manages a table of radio buttons for allowing the user that allow
319 :     a user to define the order of a set of items.
320 :     ============================================================================ -->
321 :    
322 :     <FORM $formextras>
323 :    
324 :     <TABLE>
325 :     <TR>
326 :     <TH>&nbsp;</TH>
327 :     <TH ColSpan=$nItem>Desired order</TD>
328 :     </TR>
329 :     <TR>
330 :     <TD>&nbsp;</TD>
331 :     <TD ColSpan=$nItem><HR /></TD>
332 :     </TR>
333 :     <TR>
334 :     <TH>Items to order</TH>
335 :     End_of_Intro1
336 :    
337 :     $html .= join( '', map { " <TH Width=18>$_</TH>\n" } @$colHeads );
338 :    
339 :     $html .= <<"End_of_Intro2";
340 :     </TR>
341 :     <TR>
342 :     <TD ColSpan=$nItem1><HR /></TD>
343 :     </TR>
344 :     End_of_Intro2
345 :    
346 :     my ( $i1, $label, $value, $j1, $state, $id, $name );
347 :     for ( $i1 = 1; $i1 <= $nItem; $i1++ )
348 :     {
349 :     $label = html_escape( $itemNames->[$i1-1] );
350 :     $value = value_qq( $itemIDs->[$i1-1] );
351 :    
352 :     $html .= " <TR>\n"
353 :     . " <TD>$label</TD>\n";
354 :     for ( $j1 = 1; $j1 <= $nItem; $j1++ )
355 :     {
356 :     $state = ( $j1 == 1 ) ? 'inline' : 'none';
357 :     $id = "${formName}_${i1}_$j1";
358 :     $name = html_escape( $paramNames->[$j1-1] );
359 :     $html .= " <TD Align=center><SPAN Id=$id Style=\"display:$state\"><INPUT Type=radio Name=$name Value=$value OnClick=\"javascript:onClickButtonArray(this.form,$i1,$j1);\" /></SPAN></TD>\n";
360 :     }
361 :     $html .= " </TR>\n";
362 :     }
363 :    
364 :     $html .= <<"End_of_Table";
365 :     <TR>
366 :     <TD ColSpan=$nItem1><HR /></TD>
367 :     </TR>
368 :     </TABLE>
369 :    
370 :     End_of_Table
371 :    
372 :     # Add the hidden data. Adding it earlier renumbers the radio buttons.
373 :    
374 :     my ( $data, $datum, $qq_datum );
375 :     foreach ( keys %$hiddenData )
376 :     {
377 :     $data = $hiddenData->{ $_ };
378 :     foreach $datum ( ( ref $data eq 'ARRAY' ) ? @$data : ( $data ) )
379 :     {
380 :     $qq_datum = value_qq( $datum ); # Wrap in double quotes
381 :     $html .= "<INPUT Type=hidden Name=$_ Value=$qq_datum />\n";
382 :     }
383 :     }
384 :    
385 :     # Add the action buttons and end the form
386 :    
387 :     my $submit = join( ' ', map { "$_=\"$submitData->{$_}\"" } keys %$submitData );
388 :    
389 :     $html .= <<"End_of_Form";
390 :     <SPAN Id=submit_$formName Style=\"display:none\"><INPUT Type=submit $submit /></SPAN>
391 :     <INPUT Type=button Name=Reset Value=Reset onClick=\"javascript:resetButtonArray(this.form)\" /><BR />
392 :    
393 :     <SCRIPT Language=JavaScript> // Initialize the form
394 :     initializeButtonArray( document.$formName, $nItem );
395 :     </SCRIPT>
396 :    
397 :     </FORM>
398 :    
399 :     End_of_Form
400 :    
401 :     $html
402 :     }
403 :    
404 :     } # End of bare block allowing us to count forms
405 :    
406 :     sub html_escape { local $_ = shift; s/\&/&amp;/g; s/</&lt;/g; s/</&gt;/g; $_ }
407 :    
408 :     sub value_qq { local $_ = shift; s/\&/&amp;/g; s/</&lt;/g; s/</&gt;/g; s/"/&quot;/g; '"' . $_ . '"' }
409 :    
410 :     1;

MCS Webmaster
ViewVC Help
Powered by ViewVC 1.0.3