--- loncom/interface/loncommon.pm 2007/08/02 01:07:00 1.558 +++ loncom/interface/loncommon.pm 2007/08/26 21:09:43 1.570 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # a pile of common routines # -# $Id: loncommon.pm,v 1.558 2007/08/02 01:07:00 albertel Exp $ +# $Id: loncommon.pm,v 1.570 2007/08/26 21:09:43 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -1084,6 +1084,63 @@ sub changable_area { =pod +=item * resize_textarea_js + +emits the needed javascript to resize a textarea to be as big as possible + +creates a function resize_textrea that takes two IDs first should be +the id of the element to resize, second should be the id of a div that +surrounds everything that comes after the textarea, this routine needs +to be attached to the <body> for the onload and onresize events. + + +=cut + +sub resize_textarea_js { + return <<"RESIZE"; + <script type="text/javascript"> +var Geometry = {}; +function init_geometry() { + if (Geometry.init) { return }; + Geometry.init=1; + if (window.innerHeight) { + Geometry.getViewportHeight = function() { return window.innerHeight; }; + } + else if (document.documentElement && document.documentElement.clientHeight) { + Geometry.getViewportHeight = + function() { return document.documentElement.clientHeight; }; + } + else if (document.body.clientHeight) { + Geometry.getViewportHeight = + function() { return document.body.clientHeight; }; + } +} + +function resize_textarea(textarea_id,bottom_id) { + init_geometry(); + var textarea = document.getElementById(textarea_id); + //alert(textarea); + + var textarea_top = textarea.offsetTop; + var textarea_height = textarea.offsetHeight; + var bottom = document.getElementById(bottom_id); + var bottom_top = bottom.offsetTop; + var bottom_height = bottom.offsetHeight; + var window_height = Geometry.getViewportHeight(); + var fudge = 23; + var new_height = window_height-fudge-textarea_top-bottom_height; + if (new_height < 300) { + new_height = 300; + } + textarea.style.height=new_height+'px'; +} +</script> +RESIZE + +} + +=pod + =back =head1 Excel and CSV file utility routines @@ -1424,7 +1481,7 @@ sub select_level_form { =pod -=item * select_dom_form($defdom,$name,$includeempty) +=item * select_dom_form($defdom,$name,$includeempty,$showdomdesc) Returns a string containing a <select name='$name' size='1'> form to allow a user to select the domain to preform an operation in. @@ -1433,18 +1490,28 @@ See loncreateuser.pm for an example invo If the $includeempty flag is set, it also includes an empty choice ("no domain selected"); +If the $showdomdesc flag is set, the domain name is followed by the domain description. + =cut #------------------------------------------- sub select_dom_form { - my ($defdom,$name,$includeempty) = @_; + my ($defdom,$name,$includeempty,$showdomdesc) = @_; my @domains = sort {lc($a) cmp lc($b)} (&Apache::lonnet::all_domains()); if ($includeempty) { @domains=('',@domains); } my $selectdomain = "<select name=\"$name\" size=\"1\">\n"; foreach my $dom (@domains) { $selectdomain.="<option value=\"$dom\" ". - ($dom eq $defdom ? 'selected="selected" ' : ''). - ">$dom</option>\n"; + ($dom eq $defdom ? 'selected="selected" ' : '').'>'.$dom; + if ($showdomdesc) { + if ($dom ne '') { + my $domdesc = &Apache::lonnet::domain($dom,'description'); + if ($domdesc ne '') { + $selectdomain .= ' ('.$domdesc.')'; + } + } + } + $selectdomain .= "</option>\n"; } $selectdomain.="</select>"; return $selectdomain; @@ -3397,6 +3464,9 @@ Inputs: =item * $args, optional argument valid values are no_auto_mt_title -> prevents &mt()ing the title arg + inherit_jsmath -> when creating popup window in a page, + should it have jsmath forced on by the + current page =back @@ -3453,7 +3523,7 @@ sub bodytag { # construct main body tag my $bodytag = "<body $extra_body_attr>". - &Apache::lontexconvert::init_math_support(); + &Apache::lontexconvert::init_math_support($args->{'inherit_jsmath'}); if ($bodyonly) { return $bodytag; @@ -4711,6 +4781,10 @@ Inputs: $title - optional title for the no_auto_mt_title -> prevent &mt()ing the title arg + inherit_jsmath -> when creating popup window in a page, + should it have jsmath forced on by the + current page + =cut sub start_page { @@ -5535,7 +5609,7 @@ sub get_secgrprole_info { } sub user_picker { - my ($dom,$srch,$forcenewuser) = @_; + my ($dom,$srch,$forcenewuser,$caller) = @_; my $currdom = $dom; my %curr_selected = ( srchin => 'dom', @@ -5557,12 +5631,8 @@ sub user_picker { } $srchterm = $srch->{'srchterm'}; } - use Data::Dumper; - &Apache::lonnet::logthis(&Dumper($srch)); my %lt=&Apache::lonlocal::texthash( - 'usr' => 'Search for', - 'or' => 'or', - 'doma' => 'domain', + 'doma' => 'Domain/institution to search', 'uname' => 'username', 'lastname' => 'last name', 'lastfirst' => 'last name, first name', @@ -5572,10 +5642,10 @@ sub user_picker { 'instd' => 'in institutional directory', 'exact' => 'is', 'contains' => 'contains', + 'begins' => 'begins with', ); - my $domform = &select_dom_form($currdom,'srchdomain',1); - - my $srchin; + my $domform = &select_dom_form($currdom,'srchdomain',1,1); + my $srchinsel = ' <select name="srchin">'; my @srchins = ('crs','dom','alc','instd'); @@ -5585,18 +5655,15 @@ sub user_picker { # has been completed. next if ($option eq 'alc'); next if ($option eq 'crs' && !$env{'request.course.id'}); - my $checked =($curr_selected{'srchin'} eq $option) ?'checked="checked"' - :''; - my $extra = ($option eq 'dom') ? $domform - : ''; - $srchin.=<<ROW - <tr> - <td> - <label><input type="radio" name="srchin" value="$option" $checked /> $lt{$option}</label> $extra - </td> -</tr> -ROW + if ($curr_selected{'srchin'} eq $option) { + $srchinsel .= ' + <option value="'.$option.'" selected="selected">'.$lt{$option}.'</option>'; + } else { + $srchinsel .= ' + <option value="'.$option.'">'.$lt{$option}.'</option>'; + } } + $srchinsel .= "\n </select>\n"; my $srchbysel = ' <select name="srchby">'; foreach my $option ('uname','lastname','lastfirst') { @@ -5611,7 +5678,7 @@ ROW $srchbysel .= "\n </select>\n"; my $srchtypesel = ' <select name="srchtype">'; - foreach my $option ('exact','contains') { + foreach my $option ('exact','begins','contains') { if ($curr_selected{'srchtype'} eq $option) { $srchtypesel .= ' <option value="'.$option.'" selected="selected">'.$lt{$option}.'</option>'; @@ -5625,29 +5692,29 @@ ROW my ($newuserscript,$new_user_create); if ($forcenewuser) { - $new_user_create = '<p> <input type="submit" name="forcenew" value="'.&HTML::Entities::encode(&mt('Make new user "[_1]"',$srchterm),'<>&"').'" onclick="javascript:setSearch(\'1\');" /> </p>'; + $new_user_create = '<p> <input type="submit" name="forcenew" value="'.&HTML::Entities::encode(&mt('Make new user "[_1]"',$srchterm),'<>&"').'" onclick="javascript:setSearch(\'1\','.$caller.');" /> </p>'; $newuserscript = <<"ENDSCRIPT"; -function setSearch(createnew) { +function setSearch(createnew,callingForm) { if (createnew == 1) { - for (var i=0; i<document.crtuser.srchby.length; i++) { - if (document.crtuser.srchby.options[i].value == 'uname') { - document.crtuser.srchby.selectedIndex = i; + for (var i=0; i<callingForm.srchby.length; i++) { + if (callingForm.srchby.options[i].value == 'uname') { + callingForm.srchby.selectedIndex = i; } } - for (var i=0; i<document.crtuser.srchin.length; i++) { - if ( document.crtuser.srchin[i].value == 'dom') { - document.crtuser.srchin[i].checked = 1; + for (var i=0; i<callingForm.srchin.length; i++) { + if ( callingForm.srchin.options[i].value == 'dom') { + callingForm.srchin.selectedIndex = i; } } - for (var i=0; i<document.crtuser.srchtype.length; i++) { - if (document.crtuser.srchtype.options[i].value == 'exact') { - document.crtuser.srchtype.selectedIndex = i; + for (var i=0; i<callingForm.srchtype.length; i++) { + if (callingForm.srchtype.options[i].value == 'exact') { + callingForm.srchtype.selectedIndex = i; } } - for (var i=0; i<document.crtuser.srchdomain.length; i++) { - if (document.crtuser.srchdomain.options[i].value == '$env{'request.role.domain'}') { - document.crtuser.srchdomain.selectedIndex = i; + for (var i=0; i<callingForm.srchdomain.length; i++) { + if (callingForm.srchdomain.options[i].value == '$env{'request.role.domain'}') { + callingForm.srchdomain.selectedIndex = i; } } } @@ -5658,20 +5725,21 @@ ENDSCRIPT my $output = <<"END_BLOCK"; <script type="text/javascript"> -function validateEntry() { +function validateEntry(callingForm) { var checkok = 1; var srchin; - for (var i=0; i<document.crtuser.srchin.length; i++) { - if ( document.crtuser.srchin[i].checked ) { - srchin = document.crtuser.srchin[i].value; + for (var i=0; i<callingForm.srchin.length; i++) { + if ( callingForm.srchin[i].checked ) { + srchin = callingForm.srchin[i].value; } } - var srchtype = document.crtuser.srchtype.options[document.crtuser.srchtype.selectedIndex].value; - var srchby = document.crtuser.srchby.options[document.crtuser.srchby.selectedIndex].value; - var srchdomain = document.crtuser.srchdomain.options[document.crtuser.srchdomain.selectedIndex].value; - var srchterm = document.crtuser.srchterm.value; + var srchtype = callingForm.srchtype.options[callingForm.srchtype.selectedIndex].value; + var srchby = callingForm.srchby.options[callingForm.srchby.selectedIndex].value; + var srchdomain = callingForm.srchdomain.options[callingForm.srchdomain.selectedIndex].value; + var srchterm = callingForm.srchterm.value; + var srchin = callingForm.srchin.options[callingForm.srchin.selectedIndex].value; var msg = ""; if (srchterm == "") { @@ -5679,10 +5747,17 @@ function validateEntry() { msg += "You must include some text to search for.\\n"; } + if (srchtype== 'begins') { + if (srchterm.length < 2) { + checkok = 0; + msg += "The text you are searching for must contain at least two characters when using a 'begins' type search.\\n"; + } + } + if (srchtype== 'contains') { if (srchterm.length < 3) { checkok = 0; - msg += "The text you are searching for must contain at least three characters when using a 'contained in' type search.\\n"; + msg += "The text you are searching for must contain at least three characters when using a 'contains' type search.\\n"; } } if (srchin == 'instd') { @@ -5712,7 +5787,7 @@ function validateEntry() { return; } if (checkok == 1) { - document.crtuser.submit(); + callingForm.submit(); } } @@ -5724,12 +5799,16 @@ $new_user_create <table> <tr> - <td> $srchbysel - $srchtypesel - <input type="text" size="15" name="srchterm" value="$srchterm" /> + <td>$srchbysel + $srchtypesel + <input type="text" size="15" name="srchterm" value="$srchterm" /> + $srchinsel + </td> + </tr> + <tr> + <td>$lt{'doma'}: $domform</td> </td> </tr> -$srchin </table> <br /> END_BLOCK @@ -5996,28 +6075,50 @@ sub record_sep { $i++; } } else { - my @allfields; + my $separator=','; if ($env{'form.upfiletype'} eq 'semisv') { - @allfields=split(/;/,$record,-1); - } else { - @allfields=split(/\,/,$record,-1); + $separator=';'; } my $i=0; - my $j; - for ($j=0;$j<=$#allfields;$j++) { - my $field=$allfields[$j]; - if ($field=~/^\s*(\"|\')/) { - my $delimiter=$1; - while (($field!~/$delimiter$/) && ($j<$#allfields)) { - $j++; - $field.=','.$allfields[$j]; - } - $field=~s/^\s*$delimiter//; - $field=~s/$delimiter\s*$//; - } - $components{&takeleft($i)}=$field; - $i++; +# the character we are looking for to indicate the end of a quote or a record + my $looking_for=$separator; +# do not add the characters to the fields + my $ignore=0; +# we just encountered a separator (or the beginning of the record) + my $just_found_separator=1; +# store the field we are working on here + my $field=''; +# work our way through all characters in record + foreach my $character ($record=~/(.)/g) { + if ($character eq $looking_for) { + if ($character ne $separator) { +# Found the end of a quote, again looking for separator + $looking_for=$separator; + $ignore=1; + } else { +# Found a separator, store away what we got + $components{&takeleft($i)}=$field; + $i++; + $just_found_separator=1; + $ignore=0; + $field=''; + } + next; + } +# single or double quotation marks after a separator indicate beginning of a quote +# we are now looking for the end of the quote and need to ignore separators + if ((($character eq '"') || ($character eq "'")) && ($just_found_separator)) { + $looking_for=$character; + next; + } +# ignore would be true after we reached the end of a quote + if ($ignore) { next; } + if (($just_found_separator) && ($character=~/\s/)) { next; } + $field.=$character; + $just_found_separator=0; } +# catch the very last entry, since we never encountered the separator + $components{&takeleft($i)}=$field; } return %components; } @@ -6876,6 +6977,40 @@ sub commit_studentrole { ############################################################ ############################################################ +sub check_clone { + my ($args) = @_; + my $cloneid='/'.$args->{'clonedomain'}.'/'.$args->{'clonecourse'}; + my ($clonecrsudom,$clonecrsunum)= &LONCAPA::split_courseid($cloneid); + my $clonehome=&Apache::lonnet::homeserver($clonecrsunum,$clonecrsudom); + my $clonemsg; + my $can_clone = 0; + + if ($clonehome eq 'no_host') { + $clonemsg = &mt('Attempting to clone non-existing [_1]', + $args->{'crstype'}); + } else { + my %clonedesc = &Apache::lonnet::coursedescription($cloneid,{'one_time' => 1}); + if ($env{'request.role.domain'} eq $args->{'clonedomain'}) { + $can_clone = 1; + } else { + my %clonehash = &Apache::lonnet::get('environment',['cloners'], + $args->{'clonedomain'},$args->{'clonecourse'}); + my @cloners = split(/,/,$clonehash{'cloners'}); + my %roleshash = + &Apache::lonnet::get_my_roles($args->{'ccuname'}, + $args->{'ccdomain'},'userroles',['active'],['cc'], + [$args->{'clonedomain'}]); + if (($roleshash{$args->{'clonecourse'}.':'.$args->{'clonedomain'}.':cc'}) || (grep(/^\Q$args->{'ccuname'}\E:\Q$args->{'ccdomain'}\E$/,@cloners))) { + $can_clone = 1; + } else { + $clonemsg = &mt('The new course was not cloned from an existing course because the new course owner ([_1]) does not have cloning rights in the existing course ([_2]).',$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'}); + } + } + } + + return ($can_clone, $clonemsg, $cloneid, $clonehome); +} + sub construct_course { my ($args,$logmsg,$courseid,$crsudom,$crsunum,$udom,$uname,$context) = @_; my $outcome; @@ -6883,6 +7018,23 @@ sub construct_course { if ($context eq 'auto') { $linefeed = "\n"; } + +# +# Are we cloning? +# + my ($can_clone, $clonemsg, $cloneid, $clonehome); + if (($args->{'clonecourse'}) && ($args->{'clonedomain'})) { + ($can_clone, $clonemsg, $cloneid, $clonehome) = &check_clone($args); + if ($context ne 'auto') { + $clonemsg = '<span class="LC_error">'.$clonemsg.'</span>'; + } + $outcome .= $clonemsg.$linefeed; + + if (!$can_clone) { + return (0,$outcome); + } + } + # # Open course # @@ -6903,81 +7055,39 @@ sub construct_course { # if anyone ever decides to not show this, and Utils::Course::new # will need to be suitably modified. $outcome .= &mt('New LON-CAPA [_1] ID: [_2]',$crstype,$$courseid).$linefeed; - # # Check if created correctly # ($$crsudom,$$crsunum)= &LONCAPA::split_courseid($$courseid); my $crsuhome=&Apache::lonnet::homeserver($$crsunum,$$crsudom); $outcome .= &mt('Created on').': '.$crsuhome.$linefeed; + # -# Are we cloning? -# - my $cloneid=''; - if (($args->{'clonecourse'}) && ($args->{'clonedomain'})) { - my $can_clone = 0; - $cloneid='/'.$args->{'clonedomain'}.'/'.$args->{'clonecourse'}; - my ($clonecrsudom,$clonecrsunum)= &LONCAPA::split_courseid($cloneid); - my $clonehome=&Apache::lonnet::homeserver($clonecrsunum,$clonecrsudom); - my $clonemsg; - if ($clonehome eq 'no_host') { - $clonemsg = &mt('Attempting to clone non-existing [_1]',$crstype); - if ($context eq 'auto') { - $outcome .= $clonemsg; - } else { - $outcome .= '<font color="red">'.$clonemsg.'</font>'; - } - $outcome .= $linefeed; - } else { - my %clonedesc = &Apache::lonnet::coursedescription($cloneid,{'one_time' => 1}); - if ($env{'request.role.domain'} eq $args->{'form.clonedomain'}) { - $can_clone = 1; - } else { - my %clonehash = &Apache::lonnet::get('environment',['cloners'], - $args->{'clonedomain'},$args->{'clonecourse'}); - my @cloners = split(/,/,$clonehash{'cloners'}); - my %roleshash = - &Apache::lonnet::get_my_roles($args->{'ccuname'}, - $args->{'ccdomain'},'userroles',['active'],['cc'], - [$args->{'clonedomain'}]); - if (($roleshash{$args->{'clonecourse'}.':'.$args->{'clonedomain'}.':cc'}) || (grep(/^\Q$args->{'ccuname'}\E:\Q$args->{'ccdomain'}\E$/,@cloners))) { - $can_clone = 1; - } else { - $clonemsg = &mt('The new course was not cloned from an existing course because the course owner ([_1]) does not have cloning rights in the existing course ([_2]).',$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'}); - if ($context eq 'auto') { - $outcome .= $clonemsg; - } else { - $outcome .= '<font color="red">'.$clonemsg.'</font>'; - } - $outcome .= $linefeed; - } - } - } - if ($can_clone) { - $clonemsg = &mt('Cloning [_1] from [_2]',$crstype,$clonehome); - if ($context eq 'auto') { - $outcome = $clonemsg; - } else { - $outcome .= '<font color="green">'.$clonemsg.'</font>'; - } - $outcome .= $linefeed; - my %oldcenv=&Apache::lonnet::dump('environment',$$crsudom,$$crsunum); +# Do the cloning +# + if ($can_clone && $cloneid) { + $clonemsg = &mt('Cloning [_1] from [_2]',$crstype,$clonehome); + if ($context ne 'auto') { + $clonemsg = '<span class="LC_success">'.$clonemsg.'</span>'; + } + $outcome .= $clonemsg.$linefeed; + my %oldcenv=&Apache::lonnet::dump('environment',$$crsudom,$$crsunum); # Copy all files - &Apache::lonclonecourse::copycoursefiles($cloneid,$$courseid); + &Apache::lonclonecourse::copycoursefiles($cloneid,$$courseid); # Restore URL - $cenv{'url'}=$oldcenv{'url'}; + $cenv{'url'}=$oldcenv{'url'}; # Restore title - $cenv{'description'}=$oldcenv{'description'}; + $cenv{'description'}=$oldcenv{'description'}; # restore grading mode - if (defined($oldcenv{'grading'})) { - $cenv{'grading'}=$oldcenv{'grading'}; - } -# Mark as cloned - $cenv{'clonedfrom'}=$cloneid; - delete($cenv{'default_enrollment_start_date'}); - delete($cenv{'default_enrollment_end_date'}); + if (defined($oldcenv{'grading'})) { + $cenv{'grading'}=$oldcenv{'grading'}; } +# Mark as cloned + $cenv{'clonedfrom'}=$cloneid; + delete($cenv{'default_enrollment_start_date'}); + delete($cenv{'default_enrollment_end_date'}); } + # # Set environment (will override cloned, if existing) # @@ -7085,7 +7195,7 @@ sub construct_course { ' ('.$lt{'adby'}.')'; if ($context eq 'auto') { $outcome .= $badclass_msg.$linefeed; - $outcome .= '<font color="red">'.$badclass_msg.$linefeed.'<ul>'."\n"; + $outcome .= '<div class="LC_warning">'.$badclass_msg.$linefeed.'<ul>'."\n"; foreach my $item (@badclasses) { if ($context eq 'auto') { $outcome .= " - $item\n"; @@ -7096,7 +7206,7 @@ sub construct_course { if ($context eq 'auto') { $outcome .= $linefeed; } else { - $outcome .= "</ul><br /><br /></font>\n"; + $outcome .= "</ul><br /><br /></div>\n"; } } } @@ -7118,7 +7228,7 @@ sub construct_course { if ($context eq 'auto') { $outcome .= $krb_msg; } else { - $outcome .= '<font color="red" size="+1">'.$krb_msg.'</font>'; + $outcome .= '<span class="LC_error">'.$krb_msg.'</span>'; } $outcome .= $linefeed; } @@ -7216,7 +7326,8 @@ sub construct_course { if ($errtext) { $fatal=2; } $outcome .= ($fatal?$errtext:'write ok').$linefeed; } - return $outcome; + + return (1,$outcome); } ############################################################