--- loncom/interface/londocs.pm 2012/05/15 01:41:27 1.487 +++ loncom/interface/londocs.pm 2012/06/30 23:11:11 1.488 @@ -1,7 +1,7 @@ # The LearningOnline Network # Documents # -# $Id: londocs.pm,v 1.487 2012/05/15 01:41:27 raeburn Exp $ +# $Id: londocs.pm,v 1.488 2012/06/30 23:11:11 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -40,7 +40,9 @@ use Apache::lonxml; use Apache::lonclonecourse; use Apache::lonnavmaps; use Apache::lonnavdisplay(); +use Apache::lonuserstate(); use HTML::Entities; +use HTML::TokeParser; use GDBM_File; use Apache::lonlocal; use Cwd; @@ -529,18 +531,30 @@ sub docs_change_log { ':'.$docslog{$id}{'exe_udom'}.''. $send_msg_link.''. $docslog{$id}{'logentry'}{'folder'}.''); + my $is_supp = 0; + if ($docslog{$id}{'logentry'}{'currentfolder'} =~ /^supplemental/) { + $is_supp = 1; + } # Before for (my $idx=0;$idx<=$docslog{$id}{'logentry'}{'maxidx'};$idx++) { my $oldname=(split(/\:/,$docslog{$id}{'logentry'}{'before_resources_'.$idx}))[0]; my $newname=(split(/\:/,$docslog{$id}{'logentry'}{'after_resources_'.$idx}))[0]; if ($oldname ne $newname) { - $r->print(&LONCAPA::map::qtescape($oldname)); + my $shown = &LONCAPA::map::qtescape($oldname); + if ($is_supp) { + $shown = &Apache::loncommon::parse_supplemental_title($shown); + } + $r->print($shown); } } $r->print(''); @@ -551,13 +565,21 @@ sub docs_change_log { my $oldname=(split(/\:/,$docslog{$id}{'logentry'}{'before_resources_'.$idx}))[0]; my $newname=(split(/\:/,$docslog{$id}{'logentry'}{'after_resources_'.$idx}))[0]; if ($oldname ne '' && $oldname ne $newname) { - $r->print(&LONCAPA::map::qtescape($newname)); + my $shown = &LONCAPA::map::qtescape($newname); + if ($is_supp) { + $shown = &Apache::loncommon::parse_supplemental_title(&LONCAPA::map::qtescape($newname)); + } + $r->print($shown); } } $r->print(''); @@ -602,7 +624,7 @@ sub update_paste_buffer { my ($title,$url)=split(':',$LONCAPA::map::resources[$LONCAPA::map::order[$env{'form.markcopy'}]]); if (&is_supplemental_title($title)) { &Apache::lonnet::appenv({'docs.markedcopy_supplemental' => $title}); - ($title) = &parse_supplemental_title($title); + ($title) = &Apache::loncommon::parse_supplemental_title($title); } elsif ($env{'docs.markedcopy_supplemental'}) { &Apache::lonnet::delenv('docs.markedcopy_supplemental'); } @@ -614,23 +636,42 @@ sub update_paste_buffer { } sub print_paste_buffer { - my ($r,$container) = @_; + my ($r,$container,$folder) = @_; return if (!defined($env{'docs.markedcopy_url'})); + my $is_external; + my $extension = (split(/\./,$env{'docs.markedcopy_url'}))[-1]; + if ($env{'docs.markedcopy_url'} =~ m{^(?:/adm/wrapper/ext|(?:http|https)(?::|:))//} ) { + $is_external = 1; + } + + my $canpaste; + if ($folder =~ /^supplemental/) { + $canpaste = &supp_pasteable($env{'docs.markedcopy_url'}); + } else { + $canpaste = 1; + } + + my $pasteinfo; + if ($canpaste) { + $pasteinfo = '
' + .' '; + } else { + $pasteinfo = &mt('Paste buffer contains:').' '; + } + $r->print('
' .''.&mt('Clipboard').'' - .'' - .' ' - ); + .$pasteinfo + ); my $type; - if ($env{'docs.markedcopy_url'} =~ m{^(?:/adm/wrapper/ext|(?:http|https)(?::|:))//} ) { + if ($is_external) { $type = &mt('External Resource'); $r->print($type.': '. &LONCAPA::map::qtescape($env{'docs.markedcopy_title'}).' ('. &LONCAPA::map::qtescape($env{'docs.markedcopy_url'}).')'); } else { - my $extension = (split(/\./,$env{'docs.markedcopy_url'}))[-1]; my $icon = &Apache::loncommon::icon($extension); if ($extension eq 'sequence' && $env{'docs.markedcopy_url'} =~ m{/default_\d+\.sequence$ }x) { @@ -638,19 +679,36 @@ sub print_paste_buffer { $icon .= '/navmap.folder.closed.gif'; } $icon = ''; - $r->print($icon.$type.': '. &parse_supplemental_title(&LONCAPA::map::qtescape($env{'docs.markedcopy_title'}))); + $r->print($icon.$type.': '. &Apache::loncommon::parse_supplemental_title(&LONCAPA::map::qtescape($env{'docs.markedcopy_title'}))); } - if ($container eq 'page') { - $r->print(' + if ($canpaste) { + if ($container eq 'page') { + $r->print(' '); - } else { - $r->print(' + } else { + $r->print(' '); + } + $r->print(''); + } else { + $r->print('

'.&mt('Paste into Supplemental Content unavailable for this type of content.').'

'); } - $r->print('
'); + $r->print(''); +} + +sub supp_pasteable { + my ($url) = @_; + if (($url =~ m{^(?:/adm/wrapper/ext|(?:http|https)(?::|:))//}) || + (($url =~ /\.sequence$/) && ($url =~ m{^/uploaded/})) || + ($url =~ m{^/uploaded/$match_domain/$match_courseid/(docs|supplemental)/(default|\d+)/\d+/}) || + ($url =~ m{^/adm/$match_domain/$match_username/aboutme}) || + ($url =~ m{^/public/$match_domain/$match_courseid/syllabus})) { + return 1; + } + return; } sub do_paste_from_buffer { @@ -660,15 +718,37 @@ sub do_paste_from_buffer { return; } +# Supplemental content may only include certain types of content + if ($folder =~ /^supplemental/) { + unless (&supp_pasteable($env{'docs.markedcopy_url'})) { + return &mt('Paste failed: content type is not supported within Supplemental Content'); + } + } + # paste resource to end of list my $url=&LONCAPA::map::qtescape($env{'docs.markedcopy_url'}); my $title=&LONCAPA::map::qtescape($env{'docs.markedcopy_title'}); # Maps need to be copied first - if (($url=~/\.(page|sequence)$/) && ($url=~/^\/uploaded\//)) { - $title=&mt('Copy of').' '.$title; + my ($oldurl,%removefrommap,%addedmaps,%rewrites,%copies,%dbcopies,%zombies,%params); + if ($url=~/\.(page|sequence)$/) { + # If pasting a map, check if map contains other maps + &contained_map_check($url,$folder,\%removefrommap,\%addedmaps); + if (keys(%addedmaps) > 0) { + &reinit_role($coursedom,$coursenum,$env{"course.$env{'request.course.id'}.home"}); + } + my %allmaps; + my $navmap = Apache::lonnavmaps::navmap->new(); + if (defined($navmap)) { + foreach my $res ($navmap->retrieveResources(undef,sub { $_[0]->is_map() },1,0,1)) { + $allmaps{$res->src()} = 1; + } + } + if ($url=~ m{^/uploaded/}) { + $title=&mt('Copy of').' '.$title; + } my $newid=$$.int(rand(100)).time; my ($oldid,$ext) = ($url=~/^(.+)\.(\w+)$/); - if ($oldid =~ m{^(/uploaded/\Q$coursedom\E/\Q$coursenum\E/)(\D+)(\d+)$}) { + if ($oldid =~ m{^(/uploaded/$match_domain/$match_courseid/)(\D+)(\d+)$}) { my $path = $1; my $prefix = $2; my $ancestor = $3; @@ -676,40 +756,58 @@ sub do_paste_from_buffer { $ancestor = substr($ancestor,-10,10); } $oldid = $path.$prefix.$ancestor; - } - my $counter = 0; - my $newurl=$oldid.$newid.'.'.$ext; - my $is_unique = &uniqueness_check($newurl); - while (!$is_unique && $counter < 100) { - $counter ++; - $newid ++; - $newurl = $oldid.$newid; - $is_unique = &uniqueness_check($newurl); - } - if (!$is_unique) { - if ($url=~/\.page$/) { - return &mt('Paste failed: an error occurred creating a unique URL for the composite page'); - } else { - return &mt('Paste failed: an error occurred creating a unique URL for the folder'); + my $counter = 0; + my $newurl=$oldid.$newid.'.'.$ext; + my $is_unique = &uniqueness_check($newurl); + if ($allmaps{$newurl}) { + $is_unique = 0; } - } - my $storefn=$newurl; - $storefn=~s{^/\w+/$match_domain/$match_username/}{}; - my $paste_map_result = - &Apache::lonclonecourse::writefile($env{'request.course.id'},$storefn, - &Apache::lonnet::getfile($url)); - if ($paste_map_result eq '/adm/notfound.html') { - if ($url=~/\.page$/) { - return &mt('Paste failed: an error occurred saving the composite page'); + while (!$is_unique && $allmaps{$newurl} && $counter < 100) { + $counter ++; + $newid ++; + $newurl = $oldid.$newid; + $is_unique = &uniqueness_check($newurl); + } + if ($is_unique) { + if ($path =~ m{^/uploaded/($match_domain)/($match_courseid)/$}) { + my $srcdom = $1; + my $srcnum = $2; + if (($srcdom ne $coursedom) && ($srcnum ne $coursenum)) { + if (&Apache::lonnet::allowed('mdc',$srcdom.'_'.$srcnum)) { + &url_paste_fixups($oldid,$ext,$coursedom,$coursenum, + \%allmaps, \%rewrites,\%copies,\%dbcopies,\%zombies,\%params); + } else { + return &mt('Paste failed: Item is from a different course which you do not have rights to edit'); + } + } + } } else { - return &mt('Paste failed: an error occurred saving the folder'); + if ($url=~/\.page$/) { + return &mt('Paste failed: an error occurred creating a unique URL for the composite page'); + } else { + return &mt('Paste failed: an error occurred creating a unique URL for the folder'); + } } - } - $url = $newurl; - } + my $storefn=$newurl; + $storefn=~s{^/\w+/$match_domain/$match_username/}{}; + my $paste_map_result = + &Apache::lonclonecourse::writefile($env{'request.course.id'},$storefn, + &Apache::lonnet::getfile($url)); + if ($paste_map_result eq '/adm/notfound.html') { + if ($url=~/\.page$/) { + return &mt('Paste failed: an error occurred saving the composite page'); + } else { + return &mt('Paste failed: an error occurred saving the folder'); + } + } + $url = $newurl; + } elsif ($url=~m {^/res/}) { # published maps can only exists once, so remove it from paste buffer when done - if (($url=~/\.(page|sequence)$/) && ($url=~m {^/res/})) { - &Apache::lonnet::delenv('docs.markedcopy'); + &Apache::lonnet::delenv('docs.markedcopy'); + if ($allmaps{$url}) { + return &mt('Paste failed: only one instance of a particular published sequence or page is allowed within each course.'); + } + } } if ($url=~ m{/smppg$}) { my $db_name = &Apache::lonsimplepage::get_db_name($url); @@ -730,12 +828,43 @@ sub do_paste_from_buffer { $url = &LONCAPA::map::qtunescape($url); # Now insert the URL at the bottom my $newidx = &LONCAPA::map::getresidx($url); + my $relpath; + if (($folder =~ /^supplemental/) && + ($url =~ m{^/uploaded/$coursedom/$coursenum/docs/(.+)})) { + $relpath = $1; + } elsif (($folder =~ /^default/) && + ($url =~ m{^/uploaded/$coursedom/$coursenum/supplemental/(.+)})) { + $relpath = $1; + } + if ($relpath ne '') { + my ($prefix,$subdir,$rem) = ($relpath =~ m{^(default|\d+)/(\d+)/(.+)$}); + my ($newloc,$newsubdir) = ($folder =~ /^(default|supplemental)_?(\d*)/); + my $newprefix = $newloc; + if ($newloc eq 'default') { + $newprefix = 'docs'; + } + if ($newsubdir eq '') { + $newsubdir = 'default'; + } + my $newpath = "$newprefix/$newsubdir/$newidx/$rem"; + $url = + &Apache::lonclonecourse::writefile($env{'request.course.id'},$newpath, + &Apache::lonnet::getfile($url)); + if ($url eq '/adm/notfound.html') { + return &mt('Paste failed: an error occurred saving the file.'); + } + } + my $noparams = 0; + if ((ref($params{$oldurl}) eq 'HASH') && ($relpath ne '') && ($folder =~ /^supplemental/)) { + $noparams = 1; + } + &apply_fixups($coursedom,$coursenum,$oldurl,$url,$noparams,\%rewrites,\%copies,\%dbcopies,\%zombies,\%params); if ($env{'docs.markedcopy_supplemental'}) { if ($folder =~ /^supplemental/) { $title = $env{'docs.markedcopy_supplemental'}; } else { (undef,undef,$title) = - &parse_supplemental_title($env{'docs.markedcopy_supplemental'}); + &Apache::loncommon::parse_supplemental_title($env{'docs.markedcopy_supplemental'}); } } else { if ($folder=~/^supplemental/) { @@ -750,6 +879,23 @@ sub do_paste_from_buffer { # Store the result } +sub dbcopy { + my ($url,$coursedom,$coursenum) = @_; + if ($url=~ m{/smppg$}) { + my $db_name = &Apache::lonsimplepage::get_db_name($url); + if ($db_name =~ /^smppage_/) { + #simple pages, need to copy the db contents to a new one. + my %contents=&Apache::lonnet::dump($db_name,$coursedom,$coursenum); + my $now = time(); + $db_name =~ s{_\d*$ }{_$now}x; + my $result=&Apache::lonnet::put($db_name,\%contents, + $coursedom,$coursenum); + $url =~ s{/(\d*)/smppg$ }{/$now/smppg}x; + } + } + return $url; +} + sub uniqueness_check { my ($newurl) = @_; my $unique = 1; @@ -764,6 +910,188 @@ sub uniqueness_check { return $unique; } +sub contained_map_check { + my ($url,$folder,$removefrommap,$addedmaps) = @_; + my $content = &Apache::lonnet::getfile($url); + unless ($content eq '-1') { + my $parser = HTML::TokeParser->new(\$content); + $parser->attr_encoded(1); + while (my $token = $parser->get_token) { + next if ($token->[0] ne 'S'); + if ($token->[1] eq 'resource') { + next if ($token->[2]->{'type'} eq 'zombie'); + my $ressrc = $token->[2]->{'src'}; + if ($folder =~ /^supplemental/) { + unless (&supp_pasteable($ressrc)) { + $removefrommap->{$url}{$token->[2]->{'id'}}; + next; + } + } + if ($ressrc =~ /\.(sequence|page)$/) { + if (ref($addedmaps->{$ressrc}) eq 'ARRAY') { + push(@{$addedmaps->{$ressrc}},$url); + } else { + $addedmaps->{$ressrc} = [$url]; + } + &contained_map_check($ressrc,$folder,$removefrommap,$addedmaps); + } + } elsif ($token->[1] !~ /^resource|map|link$/) { + if ($folder =~ /^supplemental/) { + $removefrommap->{$url}{$token->[1]}; + } + } + } + } + return; +} + +sub reinit_role { + my ($cdom,$cnum,$chome) = @_; + my ($furl,$ferr) = &Apache::lonuserstate::readmap("$cdom/$cnum"); + unless ($ferr) { + &Apache::loncommon::update_content_constraints($cdom,$cnum,$chome,$cdom.'_'.$cnum); + } + return; +} + +sub url_paste_fixups { + my ($oldurl,$ext,$cdom,$cnum,$allmaps,$rewrites,$copies,$dbcopies,$zombies,$params) = @_; + my $file = &Apache::lonnet::getfile("$oldurl.$ext"); + return if ($file eq '-1'); + my $parser = HTML::TokeParser->new(\$file); + $parser->attr_encoded(1); + while (my $token = $parser->get_token) { + next if ($token->[0] ne 'S'); + if ($token->[1] eq 'resource') { + my $ressrc = $token->[2]->{'src'}; + next if ($ressrc eq ''); + next if ($token->[2]->{'type'} eq 'external'); + my $id = $token->[2]->{'id'}; + if ($token->[2]->{'type'} eq 'zombie') { + $zombies->{$oldurl}{$ressrc} = $id; + } elsif ($ressrc =~ m{^/uploaded/($match_domain)/($match_courseid)/(.+)}) { + my $srccdom = $1; + my $srccnum = $2; + my $rem = $3; + if (($srccdom ne $cdom) || ($srccnum ne $cnum)) { + if ($rem =~ /^(default|supplemental)(_?\d*).(sequence|page)$/) { + $rewrites->{$oldurl}{$ressrc} = $id; + &url_paste_fixups($ressrc,$3,$cdom,$cnum,$allmaps,$rewrites,$copies,$dbcopies,$zombies,$params); + } else { + $copies->{$oldurl}{$ressrc} = $id; + } + } + } elsif ($ressrc =~ m{^/adm/($match_domain)/($match_courseid)/(.+)$}) { + my $srccdom = $1; + my $srccnum = $2; + if (($srccdom ne $cdom) || ($srccnum ne $cnum)) { + $rewrites->{$oldurl}{$ressrc} = $id; + $dbcopies->{$oldurl}{$ressrc} = $id; + } + } elsif ($ressrc =~ m{^/public/($match_domain)/($match_courseid)/(.+)$}) { + my $srccdom = $1; + my $srccnum = $2; + if (($srccdom ne $cdom) || ($srccnum ne $cnum)) { + $rewrites->{$oldurl}{$ressrc} = $id; + $dbcopies->{$oldurl}{$ressrc} = $id; + } + } + } elsif ($token->[1] eq 'param') { + my $to = $token->[2]->{'to'}; + if ($to ne '') { + if (ref($params->{$oldurl}{$to}) eq 'ARRAY') { + push (@{$params->{$oldurl}{$to}},$token->[2]->{'name'}); + } else { + @{$params->{$oldurl}{$to}} = ($token->[2]->{'name'}); + } + } + } + } + return; +} + +sub apply_fixups { + my ($cdom,$cnum,$oldurl,$url,$noparams,$rewrites,$copies,$dbcopies,$zombies,$params) = @_; + my (%newdb,%newdoc); + if (ref($dbcopies->{$oldurl}) eq 'HASH') { + foreach my $item (keys(%{$dbcopies->{$oldurl}})) { + $newdb{$item} = &dbcopy($item); + } + } + if (ref($copies->{$oldurl}) eq 'HASH') { + foreach my $item (keys(%{$copies->{$oldurl}})) { + my $content = &Apache::lonnet::getfile($item); + my $newcontent; + unless ($content eq '-1') { + my $mm = new File::MMagic; + my $mimetype = $mm->checktype_contents($content); + if ($mimetype eq 'text/html') { + my (%allfiles,%codebase,$state); + my ($embedded,$num,$delnum) = + &Apache::loncommon::ask_for_embedded_content( + '/adm/dependencies',$state,\%allfiles,\%codebase, + {'error_on_invalid_names' => 1, + 'ignore_remote_references' => 1, + 'docs_url' => $oldurl}); + if ($embedded) { + #FIXME Need to check for dependencies and copy and update refs. + } + $newcontent = $content; + } else { + $newcontent = $content; + } + my $storefn=$item; + $storefn=~s{^/\w+/$match_domain/$match_courseid/}{}; + $newdoc{$item} = &Apache::lonclonecourse::writefile($env{'request.course.id'},$storefn,$newcontent); + } + } + } + if (((ref($rewrites->{$oldurl}) eq 'HASH') || (ref($zombies->{$oldurl}) eq 'HASH')) || + ($noparams) || (keys(%newdb) > 0) || (keys(%newdoc) > 0)) { + my $map = &Apache::lonnet::getfile($url); + my $newcontent; + unless ($map eq '-1') { + my $parser = HTML::TokeParser->new(\$map); + $parser->attr_encoded(1); + while (my $token = $parser->get_token) { + if ($token->[0] eq 'S') { + next if ($token->[2]->{'type'} eq 'zombie'); + next if (($token->[1] eq 'param') && $noparams); + if ($token->[1] eq 'resource') { + my $src = $token->[2]->{'src'}; + my $id = $token->[2]->{'id'}; + if (($rewrites->{$oldurl}{$src} eq $id) || ($newdb{$src} ne '') + || ($newdoc{$src} ne '')) { + if (ref($rewrites->{$oldurl}) eq 'HASH') { + if ($rewrites->{$oldurl}{$src} eq $id) { + $token->[2]->{'src'} =~ s{^(/uploaded|adm|public)/$match_domain/$match_courseid/}{$1/$cdom/$cnum}; + } + } elsif ($newdb{$src} ne '') { + $token->[2]->{'src'} = $newdb{$src}; + } + $newcontent .= "<$token->[1] "; + foreach my $attr (@{$token->[3]}) { + $newcontent .= ' '.$attr.'="'.$token->[2]->{$attr},'"' + } + $newcontent .= ' />'; + } else { + $newcontent .= $token->[4]."\n"; + } + } + } elsif ($token->[0] eq 'E') { + $newcontent .= $token->[2]."\n"; + } + } + } + my $storefn=$url; + $storefn=~s{^/\w+/$match_domain/$match_courseid/}{}; + my $storeres = + &Apache::lonclonecourse::writefile($env{'request.course.id'},$storefn, + $newcontent); + } + return; +} + my %parameter_type = ( 'randompick' => 'int_pos', 'hiddenresource' => 'string_yesno', 'encrypturl' => 'string_yesno', @@ -1016,7 +1344,7 @@ sub editor { my $readfile="/uploaded/$coursedom/$coursenum/$folder.$container"; $r->print(&generate_edit_table($tid,$orderhash,$to_show,$iconpath,$jumpto, $readfile)); - &print_paste_buffer($r,$container); + &print_paste_buffer($r,$container,$folder); } else { if (&Apache::lonnet::allowed('mdc',$env{'request.course.id'})) { #Function Box for Supplemental Content for users with mdc priv. @@ -1192,36 +1520,13 @@ sub is_supplemental_title { return scalar($title =~ m/^(\d+)___&&&___($match_username)___&&&___($match_domain)___&&&___(.*)$/); } -sub parse_supplemental_title { - my ($title) = @_; - - my ($foldertitle,$renametitle); - if ($title =~ /&&&/) { - $title = &HTML::Entites::decode($title); - } - if ($title =~ m/^(\d+)___&&&___($match_username)___&&&___($match_domain)___&&&___(.*)$/) { - $renametitle=$4; - my ($time,$uname,$udom) = ($1,$2,$3); - $foldertitle=&Apache::lontexconvert::msgtexconverted($4); - my $name = &Apache::loncommon::plainname($uname,$udom); - $name = &HTML::Entities::encode($name,'"<>&\''); - $renametitle = &HTML::Entities::encode($renametitle,'"<>&\''); - $title=''.&Apache::lonlocal::locallocaltime($time).' '. - $name.':
'.$foldertitle; - } - if (wantarray) { - return ($title,$foldertitle,$renametitle); - } - return $title; -} - # --------------------------------------------------------------- An entry line sub entryline { my ($index,$title,$url,$folder,$allowed,$residx,$coursenum,$crstype)=@_; my ($foldertitle,$pagetitle,$renametitle); if (&is_supplemental_title($title)) { - ($title,$foldertitle,$renametitle) = &parse_supplemental_title($title); + ($title,$foldertitle,$renametitle) = &Apache::loncommon::parse_supplemental_title($title); $pagetitle = $foldertitle; } else { $title=&HTML::Entities::encode($title,'"<>&\''); @@ -2878,8 +3183,8 @@ NGFFORM $communityform = &create_form_ul(&create_list_elements(@communityforma)); my %orderhash = ( - 'aa' => ['Import Documents',$fileuploadform], - 'bb' => ['Published Resources',$simpleeditdefaultform], + 'aa' => ['Import Content',$fileuploadform], + 'bb' => ['Published Content',$simpleeditdefaultform], 'cc' => ['Grading Resources',$gradingform], ); unless ($env{'form.pagepath'}) { @@ -2998,7 +3303,7 @@ my @supimportdoc = ( $supupdocform = &create_form_ul(&create_list_elements(@supimportdoc)) . '
' . $supupdocform; my %suporderhash = ( '00' => ['Supnewfolder', $supnewfolderform], - 'ee' => ['Import Documents',$supupdocform], + 'ee' => ['Import Content',$supupdocform], 'ff' => ['Special Documents',&create_form_ul(&create_list_elements(@specialdocs))] ); if ($supplementalflag) { @@ -3283,26 +3588,24 @@ sub generate_edit_table { my $backicon = $iconpath.'clickhere.gif'; my $backtext = &mt('To Overview'); $form = '
'. - '