--- loncom/homework/edit.pm	2010/11/07 01:57:50	1.132
+++ loncom/homework/edit.pm	2023/03/27 18:41:06	1.157
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA 
 # edit mode helpers
 #
-# $Id: edit.pm,v 1.132 2010/11/07 01:57:50 www Exp $
+# $Id: edit.pm,v 1.157 2023/03/27 18:41:06 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -134,10 +134,11 @@ package Apache::edit;
 
 use strict;
 use Apache::lonnet;
+use Apache::loncommon;
 use HTML::Entities();
 use Apache::lonlocal;
 use lib '/home/httpd/lib/perl/';
-use LONCAPA;
+use LONCAPA qw(:DEFAULT :match);
  
 
 # Global Vars
@@ -161,21 +162,18 @@ sub tag_start {
     if ($target eq "edit") {
 	my $tag=$token->[1];
 	if (!$description) {
-	    $description=&Apache::lonxml::description($token);
+	    $description=&mt(&Apache::lonxml::description($token));
 	    if (!$description) { $description="<$tag>"; }
 	}
-	$result.= &start_table($token)."<tr><td>$description</td>
-                      <td>".&mt('Delete?').' '.
-		      &deletelist($target,$token)
-		      ."</td>
-                       <td>".
-		       &insertlist($target,$token);
+    $result.= &start_table($token)."<tr><td>".&Apache::loncommon::insert_folding_button().
+        " $description</td><td>".&mt('Delete?')." ".&deletelist($target,$token).
+        "</td><td>".&insertlist($target,$token);
 #<td>". 
 #  &movebuttons($target,$token).
 #    "</tr><tr><td colspan=\"3\">\n";
 	my @help = Apache::lonxml::helpinfo($token);
 	if ($help[0]) {
-	    $result .= '</td><td align="right" valign="top">' .
+	    $result .= '</td><td class="LC_edit_problem_latexhelper">'.
 		Apache::loncommon::help_open_topic(@help);
 	} else { $result .= "</td><td>&nbsp;"; }
 	$result .= &end_row().&start_spanning_row();
@@ -203,7 +201,7 @@ sub start_table {
     }
     $Apache::edit::colordepth++;
     push(@Apache::edit::inserttag,$token->[1]);
-    my $result='<div align="right">';
+    my $result='<div>';
     $result.='<table bgcolor="'.$color.'" width="97%" border="0" cellspacing="3" cellpadding="2">';
     return $result;
 }
@@ -211,7 +209,7 @@ sub start_table {
 sub end_table {
     $Apache::edit::colordepth--;
     my $result='</table></div>';
-    $result.='<div align="left"><table><tr><td>';
+    $result.='<div><table><tr><td>';
 
     my ($tagname,$closingtag);
     if (defined($Apache::edit::inserttag[-2])) {
@@ -232,7 +230,10 @@ sub end_table {
     return $result;
 }
 
-sub start_spanning_row { return '<tr><td colspan="5" bgcolor="#F0F0F0">';}
+sub start_spanning_row {
+    return '<tr name="foldblock_'.$Apache::lonxml::curdepth.
+    '" style="visibility: \'\'"><td colspan="5" bgcolor="#F0F0F0">';
+}
 sub start_row          { return '<tr><td bgcolor="#DDDDDD">';            }
 sub end_row            { return '</td></tr>';          }
 
@@ -296,7 +297,7 @@ sub get_insert_list {
 	    my $descrip=$Apache::lonxml::insertlist{"$tag.description"};
 	    my $tagnum =$Apache::lonxml::insertlist{"$tag.num"};
 	    $options{$descrip} ="<option value=\"$tagnum\">".
-		$descrip."</option>\n";
+		&mt($descrip)."</option>\n";
 	}
 	foreach my $option (sort(keys(%options))) {$result.=$options{$option};}
 	if ($result) { $result='<option selected="selected"></option>'.$result; }
@@ -400,8 +401,10 @@ sub insert_formularesponse {
 sub insert_functionplotresponse {
     return '
 <functionplotresponse>
-<spline />
-<functionplotrule />
+<functionplotelements>
+</functionplotelements>
+<functionplotruleset>
+</functionplotruleset>
 </functionplotresponse>';
 }
 
@@ -415,12 +418,64 @@ sub insert_backgroundplot {
 <backgroundplot />';
 }
 
+sub insert_plotobject {
+    return '
+<plotobject />';
+}
+
+sub insert_plotvector {
+    return '
+<plotvector />';
+}
+
+sub insert_drawvectorsum {
+    return '
+<drawvectorsum />';
+}
+
+
 sub insert_functionplotrule {
     return '
 <functionplotrule />';
 }
 
+sub insert_functionplotvectorrule {
+    return '
+<functionplotvectorrule />';
+}
+
+sub insert_functionplotvectorsumrule {
+    return '
+<functionplotvectorsumrule />';
+}
+
+sub insert_functionplotcustomrule {
+    return '
+<functionplotcustomrule>
+<answer type="loncapa/perl">
+# &fpr_val("label"), &fpr_f($x), &fpr_dfdx($x), &fpr_d2fdx2($x)
+# ($xs,$xe,$ys,$ye)=&fpr_vectorcoords("Name"), ($x,$y)=&fpr_objectcoords("Name")
+# &fpr_vectorlength("Name"), &fpr_vectorangle("Name")
+ 
+# Return 0 or 1
+return 1;
+</answer>
+</functionplotcustomrule>';
+}
+
+sub insert_functionplotruleset {
+    return '
+<functionplotruleset>
+<functionplotrule />
+</functionplotruleset>';
+}
 
+sub insert_functionplotelements {
+    return '
+<functionplotelements>
+<spline />
+</functionplotelements>';
+}
 
 sub insert_numericalresponse {
     return '
@@ -434,6 +489,13 @@ sub insert_numericalresponse {
 </numericalresponse>';
 }
 
+sub insert_externalresponse {
+    return '
+<externalresponse url="" answer="" answerdisplay="" form="">
+    <textfield spellcheck="none" />
+</externalresponse>';
+}
+
 sub insert_customresponse {
     return '
 <customresponse>
@@ -606,6 +668,9 @@ sub insert_matchresponse {
 <matchresponse max="10">
     <foilgroup options="">
       <itemgroup>
+        <item>
+          <startouttext /><endouttext />
+        </item>
       </itemgroup>
       <foil>
          <startouttext /><endouttext />
@@ -690,6 +755,7 @@ sub js_change_detection {
     my $unsaved=&mt("There are unsaved changes");
     return (<<SCRIPT);
 <script type="text/javascript">
+// <![CDATA[
 var clean = true;
 var is_submit = false;
 var still_ask = false;
@@ -708,6 +774,7 @@ function unClean() {
      clean=false;
 }
 window.onbeforeunload = compareForm;
+// ]]>
 </script>
 SCRIPT
 }
@@ -722,7 +789,58 @@ sub element_change_detection {
 
 sub submit_ask_anyway {
     my ($extra_action) = @_;
-    return ' onclick="still_ask=true;'.$extra_action.'" ';
+    my $resource = &Apache::loncommon::escape_single($env{'request.ambiguous'});
+    return ' onclick="saveScrollPosition(\''.$resource.'\');still_ask=true;'.$extra_action.';" ';
+}
+
+sub submit_dont_ask {
+    my ($extra_action) = @_;
+    my $resource = &Apache::loncommon::escape_single($env{'request.ambiguous'});
+    return ' onclick="saveScrollPosition(\''.$resource.'\');is_submit=true;'.$extra_action.';" ';
+}
+
+sub js_update_linknum {
+    return (<<SCRIPT);
+<script type="text/javascript">
+// <![CDATA[
+function updateNumber(name,index,caller,textprompt) {
+    var pickitem = document.getElementById(name+'_'+index);
+    var picknumtext = document.getElementById(name+'_numtext_'+index);
+    if (pickitem.checked) {
+        var showval = '';
+        if (pickitem.value != 'nochoice') {
+            showval = pickitem.value;
+        } 
+        var picknum=prompt(textprompt,showval);
+        if (picknum == '' || picknum == null) {
+            if (caller == 'check') {
+                pickitem.checked=false;
+                pickitem.value='nochoice';
+            }
+        } else {
+            picknum.toString();
+            var regexdigit=/^\\d+\$/;
+            if (regexdigit.test(picknum)) {
+                pickitem.value = picknum;
+                picknumtext.innerHTML = '&nbsp;<a href="javascript:updateNumber(\\''+name+'\\',\\''+index+'\\',\\'link\\',\\''+textprompt+'\\');">'+picknum+'</a>';
+            } else {
+                if (caller == 'check') {
+                    pickitem.checked=false;
+                    pickitem.value='nochoice';
+                }
+                return;
+            }
+        }
+    } else {
+        pickitem.value = '';
+        picknumtext.innerHTML = '';
+    }
+}
+
+// ]]>
+</script>
+SCRIPT
+
 }
 
 sub textarea_sizes {
@@ -766,20 +884,20 @@ sub editfield {
     if ($cols > 80) { $cols = 80; }
     if ($cols < $minwidth ) { $cols = $minwidth; }
     if ($rows < $minheight) { $rows = $minheight; }
-    if ($description) { $description=$description."<br />"; }
+    if ($description) { $description='<br />'.&mt($description).'<br />'; }
 
     # remove typesetting whitespace from between data and the end tag
     # to make the edit look prettier
     $data =~ s/\n?[ \t]*$//;
 
-    return $description."\n".'<textarea style="width:100%" rows="'.$rows.
+    return $description."\n".'<textarea style="width:99%" rows="'.$rows.
 	'" cols="'.$cols.'" name="homework_edit_'.
 	$Apache::lonxml::curdepth.'" id="homework_edit_'.
 	$Apache::lonxml::curdepth.'" '.&element_change_detection().
         $textareaclass.'>'.
 	&HTML::Entities::encode($data,'<>&"').'</textarea>'.
-	($usehtmlarea?&Apache::lonhtmlcommon::spelllink('lonhomework',
-			 'homework_edit_'.$Apache::lonxml::curdepth):'')."\n";
+        ($usehtmlarea?'<br />'.&Apache::lonhtmlcommon::spelllink('lonhomework',
+                                   'homework_edit_'.$Apache::lonxml::curdepth):'')."\n";
 }
 
 sub modifiedfield {
@@ -869,7 +987,7 @@ sub hidden_arg {
 }
 
 sub checked_arg {
-    my ($description,$name,$list,$token) = @_;
+    my ($description,$name,$list,$token,$onclick,$useid) = @_;
     my $result;
     my $optionlist="";
     my $allselected=$token->[2]{$name};
@@ -878,13 +996,13 @@ sub checked_arg {
 	my ($value,$text);
 	if ( ref($option) eq 'ARRAY') {
 	    $value='value="'.$$option[0].'"';
-	    $text=$$option[1];
+	    $text=&mt($$option[1]);
 	    $option=$$option[0];
 	} else {
-	    $text=$option;
+	    $text=&mt($option);
 	    $value='value="'.$option.'"';
 	}
-	$result.='<span class="LC_nobreak"><label><input type="checkbox" '.$value.' name="'.
+        $result.=' <span class="LC_edit_opt"><label><input type="checkbox" '.$value.' name="'.
 	    &html_element_name($name).'"';
 	foreach my $selected (split(/,/,$allselected)) {
 	    if ( $selected eq $option ) {
@@ -892,20 +1010,26 @@ sub checked_arg {
 		last;
 	    }
 	}
-	$result.=&element_change_detection().' />'.$text.'</label></span>'."\n";
+        if ($useid) {
+            $result .= ' id="'.&html_element_name($name).'" ';
+        }
+	$result.=&element_change_detection().$onclick.' />'.$text.'</label></span>'."\n";
     }
     return $result;
 }
 
 sub text_arg {
-    my ($description,$name,$token,$size) = @_;
+    my ($description,$name,$token,$size, $class) = @_;
     my $result;
     if (!defined $size) { $size=20; }
     my $arg=$token->[2]{$name};
     $result=&mt($description).'&nbsp;<input name="'.&html_element_name($name).
-	'" type="text" value="'.$arg.'" size="'.$size.'" '.
-	&element_change_detection().'/>';
-    return '<span class="LC_nobreak">'.$result.'</span>';
+	'" type="text" value="'.$arg.'" size="'.$size.'" ';
+    if (defined $class) {
+	$result .= 'class="' . $class . '" ';
+    }
+    $result .=	&element_change_detection().'/>';
+    return ' <span class="LC_edit_opt">'.$result.'</span>';
 }
 
 sub select_arg {
@@ -931,7 +1055,7 @@ sub select_arg {
 	    }
         }
     }
-    $result.='<span class="LC_nobreak">'.&mt($description).'&nbsp;<select name="'.
+    $result.=' <span class="LC_edit_opt">'.&mt($description).'&nbsp;<select name="'.
 	&html_element_name($name).'" '.&element_change_detection().' >
        '.$optionlist.'
       </select></span>';
@@ -982,16 +1106,16 @@ sub select_or_text_arg {
     $description=&mt($description);
 #
     return (<<ENDSELECTORTYPE);
-<span class="LC_nobreak">
+ <span class="LC_edit_opt">
 $description
 &nbsp;<select name="$selectelement"
-onChange="if ($selectedvalue!='TYPEDINVALUE') { $hiddenvalue=$selectedvalue; $typedinvalue=''; }" >
+onchange="if ($selectedvalue!='TYPEDINVALUE') { $hiddenvalue=$selectedvalue; $typedinvalue=''; }" >
 $optionlist
 </select>
 <input type="text" size="$size" name="$typeinelement"
        value="$typeinvalue" 
-onChange="$hiddenvalue=$typedinvalue;"
-onFocus="$selectedindex=$selecttypeinindex-1;" />
+onchange="$hiddenvalue=$typedinvalue;"
+onfocus="$selectedindex=$selecttypeinindex-1;" />
 <input type="hidden" name="$element" value="$selected" $change_code />
 </span>
 ENDSELECTORTYPE
@@ -1072,52 +1196,166 @@ sub deletecoorddata {
     &Apache::lonnet::delenv('imagechoice.');
 }
 
+#----------------------------------------------------- browse and search links
+sub browse_or_search {
+    my ($id,$mode,$titleid,$only,$crsonly,$usesearch) = @_;
+    my $output;
+    my ($cnum,$cdom) = &Apache::loncommon::crsauthor_url();
+    if ($cnum) {
+        my $form = 'lonhomework';
+        my ($element,$bretitleelement,$srchtitleelement);
+        $element = &get_element($id,$mode); 
+        my %lt = &Apache::lonlocal::texthash (
+            uacf => 'Use a course file',
+            uanf => 'Use a new file',
+            impo => 'Import',
+            sear => 'Search',
+            sefi => 'Select File',
+            upfi => 'Upload File',
+            dire => 'Directory',
+            news => 'New sub-directory',
+            empd => 'No suitable resources found',
+        );
+        my ($importcrsres,$uploadfile,$allonly);
+        if ($only) {
+            $allonly = $only;
+            if ($crsonly) {
+                $allonly .= ','.$crsonly;
+            }
+        } elsif ($crsonly) {
+            $allonly = $crsonly;
+        }
+        my ($numdirs,$pickfile) =
+            &Apache::loncommon::import_crsauthor_form('coursepath_'.$element,'coursefile_'.$element,undef,$allonly,$element);
+        $importcrsres=(<<CRSRES);
+        <fieldset id="importcrsresform_$element" style="display:inline;">
+        <legend>$lt{'uacf'}</legend>
+        <div id="hascrsres_$element" style="padding:0;clear:both;margin:0;border:0;display:none;">
+        <p>
+        $pickfile
+        </p><p>
+        <input type="button" name="crsres_$element" value="$lt{'sefi'}" onclick="updateCrsFile(this.form,'$element');" />
+        </p>
+        </div>
+        <div id="nocrsres_$element" style="padding:0;clear:both;margin:0;border:0display:none;">
+        <p>
+        $lt{'empd'}
+        </p>
+        </div>
+        </fieldset>
+CRSRES
+        my %subdirs;
+        my $toppath="/priv/$cdom/$cnum";
+        my $exclude = &Apache::lonnet::priv_exclude();
+        &Apache::lonnet::recursedirs(1,1,'',$exclude,'',0,$toppath,'',\%subdirs);
+        my $numcrsdirs = keys(%subdirs);
+        my $pickdir = $lt{'dire'}.'<select name="crsauthorpath_'.$element.'">'."\n".
+                                   '<option value="/">/</option>'."\n";
+        if ($numcrsdirs) {
+            foreach my $key (sort { lc($a) cmp lc($b) } (keys(%subdirs))) {
+                $pickdir .= '<option value="'.$key.'">'.$key.'</option>'."\n";
+            }
+        }
+        $pickdir .= '</select><br />';
+        my $uploadfile =(<<CRSUPL);
+        <fieldset id="uploadcrsresform_$element" style="display:inline;">
+        <legend>$lt{'uanf'}</legend>
+        <p>
+        $pickdir
+        <span class="LC_nobreak">$lt{'news'}?&nbsp;
+        <label><input type="radio" name="newsubdir_$element" value="0" onclick="toggleNewsubdir(this.form,'$element');" checked="checked" />No</label>
+        &nbsp;
+        <label><input type="radio" name="newsubdir_$element" value="1" onclick="toggleNewsubdir(this.form,'$element');" />Yes</label>
+        </span><span id="newsubdir_$element"></span>
+        <input type="hidden" name="newsubdirname_$element" id="newsubdirname_$element" value="" autocomplete="off" />
+        </p>
+        <input type="file" id="uploadcrsres_$element" name="uploadcrsres_$element" size="40" />
+        <input type="hidden" id="crsuploadto_$element" name="filename_$element" value="$ENV{'REQUEST_URI'}" />
+        <input type="submit" id="crsupload_$element" class="LC_uploadcrsres" value="$lt{'upfi'}" />
+        <iframe id="crsupload_target_$element" name="crsupload_target_$element" src="" style="width:0px;height:0px;border:0px"></iframe>
+        </fieldset>
+CRSUPL
+        if ($titleid) {
+            $bretitleelement=",'$only','','".&escape("$titleid\_$Apache::lonxml::curdepth")."'";
+            $srchtitleelement=",'".&escape("$titleid\_$Apache::lonxml::curdepth")."'";
+        } else {
+            $bretitleelement=",'$only'";
+        }
+        $output = '<a href="javascript:toggleChooser(document.'.$form.",'$element'".');">'.
+                  &mt('Choose File').'</a>'.
+                  '<div id="chooser_'.$element.'" style="display:none" class="LC_left_float">'.
+                  '<fieldset><legend>'.&mt('Choose File').'</legend>'.
+                  '<label><input type="radio" name="chooser_'.$element.'" value="crsres" onclick="toggleCrsFile(this.form,'."'$element'".')" />'.$lt{'uacf'}.'</label>&nbsp;'.
+                  '<label><input type="radio" name="chooser_'.$element.'" value="upload" onclick="toggleCrsUpload(this.form,'."'$element'".')" />'.$lt{'uanf'}.'</label>&nbsp;'.
+                  '<label><input type="radio" name="chooser_'.$element.'" value="import" onclick="toggleResImport(this.form,'."'$element'".');openbrowser('."'$form','$element'$bretitleelement)".'" />'.$lt{'impo'}.'</label>';
+        if ($usesearch) {
+            $output .= '&nbsp;<label><input type="radio" name="chooser_'.$element.'" value="search" onclick="opensearcher('."'$form','$element'$srchtitleelement".')" />'.$lt{'sear'}.'</label>';
+        }
+        $output .= '<div id="chooser_'.$element.'_crsres" style="display:none">'.
+                   $importcrsres.
+                   '</div>'.
+                   '<div id="chooser_'.$element.'_upload" style="display:none">'.
+                   $uploadfile. 
+                   '</div>'.
+                   '</fieldset></div>';
+                    
+    } else {
+        $output = &browse($id, $mode, $titleid, $only);
+        if ($usesearch) {
+            $output .= ' '.&search($id, $mode, $titleid);
+        }
+    }
+    return $output;
+}
+
 #----------------------------------------------------- browse
 sub browse {
     # insert a link to call up the filesystem browser (lonindexer)
     my ($id, $mode, $titleid, $only) = @_;
+    my %lt = &Apache::lonlocal::texthash (
+                                           se => 'Select',
+                                         );
     my $form    = 'lonhomework';
-    my $element;
-    if (! defined($mode) || $mode eq 'attribute') {
-        $element = &escape("$id\_$Apache::lonxml::curdepth");
-    } elsif ($mode eq 'textnode') {  # for data between <tag> ... </tag>
-        $element = &escape('homework_edit_'.
-                                           $Apache::lonxml::curdepth);	
-    }
+    my $element = &get_element($id,$mode);
     my $titleelement;
     if ($titleid) {
 	$titleelement=",'$only','','".&escape("$titleid\_$Apache::lonxml::curdepth")."'";
     } else {
         $titleelement=",'$only'";
     }
-    my $result = <<"ENDBUTTON";
-<a href=\"javascript:openbrowser('$form','$element'$titleelement)\"\>Select</a>
+    return <<"ENDBUTTON";
+<a href=\"javascript:openbrowser('$form','$element'$titleelement)\"\>$lt{'se'}</a>
 ENDBUTTON
-    return $result;
 }
 
-#----------------------------------------------------- browse
+#----------------------------------------------------- search
 sub search {
     # insert a link to call up the filesystem browser (lonindexer)
     my ($id, $mode, $titleid) = @_;
     my $form    = 'lonhomework';
-    my $element;
-    if (! defined($mode) || $mode eq 'attribute') {
-        $element = &escape("$id\_$Apache::lonxml::curdepth");
-    } elsif ($mode eq 'textnode') {  # for data between <tag> ... </tag>
-        $element = &escape('homework_edit_'.
-                                           $Apache::lonxml::curdepth);
-    }
+    my $element = &get_element($id,$mode);
     my $titleelement;
     if ($titleid) {
 	$titleelement=",'".&escape("$titleid\_$Apache::lonxml::curdepth")."'";
     }
+    my $linktext = &mt('Search');
     my $result = <<"ENDBUTTON";
-<a href=\"javascript:opensearcher('$form','$element'$titleelement)\"\>Search</a>
+<a href=\"javascript:opensearcher('$form','$element'$titleelement)\"\>$linktext</a>
 ENDBUTTON
     return $result;
 }
 
+sub get_element {
+    my ($id,$mode) = @_;
+    my $element;
+    if (! defined($mode) || $mode eq 'attribute') {
+        $element = &escape("$id\_$Apache::lonxml::curdepth");
+    } elsif ($mode eq 'textnode') {  # for data between <tag> ... </tag>
+        $element = &escape('homework_edit_'.
+                                           $Apache::lonxml::curdepth);
+    }
+    return $element;
+}
 
 1;
 __END__