--- loncom/interface/lonprintout.pm 2011/11/07 16:09:09 1.607 +++ loncom/interface/lonprintout.pm 2024/11/09 15:40:00 1.700 @@ -1,8 +1,7 @@ - # The LearningOnline Network # Printout # -# $Id: lonprintout.pm,v 1.607 2011/11/07 16:09:09 www Exp $ +# $Id: lonprintout.pm,v 1.700 2024/11/09 15:40:00 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -41,12 +40,12 @@ use Apache::admannotations; use Apache::lonenc; use Apache::entities; use Apache::londefdef; +# use Apache::structurelags; # for language management. use File::Basename; use HTTP::Response; use LONCAPA::map(); -use POSIX qw(strftime); use Apache::lonlocal; use Carp; use LONCAPA; @@ -76,6 +75,58 @@ my $font_size = 'normalsize'; # Default #---------------------------- Helper helpers. ------------------------- +## +# Filter function to determine if a resource is a printable sequence. +# +# @param $res -Resource to check. +# +# @return 1 - printable and a resource +# 0 - either notm a sequence or not printable. +# +sub printable_sequence { + my $res = shift; + + # Non-sequences are not listed: + + if (!$res->is_sequence()) { + return 0; + } + + # Person with pav or pfo can always print: + + if ($perm{'pav'} || $perm{'pfo'}) { + return 1; + } + + if ($res->is_sequence()) { + my $symb = $res->symb(); + my $navmap = $res->{NAV_MAP}; + + # Find the first resource in the map: + + my $iterator = $navmap->getIterator($res, undef, undef, 1, 1); + my $first = $iterator->next(); + + while (1) { + if ($first == $iterator->END_ITERATOR) { last; } + if (ref($first) && ! $first->is_sequence()) {last; } + $first = $iterator->next(); + } + + + # Might be an empty map: + + if (!ref($first)) { + return 0; + } + my $partsref = $first->parts(); + my @parts = @$partsref; + my ($open, $close) = $navmap->map_printdates($first, $parts[0]); + return &printable($open, $close); + } + return 0; +} + # BZ5209: # Create the states needed to run the helper for incomplete problems from # the current folder for selected students. @@ -92,13 +143,13 @@ my $font_size = 'normalsize'; # Default # Parameters: # helper - the helper which already contains info about the current folder we can # purloin. -# url - Top url of the sequence +# map - the map for which incomplete problems are to be printed +# nocurrloc - True if printout called from icon/link in Tools in /adm/navmaps # Return: # XML that can be parsed by the helper to drive the state machine. # -sub create_incomplete_folder_selstud_helper($helper) -{ - my ($helper, $map) = @_; +sub create_incomplete_folder_selstud_helper { + my ($helper, $map, $nocurrloc) = @_; my $symbFilter = '$res->shown_symb()'; @@ -107,13 +158,13 @@ sub create_incomplete_folder_selstud_hel my $resource_chooser = &generate_resource_chooser('CHOOSE_INCOMPLETE_PEOPLE_SEQ', 'Select problem(s) to print', - 'multichoice="1" toponly="1" addstatus="1" closeallpages="1"', + 'multichoice="1" toponly="1" addstatus="1" closeallpages="1" modallink="1" nocurrloc="'.$nocurrloc.'"', 'RESOURCES', 'CHOOSE_STUDENTS_INCOMPLETE', $map, $selFilter, '', - $symbFilter, + $symbFilter, ''); my $student_chooser = &generate_student_chooser('CHOOSE_STUDENTS_INCOMPLETE', @@ -126,7 +177,7 @@ sub create_incomplete_folder_selstud_hel 'CHOOSE_STUDENTS_INCOMPLETE_FORMAT'); # end state. return $resource_chooser . $student_chooser . $format_chooser; -} +} # BZ 5209 @@ -146,17 +197,17 @@ sub create_incomplete_folder_selstud_hel # helper - Helper we are creating states for. # Returns: # Text that can be parsed by the helper. -# +# sub create_incomplete_course_helper { my $helper = shift; my $filter = '$res->is_problem() || $res->contains_problem() || $res->is_sequence() || $res->is_practice())'; my $symbfilter = '$res->shown_symb()'; - + my $resource_chooser = &generate_resource_chooser('INCOMPLETE_PROBLEMS_COURSE_RESOURCES', 'Select problem(s) to print', - 'multichoice = "1" suppressEmptySequences="0" addstatus="1" closeallpagtes="1"', + 'multichoice = "1" suppressEmptySequences="0" addstatus="1" closeallpagtes="1" modallink="1"', 'RESOURCES', 'INCOMPLETE_PROBLEMS_COURSE_STUDENTS', '', @@ -179,12 +230,13 @@ sub create_incomplete_course_helper { } -# BZ5209 +# BZ5209 # Creates the states needed to run the print helper for a student # that wants to print his incomplete problems from the current folder. # Parameters: # $helper - helper we are generating states for. # $map - The map for which the student wants incomplete problems. +# $nocurrloc - True if printout called from icon/link in Tools in /adm/navmaps # Returns: # XML that defines the helper states being created. # @@ -192,7 +244,7 @@ sub create_incomplete_course_helper { # CHOOSE_INCOMPLETE_SEQ - Resource selector. # sub create_incomplete_folder_helper { - my ($helper, $map) = @_; + my ($helper, $map, $nocurrloc) = @_; my $filter = '$res->is_problem()'; $filter .= ' && $res->resprintable() '; @@ -202,11 +254,11 @@ sub create_incomplete_folder_helper { my $resource_chooser = &generate_resource_chooser('CHOOSE_INCOMPLETE_SEQ', 'Select problem(s) to print', - 'multichoice="1", toponly ="1", addstatus="1", closeallpages="1"', + 'multichoice="1", toponly ="1", addstatus="1", closeallpages="1" modallink="1" nocurrloc="'.$nocurrloc.'"', 'RESOURCES', 'PAGESIZE', $map, - $filter, '', + $filter, '', $symfilter, ''); @@ -224,9 +276,9 @@ sub create_incomplete_folder_helper { sub generate_student_chooser { - my ($this_state, - $sort_choice, - $variable, + my ($this_state, + $sort_choice, + $variable, $next_state) = @_; my $result = < @@ -238,7 +290,7 @@ sub generate_student_chooser {


- @@ -256,7 +308,8 @@ CHOOSE_STUDENTS # this_state - State name of the chooser. # prompt_text - Text to use to prompt user. # resource_options - Resource tag options e.g. -# "multichoice='1', toponly='1', addstatus='1'" +# "multichoice='1', toponly='1', addstatus='1', +# modallink='1'" # that control the selection and appearance of the # resource selector. # variable - Name of the variable to hold the choice @@ -267,7 +320,7 @@ CHOOSE_STUDENTS # filter - How to filter the resources. # value_func - function. # choice_func - If not empty generates a with this function. -# start_new_option +# start_new_option # - Fragment appended after valuefunc. # # @@ -302,7 +355,6 @@ CHOOSE_RESOURCES CHOOSE_RESOURCES - return $result; } # @@ -394,13 +446,141 @@ CHOOSE_ANON1 return $result; } -# Returns the XML for choosing how assignments are to be formatted +sub generate_common_choosers { + my ($r,$helper,$map,$url,$isProblem,$symbFilter,$start_new_option) = @_; + + my $randomly_ordered_warning = + &get_randomly_ordered_warning($helper, $map); + + # code for a few states used for printout launched from both + # /adm/navmaps and from a resource by a privileged user: + # - To allow resources to be selected for printing. + # - To determine pagination between assignments. + # - To determine how many assignments should be bundled into a single PDF. + + my $resource_selector= &generate_resource_chooser('SELECT_PROBLEMS', + 'Select resources to print', + 'multichoice="1" addstatus="1" closeallpages="1" modallink="1" suppressNavmap="1"', + 'RESOURCES', + 'PRINT_FORMATTING', + $map, + $isProblem, '', $symbFilter, + $start_new_option); + $resource_selector .= &generate_format_selector($helper, + 'How should results be printed?', + 'PRINT_FORMATTING'). + &generate_resource_chooser('CHOOSE_STUDENTS_PAGE', + 'Select Problem(s) to print', + "multichoice='1' addstatus='1' closeallpages ='1' modallink='1'", + 'RESOURCES', + 'PRINT_FORMATTING', + $url, + $isProblem, '', $symbFilter, + $start_new_option); + +# Generate student choosers. + + &Apache::lonxml::xmlparse($r, 'helper', + &generate_student_chooser('CHOOSE_TGT_STUDENTS_PAGE', + 'student_sort', + 'STUDENTS', + 'CHOOSE_STUDENTS_PAGE')); + &Apache::lonxml::xmlparse($r, 'helper', + &generate_student_chooser('CHOOSE_STUDENTS', + 'student_sort', + 'STUDENTS', + 'SELECT_PROBLEMS')); + &Apache::lonxml::xmlparse($r, 'helper', $resource_selector); + + my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; + my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + my @names=&Apache::lonnet::getkeys('CODEs',$cdom,$cnum); + my $namechoice=''; + foreach my $name (sort {uc($a) cmp uc($b)} @names) { + if ($name =~ /^error: 2 /) { next; } + if ($name =~ /^type\0/) { next; } + $namechoice.=''.$name.''; + } + + my %code_values; + my %codes_to_print; + foreach my $key (@names) { + %code_values = &Apache::grades::get_codes($key, $cdom, $cnum); + foreach my $key (keys(%code_values)) { + $codes_to_print{$key} = 1; + } + } + + my $code_selection; + foreach my $code (sort {uc($a) cmp uc($b)} (keys(%codes_to_print))) { + my $choice = $code; + if ($code =~ /^[A-Z]+$/) { # Alpha code + $choice = &letters_to_num($code); + } + push(@{$helper->{DATA}{ALL_CODE_CHOICES}},[$code,$choice]); + } + if (%codes_to_print) { + $code_selection .=' + Choose single CODE from list: + + + + + push(@{$state->{CHOICES}},@{$helper->{DATA}{ALL_CODE_CHOICES}}); + + + + '.$/; + } + + my @lines = &Apache::lonnet::get_scantronformat_file(); + my $codechoice=''; + foreach my $line (@lines) { + next if (($line =~ /^\#/) || ($line eq '')); + my ($name,$description,$code_type,$code_length)= + (split(/:/,$line))[0,1,2,4]; + if ($code_length > 0 && + $code_type =~/^(letter|number|-1)/) { + $codechoice.=''.$description.''; + } + } + if ($codechoice eq '') { + $codechoice='Default'; + } + my $anon1 = &generate_code_selector($helper, + 'CHOOSE_ANON1', + 'SELECT_PROBLEMS', + $codechoice, + $code_selection, + $namechoice) . $resource_selector; + + &Apache::lonxml::xmlparse($r, 'helper',$anon1); + + my $anon_page = &generate_code_selector($helper, + 'CHOOSE_ANON1_PAGE', + 'SELECT_PROBLEMS_PAGE', + $codechoice, + $code_selection, + $namechoice) . + &generate_resource_chooser('SELECT_PROBLEMS_PAGE', + 'Select Problem(s) to print', + "multichoice='1' addstatus='1' closeallpages ='1' modallink='1'", + 'RESOURCES', + 'PRINT_FORMATTING', + $url, + $isProblem, '', $symbFilter, + $start_new_option); + &Apache::lonxml::xmlparse($r, 'helper', $anon_page); + return ($randomly_ordered_warning,$codechoice,$code_selection,$namechoice); +} + +# Returns the XML for choosing how assignments are to be formatted # that text must still be parsed by the helper xml parser. # Parameters: 3 (required) # helper - The helper; $helper->{'VARS'}->{'PRINT_TYPE'} used # to check if splitting PDFs by section can be offered. -# title - Title for the current state. +# title - Title for the current state. # this_state - State name of the chooser. sub generate_format_selector { @@ -408,7 +588,9 @@ sub generate_format_selector { my $secpdfoption; unless (($helper->{'VARS'}->{'PRINT_TYPE'} eq 'problems_for_anon') || ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'problems_for_anon_page') || - ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'resources_for_anon') ) { + ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'resources_for_anon') || + ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'select_sequences_problems_for_anon') || + ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'select_sequences_resources_for_anon')) { $secpdfoption = 'Each PDF contains exactly one section'; } return < $latest_open)) { + $latest_open = $open; + } + } + # Earliest close: + + my $earliest_close; + foreach my $close (@closes) { + if (!defined($earliest_close) || ($close < $earliest_close)) { + $earliest_close = $close; + } + } + + # If no overlap...both are -1 as promised. + + if (($earliest_close ne '') && ($latest_open ne '') + && ($earliest_close < $latest_open)) { + $latest_open = -1; + $earliest_close = -1; + } + + return ($latest_open, $earliest_close); + +} + +## +# Determines if 'now' is within the set of printable dates. +# +# @param $open_date - Starting date/timestamp. +# @param $close_date - Ending date/timestamp. +# +# @return 0 - Not open. +# @return 1 - open. +# +sub printable { + my ($open_date, $close_date) = @_; + + + my $now = time(); + + # Have to do a bit of fancy footwork around undefined open/close dates: + + if ($open_date && ($open_date > $now)) { + return 0; + } + + if ($close_date && ($close_date < $now)) { + return 0; + } + + return 1; + +} + +## +# Returns the innermost print start/print end dates for a resource. +# This is done by looking at the start/end dates for its parts and choosing +# the intersection of those dates. +# +# @param res - lonnvamaps::resource object that represents the resource. +# +# @return (opendate, closedate) +# +# @note If open/close dates are not defined they will be returned as undef +# @note It is possible for there to be no overlap in which case -1,-1 +# will be returned. +# @note The algorithm used is to take the latest open date and the earliest end date. +# For consistency with &printable() in lonnavmaps.pm determination of start +# date for printing checks printstartdate param first, then, if not set, +# opendate param, then, if not set, contentopen param. + +sub get_print_dates { + my $res = shift; + my $partsref = $res->parts(); + my @parts; + if (ref($partsref) eq 'ARRAY') { + @parts = @{$partsref}; + } + my $open_date; + my $close_date; + my @open_dates; + my @close_dates; + + + if (@parts) { + foreach my $part (@parts) { + my $partopen = $res->parmval('printstartdate', $part); + my $partclose = $res->parmval('printenddate', $part); + if (!$partopen) { + $partopen = $res->parmval('opendate',$part); + } + if (!$partopen) { + $partopen = $res->parmval('contentopen',$part); + } + if ($partopen) { + push(@open_dates, $partopen); + } + if ($partclose) { + push(@close_dates, $partclose); + } + push(@open_dates, $partopen); + push(@close_dates, $partclose); + } + } + + ($open_date, $close_date) = &compute_open_window(\@open_dates, \@close_dates); + + return ($open_date, $close_date); +} + +## +# Get the dates for which a course says a resource can be printed. This is like +# get_print_dates but namvaps::course_print_dates are gotten...and not converted +# to times either. +# +# @param $res - Reference to a resource hash from lonnavmaps::resource. +# +# @return (opendate, closedate) +# +sub course_print_dates { + my $res = shift; + my $partsref = $res->parts(); + my @parts = @$partsref; + my $open_date; + my $close_date; + my @open_dates; + my @close_dates; + my $navmap = $res->{NAV_MAP}; # Slightly OO dirty. + + # Don't bother looping over undefined or empty parts array; + + if (@parts) { + foreach my $part (@parts) { + my ($partopen, $partclose) = $navmap->course_printdates($res, $part); + push(@open_dates, $partopen); + push(@close_dates, $partclose); + } + ($open_date, $close_date) = &compute_open_window(\@open_dates, \@close_dates); + } + return ($open_date, $close_date); +} +## +# Same as above but for the enclosing map: +# +sub map_print_dates { + my $res = shift; + my $partsref = $res->parts(); + my @parts = @$partsref; + my $open_date; + my $close_date; + my @open_dates; + my @close_dates; + my $navmap = $res->{NAV_MAP}; # slightly OO dirty. + + + # Don't bother looping over undefined or empty parts array; + + if (@parts) { + foreach my $part (@parts) { + my ($partopen, $partclose) = $navmap->map_printdates($res, $part); + push(@open_dates, $partopen); + push(@close_dates, $partclose); + } + ($open_date, $close_date) = &compute_open_window(\@open_dates, \@close_dates); + } + return ($open_date, $close_date); +} + # Determine if a resource is incomplete given the map: # Parameters: # $username - Name of user for whom we are checking. @@ -449,7 +822,7 @@ sub incomplete { my $navmap = Apache::lonnavmaps::navmap->new($username, $domain); - + if (defined($navmap)) { my $res = $navmap->getResourceByUrl($map); @@ -460,58 +833,71 @@ sub incomplete { } } # -# When printing for students, the resoures and order of the +# When printing for students, the resources and order of the # resources may need to be altered if there are folders with # random selectiopn or random ordering (or both) enabled. # This sub computes the set of resources to print for a student # modified both by random ordering and selection and filtered -# to only those that are in the original set selcted to be printed. +# to only those that are in the original set selected to be printed. # # Parameters: -# $helper - The helper we need $helper->{'VARS'}->{'symb'} -# to construct the navmap and the iteration. -# $seq - The original set of resources to print +# $map - The URL of the folder being printed. +# Used to determine which startResource and finishResource +# to use when using the navmap's getIterator method. +# $seq - The original set of resources to print. # (really an array of resource names (array of symb's). # $who - Student/domain for whome the sequence will be generated. +# $code - CODE being printed when printing Problems/Resources +# from folder for CODEd assignments +# $nohidemap - If true, parameter in map for hiddenresource will be +# ignored. The user calling the routine should have +# both the pav and vgr privileges if this is set to true). # # Implicit inputs: # $ # Returns: # reference to an array of resources that can be passed to # print_resources. -# +# sub master_seq_to_person_seq { - my ($helper, $seq, $who) = @_; + my ($map, $seq, $who, $code, $nohidemap) = @_; my ($username, $userdomain, $usersection) = split(/:/, $who); - # Toss the sequence up into a hash so that we have O(1) lookup time. # on the items that come out of the user's list of resources. # - + my %seq_hash = map {$_ => 1} @$seq; my @output_seq; - - my ($map, $id, $url) = &Apache::lonnet::decode_symb($helper->{VARS}->{'symb'}); - my $navmap = Apache::lonnavmaps::navmap->new($username, $userdomain); - my $iterator = $navmap->getIterator($navmap->firstResource(), - $navmap->finishResource(), - {}, 1); - my %nonResourceItems = ( - $iterator->BEGIN_MAP => 1, - $iterator->BEGIN_BRANCH => 1, - $iterator->END_BRANCH => 1, - $iterator->END_MAP => 1, - $iterator->FORWARD => 1, - $iterator->BACKWARD => 1 - ); # These items are not resources but appear in the midst of iteration. + my $unhidden; + if ($nohidemap) { + $unhidden = &Apache::lonnet::clutter($map); + } + + my $navmap = Apache::lonnavmaps::navmap->new($username, $userdomain, + $code, $unhidden); + my ($start,$finish); + + if ($map) { + my $mapres = $navmap->getResourceByUrl($map); + if ($mapres->is_map()) { + $start = $mapres->map_start(); + $finish = $mapres->map_finish(); + } + } + unless ($start && $finish) { + $start = $navmap->firstResource(); + $finish = $navmap->finishResource(); + } + + my $iterator = $navmap->getIterator($start,$finish,{},1); # Iterate on the resource..select the items that are randomly selected - # and that are in the seq_has. Presumably the iterator will take care - # of the random ordering part of the deal. + # and that are in the seq_hash. Presumably the iterator will take care + # of the random ordering part of the deal. # my $curres; while ($curres = $iterator->next()) { @@ -519,17 +905,16 @@ sub master_seq_to_person_seq { # Only process resources..that are not removed by randomout... # and are selected for printint as well. # - if (! exists $nonResourceItems{$curres} && ! $curres->randomout()) { - my $symb = $curres->symb(); - if (exists $seq_hash{$symb}) { - push(@output_seq, $symb); + if (ref($curres) && ! $curres->randomout()) { + my $currsymb = $curres->symb(); + if (exists($seq_hash{$currsymb})) { + push(@output_seq, $currsymb); } } } - return \@output_seq; # for now. - + } @@ -552,10 +937,10 @@ sub fetch_raw_resource { } return $contents; - + } -# Fetch the annotations associated with a URL and +# Fetch the annotations associated with a URL and # put a centered 'annotations:' title. # This is all suppressed if the annotations are empty. # @@ -588,29 +973,30 @@ sub set_font_size { my ($text) = @_; # There appear to be cases where the font directive is empty.. in which - # case the first substituion would insert a spurious \ oh happy day. + # case the first substitution would insert a spurious \ oh happy day. # as this has been the cause of much mystery and hair pulling _sigh_ if ($font_size ne '') { - $text =~ s/\\begin{document}/\\begin{document}{\\$font_size/; + $text =~ s/\\begin\{document}/\\begin{document}{\\$font_size/; + $text =~ s/\\end\{document}/}\\end{document}/; + } - $text =~ s/\\end{document}/}\\end{document}/; return $text; } -# include_pdf - PDF files are included into the +# include_pdf - PDF files are included into the # output as follows: # - The PDF, if necessary, is replicated. # - The PDF is added to the list of files to convert to postscript (along with the images). # - The LaTeX is added to include the final converted postscript in the file as an included -# job. The assumption is that the includedpsheader.ps header will be included. +# job. The assumption is that the includepsheader.ps header will be included. # # Parameters: # pdf_uri - URI of the PDF file to include. -# +# # Returns: # The LaTeX to include. # @@ -630,13 +1016,14 @@ sub include_pdf { $file = &Apache::lonnet::filelocation('',$pdf_uri); } - # The file isn ow replicated locally.. or it did not exist in the first place + # The file is now replicated locally ... or it did not exist in the first place # (unlikely). If it did exist, add the pdf to the set of files/images that - # need tob e converted for this print job: + # need to be converted for this print job: - $file =~ s|(.*)/res/|/home/httpd/html/res/|; + my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'}; + $file =~ s{(.*)/res/}{$londocroot/res/}; - open(FILE,">>/home/httpd/prtspool/$env{'user.name'}_$env{'user.domain'}_printout.dat"); + open(FILE,">>","$Apache::lonnet::perlvar{'lonPrtDir'}/$env{'user.name'}_$env{'user.domain'}_printout.dat"); print FILE ("$file\n"); close (FILE); @@ -659,7 +1046,29 @@ sub include_pdf { } - +## +# Collect the various \select_language{language_name} +# latex tags to build a \usepackage[lang-list]{babel} which will +# appear just prior to the \begin{document} at the front of the concatenated +# set of resources: +# @param doc - The string of latex to search/replace. +# @return string +# @retval - the modified document stringt. +# +sub collect_languages { + my $doc = shift; + my %languages; + while ($doc =~ /\\selectlanguage\{(\w+)}/mg) { + $languages{$1} = 1; # allows us to request each language exactly once. + } + my @lang_list = (keys(%languages)); # List of unique languages + if (scalar @lang_list) { + my $babel_header = '\usepackage[' . join(',', @lang_list) .']{babel}'. "\n"; + $doc =~ s/\\begin\{document}/$babel_header\\begin{document}/; + } + return $doc; +} +#------------------------------------------------------------------- # # ssi_with_retries- Does the server side include of a resource. @@ -667,7 +1076,7 @@ sub include_pdf { # the number of times requested by the caller. # If we still have a proble, no text is appended to the # output and we set some global variables. -# to indicate to the caller an SSI error occurred. +# to indicate to the caller an SSI error occurred. # All of this is supposed to deal with the issues described # in LonCAPA BZ 5631 see: # http://bugs.lon-capa.org/show_bug.cgi?id=5631 @@ -677,7 +1086,7 @@ sub include_pdf { # resource - The resource to include. This is passed directly, without # interpretation to lonnet::ssi. # form - The form hash parameters that guide the interpretation of the resource -# +# # retries - Number of retries allowed before giving up completely. # Returns: # On success, returns the rendered resource identified by the resource parameter. @@ -728,12 +1137,12 @@ sub get_student_view_with_retries { # # printf_style_subst item format_string repl -# +# # Does printf style substitution for a format string that # can have %[n]item in it.. wherever, %[n]item occurs, # rep is substituted in format_string. Note that # [n] is an optional integer length. If provided, -# repl is truncated to at most [n] characters prior to +# repl is truncated to at most [n] characters prior to # substitution. # sub printf_style_subst { @@ -745,15 +1154,15 @@ sub printf_style_subst { my $subst = $repl; if ($size ne "") { $subst = substr($subst, 0, $size); - - # Here's a nice edge case.. supose the end of the - # substring is a \. In that case may have just + + # Here's a nice edge case ... suppose the end of the + # substring is a \. In that case may have just # chopped off a TeX escape... in that case, we append - # " " for the trailing character, and let the field + # " " for the trailing character, and let the field # spill over a bit (sigh). # We don't just chop off the last character in order to deal # with one last pathology, and that would be if substr had - # trimmed us to e.g. \\\ + # trimmed us to e.g. \\\ if ($subst =~ /\\$/) { @@ -773,8 +1182,8 @@ sub printf_style_subst { } -# Format a header according to a format. -# +# Format a header according to a format. +# # Substitutions: # %a - Assignment name. @@ -798,7 +1207,7 @@ sub format_page_header { # we assume that each character is about 2mm in width. # (correct for the header text size??). We ignore # any formatting (e.g. boldfacing in this). - # + # # - Allow the student/course to be one line. # but only truncate the course. # - Allow the assignment to be 2 lines (wrapped). @@ -814,9 +1223,10 @@ sub format_page_header { if ($section) { $format .= ' - Sec: '."%$sec_length".'s'; } + $format .= '\\hfill\\thepage'; $format .= '\\\\%c \\\\ %a'; - + } # An open question is how to handle long user formatted page headers... @@ -827,17 +1237,17 @@ sub format_page_header { $format = &printf_style_subst("c", $format, $course); $format = &printf_style_subst("n", $format, $student); $format = &printf_style_subst("s", $format, $section); - - + + # If the user put %'s in the format string, they must be escaped # to \% else LaTeX will think they are comments and terminate # the line.. which is bad!!! - + # If the user has role author, $course and $assignment are empty so # there is '\\ \\ ' in the page header. That's cause a error in LaTeX if($format =~ /\\\\\s\\\\\s/) { #TODO find sensible caption for page header - my $testPrintout = '\\\\'.&mt('Construction Space').' \\\\'.&mt('Test-Printout '); + my $testPrintout = '\\\\'.&mt('Authoring Space').' \\\\'.&mt('Test-Printout '); $format =~ s/\\\\\s\\\\\s/$testPrintout/; } # @@ -855,7 +1265,7 @@ sub format_page_header { return $format; - + } # @@ -903,7 +1313,7 @@ sub is_valid_numeric_code { # Remove leading/trailing whitespace; $value =~ s/^\s*//g; $value =~ s/\s*$//g; - + # All digits? if ($value !~ /^[0-9]+$/) { return "Numeric code $value has invalid characters - must only be digits"; @@ -924,7 +1334,7 @@ sub is_valid_numeric_code { # sub is_valid_alpha_code { my ($value, $num_letters) = @_; - + # strip leading and trailing spaces. $value =~ s/^\s*//g; @@ -942,7 +1352,7 @@ sub is_valid_alpha_code { # Determine if a code entered by the user in a helper is valid. # valid depends on the code type and the type of code selected. -# The type of code selected can either be numeric or +# The type of code selected can either be numeric or # Alphabetic. If alphabetic, the code, in fact is a simple # substitution cipher for the actual numeric code: 0->A, 1->B ... # We'll be nice and be case insensitive for alpha codes. @@ -957,8 +1367,9 @@ sub is_valid_alpha_code { sub is_code_valid { my ($code_value, $code_option) = @_; my ($code_type, $code_length) = ('letter', 6); # defaults. - my @lines = &Apache::grades::get_scantronformat_file(); + my @lines = &Apache::lonnet::get_scantronformat_file(); foreach my $line (@lines) { + next if (($line =~ /^\#/) || ($line eq '')); my ($name, $type, $length) = (split(/:/, $line))[0,2,4]; if($name eq $code_option) { $code_length = $length; @@ -975,6 +1386,22 @@ sub is_code_valid { } } +# +# Compare two students by section (Used to sort by section). +# +# Implicit inputs, +# $a - The first one +# $b - The second one. +# +# Returns: +# a-section cmp b-section +# +sub compare_sections { + my ($u1, $d1, $s1, $n1, $stat1) = split(/:/, $a); + my ($u2, $d2, $s2, $n2, $stat2) = split(/:/, $b); + + return $s1 cmp $s2; +} # Compare two students by name. The students are in the form # returned by the helper: @@ -1014,11 +1441,11 @@ sub compare_names { } # Break the tie on the first name, but there are leading (possibly trailing - # whitespaces to get rid of first + # whitespaces to get rid of first) # $f1 =~ s/^\s+//; # Remove leading... $f1 =~ s/\s+$//; # Trailing spaces from first 1... - + $f2 =~ s/^\s+//; $f2 =~ s/\s+$//; # And the same for first 2... @@ -1028,7 +1455,7 @@ sub compare_names { if($f1 gt $f2) { return 1; } - + # Must be the same name. return 0; @@ -1036,18 +1463,18 @@ sub compare_names { sub latex_header_footer_remove { my $text = shift; - $text =~ s/\\end{document}//; - $text =~ s/\\documentclass([^&]*)\\begin{document}//; + $text =~ s/\\end\{document}//; + $text =~ s/\\documentclass([^&]*)\\begin\{document}//; return $text; } # -# If necessary, encapsulate text inside +# If necessary, encapsulate text inside # a minipage env. # necessity is determined by the problem_split param. # sub encapsulate_minipage { - my ($text) = @_; - if (!($env{'form.problem.split'} =~ /yes/i)) { + my ($text,$problem_split) = @_; + if (!($problem_split =~ /yes/i)) { $text = '\begin{minipage}{\textwidth}'.$text.'\end{minipage}'; } return $text; @@ -1065,7 +1492,7 @@ sub adjust_number_to_print { my $helper = shift; my $split_pdf = $helper->{'VARS'}->{'SPLIT_PDFS'}; - + if ($split_pdf eq 'all') { $helper->{'VARS'}->{'NUMBER_TO_PRINT'} = 'all'; } elsif ($split_pdf eq 'oneper') { @@ -1097,8 +1524,8 @@ sub old_character_chart { $result =~ s/&(\#0?34|quot);/\"/g; $result =~ s/&\#0?35;/\\\#/g; $result =~ s/&\#0?36;/\\\$/g; - $result =~ s/&\#0?37;/\\%/g; - $result =~ s/&(\#0?38|amp);/\\&/g; + $result =~ s/&\#0?37;/\\%/g; + $result =~ s/&(\#0?38|amp);/\\&/g; $result =~ s/&\#(0?39|146);/\'/g; $result =~ s/&\#0?40;/(/g; $result =~ s/&\#0?41;/)/g; @@ -1205,7 +1632,7 @@ sub old_character_chart { $result =~ s/&(\#160|nbsp);/~/g; $result =~ s/&(\#161|iexcl);/!\`/g; $result =~ s/&(\#162|cent);/\\textcent /g; - $result =~ s/&(\#163|pound);/\\pounds /g; + $result =~ s/&(\#163|pound);/\\pounds /g; $result =~ s/&(\#164|curren);/\\textcurrency /g; $result =~ s/&(\#165|yen);/\\textyen /g; $result =~ s/&(\#166|brvbar);/\\textbrokenbar /g; @@ -1231,32 +1658,32 @@ sub old_character_chart { $result =~ s/&(\#188|frac14);/\\textonequarter /g; $result =~ s/&(\#189|frac12);/\\textonehalf /g; $result =~ s/&(\#190|frac34);/\\textthreequarters /g; - $result =~ s/&(\#191|iquest);/?\`/g; - $result =~ s/&(\#192|Agrave);/\\\`{A}/g; - $result =~ s/&(\#193|Aacute);/\\\'{A}/g; + $result =~ s/&(\#191|iquest);/?\`/g; + $result =~ s/&(\#192|Agrave);/\\\`{A}/g; + $result =~ s/&(\#193|Aacute);/\\\'{A}/g; $result =~ s/&(\#194|Acirc);/\\^{A}/g; $result =~ s/&(\#195|Atilde);/\\~{A}/g; - $result =~ s/&(\#196|Auml);/\\\"{A}/g; + $result =~ s/&(\#196|Auml);/\\\"{A}/g; $result =~ s/&(\#197|Aring);/{\\AA}/g; $result =~ s/&(\#198|AElig);/{\\AE}/g; $result =~ s/&(\#199|Ccedil);/\\c{c}/g; - $result =~ s/&(\#200|Egrave);/\\\`{E}/g; - $result =~ s/&(\#201|Eacute);/\\\'{E}/g; + $result =~ s/&(\#200|Egrave);/\\\`{E}/g; + $result =~ s/&(\#201|Eacute);/\\\'{E}/g; $result =~ s/&(\#202|Ecirc);/\\^{E}/g; $result =~ s/&(\#203|Euml);/\\\"{E}/g; $result =~ s/&(\#204|Igrave);/\\\`{I}/g; - $result =~ s/&(\#205|Iacute);/\\\'{I}/g; + $result =~ s/&(\#205|Iacute);/\\\'{I}/g; $result =~ s/&(\#206|Icirc);/\\^{I}/g; - $result =~ s/&(\#207|Iuml);/\\\"{I}/g; + $result =~ s/&(\#207|Iuml);/\\\"{I}/g; $result =~ s/&(\#209|Ntilde);/\\~{N}/g; $result =~ s/&(\#210|Ograve);/\\\`{O}/g; $result =~ s/&(\#211|Oacute);/\\\'{O}/g; $result =~ s/&(\#212|Ocirc);/\\^{O}/g; $result =~ s/&(\#213|Otilde);/\\~{O}/g; - $result =~ s/&(\#214|Ouml);/\\\"{O}/g; + $result =~ s/&(\#214|Ouml);/\\\"{O}/g; $result =~ s/&(\#215|times);/\\ensuremath\{\\times\}/g; $result =~ s/&(\#216|Oslash);/{\\O}/g; - $result =~ s/&(\#217|Ugrave);/\\\`{U}/g; + $result =~ s/&(\#217|Ugrave);/\\\`{U}/g; $result =~ s/&(\#218|Uacute);/\\\'{U}/g; $result =~ s/&(\#219|Ucirc);/\\^{U}/g; $result =~ s/&(\#220|Uuml);/\\\"{U}/g; @@ -1287,7 +1714,7 @@ sub old_character_chart { $result =~ s/&(\#246|ouml);/\\\"{o}/g; $result =~ s/&(\#247|divide);/\\ensuremath\{\\div\}/g; $result =~ s/&(\#248|oslash);/{\\o}/g; - $result =~ s/&(\#249|ugrave);/\\\`{u}/g; + $result =~ s/&(\#249|ugrave);/\\\`{u}/g; $result =~ s/&(\#250|uacute);/\\\'{u}/g; $result =~ s/&(\#251|ucirc);/\\^{u}/g; $result =~ s/&(\#252|uuml);/\\\"{u}/g; @@ -1439,7 +1866,7 @@ my %page_formats= }, 'album' => { '1' => [ '8.8 in', '6.8 in','-0.55 in', '-0.55 in','0.394 in'], - '2' => [ '4.8 in', '6.8 in','-0.5 in', '-1.0 in','3.5 in'] + '2' => [ '4.8 in', '6.8 in','-0.5 in', '-1.0 in','3.0 in'] }, }, 'legal' => { @@ -1499,7 +1926,7 @@ my %page_formats= }, 'album' => { '1' => ['21.59 cm','19.558 cm','-1.397cm','-2.11 cm','0 cm'], - '2' => ['9.91 cm','19.558 cm','-1.397 cm','-2.11 cm','0 cm'] + '2' => ['9.91 cm','19.558 cm','-1.397 cm','-2.11 cm','-1 cm'] }, }, 'a5' => { @@ -1531,8 +1958,8 @@ sub page_format { # "A2 [420x594 mm]", "A3 [297x420 mm]", # "A4 [210x297 mm]", "A5 [148x210 mm]", # "A6 [105x148 mm]" -# - my ($papersize,$layout,$numberofcolumns) = @_; +# + my ($papersize,$layout,$numberofcolumns) = @_; return @{$page_formats{$papersize}->{$layout}->{$numberofcolumns}}; } @@ -1552,13 +1979,13 @@ sub get_course { if (defined($env{'request.course.id'})) { $courseidinfo = &Apache::lonxml::latex_special_symbols(&unescape($env{'course.'.$env{'request.course.id'}.'.description'}),'header'); my $sec = $env{'request.course.sec'}; - + } return $courseidinfo; } sub page_format_transformation { - my ($papersize,$layout,$numberofcolumns,$choice,$text,$assignment,$tableofcontents,$indexlist,$selectionmade) = @_; + my ($papersize,$layout,$numberofcolumns,$choice,$text,$assignment,$tableofcontents,$indexlist,$selectionmade) = @_; my ($textwidth,$textheight,$oddoffset,$evenoffset,$topmargin); if ($selectionmade eq '4') { @@ -1583,31 +2010,58 @@ sub page_format_transformation { my $fancypagestatement=''; if ($numberofcolumns eq '2') { $fancypagestatement="\\fancyhead{}\\fancyhead[LO]{$header_text}"; + if ($parmhash{'print_header_format'} eq '') { + $fancypagestatement .= "\\fancyhead[RE]{\\thepage \\\\[\\baselineskip]}"; + } } else { $fancypagestatement="\\rhead{}\\chead{}\\lhead{$header_text}"; } + $fancypagestatement .= "\\fancyfoot{}"; + my ($paperwidth,$paperheight); if ($layout eq 'album') { - $text =~ s/\\begin{document}/\\setlength{\\oddsidemargin}{$oddoffset}\\setlength{\\evensidemargin}{$evenoffset}$topmargintoinsert\n\\setlength{\\textwidth}{$textwidth}\\setlength{\\textheight}{$textheight}\\setlength{\\textfloatsep}{8pt plus 2\.0pt minus 4\.0pt}\n\\newlength{\\minipagewidth}\\setlength{\\minipagewidth}{\\textwidth\/\$number_of_columns-0\.2cm}\\usepackage{fancyhdr}\\addtolength{\\headheight}{\\baselineskip}\n\\pagestyle{fancy}$fancypagestatement\\usepackage{booktabs}\\begin{document}\\voffset=-0\.8 cm\\setcounter{page}{1}\n /; + $text =~ s/\\begin\{document}/\\setlength{\\oddsidemargin}{$oddoffset}\\setlength{\\evensidemargin}{$evenoffset}$topmargintoinsert\n\\setlength{\\textwidth}{$textwidth}\\setlength{\\textheight}{$textheight}\\setlength{\\textfloatsep}{8pt plus 2\.0pt minus 4\.0pt}\n\\newlength{\\minipagewidth}\\setlength{\\minipagewidth}{\\textwidth\/\$number_of_columns-0\.2cm}\\usepackage{fancyhdr}\\addtolength{\\headheight}{\\baselineskip}\n\\pagestyle{fancy}$fancypagestatement\\usepackage{booktabs}\\begin{document}\\voffset=-0\.8 cm\\setcounter{page}{1}\n /; + if ($papersize eq 'a4') { + $paperwidth = '29.7cm'; + $paperheight = '21cm'; + } elsif ($numberofcolumns eq '1') { + if ($papersize eq 'letter') { + $paperwidth = '11in'; + $paperheight = '8.5in'; + } elsif ($papersize eq 'legal') { + $paperwidth = '14in'; + $paperheight = '8.5in'; + } + } } elsif ($layout eq 'book') { - if ($choice ne 'All class print') { - $text =~ s/\\begin{document}/\\textheight $textheight\\oddsidemargin = $evenoffset\\evensidemargin = $evenoffset $topmargintoinsert\n\\textwidth= $textwidth\\newlength{\\minipagewidth}\\setlength{\\minipagewidth}{\\textwidth\/\$number_of_columns-0\.2cm}\n\\renewcommand{\\ref}{\\keephidden\}\\usepackage{fancyhdr}\\addtolength{\\headheight}{\\baselineskip}\\pagestyle{fancy}$fancypagestatement\\usepackage{booktabs}\\begin{document}\n\\voffset=-0\.8 cm\\setcounter{page}{1}\n/; + if ($choice ne 'All class print') { + $text =~ s/\\begin\{document}/\\textheight $textheight\\oddsidemargin = $evenoffset\\evensidemargin = $evenoffset $topmargintoinsert\n\\textwidth= $textwidth\\newlength{\\minipagewidth}\\setlength{\\minipagewidth}{\\textwidth\/\$number_of_columns-0\.2cm}\n\\renewcommand{\\ref}{\\keephidden\}\\usepackage{fancyhdr}\\addtolength{\\headheight}{\\baselineskip}\\pagestyle{fancy}$fancypagestatement\\usepackage{booktabs}\\begin{document}\n\\voffset=-0\.8 cm\\setcounter{page}{1}\n/; } else { - $text =~ s/\\pagestyle{fancy}\\rhead{}\\chead{}\s*\\begin{document}/\\textheight = $textheight\\oddsidemargin = $evenoffset\n\\evensidemargin = $evenoffset $topmargintoinsert\\textwidth= $textwidth\\newlength{\\minipagewidth}\n\\setlength{\\minipagewidth}{\\textwidth\/\$number_of_columns-0\.2cm}\\renewcommand{\\ref}{\\keephidden\}\\pagestyle{fancy}\\rhead{}\\chead{}\\usepackage{booktabs}\\begin{document}\\voffset=-0\.8cm\n\\setcounter{page}{1} \\vskip 5 mm\n /; - } - if ($papersize eq 'a4') { - my $papersize_text; - if ($perm{'pav'}) { - $papersize_text = '\\special{papersize=210mm,297mm}'; - } else { - $papersize_text = '\special{papersize=210mm,297mm}'; - } - $text =~ s/(\\begin{document})/$1$papersize_text/; + $text =~ s/\\pagestyle\{fancy}\\rhead\{}\\chead\{}\s*\\begin\{document}/\\textheight = $textheight\\oddsidemargin = $evenoffset\n\\evensidemargin = $evenoffset $topmargintoinsert\\textwidth= $textwidth\\newlength{\\minipagewidth}\n\\setlength{\\minipagewidth}{\\textwidth\/\$number_of_columns-0\.2cm}\\renewcommand{\\ref}{\\keephidden\}\\pagestyle{fancy}\\rhead{}\\chead{}\\usepackage{booktabs}\\begin{document}\\voffset=-0\.8cm\n\\setcounter{page}{1} \\vskip 5 mm\n /; } + if ($papersize eq 'a4') { + $paperwidth = '21cm'; + $paperheight = '29.7cm'; + } elsif ($papersize eq 'letter') { + $paperwidth = '8.5in'; + $paperheight = '11.5in'; + } elsif ($papersize eq 'legal') { + $paperwidth = '8.5in'; + $paperheight = '14.0in'; + } + } + if ($paperwidth ne '' && $paperheight ne '') { + my $papersize_text; + if ($perm{'pav'}) { + $papersize_text = '\\special{papersize='.$paperwidth.','.$paperheight.'}'; + } else { + $papersize_text = '\special{papersize='.$paperwidth.','.$paperheight.'}'; + } + $text =~ s/(\\begin\{document})/$1$papersize_text/; } if ($tableofcontents eq 'yes') {$text=~s/(\\setcounter\{page\}\{1\})/$1 \\tableofcontents\\newpage /;} if ($indexlist eq 'yes') { - $text=~s/(\\begin{document})/\\makeindex $1/; - $text=~s/(\\end{document})/\\strut\\\\\\strut\\printindex $1/; + $text=~s/(\\begin\{document})/\\makeindex $1/; + $text=~s/(\\end\{document})/\\strut\\\\\\strut\\printindex $1/; } return $text; } @@ -1615,13 +2069,13 @@ sub page_format_transformation { sub page_cleanup { my $result = shift; - - $result =~ m/\\end{document}(\d*)$/; + + $result =~ m/\\end\{document}(\d*)$/; my $number_of_columns = $1; my $insert = '{'; for (my $id=1;$id<=$number_of_columns;$id++) { $insert .='l'; } $insert .= '}'; - $result =~ s/(\\begin{longtable})INSERTTHEHEADOFLONGTABLE\\endfirsthead\\endhead/$1$insert/g; + $result =~ s/(\\begin\{longtable})INSERTTHEHEADOFLONGTABLE\\endfirsthead\\endhead/$1$insert/g; $result =~ s/&\s*REMOVETHEHEADOFLONGTABLE\\\\/\\\\/g; return $result,$number_of_columns; } @@ -1657,17 +2111,17 @@ my $end_of_student = "\n".'\special{ps:E sub latex_corrections { my ($number_of_columns,$result,$selectionmade,$answer_mode) = @_; -# $result =~ s/\\includegraphics{/\\includegraphics\[width=\\minipagewidth\]{/g; +# $result =~ s/\\includegraphics\{/\\includegraphics\[width=\\minipagewidth\]{/g; my $copyright = ©right_line(); if ($selectionmade eq '1' || $answer_mode eq 'only') { - $result =~ s/(\\end{document})/\\strut\\vskip 0 mm $copyright $end_of_student $1/; + $result =~ s/(\\end\{document})/\\strut\\vskip 0 mm $copyright $end_of_student $1/; } else { - $result =~ s/(\\end{document})/\\strut\\vspace\*{-4 mm}\\newline $copyright $end_of_student $1/; + $result =~ s/(\\end\{document})/\\strut\\vspace\*{-4 mm}\\newline $copyright $end_of_student $1/; } $result =~ s/\$number_of_columns/$number_of_columns/g; - $result =~ s/(\\end{longtable}\s*)(\\strut\\newline\\noindent\\makebox\[\\textwidth\/$number_of_columns\]\[b\]{\\hrulefill})/$2$1/g; - $result =~ s/(\\end{longtable}\s*)\\strut\\newline/$1/g; -#-- LaTeX corrections + $result =~ s/(\\end\{longtable}\s*)(\\strut\\newline\\noindent\\makebox\[\\textwidth\/$number_of_columns\]\[b\]\{\\hrulefill})/$2$1/g; + $result =~ s/(\\end\{longtable}\s*)\\strut\\newline/$1/g; +#-- LaTeX corrections my $first_comment = index($result,'',$first_comment); @@ -1685,8 +2139,8 @@ sub latex_corrections { if ($result =~ m/&(\w+|#\d+);/) { $result = &character_chart($result); } - $result =~ s/(\\end{tabular})\s*\\vskip 0 mm/$1/g; - $result =~ s/(\\begin{enumerate})\s*\\noindent/$1/g; + $result =~ s/(\\end\{tabular})\s*\\vskip 0 mm/$1/g; + $result =~ s/(\\begin\{enumerate})\s*\\noindent/$1/g; return $result; } @@ -1779,15 +2233,28 @@ sub get_textwidth { sub unsupported { my ($currentURL,$mode,$symb)=@_; + my $cleanURL=&Apache::lonenc::check_decrypt($currentURL); + my $shown = $currentURL; + if (($cleanURL ne $currentURL) || ($symb =~ m{/^enc/})) { + $shown = &mt('URL not shown (encrypted)'); + } if ($mode ne '') {$mode='\\'.$mode} - my $result.= &print_latex_header($mode); - if ($currentURL=~m|^(/adm/wrapper/)?ext/|) { - $currentURL=~s|^(/adm/wrapper/)?ext/|http://|; - my $title=&Apache::lonnet::gettitle($symb); - $title = &Apache::lonxml::latex_special_symbols($title); - $result.=' \strut \\\\ '.$title.' \strut \\\\ '.$currentURL.' '; + my $result = &print_latex_header($mode); + if ($cleanURL=~m|^(/adm/wrapper)?/ext/|) { + $cleanURL=~s|^(/adm/wrapper)?/ext/|http://|; + $cleanURL=~s|^http://https://|https://|; + if ($shown eq $currentURL) { + $shown = &Apache::lonxml::latex_special_symbols($cleanURL); + } + my $title=&Apache::lonnet::gettitle($symb); + $title = &Apache::lonxml::latex_special_symbols($title); + $result.=' \strut \\\\ \textit{'.$title.'} \strut \\\\ '.$shown.' '; } else { - $result.=$currentURL; + if ($shown eq $currentURL) { + $result.=&Apache::lonxml::latex_special_symbols($currentURL); + } else { + $result.=$shown; + } } $result.= '\vskip 0.5mm\noindent\makebox[\textwidth/$number_of_columns][b]{\hrulefill} \end{document}'; return $result; @@ -1823,21 +2290,14 @@ sub print_page_in_course { $laystyle = &map_laystyle($laystyle); my ($textwidth,$textheight,$oddoffset,$evenoffset) = &page_format($papersize,$laystyle, $numberofcolumns); - my $LaTeXwidth=&recalcto_mm($textwidth); - + my $LaTeXwidth=&recalcto_mm($textwidth); if ($mode ne '') {$mode='\\'.$mode} my $result = &print_latex_header($mode); - if ($currentURL=~m|^(/adm/wrapper/)?ext/|) { - $currentURL=~s|^(/adm/wrapper/)?ext/|http://|; - my $title=&Apache::lonnet::gettitle($symb); - $title = &Apache::lonxml::latex_special_symbols($title); - } else { - my $esc_currentURL= $currentURL; - $esc_currentURL =~ s/_/\\_/g; - $result.=$esc_currentURL; - } - $result .= '\\\\'; + + my $title=&Apache::lonnet::gettitle($currentURL); + $title = &Apache::lonxml::latex_special_symbols($title); + $result .= '\noindent\textit{'.$title.'}\\\\'; if ($helper->{'VARS'}->{'style_file'}=~/\w/) { &Apache::lonnet::appenv({'construct.style' => @@ -1846,26 +2306,27 @@ sub print_page_in_course { &Apache::lonnet::delenv('construct.style'); } - # First is the overall page description. This is then followed by the + # First is the overall page description. This is then followed by the # components of the page. Each of which must be printed independently. - my $the_page = shift(@page_resources); + my $the_page = shift(@page_resources); foreach my $resource (@page_resources) { my $resource_src = $resource->src(); # Essentially the URL of the resource. - $result .= $resource->title() . '\\\\'; + my $current_url = $resource->link(); # Recurse if a .page: if ($resource_src =~ /.page$/i) { my $navmap = Apache::lonnavmaps::navmap->new(); my @page_resources = $navmap->retrieveResources($resource_src); - $result .= &print_page_in_course($helper, $rparmhash, + $result .= &print_page_in_course($helper, $rparmhash, $resource_src, \@page_resources); - } - # these resources go through the XML transformer: - - elsif ($resource_src =~ /\.(problem|exam|quiz|assess|survey|form|library|xml|html|htm|xhtml|xhtm)$/) { + } elsif ($resource->ext()) { + $result.=&latex_header_footer_remove(&unsupported($current_url,$mode,$resource->symb)); + } elsif ($resource_src =~ /\.(problem|exam|quiz|assess|survey|form|library|xml|html|htm|xhtml|xhtm)$/) { + # these resources go through the XML transformer: + $result .= &Apache::lonxml::latex_special_symbols($resource->title()) . '\\\\'; my $urlp = &Apache::lonnet::clutter($resource_src); @@ -1878,9 +2339,9 @@ sub print_page_in_course { $form{'grade_target'} = 'tex'; $form{'textwidth'} = &get_textwidth($helper, $LaTeXwidth); - $form{'pdfFormFields'} = $pdfFormFields; # - $form{'showallfoils'} = $helper->{'VARS'}->{'showallfoils'}; - + $form{'pdfFormFields'} = $pdfFormFields; # + $form{'showallfoils'} = $helper->{'VARS'}->{'showallfoils'}; + $form{'problem_split'}=$parmhash{'problem_stream_switch'}; $form{'suppress_tries'}=$parmhash{'suppress_tries'}; $form{'latex_type'}=$helper->{'VARS'}->{'LATEX_TYPE'}; @@ -1896,7 +2357,7 @@ sub print_page_in_course { } $form{'rndseed'}=$rndseed; &Apache::lonnet::appenv(\%moreenv); - + &Apache::lonxml::clear_problem_counter(); my $texversion = &ssi_with_retries($urlp, $ssi_retry_count, %form); @@ -1921,7 +2382,7 @@ sub print_page_in_course { my $answer=&ssi_with_retries($urlp,$ssi_retry_count, %answerform); if ($helper->{'VARS'}->{'ANSWER_TYPE'} eq 'no') { - $texversion=~s/(\\keephidden{ENDOFPROBLEM})/$answer$1/; + $texversion=~s/(\\keephidden\{ENDOFPROBLEM})/$answer$1/; } else { $texversion= &print_latex_header($helper->{'VARS'}->{'LATEX_TYPE'}); if ($helper->{'VARS'}->{'construction'} ne '1') { @@ -1931,25 +2392,20 @@ sub print_page_in_course { $texversion.=&path_to_problem($urlp,$LaTeXwidth); } else { $texversion.='\vskip 0 mm \noindent\textbf{'. - &mt("Printing from Construction Space: No Title").'}\vskip 0 mm '; + &mt("Printing from Authoring Space: No Title").'}\vskip 0 mm '; $texversion.=&path_to_problem($urlp,$LaTeXwidth); } $texversion.='\vskip 1 mm '.$answer.'\end{document}'; } - - - - - } # Print annotations. if ($helper->{'VARS'}->{'PRINT_ANNOTATIONS'} eq 'yes') { my $annotation .= &annotate($currentURL); - $texversion =~ s/(\\keephidden{ENDOFPROBLEM})/$annotation$1/; + $texversion =~ s/(\\keephidden\{ENDOFPROBLEM})/$annotation$1/; } - + if ($helper->{'VARS'}->{'TABLE_INDEX'} eq 'yes') { $texversion=&IndexCreation($texversion,$currentURL); } @@ -1987,7 +2443,7 @@ sub recently_generated { my $pdf_result; opendir(DIR,$prtspool); - my @files = + my @files = grep(/^$env{'user.name'}_$env{'user.domain'}_printout_(\d+)_.*\.(pdf|zip)$/,readdir(DIR)); closedir(DIR); @@ -2051,7 +2507,7 @@ sub recently_generated { # A reference to a page break hash. # # -use Data::Dumper; +# use Data::Dumper; # sub dump_helper_vars { # my ($helper) = @_; # my $helpervars = Dumper($helper->{'VARS'}); @@ -2067,7 +2523,7 @@ sub get_page_breaks { } return %page_breaks; } -# +# # Returns text to insert for any extra vskip prior to the resource. # Parameters: # helper - Reference to the helper object driving the printout. @@ -2078,7 +2534,7 @@ sub get_page_breaks { # EXTRASPACE has the list of extra space values. # EXTRASPACE_UNITS is the set of resources for which the units are # mm. All others are 'in'. -# +# # The resource is found in the POSSIBLE_RESOURCES to get the index # of the EXTRASPACE value. # @@ -2099,7 +2555,7 @@ sub load_skips { my ($helper) = @_; - # If this is the first time, unrap the resources and extra spaces: + # If this is the first time, unwrap the resources and extra spaces: if (!$skips_loaded) { @extraspace = (split(/\|\|\|/, $helper->{'VARS'}->{'EXTRASPACE'})); @@ -2147,7 +2603,7 @@ sub get_extra_vspaces { # The resource chooser part of the helper needs more than just # the value of the extraspaces var to recover the value into a text # field option. This sub produces the required format for the saved var: -# specifically +# specifically # ||| separated fields of the form resourcename=value # # Parameters: @@ -2181,7 +2637,7 @@ sub set_form_extraspace { $env{'form.extraspace'} = $result; $env{'form.extraspace_units'} = $helper->{'VARS'}->{'EXTRASPACE_UNITS'}; return $result; - + } # Output a sequence (recursively if neeed) @@ -2207,11 +2663,11 @@ sub print_construction_sequence { } my $errtext=&LONCAPA::map::mapread(&Apache::lonnet::filelocation('',$currentURL)); - # + # # These make this all support recursing for subsequences. # my @order = @LONCAPA::map::order; - my @resources = @LONCAPA::map::resources; + my @resources = @LONCAPA::map::resources; for (my $member=0;$member<=$#order;$member++) { $resources[$order[$member]]=~/^([^:]*):([^:]*):/; @@ -2227,8 +2683,8 @@ sub print_construction_sequence { $texversion=&ssi_with_retries($urlp, $ssi_retry_count, %form); } if((($helper->{'VARS'}->{'ANSWER_TYPE'} eq 'no') || - ($helper->{'VARS'}->{'ANSWER_TYPE'} eq 'only')) && - ($urlp=~/\.(problem|exam|quiz|assess|survey|form|library|page)$/)) { + ($helper->{'VARS'}->{'ANSWER_TYPE'} eq 'only')) && + ($urlp=~/$LONCAPA::assess_page_re/)) { # Don't permanently modify %$form... my %answerform = %form; $answerform{'grade_target'}='answer'; @@ -2239,17 +2695,17 @@ sub print_construction_sequence { $resources_printed .= $urlp.':'; my $answer=&ssi_with_retries($urlp, $ssi_retry_count, %answerform); if ($helper->{'VARS'}->{'ANSWER_TYPE'} eq 'no') { - $texversion=~s/(\\keephidden{ENDOFPROBLEM})/$answer$1/; + $texversion=~s/(\\keephidden\{ENDOFPROBLEM})/$answer$1/; } else { # If necessary, encapsulate answer in minipage: - + $texversion=&print_latex_header($helper->{'VARS'}->{'LATEX_TYPE'}); my $title = &Apache::lonnet::gettitle($helper->{'VARS'}->{'symb'}); $title = &Apache::lonxml::latex_special_symbols($title); my $body ='\vskip 0 mm \noindent\textbf{'.$title.'}\vskip 0 mm '; $body.=&path_to_problem($urlp,$LaTeXwidth); $body.='\vskip 1 mm '.$answer.'\end{document}'; - $body = &encapsulate_minipage($body); + $body = &encapsulate_minipage($body,$answerform{'problem_split'}); $texversion.=$body; } } @@ -2264,16 +2720,16 @@ sub print_construction_sequence { $result.=$texversion; } elsif ($urlp=~/\.(sequence|page)$/) { - + # header: $result.='\strut\newline\noindent Sequence/page '.$urlp.'\strut\newline\noindent\makebox[\textwidth/$number_of_columns][b]{\hrulefill}\newline\noindent '; # IF sequence, recurse: - + if ($urlp =~ /\.sequence$/) { - $result .= &print_construction_sequence($urlp, - $helper, %form, + $result .= &print_construction_sequence($urlp, + $helper, %form, $LaTeXwidth); } } @@ -2288,11 +2744,11 @@ sub print_construction_sequence { if ($member != $#order) { $texversion .= '\\ \cleardoublepage'; } - + $result .= $texversion; } } - if ($helper->{VARS}->{'construction'} eq '1') {$result=~s/(\\begin{document})/$1 \\fbox\{RANDOM SEED IS $rndseed\} /;} + if ($helper->{VARS}->{'construction'} eq '1') {$result=~s/(\\begin\{document})/$1 \\fbox\{RANDOM SEED IS $rndseed\} /;} return $result; } @@ -2328,6 +2784,7 @@ sub print_construction_sequence { # For item 100, filtering was done at the helper level. sub output_data { + my ($r,$helper,$rparmhash) = @_; my %parmhash = %$rparmhash; $ssi_error = 0; # This will be set nonzero by failing ssi's. @@ -2348,7 +2805,7 @@ sub output_data { url += 'form=' + formname + '&'; if (only != null) { url += 'only=' + only + '&'; - } + } if (omit != null) { url += 'omit=' + omit + '&'; } @@ -2383,7 +2840,7 @@ ENDPART $env{'form.pagebreaks'} = $helper->{'VARS'}->{'FINISHPAGE'}; &set_form_extraspace($helper); - $env{'form.lastprinttype'} = $print_type; + $env{'form.lastprinttype'} = $print_type; &Apache::loncommon::store_course_settings('print', {'pagebreaks' => 'scalar', 'extraspace' => 'scalar', @@ -2400,13 +2857,13 @@ ENDPART $laystyle = &map_laystyle($laystyle); my ($textwidth,$textheight,$oddoffset,$evenoffset) = &page_format($papersize,$laystyle,$numberofcolumns); my $assignment = $env{'form.assignment'}; - my $LaTeXwidth=&recalcto_mm($textwidth); + my $LaTeXwidth=&recalcto_mm($textwidth); my @print_array=(); my @student_names=(); - - # Common settings for the %form has: - # In some cases these settings get overriddent by specific cases, but the + + # Common settings for the %form hash: + # In some cases these settings get overridden by specific cases, but the # settings are common enough to make it worthwhile factoring them out # here. # @@ -2416,16 +2873,16 @@ ENDPART $form{'pdfFormFields'} = $pdfFormFields; # If form.showallfoils is set, then request all foils be shown: - # privilege will be enforced both by not allowing the + # privilege will be enforced both by not allowing the # check box selecting this option to be presnt unless it's ok, # and by lonresponse's priv. check. # The if is here because lonresponse.pm only cares that # showallfoils is defined, not what the value is. - if ($helper->{'VARS'}->{'showallfoils'} eq "1") { + if ($helper->{'VARS'}->{'showallfoils'} eq "1") { $form{'showallfoils'} = $helper->{'VARS'}->{'showallfoils'}; } - + if ($helper->{'VARS'}->{'style_file'}=~/\w/) { &Apache::lonnet::appenv({'construct.style' => $helper->{'VARS'}->{'style_file'}}); @@ -2448,7 +2905,7 @@ ENDPART $cleanURL=$currentURL; } $selectionmade = 1; - + if ($cleanURL!~m|^/adm/| && $cleanURL=~/\.(problem|exam|quiz|assess|survey|form|library|xml|html|htm|xhtml|xhtm)$/) { my $rndseed=time; @@ -2478,7 +2935,7 @@ ENDPART $texversion.=&ssi_with_retries($currentURL,$ssi_retry_count, %form); # Add annotations if required: - + &Apache::lonxml::clear_problem_counter(); &Apache::lonnet::delenv('request.filename'); @@ -2501,7 +2958,7 @@ ENDPART if ($helper->{'VARS'}->{'ANSWER_TYPE'} eq 'no') { - $texversion=~s/(\\keephidden{ENDOFPROBLEM})/$answer$1/; + $texversion=~s/(\\keephidden\{ENDOFPROBLEM})/$answer$1/; } else { $texversion=&print_latex_header($helper->{'VARS'}->{'LATEX_TYPE'}); if ($helper->{'VARS'}->{'construction'} ne '1') { @@ -2511,7 +2968,7 @@ ENDPART $texversion.=&path_to_problem($cleanURL,$LaTeXwidth); } else { $texversion.='\vskip 0 mm \noindent\textbf{'. - &mt("Printing from Construction Space: No Title").'}\vskip 0 mm '; + &mt("Printing from Authoring Space: No Title").'}\vskip 0 mm '; $texversion.=&path_to_problem($cleanURL,$LaTeXwidth); } @@ -2521,14 +2978,14 @@ ENDPART - + } # Print annotations. if ($helper->{'VARS'}->{'PRINT_ANNOTATIONS'} eq 'yes') { my $annotation .= &annotate($currentURL); - $texversion =~ s/(\\keephidden{ENDOFPROBLEM})/$annotation$1/; + $texversion =~ s/(\\keephidden\{ENDOFPROBLEM})/$annotation$1/; } @@ -2547,19 +3004,20 @@ ENDPART && $currentURL=~/\.(sequence|page)$/ && $helper->{'VARS'}->{'construction'} eq '1') { $result .= &print_construction_sequence($currentURL, $helper, %form, $LaTeXwidth); - $result .= '\end{document}'; + $result .= '\end{document}'; if (!($result =~ /\\begin\{document\}/)) { $result = &print_latex_header() . $result; } # End construction space sequence. - } elsif ($cleanURL=~/\/(smppg|syllabus|aboutme|bulletinboard)$/) { + } elsif ($cleanURL=~/\/(smppg|syllabus|aboutme|bulletinboard|ext\.tool)$/) { $form{'latex_type'}=$helper->{'VARS'}->{'LATEX_TYPE'}; if ($currentURL=~/\/syllabus$/) {$currentURL=~s/\/res//;} + if ($currentURL=~/\/ext\.tool$/) {$currentURL=~s/^\/adm\/wrapper//;} $resources_printed .= $currentURL.':'; my $texversion = &ssi_with_retries($currentURL, $ssi_retry_count, %form); if ($helper->{'VARS'}->{'PRINT_ANNOTATIONS'} eq 'yes') { my $annotation = &annotate($currentURL); - $texversion =~ s/(\\end{document})/$annotation$1/; + $texversion =~ s/(\\end\{document})/$annotation$1/; } $result .= $texversion; } elsif ($cleanURL =~/\.tex$/) { @@ -2570,7 +3028,7 @@ ENDPART $result = &fetch_raw_resource($currentURL); if ($helper->{'VARS'}->{'PRINT_ANNOTATIONS'} eq 'yes') { my $annotation = &annotate($currentURL); - $result =~ s/(\\end{document})/$annotation$1/; + $result =~ s/(\\end\{document})/$annotation$1/; } $do_postprocessing = 0; # Don't massage the result. @@ -2587,7 +3045,7 @@ ENDPART $result .= &print_page_in_course($helper, $rparmhash, $cleanURL, \@page_resources); - + } else { $result.=&unsupported($currentURL,$helper->{'VARS'}->{'LATEX_TYPE'}, $helper->{'VARS'}->{'symb'}); @@ -2602,7 +3060,6 @@ ENDPART ($print_type eq 'map_incomplete_problems_seq') ) { - #-- produce an output string if (($print_type eq 'map_problems') or ($print_type eq 'map_incomplete_problems_seq') or @@ -2612,7 +3069,7 @@ ENDPART ($print_type eq 'map_resources_in_page')) { $selectionmade = 3; - } elsif (($print_type eq 'all_problems') + } elsif (($print_type eq 'all_problems') ) { $selectionmade = 4; } elsif ($print_type eq 'all_resources') { #BUGBUG @@ -2637,12 +3094,10 @@ ENDPART &Apache::lonxml::clear_problem_counter(); - my $pbreakresources = keys %page_breaks; for (my $i=0;$i<=$#master_seq;$i++) { &Apache::lonenc::reset_enc(); - # Note due to document structure, not allowed to put \newpage # prior to the first resource @@ -2663,6 +3118,7 @@ ENDPART my $texversion=''; if ($urlp!~m|^/adm/| && $urlp=~/\.(problem|exam|quiz|assess|survey|form|library|page|xml|html|htm|xhtml|xhtm)$/) { + my $extension = $1; $resources_printed .= $urlp.':'; &Apache::lonxml::remember_problem_counter(); if ($flag_latex_header_remove eq 'NO') { @@ -2671,15 +3127,15 @@ ENDPART (($i==0) && (($urlp=~/\.page$/) || ($print_type eq 'map_problems_in_page') || - ($print_type eq 'map_resources_in_page')))) { + (($print_type eq 'map_resources_in_page') && ($extension !~ /^x?html?$/))))) { $flag_latex_header_remove = 'YES'; } } $texversion.=&ssi_with_retries($urlp, $ssi_retry_count, %form); if ($urlp=~/\.page$/) { ($texversion,my $number_of_columns_page) = &page_cleanup($texversion); - if ($number_of_columns_page > $number_of_columns) {$number_of_columns=$number_of_columns_page;} - $texversion =~ s/\\end{document}\d*/\\end{document}/; + if ($number_of_columns_page > $number_of_columns) {$number_of_columns=$number_of_columns_page;} + $texversion =~ s/\\end\{document}\d*/\\end{document}/; $flag_page_in_sequence = 'YES'; } @@ -2694,27 +3150,27 @@ ENDPART &Apache::lonxml::restore_problem_counter(); my $answer=&ssi_with_retries($urlp, $ssi_retry_count, %answerform); if ($urlp =~ /\.page$/) { - $answer =~ s/\\end{document}(\d*)$//; + $answer =~ s/\\end\{document}(\d*)$//; } if ($helper->{'VARS'}->{'ANSWER_TYPE'} eq 'no') { if ($urlp =~ /\.page$/) { - my @probs = split(/\\keephidden{ENDOFPROBLEM}/,$texversion); + my @probs = split(/\\keephidden\{ENDOFPROBLEM}/,$texversion); my $lastprob = pop(@probs); $texversion = join('\keephidden{ENDOFPROBLEM}',@probs). $answer.'\keephidden{ENDOFPROBLEM}'.$lastprob; } else { - $texversion=~s/(\\keephidden{ENDOFPROBLEM})/$answer$1/; + $texversion=~s/(\\keephidden\{ENDOFPROBLEM})/$answer$1/; } } else { - if ($urlp=~/\.(problem|exam|quiz|assess|survey|form|library|page)$/) { + if ($urlp=~/$LONCAPA::assess_page_re/) { $texversion=&print_latex_header($helper->{'VARS'}->{'LATEX_TYPE'}); -# $texversion =~ s/\\begin{document}//; # FIXME +# $texversion =~ s/\\begin\{document}//; # FIXME my $title = &Apache::lonnet::gettitle($master_seq[$i]); $title = &Apache::lonxml::latex_special_symbols($title); my $body ='\vskip 0 mm \noindent\textbf{'.$title.'}\vskip 0 mm '; $body .= &path_to_problem ($urlp,$LaTeXwidth); $body .='\vskip 1 mm '.$answer; - $body = &encapsulate_minipage($body); + $body = &encapsulate_minipage($body,$answerform{'problem_split'}); $texversion .= $body; } else { $texversion=''; @@ -2724,13 +3180,13 @@ ENDPART } if ($helper->{'VARS'}->{'PRINT_ANNOTATIONS'} eq 'yes') { my $annotation .= &annotate($urlp); - $texversion =~ s/(\\keephidden{ENDOFPROBLEM})/$annotation$1/; + $texversion =~ s/(\\keephidden\{ENDOFPROBLEM})/$annotation$1/; } if ($flag_latex_header_remove ne 'NO') { $texversion = &latex_header_footer_remove($texversion); } else { - $texversion =~ s/\\end{document}//; + $texversion =~ s/\\end\{document}//; } if ($helper->{'VARS'}->{'TABLE_INDEX'} eq 'yes') { $texversion=&IndexCreation($texversion,$urlp); @@ -2741,10 +3197,9 @@ ENDPART $prevassignment=$assignment; my $header_text = $parmhash{'print_header_format'}; $header_text = &format_page_header($textwidth, $header_text, - $assignment, - $courseidinfo, + $assignment, + $courseidinfo, $name); - if ($numberofcolumns eq '1') { $result .='\newpage \noindent\parbox{\minipagewidth}{\noindent\\lhead{'.$header_text.'}} \vskip 5 mm '; } else { @@ -2752,24 +3207,25 @@ ENDPART } } $result .= $texversion; - $flag_latex_header_remove = 'YES'; - } elsif ($urlp=~/\/(smppg|syllabus|aboutme|bulletinboard)$/) { + $flag_latex_header_remove = 'YES'; + } elsif ($urlp=~/\/(smppg|syllabus|aboutme|bulletinboard|ext\.tool)$/) { $form{'latex_type'}=$helper->{'VARS'}->{'LATEX_TYPE'}; if ($urlp=~/\/syllabus$/) {$urlp=~s/\/res//;} + if ($urlp=~/\/ext\.tool$/) {$urlp=~s/^\/adm\/wrapper//;} $resources_printed .= $urlp.':'; my $texversion = &ssi_with_retries($urlp, $ssi_retry_count, %form); if ($helper->{'VARS'}->{'PRINT_ANNOTATIONS'} eq 'yes') { my $annotation = &annotate($urlp); - $texversion =~ s/(\\end{document)/$annotation$1/; + $texversion =~ s/(\\end\{document)/$annotation$1/; } if ($flag_latex_header_remove ne 'NO') { $texversion = &latex_header_footer_remove($texversion); } else { - $texversion =~ s/\\end{document}/\\vskip 0\.5mm\\noindent\\makebox\[\\textwidth\/\$number_of_columns\]\[b\]\{\\hrulefill\}/; + $texversion =~ s/\\end\{document}/\\vskip 0\.5mm\\noindent\\makebox\[\\textwidth\/\$number_of_columns\]\[b\]\{\\hrulefill\}/; } $result .= $texversion; - $flag_latex_header_remove = 'YES'; + $flag_latex_header_remove = 'YES'; } elsif ($urlp=~ /\.pdf$/i) { if ($i > 0) { $result .= '\cleardoublepage'; @@ -2797,18 +3253,18 @@ ENDPART if ($flag_latex_header_remove ne 'NO') { $texversion = &latex_header_footer_remove($texversion); } else { - $texversion =~ s/\\end{document}//; + $texversion =~ s/\\end\{document}//; } $result .= $texversion; - $flag_latex_header_remove = 'YES'; + $flag_latex_header_remove = 'YES'; } - if (&Apache::loncommon::connection_aborted($r)) { - last; + if (&Apache::loncommon::connection_aborted($r)) { + last; } } &Apache::lonxml::clear_problem_counter(); if ($flag_page_in_sequence eq 'YES') { - $result =~ s/\\usepackage{calc}/\\usepackage{calc}\\usepackage{longtable}/; + $result =~ s/\\usepackage\{calc}/\\usepackage{calc}\\usepackage{longtable}/; } $result .= '\end{document}'; } elsif (($print_type eq 'problems_for_students') || @@ -2816,19 +3272,23 @@ ENDPART ($print_type eq 'all_problems_students') || ($print_type eq 'resources_for_students') || ($print_type eq 'incomplete_problems_selpeople_course') || - ($print_type eq 'map_incomplete_problems_people_seq')){ + ($print_type eq 'map_incomplete_problems_people_seq') || + ($print_type eq 'select_sequences_problems_for_students') || + ($print_type eq 'select_sequences_resources_for_students')) { - #-- prints assignments for whole class or for selected students + #-- prints assignments for whole class or for selected students my $type; if (($print_type eq 'problems_for_students') || ($print_type eq 'problems_for_students_from_page') || ($print_type eq 'all_problems_students') || ($print_type eq 'incomplete_problems_selpeople_course') || - ($print_type eq 'map_incomplete_problems_people_seq')) { + ($print_type eq 'map_incomplete_problems_people_seq') || + ($print_type eq 'select_sequences_problems_for_students')) { $selectionmade=5; $type='problems'; - } elsif ($print_type eq 'resources_for_students') { + } elsif (($print_type eq 'resources_for_students') || + ($print_type eq 'select_sequences_resources_for_students')) { $selectionmade=8; $type='resources'; } @@ -2838,13 +3298,15 @@ ENDPART # to override this and output the students by name. # Each element of the students array is of the form: # username:domain:section:last, first:status - # - # Note that student sort is not compatible with printing + # + # Note that student sort is not compatible with printing # 1 section per pdf...so that setting overrides. - # - if (($helper->{'VARS'}->{'student_sort'} eq 1) && + # + if (($helper->{'VARS'}->{'student_sort'} eq 1) && ($helper->{'VARS'}->{'SPLIT_PDFS'} ne "sections")) { @students = sort compare_names @students; + } else { + @students = sort compare_sections @students; } &adjust_number_to_print($helper); @@ -2852,8 +3314,8 @@ ENDPART $helper->{'VARS'}->{'NUMBER_TO_PRINT'} eq 'all' ) { $helper->{'VARS'}->{'NUMBER_TO_PRINT'}=$#students+1; } - # If we are splitting on section boundaries, we need - # to remember that in split_on_sections and + # If we are splitting on section boundaries, we need + # to remember that in split_on_sections and # print all of the students in the list. # my $split_on_sections = 0; @@ -2863,6 +3325,18 @@ ENDPART } my @master_seq=split /\|\|\|/, $helper->{'VARS'}->{'RESOURCES'}; + my $map; + if ($helper->{VARS}->{'symb'}) { + unless ((($print_type eq 'all_problems_students') || + ($print_type eq 'incomplete_problems_selpeople_course')) && + $perm{'pfo'}) { + ($map, my $id, my $resource) = + &Apache::lonnet::decode_symb($helper->{VARS}->{'symb'}); + } + } elsif (($helper->{'VARS'}->{'postdata'} eq '/adm/navmaps') && ($perm{'pfo'})) { + $map = $helper->{'VARS'}->{'SEQUENCE'}; + } + #loop over students my $flag_latex_header_remove = 'NO'; @@ -2877,10 +3351,14 @@ ENDPART ($helper->{'VARS'}->{'PRINT_ANNOTATIONS'} eq 'yes')) { $moreenv{'problem_split'}='yes'; } - my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin($r,'Print Status','Class Print Status',$#students+1,'inline','75'); + my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin($r,$#students+1); my $student_counter=-1; my $i = 0; my $last_section = (split(/:/,$students[0]))[2]; + my $nohidemap; + if ($perm{'pav'} && $perm{'vgr'}) { + $nohidemap = 1; + } foreach my $person (@students) { my $duefile="/home/httpd/prtspool/$env{'user.name'}_$env{'user.domain'}_printout.due"; if (-e $duefile) { @@ -2897,7 +3375,8 @@ ENDPART } else { $i=int($student_counter/$helper->{'VARS'}{'NUMBER_TO_PRINT'}); } - my $actual_seq = master_seq_to_person_seq($helper, \@master_seq, $person); + my $actual_seq = master_seq_to_person_seq($map, \@master_seq, + $person, undef, $nohidemap); my ($output,$fullname, $printed)=&print_resources($r,$helper, $person,$type, \%moreenv, $actual_seq, @@ -2915,7 +3394,9 @@ ENDPART $result .= $print_array[0].' \end{document}'; } elsif (($print_type eq 'problems_for_anon') || ($print_type eq 'problems_for_anon_page') || - ($print_type eq 'resources_for_anon') ) { + ($print_type eq 'resources_for_anon') || + ($print_type eq 'select_sequences_problems_for_anon') || + ($print_type eq 'select_sequences_resources_for_anon')) { my $cdom =$env{'course.'.$env{'request.course.id'}.'.domain'}; my $cnum =$env{'course.'.$env{'request.course.id'}.'.num'}; my $num_todo=$helper->{'VARS'}->{'NUMBER_TO_PRINT_TOTAL'}; @@ -2923,25 +3404,32 @@ ENDPART my $old_name=$helper->{'VARS'}->{'REUSE_OLD_CODES'}; my $single_code = $helper->{'VARS'}->{'SINGLE_CODE'}; my $selected_code = $helper->{'VARS'}->{'CODE_SELECTED_FROM_LIST'}; - my $code_option=$helper->{'VARS'}->{'CODE_OPTION'}; - my @lines = &Apache::grades::get_scantronformat_file(); + my @lines = &Apache::lonnet::get_scantronformat_file(); my ($code_type,$code_length,$bubbles_per_row)=('letter',6,10); foreach my $line (@lines) { - chomp($line); - my ($name,$type,$length,$bubbles_per_item) = + next if (($line =~ /^\#/) || ($line eq '')); + my ($name,$type,$length,$bubbles_per_item) = (split(/:/,$line))[0,2,4,17]; if ($name eq $code_option) { $code_length=$length; if ($type eq 'number') { $code_type = 'number'; } - chomp($bubbles_per_item); + chomp($bubbles_per_item); if (($bubbles_per_item ne '') && ($bubbles_per_item > 0)) { - $bubbles_per_row = $bubbles_per_item; + $bubbles_per_row = $bubbles_per_item; } } } + my $map; + if ($helper->{VARS}{'symb'}) { + ($map, my $id, my $resource) = + &Apache::lonnet::decode_symb($helper->{VARS}{'symb'}); + } elsif (($helper->{'VARS'}->{'postdata'} eq '/adm/navmaps') && ($perm{'pfo'})) { + $map = $helper->{'VARS'}->{'SEQUENCE'}; + } my %moreenv = ('textwidth' => &get_textwidth($helper,$LaTeXwidth)); $moreenv{'problem_split'} = $parmhash{'problem_stream_switch'}; + $moreenv{'suppress_tries'} = $parmhash{'suppress_tries'}; $moreenv{'instructor_comments'}='hide'; $moreenv{'bubbles_per_row'} = $bubbles_per_row; my $seed=time+($$<<16)+($$); @@ -2973,6 +3461,8 @@ ENDPART $moreenv{'CODE'}=&get_CODE(\%allcodes,$i,$seed,$code_length, $code_type); } + $code_name =~ s/^\s+//; + $code_name =~ s/\s+$//; if ($code_name) { &Apache::lonnet::put('CODEs', { @@ -2991,19 +3481,28 @@ ENDPART || $number_per_page eq 'section') { $number_per_page=$num_todo > 0 ? $num_todo : 1; } - my $flag_latex_header_remove = 'NO'; - my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin($r,'Print Status','Class Print Status',$num_todo,'inline','75'); + my $flag_latex_header_remove = 'NO'; + my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin($r,$num_todo); my $count=0; + my $nohidemap; + if ($perm{'pav'} && $perm{'vgr'}) { + $nohidemap = 1; + } foreach my $code (sort(@allcodes)) { my $file_num=int($count/$number_per_page); - if ($code_type eq 'number') { + if ($code_type eq 'number') { $moreenv{'CODE'}=$code; } else { $moreenv{'CODE'}=&num_to_letters($code); } + $env{'form.CODE'} = $moreenv{'CODE'}; + my $actual_seq = master_seq_to_person_seq($map, \@master_seq, + undef, + $moreenv{'CODE'}, $nohidemap); + delete($env{'form.CODE'}); my ($output,$fullname, $printed)= &print_resources($r,$helper,'anonymous',$type,\%moreenv, - \@master_seq,$flag_latex_header_remove, + $actual_seq,$flag_latex_header_remove, $LaTeXwidth); $resources_printed .= ":"; $print_array[$file_num].=$output; @@ -3015,12 +3514,12 @@ ENDPART } &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state); $result .= $print_array[0].' \end{document}'; - } elsif ($print_type eq 'problems_from_directory') { - #prints selected problems from the subdirectory + } elsif ($print_type eq 'problems_from_directory') { + #prints selected problems from the subdirectory $selectionmade = 6; my @list_of_files=split /\|\|\|/, $helper->{'VARS'}->{'FILES'}; @list_of_files=sort @list_of_files; - my $flag_latex_header_remove = 'NO'; + my $flag_latex_header_remove = 'NO'; my $rndseed=time; if ($helper->{'VARS'}->{'curseed'}) { $rndseed=$helper->{'VARS'}->{'curseed'}; @@ -3048,7 +3547,7 @@ ENDPART $resources_printed .= $urlp.':'; my $answer=&ssi_with_retries($urlp, $ssi_retry_count, %answerform); if ($helper->{'VARS'}->{'ANSWER_TYPE'} eq 'no') { - $texversion=~s/(\\keephidden{ENDOFPROBLEM})/$answer$1/; + $texversion=~s/(\\keephidden\{ENDOFPROBLEM})/$answer$1/; } else { $texversion=&print_latex_header($helper->{'VARS'}->{'LATEX_TYPE'}); if ($helper->{'VARS'}->{'construction'} ne '1') { @@ -3056,7 +3555,7 @@ ENDPART $texversion.=&path_to_problem ($urlp,$LaTeXwidth); } else { $texversion.='\vskip 0 mm \noindent\textbf{'. - &mt("Printing from Construction Space: No Title").'}\vskip 0 mm '; + &mt("Printing from Authoring Space: No Title").'}\vskip 0 mm '; $texversion.=&path_to_problem ($urlp,$LaTeXwidth); } $texversion.='\vskip 1 mm '.$answer.'\end{document}'; @@ -3065,22 +3564,22 @@ ENDPART #this chunk is responsible for printing the path to problem my $newurlp=&path_to_problem($urlp,$LaTeXwidth); - $texversion =~ s/(\\begin{minipage}{\\textwidth})/$1 $newurlp/; + $texversion =~ s/(\\begin\{minipage}\{\\textwidth})/$1 $newurlp/; if ($flag_latex_header_remove ne 'NO') { $texversion = &latex_header_footer_remove($texversion); } else { - $texversion =~ s/\\end{document}//; + $texversion =~ s/\\end\{document}//; } if ($helper->{'VARS'}->{'TABLE_INDEX'} eq 'yes') { $texversion=&IndexCreation($texversion,$urlp); } if ($helper->{'VARS'}->{'CONSTR_RESOURSE_URL'} eq 'yes') { $texversion=~s/(\\addcontentsline\{toc\}\{subsection\}\{[^\}]*\})/$1 URL: \\verb|$urlp| \\strut\\\\\\strut /; - + } $result .= $texversion; } - $flag_latex_header_remove = 'YES'; + $flag_latex_header_remove = 'YES'; } if ($helper->{VARS}->{'construction'} eq '1') {$result=~s/(\\typeout)/ RANDOM SEED IS $rndseed $1/;} $result .= '\end{document}'; @@ -3107,13 +3606,51 @@ ENDPART #} } - # Set URLback if this is a construction space print so we can provide - # a link to the resource being edited. - # + # Set URLback so we can provide a link back to the resource and to change options. + # (Since the browser back button does not currently work with https, + # the back link is useful even when there is an easy-to-miss LON-CAPA back button.) my $URLback=''; #link to original document if ($helper->{'VARS'}->{'construction'} eq '1') { $URLback=$helper->{'VARS'}->{'filename'}; + } elsif ($helper->{VARS}{'symb'}) { + my ($map, $id, $url) = &Apache::lonnet::decode_symb($helper->{VARS}{'symb'}); + my $cdom =$env{'course.'.$env{'request.course.id'}.'.domain'}; + my $cnum =$env{'course.'.$env{'request.course.id'}.'.num'}; + my ($anchor,$usehttp,$plainurl); + $url = &Apache::lonnet::clutter($url); + $plainurl = $url; + if (($ENV{'SERVER_PORT'} == 443) && ($env{'request.course.id'}) && + (($url =~ m{^\Q/public/$cdom/$cnum/syllabus\E($|\?)}) || + ($url =~ m{^\Q/adm/wrapper/ext/\E(?!https:)}))) { + unless ((&Apache::lonnet::uses_sts()) || (&Apache::lonnet::waf_allssl())) { + $usehttp = 1; + } + } + if ($env{'request.enc'}) { + $url = &Apache::lonenc::encrypted($url); + } + if ($url ne '') { + my $symb = $helper->{VARS}{'symb'}; + if ($url =~ m{^\Q/adm/wrapper/ext/\E}) { + my $link = $url; + ($link,$anchor) = ($url =~ /^([^\#]+)(?:|(\#[^\#]+))$/); + if ($anchor) { + ($symb) = ($helper->{VARS}{'symb'} =~ /^([^\#]+)/); + } + $url = $link; + } + $URLback = $url; + if ($usehttp) { + $URLback .= (($URLback =~ /\?/) ? '&':'?').'usehttp=1'; + } + unless ($plainurl =~ /\.page$/) { + $URLback .= (($URLback =~ /\?/) ? '&':'?').'symb='.&escape($symb.$anchor); + } + } + } elsif (($helper->{VARS}->{'postdata'} eq '/adm/navmaps') && + ($env{'request.course.id'})) { + $URLback=$helper->{VARS}->{'postdata'}; } # # Final adjustment of the font size: @@ -3121,18 +3658,23 @@ ENDPART $result = set_font_size($result); -#-- writing .tex file in prtspool + # Insert any babel headers required. + + $result = &collect_languages($result); + + +#-- writing .tex file in prtspool my $temp_file; my $identifier = &Apache::loncommon::get_cgi_id(); my $filename = "/home/httpd/prtspool/$env{'user.name'}_$env{'user.domain'}_printout_$identifier.tex"; - if (!($#print_array>0)) { + if (!($#print_array>0)) { unless ($temp_file = Apache::File->new('>'.$filename)) { $r->log_error("Couldn't open $filename for output $!"); - return SERVER_ERROR; + return SERVER_ERROR; } print $temp_file $result; my $begin=index($result,'\begin{document}',0); - my $inc=substr($result,0,$begin+16); + my $inc=substr($result,0,$begin+16); } else { my $begin=index($result,'\begin{document}',0); my $inc=substr($result,0,$begin+16); @@ -3141,11 +3683,11 @@ ENDPART $print_array[$i]=$result; } else { $print_array[$i].='\end{document}'; - $print_array[$i] = + $print_array[$i] = &latex_corrections($number_of_columns,$print_array[$i], - $selectionmade, + $selectionmade, $helper->{'VARS'}->{'ANSWER_TYPE'}); - + my $anobegin=index($print_array[$i],'\setcounter{page}',0); substr($print_array[$i],0,$anobegin)=''; $print_array[$i]=$inc.$print_array[$i]; @@ -3153,11 +3695,11 @@ ENDPART my $temp_file; my $newfilename=$filename; my $num=$i+1; - $newfilename =~s/\.tex$//; + $newfilename =~s/\.tex$//; $newfilename=sprintf("%s_%03d.tex",$newfilename, $num); unless ($temp_file = Apache::File->new('>'.$newfilename)) { $r->log_error("Couldn't open $newfilename for output $!"); - return SERVER_ERROR; + return SERVER_ERROR; } print $temp_file $print_array[$i]; } @@ -3192,11 +3734,11 @@ ENDPART 'cgi.'.$identifier.'.role' => $perm{'pav'}, 'cgi.'.$identifier.'.numberoffiles' => $#print_array, 'cgi.'.$identifier.'.studentnames' => $student_names, - 'cgi.'.$identifier.'.backref' => $URLback,}); + 'cgi.'.$identifier.'.backref' => &escape($URLback),}); &Apache::lonnet::appenv({"cgi.$identifier.user" => $env{'user.name'}, "cgi.$identifier.domain" => $env{'user.domain'}, - "cgi.$identifier.courseid" => $cnum, - "cgi.$identifier.coursedom" => $cdom, + "cgi.$identifier.courseid" => $cnum, + "cgi.$identifier.coursedom" => $cdom, "cgi.$identifier.resources" => $resources_printed}); my $end_page = &Apache::loncommon::end_page(); @@ -3243,12 +3785,13 @@ sub get_CODE { sub print_resources { my ($r,$helper,$person,$type,$moreenv,$master_seq,$remove_latex_header, $LaTeXwidth)=@_; - my $current_output = ''; + my $current_output = ''; my $printed = ''; my ($username,$userdomain,$usersection) = split /:/,$person; my $fullname = &get_name($username,$userdomain); my $namepostfix = "\\\\"; # Both anon and not anon should get the same vspace. + # # Figure out if we need to filter the output by # the incomplete problems for that person @@ -3260,7 +3803,7 @@ sub print_resources { $print_incomplete = 1; } if ($person eq 'anonymous') { - $namepostfix .="Name: "; + $namepostfix .=&mt('Name:')." "; $fullname = "CODE - ".$moreenv->{'CODE'}; } @@ -3269,24 +3812,29 @@ sub print_resources { my $i = 0; my $actually_printed = 0; # Count of resources printed. - #goes through all resources, checks if they are available for - #current student, and produces output + #goes through all resources, checks if they are available for + #current student, and produces output &Apache::lonxml::clear_problem_counter(); my %page_breaks = &get_page_breaks($helper); my $columns_in_format = (split(/\|/,$helper->{'VARS'}->{'FORMAT'}))[1]; # - # end each student with a + # end each student with a # Special that allows the post processor to even out the page # counts later. Nasty problem this... it would be really # nice to put the special in as a postscript comment # e.g. \special{ps:\ENDOFSTUDENTSTAMP} unfortunately, # The special gets passed the \ and dvips puts it in the output file - # so we will just rely on prntout.pl to strip ENDOFSTUDENTSTAMP from the + # so we will just rely on printout.pl to strip ENDOFSTUDENTSTAMP from the # postscript. Each ENDOFSTUDENTSTAMP will go on a line by itself. # my $syllabus_first = 0; + my $current_assignment = ""; + my $assignment; + my $courseidinfo = &get_course(); + my $possprint = scalar(@{$master_seq}); + foreach my $curresline (@{$master_seq}) { if (defined $page_breaks{$curresline}) { if($i != 0) { @@ -3295,18 +3843,22 @@ sub print_resources { } $current_output .= &get_extra_vspaces($helper, $curresline); $i++; - if ( !($type eq 'problems' && - ($curresline!~ m/\.(problem|exam|quiz|assess|survey|form|library|page)$/)) ) { - my ($map,$id,$res_url) = &Apache::lonnet::decode_symb($curresline); + my ($map,$id,$res_url) = &Apache::lonnet::decode_symb($curresline); + + # See if we need to emit a new header: + + if ( !($type eq 'problems' && + ($curresline!~ m/$LONCAPA::assess_page_re/)) ) { if ($print_incomplete && !&incomplete($username, $userdomain, $res_url)) { next; } $actually_printed++; # we're going to print one. + if (&Apache::lonnet::allowed('bre',$res_url)) { if ($res_url!~m|^ext/| && $res_url=~/\.(problem|exam|quiz|assess|survey|form|library|page|xml|html|htm|xhtml|xhtm)$/) { $printed .= $curresline.':'; - &Apache::lonxml::remember_problem_counter(); + &Apache::lonxml::remember_problem_counter(); my $rendered = &get_student_view_with_retries($curresline,$ssi_retry_count,$username,$userdomain,$env{'request.course.id'},'tex',$moreenv); if ($res_url =~ /\.page$/) { @@ -3319,7 +3871,7 @@ sub print_resources { if ($remove_latex_header eq 'YES') { $rendered = &latex_header_footer_remove($rendered); } else { - $rendered =~ s/\\end{document}\d*//; + $rendered =~ s/\\end\{document}\d*//; } } if(($helper->{'VARS'}->{'ANSWER_TYPE'} eq 'no') || @@ -3336,36 +3888,34 @@ sub print_resources { my $ansrendered = &Apache::loncommon::get_student_answers($curresline,$username,$userdomain,$env{'request.course.id'},%answerenv); if ($helper->{'VARS'}->{'ANSWER_TYPE'} eq 'no') { - $rendered=~s/(\\keephidden{ENDOFPROBLEM})/$ansrendered$1/; + $rendered=~s/(\\keephidden\{ENDOFPROBLEM})/$ansrendered$1/; } else { - - my $header =&print_latex_header($helper->{'VARS'}->{'LATEX_TYPE'}); unless ($helper->{'VARS'}->{'ANSWER_TYPE'} eq 'only') { - $header =~ s/\\begin{document}//; #<<<<< + $header =~ s/\\begin\{document}//; #<<<<< } my $title = &Apache::lonnet::gettitle($curresline); $title = &Apache::lonxml::latex_special_symbols($title); my $body ='\vskip 0 mm \noindent\textbf{'.$title.'}\vskip 0 mm '; $body .=&path_to_problem($res_url,$LaTeXwidth); $body .='\vskip 1 mm '.$ansrendered; - $body = &encapsulate_minipage($body); + $body = &encapsulate_minipage($body,$answerenv{'problem_split'}); $rendered = $header.$body; } } if ($helper->{'VARS'}->{'PRINT_ANNOTATIONS'} eq 'yes') { my $url = &Apache::lonnet::clutter($res_url); my $annotation = &annotate($url); - $rendered =~ s/(\\keephidden{ENDOFPROBLEM})/$annotation$1/; + $rendered =~ s/(\\keephidden\{ENDOFPROBLEM})/$annotation$1/; } my $junk; if ($remove_latex_header eq 'YES') { $rendered = &latex_header_footer_remove($rendered); } else { - $rendered =~ s/\\end{document}//; + $rendered =~ s/\\end\{document}//; } - $current_output .= $rendered; - } elsif ($res_url=~/\/(smppg|syllabus|aboutme|bulletinboard)$/) { + $current_output .= $rendered; + } elsif ($res_url=~/\/(smppg|syllabus|aboutme|bulletinboard|ext\.tool)$/) { if ($i == 1) { $syllabus_first = 1; } @@ -3374,15 +3924,15 @@ sub print_resources { if ($helper->{'VARS'}->{'PRINT_ANNOTATIONS'} eq 'yes') { my $url = &Apache::lonnet::clutter($res_url); my $annotation = &annotate($url); - $annotation =~ s/(\\end{document})/$annotation$1/; + $annotation =~ s/(\\end\{document})/$annotation$1/; } if ($remove_latex_header eq 'YES') { $rendered = &latex_header_footer_remove($rendered); } else { - $rendered =~ s/\\end{document}//; + $rendered =~ s/\\end\{document}//; } $current_output .= $rendered.'\vskip 0.5mm\noindent\makebox[\textwidth/$number_of_columns][b]{\hrulefill}\strut \vskip 0 mm \strut '; - } elsif($res_url = ~/\.pdf$/) { + } elsif($res_url =~ /\.pdf$/) { my $url = &Apache::lonnet::clutter($res_url); my $rendered = &include_pdf($url); if ($remove_latex_header ne 'NO') { @@ -3394,13 +3944,26 @@ sub print_resources { if ($remove_latex_header ne 'NO') { $rendered = &latex_header_footer_remove($rendered); } else { - $rendered =~ s/\\end{document}//; + $rendered =~ s/\\end\{document}//; } $current_output .= $rendered; } } $remove_latex_header = 'YES'; } + $assignment = &Apache::lonxml::latex_special_symbols( + &Apache::lonnet::gettitle($map), 'header'); + if (($assignment ne $current_assignment) && ($assignment ne "")) { + my $header_line = &format_page_header($LaTeXwidth, $parmhash{'print_header_format'}, + $assignment, $courseidinfo, + $fullname, $usersection); + my $header_start = ($columns_in_format == 1) ? '\lhead' + : '\fancyhead[LO]'; + $header_line = $header_start.'{'.$header_line.'}'; + $current_output = $current_output . $header_line; + $current_assignment = $assignment; + } + if (&Apache::loncommon::connection_aborted($r)) { last; } } # If we are printing incomplete it's possible we don't have @@ -3410,7 +3973,24 @@ sub print_resources { # if ($actually_printed == 0) { - $current_output = &encapsulate_minipage("\\vskip -10mm \nNo incomplete resources\n \\vskip 100 mm { }\n"); + my $message = &mt('No resources to print'); + if (!$possprint) { + if ($perm{'pav'} || $perm{'pfo'}) { + $message = &mt('There are no unhidden resources to print.')."\n\n". + &mt('The most likely reason is one of the following: ')."\n". + '\begin{itemize}'."\n". + '\item '.&mt("The 'Resource hidden from students' parameter is set for the folder being printed.")."\n". + '\item '.&mt("'Hidden' is checked in the Course Editor individually for each resource in the folder being printed.")."\n". + '\end{itemize}'."\n\n". + &mt("Note: to print a bubblesheet exam which you want to hide from students, ". + "use the Course Editor to check the 'Hidden' checkbox for the exam folder itself.")."\n"; + } + } elsif ($print_incomplete) { + $message = &mt('No incomplete resources'); + } + if ($message) { + $current_output = &encapsulate_minipage("\\vskip -10mm \n$message\n \\vskip 100 mm { }\n",$moreenv->{'problem_split'}); + } if ($remove_latex_header eq "NO") { $current_output = &print_latex_header() . $current_output; } else { @@ -3421,24 +4001,24 @@ sub print_resources { if ($syllabus_first) { $current_output =~ s/\\\\ Last updated:/Last updated:/ } - my $courseidinfo = &get_course(); my $currentassignment=&Apache::lonxml::latex_special_symbols($helper->{VARS}->{'assignment'},'header'); my $header_line = - &format_page_header($LaTeXwidth, $parmhash{'print_header_format'}, - $currentassignment, $courseidinfo, $fullname, $usersection); - my $header_start = ($columns_in_format == 1) ? '\lhead' - : '\fancyhead[LO]'; - $header_line = $header_start.'{'.$header_line.'}'; + &format_page_header($LaTeXwidth, $parmhash{'print_header_format'}, + $currentassignment, $courseidinfo, $fullname, $usersection); + my $header_start = ($columns_in_format == 1) ? '\lhead' : '\fancyhead[LO]'; + my $newheader = $header_start.'{'.$header_line.'}'; if ($current_output=~/\\documentclass/) { - $current_output =~ s/\\begin{document}/\\setlength{\\topmargin}{1cm} \\begin{document}\\noindent\\parbox{\\minipagewidth}{\\noindent$header_line$namepostfix}\\vskip 5 mm /; + $current_output =~ s/\\begin\{document}/\\setlength{\\topmargin}{1cm} \\begin{document}\\noindent\\parbox{\\minipagewidth}{\\noindent$newheader$namepostfix}\\vskip 5 mm /; + } else { - my $blankpages = + my $blankpages = '\clearpage\strut\clearpage'x$helper->{'VARS'}->{'EMPTY_PAGES'}; - + $current_output = '\strut\vspace*{-6 mm}\\newline'. ©right_line().' \newpage '.$blankpages.$end_of_student. '\setcounter{page}{1}\noindent\parbox{\minipagewidth}{\noindent'. - $header_line.$namepostfix.'} \vskip 5 mm '.$current_output; + $newheader.$namepostfix. '} \vskip 5 mm '.$current_output; + } # # Close the student bracketing. @@ -3447,22 +4027,54 @@ sub print_resources { } +sub printing_blocked { + my ($r,$blocktext) = @_; + my $title = &mt('Preparing Printout'); + &Apache::lonhtmlcommon::clear_breadcrumbs(); + &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/printout', + text=> $title}); + my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs($title); + &Apache::loncommon::content_type($r,'text/html'); + &Apache::loncommon::no_cache($r); + $r->send_http_header; + $r->print(&Apache::loncommon::start_page('Preparing Printout'). + $breadcrumbs. + $blocktext. + &Apache::loncommon::end_page()); + return; +} + sub handler { my $r = shift; - - &init_perm(); + if ($env{'request.course.id'}) { + my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; + my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + my $clientip = &Apache::lonnet::get_requestor_ip($r); + my ($blocked,$blocktext) = + &Apache::loncommon::blocking_status('printout',$clientip,$cnum,$cdom); + if ($blocked) { + my $checkrole = "cm./$cdom/$cnum"; + if ($env{'request.course.sec'} ne '') { + $checkrole .= "/$env{'request.course.sec'}"; + } + unless ((&Apache::lonnet::allowed('evb',undef,undef,$checkrole)) && + ($env{'request.role'} !~ m{^st\./$cdom/$cnum})) { + &printing_blocked($r,$blocktext); + return OK; + } + } + } + + &init_perm(); my $helper = printHelper($r); if (!ref($helper)) { return $helper; } - - - %parmhash=&Apache::lonnet::coursedescription($env{'request.course.id'}); - + %parmhash=&Apache::lonnet::coursedescription($env{'request.course.id'}); # If a figure conversion queue file exists for this user.domain # we delete it since it can only be bad (if it were good, printout.pl @@ -3472,11 +4084,10 @@ sub handler { if(-e $conversion_queuefile) { unlink $conversion_queuefile; } - &output_data($r,$helper,\%parmhash); return OK; -} +} use Apache::lonhelper; @@ -3518,18 +4129,13 @@ sub get_randomly_ordered_warning { if (defined($navmap)) { my $res = $navmap->getResourceByUrl($map); if ($res) { - my $func = + my $func = sub { return ($_[0]->is_map() && $_[0]->randomorder); }; my @matches = $navmap->retrieveResources($res, $func,1,1,1); - if (@matches) { - $message = "Some of the items below are in folders set to be randomly ordered. However, when printing the contents of these folders, they will be printed in the original order for all students, not the randomized order."; - } - } - if ($message) { - return ''.$message.''; + } } else { - $message = "Retrieval of information about ordering of resources failed."; + $message = "Retrieval of information about ordering of resources failed."; return ''.$message.''; } return; @@ -3562,12 +4168,12 @@ sub printHelper { # write it by hand Apache::loncommon::get_unprocessed_cgi($ENV{QUERY_STRING}); - + my $helper = Apache::lonhelper::helper->new("Printing Helper"); $helper->declareVar('symb'); - $helper->declareVar('postdata'); - $helper->declareVar('curseed'); - $helper->declareVar('probstatus'); + $helper->declareVar('postdata'); + $helper->declareVar('curseed'); + $helper->declareVar('probstatus'); $helper->declareVar('filename'); $helper->declareVar('construction'); $helper->declareVar('assignment'); @@ -3579,7 +4185,7 @@ sub printHelper { $helper->declareVar("STUDENTS"); $helper->declareVar("EXTRASPACE"); - + # The page breaks and extra spaces @@ -3587,19 +4193,19 @@ sub printHelper { # But we only do this in the initial state so that they are allowed to change. # - + &Apache::loncommon::restore_course_settings('print', {'pagebreaks' => 'scalar', 'extraspace' => 'scalar', 'extraspace_units' => 'scalar', 'lastprinttype' => 'scalar'}); - + # This will persistently load in the data we want from the # very first screen. - + if($helper->{VARS}->{PRINT_TYPE} eq $env{'form.lastprinttype'}) { if (!defined ($env{"form.CURRENT_STATE"})) { - + $helper->{VARS}->{FINISHPAGE} = $env{'form.pagebreaks'}; $helper->{VARS}->{EXTRASPACE} = $env{'form.extraspace'}; $helper->{VARS}->{EXTRASPACE_UNITS} = $env{'form.extraspace_units'}; @@ -3621,7 +4227,9 @@ sub printHelper { $helper->{VARS}->{'construction'} = 1; } else { if ($env{'form.postdata'}) { - $helper->{VARS}->{'symb'} = &Apache::lonnet::symbread($env{'form.postdata'}); + unless ($env{'form.postdata'} eq '/adm/navmaps') { + $helper->{VARS}->{'symb'} = &Apache::lonnet::symbread($env{'form.postdata'}); + } if ( $helper->{VARS}->{'symb'} eq '') { $helper->{VARS}->{'postdata'} = $env{'form.postdata'}; } @@ -3630,35 +4238,62 @@ sub printHelper { $helper->{VARS}->{'symb'} = $env{'form.symb'}; } if ($env{'form.url'}) { - $helper->{VARS}->{'symb'} = &Apache::lonnet::symbread($helper->{VARS}->{'postdata'}); + unless ($env{'form.url'} eq '/adm/navmaps') { + $helper->{VARS}->{'symb'} = &Apache::lonnet::symbread($helper->{VARS}->{'postdata'}); + } } - - } - - if ($env{'form.symb'}) { - $helper->{VARS}->{'symb'} = $env{'form.symb'}; } - if ($env{'form.url'}) { - $helper->{VARS}->{'symb'} = &Apache::lonnet::symbread($helper->{VARS}->{'postdata'}); + if ($helper->{VARS}->{'symb'} ne '') { + $helper->{VARS}->{'symb'}= + &Apache::lonenc::check_encrypt($helper->{VARS}->{'symb'}); + } + my ($resourceTitle,$sequenceTitle,$mapTitle,$cdom,$cnum); + if ($helper->{VARS}->{'postdata'} eq '/adm/navmaps') { + $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; + $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + if ($env{'course.'.$env{'request.course.id'}.'.url'} eq + "uploaded/$cdom/$cnum/default.sequence") { + my $navmap = Apache::lonnavmaps::navmap->new(); + if (ref($navmap)) { + my @toplevelres = $navmap->retrieveResources('',sub { !(($_[0]->is_map()) || ($_[0]->src =~ /^\/adm\/navmaps/)) },0,0); + if (@toplevelres) { + my @printable; + if ($perm{'pav'} || $perm{'pfo'}) { + @printable = @toplevelres; + } else { + @printable = $navmap->retrieveResources(undef,sub { $_[0]->resprintable() },0,1); + } + if (@printable) { + $sequenceTitle = 'Main Content'; + $mapTitle = $sequenceTitle; + } + } + } + } + } else { + ($resourceTitle,$sequenceTitle,$mapTitle) = &details_for_menu($helper); } - $helper->{VARS}->{'symb'}= - &Apache::lonenc::check_encrypt($helper->{VARS}->{'symb'}); - my ($resourceTitle,$sequenceTitle,$mapTitle) = &details_for_menu($helper); if ($sequenceTitle ne '') {$helper->{VARS}->{'assignment'}=$sequenceTitle;} - # Extract map my $symb = $helper->{VARS}->{'symb'}; my ($map, $id, $url); my $subdir; my $is_published=0; # True when printing from resource space. - my $res_printable = 1; # By default the current resource is printable. + my $res_printable = 1; # By default the current resource is printable. + my $res_error; my $userCanPrint = ($perm{'pav'} || $perm{'pfo'}); + my $res_printstartdate; + my $res_printenddate; + my $map_open = 0; + my $map_close = 0xffffffff; + my $course_open = 0; + my $course_close = 0xffffffff; # Get the resource name from construction space if ($helper->{VARS}->{'construction'}) { - $resourceTitle = substr($helper->{VARS}->{'filename'}, + $resourceTitle = substr($helper->{VARS}->{'filename'}, rindex($helper->{VARS}->{'filename'}, '/')+1); $subdir = substr($helper->{VARS}->{'filename'}, 0, rindex($helper->{VARS}->{'filename'}, '/') + 1); @@ -3667,11 +4302,38 @@ sub printHelper { if ($symb ne '') { ($map, $id, $url) = &Apache::lonnet::decode_symb($symb); - $helper->{VARS}->{'postdata'} = + $helper->{VARS}->{'postdata'} = &Apache::lonenc::check_encrypt(&Apache::lonnet::clutter($url)); - my $navmap = Apache::lonnavmaps::navmap->new(); - my $res = $navmap->getBySymb($symb); - $res_printable = $res->resprintable() || $userCanPrint; #printability in course context + } elsif (($helper->{VARS}->{'postdata'} eq '/adm/navmaps') && + ($env{'request.course.id'} ne '')) { + if ($env{'course.'.$env{'request.course.id'}.'.url'} eq + "uploaded/$cdom/$cnum/default.sequence") { + $map = $env{'course.'.$env{'request.course.id'}.'.url'}; + $url = $helper->{VARS}->{'postdata'}; + } + } + if (($symb ne '') || ($map ne '')) { + if (!$userCanPrint) { + my $navmap = Apache::lonnavmaps::navmap->new(); + if (ref($navmap)) { + my $res; + if ($symb ne '') { + $res = $navmap->getBySymb($symb); + } elsif ($map ne '') { + $res = $navmap->getResourceByUrl($map); + } + if (ref($res)) { + $res_printable = $res->resprintable(); #printability in course context + ($res_printstartdate, $res_printenddate) = &get_print_dates($res); + ($course_open, $course_close) = &course_print_dates($res); + ($map_open, $map_close) = &map_print_dates($res); + } else { + $res_error = 1; + } + } else { + $res_error = 1; + } + } } else { # Resource space. @@ -3683,13 +4345,18 @@ sub printHelper { my $postdata = $helper->{VARS}->{'postdata'}; $resourceTitle = substr($postdata, rindex($postdata, '/') + 1); } - $subdir = &Apache::lonnet::filelocation("", $url); + if (($url eq '/adm/navmaps') && ($map eq $env{'course.'.$env{'request.course.id'}.'.url'})) { + $res_printable=0; + } else { + $subdir = &Apache::lonnet::filelocation("", $url); + } } if (!$helper->{VARS}->{'curseed'} && $env{'form.curseed'}) { $helper->{VARS}->{'curseed'}=$env{'form.curseed'}; } + if (!$helper->{VARS}->{'probstatus'} && $env{'form.problemtype'}) { $helper->{VARS}->{'probstatus'}=$env{'form.problemstatus'}; } @@ -3721,7 +4388,6 @@ sub printHelper { if ($resourceTitle && $res_printable) { push @{$printChoices}, ["$resourceTitle (".&mt('the resource you just saw on the screen').")", 'current_document', 'PAGESIZE']; } - # Useful filter strings @@ -3746,18 +4412,16 @@ sub printHelper { my $start_new_option; if ($perm{'pav'}) { - $start_new_option = - "