--- loncom/homework/edit.pm 2001/05/15 20:48:43 1.7 +++ loncom/homework/edit.pm 2003/01/19 08:13:54 1.43 @@ -1,84 +1,225 @@ # The LearningOnline Network with CAPA # edit mode helpers +# +# $Id: edit.pm,v 1.43 2003/01/19 08:13:54 albertel Exp $ +# +# Copyright Michigan State University Board of Trustees +# +# This file is part of the LearningOnline Network with CAPA (LON-CAPA). +# +# LON-CAPA is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# LON-CAPA is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with LON-CAPA; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# /home/httpd/html/adm/gpl.txt +# +# http://www.lon-capa.org/ +# # 3/20 Guy +# 01/10/02 Matthew +# 03/06/02 Matthew package Apache::edit; use strict; -use Apache::lonnet; +use Apache::lonnet(); +use HTML::Entities(); + +# Global Vars +# default list of colors to use in editing +@Apache::edit::colorlist=('#ffffff','#ff0000','#00ff00','#0000ff','#0ff000','#000ff0','#f0000f'); +# depth of nesting of edit +$Apache::edit::colordepth=0; +@Apache::edit::inserttag=(); + +sub initialize_edit { + $Apache::edit::colordepth=0; + @Apache::edit::inserttag=(); +} sub tag_start { - my ($target,$token) = @_; + my ($target,$token,$description) = @_; my $result=''; if ($target eq "edit") { my $tag=$token->[1]; -# my $color = sprintf("#%06lx",(hex("ffffff")) >> scalar(split(/_/,$Apache::lonxml::curdepth))); - my $color = sprintf("#%02lxffff",33* scalar(split(/_/,$Apache::lonxml::curdepth))); - $result.=" - + if (!$description) { + $description=&Apache::lonxml::description($token); + if (!$description) { $description="<$tag>"; } + } + $result.= &start_table($token)." + -
<$tag>Delete: -
$descriptionDelete". + &deletelist($target,$token) + ." ". - &insertlist($token,$target). - "
\n"; + &insertlist($target,$token).&end_row().&start_spanning_row(); +#". +# &movebuttons($target,$token). +# "
\n"; } return $result; } sub tag_end { - my ($target,$token) = @_; + my ($target,$token,$description) = @_; my $result=''; if ($target eq 'edit') { my $tag=$token->[1]; - $result.="
</$tag>
\n"; + if (!defined($description)) { + $result.="</$tag> "; + } else { + if ($description ne '') { $result.="$description "; } + } + $result.="".&end_table()."\n"; + } + return $result; +} + +sub start_table { + my ($token)=@_; + my $tag = $token->[1]; + my $tagnum; + foreach my $namespace (reverse @Apache::lonxml::namespace) { + my $testtag=$namespace.'::'.$tag; + $tagnum=$Apache::lonxml::insertlist{"$testtag.num"}; + if (defined($tagnum)) { last; } + } + if (!defined ($tagnum)) { $tagnum=$Apache::lonxml::insertlist{"$tag.num"}; } + my $color = $Apache::lonxml::insertlist{"$tagnum.color"}; + if (!defined($color)) { + $color = $Apache::edit::colorlist[$Apache::edit::colordepth]; } + $Apache::edit::colordepth++; + push(@Apache::edit::inserttag,$token->[1]); + my $result='
'; + $result.=''; return $result; } +sub end_table { + $Apache::edit::colordepth--; + my $result='
'; + $result.="
"; + + my ($tagname,$closingtag); + if (defined($Apache::edit::inserttag[-2])) { + $tagname=$Apache::edit::inserttag[-2]; + } else {$tagname='problem';} + if (defined($Apache::edit::inserttag[-1])) { + $closingtag=$Apache::edit::inserttag[-1]; + } + $result.=&innerinsertlist('edit',$tagname,$closingtag). + "
"; + pop(@Apache::edit::inserttag); + return $result; +} + +sub start_spanning_row { return '';} +sub start_row { return ''; } +sub end_row { return ''; } + +sub movebuttons { + my ($target,$token) = @_; + my $result=''; + $result.=''; + return $result; +} + +sub deletelist { + my ($target,$token) = @_; + my $result = ""; + return $result; +} + +sub handle_delete { + if (!$ENV{"form.delete_$Apache::lonxml::curdepth"}) { return ''; } + my ($space,$target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; + my $result=0; + if ($space) { + my $sub1="$space\:\:delete_$token->[1]"; + { + no strict 'refs'; + if (defined &$sub1) { + $result=&$sub1($target,$token,$tagstack,$parstack,$parser,$safeeval,$style); + } + } + } + if (!$result) { + my $endtag='/'.$token->[1]; + my $bodytext=&Apache::lonxml::get_all_text($endtag,$$parser[$#$parser]); + $$parser['-1']->get_token(); + &Apache::lonxml::debug("Deleting :$bodytext: for $token->[1]"); + &Apache::lonxml::end_tag($tagstack,$parstack,$token); + } + return 1; +} + sub get_insert_list { - my ($token) = @_; + my ($tagname) = @_; my $result=''; my @tagnums= (); #&Apache::lonxml::debug("keys ".join("\n",sort(keys(%Apache::lonxml::insertlist)))); - if ($Apache::lonxml::insertlist{"$token->[1].which"}) { - &Apache::lonxml::debug("Adding1 $token->[1].which"); - push (@tagnums, @{ $Apache::lonxml::insertlist{"$token->[1].which"} }); + if ($Apache::lonxml::insertlist{"$tagname.which"}) { + push (@tagnums, @{ $Apache::lonxml::insertlist{"$tagname.which"} }); } foreach my $namespace (@Apache::lonxml::namespace) { - if ($Apache::lonxml::insertlist{"$namespace".'::'."$token->[1].which"}) { - &Apache::lonxml::debug("Adding2 $namespace".'::'."$token->[1].which"); - push (@tagnums, @{ $Apache::lonxml::insertlist{"$namespace".'::'."$token->[1].which"} }); + if ($Apache::lonxml::insertlist{"$namespace".'::'."$tagname.which"}) { + push (@tagnums, @{ $Apache::lonxml::insertlist{"$namespace".'::'."$tagname.which"} }); } } if (@tagnums) { + my %options; foreach my $tagnum (@tagnums) { - $result.='\n"; + my $descrip=$Apache::lonxml::insertlist{"$tagnum.description"}; + $options{$descrip} ="\n"; } + foreach my $option (sort(keys(%options))) { $result.=$options{$option}; } if ($result) { $result=''.$result; } } return $result; } sub insertlist { - my ($token,$target) = @_; + my ($target,$token) = @_; + return &innerinsertlist($target,$token->[1]); +} + +sub innerinsertlist { + my ($target,$tagname,$closingtag) = @_; my $result; + my $after=''; + if ($closingtag) { + $after='_after_'.$closingtag; + } if ($target eq 'edit') { - my $optionlist= &get_insert_list($token); + my $optionlist= &get_insert_list($tagname); if ($optionlist) { $result = "Insert: - $optionlist " + } else { + $result=" "; } } return $result; } sub handle_insert { - if (!$ENV{"form.insert_$Apache::lonxml::curdepth"}) { return ''; } + if ($ENV{"form.insert_$Apache::lonxml::curdepth"} eq '') { return ''; } my $result; my $tagnum = $ENV{"form.insert_$Apache::lonxml::curdepth"}; my $func=$Apache::lonxml::insertlist{"$tagnum.function"}; @@ -88,38 +229,179 @@ sub handle_insert { if ($newtag =~ /::/) { ($namespace,$newtag) = split(/::/,$newtag); } $result.="\n<$newtag>\n"; } else { - { - no strict 'refs'; - $result.=&$func(); + if (defined(&$func)) { + { + no strict 'refs'; + $result.=&$func(); + } + } else { + my $newtag=$Apache::lonxml::insertlist{"$tagnum.tag"}; + &Apache::lonxml::error("Unable to insert tag $newtag, $func was not defined."); } } return $result; } +sub handle_insertafter { + my $tagname=shift; + if ($ENV{"form.insert_after_$tagname\_$Apache::lonxml::curdepth"} eq '') + { return ''; } + my $result; + my $tagnum =$ENV{"form.insert_after_$tagname\_$Apache::lonxml::curdepth"}; + my $func=$Apache::lonxml::insertlist{"$tagnum.function"}; + if ($func eq 'default') { + my $newtag=$Apache::lonxml::insertlist{"$tagnum.tag"}; + my $namespace; + if ($newtag =~ /::/) { ($namespace,$newtag) = split(/::/,$newtag); } + $result.="\n<$newtag>\n"; + } else { + if (defined(&$func)) { + { + no strict 'refs'; + $result.=&$func(); + } + } else { + my $newtag=$Apache::lonxml::insertlist{"$tagnum.tag"}; + &Apache::lonxml::error("Unable to insert (after) tag $newtag, $func was not defined. ($tagname $tagnum)"); + } + } + return $result; +} + +sub insert_responseparam { + return ' + '; +} + +sub insert_formularesponse { + return ' + + + + +'; +} + +sub insert_numericalresponse { + return ' + + + + +'; +} + +sub insert_stringresponse { + return ' + + + + +'; +} + +sub insert_essayresponse { + return ' + + +'; +} + sub insert_optionresponse { return ' + + '; } -sub editfield { - my ($tag,$data,$description,$minwidth,$minheight)=@_; - +sub insert_radiobuttonresponse { + return ' + + + + + +'; +} + +sub insert_rankresponse { + return ' + + + + + +'; +} + +sub insert_displayduedate { return ''; } +sub insert_displaytitle { return ''; } +sub insert_hintpart { + return ' + + + +'; +} + +sub insert_numericalhint { + return ' + +'; +} + +sub insert_radiobuttonhint { + return ' + +'; +} + +sub insert_startouttext { + return "\n"; +} + +sub insert_script { + return "\n"; +} + +sub textarea_sizes { + my ($data)=@_; my $count=0; my $maxlength=-1; - map { $count++; - if (length($_) > $maxlength) { $maxlength = length ($_); } - } split ("\n", $data); - if ($maxlength > 80) { $maxlength = 80; } - if ($maxlength < $minwidth) { $maxlength = $minwidth; } - if ( $count < $minheight) { $count = $minheight; } - if ($description) { - $description="
".$description; - } - return "$description
\n   \n"; -# return "
\n<$tag>
\n   
\n</$tag>
\n"; + foreach (split ("\n", $$data)) { $count++; + if (length($_) > $maxlength) { $maxlength = length($_); } + } + my $rows = $count; + my $cols = $maxlength; + return ($rows,$cols); +} + +sub editline { + my ($tag,$data,$description,$size)=@_; + $data=&HTML::Entities::encode($data); + if ($description) { $description="
".$description."
"; } + my $result = <<"END"; +$description + +END + return $result; +} + +sub editfield { + my ($tag,$data,$description,$minwidth,$minheight)=@_; + + my ($rows,$cols)=&textarea_sizes(\$data); + if ($cols > 80) { $cols = 80; } + if ($cols < $minwidth ) { $cols = $minwidth; } + if ($rows < $minheight) { $rows = $minheight; } + if ($description) { $description="
".$description."
"; } + return $description."\n".'   '."\n"; } sub modifiedfield { @@ -131,19 +413,265 @@ sub modifiedfield { # &Apache::lonxml::debug("I want homework_edit_$Apache::lonxml::curdepth"); # &Apache::lonxml::debug($ENV{"form.homework_edit_$Apache::lonxml::curdepth"}); $result=$ENV{"form.homework_edit_$Apache::lonxml::curdepth"}; - if (defined $token) { - if (defined $token->[4]) { - $result=$token->[4].$result; + return $result; +} + +# Returns a 1 if the token has been modified and you should rebuild the tag +# side-effects, will modify the $token if new values are found +sub get_new_args { + my ($token,$parstack,$safeeval,@args)=@_; + my $rebuild=0; + foreach my $arg (@args) { + #just want the string that it was set to + my $value=$token->[2]->{$arg}; + my $newvalue=$ENV{"form.$Apache::lonxml::curdepth.$arg"}; + &Apache::lonxml::debug(" for:$arg: cur is :$value: new is :$newvalue:"); + if ($value ne $newvalue) { + $token->[2]->{$arg}=$newvalue; + $rebuild=1; + } + } + return $rebuild; +} + +# looks for /> on start tags +sub rebuild_tag { + my ($token) = @_; + my $result; + if ($token->[0] eq 'S') { + $result = '<'.$token->[1]; + while (my ($key,$val)= each(%{$token->[2]})) { + $val=~s:^\s+|\s+$::g; + $val=~s:"::g; #" + &Apache::lonxml::debug("setting :$key: to :$val:"); + $result.=' '.$key.'="'.$val.'"'; + } + if ($token->[4] =~ m:/>$:) { + $result.=' />'; } else { - $result=$result.$token->[2]; + $result.='>'; } + } elsif ( $token->[0] eq 'E' ) { + $result = '[1].'>'; } return $result; } -sub insert_startouttext { - return "\n\n"; +sub text_arg { + my ($description,$name,$token,$size) = @_; + my $result; + if (!defined $size) { $size=20; } + my $arg=$token->[2]{$name}; + $result=$description.''; + return $result; +} + +sub select_arg { + my ($description,$name,$list,$token) = @_; + my $result; + my $optionlist=""; + my $selected=$token->[2]{$name}; + foreach my $option (@$list) { + my $value; + if ( ref($option) eq 'ARRAY') { + $value='value="'.$$option[0].'"'; + $option=$$option[1]; + } else { + $value='value="'.$option.'"'; + } + if ( $selected eq $option ) { + $optionlist.="\n"; + } else { + $optionlist.="\n"; + } + } + $result.=$description.''; + return $result; +} + +sub select_or_text_arg { + my ($description,$name,$list,$token,$size) = @_; + my $result; + my $optionlist=""; + my $found=0; + my $selected=$token->[2]{$name}; + foreach my $option (@$list) { + my $value; + if ( ref($option) eq 'ARRAY') { + $value='value="'.$$option[0].'"'; + $option=$$option[1]; + } else { + $value='value="'.$option.'"'; + } + if ( $selected eq $option ) { + $optionlist.="\n"; + $found=1; + } else { + $optionlist.="\n"; + } + } + $optionlist.="\n"; + if (($found) || (!$selected)) { + $result.=$description.''; + } else { + $result.=&text_arg($description,$name,$token,$size); + } + return $result; +} + +#----------------------------------------------------- browse +sub browse { + # insert a link to call up the filesystem browser (lonindexer) + my ($id, $mode) = @_; + my $form = 'lonhomework'; + my $element; + if (! defined($mode) || $mode eq 'attribute') { + $element = &Apache::lonnet::escape("$Apache::lonxml::curdepth.$id"); + } elsif ($mode eq 'textnode') { # for data between ... + $element = &Apache::lonnet::escape('homework_edit_'. + $Apache::lonxml::curdepth); + } + my $result = <<"ENDBUTTON"; +Browse +ENDBUTTON + return $result; +} + +#----------------------------------------------------- browse +sub search { + # insert a link to call up the filesystem browser (lonindexer) + $_ = shift; + my $form = 'lonhomework'; + my $element = &Apache::lonnet::escape("$Apache::lonxml::curdepth.$_"); + my $result = <<"ENDBUTTON"; +Search +ENDBUTTON + return $result; } + 1; __END__ + +=head1 NAME + +Apache::edit - edit mode helpers + +=head1 SYNOPSIS + +Invoked by many homework and xml related modules. + + &Apache::edit::SUBROUTINENAME(ARGUMENTS); + +=head1 INTRODUCTION + +This module outputs HTML syntax helpful for the rendering of edit +mode interfaces. + +This is part of the LearningOnline Network with CAPA project +described at http://www.lon-capa.org. + +=head1 HANDLER SUBROUTINE + +There is no handler subroutine. + +=head1 OTHER SUBROUTINES + +=over 4 + +=item * + +initialize_edit() : initialize edit (set colordepth to zero) + +=item * + +tag_start($target,$token,$description) : provide deletion and insertion lists +for the manipulation of a start tag; return a scalar string + +=item * + +tag_end($target,$token,$description) : ending syntax corresponding to +&tag_start. return a scalar string. + +=item * + +start_table($token) : start table; update colordepth; return scalar string. + +=item * + +end_table() : reduce color depth; end table; return scalar string + +=item * + +start_spanning_row() : start a new table row spanning the 'edit' environment. + +=item * + +start_row() : start a new table row and element. + +=item * + +end_row() : end current table element and row. + +=item * + +movebuttons($target,$token) : move-up and move-down buttons; return scalar +string + +=item * + +deletelist($target,$token) : provide a yes option in an HTML select element; +return scalar string + +=item * + +handle_delete($space,$target,$token,$tagstack,$parstack,$parser,$safeeval, +$style) : respond to a user delete request by passing relevant stack +and array information to various rendering functions; return a scalar string + +=item * + +get_insert_list($token) : provide an insertion list based on possibilities +from lonxml; return a scalar string + +=item * + +insertlist($target,$token) : api that uses get_insert_list; +return a scalar string + +=item * + +handleinsert($token) : provide an insertion list based on possibilities +from lonxml; return a scalar string + +=item * + +get_insert_list($token) : provide an insertion list based on possibilities +from lonxml; return a scalar string + +=item * +browse($elementname) : provide a link which will open up the filesystem +browser (lonindexer) and, once a file is selected, place the result in +the form element $elementname. + +=item * +search($elementname) : provide a link which will open up the filesystem +searcher (lonsearchcat) and, once a file is selected, place the result in +the form element $elementname. + +=item * +editline(tag,data,description,size): Provide a for +single-line text entry. This is to be used for text enclosed by tags, not +arguements/parameters associated with a tag. + +=back + +incomplete... + +=cut