[system] / trunk / webwork-modperl / lib / WeBWorK / ContentGenerator.pm Repository:
ViewVC logotype

Annotation of /trunk/webwork-modperl/lib/WeBWorK/ContentGenerator.pm

Parent Directory Parent Directory | Revision Log Revision Log


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

1 : sh002i 455 ################################################################################
2 : sh002i 1663 # WeBWorK Online Homework Delivery System
3 :     # Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/
4 : sh002i 2030 # $CVSHeader: webwork-modperl/lib/WeBWorK/ContentGenerator.pm,v 1.96 2004/05/06 20:31:50 toenail Exp $
5 : sh002i 1663 #
6 :     # This program is free software; you can redistribute it and/or modify it under
7 :     # the terms of either: (a) the GNU General Public License as published by the
8 :     # Free Software Foundation; either version 2, or (at your option) any later
9 :     # version, or (b) the "Artistic License" which comes with this package.
10 :     #
11 :     # This program is distributed in the hope that it will be useful, but WITHOUT
12 :     # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 :     # FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the
14 :     # Artistic License for more details.
15 : sh002i 455 ################################################################################
16 :    
17 : malsyned 313 package WeBWorK::ContentGenerator;
18 : malsyned 305
19 : sh002i 455 =head1 NAME
20 :    
21 :     WeBWorK::ContentGenerator - base class for modules that generate page content.
22 :    
23 : sh002i 1861 =head1 SYNOPSIS
24 :    
25 :     # start with a WeBWorK::Request object: $r
26 :    
27 :     use WeBWorK::ContentGenerator::SomeSubclass;
28 :    
29 :     my $cg = WeBWorK::ContentGenerator::SomeSubclass->new($r);
30 :     my $result = $cg->go();
31 :    
32 :     =head1 DESCRIPTION
33 :    
34 : sh002i 1873 WeBWorK::ContentGenerator provides the framework for generating page content.
35 :     "Content generators" are subclasses of this class which provide content for
36 :     particular parts of the system.
37 : sh002i 1861
38 : sh002i 1873 Default versions of methods used by the templating system are provided. Several
39 :     useful methods are provided for rendering common output idioms and some
40 :     miscellaneous utilities are provided.
41 :    
42 : sh002i 455 =cut
43 :    
44 : malsyned 441 use strict;
45 :     use warnings;
46 : sh002i 1911 use Apache::Constants qw(:response);
47 : sh002i 1882 use Carp;
48 : sh002i 1880 use CGI::Pretty qw(*ul *li);
49 : sh002i 469 use URI::Escape;
50 : sh002i 1869 use WeBWorK::Template qw(template);
51 : malsyned 390
52 : sh002i 1873 ################################################################################
53 : malsyned 390
54 : sh002i 1861 =head1 CONSTRUCTOR
55 : sh002i 1838
56 : sh002i 1861 =over
57 :    
58 :     =item new($r)
59 :    
60 : sh002i 1873 Creates a new instance of a content generator. Supply a WeBWorK::Request object
61 : sh002i 1861 $r.
62 :    
63 :     =cut
64 :    
65 : sh002i 1613 sub new {
66 : sh002i 1838 my ($invocant, $r) = @_;
67 : malsyned 323 my $class = ref($invocant) || $invocant;
68 : sh002i 809 my $self = {
69 : sh002i 1838 r => $r, # this is now a WeBWorK::Request
70 :     ce => $r->ce(), # these three are here for
71 :     db => $r->db(), # backward-compatability
72 :     authz => $r->authz(), # with unconverted CGs
73 : sh002i 1869 noContent => undef, # this should get clobbered at some point
74 : sh002i 809 };
75 : malsyned 305 bless $self, $class;
76 :     return $self;
77 :     }
78 :    
79 : sh002i 1861 =back
80 :    
81 :     =cut
82 :    
83 : sh002i 469 ################################################################################
84 : malsyned 323
85 : sh002i 1861 =head1 INVOCATION
86 :    
87 :     =over
88 :    
89 :     =item go()
90 :    
91 : sh002i 1873 Generates a page, using methods from the particular subclass of ContentGenerator
92 :     that is instantiated. Generatoion is broken up into several steps, to give
93 :     subclasses ample control over the process.
94 : sh002i 1861
95 :     =over
96 :    
97 : sh002i 1873 =item 1
98 : sh002i 1861
99 : sh002i 1873 go() will attempt to call the method pre_header_initialize(). This method may be
100 :     implemented in subclasses which must do processing before the HTTP header is
101 :     emitted.
102 : sh002i 1861
103 : sh002i 1873 =item 2
104 : sh002i 1861
105 : sh002i 1873 go() will attempt to call the method header(). This method emits the HTTP
106 :     header. It is defined in this class (see below), but may be overridden in
107 :     subclasses which need to send different header information. For some reason, the
108 :     return value of header() will be used as the result of this function, if it is
109 :     defined.
110 : sh002i 1861
111 : sh002i 1911 FIXME: figure out what the deal is with the return value of header(). If we sent
112 :     a header, it's too late to set the status by returning. If we didn't, header()
113 :     didn't perform its function!
114 :    
115 : sh002i 1873 =item 3
116 : sh002i 1861
117 : sh002i 1873 At this point, go() will terminate if the request is a HEAD request or if the
118 :     field $self->{noContent} contains a true value.
119 : sh002i 1861
120 : sh002i 1911 FIXME: I don't think we'll need noContent after reply_with_redirect() is
121 :     adopted by all modules.
122 :    
123 : sh002i 1873 =item 4
124 : sh002i 1861
125 : sh002i 1873 go() then attempts to call the method initialize(). This method may be
126 :     implemented in subclasses which must do processing after the HTTP header is sent
127 :     but before any content is sent.
128 : sh002i 1861
129 : sh002i 1873 =item 6
130 :    
131 :     The method content() is called to send the page content to client.
132 :    
133 : sh002i 1861 =back
134 :    
135 :     =cut
136 :    
137 : sh002i 469 sub go {
138 : sh002i 1873 my ($self) = @_;
139 :     my $r = $self->r;
140 : sh002i 1869 my $ce = $r->ce;
141 :    
142 : malsyned 1408 my $returnValue = OK;
143 : sh002i 1131
144 : sh002i 469 $self->pre_header_initialize(@_) if $self->can("pre_header_initialize");
145 : sh002i 1873
146 : sh002i 1911 # send a file instead of a normal reply (reply_with_file() sets this field)
147 :     defined $self->{reply_with_file} and do {
148 :     return $self->do_reply_with_file($self->{reply_with_file});
149 :     };
150 :    
151 :     # send a Location: header instead of a normal reply (reply_with_redirect() sets this field)
152 :     defined $self->{reply_with_redirect} and do {
153 :     return $self->do_reply_with_redirect($self->{reply_with_redirect});
154 :     };
155 :    
156 : malsyned 1408 my $headerReturn = $self->header(@_);
157 :     $returnValue = $headerReturn if defined $headerReturn;
158 : sh002i 1911 # FIXME: we won't need noContent after reply_with_redirect() is adopted
159 : malsyned 1408 return $returnValue if $r->header_only or $self->{noContent};
160 : malsyned 313
161 : sh002i 1873 $self->initialize() if $self->can("initialize");
162 : sh002i 1225
163 : sh002i 1873 $self->content();
164 : malsyned 1408
165 :     return $returnValue;
166 : sh002i 469 }
167 :    
168 : sh002i 1873 =item r()
169 : sh002i 1861
170 : sh002i 1873 Returns a reference to the WeBWorK::Request object associated with this
171 :     instance.
172 : sh002i 1861
173 :     =cut
174 :    
175 : sh002i 1873 sub r {
176 :     my ($self) = @_;
177 : sh002i 1869
178 : sh002i 1873 return $self->{r};
179 : sh002i 469 }
180 :    
181 : sh002i 1911 =item do_reply_with_file($fileHash)
182 :    
183 :     Handler for reply_with_file(), used by go(). DO NOT CALL THIS METHOD DIRECTLY.
184 :    
185 :     =cut
186 :    
187 :     sub do_reply_with_file {
188 :     my ($self, $fileHash) = @_;
189 :     my $r = $self->r;
190 :    
191 : sh002i 1984 my $type = $fileHash->{type};
192 : sh002i 1911 my $source = $fileHash->{source};
193 : sh002i 1984 my $name = $fileHash->{name};
194 :     my $delete_after = $fileHash->{delete_after};
195 : sh002i 1911
196 :     # if there was a problem, we return here and let go() worry about sending the reply
197 :     return NOT_FOUND unless -e $source;
198 :     return FORBIDDEN unless -r $source;
199 :    
200 :     # open the file now, so we can send the proper error status is we fail
201 :     open my $fh, "<", $source or return SERVER_ERROR;
202 :    
203 :     # send our custom HTTP header
204 :     $r->status(OK);
205 :     $r->content_type($type);
206 :     $r->header_out("Content-Disposition" => "attachment; filename=\"$name\"");
207 :     $r->send_http_header;
208 :    
209 :     # send the file
210 :     $r->send_fd($fh);
211 :    
212 :     # close the file and go home
213 :     close $fh;
214 : sh002i 1984
215 :     if ($delete_after) {
216 :     unlink $source or warn "failed to unlink $source after sending: $!";
217 :     }
218 : sh002i 1911 }
219 :    
220 : sh002i 2030 =item do_reply_with_redirect($url)
221 :    
222 :     Handler for reply_with_redirect(), used by go(). DO NOT CALL THIS METHOD DIRECTLY.
223 :    
224 :     =cut
225 :    
226 :     sub do_reply_with_redirect {
227 :     my ($self, $url) = @_;
228 :     my $r = $self->r;
229 :    
230 :     $r->status(REDIRECT);
231 :     $r->header_out(Location => $url);
232 :     $r->send_http_header();
233 :     }
234 :    
235 :     =back
236 :    
237 :     =cut
238 :    
239 :     ################################################################################
240 :    
241 :     =head1 DATA MODIFIERS
242 :    
243 :     Modifiers allow the caller to register a piece of data for later retrieval in a
244 :     standard way.
245 :    
246 :     =over
247 :    
248 :     =item reply_with_file($type, $source, $name, $delete_after)
249 :    
250 :     Enables file sending mode, causing go() to send the file specified by $source to
251 :     the client after calling pre_header_initialize(). The content type sent is
252 :     $type, and the suggested client-side file name is $name. If $delete_after is
253 :     true, $source is deleted after it is sent.
254 :    
255 :     Must be called before the HTTP header is sent. Usually called from
256 :     pre_header_initialize().
257 :    
258 :     =cut
259 :    
260 :     sub reply_with_file {
261 :     my ($self, $type, $source, $name, $delete_after) = @_;
262 :     $delete_after ||= "";
263 :    
264 :     $self->{reply_with_file} = {
265 :     type => $type,
266 :     source => $source,
267 :     name => $name,
268 :     delete_after => $delete_after,
269 :     };
270 :     }
271 :    
272 : sh002i 1911 =item reply_with_redirect($url)
273 :    
274 :     Enables redirect mode, causing go() to redirect to the given URL after calling
275 :     pre_header_initialize().
276 :    
277 : sh002i 2030 Must be called before the HTTP header is sent. Usually called from
278 :     pre_header_initialize().
279 :    
280 : sh002i 1911 =cut
281 :    
282 :     sub reply_with_redirect {
283 :     my ($self, $url) = @_;
284 :    
285 :     $self->{reply_with_redirect} = $url;
286 :     }
287 :    
288 : sh002i 2030 =item addmessage($message)
289 : sh002i 1911
290 : sh002i 2030 Adds a message to the list of messages to be printed by the message() template
291 :     escape handler.
292 : sh002i 1911
293 : sh002i 2030 Must be called before the message() template escape is invoked.
294 :    
295 : sh002i 1911 =cut
296 :    
297 : sh002i 2030 # FIXME: we should probably
298 :    
299 :     sub addmessage {
300 :     my ($self, $message) = @_;
301 :     $self->{message} .= $message;
302 : sh002i 1911 }
303 :    
304 : sh002i 2030
305 :    
306 : sh002i 1873 =back
307 : sh002i 1861
308 :     =cut
309 :    
310 : sh002i 1873 ################################################################################
311 : sh002i 469
312 : sh002i 1873 =head1 STANDARD METHODS
313 : sh002i 1861
314 : sh002i 1873 The following are the standard content generator methods. Some are defined here,
315 :     but may be overridden in a subclass. Others are not defined unless they are
316 :     defined in a subclass.
317 : sh002i 1861
318 : sh002i 1873 =over
319 : sh002i 469
320 : sh002i 1873 =item pre_header_initialize()
321 : sh002i 1861
322 : sh002i 1873 Not defined in this package.
323 : sh002i 1861
324 : sh002i 1873 May be defined by a subclass to perform any processing that must occur before
325 :     the HTTP header is sent.
326 :    
327 : sh002i 1861 =cut
328 :    
329 : sh002i 1873 #sub pre_header_initialize { }
330 : malsyned 323
331 : sh002i 1873 =item header()
332 : sh002i 1861
333 : sh002i 1873 Defined in this package.
334 : sh002i 1861
335 : sh002i 2030 Generates and sends a default HTTP header, specifying the "text/html" content
336 :     type.
337 : sh002i 1861
338 :     =cut
339 :    
340 : sh002i 1873 sub header {
341 : sh002i 425 my $self = shift;
342 : sh002i 1873 my $r = $self->r;
343 : sh002i 425
344 : sh002i 2030 $r->content_type("text/html");
345 : sh002i 1873 $r->send_http_header();
346 :     return OK;
347 : sh002i 425 }
348 :    
349 : sh002i 1873 =item initialize()
350 : sh002i 1861
351 : sh002i 1873 Not defined in this package.
352 : sh002i 1861
353 : sh002i 1873 May be defined by a subclass to perform any processing that must occur after the
354 :     HTTP header is sent but before any content is sent.
355 : sh002i 1861
356 :     =cut
357 :    
358 : sh002i 1873 #sub initialize { }
359 : sh002i 1861
360 : sh002i 1873 =item content()
361 : sh002i 1861
362 : sh002i 1873 Defined in this package.
363 : sh002i 1861
364 : sh002i 1873 Print the content of the generated page.
365 : sh002i 1861
366 : sh002i 1873 The implementation in this package uses WeBWorK::Template to define the content
367 :     of the page. See WeBWorK::Template for details.
368 : malsyned 390
369 : sh002i 1873 If a method named templateName() exists, it it called to determine the name of
370 :     the template to use. If not, the default template, "system", is used. The
371 :     location of the template is looked up in the course environment.
372 : sh002i 1861
373 :     =cut
374 :    
375 : sh002i 1873 sub content {
376 :     my ($self) = @_;
377 :     my $ce = $self->r->ce;
378 : sh002i 737
379 : sh002i 1873 # if the content generator specifies a custom template name, use that
380 :     # field in the $ce->{templates} hash instead of "system" if it exists.
381 :     my $templateName;
382 :     if ($self->can("templateName")) {
383 :     $templateName = $self->templateName;
384 :     } else {
385 :     $templateName = "system";
386 :     }
387 :     $templateName = "system" unless exists $ce->{templates}->{$templateName};
388 :     template($ce->{templates}->{$templateName}, $self);
389 : sh002i 737 }
390 :    
391 : sh002i 1861 =back
392 :    
393 :     =cut
394 :    
395 : sh002i 1873 # ------------------------------------------------------------------------------
396 : sh002i 1866
397 : sh002i 1873 =head2 Template escape handlers
398 : sh002i 1866
399 : sh002i 1873 Template escape handlers are invoked when the template processor encounters a
400 :     matching escape sequence in the template. The escapse sequence's arguments are
401 :     passed to the methods as a reference to a hash.
402 : sh002i 1866
403 : sh002i 1873 For more information, refer to WeBWorK::Template.
404 : malsyned 390
405 : sh002i 1873 The following template escapes handlers are defined here or may be defined in
406 :     subclasses. For methods that are not defined in this package, the documentation
407 :     defines the interface and behavior that any subclass implementation must follow.
408 : malsyned 313
409 : sh002i 1861 =over
410 :    
411 : sh002i 1873 =item head()
412 : sh002i 1861
413 : sh002i 1873 Not defined in this package.
414 : sh002i 1861
415 : sh002i 1873 Any tags that should appear in the HEAD of the document.
416 : sh002i 1861
417 :     =cut
418 :    
419 : sh002i 1873 #sub head { }
420 : malsyned 349
421 : sh002i 1873 =item info()
422 : sh002i 682
423 : sh002i 1873 Not defined in this package.
424 : sh002i 1861
425 : sh002i 1873 Auxiliary information related to the content displayed in the C<body>.
426 : sh002i 1861
427 : sh002i 1873 =cut
428 : sh002i 1861
429 : sh002i 1873 #sub info { }
430 : sh002i 1861
431 : sh002i 1873 =item links()
432 : sh002i 1861
433 : sh002i 1873 Defined in this package.
434 : sh002i 1861
435 : sh002i 1873 Links that should appear on every page.
436 : sh002i 1861
437 :     =cut
438 :    
439 : sh002i 1866 sub links {
440 :     my ($self) = @_;
441 : sh002i 1873 my $r = $self->r;
442 : sh002i 1866 my $db = $r->db;
443 :     my $urlpath = $r->urlpath;
444 :    
445 :     # we're linking to other places in the same course, so grab the courseID from the current path
446 :     my $courseID = $urlpath->arg("courseID");
447 :    
448 :     # to make things more concise
449 :     my %args = ( courseID => $courseID );
450 :     my $pfx = "WeBWorK::ContentGenerator::";
451 :    
452 : sh002i 1880 my $sets = $urlpath->newFromModule("${pfx}ProblemSets", %args);
453 :     my $options = $urlpath->newFromModule("${pfx}Options", %args);
454 :     my $grades = $urlpath->newFromModule("${pfx}Grades", %args);
455 :     my $logout = $urlpath->newFromModule("${pfx}Logout", %args);
456 :    
457 :     print "\n<!-- BEGIN " . __PACKAGE__ . "::links -->\n";
458 :     print CGI::start_ul({class=>"LinksMenu"});
459 :     print CGI::li(CGI::span({style=>"font-size:larger"},
460 :     CGI::a({href=>$self->systemLink($sets)}, "Problem Sets")));
461 :     print CGI::li(CGI::a({href=>$self->systemLink($options)}, $options->name));
462 :     print CGI::li(CGI::a({href=>$self->systemLink($grades)}, $grades->name));
463 :     print CGI::li(CGI::a({href=>$self->systemLink($logout)}, $logout->name));
464 :    
465 : sh002i 1866 my $PermissionLevel = $db->getPermissionLevel($r->param("user")); # checked
466 :     my $permLevel = $PermissionLevel ? $PermissionLevel->permission : 0;
467 :    
468 :     if ($permLevel > 0) {
469 :     my $ipfx = "${pfx}Instructor::";
470 :    
471 :     my $userID = $r->param("effectiveUser");
472 :     my $setID = $urlpath->arg("setID");
473 : toenail 2014 $setID = "" if (defined $setID && !(grep /$setID/, $db->listUserSets($userID)));
474 : sh002i 1866 my $problemID = $urlpath->arg("problemID");
475 : toenail 2014 $problemID = "" if (defined $problemID && !(grep /$problemID/, $db->listUserProblems($userID, $setID)));
476 : sh002i 1866
477 :     my $instr = $urlpath->newFromModule("${ipfx}Index", %args);
478 : sh002i 1918 my $addUsers = $urlpath->newFromModule("${ipfx}AddUsers", %args);
479 : sh002i 1866 my $userList = $urlpath->newFromModule("${ipfx}UserList", %args);
480 :    
481 :     # set list links
482 :     my $setList = $urlpath->newFromModule("${ipfx}ProblemSetList", %args);
483 :     my $setDetail = $urlpath->newFromModule("${ipfx}ProblemSetEditor", %args, setID => $setID);
484 :     my $problemEditor = $urlpath->newFromModule("${ipfx}PGProblemEditor", %args, setID => $setID, problemID => $problemID);
485 :    
486 : jj 1998 my $maker = $urlpath->newFromModule("${ipfx}SetMaker", %args);
487 : sh002i 1918 my $assigner = $urlpath->newFromModule("${ipfx}Assigner", %args);
488 : sh002i 1866 my $mail = $urlpath->newFromModule("${ipfx}SendMail", %args);
489 :     my $scoring = $urlpath->newFromModule("${ipfx}Scoring", %args);
490 :    
491 :     # statistics links
492 :     my $stats = $urlpath->newFromModule("${ipfx}Stats", %args);
493 :     my $userStats = $urlpath->newFromModule("${ipfx}Stats", %args, statType => "student", userID => $userID);
494 :     my $setStats = $urlpath->newFromModule("${ipfx}Stats", %args, statType => "set", setID => $setID);
495 :    
496 :     my $files = $urlpath->newFromModule("${ipfx}FileXfer", %args);
497 :    
498 : jj 1998 print CGI::hr();
499 : sh002i 1880 print CGI::start_li();
500 :     print CGI::span({style=>"font-size:larger"}, CGI::a({href=>$self->systemLink($instr)}, $instr->name));
501 :     print CGI::start_ul();
502 : sh002i 1918 print CGI::li(CGI::a({href=>$self->systemLink($addUsers)}, $addUsers->name));
503 : sh002i 1880 print CGI::li(CGI::a({href=>$self->systemLink($userList)}, $userList->name));
504 :     print CGI::start_li();
505 :     print CGI::a({href=>$self->systemLink($setList)}, $setList->name);
506 : sh002i 1869 if (defined $setID and $setID ne "") {
507 : sh002i 1880 print CGI::start_ul();
508 :     print CGI::start_li();
509 :     print CGI::a({href=>$self->systemLink($setDetail)}, $setID);
510 : sh002i 1869 if (defined $problemID and $problemID ne "") {
511 : sh002i 1880 print CGI::ul(
512 : sh002i 1866 CGI::li(CGI::a({href=>$self->systemLink($problemEditor)}, $problemID))
513 :     );
514 :     }
515 : sh002i 1880 print CGI::end_li();
516 :     print CGI::end_ul();
517 : sh002i 1866 }
518 : sh002i 1880 print CGI::end_li();
519 : jj 1998 print CGI::li(CGI::a({href=>$self->systemLink($maker)}, $maker->name));
520 : sh002i 1918 print CGI::li(CGI::a({href=>$self->systemLink($assigner)}, $assigner->name));
521 : sh002i 1880 print CGI::li(CGI::a({href=>$self->systemLink($mail)}, $mail->name));
522 :     print CGI::li(CGI::a({href=>$self->systemLink($scoring)}, $scoring->name));
523 :     print CGI::start_li();
524 :     print CGI::a({href=>$self->systemLink($stats)}, $stats->name);
525 : sh002i 1869 if (defined $userID and $userID ne "") {
526 : sh002i 1880 print CGI::ul(
527 : sh002i 1866 CGI::li(CGI::a({href=>$self->systemLink($userStats)}, $userID))
528 :     );
529 :     }
530 : sh002i 1869 if (defined $setID and $setID ne "") {
531 : sh002i 1880 print CGI::ul(
532 : sh002i 1866 CGI::li(CGI::a({href=>$self->systemLink($setStats)}, $setID))
533 :     );
534 :     }
535 : sh002i 1880 print CGI::end_li();
536 :     print CGI::li(CGI::a({href=>$self->systemLink($files)}, $files->name));
537 :     print CGI::end_ul();
538 :     print CGI::end_li();
539 : sh002i 1866 }
540 :    
541 : sh002i 1880 print CGI::end_ul();
542 :     print "<!-- end " . __PACKAGE__ . "::links -->\n";
543 : sh002i 1866
544 : sh002i 1880 return "";
545 : sh002i 1866 }
546 :    
547 : sh002i 1873 =item loginstatus()
548 : sh002i 1861
549 : sh002i 1873 Defined in this package.
550 : sh002i 1861
551 : sh002i 1873 Print a notification message announcing the current real user and effective
552 :     user, a link to stop acting as the effective user, and a link to logout.
553 : sh002i 1861
554 :     =cut
555 :    
556 :     sub loginstatus {
557 : sh002i 1869 my ($self) = @_;
558 : sh002i 1873 my $r = $self->r;
559 : sh002i 1869 my $urlpath = $r->urlpath;
560 : sh002i 1861
561 :     my $key = $r->param("key");
562 :    
563 : sh002i 1869 if ($key) {
564 :     my $courseID = $urlpath->arg("courseID");
565 :     my $userID = $r->param("user");
566 :     my $eUserID = $r->param("effectiveUser");
567 :    
568 : sh002i 1882 my $stopActingURL = $self->systemLink($urlpath, # current path
569 : sh002i 1911 params => { effectiveUser => $userID },
570 : sh002i 1882 );
571 : sh002i 1869 my $logoutURL = $self->systemLink($urlpath->newFromModule(__PACKAGE__ . "::Logout", courseID => $courseID));
572 :    
573 : sh002i 1880 print "\n<!-- BEGIN " . __PACKAGE__ . "::loginstatus -->\n";
574 :    
575 : sh002i 1869 print "Logged in as $userID. ";
576 :     print CGI::a({href=>$logoutURL}, "Log Out");
577 :    
578 :     if ($eUserID ne $userID) {
579 :     print " | Acting as $eUserID. ";
580 :     print CGI::a({href=>$stopActingURL}, "Stop Acting");
581 :     }
582 : sh002i 1880
583 :     print "<!-- END " . __PACKAGE__ . "::loginstatus -->\n";
584 : sh002i 1861 }
585 :    
586 :     return "";
587 :     }
588 :    
589 : sh002i 1873 =item nav($args)
590 : sh002i 1869
591 : sh002i 1873 Not defined in this package.
592 : sh002i 1861
593 : sh002i 1873 Links to the previous, next, and parent objects.
594 : sh002i 1861
595 : sh002i 1873 $args is a reference to a hash containing the following fields:
596 :    
597 : sh002i 1861 style => text|image
598 :     imageprefix => prefix to prepend to base image URL
599 :     imagesuffix => suffix to append to base image URL
600 :     separator => HTML to place in between links
601 :    
602 : sh002i 1873 If C<style> is "image", image URLs are constructed by prepending C<imageprefix>
603 :     and postpending C<imagesuffix> to the image base names defined by the
604 :     implementor. (Examples of base names include "Prev", "Next", "ProbSet", and
605 :     "Up"). Each concatenated string should form an absolute URL to an image file.
606 :     For example:
607 : sh002i 1861
608 : sh002i 1873 <!--#nav style="images" imageprefix="/webwork2_files/images/nav"
609 :     imagesuffix=".gif" separator=" "-->
610 : sh002i 1861
611 : sh002i 1873 =cut
612 : sh002i 1861
613 : sh002i 1873 #sub nav { }
614 : sh002i 1861
615 : sh002i 1873 =item options()
616 :    
617 :     Not defined in this package.
618 :    
619 :     Print an auxiliary options form, related to the content displayed in the
620 :     C<body>.
621 :    
622 :     =item path($args)
623 :    
624 :     Defined in this package.
625 :    
626 :     Print "breadcrubs" from the root of the virtual hierarchy to the current page.
627 :     $args is a reference to a hash containing the following fields:
628 :    
629 : sh002i 1861 style => type of separator: text|image
630 : sh002i 1873 image => if style=image, URL of image to use as path separator
631 :     text => if style=text, text to use as path separator
632 :     if style=image, the ALT text of each separator image
633 :     textonly => suppress all HTML, return only plain text
634 : sh002i 1861
635 : sh002i 1873 The implementation in this package takes information from the WeBWorK::URLPath
636 :     associated with the current request.
637 :    
638 : sh002i 1861 =cut
639 :    
640 :     sub path {
641 :     my ($self, $args) = @_;
642 : sh002i 1873 my $r = $self->r;
643 : sh002i 1861
644 :     my @path;
645 :    
646 :     my $urlpath = $r->urlpath;
647 :     do {
648 :     unshift @path, $urlpath->name, $r->location . $urlpath->path;
649 :     } while ($urlpath = $urlpath->parent);
650 :    
651 :     $path[$#path] = ""; # we don't want the last path element to be a link
652 :    
653 : sh002i 1882 #print "\n<!-- BEGIN " . __PACKAGE__ . "::path -->\n";
654 : sh002i 1880 print $self->pathMacro($args, @path);
655 : sh002i 1882 #print "<!-- END " . __PACKAGE__ . "::path -->\n";
656 : sh002i 1880
657 :     return "";
658 : sh002i 1861 }
659 :    
660 : sh002i 1873 =item siblings()
661 : sh002i 1861
662 : sh002i 1873 Not defined in this package.
663 : sh002i 1861
664 : sh002i 1873 Print links to siblings of the current object.
665 : sh002i 1861
666 : sh002i 1873 =cut
667 : sh002i 1861
668 : sh002i 1873 #sub siblings { }
669 :    
670 : jj 1942 =item timestamp()
671 :    
672 :     Defined in this package.
673 :    
674 :     Display the current time and date using default format "3:37pm on Jan 7, 2004".
675 :     The display format can be adjusted by giving a style in the template.
676 :     For example,
677 :    
678 :     <!--#timestamp style="%m/%d/%y at %I:%M%P"-->
679 :    
680 :     will give standard WeBWorK time format. Wording and other formatting
681 :     can be done in the template itself.
682 :     =cut
683 :    
684 :     sub timestamp {
685 :     my ($self, $args) = @_;
686 :     my $formatstring = "%l:%M%P on %b %e, %Y";
687 :     $formatstring = $args->{style} if(defined($args->{style}));
688 :     return(Date::Format::time2str($formatstring, time()));
689 :     }
690 :    
691 : sh002i 1873 =item submiterror()
692 :    
693 :     Defined in this package.
694 :    
695 :     Print any error messages resulting from the last form submission.
696 :    
697 : toenail 2013 This method is deprecated -- use message() instead
698 :    
699 : sh002i 1873 The implementation in this package prints the value of the field
700 :     $self->{submitError}, if it is present.
701 :    
702 : sh002i 1861 =cut
703 :    
704 :     sub submiterror {
705 :     my ($self) = @_;
706 : sh002i 1880
707 :     print "\n<!-- BEGIN " . __PACKAGE__ . "::submiterror -->\n";
708 :     print $self->{submitError} if exists $self->{submitError};
709 :     print "<!-- END " . __PACKAGE__ . "::submiterror -->\n";
710 :    
711 :     return "";
712 : sh002i 1861 }
713 :    
714 : toenail 2013 =item message()
715 :    
716 :     Defined in this package.
717 :    
718 :     Print any messages (error or non-error) resulting from the last form submission.
719 :     This could be used to give Sucess and Failure messages after an action is performed by a module.
720 :    
721 :     The implementation in this package prints the value of the field
722 :     $self->{message}, if it is present.
723 :    
724 :     =cut
725 :    
726 :     sub message {
727 :     my ($self) = @_;
728 :    
729 :     print "\n<!-- BEGIN " . __PACKAGE__ . "::message -->\n";
730 :     print $self->{message} if exists $self->{message};
731 :     print "<!-- END " . __PACKAGE__ . "::message -->\n";
732 :    
733 :     return "";
734 :     }
735 :    
736 : sh002i 1873 =item title()
737 : sh002i 1861
738 : sh002i 1873 Defined in this package.
739 : sh002i 1861
740 : sh002i 1873 Print the title of the current page.
741 :    
742 :     The implementation in this package takes information from the WeBWorK::URLPath
743 :     associated with the current request.
744 :    
745 : sh002i 1861 =cut
746 :    
747 :     sub title {
748 :     my ($self, $args) = @_;
749 : sh002i 1873 my $r = $self->r;
750 : sh002i 1861
751 : sh002i 1880
752 : sh002i 1882 #print "\n<!-- BEGIN " . __PACKAGE__ . "::title -->\n";
753 : sh002i 1880 print $r->urlpath->name;
754 : sh002i 1882 #print "<!-- END " . __PACKAGE__ . "::title -->\n";
755 : sh002i 1880
756 :     return "";
757 : sh002i 1861 }
758 :    
759 : sh002i 1873 =item warnings()
760 : sh002i 1861
761 : sh002i 1873 Defined in this package.
762 : sh002i 1861
763 : sh002i 1873 Print accumulated warnings.
764 :    
765 :     The implementation in this package checks for a note in the request named
766 :     "warnings". If present, its contents are formatted and returned.
767 :    
768 : sh002i 1861 =cut
769 :    
770 :     sub warnings {
771 :     my ($self) = @_;
772 : sh002i 1873 my $r = $self->r;
773 : sh002i 1880
774 :     print "\n<!-- BEGIN " . __PACKAGE__ . "::warnings -->\n";
775 :     print $self->warningOutput($r->notes("warnings")) if $r->notes("warnings");
776 :     print "<!-- END " . __PACKAGE__ . "::warnings -->\n";
777 :    
778 :     return "";
779 : sh002i 1861 }
780 :    
781 :     =back
782 :    
783 : sh002i 1873 =cut
784 : sh002i 1861
785 : sh002i 1873 # ------------------------------------------------------------------------------
786 : sh002i 1861
787 : sh002i 1873 =head2 Conditional predicates
788 :    
789 :     Conditional predicate methods are invoked when the C<#if> escape sequence is
790 :     encountered in the template. If a method named C<if_predicate> is defined in
791 :     here or in the instantiated subclass, it is invoked.
792 :    
793 : sh002i 1861 The following predicates are currently defined:
794 :    
795 :     =over
796 :    
797 : sh002i 1873 =item if_can($function)
798 : sh002i 1861
799 : sh002i 1873 If a function named $function is present in the current content generator (or
800 :     any superclass), a true value is returned. Otherwise, a false value is returned.
801 : sh002i 1861
802 : sh002i 1873 The implementation in this package uses the method UNIVERSAL->can(function) to
803 :     arrive at the result.
804 :    
805 :     A subclass could redefine this method to, for example, "hide" a method from the
806 :     template:
807 :    
808 :     sub if_can {
809 :     my ($self, $arg) = @_;
810 :    
811 :     if ($arg eq "floobar") {
812 :     return 0;
813 :     } else {
814 :     return $self->SUPER::if_can($arg);
815 :     }
816 :     }
817 :    
818 : sh002i 1861 =cut
819 :    
820 : sh002i 1873 sub if_can {
821 :     my ($self, $arg) = @_;
822 : malsyned 525
823 : sh002i 1873 return $self->can($arg) ? 1 : 0;
824 : malsyned 525 }
825 :    
826 : sh002i 1873 =item if_loggedin($arg)
827 : sh002i 1861
828 : sh002i 1873 If the user is currently logged in, $arg is returned. Otherwise, the inverse of
829 :     $arg is returned.
830 : sh002i 1861
831 : sh002i 1873 The implementation in this package always returns $arg, since most content
832 :     generators are only reachable when the user is authenticated. It is up to
833 :     classes that can be reached without logging in to override this method and
834 :     provide the correct behavior.
835 :    
836 :     This is suboptimal, and may change in the future.
837 :    
838 : sh002i 1861 =cut
839 :    
840 : sh002i 1873 sub if_loggedin {
841 :     my ($self, $arg) = @_;
842 : malsyned 748
843 :     return $arg;
844 :     }
845 :    
846 : sh002i 1873 =item if_submiterror($arg)
847 : sh002i 1131
848 : sh002i 1873 If the last form submission generated an error, $arg is returned. Otherwise, the
849 :     inverse of $arg is returned.
850 :    
851 :     The implementation in this package checks for the field $self->{submitError} to
852 :     determine if an error condition is present.
853 :    
854 :     If a subclass uses some other method to classify submission results, this method could be
855 :     redefined to handle that variance:
856 :    
857 :     sub if_submiterror {
858 :     my ($self, $arg) = @_;
859 :    
860 :     my $status = $self->{processReturnValue};
861 :     if ($status != 0) {
862 :     return $arg;
863 :     } else {
864 :     return !$arg;
865 :     }
866 :     }
867 :    
868 : sh002i 1861 =cut
869 :    
870 : sh002i 1873 sub if_submiterror {
871 : malsyned 1017 my ($self, $arg) = @_;
872 : sh002i 1873
873 : malsyned 1017 if (exists $self->{submitError}) {
874 :     return $arg;
875 :     } else {
876 :     return !$arg;
877 :     }
878 :     }
879 :    
880 : toenail 2013 =item if_message($arg)
881 :    
882 :     If the last form submission generated a message, $arg is returned. Otherwise, the
883 :     inverse of $arg is returned.
884 :    
885 :     The implementation in this package checks for the field $self->{message} to
886 :     determine if a message is present.
887 :    
888 :     If a subclass uses some other method to classify submission results, this method could be
889 :     redefined to handle that variance:
890 :    
891 :     sub if_message {
892 :     my ($self, $arg) = @_;
893 :    
894 :     my $status = $self->{processReturnValue};
895 :     if ($status != 0) {
896 :     return $arg;
897 :     } else {
898 :     return !$arg;
899 :     }
900 :     }
901 :    
902 :     =cut
903 :    
904 :     sub if_message {
905 :     my ($self, $arg) = @_;
906 :    
907 :     if (exists $self->{message}) {
908 :     return $arg;
909 :     } else {
910 :     return !$arg;
911 :     }
912 :     }
913 :    
914 : sh002i 1861 =item if_warnings
915 : sh002i 1131
916 : sh002i 1873 If warnings have been emitted while handling this request, $arg is returned.
917 :     Otherwise, the inverse of $arg is returned.
918 :    
919 :     The implementation in this package checks for a note in the request named
920 :     "warnings". This is set by the WARN handler in Apache::WeBWorK when a warning is
921 :     handled.
922 :    
923 : sh002i 1869 =cut
924 :    
925 : sh002i 1873 sub if_warnings {
926 : sh002i 1131 my ($self, $arg) = @_;
927 : sh002i 1873 my $r = $self->r;
928 :    
929 :     if ($r->notes("warnings")) {
930 :     return $arg;
931 :     } else {
932 :     !$arg;
933 :     }
934 : sh002i 1131 }
935 :    
936 : sh002i 1861 =back
937 : sh002i 1131
938 : sh002i 1861 =cut
939 :    
940 : sh002i 1873 ################################################################################
941 : malsyned 508
942 : sh002i 1873 =head1 HTML MACROS
943 : malsyned 508
944 : sh002i 1873 Various routines are defined in this package for rendering common WeBWorK
945 :     idioms.
946 :    
947 :     FIXME: some of these should be moved to WeBWorK::HTML:: modules!
948 :    
949 :     # ------------------------------------------------------------------------------
950 :    
951 :     =head2 Template escape handler macros
952 :    
953 :     These methods are used by implementations of the escape sequence handlers to
954 :     maintain a consistent style.
955 :    
956 :     =over
957 :    
958 :     =item pathMacro($args, @path)
959 :    
960 :     Helper macro for the C<#path> escape sequence: $args is a hash reference
961 :     containing the "style", "image", "text", and "textonly" arguments to the escape.
962 :     @path consists of ordered key-value pairs of the form:
963 :    
964 :     "Page Name" => URL
965 :    
966 :     If the page should not have a link associated with it, the URL should be left
967 :     empty. Authentication data is added to each URL so you don't have to. A fully-
968 :     formed path line is returned, suitable for returning by a function implementing
969 :     the C<#path> escape.
970 :    
971 :     FIXME: authentication data probably shouldn't be added here any more, now that
972 :     we have systemLink().
973 :    
974 :     =cut
975 :    
976 :     sub pathMacro {
977 :     my ($self, $args, @path) = @_;
978 :     my %args = %$args;
979 :     $args{style} = "text" if $args{textonly};
980 :    
981 :     my $auth = $self->url_authen_args;
982 :     my $sep;
983 :     if ($args{style} eq "image") {
984 :     $sep = CGI::img({-src=>$args{image}, -alt=>$args{text}});
985 :     } else {
986 :     $sep = $args{text};
987 :     }
988 :    
989 :     my @result;
990 :     while (@path) {
991 :     my $name = shift @path;
992 :     my $url = shift @path;
993 :     if ($url and not $args{textonly}) {
994 :     push @result, CGI::a({-href=>"$url?$auth"}, $name);
995 :     } else {
996 :     push @result, $name;
997 :     }
998 :     }
999 :    
1000 :     return join($sep, @result), "\n";
1001 :     }
1002 :    
1003 :     =item siblingsMacro(@siblings)
1004 :    
1005 :     Helper macro for the C<#siblings> escape sequence. @siblings consists of ordered
1006 :     key-value pairs of the form:
1007 :    
1008 :     "Sibling Name" => URL
1009 :    
1010 :     If the sibling should not have a link associated with it, the URL should be left
1011 :     empty. Authentication data is added to each URL so you don't have to. A fully-
1012 :     formed siblings block is returned, suitable for returning by a function
1013 :     implementing the C<#siblings> escape.
1014 :    
1015 :     FIXME: authentication data probably shouldn't be added here any more, now that
1016 :     we have systemLink().
1017 :    
1018 :     =cut
1019 :    
1020 :     sub siblingsMacro {
1021 :     my ($self, @siblings) = @_;
1022 :    
1023 :     my $auth = $self->url_authen_args;
1024 :     my $sep = CGI::br();
1025 :    
1026 :     my @result;
1027 :     while (@siblings) {
1028 :     my $name = shift @siblings;
1029 :     my $url = shift @siblings;
1030 :     push @result, $url
1031 :     ? CGI::a({-href=>"$url?$auth"}, $name)
1032 :     : $name;
1033 :     }
1034 :    
1035 :     return join($sep, @result) . "\n";
1036 :     }
1037 :    
1038 :     =item navMacro($args, $tail, @links)
1039 :    
1040 :     Helper macro for the C<#nav> escape sequence: $args is a hash reference
1041 :     containing the "style", "imageprefix", "imagesuffix", and "separator" arguments
1042 :     to the escape. @siblings consists of ordered tuples of the form:
1043 :    
1044 :     "Link Name", URL, ImageBaseName
1045 :    
1046 :     If the sibling should not have a link associated with it, the URL should be left
1047 :     empty. ImageBaseName is placed between the C<imageprefix> and C<imagesuffix>.
1048 :     Authentication data is added to each URL so you don't have to. $tail is appended
1049 :     to each URL, after the authentication information. A fully-formed nav line is
1050 :     returned, suitable for returning by a function implementing the C<#nav> escape.
1051 :    
1052 :     =cut
1053 :    
1054 :     sub navMacro {
1055 :     my ($self, $args, $tail, @links) = @_;
1056 :     my $r = $self->r;
1057 :     my $ce = $r->ce;
1058 :     my %args = %$args;
1059 :    
1060 :     my $auth = $self->url_authen_args;
1061 :     my $prefix = $ce->{webworkURLs}->{htdocs}."/images";
1062 :    
1063 :     my @result;
1064 :     while (@links) {
1065 :     my $name = shift @links;
1066 :     my $url = shift @links;
1067 :     my $img = shift @links;
1068 :     my $html =
1069 :     ($img && $args{style} eq "images")
1070 :     ? CGI::img(
1071 :     {src=>($prefix."/".$img.$args{imagesuffix}),
1072 :     border=>"",
1073 :     alt=>"$name"})
1074 :     : $name;
1075 :     unless($img && !$url) {
1076 :     push @result, $url
1077 :     ? CGI::a({-href=>"$url?$auth$tail"}, $html)
1078 :     : $html;
1079 :     }
1080 :     }
1081 :    
1082 :     return join($args{separator}, @result) . "\n";
1083 :     }
1084 :    
1085 :     =back
1086 :    
1087 :     =cut
1088 :    
1089 :     # ------------------------------------------------------------------------------
1090 :    
1091 :     =head2 Parameter management
1092 :    
1093 :     Methods for formatting request parameters as hidden form fields or query string
1094 :     fragments.
1095 :    
1096 :     =over
1097 :    
1098 :     =item hidden_fields(@fields)
1099 :    
1100 :     Return hidden <INPUT> tags for each field mentioned in @fields (or all fields if
1101 :     list is empty), taking data from the current request.
1102 :    
1103 :     =cut
1104 :    
1105 :     sub hidden_fields {
1106 :     my ($self, @fields) = @_;
1107 :     my $r = $self->r;
1108 :    
1109 :     @fields = $r->param unless @fields;
1110 :    
1111 :     my $html = "";
1112 :     foreach my $param (@fields) {
1113 :     my @values = $r->param($param);
1114 :     $html .= CGI::hidden($param, @values);
1115 :     }
1116 :     return $html;
1117 :     }
1118 :    
1119 :     =item hidden_authen_fields()
1120 :    
1121 :     Use hidden_fields to return hidden <INPUT> tags for request fields used in
1122 :     authentication.
1123 :    
1124 :     =cut
1125 :    
1126 :     sub hidden_authen_fields {
1127 :     my ($self) = @_;
1128 :    
1129 :     return $self->hidden_fields("user", "effectiveUser", "key");
1130 :     }
1131 :    
1132 :     =item url_args(@fields)
1133 :    
1134 :     Return a URL query string (without the leading `?') containing values for each
1135 :     field mentioned in @fields, or all fields if list is empty. Data is taken from
1136 :     the current request.
1137 :    
1138 :     =cut
1139 :    
1140 :     sub url_args {
1141 :     my ($self, @fields) = @_;
1142 :     my $r = $self->r;
1143 :    
1144 :     @fields = $r->param unless @fields;
1145 :    
1146 :     my @pairs;
1147 :     foreach my $param (@fields) {
1148 :     my @values = $r->param($param);
1149 :     foreach my $value (@values) {
1150 :     push @pairs, uri_escape($param) . "=" . uri_escape($value);
1151 :     }
1152 :     }
1153 :    
1154 :     return join("&", @pairs);
1155 :     }
1156 :    
1157 :     =item url_authen_args()
1158 :    
1159 :     Use url_args to return a URL query string for request fields used in
1160 :     authentication.
1161 :    
1162 :     =cut
1163 :    
1164 :     sub url_authen_args {
1165 :     my ($self) = @_;
1166 :    
1167 :     return $self->url_args("user", "effectiveUser", "key");
1168 :     }
1169 :    
1170 :     =item print_form_data($begin, $middle, $end, $omit)
1171 :    
1172 :     Return a string containing every request field not matched by the quoted reguar
1173 :     expression $omit, placing $begin before each field name, $middle between each
1174 :     field name and its value, and $end after each value. Values are taken from the
1175 :     current request.
1176 :    
1177 :     =cut
1178 :    
1179 :     sub print_form_data {
1180 :     my ($self, $begin, $middle, $end, $qr_omit) = @_;
1181 :     my $r=$self->r;
1182 :     my @form_data = $r->param;
1183 :    
1184 :     my $return_string = "";
1185 :     foreach my $name (@form_data) {
1186 :     next if ($qr_omit and $name =~ /$qr_omit/);
1187 :     my @values = $r->param($name);
1188 :     foreach my $variable (qw(begin name middle value end)) {
1189 :     # FIXME: can this loop be moved out of the enclosing loop?
1190 :     no strict 'refs';
1191 :     ${$variable} = "" unless defined ${$variable};
1192 :     }
1193 :     foreach my $value (@values) {
1194 :     $return_string .= "$begin$name$middle$value$end";
1195 :     }
1196 :     }
1197 :    
1198 :     return $return_string;
1199 :     }
1200 :    
1201 :     =back
1202 :    
1203 :     =cut
1204 :    
1205 :     # ------------------------------------------------------------------------------
1206 :    
1207 :     =head2 Utilities
1208 :    
1209 :     =over
1210 :    
1211 :     =item systemLink($urlpath, %options)
1212 :    
1213 :     Generate a link to another part of the system. $urlpath is WeBWorK::URLPath
1214 :     object from which the base path will be taken. %options can consist of:
1215 :    
1216 :     =over
1217 :    
1218 : sh002i 1882 =item params
1219 : sh002i 1873
1220 : sh002i 1911 Can be either a reference to an array or a reference to a hash.
1221 : sh002i 1873
1222 : sh002i 1911 If it is a reference to a hash, it maps parmaeter names to values. These
1223 :     parameters will be included in the generated link. If a value is an arrayref,
1224 :     the values of the array referenced will be used. If a value is undefined, the
1225 :     value from the current request will be used.
1226 : sh002i 1873
1227 : sh002i 1911 If C<params> is an arrayref, it is interpreted as a list of parameter names.
1228 :     These parameters will be included in the generated link, using the values from
1229 :     the current request.
1230 : sh002i 1873
1231 : sh002i 1911 Unless C<authen> is false (see below), the authentication parameters (C<user>,
1232 :     C<effectiveUser>, and C<key>) are included with their default values.
1233 : sh002i 1898
1234 : sh002i 1882 =item authen
1235 : sh002i 1873
1236 : sh002i 1911 If set to a false value, the authentication parameters (C<user>,
1237 :     C<effectiveUser>, and C<key>) are included in the the generated link unless
1238 :     explicitly listed in C<params>.
1239 : sh002i 1873
1240 :     =back
1241 :    
1242 :     =cut
1243 :    
1244 : sh002i 1882 # FIXME: there should probably be an option for prepending "http://hostname:port"
1245 : sh002i 1873 sub systemLink {
1246 :     my ($self, $urlpath, %options) = @_;
1247 :     my $r = $self->r;
1248 :    
1249 : sh002i 1911 my %params = ();
1250 : sh002i 1882 if (exists $options{params}) {
1251 : sh002i 1911 if (ref $options{params} eq "HASH") {
1252 :     %params = %{ $options{params} };
1253 :     } elsif (ref $options{params} eq "ARRAY") {
1254 :     my @names = @{ $options{params} };
1255 :     @params{@names} = ();
1256 :     } else {
1257 :     croak "option 'params' is not a hashref or an arrayref";
1258 :     }
1259 : sh002i 1882 }
1260 : sh002i 1873
1261 : sh002i 1893 my $authen = exists $options{authen} ? $options{authen} : 1;
1262 : sh002i 1911 if ($authen) {
1263 :     $params{user} = undef unless exists $params{user};
1264 :     $params{effectiveUser} = undef unless exists $params{effectiveUser};
1265 :     $params{key} = undef unless exists $params{key};
1266 : sh002i 1882 }
1267 :    
1268 : sh002i 1873 my $url = $r->location . $urlpath->path;
1269 : sh002i 1911 my $first = 1;
1270 : sh002i 1873
1271 : sh002i 1911 foreach my $name (keys %params) {
1272 :     my $value = $params{$name};
1273 :    
1274 :     my @values;
1275 :     if (defined $value) {
1276 :     if (ref $value eq "ARRAY") {
1277 :     @values = @$value;
1278 :     } else {
1279 :     @values = $value;
1280 :     }
1281 :     } elsif (defined $r->param($name)) {
1282 :     @values = $r->param($name);
1283 :     }
1284 :    
1285 :     if (@values) {
1286 :     if ($first) {
1287 :     $url .= "?";
1288 :     $first = 0;
1289 :     } else {
1290 :     $url .= "&";
1291 :     }
1292 :     $url .= join "&", map { "$name=$_" } @values;
1293 :     }
1294 : sh002i 1873 }
1295 :    
1296 :     return $url;
1297 :     }
1298 :    
1299 :     =item nbsp($string)
1300 :    
1301 :     If string consists of only whitespace, the HTML entity C<&nbsp;> is returned.
1302 :     Otherwise $string is returned.
1303 :    
1304 :     =cut
1305 :    
1306 :     sub nbsp {
1307 :     my $self = shift;
1308 :     my $str = shift;
1309 : sh002i 1974 (defined $str && $str =~/\S/) ? $str : '&nbsp;';
1310 : sh002i 1873 }
1311 :    
1312 :     =item errorOutput($error, $details)
1313 :    
1314 :     =cut
1315 :    
1316 :     sub errorOutput($$$) {
1317 :     my ($self, $error, $details) = @_;
1318 :     return
1319 :     CGI::h3("Software Error"),
1320 :     CGI::p(<<EOF),
1321 :     WeBWorK has encountered a software error while attempting to process this
1322 :     problem. It is likely that there is an error in the problem itself. If you are
1323 :     a student, contact your professor to have the error corrected. If you are a
1324 :     professor, please consut the error output below for more informaiton.
1325 :     EOF
1326 :     # FIXME: this message shouldn't refer the the "problem" since it is for general error reporting
1327 :     CGI::h3("Error messages"), CGI::p(CGI::tt($error)),
1328 :     CGI::h3("Error context"), CGI::p(CGI::tt($details));
1329 :     }
1330 :    
1331 :     =item warningOutput($warnings)
1332 :    
1333 :     =cut
1334 :    
1335 :     sub warningOutput($$) {
1336 :     my ($self, $warnings) = @_;
1337 :    
1338 :     my @warnings = split m/\n+/, $warnings;
1339 :    
1340 :     return
1341 :     CGI::h3("Software Warnings"),
1342 :     CGI::p(<<EOF),
1343 :     WeBWorK has encountered warnings while attempting to process this problem. It
1344 :     is likely that this indicates an error or ambiguity in the problem itself. If
1345 :     you are a student, contact your professor to have the problem corrected. If you
1346 :     are a professor, please consut the warning output below for more informaiton.
1347 :     EOF
1348 :     # FIXME: this message shouldn't refer the the "problem" since it is for general warning reporting
1349 :     CGI::h3("Warning messages"),
1350 :     CGI::ul(CGI::li(\@warnings));
1351 :     }
1352 :    
1353 :     =back
1354 :    
1355 : malsyned 508 =head1 AUTHOR
1356 :    
1357 : sh002i 1873 Written by Dennis Lambe Jr., malsyned (at) math.rochester.edu and Sam Hathaway,
1358 :     sh002i (at) math.rochester.edu.
1359 : malsyned 508
1360 :     =cut
1361 : sh002i 1873
1362 :     1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9