--- loncom/homework/structuretags.pm 2014/11/24 02:36:26 1.524 +++ loncom/homework/structuretags.pm 2015/04/10 08:22:21 1.533 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # definition of tags that give a structure to a document # -# $Id: structuretags.pm,v 1.524 2014/11/24 02:36:26 raeburn Exp $ +# $Id: structuretags.pm,v 1.533 2015/04/10 08:22:21 droeschl Exp $ # # Copyright Michigan State University Board of Trustees # @@ -224,9 +224,55 @@ sub end_tex { } sub homework_js { + my ($postsubmit,$timeout); + if (($env{'request.course.id'}) && ($env{'request.state'} ne 'construct')) { + my $crstype; + if (&Apache::loncommon::course_type() eq 'Community') { + $crstype = 'community'; + } 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"; \n"; + if ($target eq 'edit') { + $extra_head .= &Apache::edit::js_update_linknum(); + } } } @@ -511,7 +604,7 @@ sub page_start { "\t".''."\n"; } } - return ($page_start,$form_tag_start); + return ($page_start,$form_tag_start,$partlist); } #use Time::HiRes(); @@ -542,7 +635,7 @@ sub get_resource_name { } sub setup_rndseed { - my ($safeeval,$target)=@_; + my ($safeeval,$target,$probpartlist)=@_; my ($symb)=&Apache::lonnet::whichuser(); my ($questiontype,$set_safespace,$rndseed); if ($target eq 'analyze') { @@ -603,7 +696,13 @@ sub setup_rndseed { } unless (($target eq 'analyze') && (defined($rndseed))) { $rndseed=&Apache::lonnet::rndseed(); - my $curr_try = $Apache::lonhomework::history{"resource.$Apache::inputtags::part.tries"}; + my $partfortries = $Apache::inputtags::part; + if (ref($probpartlist) eq 'ARRAY') { + if ((@{$probpartlist} == 1) && ($probpartlist->[0] ne $Apache::inputtags::part)) { + $partfortries = $probpartlist->[0]; + } + } + my $curr_try = $Apache::lonhomework::history{"resource.$partfortries.tries"}; if ($Apache::inputtags::status[-1] eq 'CAN_ANSWER') { $curr_try ++; } @@ -611,7 +710,7 @@ sub setup_rndseed { $rndseed = $1; } if ($curr_try) { - my $reqtries = &Apache::lonnet::EXT("resource.$Apache::inputtags::part.randomizeontries"); + my $reqtries = &Apache::lonnet::EXT("resource.$partfortries.randomizeontries"); if (($reqtries =~ /^\d+$/) && ($reqtries > 1)) { my $inc = int(($curr_try-1)/$reqtries); $rndseed += $inc; @@ -621,6 +720,9 @@ sub setup_rndseed { } } $set_safespace = 1; + if ($target eq 'grade') { + $Apache::lonhomework::rawrndseed = $rndseed; + } } if ($set_safespace) { if ($safeeval) { @@ -675,28 +777,260 @@ sub problem_edit_buttons { return $result; } +sub insert_menu_datastructure { + + my $template_menu = &template_dropdown_datastructure(); + my $responseblock_menu = &responseblock_dropdown_datastructure(); + my $conditional_scripting = &conditional_scripting_datastructure(); + my $misc = &misc_datastructure(); + + my @menu = ($template_menu, $responseblock_menu, $conditional_scripting, $misc); + return \@menu; + +} + +sub template_dropdown_datastructure { + # gathering the all templates and their path, title, category and help topic + my @templates = &Apache::lonhomework::get_template_list('problem'); + # template category => title + my %tmplthash = (); + # template title => path + my %tmpltcontent = (); + + foreach my $template (@templates){ + # put in hash if the template is not empty + unless ($template->[1] eq ''){ + push(@{$tmplthash{$template->[2]}}, $template->[1]); + push(@{$tmpltcontent{$template->[1]}},$template->[0]); + } + } + + my $catList = []; + foreach my $cat (sort keys %tmplthash) { + my $catItems = []; + foreach my $title (sort @{$tmplthash{$cat}}) { + my $path = $tmpltcontent{$title}->[0]; + my $code; + open(FH, "<:encoding(UTF-8)", $path); + while(){ + $code.= $_ unless $_ =~ /()|(<\/problem>)/; + } + close(FH); + + if ($code ne '') { + my $href = 'javascript:insertText(\'' . &convert_for_js(&HTML::Entities::encode($code)) . '\')'; + my $currItem = [$href, $title, undef]; + push @{$catItems}, $currItem; + } + } + push @{$catList}, [$catItems, $cat, undef]; + } + + my $templDropdown = [$catList, &mt("Complete Problem Templates"), undef]; + return $templDropdown; +} + +sub responseblock_dropdown_datastructure { + + my $mathCat = [ + [ + ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_formularesponse())) . "\')", &mt("Formula Response"), undef], + ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_functionplotresponse())) . "\')", &mt("Function Plot Response"), undef], + ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_mathresponse())) . "\')", &mt("Math Response"), undef], + ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_numericalresponse())) . "\')", &mt("Numerical Response"), undef] + ], + &mt("Math"), + undef + ]; + + my $miscCat = [ + [ + ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_imageresponse())) . "\')", &mt("Click on Image"), undef], + ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_customresponse())) . "\')", &mt("Custom Response"), undef], + ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_externalresponse())) . "\')", &mt("External Response"), undef], + ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_matchresponse())) . "\')", &mt("Match Response"), undef], + ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_radiobuttonresponse())) . "\')", &mt("One out of N Statement"), undef], + ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_optionresponse())) . "\')", &mt("Optionresponse"), undef], + ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_rankresponse())) . "\')", &mt("Rank Values"), undef] + ], + &mt("Misc"), + undef + ]; + + my $chemCat = [ + [ + ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_reactionresponse())) . "\')", &mt("Chemical Reaction"), undef], + ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_organicresponse())) . "\')", &mt("Organic Structure"), undef] + ], + &mt("Chemical"), + undef + ]; + + my $textCat = [ + [ + ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_stringresponse())) . "\')", &mt("String Response"), undef], + ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_essayresponse())) . "\')", &mt("Essay"), undef] + ], + &mt("Text"), + undef + ]; + + my $cats = [[$mathCat, $miscCat, $chemCat, $textCat], &mt("Response Types"), undef]; + return $cats; +} + + +sub conditional_scripting_datastructure { +# TODO: corresponding routines should be used for the javascript:insertText parts +# instead of the placeholder routine default_xml_tag with the tags +# e.g. &default_xml_tag("postanswerdate") should be replaced with a routine which +# returns the corresponding content for this case + +#TODO translated is currently temporarily here, another solution should be found where the +# needed string can be retrieved + + my $translatedTag = ' + + + +'; + + my $cat = [ + [ + ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode($translatedTag)) . "\')", &mt("Translated Tag"), undef], + ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&default_xml_tag("block"))) . "\')", &mt("Conditional Block"), undef], + ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&default_xml_tag("postanswerdate"))) . "\')", &mt("After Answer Block"), undef], + ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&default_xml_tag("preduedate"))) . "\')", &mt("Before Due Date Block"), undef], + ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&default_xml_tag("solved"))) . "\')", &mt("Block For After Solved"), undef], + ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&default_xml_tag("notsolved"))) . "\')", &mt("Block For When Not Solved"), undef] + ], + &mt("Contitional Scripting"), + undef + ]; + + return $cat; +} + +sub misc_datastructure { + + my $graphicalCat = [ + [ + ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_img())) . "\')", &mt("Image"), undef], + ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::lonplot::insert_gnuplot())) . "\')", &mt("GNU Plot"), undef], + ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_organicstructure())) . "\')", &mt("Organic Structure"), undef] + ], + "Graphical", + undef + ]; + + my $advancedCat = [ + [ + ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_script())) . "\')", &mt("Script Block"), undef], + ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&default_xml_tag("allow"))) . "\')", &mt("File Dependencies"), undef], + ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&default_xml_tag("import"))) . "\')", &mt("Import a File"), undef], + ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::londefdef::insert_meta())) . "\')", &mt("Custom Metadata"), undef] + ], + "advanced", + undef + ]; + + my $cats = [[$graphicalCat, $advancedCat], &mt("misc"), undef]; + return $cats; +} + +# helper routine for the datastructure building subroutines +sub default_xml_tag { + my ($tag) = @_; + return "\n<$tag>"; +} + + +sub helpmenu_datastructure { + + my $width = 500; + my $height = 600; + + my $helpers = [ + ['Problem_LON-CAPA_Functions', &mt('Script Functions')], + ['Greek_Symbols', &mt('Greek Symbols')], + ['Other_Symbols', &mt('Other Symbols')], + ['Authoring_Output_Tags', &mt('Output Tags')], + ['Authoring_Multilingual_Problems', + &mt('How to create problems in different languages')] + ]; + + my $help_structure = []; + + foreach my $count (0..(scalar(@{$helpers})-1)) { + my $filename = $helpers->[$count]->[0]; + my $title = $helpers->[$count]->[1]; + my $href = &HTML::Entities::encode("javascript:openMyModal('/adm/help/$filename.hlp',$width,$height,'yes');"); + push @{$help_structure}, [$href, $title, undef]; + } + + return $help_structure; +} + +# we need substitution to not break javascript code +sub convert_for_js { + my $return = shift; + $return =~ s|script|ESCAPEDSCRIPT|g; + $return =~ s|\\|\\\\|g; + $return =~ s|\n|\\r\\n|g; + $return =~ s|'|\\'|g; + $return =~ s|'|\\'|g; + return $return; +} + sub problem_edit_header { - return ''. + my ($mode)=@_; + my $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().' -
-'. - '" + $result.=&Apache::edit::start_table($token)."" .''
'; +
+
+ '.&mt('Problem Editing').$mode.&Apache::loncommon::help_open_menu('Problem Editing','Problem_Editor_XML_Index',5,'Authoring').' +
'. + ''. + &problem_edit_buttons(); + + $return.='
+
' + .&Apache::lonxml::message_location(); + $return .= ' + '; + + $return .= ' + +
'; + return $return; } sub problem_edit_footer { + my $resource = $env{'request.ambiguous'}; return '

'. "\n\n".&Apache::loncommon::end_page(); @@ -881,7 +1215,7 @@ sub initialize_storage { } %Apache::lonhomework::history= &Apache::lonnet::tmprestore($namespace,'',$domain,$name); - my ($temp)=keys %Apache::lonhomework::history ; + my ($temp)=keys(%Apache::lonhomework::history) ; &Apache::lonxml::debug("Return message of $temp"); } else { %Apache::lonhomework::history= @@ -889,7 +1223,7 @@ sub initialize_storage { } #ignore error conditions - my ($temp)=keys %Apache::lonhomework::history ; + my ($temp)=keys(%Apache::lonhomework::history); if ($temp =~ m/^error:.*/) { %Apache::lonhomework::history=(); } } @@ -1163,7 +1497,7 @@ sub store_aggregates { } } } - if (keys (%aggregate) > 0) { + if (keys(%aggregate) > 0) { &Apache::lonnet::cinc('nohist_resourcetracker',\%aggregate, $cdomain,$cname); } @@ -1277,6 +1611,8 @@ sub reset_problem_globals { undef($Apache::inputtags::part); if ($type eq 'Task') { undef($Apache::inputtags::slot_name); + } elsif ($type eq 'problem') { + undef($Apache::lonhomework::rawrndseed); } #don't undef this, lonhomework.pm takes care of this, we use this to #detect if we try to do 2 problems in one file @@ -1378,7 +1714,7 @@ sub start_problem { my $resource_due; my $name= &get_resource_name($parstack,$safeeval); - my ($result,$form_tag_start,$slot_name,$slot); + my ($result,$form_tag_start,$slot_name,$slot,$probpartlist); if ($target eq 'web' || $target eq 'grade' || $target eq 'answer' || $target eq 'tex') { @@ -1394,9 +1730,18 @@ sub start_problem { if ($target eq 'web' || $target eq 'webgrade' || $target eq 'tex' || $target eq 'edit') { - ($result,$form_tag_start) = + ($result,$form_tag_start,$probpartlist) = &page_start($target,$token,$tagstack,$parstack,$parser,$safeeval, $name); + } elsif (($target eq 'grade') && ($Apache::lonhomework::type eq 'randomizetry')) { + my ($symb)= &Apache::lonnet::whichuser(); + my $navmap = Apache::lonnavmaps::navmap->new(); + if (ref($navmap)) { + my $res = $navmap->getBySymb($symb); + if (ref($res)) { + $probpartlist = $res->parts(); + } + } } if ($target eq 'tex' and $env{'request.symb'} =~ m/\.page_/) {$result='';} @@ -1406,7 +1751,20 @@ sub start_problem { $target eq 'tex') { #handle rand seed in construction space - my $rndseed=&setup_rndseed($safeeval,$target); + my $rndseed=&setup_rndseed($safeeval,$target,$probpartlist); + if (($target eq 'grade') && &Apache::response::submitted()) { + if ($Apache::lonhomework::type eq 'randomizetry') { + $Apache::lonhomework::results{'resource.0.rndseed'}=$rndseed; + } else { + my @parts; + if (ref($probpartlist) eq 'ARRAY') { + @parts = @{$probpartlist}; + } + unless (@parts) { + $Apache::lonhomework::results{'resource.0.rndseed'}=$Apache::lonhomework::rawrndseed; + } + } + } my ($symb)=&Apache::lonnet::whichuser(); if ($env{'request.state'} ne "construct" && @@ -1614,7 +1972,7 @@ sub end_problem { my $id = $Apache::inputtags::part; my $weight = &Apache::lonnet::EXT("resource.$id.weight"); my $packages=&Apache::lonnet::metadata($env{'request.uri'},'packages'); - my @packages = split /,/,$packages; + my @packages = split(/,/,$packages); my $allow_print_points = 0; foreach my $partial_key (@packages) { if ($partial_key=~m/^part_0$/) { @@ -2348,8 +2706,8 @@ sub start_randomlist { } } } - for(0 .. $show) { - $bodytext .= "$randomlist[ $idx_arr[$_] ]"; + for my $i (0 .. $show) { + $bodytext .= "$randomlist[ $idx_arr[$i] ]"; } &Apache::lonxml::newparser($parser,\$bodytext); } @@ -2463,6 +2821,14 @@ sub start_part { my $hidden=&Apache::loncommon::check_if_partid_hidden($Apache::inputtags::part); my $newtype=&Apache::lonnet::EXT("resource.$id.type"); if ($newtype) { $Apache::lonhomework::type=$newtype; } + if ($Apache::lonhomework::type eq 'randomizetry') { + my $rndseed=&setup_rndseed($safeeval,$target); + if (($target eq 'grade') && &Apache::response::submitted()) { + $Apache::lonhomework::results{"resource.$id.rndseed"}=$rndseed; + } + } elsif (($target eq 'grade') && &Apache::response::submitted()) { + $Apache::lonhomework::results{"resource.$id.rndseed"}=$Apache::lonhomework::rawrndseed; + } my $in_order_show=&ordered_show_check(); my $expression='$external::part=\''.$Apache::inputtags::part.'\';'; $expression.='$external::type=\''.$Apache::lonhomework::type.'\';'; @@ -2513,7 +2879,7 @@ sub start_part { } my $weight = &Apache::lonnet::EXT("resource.$id.weight"); my $allkeys=&Apache::lonnet::metadata($env{'request.uri'},'packages'); - my @allkeys = split /,/,$allkeys; + my @allkeys = split(/,/,$allkeys); my $allow_print_points = 0; foreach my $partial_key (@allkeys) { if ($partial_key=~m/^part_(.*)$/) { @@ -2761,7 +3127,8 @@ sub end_startouttext { if ($target eq 'edit') { my $areaid = 'homework_edit_'.$Apache::lonxml::curdepth; $text=&Apache::lonxml::get_all_text("endouttext",$parser,$style); - $result.=&Apache::edit::start_table($token)."
".&mt('Text Block')."
".&Apache::loncommon::insert_folding_button() + ." ".&mt('Text Block')."'.&mt('Delete?').' ' .&Apache::edit::deletelist($target,$token) .'