[system] / trunk / webwork2 / lib / WeBWorK / ContentGenerator.pm Repository:
ViewVC logotype

Annotation of /trunk/webwork2/lib/WeBWorK/ContentGenerator.pm

Parent Directory Parent Directory | Revision Log Revision Log


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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9