--- loncom/homework/structuretags.pm 2002/05/03 19:32:57 1.93 +++ loncom/homework/structuretags.pm 2013/06/05 15:37:26 1.512.2.3 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # definition of tags that give a structure to a document # -# $Id: structuretags.pm,v 1.93 2002/05/03 19:32:57 albertel Exp $ +# $Id: structuretags.pm,v 1.512.2.3 2013/06/05 15:37:26 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -25,27 +25,167 @@ # # http://www.lon-capa.org/ # -# 2/19 Guy -# 6/26/2001 fixed extra web display at end of tags -# 8/17,8/18,8/20 Gerd Kortemeyer +### + +=pod + +=head1 NAME + +Apache::structuretags + +=head1 SYNOPSIS + + +This is part of the LearningOnline Network with CAPA project +described at http://www.lon-capa.org. + + +=head1 NOTABLE SUBROUTINES + +=over + +=item + +=back + +=cut + package Apache::structuretags; use strict; use Apache::lonnet; - +use Apache::File(); +use Apache::lonmenu; +use Apache::lonlocal; +use Apache::lonxml; +use Apache::londefdef; +use Apache::lonenc(); +use Apache::loncommon(); +use Time::HiRes qw( gettimeofday tv_interval ); +use lib '/home/httpd/lib/perl/'; +use LONCAPA; + BEGIN { - &Apache::lonxml::register('Apache::structuretags',('block','while','randomlist','problem','library','web','tex','part','preduedate','postanswerdate','solved','notsolved','startouttext','endouttext')); -# &Apache::lonxml::register_insert('problem','',('part','postanswerdate','preduedate')) + &Apache::lonxml::register('Apache::structuretags',('block','languageblock','translated','instructorcomment','while','randomlist','problem','library','web','tex','part','preduedate','postanswerdate','solved','notsolved','problemtype','startpartmarker','startouttext','endpartmarker','endouttext','simpleeditbutton','definetag')); +} + + +#--------------------------------------------------------------------------------- +# +# This section of code deals with hyphenation management. +# We must do three things: +# - keep track fo the desired languages to alter the header. +# - provide hyphenation selection as needed by each language that appears in the +# text. +# - Provide the header text needed to make available the desired hyphenations. +# +# + +# Hash whose keys are the languages encountered in the document/resource. +# + +my %languages_required; +## +# Given a language selection as input returns a chunk of LaTeX that +# selects the required hyphenator. +# +# @param language - the language being selected. +# @return string +# @retval The LaTeX needed to select the hyphenation appropriate to the language. +# +sub select_hyphenation { + my $language = shift; + + $language = &Apache::loncommon::latexlanguage($language); # Translate -> latex language. + + # If there is no latex language there's not much we can do: + + if ($language) { + &require_language($language); + my $babel_hyphenation = "\\selectlanguage{$language}"; + + return $babel_hyphenation; + } else { + return ''; + } +} +## +# Selects hyphenation based on the current problem metadata. +# This requires that +# - There is a language metadata item set for the problem. +# - The language has a latex/babel hyphenation. +# +# @note: Uses &Apache::lonxml::request to locate the Uri associated with +# this problem. +# @return string (possibly empty). +# @retval If not empty an appropriate \selectlanguage{} directive. +# +sub select_metadata_hyphenation { + my $uri = $Apache::lonxml::request->uri; + my $language = &Apache::lonnet::metadata($uri, 'language'); + my $latex_language = &Apache::loncommon::latexhyphenation($language); + if ($latex_language) { + return '\selectlanguage{'.$latex_language."}\n"; + } + return ''; # no latex hyphenation or no lang metadata. +} + + +## +# Clears the set of languages required by the document being rendered. +# +sub clear_required_languages { + %languages_required = (); +} +## +# Allows an external client of this module to register a need for a language: +# +# @param LaTeX language required: +# +sub require_language { + my $language = shift; + $languages_required{$language} = 1; } +## +# Provides the header for babel that indicates the languages +# the document requires. +# @return string +# @retval \usepackage[lang1,lang2...]{babel} +# @retval '' if there are no languages_required. +sub languages_header { + my $header =''; + my @languages = (keys(%languages_required)); + + # Only generate the header if there are languages: + + if (scalar @languages) { + my $language_list = join(',', (@languages)); + $header = '\usepackage['.$language_list."]{babel}\n"; + } + return $header; +} + +#---------------------------------------------------------------------------------- + sub start_web { - my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; - my $bodytext=&Apache::lonxml::get_all_text("/web",$$parser[$#$parser]); - if ($target eq 'web') { - return $bodytext; - } - return ''; + my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; + if ($target ne 'edit' && $target ne 'modified') { + my $bodytext=&Apache::lonxml::get_all_text("/web",$parser,$style); + if ($target eq 'web' || $target eq 'webgrade') { + return $bodytext; + } + } elsif ($target eq "edit" ) { + my $bodytext = + &Apache::lonxml::get_all_text_unbalanced("/web",$parser); + my $result = &Apache::edit::tag_start($target,$token); + $result .= &Apache::edit::editfield($token->[1],$bodytext,'',80,1); + return $result; + } elsif ( $target eq "modified" ) { + return $token->[4].&Apache::edit::modifiedfield("/web",$parser); + } + return ''; } sub end_web { @@ -53,628 +193,2514 @@ sub end_web { } sub start_tex { - my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; - my $bodytext=&Apache::lonxml::get_all_text("/tex",$$parser[$#$parser]); - if ($target eq 'tex') { - return $bodytext - } - return ''; + my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; + my $result=''; + if ($target ne 'edit' && $target ne 'modified') { + my $bodytext=&Apache::lonxml::get_all_text("/tex",$parser,$style); + if ($target eq 'tex') { + + # If inside a table, occurrences of \\ must be removed; + # else the table blows up. + + if (&Apache::londefdef::is_inside_of($tagstack, "table")) { + $bodytext =~ s/\\\\//g; + } + return $bodytext.'{}'; + } + } elsif ($target eq "edit" ) { + my $bodytext = + &Apache::lonxml::get_all_text_unbalanced("/tex",$parser); + my $result = &Apache::edit::tag_start($target,$token); + $result .= &Apache::edit::editfield($token->[1],$bodytext,'',80,1); + return $result; + } elsif ( $target eq "modified" ) { + return $token->[4].&Apache::edit::modifiedfield("/tex",$parser); + } + return $result;; } sub end_tex { return ''; } +sub homework_js { + return &Apache::loncommon::resize_textarea_js(). + &setmode_javascript(). + <<'JS'; + +JS +} + +sub setmode_javascript { + return <<"ENDSCRIPT"; + +ENDSCRIPT +} + sub page_start { - my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; - my %found; - foreach my $taginside ($tagstack) { - foreach my $taglookedfor ('html','body','form') { - if ($taginside =~ /^$taglookedfor$/i) { $found{$taglookedfor} = 1; } - } - } - - my $result; - my $head_tag_start; - if (!defined($found{'html'})) { - $result=&Apache::londefdef::start_html($target,$token,$tagstack,$parstack, - $parser,$safeeval); - $head_tag_start=''.&Apache::lonxml::registerurl(undef,$target); - } - my $body_tag_start; - if (!defined($found{'body'})) { - $body_tag_start=' 'math', + ); + $extra_head .= &Apache::lonhtmlcommon::htmlareaselectactive(\%textarea_args); + } + my $is_task = ($env{'request.uri'} =~ /\.task$/); + my $needs_upload; + my ($symb)= &Apache::lonnet::whichuser(); + my ($map,$resid,$resurl)=&Apache::lonnet::decode_symb($symb); + if ($is_task) { + $extra_head .= &Apache::lonhtmlcommon::file_submissionchk_js(); + } else { + if (&Apache::lonnet::EXT("resource.$Apache::inputtags::part.uploadedfiletypes") ne '') { + unless ($env{'request.state'} eq 'construct') { + my $navmap = Apache::lonnavmaps::navmap->new(); + if (ref($navmap)) { + my $mapres = $navmap->getResourceByUrl($map); + my $is_page; + if (ref($mapres)) { + $is_page = $mapres->is_page(); + } + unless ($is_page) { + $needs_upload = 1; + } + } + } + } else { + unless ($env{'request.state'} eq 'construct') { + my $navmap = Apache::lonnavmaps::navmap->new(); + if (ref($navmap)) { + my $mapres = $navmap->getResourceByUrl($map); + my $is_page; + if (ref($mapres)) { + $is_page = $mapres->is_page(); + } + unless ($is_page) { + my $res = $navmap->getBySymb($symb); + if (ref($res)) { + my $partlist = $res->parts(); + if (ref($partlist) eq 'ARRAY') { + foreach my $part (@{$partlist}) { + my @types = $res->responseType($part); + my @ids = $res->responseIds($part); + for (my $i=0; $i < scalar(@ids); $i++) { + if ($types[$i] eq 'essay') { + my $partid = $part.'_'.$ids[$i]; + if (&Apache::lonnet::EXT("resource.$partid.uploadedfiletypes") ne '') { + $needs_upload = 1; + last; + } + } + } + } + } + } + } + } + } + } + if ($needs_upload) { + $extra_head .= &Apache::lonhtmlcommon::file_submissionchk_js(); + } + } + + my %body_args; + if (defined($found{'html'})) { + $body_args{'skip_phases'}{'head'}=1; + } else { + + $extra_head .= &Apache::lonhtmlcommon::spellheader(); + + $extra_head .= &Apache::londefdef::generate_css_links(); + + if ($env{'request.state'} eq 'construct') { + $extra_head.=&Apache::edit::js_change_detection(). + "\n"; + } + } + + my $pageheader = ''; + if (defined($found{'body'})) { + $body_args{'skip_phases'}{'body'}=1; + } elsif (!defined($found{'body'}) + && $env{'request.state'} eq 'construct') { + if ($target eq 'web' || $target eq 'edit') { + # Breadcrumbs for Authoring Space + &Apache::lonhtmlcommon::clear_breadcrumbs(); + &Apache::lonhtmlcommon::add_breadcrumb({ + 'text' => 'Authoring Space', + 'href' => &Apache::loncommon::authorspace($env{'request.uri'}), + }); + # breadcrumbs (and tools) will be created + # in start_page->bodytag->innerregister + +# FIXME Where are we? +# &Apache::lonhtmlcommon::add_breadcrumb({ +# 'text' => 'Problem Editing', # 'Problem Testing' +# 'href' => '', +# }); + $pageheader =&Apache::loncommon::head_subbox( + &Apache::loncommon::CSTR_pageheader()); + } + } elsif (!defined($found{'body'})) { + my %add_entries; + my $background=&Apache::lonxml::get_param('background',$parstack, + $safeeval); + if ($background ne '' ) { + $add_entries{'background'} = $background; + } + + my $bgcolor=&Apache::lonxml::get_param('bgcolor',$parstack, + $safeeval); + if ($bgcolor eq '' ) { $bgcolor = '#FFFFFF'; } + + $body_args{'bgcolor'} = $bgcolor; + # $body_args{'no_title'} = 1; + $body_args{'force_register'} = 1; + $body_args{'add_entries'} = \%add_entries; + if ( $env{'request.state'} eq 'construct') { + $body_args{'only_body'} = 1; + } + } + $body_args{'no_auto_mt_title'} = 1; + my $page_start = &Apache::loncommon::start_page($name,$extra_head, + \%body_args); + $page_start .= $pageheader; + if (!defined($found{'body'}) + && $env{'request.state'} ne 'construct' + && ($target eq 'web' || $target eq 'webgrade')) { + + my ($symb,undef,undef,undef,$publicuser)= &Apache::lonnet::whichuser(); + if ($symb eq '' && !$publicuser) { + $page_start .= '

' + .&mt('Browsing resource, all submissions are temporary.') + .'

'; + } + } + + if (!defined($found{'body'}) && $env{'request.state'} ne 'construct') { + $page_start .= &Apache::lonxml::message_location(); + } + my $form_tag_start; + if (!defined($found{'form'})) { + $form_tag_start='
'."\n"; + } + } + return ($page_start,$form_tag_start); +} + +#use Time::HiRes(); +sub get_resource_name { + my ($parstack,$safeeval)=@_; + my $name; + if (defined($Apache::lonhomework::name)) { + $name = $Apache::lonhomework::name; + } else { + my ($symb)=&Apache::lonnet::whichuser(); + $name=&Apache::lonnet::gettitle($symb); + if ($name eq '') { + $name=&Apache::lonnet::EXT('resource.title'); + if ($name eq 'con_lost') { $name = ''; } + } + if ($name!~/\S+/) { + $name=$env{'request.uri'}; + $name=~s-.*/([^/]+)$-$1-; + } + # The name has had html tags escaped: + + $name=~s/<//gs; + + $Apache::lonhomework::name=$name; + } + return $name; +} + +sub setup_rndseed { + my ($safeeval,$target)=@_; + my ($symb)=&Apache::lonnet::whichuser(); + my ($questiontype,$set_safespace,$rndseed); + if ($target eq 'analyze') { + $questiontype = $env{'form.grade_questiontype'}; + } + unless (defined($questiontype)) { + $questiontype = $Apache::lonhomework::type; + } + if ($env{'request.state'} eq "construct" + || $symb eq '' + || $Apache::lonhomework::type eq 'practice' + || $Apache::lonhomework::history{'resource.CODE'}) { + &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, + ['rndseed']); + $rndseed=$env{'form.rndseed'}; + if (!$rndseed) { + $rndseed=$Apache::lonhomework::history{'rndseed'}; + if (!$rndseed) { + $rndseed=time; + } + $env{'form.rndseed'}=$rndseed; + } + if (($env{'request.state'} eq "construct") && + ($Apache::lonhomework::type eq 'randomizetry')) { + my $tries = $Apache::lonhomework::history{"resource.$Apache::inputtags::part.tries"}; + if ($tries) { + $rndseed += $tries; + } + $env{'form.'.$Apache::inputtags::part.'.rndseed'}=$rndseed; + } + if ( ($env{'form.resetdata'} eq &mt('New Problem Variation') + && $env{'form.submitted'} eq 'yes') || + $env{'form.newrandomization'} eq &mt('New Randomization')) { + srand(time); + $rndseed=int(rand(2100000000)); + $env{'form.rndseed'}=$rndseed; + delete($env{'form.resetdata'}); + delete($env{'form.newrandomization'}); + } + $rndseed=~s/\,/\:/g; + $rndseed=~s/[^\w\d\:\-]//g; + if (defined($rndseed)) { + my ($c1,$c2)=split(/\:/,$rndseed); + unless ($c2) { $c2=0; } + unless (($c1==int($c1)) && ($c2==int($c2))) { + $rndseed=join(':',&Apache::lonnet::digest($rndseed)); + } + } + if ($Apache::lonhomework::history{'resource.CODE'}) { + $rndseed=&Apache::lonnet::rndseed(); + } + $set_safespace = 1; + } elsif ($questiontype eq 'randomizetry') { + if ($target eq 'analyze') { + if (defined($env{'form.grade_rndseed'})) { + $rndseed = $env{'form.grade_rndseed'}; + } + } + unless (($target eq 'analyze') && (defined($rndseed))) { + $rndseed=&Apache::lonnet::rndseed(); + my $curr_try = $Apache::lonhomework::history{"resource.$Apache::inputtags::part.tries"}; + if ($Apache::inputtags::status[-1] eq 'CAN_ANSWER') { + $curr_try ++; + } + if ($rndseed =~/^(\d+)[,:](\d+)$/) { + $rndseed = $1; + } + if ($curr_try) { + my $reqtries = &Apache::lonnet::EXT("resource.$Apache::inputtags::part.randomizeontries"); + if (($reqtries =~ /^\d+$/) && ($reqtries > 1)) { + my $inc = int(($curr_try-1)/$reqtries); + $rndseed += $inc; + } else { + $rndseed += $curr_try; + } + } + } + $set_safespace = 1; + } + if ($set_safespace) { + if ($safeeval) { + &Apache::lonxml::debug("Setting rndseed to $rndseed"); + &Apache::run::run('$external::randomseed="'.$rndseed.'";',$safeeval); + } + } + unless (($env{'request.state'} eq "construct") || ($symb eq '')) { + $env{'form.'.$Apache::inputtags::part.'.rndseed'}=$rndseed; + } + return $rndseed; +} + +sub remember_problem_state { + return ' + + + '; +} + +sub problem_edit_action_button { + my ($name,$action,$accesskey,$text,$flag)=@_; + my $actionscript="setmode(this.form,'$action')"; + return "\n"; +} + +sub problem_edit_buttons { + my ($mode)=@_; +# Buttons that do not save + my $result='
'. + &problem_edit_action_button('subdiscview','discard','d','Discard Edits and View',1); + if ($mode eq 'editxml') { + $result.=&problem_edit_action_button('subedit','edit','e','Edit',1); + $result.=&problem_edit_action_button('subundo','undoxml','u','Undo',1); + $result.=&Apache::lonhtmlcommon::dragmath_button("LC_editxmltext",1); + } else { + $result.=&problem_edit_action_button('subeditxml','editxml','x','EditXML',1); + $result.=&problem_edit_action_button('subundo','undo','u','Undo',1); + } + $result.="\n
"; +# Buttons that save + $result.='
'; + if ($mode eq 'editxml') { + $result.=&problem_edit_action_button('subsaveedit','saveeditxml','s','Save and EditXML'); + $result.=&problem_edit_action_button('subsaveview','saveviewxml','v','Save and View'); + } else { + $result.=&problem_edit_action_button('subsaveedit','saveedit','s','Save and Edit'); + $result.=&problem_edit_action_button('subsaveview','saveview','v','Save and View'); + } + $result.="\n
\n"; + return $result; +} + +sub problem_edit_header { + return ''. + &remember_problem_state('edit').' +
+
+'.&mt('Problem Editing').&Apache::loncommon::help_open_menu('Problem Editing','Problem_Editor_XML_Index',5,'Authoring').' +
'. +''. +&problem_edit_buttons().' +
+'.&Apache::lonxml::message_location().' +
+'. + '
'; +} + +sub problem_edit_footer { + return '

+ +'. + "\n
\n".&Apache::loncommon::end_page(); +} + +sub option { + my ($value,$name) = @_; + my $result ="