[system] / branches / rel-2-1-a1 / webwork2 / lib / WeBWorK / ContentGenerator.pm Repository:
ViewVC logotype

Annotation of /branches/rel-2-1-a1/webwork2/lib/WeBWorK/ContentGenerator.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1893 - (view) (download) (as text)
Original Path: trunk/webwork2/lib/WeBWorK/ContentGenerator.pm

1 : sh002i 455 ################################################################################
2 : sh002i 1663 # WeBWorK Online Homework Delivery System
3 :     # Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/
4 : sh002i 1893 # $CVSHeader: webwork-modperl/lib/WeBWorK/ContentGenerator.pm,v 1.86 2004/03/15 04:09:56 sh002i 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 : malsyned 323 use Apache::Constants qw(:common);
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 1873 =item 3
112 : sh002i 1861
113 : sh002i 1873 At this point, go() will terminate if the request is a HEAD request or if the
114 :     field $self->{noContent} contains a true value.
115 : sh002i 1861
116 : sh002i 1873 =item 4
117 : sh002i 1861
118 : sh002i 1873 If the field $self->{sendFile} is defined, the method sendFile() is called to
119 :     send the specified file to the client, and go() terminates. See below.
120 : sh002i 1861
121 : sh002i 1873 =item 5
122 : sh002i 1861
123 : sh002i 1873 go() then attempts to call the method initialize(). This method may be
124 :     implemented in subclasses which must do processing after the HTTP header is sent
125 :     but before any content is sent.
126 : sh002i 1861
127 : sh002i 1873 =item 6
128 :    
129 :     The method content() is called to send the page content to client.
130 :    
131 : sh002i 1861 =back
132 :    
133 :     =cut
134 :    
135 : sh002i 469 sub go {
136 : sh002i 1873 my ($self) = @_;
137 :     my $r = $self->r;
138 : sh002i 1869 my $ce = $r->ce;
139 :    
140 : malsyned 1408 my $returnValue = OK;
141 : sh002i 1131
142 : sh002i 469 $self->pre_header_initialize(@_) if $self->can("pre_header_initialize");
143 : sh002i 1873
144 : malsyned 1408 my $headerReturn = $self->header(@_);
145 :     $returnValue = $headerReturn if defined $headerReturn;
146 :     return $returnValue if $r->header_only or $self->{noContent};
147 : malsyned 313
148 : sh002i 1613 # if the sendFile flag is set, send the file and exit;
149 :     if ($self->{sendFile}) {
150 :     return $self->sendFile;
151 :     }
152 :    
153 : sh002i 1873 $self->initialize() if $self->can("initialize");
154 : sh002i 1225
155 : sh002i 1873 $self->content();
156 : malsyned 1408
157 :     return $returnValue;
158 : sh002i 469 }
159 :    
160 : sh002i 1861 =item sendFile()
161 :    
162 : sh002i 1873 Sends the file specified in $self->{sendFile} to the client. $self->{sendFile}
163 :     should be a reference to a hash containing the following fields:
164 :    
165 :     source => full path to the file to send
166 :     type => the content type of the file
167 :     name => the name that the client should give to the file upon download
168 :    
169 :     This method is called internally by go() if the field $self->{sendFile} is
170 :     present.
171 :    
172 :     This mechanism relies on the header() method to send appropriate C<Content-Type>
173 :     and C<Content-Disposition> headers.
174 :    
175 :     This mechanism is fragile and will probably be replaced by something else in the
176 :     future.
177 :    
178 : sh002i 1861 =cut
179 :    
180 : sh002i 1613 sub sendFile {
181 :     my ($self) = @_;
182 :    
183 :     my $file = $self->{sendFile}->{source};
184 :    
185 :     return NOT_FOUND unless -e $file;
186 :     return FORBIDDEN unless -r $file;
187 :    
188 :     open my $fh, "<", $file
189 :     or return SERVER_ERROR;
190 :     while (<$fh>) {
191 :     print $_;
192 :     }
193 :     close $fh;
194 :    
195 :     return OK;
196 :     }
197 :    
198 : sh002i 1873 =item r()
199 : sh002i 1861
200 : sh002i 1873 Returns a reference to the WeBWorK::Request object associated with this
201 :     instance.
202 : sh002i 1861
203 :     =cut
204 :    
205 : sh002i 1873 sub r {
206 :     my ($self) = @_;
207 : sh002i 1869
208 : sh002i 1873 return $self->{r};
209 : sh002i 469 }
210 :    
211 : sh002i 1873 =back
212 : sh002i 1861
213 :     =cut
214 :    
215 : sh002i 1873 ################################################################################
216 : sh002i 469
217 : sh002i 1873 =head1 STANDARD METHODS
218 : sh002i 1861
219 : sh002i 1873 The following are the standard content generator methods. Some are defined here,
220 :     but may be overridden in a subclass. Others are not defined unless they are
221 :     defined in a subclass.
222 : sh002i 1861
223 : sh002i 1873 =over
224 : sh002i 469
225 : sh002i 1873 =item pre_header_initialize()
226 : sh002i 1861
227 : sh002i 1873 Not defined in this package.
228 : sh002i 1861
229 : sh002i 1873 May be defined by a subclass to perform any processing that must occur before
230 :     the HTTP header is sent.
231 :    
232 : sh002i 1861 =cut
233 :    
234 : sh002i 1873 #sub pre_header_initialize { }
235 : malsyned 323
236 : sh002i 1873 =item header()
237 : sh002i 1861
238 : sh002i 1873 Defined in this package.
239 : sh002i 1861
240 : sh002i 1873 Generates and sends a default HTTP header. If the field $self->{sendFile} is
241 :     present, sends the following headers (where TYPE is $self->{sendFile}->{type}
242 :     and NAME is $self->{sendFile}->{name}):
243 : sh002i 1861
244 : sh002i 1873 Content-Type: TYPE
245 :     Content-Disposition: attachment; filename=NAME
246 : sh002i 425
247 : sh002i 1873 If $self->{sendFile} is not present, sends the following headers:
248 : sh002i 1861
249 : sh002i 1873 Content-Type: text/html
250 : sh002i 1861
251 : sh002i 1873 See sendFile() above for more information on the sendFile mechanism.
252 :    
253 : sh002i 1861 =cut
254 :    
255 : sh002i 1873 sub header {
256 : sh002i 425 my $self = shift;
257 : sh002i 1873 my $r = $self->r;
258 : sh002i 425
259 : sh002i 1873 if ($self->{sendFile}) {
260 :     my $contentType = $self->{sendFile}->{type};
261 :     my $fileName = $self->{sendFile}->{name};
262 :     $r->content_type($contentType);
263 :     $r->header_out("Content-Disposition" => "attachment; filename=\"$fileName\"");
264 :     } else {
265 :     $r->content_type("text/html");
266 :    
267 : sh002i 425 }
268 : sh002i 469
269 : sh002i 1873 $r->send_http_header();
270 :     return OK;
271 : sh002i 425 }
272 :    
273 : sh002i 1873 =item initialize()
274 : sh002i 1861
275 : sh002i 1873 Not defined in this package.
276 : sh002i 1861
277 : sh002i 1873 May be defined by a subclass to perform any processing that must occur after the
278 :     HTTP header is sent but before any content is sent.
279 : sh002i 1861
280 :     =cut
281 :    
282 : sh002i 1873 #sub initialize { }
283 : sh002i 1861
284 : sh002i 1873 =item content()
285 : sh002i 1861
286 : sh002i 1873 Defined in this package.
287 : sh002i 1861
288 : sh002i 1873 Print the content of the generated page.
289 : sh002i 1861
290 : sh002i 1873 The implementation in this package uses WeBWorK::Template to define the content
291 :     of the page. See WeBWorK::Template for details.
292 : malsyned 390
293 : sh002i 1873 If a method named templateName() exists, it it called to determine the name of
294 :     the template to use. If not, the default template, "system", is used. The
295 :     location of the template is looked up in the course environment.
296 : sh002i 1861
297 :     =cut
298 :    
299 : sh002i 1873 sub content {
300 :     my ($self) = @_;
301 :     my $ce = $self->r->ce;
302 : sh002i 737
303 : sh002i 1873 # if the content generator specifies a custom template name, use that
304 :     # field in the $ce->{templates} hash instead of "system" if it exists.
305 :     my $templateName;
306 :     if ($self->can("templateName")) {
307 :     $templateName = $self->templateName;
308 :     } else {
309 :     $templateName = "system";
310 :     }
311 :     $templateName = "system" unless exists $ce->{templates}->{$templateName};
312 :     template($ce->{templates}->{$templateName}, $self);
313 : sh002i 737 }
314 :    
315 : sh002i 1861 =back
316 :    
317 :     =cut
318 :    
319 : sh002i 1873 # ------------------------------------------------------------------------------
320 : sh002i 1866
321 : sh002i 1873 =head2 Template escape handlers
322 : sh002i 1866
323 : sh002i 1873 Template escape handlers are invoked when the template processor encounters a
324 :     matching escape sequence in the template. The escapse sequence's arguments are
325 :     passed to the methods as a reference to a hash.
326 : sh002i 1866
327 : sh002i 1873 For more information, refer to WeBWorK::Template.
328 : malsyned 390
329 : sh002i 1873 The following template escapes handlers are defined here or may be defined in
330 :     subclasses. For methods that are not defined in this package, the documentation
331 :     defines the interface and behavior that any subclass implementation must follow.
332 : malsyned 313
333 : sh002i 1861 =over
334 :    
335 : sh002i 1873 =item head()
336 : sh002i 1861
337 : sh002i 1873 Not defined in this package.
338 : sh002i 1861
339 : sh002i 1873 Any tags that should appear in the HEAD of the document.
340 : sh002i 1861
341 :     =cut
342 :    
343 : sh002i 1873 #sub head { }
344 : malsyned 349
345 : sh002i 1873 =item info()
346 : sh002i 682
347 : sh002i 1873 Not defined in this package.
348 : sh002i 1861
349 : sh002i 1873 Auxiliary information related to the content displayed in the C<body>.
350 : sh002i 1861
351 : sh002i 1873 =cut
352 : sh002i 1861
353 : sh002i 1873 #sub info { }
354 : sh002i 1861
355 : sh002i 1873 =item links()
356 : sh002i 1861
357 : sh002i 1873 Defined in this package.
358 : sh002i 1861
359 : sh002i 1873 Links that should appear on every page.
360 : sh002i 1861
361 :     =cut
362 :    
363 : sh002i 1866 sub links {
364 :     my ($self) = @_;
365 : sh002i 1873 my $r = $self->r;
366 : sh002i 1866 my $db = $r->db;
367 :     my $urlpath = $r->urlpath;
368 :    
369 :     # we're linking to other places in the same course, so grab the courseID from the current path
370 :     my $courseID = $urlpath->arg("courseID");
371 :    
372 :     # to make things more concise
373 :     my %args = ( courseID => $courseID );
374 :     my $pfx = "WeBWorK::ContentGenerator::";
375 :    
376 : sh002i 1880 my $sets = $urlpath->newFromModule("${pfx}ProblemSets", %args);
377 :     my $options = $urlpath->newFromModule("${pfx}Options", %args);
378 :     my $grades = $urlpath->newFromModule("${pfx}Grades", %args);
379 :     my $logout = $urlpath->newFromModule("${pfx}Logout", %args);
380 :    
381 :     print "\n<!-- BEGIN " . __PACKAGE__ . "::links -->\n";
382 :     print CGI::start_ul({class=>"LinksMenu"});
383 :     print CGI::li(CGI::span({style=>"font-size:larger"},
384 :     CGI::a({href=>$self->systemLink($sets)}, "Problem Sets")));
385 :     print CGI::li(CGI::a({href=>$self->systemLink($options)}, $options->name));
386 :     print CGI::li(CGI::a({href=>$self->systemLink($grades)}, $grades->name));
387 :     print CGI::li(CGI::a({href=>$self->systemLink($logout)}, $logout->name));
388 :    
389 : sh002i 1866 my $PermissionLevel = $db->getPermissionLevel($r->param("user")); # checked
390 :     my $permLevel = $PermissionLevel ? $PermissionLevel->permission : 0;
391 :    
392 :     if ($permLevel > 0) {
393 :     my $ipfx = "${pfx}Instructor::";
394 :    
395 :     my $userID = $r->param("effectiveUser");
396 :     my $setID = $urlpath->arg("setID");
397 :     my $problemID = $urlpath->arg("problemID");
398 :    
399 :     my $instr = $urlpath->newFromModule("${ipfx}Index", %args);
400 :     my $userList = $urlpath->newFromModule("${ipfx}UserList", %args);
401 :    
402 :     # set list links
403 :     my $setList = $urlpath->newFromModule("${ipfx}ProblemSetList", %args);
404 :     my $setDetail = $urlpath->newFromModule("${ipfx}ProblemSetEditor", %args, setID => $setID);
405 :     my $problemEditor = $urlpath->newFromModule("${ipfx}PGProblemEditor", %args, setID => $setID, problemID => $problemID);
406 :    
407 :     my $mail = $urlpath->newFromModule("${ipfx}SendMail", %args);
408 :     my $scoring = $urlpath->newFromModule("${ipfx}Scoring", %args);
409 :    
410 :     # statistics links
411 :     my $stats = $urlpath->newFromModule("${ipfx}Stats", %args);
412 :     my $userStats = $urlpath->newFromModule("${ipfx}Stats", %args, statType => "student", userID => $userID);
413 :     my $setStats = $urlpath->newFromModule("${ipfx}Stats", %args, statType => "set", setID => $setID);
414 :    
415 :     my $files = $urlpath->newFromModule("${ipfx}FileXfer", %args);
416 :    
417 : sh002i 1880 print CGI::start_li();
418 :     print CGI::span({style=>"font-size:larger"}, CGI::a({href=>$self->systemLink($instr)}, $instr->name));
419 :     print CGI::start_ul();
420 :     print CGI::li(CGI::a({href=>$self->systemLink($userList)}, $userList->name));
421 :     print CGI::start_li();
422 :     print CGI::a({href=>$self->systemLink($setList)}, $setList->name);
423 : sh002i 1869 if (defined $setID and $setID ne "") {
424 : sh002i 1880 print CGI::start_ul();
425 :     print CGI::start_li();
426 :     print CGI::a({href=>$self->systemLink($setDetail)}, $setID);
427 : sh002i 1869 if (defined $problemID and $problemID ne "") {
428 : sh002i 1880 print CGI::ul(
429 : sh002i 1866 CGI::li(CGI::a({href=>$self->systemLink($problemEditor)}, $problemID))
430 :     );
431 :     }
432 : sh002i 1880 print CGI::end_li();
433 :     print CGI::end_ul();
434 : sh002i 1866 }
435 : sh002i 1880 print CGI::end_li();
436 :     print CGI::li(CGI::a({href=>$self->systemLink($mail)}, $mail->name));
437 :     print CGI::li(CGI::a({href=>$self->systemLink($scoring)}, $scoring->name));
438 :     print CGI::start_li();
439 :     print CGI::a({href=>$self->systemLink($stats)}, $stats->name);
440 : sh002i 1869 if (defined $userID and $userID ne "") {
441 : sh002i 1880 print CGI::ul(
442 : sh002i 1866 CGI::li(CGI::a({href=>$self->systemLink($userStats)}, $userID))
443 :     );
444 :     }
445 : sh002i 1869 if (defined $setID and $setID ne "") {
446 : sh002i 1880 print CGI::ul(
447 : sh002i 1866 CGI::li(CGI::a({href=>$self->systemLink($setStats)}, $setID))
448 :     );
449 :     }
450 : sh002i 1880 print CGI::end_li();
451 :     print CGI::li(CGI::a({href=>$self->systemLink($files)}, $files->name));
452 :     print CGI::end_ul();
453 :     print CGI::end_li();
454 : sh002i 1866 }
455 :    
456 : sh002i 1880 print CGI::end_ul();
457 :     print "<!-- end " . __PACKAGE__ . "::links -->\n";
458 : sh002i 1866
459 : sh002i 1880 return "";
460 : sh002i 1866 }
461 :    
462 : sh002i 1873 =item loginstatus()
463 : sh002i 1861
464 : sh002i 1873 Defined in this package.
465 : sh002i 1861
466 : sh002i 1873 Print a notification message announcing the current real user and effective
467 :     user, a link to stop acting as the effective user, and a link to logout.
468 : sh002i 1861
469 :     =cut
470 :    
471 :     sub loginstatus {
472 : sh002i 1869 my ($self) = @_;
473 : sh002i 1873 my $r = $self->r;
474 : sh002i 1869 my $urlpath = $r->urlpath;
475 : sh002i 1861
476 :     my $key = $r->param("key");
477 :    
478 : sh002i 1869 if ($key) {
479 :     my $courseID = $urlpath->arg("courseID");
480 :     my $userID = $r->param("user");
481 :     my $eUserID = $r->param("effectiveUser");
482 :    
483 : sh002i 1882 my $stopActingURL = $self->systemLink($urlpath, # current path
484 :     values => {
485 :     effectiveUser => $userID,
486 :     },
487 :     );
488 : sh002i 1869 my $logoutURL = $self->systemLink($urlpath->newFromModule(__PACKAGE__ . "::Logout", courseID => $courseID));
489 :    
490 : sh002i 1880 print "\n<!-- BEGIN " . __PACKAGE__ . "::loginstatus -->\n";
491 :    
492 : sh002i 1869 print "Logged in as $userID. ";
493 :     print CGI::a({href=>$logoutURL}, "Log Out");
494 :    
495 :     if ($eUserID ne $userID) {
496 :     print " | Acting as $eUserID. ";
497 :     print CGI::a({href=>$stopActingURL}, "Stop Acting");
498 :     }
499 : sh002i 1880
500 :     print "<!-- END " . __PACKAGE__ . "::loginstatus -->\n";
501 : sh002i 1861 }
502 :    
503 :     return "";
504 :     }
505 :    
506 : sh002i 1873 =item nav($args)
507 : sh002i 1869
508 : sh002i 1873 Not defined in this package.
509 : sh002i 1861
510 : sh002i 1873 Links to the previous, next, and parent objects.
511 : sh002i 1861
512 : sh002i 1873 $args is a reference to a hash containing the following fields:
513 :    
514 : sh002i 1861 style => text|image
515 :     imageprefix => prefix to prepend to base image URL
516 :     imagesuffix => suffix to append to base image URL
517 :     separator => HTML to place in between links
518 :    
519 : sh002i 1873 If C<style> is "image", image URLs are constructed by prepending C<imageprefix>
520 :     and postpending C<imagesuffix> to the image base names defined by the
521 :     implementor. (Examples of base names include "Prev", "Next", "ProbSet", and
522 :     "Up"). Each concatenated string should form an absolute URL to an image file.
523 :     For example:
524 : sh002i 1861
525 : sh002i 1873 <!--#nav style="images" imageprefix="/webwork2_files/images/nav"
526 :     imagesuffix=".gif" separator=" "-->
527 : sh002i 1861
528 : sh002i 1873 =cut
529 : sh002i 1861
530 : sh002i 1873 #sub nav { }
531 : sh002i 1861
532 : sh002i 1873 =item options()
533 :    
534 :     Not defined in this package.
535 :    
536 :     Print an auxiliary options form, related to the content displayed in the
537 :     C<body>.
538 :    
539 :     =item path($args)
540 :    
541 :     Defined in this package.
542 :    
543 :     Print "breadcrubs" from the root of the virtual hierarchy to the current page.
544 :     $args is a reference to a hash containing the following fields:
545 :    
546 : sh002i 1861 style => type of separator: text|image
547 : sh002i 1873 image => if style=image, URL of image to use as path separator
548 :     text => if style=text, text to use as path separator
549 :     if style=image, the ALT text of each separator image
550 :     textonly => suppress all HTML, return only plain text
551 : sh002i 1861
552 : sh002i 1873 The implementation in this package takes information from the WeBWorK::URLPath
553 :     associated with the current request.
554 :    
555 : sh002i 1861 =cut
556 :    
557 :     sub path {
558 :     my ($self, $args) = @_;
559 : sh002i 1873 my $r = $self->r;
560 : sh002i 1861
561 :     my @path;
562 :    
563 :     my $urlpath = $r->urlpath;
564 :     do {
565 :     unshift @path, $urlpath->name, $r->location . $urlpath->path;
566 :     } while ($urlpath = $urlpath->parent);
567 :    
568 :     $path[$#path] = ""; # we don't want the last path element to be a link
569 :    
570 : sh002i 1882 #print "\n<!-- BEGIN " . __PACKAGE__ . "::path -->\n";
571 : sh002i 1880 print $self->pathMacro($args, @path);
572 : sh002i 1882 #print "<!-- END " . __PACKAGE__ . "::path -->\n";
573 : sh002i 1880
574 :     return "";
575 : sh002i 1861 }
576 :    
577 : sh002i 1873 =item siblings()
578 : sh002i 1861
579 : sh002i 1873 Not defined in this package.
580 : sh002i 1861
581 : sh002i 1873 Print links to siblings of the current object.
582 : sh002i 1861
583 : sh002i 1873 =cut
584 : sh002i 1861
585 : sh002i 1873 #sub siblings { }
586 :    
587 :     =item submiterror()
588 :    
589 :     Defined in this package.
590 :    
591 :     Print any error messages resulting from the last form submission.
592 :    
593 :     The implementation in this package prints the value of the field
594 :     $self->{submitError}, if it is present.
595 :    
596 : sh002i 1861 =cut
597 :    
598 :     sub submiterror {
599 :     my ($self) = @_;
600 : sh002i 1880
601 :     print "\n<!-- BEGIN " . __PACKAGE__ . "::submiterror -->\n";
602 :     print $self->{submitError} if exists $self->{submitError};
603 :     print "<!-- END " . __PACKAGE__ . "::submiterror -->\n";
604 :    
605 :     return "";
606 : sh002i 1861 }
607 :    
608 : sh002i 1873 =item title()
609 : sh002i 1861
610 : sh002i 1873 Defined in this package.
611 : sh002i 1861
612 : sh002i 1873 Print the title of the current page.
613 :    
614 :     The implementation in this package takes information from the WeBWorK::URLPath
615 :     associated with the current request.
616 :    
617 : sh002i 1861 =cut
618 :    
619 :     sub title {
620 :     my ($self, $args) = @_;
621 : sh002i 1873 my $r = $self->r;
622 : sh002i 1861
623 : sh002i 1880
624 : sh002i 1882 #print "\n<!-- BEGIN " . __PACKAGE__ . "::title -->\n";
625 : sh002i 1880 print $r->urlpath->name;
626 : sh002i 1882 #print "<!-- END " . __PACKAGE__ . "::title -->\n";
627 : sh002i 1880
628 :     return "";
629 : sh002i 1861 }
630 :    
631 : sh002i 1873 =item warnings()
632 : sh002i 1861
633 : sh002i 1873 Defined in this package.
634 : sh002i 1861
635 : sh002i 1873 Print accumulated warnings.
636 :    
637 :     The implementation in this package checks for a note in the request named
638 :     "warnings". If present, its contents are formatted and returned.
639 :    
640 : sh002i 1861 =cut
641 :    
642 :     sub warnings {
643 :     my ($self) = @_;
644 : sh002i 1873 my $r = $self->r;
645 : sh002i 1880
646 :     print "\n<!-- BEGIN " . __PACKAGE__ . "::warnings -->\n";
647 :     print $self->warningOutput($r->notes("warnings")) if $r->notes("warnings");
648 :     print "<!-- END " . __PACKAGE__ . "::warnings -->\n";
649 :    
650 :     return "";
651 : sh002i 1861 }
652 :    
653 :     =back
654 :    
655 : sh002i 1873 =cut
656 : sh002i 1861
657 : sh002i 1873 # ------------------------------------------------------------------------------
658 : sh002i 1861
659 : sh002i 1873 =head2 Conditional predicates
660 :    
661 :     Conditional predicate methods are invoked when the C<#if> escape sequence is
662 :     encountered in the template. If a method named C<if_predicate> is defined in
663 :     here or in the instantiated subclass, it is invoked.
664 :    
665 : sh002i 1861 The following predicates are currently defined:
666 :    
667 :     =over
668 :    
669 : sh002i 1873 =item if_can($function)
670 : sh002i 1861
671 : sh002i 1873 If a function named $function is present in the current content generator (or
672 :     any superclass), a true value is returned. Otherwise, a false value is returned.
673 : sh002i 1861
674 : sh002i 1873 The implementation in this package uses the method UNIVERSAL->can(function) to
675 :     arrive at the result.
676 :    
677 :     A subclass could redefine this method to, for example, "hide" a method from the
678 :     template:
679 :    
680 :     sub if_can {
681 :     my ($self, $arg) = @_;
682 :    
683 :     if ($arg eq "floobar") {
684 :     return 0;
685 :     } else {
686 :     return $self->SUPER::if_can($arg);
687 :     }
688 :     }
689 :    
690 : sh002i 1861 =cut
691 :    
692 : sh002i 1873 sub if_can {
693 :     my ($self, $arg) = @_;
694 : malsyned 525
695 : sh002i 1873 return $self->can($arg) ? 1 : 0;
696 : malsyned 525 }
697 :    
698 : sh002i 1873 =item if_loggedin($arg)
699 : sh002i 1861
700 : sh002i 1873 If the user is currently logged in, $arg is returned. Otherwise, the inverse of
701 :     $arg is returned.
702 : sh002i 1861
703 : sh002i 1873 The implementation in this package always returns $arg, since most content
704 :     generators are only reachable when the user is authenticated. It is up to
705 :     classes that can be reached without logging in to override this method and
706 :     provide the correct behavior.
707 :    
708 :     This is suboptimal, and may change in the future.
709 :    
710 : sh002i 1861 =cut
711 :    
712 : sh002i 1873 sub if_loggedin {
713 :     my ($self, $arg) = @_;
714 : malsyned 748
715 :     return $arg;
716 :     }
717 :    
718 : sh002i 1873 =item if_submiterror($arg)
719 : sh002i 1131
720 : sh002i 1873 If the last form submission generated an error, $arg is returned. Otherwise, the
721 :     inverse of $arg is returned.
722 :    
723 :     The implementation in this package checks for the field $self->{submitError} to
724 :     determine if an error condition is present.
725 :    
726 :     If a subclass uses some other method to classify submission results, this method could be
727 :     redefined to handle that variance:
728 :    
729 :     sub if_submiterror {
730 :     my ($self, $arg) = @_;
731 :    
732 :     my $status = $self->{processReturnValue};
733 :     if ($status != 0) {
734 :     return $arg;
735 :     } else {
736 :     return !$arg;
737 :     }
738 :     }
739 :    
740 : sh002i 1861 =cut
741 :    
742 : sh002i 1873 sub if_submiterror {
743 : malsyned 1017 my ($self, $arg) = @_;
744 : sh002i 1873
745 : malsyned 1017 if (exists $self->{submitError}) {
746 :     return $arg;
747 :     } else {
748 :     return !$arg;
749 :     }
750 :     }
751 :    
752 : sh002i 1861 =item if_warnings
753 : sh002i 1131
754 : sh002i 1873 If warnings have been emitted while handling this request, $arg is returned.
755 :     Otherwise, the inverse of $arg is returned.
756 :    
757 :     The implementation in this package checks for a note in the request named
758 :     "warnings". This is set by the WARN handler in Apache::WeBWorK when a warning is
759 :     handled.
760 :    
761 : sh002i 1869 =cut
762 :    
763 : sh002i 1873 sub if_warnings {
764 : sh002i 1131 my ($self, $arg) = @_;
765 : sh002i 1873 my $r = $self->r;
766 :    
767 :     if ($r->notes("warnings")) {
768 :     return $arg;
769 :     } else {
770 :     !$arg;
771 :     }
772 : sh002i 1131 }
773 :    
774 : sh002i 1861 =back
775 : sh002i 1131
776 : sh002i 1861 =cut
777 :    
778 : sh002i 1873 ################################################################################
779 : malsyned 508
780 : sh002i 1873 =head1 HTML MACROS
781 : malsyned 508
782 : sh002i 1873 Various routines are defined in this package for rendering common WeBWorK
783 :     idioms.
784 :    
785 :     FIXME: some of these should be moved to WeBWorK::HTML:: modules!
786 :    
787 :     # ------------------------------------------------------------------------------
788 :    
789 :     =head2 Template escape handler macros
790 :    
791 :     These methods are used by implementations of the escape sequence handlers to
792 :     maintain a consistent style.
793 :    
794 :     =over
795 :    
796 :     =item pathMacro($args, @path)
797 :    
798 :     Helper macro for the C<#path> escape sequence: $args is a hash reference
799 :     containing the "style", "image", "text", and "textonly" arguments to the escape.
800 :     @path consists of ordered key-value pairs of the form:
801 :    
802 :     "Page Name" => URL
803 :    
804 :     If the page should not have a link associated with it, the URL should be left
805 :     empty. Authentication data is added to each URL so you don't have to. A fully-
806 :     formed path line is returned, suitable for returning by a function implementing
807 :     the C<#path> escape.
808 :    
809 :     FIXME: authentication data probably shouldn't be added here any more, now that
810 :     we have systemLink().
811 :    
812 :     =cut
813 :    
814 :     sub pathMacro {
815 :     my ($self, $args, @path) = @_;
816 :     my %args = %$args;
817 :     $args{style} = "text" if $args{textonly};
818 :    
819 :     my $auth = $self->url_authen_args;
820 :     my $sep;
821 :     if ($args{style} eq "image") {
822 :     $sep = CGI::img({-src=>$args{image}, -alt=>$args{text}});
823 :     } else {
824 :     $sep = $args{text};
825 :     }
826 :    
827 :     my @result;
828 :     while (@path) {
829 :     my $name = shift @path;
830 :     my $url = shift @path;
831 :     if ($url and not $args{textonly}) {
832 :     push @result, CGI::a({-href=>"$url?$auth"}, $name);
833 :     } else {
834 :     push @result, $name;
835 :     }
836 :     }
837 :    
838 :     return join($sep, @result), "\n";
839 :     }
840 :    
841 :     =item siblingsMacro(@siblings)
842 :    
843 :     Helper macro for the C<#siblings> escape sequence. @siblings consists of ordered
844 :     key-value pairs of the form:
845 :    
846 :     "Sibling Name" => URL
847 :    
848 :     If the sibling should not have a link associated with it, the URL should be left
849 :     empty. Authentication data is added to each URL so you don't have to. A fully-
850 :     formed siblings block is returned, suitable for returning by a function
851 :     implementing the C<#siblings> escape.
852 :    
853 :     FIXME: authentication data probably shouldn't be added here any more, now that
854 :     we have systemLink().
855 :    
856 :     =cut
857 :    
858 :     sub siblingsMacro {
859 :     my ($self, @siblings) = @_;
860 :    
861 :     my $auth = $self->url_authen_args;
862 :     my $sep = CGI::br();
863 :    
864 :     my @result;
865 :     while (@siblings) {
866 :     my $name = shift @siblings;
867 :     my $url = shift @siblings;
868 :     push @result, $url
869 :     ? CGI::a({-href=>"$url?$auth"}, $name)
870 :     : $name;
871 :     }
872 :    
873 :     return join($sep, @result) . "\n";
874 :     }
875 :    
876 :     =item navMacro($args, $tail, @links)
877 :    
878 :     Helper macro for the C<#nav> escape sequence: $args is a hash reference
879 :     containing the "style", "imageprefix", "imagesuffix", and "separator" arguments
880 :     to the escape. @siblings consists of ordered tuples of the form:
881 :    
882 :     "Link Name", URL, ImageBaseName
883 :    
884 :     If the sibling should not have a link associated with it, the URL should be left
885 :     empty. ImageBaseName is placed between the C<imageprefix> and C<imagesuffix>.
886 :     Authentication data is added to each URL so you don't have to. $tail is appended
887 :     to each URL, after the authentication information. A fully-formed nav line is
888 :     returned, suitable for returning by a function implementing the C<#nav> escape.
889 :    
890 :     =cut
891 :    
892 :     sub navMacro {
893 :     my ($self, $args, $tail, @links) = @_;
894 :     my $r = $self->r;
895 :     my $ce = $r->ce;
896 :     my %args = %$args;
897 :    
898 :     my $auth = $self->url_authen_args;
899 :     my $prefix = $ce->{webworkURLs}->{htdocs}."/images";
900 :    
901 :     my @result;
902 :     while (@links) {
903 :     my $name = shift @links;
904 :     my $url = shift @links;
905 :     my $img = shift @links;
906 :     my $html =
907 :     ($img && $args{style} eq "images")
908 :     ? CGI::img(
909 :     {src=>($prefix."/".$img.$args{imagesuffix}),
910 :     border=>"",
911 :     alt=>"$name"})
912 :     : $name;
913 :     unless($img && !$url) {
914 :     push @result, $url
915 :     ? CGI::a({-href=>"$url?$auth$tail"}, $html)
916 :     : $html;
917 :     }
918 :     }
919 :    
920 :     return join($args{separator}, @result) . "\n";
921 :     }
922 :    
923 :     =back
924 :    
925 :     =cut
926 :    
927 :     # ------------------------------------------------------------------------------
928 :    
929 :     =head2 Parameter management
930 :    
931 :     Methods for formatting request parameters as hidden form fields or query string
932 :     fragments.
933 :    
934 :     =over
935 :    
936 :     =item hidden_fields(@fields)
937 :    
938 :     Return hidden <INPUT> tags for each field mentioned in @fields (or all fields if
939 :     list is empty), taking data from the current request.
940 :    
941 :     =cut
942 :    
943 :     sub hidden_fields {
944 :     my ($self, @fields) = @_;
945 :     my $r = $self->r;
946 :    
947 :     @fields = $r->param unless @fields;
948 :    
949 :     my $html = "";
950 :     foreach my $param (@fields) {
951 :     my @values = $r->param($param);
952 :     $html .= CGI::hidden($param, @values);
953 :     }
954 :     return $html;
955 :     }
956 :    
957 :     =item hidden_authen_fields()
958 :    
959 :     Use hidden_fields to return hidden <INPUT> tags for request fields used in
960 :     authentication.
961 :    
962 :     =cut
963 :    
964 :     sub hidden_authen_fields {
965 :     my ($self) = @_;
966 :    
967 :     return $self->hidden_fields("user", "effectiveUser", "key");
968 :     }
969 :    
970 :     =item url_args(@fields)
971 :    
972 :     Return a URL query string (without the leading `?') containing values for each
973 :     field mentioned in @fields, or all fields if list is empty. Data is taken from
974 :     the current request.
975 :    
976 :     =cut
977 :    
978 :     sub url_args {
979 :     my ($self, @fields) = @_;
980 :     my $r = $self->r;
981 :    
982 :     @fields = $r->param unless @fields;
983 :    
984 :     my @pairs;
985 :     foreach my $param (@fields) {
986 :     my @values = $r->param($param);
987 :     foreach my $value (@values) {
988 :     push @pairs, uri_escape($param) . "=" . uri_escape($value);
989 :     }
990 :     }
991 :    
992 :     return join("&", @pairs);
993 :     }
994 :    
995 :     =item url_authen_args()
996 :    
997 :     Use url_args to return a URL query string for request fields used in
998 :     authentication.
999 :    
1000 :     =cut
1001 :    
1002 :     sub url_authen_args {
1003 :     my ($self) = @_;
1004 :    
1005 :     return $self->url_args("user", "effectiveUser", "key");
1006 :     }
1007 :    
1008 :     =item print_form_data($begin, $middle, $end, $omit)
1009 :    
1010 :     Return a string containing every request field not matched by the quoted reguar
1011 :     expression $omit, placing $begin before each field name, $middle between each
1012 :     field name and its value, and $end after each value. Values are taken from the
1013 :     current request.
1014 :    
1015 :     =cut
1016 :    
1017 :     sub print_form_data {
1018 :     my ($self, $begin, $middle, $end, $qr_omit) = @_;
1019 :     my $r=$self->r;
1020 :     my @form_data = $r->param;
1021 :    
1022 :     my $return_string = "";
1023 :     foreach my $name (@form_data) {
1024 :     next if ($qr_omit and $name =~ /$qr_omit/);
1025 :     my @values = $r->param($name);
1026 :     foreach my $variable (qw(begin name middle value end)) {
1027 :     # FIXME: can this loop be moved out of the enclosing loop?
1028 :     no strict 'refs';
1029 :     ${$variable} = "" unless defined ${$variable};
1030 :     }
1031 :     foreach my $value (@values) {
1032 :     $return_string .= "$begin$name$middle$value$end";
1033 :     }
1034 :     }
1035 :    
1036 :     return $return_string;
1037 :     }
1038 :    
1039 :     =back
1040 :    
1041 :     =cut
1042 :    
1043 :     # ------------------------------------------------------------------------------
1044 :    
1045 :     =head2 Utilities
1046 :    
1047 :     =over
1048 :    
1049 :     =item systemLink($urlpath, %options)
1050 :    
1051 :     Generate a link to another part of the system. $urlpath is WeBWorK::URLPath
1052 :     object from which the base path will be taken. %options can consist of:
1053 :    
1054 :     =over
1055 :    
1056 : sh002i 1882 =item params
1057 : sh002i 1873
1058 : sh002i 1882 A reference to a list containing names of parameters to add to the URL. The
1059 :     parameter values are taken from the current request.
1060 : sh002i 1873
1061 : sh002i 1882 =item values
1062 : sh002i 1873
1063 : sh002i 1882 A reference to a hash associating request parameters with replacement values. If
1064 :     parameter is given in C<params> above, the value given here will be substituted
1065 :     for that in the current request.
1066 : sh002i 1873
1067 : sh002i 1882 =item authen
1068 : sh002i 1873
1069 : sh002i 1882 If true, authentication parameters (C<user>, C<effectiveUser>, and <key>) will
1070 :     be included in the list of C<params>. Since this is usually what you want, if
1071 :     this option is not given a true value is assumed.
1072 : sh002i 1873
1073 :     =back
1074 :    
1075 :     =cut
1076 :    
1077 : sh002i 1882 # FIXME: there should probably be an option for prepending "http://hostname:port"
1078 : sh002i 1873 sub systemLink {
1079 :     my ($self, $urlpath, %options) = @_;
1080 :     my $r = $self->r;
1081 :    
1082 : sh002i 1882 my @params = ();
1083 :     if (exists $options{params}) {
1084 :     croak "option 'params' is not an arrayref" unless ref $options{params} eq "ARRAY";
1085 :     @params = @{ $options{params} };
1086 :     }
1087 : sh002i 1873
1088 : sh002i 1882 my %values = ();
1089 :     if (exists $options{values}) {
1090 :     croak "option 'values' is not an hashref" unless ref $options{values} eq "HASH";
1091 :     %values = %{ $options{values} };
1092 :     }
1093 :    
1094 : sh002i 1893 my $authen = exists $options{authen} ? $options{authen} : 1;
1095 : sh002i 1882 push @params, qw/user effectiveUser key/ if $authen;
1096 :    
1097 :     foreach my $param (@params) {
1098 :     next if exists $values{$param};
1099 :     $values{$param} = $r->param($param);
1100 :     }
1101 :    
1102 : sh002i 1873 my $url = $r->location . $urlpath->path;
1103 :    
1104 : sh002i 1882 if (keys %values) {
1105 :     $url .= "?";
1106 :     $url .= join("&", map { "$_=$values{$_}" } keys %values);
1107 : sh002i 1873 }
1108 :    
1109 :     return $url;
1110 :     }
1111 :    
1112 :     =item nbsp($string)
1113 :    
1114 :     If string consists of only whitespace, the HTML entity C<&nbsp;> is returned.
1115 :     Otherwise $string is returned.
1116 :    
1117 :     =cut
1118 :    
1119 :     sub nbsp {
1120 :     my $self = shift;
1121 :     my $str = shift;
1122 :     ($str =~/\S/) ? $str : '&nbsp;';
1123 :     }
1124 :    
1125 :     =item errorOutput($error, $details)
1126 :    
1127 :     =cut
1128 :    
1129 :     sub errorOutput($$$) {
1130 :     my ($self, $error, $details) = @_;
1131 :     return
1132 :     CGI::h3("Software Error"),
1133 :     CGI::p(<<EOF),
1134 :     WeBWorK has encountered a software error while attempting to process this
1135 :     problem. It is likely that there is an error in the problem itself. If you are
1136 :     a student, contact your professor to have the error corrected. If you are a
1137 :     professor, please consut the error output below for more informaiton.
1138 :     EOF
1139 :     # FIXME: this message shouldn't refer the the "problem" since it is for general error reporting
1140 :     CGI::h3("Error messages"), CGI::p(CGI::tt($error)),
1141 :     CGI::h3("Error context"), CGI::p(CGI::tt($details));
1142 :     }
1143 :    
1144 :     =item warningOutput($warnings)
1145 :    
1146 :     =cut
1147 :    
1148 :     sub warningOutput($$) {
1149 :     my ($self, $warnings) = @_;
1150 :    
1151 :     my @warnings = split m/\n+/, $warnings;
1152 :    
1153 :     return
1154 :     CGI::h3("Software Warnings"),
1155 :     CGI::p(<<EOF),
1156 :     WeBWorK has encountered warnings while attempting to process this problem. It
1157 :     is likely that this indicates an error or ambiguity in the problem itself. If
1158 :     you are a student, contact your professor to have the problem corrected. If you
1159 :     are a professor, please consut the warning output below for more informaiton.
1160 :     EOF
1161 :     # FIXME: this message shouldn't refer the the "problem" since it is for general warning reporting
1162 :     CGI::h3("Warning messages"),
1163 :     CGI::ul(CGI::li(\@warnings));
1164 :     }
1165 :    
1166 :     =back
1167 :    
1168 : malsyned 508 =head1 AUTHOR
1169 :    
1170 : sh002i 1873 Written by Dennis Lambe Jr., malsyned (at) math.rochester.edu and Sam Hathaway,
1171 :     sh002i (at) math.rochester.edu.
1172 : malsyned 508
1173 :     =cut
1174 : sh002i 1873
1175 :     1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9