3 package CXGN
::Page
::Widgets
;
9 use CXGN
::Page
::UserPrefs
;
15 CXGN::Page::Widget - helper functions for creating dynamic page elements such
16 as collapsible boxes, content swappers, and (moveable windows?).
20 Built-in support for cookie-setting will give the user fine control over his or her
23 The basic requirement for something to be a widget and not a FormattingHelper is
28 All functions are EXPORT_OK.
34 our @ISA = qw
/Exporter/;
36 our $VERSION = sprintf "%d.%03d", q
$Revision: 1.1 $ =~ /(\d+)/g;
37 our @EXPORT_OK = qw
/collapser swapper cycler/;
44 Returns a link and target content, where use of the link by the user
45 will cause that content to collapse.
48 Args: Pass a hash reference with the following keys:
49 linktext: text of the link, which will be prepended with (+) or (-)
50 hide_state_linktext: text of link when hidden, if this is not specified, prepending will be used
51 content: the content that you want to be hidden
52 id: a unique id of your choice, which will serve as part of the user's cookie prefs
53 linkstyle(optional): style of the controller link
54 collapsed: default state is: already collapsed
55 save: the state is savable to the user preference string. If you use this feature,
56 you MUST add the id to the UserPref/Registry
57 alt_href: go to page if javascript not working
58 alt_target: target for alt_href
60 Returns: ($link, $content), where $link is the html for the two consecutive <a>links</a> that make the button, and $content is the content you provided,
61 wrapped with <span id='[provided id]'></span>
63 Usage: my ($link, $content) = collapser({
64 linktext => 'Heading',
65 linkstyle => 'text-decoration:none',
66 content => '<b>Hide this text on link-click</b>',
68 save => 1, #uses CXGN::UserPrefs, the "id" key on the
69 #next line would have to be in the Register
72 print $link . "<br>" . $content;
77 my %args = %{ shift @_ };
81 valid
=> ['linktext', 'hide_state_linktext', 'linkstyle', 'content', 'id', 'collapsed', 'save', 'alt_href', 'alt_target'],
82 required
=> ['linktext', 'content', 'id']
85 my ($linktext, $hide_state_linktext, $content, $id, $alt_href, $alt_target)
86 = ($args{'linktext'}, $args{'hide_state_linktext'}, $args{'content'}, $args{'id'}, $args{'alt_href'}, $args{'alt_target'});
87 _check_id
($id) if $args{save
};
90 $state = _get_pref
($id) if $args{save
};
96 my ($on_display, $off_display) = ("", "");
97 if($state eq "hid") { $on_display = "display:none;"; }
98 else { $off_display = "display:none;" }
100 my $linkstyle = $args{'linkstyle'} || "";
101 $linkstyle =~ s/;\s*$//;
103 my ($hide_save_js, $show_save_js) = ("","");
105 $hide_save_js = "UserPrefs.set(\"$id\", \"hid\");UserPrefs.setCookie();";
106 $show_save_js = "UserPrefs.set(\"$id\", \"dsp\");UserPrefs.setCookie();";
108 $hide_state_linktext ||= $linktext;
109 no warnings
'uninitialized';
111 <a class="collapser collapser_show" target="$alt_target" href="$alt_href" style="$linkstyle;$on_display" onclick="
112 Effects.swapElements('${id}_offswitch', '${id}_onswitch');
113 Effects.hideElement('${id}_content');
116 id="${id}_offswitch"><img src="/documents/img/collapser_minus.png" />$linktext</a>
117 <a class="collapser collapser_show" target="$alt_target" href="$alt_href" style="$linkstyle;$off_display" onclick="
118 Effects.swapElements('${id}_onswitch', '${id}_offswitch');
119 Effects.showElement('${id}_content');
122 id="${id}_onswitch"><img src="/documents/img/collapser_plus.png" />$hide_state_linktext</a>
125 my $wrapped_content = qq|<span id
="${id}_content" style
="$on_display">$content</span
>|;
127 return ($link, $wrapped_content);
132 Returns a link and target content, where use of the link by the user
133 will cause that content to switch to alternate content (back-and-forth), which will be displayed in a consecutively hidden fashion
137 Returns: ($link, $content), where $link is the html for the two consecutive <a>links</a> that make the button, and $content contains consecutive
138 contents, one hidden, each wrapped with <span id=[provided id]:(def|alt)></span>
139 Usage: my ($link, $content) = swapper ({
140 linktext => 'Swap With Something Else',
141 linktext_alt => 'Unswap me you savage!",
142 linkstyle => 'text-decoration:none',
143 content => 'I am the regular content',
144 content_alt => 'I am the alternate content <a href='www.boycott-riaa.org'>Click me!</a>',
147 print $link . "<br>" . $content;
152 my %args = %{ shift @_ };
153 #check arguments. i think this is better for everyone except beth
154 my @valid_keys = qw
/linktext linktext_alt linkstyle content content_alt id/;
155 my @required_keys = qw
/linktext linktext_alt content content_alt id/;
156 foreach my $argname (keys %args) {
157 grep {$_ eq $argname} @valid_keys
158 or croak
"Unknown argument name '$argname' to collapser";
160 foreach my $required (@required_keys) {
161 grep {$_ eq $required} (keys %args)
162 or croak
"Required key: '$required' not specified";
164 my ($linktext, $linktext_alt, $content, $content_alt, $id) = ($args{'linktext'}, $args{'linktext_alt'}, $args{'content'}, $args{'content_alt'}, $args{'id'});
165 my $linkstyle = $args{'linkstyle'} || "";
167 my $state = _get_pref
($id);
168 my ($def_display, $alt_display) = ("", "");
169 if($state eq "alt") { $def_display = "display:none"; }
170 else { $alt_display = "display:none"; }
171 $linkstyle =~ s/;\s*$//g;
174 <a href='#' style='$linkstyle;$def_display' onclick='
175 Effects.swapElements("${id}_swap", "${id}_unswap");
176 Effects.swapElements("${id}_def", "${id}_alt");
177 UserPrefs.set("$id", "alt");
178 UserPrefs.setCookie();
180 id='${id}_swap'>$linktext</a>
181 <a href='#' style='$linkstyle;$alt_display', onclick='
182 Effects.swapElements("${id}_unswap", "${id}_swap");
183 Effects.swapElements("${id}_alt", "${id}_def");
184 UserPrefs.set("$id", "def");
185 UserPrefs.setCookie();
187 id='${id}_unswap'>$linktext_alt</a>
190 my $wrapped_content = "<span id='${id}_def' style='$def_display'>$content</span><span id='${id}_alt' style='$alt_display'>$content_alt</span>";
191 return ($link, $wrapped_content);
196 Returns a link and target content, where use of the link by the user
197 will cause that content to cycle amongst alternate content, which will be displayed in a consecutively hidden fashion
199 Args: a hash reference with the keys:
200 id: a unique alphanumeric key
201 linktexts: an array reference containing the various texts (or html) to display as the cycler button link
202 linkstyle: (optional) a string containing common style for the link
203 contents: an array reference containing the contents to be cycled, in HTML format
205 Returns: ($link, $content), where $link is the html for the two consecutive <a>links</a> that make the button, and $content contains consecutive
206 contents, all but one hidden, each wrapped with <span id='[provided id]:(1|2|3...)'></span>
207 Usage: my ($link, $content) = cycler({
208 linktexts => ['Go to state two','Go to state three', 'Back to first state']
209 linkstyle => 'text-decoration:none',
210 contents => ['It's good to be state one!!', 'It's my turn, now, bitches!', 'State three is fine with me!']
213 print $link . "<br>" . $content;
218 my %args = %{ shift @_ };
219 my @valid_keys = qw
/linktexts linkstyle contents id/;
220 my @required_keys = qw
/linktexts contents id/;
221 foreach my $argname (keys %args) {
222 grep {$_ eq $argname} @valid_keys
223 or croak
"Unknown argument name '$argname' to collapser";
225 foreach my $required (@required_keys) {
226 grep {$_ eq $required} (keys %args)
227 or croak
"Required key: '$required' not specified";
229 my ($linktexts, $contents) = ($args{'linktexts'}, $args{'contents'});
230 unless(@
{$linktexts}==@
{$contents} && @
{$linktexts}>1) {
231 croak
"'linktexts' array (@{$linktexts}) must have more than one element AND be equal in length to 'contents' array (size:@{$contents})";
233 my $id = $args{'id'};
235 my $linkstyle = $args{'linkstyle'} || "";
236 my $cyclesize = @
{$contents};
240 foreach my $linktext (@
{$linktexts}) {
242 if($count >= ($cyclesize - 1)) {$next = 0;}
244 <a href='#' style='$linkstyle' onclick='
245 Effects.swapElements("${id}_$count", "${id}_$next");
246 Effects.swapElements("${id}_control$count", "${id}_control$next");
248 id='${id}_control$count'>$linktext</a>
253 my $wrapped_content = "";
255 foreach my $content (@
{$contents}) {
256 $wrapped_content .= "<span id='${id}_$counter'>$content</span>";
259 return ($link, $wrapped_content);
264 Provides the html notifier box that corresponds with the notify() command in jslib: CXGN.Base. There should be one below every page toolbar, as far as I'm concerned ;)
266 Usage: print CXGN::Page::Widgets::notifier({style => "yaddayadda", append_style => "background-color:#fa0"});
268 Note: You can only print one notifier per page, as there is a pair of standard elementIds: SGN_NOTIFY_BOX and SGN_NOTIFY_CONTENT
274 my $style= $args->{style
};
275 $style ||= "width:350px; display:none; background-color:#fd6;border: #fa0 2px solid; text-align:left; padding:3px;";
276 my $append_style = $args->{append_style
};
277 $append_style ||= "";
280 <div id='SGN_NOTIFY_BOX' style='${style}$append_style'>
281 <table style='width:100%; margin:0px; padding:0px;'><tr>
282 <td style='text-align:left'>
283 <a href='#' style='text-decoration:none' onclick='
284 document.getElementById("SGN_NOTIFY_BOX").style.display = "none";
285 document.getElementById("SGN_NOTIFY_CONTENT").innerHTML = "";'>(X)</a></td>
286 <td style='text-align:center'>
287 <span id='SGN_NOTIFY_CONTENT'>Notification Area</span>
289 <td style='text-align:right;visibility:hidden'>(X)</span> <!--balances close tick on left side so text appears centered-->
295 # Dependent 'private' subroutines
298 die "No ID specified. You cannot use the save option without specifying a registered ID" unless ($id);
299 CXGN
::Page
::UserPrefs
->validate_key($id);
303 #since Widgets will be used after headers are sent, we shouldn't use the UserPrefs handle, but we can use the cookie string that we got from the handle when this module is called. It will be faster this way, anyhow.
305 my $cookie_string = CXGN
::Cookie
::get_cookie
("user_prefs");
306 my ($value) = $cookie_string =~ /$name=([^:]+)/;
312 my @valid = @
{$args->{valid
}};
313 my @required = @
{$args->{required
}};
314 my $args_hash_ref = $args->{args
};
315 die "Key required: 'args'\n" unless($args_hash_ref);
318 foreach my $argname (keys %{$args_hash_ref}) {
319 grep {$_ eq $argname} @valid
320 or croak
"Unknown argument name '$argname' to collapser";
324 foreach my $required (@required) {
325 grep {$_ eq $required} (keys %{$args_hash_ref})
326 or croak
"Required key: '$required' not specified";
337 Chris Carpita <csc32@cornell.edu>