--- loncom/homework/structuretags.pm 2003/07/17 18:42:13 1.198
+++ loncom/homework/structuretags.pm 2019/10/31 15:01:22 1.564
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# definition of tags that give a structure to a document
#
-# $Id: structuretags.pm,v 1.198 2003/07/17 18:42:13 sakharuk Exp $
+# $Id: structuretags.pm,v 1.564 2019/10/31 15:01:22 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -25,9 +25,30 @@
#
# 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;
@@ -36,17 +57,133 @@ 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','languageblock','instructorcomment','while','randomlist','problem','library','web','tex','part','preduedate','postanswerdate','solved','notsolved','startouttext','endouttext',
-'simpleeditbutton','definetag'));
+ &Apache::lonxml::register('Apache::structuretags',('block','languageblock','translated','instructorcomment','while','randomlist','problem','library','web','print','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)=@_;
- if (!($target eq 'web' || $target eq 'edit' || $target eq 'modified' ||
- $target eq 'answer' || $target eq 'grade' || $target eq 'meta' )) {
- my $bodytext=&Apache::lonxml::get_all_text("/web",$parser);
+ 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 '';
}
@@ -55,15 +192,51 @@ sub end_web {
return '';
}
+sub start_print {
+ my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
+ if ($target ne 'edit' && $target ne 'modified') {
+ if ($target ne 'tex') {
+ my $skip = &Apache::lonxml::get_all_text("/print",$parser,$style);
+ &Apache::lonxml::debug("skipping ahead :$skip: $$parser[-1]");
+ }
+ } elsif ($target eq "edit") {
+ my $bodytext = &Apache::lonxml::get_all_text_unbalanced("/print",$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("/print",$parser);
+ }
+ return '';
+}
+
+sub end_print {
+ return '';
+}
+
sub start_tex {
- my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
+ my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
my $result='';
- if (!($target eq 'edit' || $target eq 'modified' ||
- $target eq 'answer' || $target eq 'grade' || $target eq 'meta' )) {
- &Apache::lonxml::debug("tex 1");
- my $bodytext=&Apache::lonxml::get_all_text("/tex",$parser);
- } elsif ($target eq 'tex') {
- $result=&Apache::lonxml::get_all_text("/tex",$parser);
+ 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;;
}
@@ -72,241 +245,1513 @@ sub end_tex {
return '';
}
+sub homework_js {
+ my ($postsubmit,$timeout);
+ if (($env{'request.course.id'}) && ($env{'request.state'} ne 'construct')) {
+ my $crstype = &Apache::loncommon::course_type();
+ if ($crstype eq 'Community') {
+ $crstype = 'community';
+ } elsif ($crstype eq 'Placement') {
+ $crstype = 'placement';
+ } else {
+ if ($env{'course.'.$env{'request.course.id'}.'.internal.coursecode'}) {
+ $crstype = 'official';
+ } elsif ($env{'course.'.$env{'request.course.id'}.'.internal.textbook'}) {
+ $crstype = 'textbook';
+ } else {
+ $crstype = 'unofficial';
+ }
+ }
+ $postsubmit = $env{'course.'.$env{'request.course.id'}.'.internal.postsubmit'};
+ if ($postsubmit eq '') {
+ my %domdefs = &Apache::lonnet::get_domain_defaults($env{'course.'.$env{'request.course.id'}.'.domain'});
+ $postsubmit = $domdefs{'postsubmit'};
+ unless ($postsubmit eq 'off') {
+ $timeout = $domdefs{$crstype.'postsubtimeout'};
+ }
+ } elsif ($postsubmit eq '0') {
+ $postsubmit = 'off';
+ } elsif ($postsubmit eq '1') {
+ $postsubmit = 'on';
+ $timeout = $env{'course.'.$env{'request.course.id'}.'.internal.postsubtimeout'};
+ if ($timeout eq '') {
+ my %domdefs = &Apache::lonnet::get_domain_defaults($env{'course.'.$env{'request.course.id'}.'.domain'});
+ $timeout = $domdefs{$crstype.'postsubtimeout'};
+ }
+ }
+ if ($timeout eq '') {
+ $timeout = 60;
+ }
+ } else {
+ my %domdefs = &Apache::lonnet::get_domain_defaults($env{'request.role.domain'});
+ $postsubmit = $domdefs{'postsubmit'};
+ unless ($postsubmit eq 'off') {
+ $timeout = 60;
+ }
+ }
+ my $jstimeout = 0;
+ if ($timeout) {
+ $jstimeout = 1000 * $timeout;
+ }
+ return &Apache::loncommon::resize_textarea_js().
+ &Apache::loncommon::colorfuleditor_js().
+ &setmode_javascript().
+ <<"JS";
+
+JS
+}
+
+sub setmode_javascript {
+ return <<"ENDSCRIPT";
+
+ENDSCRIPT
+}
+
sub page_start {
- my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
+ my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$name,
+ $extra_head)=@_;
my %found;
- foreach my $taginside ($tagstack) {
+ 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::lonmenu::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,$partlist);
+ 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;
+ }
+ if ((ref($tagstack) eq 'ARRAY') && ($tagstack->[-1] eq 'problem')) {
+ my $res = $navmap->getBySymb($symb);
+ if (ref($res)) {
+ $partlist = $res->parts();
+ }
+ }
+ }
+ }
+ } 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();
+ }
+ if ($is_page) {
+ if ((ref($tagstack) eq 'ARRAY') && ($tagstack->[-1] eq 'problem')) {
+ my $res = $navmap->getBySymb($symb);
+ if (ref($res)) {
+ $partlist = $res->parts();
+ }
+ }
+ } else {
+ my $res = $navmap->getBySymb($symb);
+ if (ref($res)) {
+ $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";
+ if ($target eq 'edit') {
+ $extra_head .= &Apache::edit::js_update_linknum();
+ }
}
- $body_tag_start.='>'.&Apache::lonmenu::menubuttons(undef,$target,1);
- if ($target eq 'web' && $ENV{'request.state'} ne 'construct') {
- my ($symb,undef,undef,undef,$publicuser)=
- &Apache::lonxml::whichuser();
- if ($symb eq '' && !$publicuser) {
- my $help = &Apache::loncommon::help_open_topic("Ambiguous_Reference");
- $help="Browsing resource, all submissions are temporary.
";
- $body_tag_start.=$help;
+ }
+
+ 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') {
+ unless ($env{'form.inhibitmenu'} eq 'yes') {
+ # 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;
+ } elsif ($target eq 'web') {
+ $body_args{'print_suppress'} = 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".&Apache::loncommon::end_page();
+}
+
+sub option {
+ my ($value,$name) = @_;
+ my $result ="