# The LearningOnline Network # Documents # # $Id: lonextresedit.pm,v 1.8.2.4.4.2 2023/07/05 18:41:20 raeburn 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/ # package Apache::lonextresedit; use strict; use Apache::Constants qw(:common :http); use HTML::Entities; use Apache::lonlocal; use Apache::lonnet; use Apache::loncommon; use Apache::lonhtmlcommon; use Apache::lonuserstate; use LONCAPA::map(); use LONCAPA qw(:DEFAULT :match); sub handler { my $r=shift; &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; return OK if $r->header_only; # Check for access if (! &Apache::lonnet::allowed('mdc',$env{'request.course.id'})) { $env{'user.error.msg'}= $r->uri.":mdc:0:0:Cannot modify course content."; return HTTP_NOT_ACCEPTABLE; } my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; my $chome = $env{'course.'.$env{'request.course.id'}.'.home'}; my ($supplementalflag,$updated,$output,$errormsg,$residx,$url,$title, $symb,$type); if (($env{'form.folderpath'} =~ /^supplemental/) && ($env{'form.suppurl'})) { $supplementalflag = 1; if (&unescape($env{'form.suppurl'}) =~ m{^/adm/$cdom/$cnum/\d+/ext\.tool$}) { $type = 'tool'; } } if (($supplementalflag) || ($env{'form.symb'} =~ /^uploaded/)) { ($updated,$output,$errormsg,$residx,$url,$title,$symb) = &process_changes($supplementalflag,$cdom,$cnum,$chome); if ($supplementalflag) { if ($url ne &unescape($env{'form.suppurl'})) { $env{'form.suppurl'} = $url; } if ($title ne $env{'form.title'}) { $env{'form.title'} = $title; } $env{'form.idx'} = $residx; } else { if ($symb ne $env{'form.symb'}) { $env{'form.symb'} = $symb; } if ($url =~ m{/adm/$cdom/$cnum/\d+/ext\.tool$}) { $type = 'tool'; } } } else { $errormsg = &mt('Information about external resource to edit is missing.'); } if ($updated) { my $msg = &mt('External Resource updated'); if ($type eq 'tool') { $msg = &mt('External Tool updated'); } $output = &Apache::lonhtmlcommon::confirm_success($msg); } if ($errormsg) { $errormsg = '

'.$errormsg.'

'; } my %ltitools; if ($type eq 'tool') { my (%domtools,%crstools); my %tooltypes = &Apache::loncommon::usable_exttools(); if ($tooltypes{'dom'}) { %domtools = &Apache::lonnet::get_domain_lti($cdom,'consumer'); } if ($tooltypes{'crs'}) { %crstools = &Apache::lonnet::get_course_lti($cnum,$cdom,'consumer'); } %ltitools = ( dom => \%domtools, crs => \%crstools, ); } my $js = &Apache::lonhtmlcommon::scripttag(&extedit_javascript()); my $pathitem = ''; my $description = 'External Resource Editor'; if ($type eq 'tool') { $description = 'External Tool Editor'; } $r->print(&Apache::loncommon::start_page($description,$js). '
'. $output. $errormsg. &extedit_form($supplementalflag,$residx,$url,$title,$pathitem,undef, 'direct',$env{'form.symb'},$type,$cdom,$cnum,\%ltitools). '
'.&Apache::loncommon::end_page()); return OK; } sub process_changes { my ($supplementalflag,$cdom,$cnum,$chome) = @_; my ($folder,$container,$output,$errormsg,$updated,$symb,$oldidx,$oldurl,$type, $oldtitle,$newidx,$newurl,$newtitle,$residx,$url,$title,$marker,$args); if ($env{'form.symb'}) { $symb = $env{'form.symb'}; (my $map,$oldidx,$oldurl)=&Apache::lonnet::decode_symb($symb); if ($map =~ m{^uploaded/$cdom/$cnum/(default(_\d+|))\.(sequence|page)$}) { $folder = $1; $container = $3; } $oldtitle = &Apache::lonnet::gettitle($env{'form.symb'}); if ($oldurl =~ m{^ext/(.+)$}) { my $external = $1; if ($external =~ m{^https://}) { $oldurl = $external; } else { $oldurl = 'http://'.$oldurl; } $type = 'ext'; } else { $type = 'tool'; } } elsif ($env{'form.folderpath'}) { $folder = &unescape( (split('&',$env{'form.folderpath'}))[-2] ); $oldurl = &unescape($env{'form.suppurl'}); $oldtitle = &unescape($env{'form.title'}); $container = 'sequence'; $supplementalflag = 1; if ($oldurl =~ m{^/adm/$cdom/$cnum/\d+/ext\.tool$}) { $type = 'tool'; } else { $type = 'ext'; } } $url = $oldurl; $title = $oldtitle; if ($env{'form.importdetail'}) { ($newtitle,$newurl,$newidx) = map {&unescape($_)} split(/\=/,$env{'form.importdetail'}); if ($newurl =~ m{^(/adm/$cdom/$cnum/(\d+)/ext\.tool)\:?(.*)$}) { $newurl = $1; $marker = $2; $args = $3; if ((!$symb) && (!$supplementalflag)) { $symb = "uploaded/$cdom/$cnum/$folder.$container"."___$newidx"."___adm/$cdom/$cnum/$marker/ext.tool"; } } } if ($supplementalflag) { $residx = $newidx; } else { $residx = $oldidx; } if ($folder && $container) { if ($env{'form.importdetail'}) { my ($errtext,$fatal,$mismatchedid,$needreload,$newgradable,@imports); if (!$supplementalflag) { if (($oldidx) && ($oldidx != $newidx)) { $mismatchedid = 1; } } if ($mismatchedid) { $errormsg = 'Wrong item identifier'; } elsif (($newtitle eq $oldtitle) && ($newurl eq $oldurl)) { if ($type eq 'tool') { if ($args) { ($updated,$newgradable,$errormsg) = &update_exttool($marker,$cdom,$cnum, $supplementalflag,$args); if ($updated) { if ($newgradable) { my $map = "/uploaded/$cdom/$cnum/$folder.$container"; my ($errtext,$fatal) = &LONCAPA::map::mapread($map); if ($fatal) { $errormsg = &mt('Update failed: [_1].',$errtext); } else { &LONCAPA::map::storeparameter($residx,'parameter_0_gradable', $newgradable,'string_yesno'); my ($outtext,$errtext) = &LONCAPA::map::storemap($map,1,1); if ($errtext) { $errormsg = &mt('Update failed: [_1].',$errtext); } else { $needreload = 1; } } } } else { $output = &mt('No change'); } } else { $output = &mt('No change'); } } else { $output = &mt('No change'); } } else { my $map = "/uploaded/$cdom/$cnum/$folder.$container"; my ($errtext,$fatal) = &LONCAPA::map::mapread($map); if ($fatal) { $errormsg = &mt('Update failed: [_1].',$errtext); } else { my $saveurl = &LONCAPA::map::qtunescape($newurl); my $savetitle = &LONCAPA::map::qtunescape($newtitle); my $ext = 'true'; if ($type eq 'tool') { if ($args) { ($updated,$newgradable,$errormsg) = &update_exttool($marker,$cdom,$cnum, $supplementalflag,$args); if ($newgradable) { &LONCAPA::map::storeparameter($residx,'parameter_0_gradable',$newgradable, 'string_yesno'); $needreload = 1; } } $ext = 'false'; } my $dotimeupdate; unless ($supplementalflag) { if (($newgradable) || ($newurl ne $oldurl)) { $dotimeupdate = 1; } } $LONCAPA::map::resources[$residx] = join(':', ($savetitle,$saveurl,$ext,'normal','res')); my ($outtext,$errtext) = &LONCAPA::map::storemap($map,1,$dotimeupdate); if ($errtext) { $errormsg = &mt('Update failed: [_1].',$errtext); } else { $updated = 1; $title = $newtitle; if ($newurl ne $oldurl) { $url = $newurl; if ($ext eq 'true') { $newurl =~ s{^http://}{}; $newurl = "ext/$newurl"; } } if (!$supplementalflag) { if ($newurl ne $oldurl) { $symb = &Apache::lonnet::encode_symb($map,$residx,$newurl); } else { $symb = $env{'form.symb'}; if ($symb) { &Apache::lonnet::devalidate_title_cache($symb); } } $needreload = 1; } } } } if ($needreload) { my ($furl,$ferr) = &Apache::lonuserstate::readmap("$cdom/$cnum"); if ($ferr) { $errormsg = &mt('Reload failed: [_1].',$ferr); } else { unless ($supplementalflag) { &Apache::loncommon::update_content_constraints($cdom,$cnum,$chome, $cdom.'_'.$cnum); } } } if (($type eq 'tool') && ($newgradable)) { my $uri = &Apache::lonnet::declutter($url); &Apache::lonnet::devalidate_cache_new('meta',$uri); } } else { $output = &mt('No change'); } } else { if ($type eq 'tool') { $errormsg = &mt('Information about current external tool is incomplete.'); } else { $errormsg = &mt('Information about current external resource is incomplete.'); } } return ($updated,$output,$errormsg,$residx,$url,$title,$symb); } sub update_exttool { my ($marker,$cdom,$cnum,$supplementalflag,$args) = @_; my (%newhash,$changed,$newgradable,@deleted,$errormsg); ($newhash{'target'},$newhash{'width'},$newhash{'height'},$newhash{'linktext'},$newhash{'explanation'}, $newhash{'crslabel'},$newhash{'crstitle'},$newhash{'crsappend'},$newhash{'gradable'}) = split(/:/,$args); foreach my $item ('linktext','explanation','crslabel','crstitle','crsappend') { $newhash{$item} = &unescape($newhash{$item}); } my %toolhash=&Apache::lonnet::dump('exttool_'.$marker,$cdom,$cnum); foreach my $item ('target','width','height','linktext','explanation','crslabel','crstitle','crsappend','gradable') { $newhash{$item} =~ s/^\s+//; $newhash{$item} =~ s/\s+$//; if (($item eq 'width') || ($item eq 'height') || ($item eq 'linktext') || ($item eq 'explanation')) { if ($newhash{'target'} eq 'iframe') { $newhash{$item} = ''; } elsif ($newhash{'target'} eq 'tab') { if (($item eq 'width') || ($item eq 'height')) { $newhash{$item} = ''; } } } elsif ($item eq 'gradable') { unless ($newhash{$item} == 1) { $newhash{$item} = ''; } } if ($toolhash{$item} ne $newhash{$item}) { if (($item eq 'gradable') && (!$supplementalflag)) { if ($newhash{$item}) { $newgradable = 'yes'; } else { $newgradable = 'no'; } } if ($newhash{$item} eq '') { unless (($item eq 'target') || ((($item eq 'width') || ($item eq 'height')) && (($newhash{'target'} eq 'window') || (($newhash{'target'} eq '') && ($toolhash{'target'} eq 'window')))) || ((($item eq 'linktext') || ($item eq 'explanation')) && ((($newhash{'target'} =~ /^(window|tab)$/)) || (($newhash{'target'} eq '') && ($toolhash{'target'} =~ /^(window|tab)$/))))) { delete($toolhash{$item}); push(@deleted,$item); $changed = 1; } } else { $toolhash{$item} = $newhash{$item}; $changed = 1; } } } if ($changed) { my $putres = &Apache::lonnet::put('exttool_'.$marker,\%toolhash,$cdom,$cnum); unless ($putres eq 'ok') { $errormsg = &mt('Failed to save updated settings.').' '.&mt('Error: [_1].',$putres); } } if (@deleted) { &Apache::lonnet::del('exttool_'.$marker,\@deleted,$cdom,$cnum); } return ($changed,$newgradable,$errormsg); } sub extedit_form { my ($supplementalflag,$residx,$orig_url,$orig_title,$pathitem,$helpitem,$caller, $symb,$type,$cdom,$cnum,$ltitools,$disabled) = @_; if ($type ne 'tool') { $type = 'ext'; } my %lt = &Apache::lonlocal::texthash( ex => 'External Resource', et => 'External Tool', ed => 'Edit', ee => 'External Resource Editor', te => 'External Tool Editor', pr => 'Preview', sv => 'Save', ul => 'URL', ti => 'Title', al => 'Add Link', at => 'Add Tool', dd => 'Defined in domain', dc => 'Defined in course', ); my $tabid = 'aa'; my $size = 60; if ($supplementalflag) { $tabid = 'ee'; } my ($formname,$formid,$toggle,$fieldsetid,$urlid,$subdivid,$dispdivstyle,$dimendivstyle, $windivstyle,$linktextstyle,$explanationstyle,$labelstyle,$titlestyle, $appendstyle,$gradablestyle,$subdivstyle,$legend,$urlelem,$toolelem,%toolattr); $formname = 'new'.$type; $toggle = $type; $fieldsetid = 'upload'.$type.'form'; $urlid = $type.'url'; map { $toolattr{$_} = $type.$_; } ('dispdiv','dimendiv','dimenwidth','dimenheight', 'crstitlediv','crslabeldiv','crsappenddiv', 'gradablediv','crstitle','crslabel','crsappend', 'windiv','linktextdiv','explanationdiv', 'linktext','explanation','providerurl'); $dispdivstyle = 'display:none'; $dimendivstyle = 'display:none'; $windivstyle = 'display:none'; $linktextstyle = 'display:none'; $explanationstyle = 'display:none'; $labelstyle = 'display:none'; $titlestyle = 'display:none'; $appendstyle = 'display:none'; $gradablestyle = 'display:none'; $subdivstyle = 'display:block'; if ($supplementalflag) { $formname = 'newsupp'.$type; $toggle = 'supp'.$type; $fieldsetid = 'uploadsupp'.$type.'form'; $urlid = 'supp'.$type.'url'; map { $toolattr{$_} = 'supp'.$toolattr{$_}; } (keys(%toolattr)); } my ($link,$legend,$active,$srcclass,$extsrc,$preview,$title,$save,$crstitle,$crslabel, $crsappend,$fieldsetstyle,$action,$hiddenelem,$form,$width,$height,$tooltarget, $linktext,$explanation,$providerurl,$chkgrd,$chknogrd,%chkstate); $fieldsetstyle = 'display: none;'; $action = '/adm/coursedocs'; my $protocol = ($ENV{'SERVER_PORT'} == 443?'https':'http'); my $rows = 2; my $cols = 20; if ($residx) { if ($caller eq 'direct') { $fieldsetstyle = 'display: block;'; $action = '/adm/extresedit'; $rows = 10; $cols = 45; if ($type eq 'tool') { $legend = $lt{'te'}; } else { $legend = $lt{'ee'}; } $legend = ''.$legend.''; if ($symb) { $hiddenelem = ''; } elsif ($supplementalflag) { $hiddenelem = ''."\n". ''; } } else { $link = ''.$lt{'ed'}.' '."\n"; $size = 40; $active = ''; } $formname = 'edit'.$type.'_'.$residx; $fieldsetid = 'upload'.$type.$residx; $urlid = $type.'url_'.$residx; map { $toolattr{$_} .= '_'.$residx; } (keys(%toolattr)); $srcclass = ' class="LC_nobreak"'; if ($type eq 'ext') { $extsrc = ''.$lt{'ul'}.' '; $preview = ' '.$lt{'pr'}.''; } $title = ''.$lt{'ti'}.' '; $save = $lt{'sv'}; } else { $link = $lt{'ex'}; if ($type eq 'tool') { $link = $lt{'et'}; } $link = ''.$link.''.$helpitem; if ($type eq 'tool') { $legend = $lt{'te'}; } else { $legend = $lt{'ee'}; } $legend = ''.$legend.''; $title = $lt{'ti'}.':
'; $residx = 0; if ($type eq 'ext') { $orig_url = 'http://'; $orig_title = $lt{'ex'}; $extsrc = $lt{'ul'}.':
'; $preview = ''; $save = $lt{'al'}; } else { $orig_title = $lt{'et'}; $save = $lt{'at'}; $orig_url = "/adm/$cdom/$cnum/new/ext\.tool"; } $pathitem .= '
'; } $formid = $formname; if ($type eq 'ext') { $urlelem = ''; } else { my $class = 'LC_nobreak'; if ($residx) { $class = 'LC_docs_ext_edit LC_nobreak'; if ($orig_url =~ m{^/adm/$cdom/$cnum/(\d+)/ext\.tool$}) { my $marker = $1; my %toolhash=&Apache::lonnet::dump('exttool_'.$marker,$cdom,$cnum); my ($tooltype,$tool,$ltihash); if ($toolhash{'id'} =~/^c(\d+)$/) { $tool = $1; $tooltype = 'crs'; if (ref($ltitools) eq 'HASH') { if (ref($ltitools->{'crs'}) eq 'HASH') { $ltihash = $ltitools->{'crs'}->{$tool}; } } } elsif ($toolhash{'id'} =~/^\d+$/) { $tooltype = 'dom'; $tool = $toolhash{'id'}; if (ref($ltitools) eq 'HASH') { if (ref($ltitools->{'dom'}) eq 'HASH') { $ltihash = $ltitools->{'dom'}->{$tool}; } } } if (($tool ne '') && (ref($ltihash) eq 'HASH')) { my $tooltitle = $ltihash->{'title'}; my $icon = $ltihash->{'image'}; my $image; if ($icon) { $image = ''.$tooltitle.''; } if ($ltihash->{'url'} =~ m{://}) { (my $prot,my $host,$providerurl) = ($ltihash->{'url'} =~ m{^([^/]+)://([^/]+)(|/.+)$}); } else { $providerurl = $ltihash->{'url'}; } $tooltarget = $toolhash{'target'}; if ($tooltarget eq 'window') { $dimendivstyle = 'display:block'; $windivstyle = 'display:block'; $chkstate{'window'} = 'checked="checked" '; } elsif ($tooltarget eq 'tab') { $windivstyle = 'display:block'; $chkstate{'tab'} = 'checked="checked" '; } else { $chkstate{'iframe'} = 'checked="checked" '; } $width = $toolhash{'width'}; $height = $toolhash{'height'}; $linktext = $toolhash{'linktext'}; $explanation = $toolhash{'explanation'}; if ($toolhash{'gradable'}) { $chkgrd = ' checked="checked"'; } else { $chknogrd = ' checked="checked"'; } if (ref($ltihash->{'crsconf'}) eq 'HASH') { if ($ltihash->{'crsconf'}->{'title'}) { $crstitle = $toolhash{'crstitle'}; $titlestyle = 'display:inline'; } if ($ltihash->{'crsconf'}->{'label'}) { $crslabel = $toolhash{'crslabel'}; $labelstyle = 'display:inline'; } if ($ltihash->{'crsconf'}->{'append'}) { $crsappend = $toolhash{'crsappend'}; $appendstyle = 'display:inline'; } if ($ltihash->{'crsconf'}->{'target'}) { $dispdivstyle = 'display:block'; } if ($ltihash->{'crsconf'}->{'linktext'}) { $linktextstyle = 'padding:0;display:inline'; } if ($ltihash->{'crsconf'}->{'explanation'}) { $explanationstyle = 'padding:0;display:inline'; } } $toolelem = ''.$image.' '.$tooltitle.'
'; $gradablestyle = 'display:inline'; } } } else { $subdivstyle = 'display:none'; my $toolradio = 'exttooltype'; my $exttypeon = 'LC_exttoolon'; my $exttypeoff = 'LC_exttooloff'; my $exttypeonsty = 'display:none'; my $exttypeoffsty = 'display:none'; my $exttypeofftext; if ($supplementalflag) { $toolradio = 'suppexttooltype'; $exttypeon = 'LC_exttoolonsupp'; $exttypeoff = 'LC_exttooloffsupp'; } my ($numcrstools,$numdomtools,$typeclick,%defcheck,%typedesc); %typedesc = ( crs => 'Defined in course', dom => 'Defined in domain', ); #FIXME need crstype my $seloptions; $subdivid = 'LC_addtool'; if ($supplementalflag) { $subdivid = 'LC_addtoolsupp'; } if (ref($ltitools) eq 'HASH') { if (ref($ltitools->{'crs'}) eq 'HASH') { $numcrstools = scalar(keys(%{$ltitools->{'crs'}})); } if (ref($ltitools->{'dom'}) eq 'HASH') { $numdomtools = scalar(keys(%{$ltitools->{'dom'}})); } if ($numcrstools || $numdomtools) { $typeclick = ' onclick="'. 'javascript:updateExttoolSel(this.form,'."'$toolradio','$supplementalflag'".');"'; } else { $exttypeoffsty = 'display:block'; $exttypeofftext = &mt('No external tools defined in either the domain or the course are available for selection.'); } if ($numcrstools && !$numdomtools) { $defcheck{'crs'} = ' checked="checked"'; $subdivstyle = 'display:block'; $exttypeonsty = 'display:block'; my $firstoption = ''; $seloptions = &ordered_tooloptions($ltitools->{'crs'}); if ($seloptions) { $seloptions = "$firstoption\n$seloptions"; } $exttypeofftext = &mt('No external tools defined in the domain are available for selection.'); } elsif (!$numcrstools && $numdomtools) { $defcheck{'dom'} = ' checked="checked"'; $subdivstyle = 'display:block'; $exttypeonsty = 'display:block'; my $firstoption = ''; $seloptions = &ordered_tooloptions($ltitools->{'dom'}); if ($seloptions) { $seloptions = "$firstoption\n$seloptions"; } #FIXME need crstype $exttypeofftext = &mt('No external tools defined in the course are available for selection.'); } } foreach my $type ('crs','dom') { $toolelem .= ' '."\n"; } $toolelem .= '
'. '
'."\n". '
'. $exttypeofftext. '
'."\n"; $crslabel = $env{'course.'.$cdom.'_'.$cnum.'.internal.coursecode'}; $crstitle = $env{'course.'.$cdom.'_'.$cnum.'.description'}; $crsappend = ''; $chknogrd = ' checked="checked"'; } $toolelem .= '
'. ''.&mt('Display target:').' '. ''.(' 'x2). ''.(' 'x2). ''. '
'. &mt('Width').': '.(' 'x2). &mt('Height').': '."\n". '
'; $toolelem .= '
'. '
'. ''.&mt('Link Text').'
'. '
'. ''.&mt('Explanation').'
'. '
'. '
'; $toolelem .= '
'. ''.&mt('Course label:').' '. '
'. '
'. '
'. ''.&mt('Course title:').' '. '
'. '
'. '
'. ''.&mt('Append to URL[_1]', ' ('.$providerurl.')
'). '

'. '
'. '
'. ''.&mt('Gradable').' '. ''.(' 'x2). '
'; } my $chooser = $toolelem; if ($type eq 'ext') { $chooser = "
$extsrc $urlelem $preview
"; } $form = <
$legend $active $chooser
$title $pathitem $hiddenelem
ENDFORM if (wantarray) { return ($link,$form); } else { return $link.$form; } } sub ordered_tooloptions { my ($toolsref) = @_; my ($seloptions,@ids,@titles); if (ref($toolsref) eq 'HASH') { my %bynum; foreach my $id (keys(%{$toolsref})) { if (ref($toolsref->{$id}) eq 'HASH') { my $order = $toolsref->{$id}->{'order'}; $bynum{$order} = [$id,$toolsref->{$id}]; } } foreach my $item (sort { $a <=> $b } keys(%bynum)) { if (ref($bynum{$item}) eq 'ARRAY') { if (ref($bynum{$item}->[1]) eq 'HASH') { my $tooltitle = $bynum{$item}->[1]->{'title'}; push(@titles,$tooltitle); push(@ids,$bynum{$item}->[0]); $seloptions .= ''."\n"; } } } } if (wantarray) { return (\@ids,\@titles); } else { return $seloptions; } } sub display_editor { my ($url,$folderpath,$symb,$idx,$type,$cdom,$cnum,$hostname) = @_; my ($residx,$supplementalflag,$title,$pathitem,$output,$js,$navmap); if ($folderpath =~ /^supplemental/) { $supplementalflag = 1; $residx = $idx; $title = &unescape($env{'form.title'}); $pathitem = ''; } elsif ($symb =~ /^uploaded/) { (my $map,$residx,my $res) = &Apache::lonnet::decode_symb($symb); $title = &Apache::lonnet::gettitle($symb); my $path = &Apache::loncommon::symb_to_docspath($symb,\$navmap); $pathitem = ''; } my (%ltitools,%tooltypes); if ($type eq 'tool') { my (%domtools,%crstools); %tooltypes = &Apache::loncommon::usable_exttools(); if ($tooltypes{'dom'}) { %domtools = &Apache::lonnet::get_domain_lti($cdom,'consumer'); } if ($tooltypes{'crs'}) { %crstools = &Apache::lonnet::get_course_lti($cnum,$cdom,'consumer'); } %ltitools = ( dom => \%domtools, crs => \%crstools, ); } $js = &Apache::lonhtmlcommon::scripttag(&extedit_javascript()); my $args = { 'force_register' => $env{'form.register'} }; if ($hostname) { $args->{'hostname'} = $hostname; } my $description = 'External Resource Editor'; if ($type eq 'tool') { $description = 'External Tool Editor'; } return &Apache::loncommon::start_page($description,$js,$args). '
'. &extedit_form($supplementalflag,$residx,$url,$title,$pathitem,undef,'direct', $symb,$type,$cdom,$cnum,\%ltitools). '
'. &Apache::loncommon::end_page(); } sub extedit_javascript { my ($toolsref) = @_; my ($toolsjs,$exttoolnums,$exttooloptions); if (ref($toolsref) eq 'HASH') { $toolsjs = " var ltitools = new Array();\n". " var ltitoolsUrl = new Array();\n". " var ltitoolsTarget = new Array();\n". " var ltitoolsWidth = new Array();\n". " var ltitoolsHeight = new Array();\n". " var ltitoolsLinkDef = new Array();\n". " var ltitoolsExplainDef = new Array();\n". " var ltitoolsDisplay = new Array();\n". " var ltitoolsLink = new Array();\n". " var ltitoolsExplain = new Array();\n". " var ltitoolsLabel = new Array();\n". " var ltitoolsTitle = new Array();\n". " var ltitoolsAppend = new Array();\n"; $exttoolnums = " var ltitoolsnum = new Array();\n". " var tooloptval = new Array();\n". " var toolopttxt = new Array();\n"; my $idx = 0; foreach my $type ('crs','dom') { if (ref($toolsref->{$type}) eq 'HASH') { my $num = scalar(keys(%{$toolsref->{$type}})); $toolsjs .= " ltitools[$idx] = new Array($num);\n". " ltitoolsUrl[$idx] = new Array($num);\n". " ltitoolsTarget[$idx] = new Array($num);\n". " ltitoolsWidth[$idx] = new Array($num);\n". " ltitoolsHeight[$idx] = new Array($num);\n". " ltitoolsLinkDef[$idx] = new Array($num);\n". " ltitoolsExplainDef[$idx] = new Array($num);\n". " ltitoolsDisplay[$idx] = new Array($num);\n". " ltitoolsLink[$idx] = new Array($num);\n". " ltitoolsExplain[$idx] = new Array($num);\n". " ltitoolsLabel[$idx] = new Array($num);\n". " ltitoolsTitle[$idx] = new Array($num);\n". " ltitoolsAppend[$idx] = new Array($num);\n"; my $i=0; foreach my $key (sort { $a <=> $b } keys(%{$toolsref->{$type}})) { if (ref($toolsref->{$type}->{$key}) eq 'HASH') { if (ref($toolsref->{$type}->{$key}->{'display'}) eq 'HASH') { my $target = $toolsref->{$type}->{$key}->{'display'}->{'target'}; my $width = $toolsref->{$type}->{$key}->{'display'}->{'width'}; my $height = $toolsref->{$type}->{$key}->{'display'}->{'height'}; my $linkdef = $toolsref->{$type}->{$key}->{'display'}->{'linktext'}; my $explaindef = $toolsref->{$type}->{$key}->{'display'}->{'explanation'}; my $providerurl; if ($toolsref->{$type}->{$key}->{'url'} =~ m{://}) { (my $prot,my $host,$providerurl) = ($toolsref->{$type}->{$key}->{'url'} =~ m{^([^/]+)://([^/]+)(|/.+)$}); } else { $providerurl = $toolsref->{$type}->{$key}->{'url'}; } $providerurl = &LONCAPA::map::qtunescape($providerurl); $toolsjs .= " ltitools[$idx][$i] = '$key';\n". " ltitoolsTarget[$idx][$i] = '$target';\n". " ltitoolsWidth[$idx][$i] = '$width';\n". " ltitoolsHeight[$idx][$i] = '$height';\n". " ltitoolsLinkDef[$idx][$i] = '$linkdef';\n". " ltitoolsExplainDef[$idx][$i] = '$explaindef';\n". " ltitoolsUrl[$idx][$i] = '$providerurl';\n"; } if (ref($toolsref->{$type}->{$key}->{'crsconf'}) eq 'HASH') { my $display = $toolsref->{$type}->{$key}->{'crsconf'}->{'target'}; $toolsjs .= " ltitoolsDisplay[$idx][$i] = '$display';\n"; my $linktext = $toolsref->{$type}->{$key}->{'crsconf'}->{'linktext'}; $toolsjs .= " ltitoolsLink[$idx][$i] = '$linktext';\n"; my $explanation = $toolsref->{$type}->{$key}->{'crsconf'}->{'explanation'}; $toolsjs .= " ltitoolsExplain[$idx][$i] = '$explanation';\n"; my $label = $toolsref->{$type}->{$key}->{'crsconf'}->{'label'}; $toolsjs .= " ltitoolsLabel[$idx][$i] = '$label';\n"; my $title = $toolsref->{$type}->{$key}->{'crsconf'}->{'title'}; $toolsjs .= " ltitoolsTitle[$idx][$i] = '$title';\n"; my $append = $toolsref->{$type}->{$key}->{'crsconf'}->{'append'}; $toolsjs .= " ltitoolsAppend[$idx][$i] = '$append';\n"; } } $i++; } my $firstoption = ''; my ($idsref,$titlesref) = &ordered_tooloptions($toolsref->{$type}); if ((ref($idsref) eq 'ARRAY') && (ref($titlesref) eq 'ARRAY')) { my $count = scalar(@{$idsref}); $exttooloptions .= " tooloptval[$idx] = new Array($count);\n". " toolopttxt[$idx] = new Array($count);\n"; for (my $n=0; $n<@{$idsref}; $n++) { my $id = $idsref->[$n]; my $text = $titlesref->[$n]; $exttooloptions .= " tooloptval[$idx][$n] = '$id';\n". " toolopttxt[$idx][$n] = '$text';\n"; } } $exttoolnums .= " ltitoolsnum[$idx] = $i;\n"; } $idx ++; } } my %js_lt = &Apache::lonlocal::texthash( invurl => 'Invalid URL', titbl => 'Title is blank', invtool => 'Please select an external tool', mixfra => 'Show preview in pop-up? (http in https page + no framing)', mixonly => 'Show preview in pop-up? (http in https page)', fraonly => 'Show preview in pop-up? (framing disallowed)', nopopup => 'Pop-up blocked', nopriv => 'Insufficient privileges to use preview', badurl => 'URL is not: http://hostname/path or https://hostname/path', sele => 'Select', ); &js_escape(\%js_lt); my $urlregexp = <<'ENDREGEXP'; /^([a-z]([a-z]|\d|\+|-|\.)*):(\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?((\[(|(v[\da-f]{1,}\.(([a-z]|\d|-|\.|_|~)|[!\$&'\(\)\*\+,;=]|:)+))\])|((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=])*)(:\d*)?)(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*|(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)|((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)|((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)){0})(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i ENDREGEXP return < 0) { eval("extform.importdetail.value=title+'='+url+'='+residx;extform.submit();"); } else { eval("extform.importdetail.value=title+'='+url;extform.submit();"); } } } else { title = escape(title); var info = exttoolurl; var prefix = ''; if (supplementalflag == 1) { prefix = 'supp'; } if (residx == 0) { var toolid = parseInt(extform.exttoolid.options[extform.exttoolid.selectedIndex].value); if (isNaN(toolid)) { alert("$js_lt{'invtool'}"); return; } var typeelem = extform.elements[prefix+'exttooltype']; if (typeelem.length) { for (var i=0; i 0) { dispdiv += '_'+residx; windiv += '_'+residx; } if (document.getElementById(dispdiv)) { if (document.getElementById(dispdiv).style.display == 'block') { if (extform.exttooltarget.length) { for (var i=0; i 0) { linktextdiv += '_'+residx; explanationdiv += '_'+residx; } if (document.getElementById(linktextdiv).style.display == 'inline') { var linktext = extform.exttoollinktext.value; linktext.trim(); info += ':'+escape(linktext); } else { info += ':'; } if (document.getElementById(explanationdiv).style.display == 'inline') { var explaintext = extform.exttoolexplanation.value; explaintext.trim(); info += ':'+escape(explaintext); } else { info += ':'; } } else { info += '::'; } } else { info += '::'; } var labelinput = prefix+'toolcrslabel'; var titleinput = prefix+'toolcrstitle'; var appendinput = prefix+'toolcrsappend'; if (residx > 0) { labelinput += '_'+residx; titleinput += '_'+residx; appendinput += '_'+residx; } if (document.getElementById(labelinput)) { var crslabel = document.getElementById(labelinput).value; crslabel.trim(); info += ':'+escape(crslabel); } else { info += ':'; } if (document.getElementById(titleinput)) { var crstitle = document.getElementById(titleinput).value; crstitle.trim(); info += ':'+escape(crstitle); } else { info += ':'; } if (document.getElementById(appendinput)) { var crsappend = document.getElementById(appendinput).value; crsappend.trim(); info += ':'+escape(crsappend); } else { info += ':'; } var gradablediv = prefix+'toolgradablediv'; if (residx > 0) { gradablediv += '_'+residx; } if (document.getElementById(gradablediv)) { if (document.getElementById(gradablediv).style.display == 'inline') { if (extform.exttoolgradable.length) { for (var i=0; i 0) { eval("extform.importdetail.value=title+'='+info+'='+residx;extform.submit();"); } else { eval("extform.importdetail.value=title+'='+info;extform.submit();"); } } } function editext(residx,type) { if (document.getElementById('upload'+type+residx)) { var curr = document.getElementById('upload'+type+residx).style.display; if (curr == 'none') { disp = 'block'; } else { disp = 'none'; } document.getElementById('upload'+type+residx).style.display=disp; } resize_scrollbox('contentscroll','1','1'); return; } function extUrlPreview(caller,protocol) { if (document.getElementById(caller)) { var url = document.getElementById(caller).value; if (regexp.test(url)) { var http_regex = /^http\:\/\//gi; var mixed = 0; var noiframe = 0; var nopriv = 0; var badurl = 0; var name = "externalpreview"; if ((protocol == 'https') && (http_regex.test(url))) { mixed = 1; } var http = new XMLHttpRequest(); var lcurl = "/adm/exturlcheck"; var params = "exturl="+url; http.open("POST",lcurl, true); http.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); http.onreadystatechange = function() { if (http.readyState == 4) { if (http.status == 200) { if (http.responseText.length > 0) { if (http.responseText == 1) { noiframe = 1; } else if (http.responseText == -1) { nopriv = 1; } else if (http.responseText == 0) { badurl = 1; } } openPreviewWindow(url,name,noiframe,mixed,nopriv,badurl); } } } http.send(params); } else { alert("$js_lt{'invurl'}"); } } } var previewLCWindow = null; function openPreviewWindow(url,name,noiframe,mixed,nopriv,badurl) { if (previewLCWindow !=null) { previewLCWindow.close(); } if (badurl) { alert("$js_lt{'badurl'}"); } else if (nopriv) { alert("$js_lt{'nopriv'}"); } else if ((noiframe == 1) || (mixed == 1)) { var encurl = encodeURI(url); var msg; if (mixed == 1) { if (noiframe == 1) { msg = "$js_lt{'mixfra'}"; } else { msg = "$js_lt{'mixonly'}"; } } else { msg = "$js_lt{'fraonly'}"; } if (confirm(msg)) { previewLCWindow = window.open(url,name,"height=400,width=500,scrollbars=1,resizable=1,menubar=0,location=1"); if (previewLCWindow != null) { previewLCWindow.focus(); } else { alert("$js_lt{'nopopup'}"); } } } else { openMyModal(url,500,400,'yes'); } } function updateExttoolSel(form,radioname,supplementalflag) { var prefix = ''; var typepick; var radelem = form.elements[radioname]; if (radelem.length) { for (var i=0; i=0) { for (i = numopts; i >= 0; i--) { selelem.remove(i); } } if (ltitoolsnum[typepick]) { if ((Array.isArray(tooloptval[typepick])) && (Array.isArray(toolopttxt[typepick]))) { var len = tooloptval[typepick].length; if (len) { selelem.options[selelem.options.length] = new Option('$js_lt{sele}','',1,1); var j; for (j=0; j 0) { for (var j=0; j'; } } } else { document.getElementById(appenddiv).style.display = 'none'; if (document.getElementById(providerurl)) { document.getElementById(providerurl).innerHTML = ''; } } } if (document.getElementById(gradablediv)) { if (supplementalflag != 1) { document.getElementById(gradablediv).style.display = 'inline'; } } break; } } } } } } } function updateTooldim(form,dimendiv,windiv,widthinput,heightinput,linkinput,explaininput) { if (form.exttooltarget.length) { for (var i=0; i