--- loncom/interface/lonextresedit.pm 2012/12/02 18:25:11 1.2 +++ loncom/interface/lonextresedit.pm 2023/07/12 00:05:02 1.34 @@ -1,7 +1,7 @@ # The LearningOnline Network # Documents # -# $Id: lonextresedit.pm,v 1.2 2012/12/02 18:25:11 raeburn Exp $ +# $Id: lonextresedit.pm,v 1.34 2023/07/12 00:05:02 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -56,87 +56,173 @@ sub handler { 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); - if ((($env{'form.folderpath'} =~ /^supplemental/) && ($env{'form.suppurl'})) || - ($env{'form.symb'} =~ /^uploaded/)) { - $supplementalflag = 1; - ($updated,$output,$errormsg,$residx,$url,$title,$symb) = + 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 $env{'form.suppurl'}) { + 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) { - $output = &Apache::lonhtmlcommon::confirm_success(&mt('External Resource 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 = ''; - $r->print(&Apache::loncommon::start_page('External Resource Editor',$js). + 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'}). + '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, - $oldtitle,$residx,$newurl,$newtitle); + 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,my $url)=&Apache::lonnet::decode_symb($symb); + (my $map,$oldidx,$oldurl)=&Apache::lonnet::decode_symb($symb); if ($map =~ m{^uploaded/$cdom/$cnum/(default(_\d+|))\.(sequence|page)$}) { $folder = $1; $container = $3; } - if ($url =~ m{^ext/(.+)$}) { - $oldurl = $1; - if ($oldurl !~ m{^https://}) { + $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'; } - $oldtitle = &Apache::lonnet::gettitle($env{'form.symb'}); } 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); - ($newtitle,$newurl, $residx) = - map {&unescape($_)} split(/\=/,$env{'form.importdetail'}); - if (!$supplementalflag && $oldidx) { - if ($oldidx != $residx) { - $mismatchedid = 1; - $residx = $oldidx; - } + my ($errtext,$fatal,$mismatchedid,$needreload,$newgradable,@imports); + if (!$supplementalflag) { + if (($oldidx) && ($oldidx != $newidx)) { + $mismatchedid = 1; + } } - my @imports; if ($mismatchedid) { $errormsg = 'Wrong item identifier'; } elsif (($newtitle eq $oldtitle) && ($newurl eq $oldurl)) { - $output = &mt('No change'); + 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); @@ -145,80 +231,218 @@ sub process_changes { } 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,'true','normal','res')); - my ($outtext,$errtext) = &LONCAPA::map::storemap($map,1); + 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,"ext/$newurl"); + $symb = &Apache::lonnet::encode_symb($map,$residx,$newurl); } else { $symb = $env{'form.symb'}; if ($symb) { &Apache::lonnet::devalidate_title_cache($symb); } } - } - my ($furl,$ferr) = &Apache::lonuserstate::readmap("$cdom/$cnum"); - if ($ferr) { - $errormsg = &mt('Reload failed: [_1].',$ferr); - } else { - &Apache::loncommon::update_content_constraints($cdom,$cnum,$chome, - $cdom.'_'.$cnum); + $needreload = 1; } } } } + if ($needreload) { + my ($furl,$ferr) = &Apache::lonuserstate::readmap("$cdom/$cnum"); + if ($ferr) { + $errormsg = &mt('Reload failed: [_1].',$ferr); + } else { + &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 { - $errormsg = &mt('Information about current external resource is incomplete.'); + if ($type eq 'tool') { + $errormsg = &mt('Information about current external tool is incomplete.'); + } else { + $errormsg = &mt('Information about current external resource is incomplete.'); + } } - if ($updated) { - return ($updated,$output,$errormsg,$residx,$newurl,$newtitle,$symb); - } else { - return ($updated,$output,$errormsg,$residx,$oldurl,$oldtitle,$symb); + 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) = @_; + 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 $formname = 'newext'; my $tabid = 'aa'; - my $toggle = 'ext'; - my $fieldsetid = 'uploadextform'; - my $urlid = 'exturl'; my $size = 60; if ($supplementalflag) { - $formname = 'newsuppext'; $tabid = 'ee'; - $toggle = 'suppext'; - $fieldsetid = 'uploadsuppextform'; - $urlid = 'suppexturl'; } - my ($link,$legend,$active,$srcclass,$extsrc,$preview,$title,$save, - $fieldsetstyle,$action,$hiddenelem); + 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 = 'external'.$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 = 'externalsupp'.$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'; - $legend = "$lt{'ee'}"; + $rows = 10; + $cols = 45; + if ($type eq 'tool') { + $legend = $lt{'te'}; + } else { + $legend = $lt{'ee'}; + } + $legend = ''.$legend.''; if ($symb) { $hiddenelem = ''; } elsif ($supplementalflag) { @@ -227,60 +451,333 @@ sub extedit_form { ''; } - } else { - $link = ''.$lt{'ed'}.''; + } else { + $link = ''.$lt{'ed'}.' '."\n"; $size = 40; - $active = ''; + $active = ''; } - $formname = "editext_$residx"; - $fieldsetid = "uploadext$residx"; - $urlid = "exturl_$residx"; + $formname = 'edit'.$type.'_'.$residx; + $fieldsetid = 'external'.$type.$residx; + $urlid = $type.'url_'.$residx; + map { $toolattr{$_} .= '_'.$residx; } (keys(%toolattr)); $srcclass = ' class="LC_nobreak"'; - $extsrc = ''.$lt{'ul'}.' '; - $preview = ' '.$lt{'pr'}.''; + if ($type eq 'ext') { + $extsrc = ''.$lt{'ul'}.' '; + $preview = ' '.$lt{'pr'}.''; + } $title = ''.$lt{'ti'}.' '; $save = $lt{'sv'}; } else { - $link = ''.$lt{'ex'}.''.$helpitem; - $legend = "$lt{'ex'}"; - $extsrc = $lt{'ul'}.':
'; + $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; - $orig_url = 'http://'; - $orig_title = $lt{'ex'}; - $preview = ''; - $save = $lt{'al'}; + 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 .= '
'; } - return < -
-$legend -$active + $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 - -
+ +
+"; + } + my $idattr; + unless ($subdivid eq '') { + $idattr = 'id="'.$subdivid.'"'; + } + $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) = @_; - my ($residx,$supplementalflag,$title,$pathitem,$output); + my ($url,$folderpath,$symb,$idx,$type,$cdom,$cnum,$hostname) = @_; + my ($residx,$supplementalflag,$title,$pathitem,$output,$js,$navmap); if ($folderpath =~ /^supplemental/) { $supplementalflag = 1; $residx = $idx; @@ -290,27 +787,151 @@ sub display_editor { (my $map,$residx,my $res) = &Apache::lonnet::decode_symb($symb); $title = &Apache::lonnet::gettitle($symb); - my $path = &Apache::lonnet::getdocspath($symb); - if ($map =~ /\.page$/) { - $pathitem = ''; - } else { - $pathitem = ''; + 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, + ); } - my $js = &Apache::lonhtmlcommon::scripttag(&extedit_javascript()); + $js = &Apache::lonhtmlcommon::scripttag(&extedit_javascript()); my $args = { 'force_register' => $env{'form.register'} }; - return &Apache::loncommon::start_page('External Resource Editor',$js,$args). + 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). + &extedit_form($supplementalflag,$residx,$url,$title,$pathitem,undef,'direct', + $symb,$type,$cdom,$cnum,\%ltitools). '
'. &Apache::loncommon::end_page(); } sub extedit_javascript { - my %lt = &Apache::lonlocal::texthash( + 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 @@ -320,51 +941,554 @@ ENDREGEXP var regexp = $urlregexp; -function setExternal(extform,residx) { +function setExternal(extform,residx,type,exttoolurl,supplementalflag) { var title=extform.exttitle.value; if (!String.trim) { String.prototype.trim = function() {return this.replace(\/^\\s+|\\s+$\/g, "");}; } - var url=extform.exturl.value; if (title == null || title.trim()=="") { - alert("$lt{'titbl'}"); + alert("$js_lt{'titbl'}"); extform.exttitle.focus(); return; } - if (regexp.test(url)) { - url = escape(url); - if (residx > 0) { - eval("extform.importdetail.value=title+'='+url+'='+residx;extform.submit();"); + if (type == 'ext') { + var url=extform.exturl.value; + if (!regexp.test(url)) { + alert("$js_lt{'invurl'}"); + extform.exturl.focus(); + return; } else { - eval("extform.importdetail.value=title+'='+url;extform.submit();"); + url = escape(url); + title = escape(title); + if (residx > 0) { + eval("extform.importdetail.value=title+'='+url+'='+residx;extform.submit();"); + } else { + eval("extform.importdetail.value=title+'='+url;extform.submit();"); + } } } else { - alert("$lt{'invurl'}"); - extform.exturl.focus(); - return; + 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) { - if (document.getElementById('uploadext'+residx)) { - var curr = document.getElementById('uploadext'+residx).style.display; +function editext(residx,type) { + if (document.getElementById('external'+type+residx)) { + var curr = document.getElementById('external'+type+residx).style.display; if (curr == 'none') { disp = 'block'; } else { disp = 'none'; } - document.getElementById('uploadext'+residx).style.display=disp; + document.getElementById('external'+type+residx).style.display=disp; } resize_scrollbox('contentscroll','1','1'); return; } -function extUrlPreview(caller) { +function extUrlPreview(caller,protocol) { if (document.getElementById(caller)) { var url = document.getElementById(caller).value; if (regexp.test(url)) { - openMyModal(url,500,400,'yes'); + 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 { - alert("$lt{'invurl'}"); + 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