--- loncom/interface/loncommon.pm 2010/01/06 18:17:30 1.925.2.6 +++ loncom/interface/loncommon.pm 2010/10/04 22:30:42 1.925.2.15 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # a pile of common routines # -# $Id: loncommon.pm,v 1.925.2.6 2010/01/06 18:17:30 raeburn Exp $ +# $Id: loncommon.pm,v 1.925.2.15 2010/10/04 22:30:42 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -1978,7 +1978,16 @@ sub select_dom_form { ($dom eq $defdom ? 'selected="selected" ' : '').'>'.$dom; if ($showdomdesc) { if ($dom ne '') { - my $domdesc = &Apache::lonnet::domain($dom,'description'); + my $domdesc; + if ($name eq 'srchdomain') { + if ($dom eq 'gci') { + $domdesc = 'Faculty'; + } else { + $domdesc = 'Students'; + } + } else { + $domdesc = &Apache::lonnet::domain($dom,'description'); + } if ($domdesc ne '') { $selectdomain .= ' ('.$domdesc.')'; } @@ -2469,9 +2478,11 @@ sub authform_internal{ } $autharg = ''; - $result = &mt - ('[_1] Internally authenticated (with initial password [_2])', - ''.$autharg); + my $authtext = '[_1] Internally authenticated (with initial password [_2])'; + if ($in{'caller'} eq 'requestcrs') { + $authtext = "[_1] Students' password, if none in the uploaded file: [_2]"; + } + $result = &mt($authtext,''.$autharg); $result.="'; return $result; } @@ -4548,8 +4559,7 @@ sub bodytag { my $role_selector; if (($custommenu) && ($env{'request.course.id'}) && - ($env{'course.'.$env{'request.course.id'}.'.domain'} eq 'gcitest') && - ($env{'request.role'} !~ m{^st\./gcitest/$match_courseid})) { + ($env{'course.'.$env{'request.course.id'}.'.domain'} eq 'gcitest')) { $role_selector = &Apache::lonmenu::roles_selector( $env{'course.' . $env{'request.course.id'} . '.domain'}, $env{'course.' . $env{'request.course.id'} . '.num'} ); @@ -4557,6 +4567,56 @@ sub bodytag { $role_selector = '
'.$role_selector; } } + my $cid = $env{'request.course.id'}; + my %gcicourses = ( + gci_9615072b469884921gcil1 => 'review', + gci_1H96711d710194bfegcil1 => 'submit', + gci_5422913620b814c90gcil1 => 'tutorial', + ); + if (($custommenu && $cid && !$gcicourses{$cid}) || ($env{'user.domain'} eq 'gcitest')) { + my $role = 'st'; + if ($custommenu) { + $role = 'cc'; + } + my ($switcher_js,$switcher,$formname); + $formname = 'pickrole'; + my %courses = &existing_gcitest_courses($role); + my $numcourses = keys(%courses); + my $reqdcount = 0; + if ($cid) { + if ($courses{$cid}) { + $reqdcount = 1; + } + } + if ($numcourses > $reqdcount) { + $switcher = &gcitest_switcher($role,$formname,%courses); + my $current; + if ($cid) { + $current = $role.'./'.$env{'course.'.$cid.'.domain'}. + '/'.$env{'course.'.$cid.'.num'}; + } + $switcher_js = &Apache::loncommon::gcitest_switcher_js($current,$numcourses,$formname); + if ($switcher_js) { + $switcher_js= <<"ENDSCRIPT"; + +ENDSCRIPT + } + } + if ($switcher) { + $switcher = $switcher_js.$switcher; + if ($role_selector) { + $role_selector .= '   '.$switcher; + } else { + $role_selector .= '
'.$switcher; + } + } + } if ($env{'request.noversionuri'} =~ m{^/res/adm/pages/}) { if ($dc_info) { @@ -4567,6 +4627,9 @@ sub bodytag { return $bodytag; } + if ($cid && $gcicourses{$cid} eq 'tutorial') { + $bodytag .= '
'; + } $bodytag .= qq|
$name $role $role_selector
|; $bodytag .= Apache::lonhtmlcommon::scripttag( @@ -4578,6 +4641,9 @@ sub bodytag { $dc_info = &dc_courseid_toggle($dc_info); } $bodytag .= qq|
$realm $dc_info
|; + if ($cid && $gcicourses{$cid} eq 'tutorial') { + $bodytag .= '
'; + } #don't show menus for public users if($env{'user.name'} ne 'public' && $env{'user.domain'} ne 'public'){ @@ -4594,6 +4660,17 @@ sub bodytag { $args->{'bread_crumbs'}); } elsif ($forcereg) { $bodytag .= &Apache::lonmenu::innerregister($forcereg); + } elsif ($custommenu && $env{'request.course.id'} && + &Apache::lonnet::allowed('mdc', $env{'request.course.id'})) { + if ($env{'request.noversionuri'} eq '/adm/navmaps') { + my @advtools = &concept_test_manager(); + &Apache::lonhtmlcommon::add_breadcrumb_tool( + 'advtools',@advtools); + my $advlinks; + my $legendtext = ''.&mt('Management').''; + &Apache::lonhtmlcommon::render_advtools(\$advlinks,$legendtext); + $bodytag .= $advlinks; + } } }else{ # this is to seperate menu from content when there's no secondary @@ -4602,8 +4679,6 @@ sub bodytag { $bodytag .= Apache::lonhtmlcommon::scripttag('', 'end'); } - #SD testing - #$bodytag .= Apache::lonmenu::menubuttons($forcereg); return $bodytag; } @@ -4641,6 +4716,52 @@ $bodytag ENDBODY } +sub concept_test_manager { + my @advtools; + my %items = ( + docs => { + desc => 'Edit Test', + action => "go('/adm/coursedocs')", + tooltip => 'Assemble or modify Concept Test' + }, + cprv => { + desc => 'Enrollment/Activity', + action => "go('/adm/createuser')", + tooltip => 'Enrollment and student activity', + }, + new => { + desc => "What's New?", + action => "go('/adm/whatsnew')", + tooltip => 'Recent events/action items in Concept Test' , + }, + prnt => { + desc => 'Print Test', + action => "go('/adm/printout');", + tooltip => 'Prepare printable Concept Test', + }, + chrt => { + desc => 'Test Statistics', + action => "go('/adm/statistics');", + tooltip => 'Concept Test Statistics', + }, + rcrs => { + desc => 'Create New Test', + action => "switchpage('createtest');", + tooltip => 'Create new Concept Test', + }, + ); + my @ordered = ('docs','cprv','new','prnt','chrt','rcrs'); + foreach my $item (@ordered) { + push(@advtools, + ''. + ''.$items{$item}{tooltip}.
+                  ''. + ''.$items{$item}{desc}.''); + } + return @advtools; +} + sub dc_courseid_toggle { my ($dc_info) = @_; return ' '. @@ -4943,46 +5064,70 @@ table#LC_title_bar.LC_with_remote { margin: 0; } -/* #SD START (work in progress)*/ - -ul.LC_bct { +ul.LC_breadcrumb_tools_outerlist { margin: 0; padding: 0; + position: relative; + list-style: none; } -ul.LC_bct ol { +ul.LC_breadcrumb_tools_outerlist li { display: inline; } -ul.LC_bct ul { - display: inline; + +.LC_breadcrumb_tools_navigation { padding: 0; + margin: 0; + float: left; } -ul.LC_bct li { - list-style-type: none; - display: inline; +.LC_breadcrumb_tools_tools { + padding: 0; + margin: 0; + float: right; } +div.LC_GCI_Menu { + width:900px; +} -ul.LC_breadcrumb_tools { +div.LC_GCI_Menu:after { + content:''; + display:block; + clear:both; } -li.LC_breadcrumb_tools { +div.LC_GCI_Menu_left { + float:left; + width:400px; } -li.LC_breadcrumb_tools img{ - vertical-align: middle; + +div.LC_GCI_Menu_right { + float:left; + width:400px;; } -.LC_breadcrumb_tools_A { - margin: 0 0 0 1em; +dl.LC_GCI_Menu { + width:300px; + float:left; + margin-right:2em; } -.LC_breadcrumb_tools_B { - float: right; - margin-top: 0.4em; + +dl.LC_GCI_Menu dt { + font-weight: bold; + font-size:0.9em; + margin-bottom:0.7em; } -.LC_breadcrumb_tools_C { - margin: 0 1em 0 0; - float: right; + +dl.LC_GCI_Menu dt a { + color: $font; +} + +dl.LC_GCI_Menu dd { + font-size:0.8em; + margin:0 0 2em 0; + padding-left:4.5em; + line-height:1.5em; + background:none no-repeat left top; } -/* #SD END */ table#LC_title_bar td { background: $tabbg; @@ -4994,7 +5139,7 @@ table#LC_menubuttons img { .LC_breadcrumbs_component { float: right; - margin: 0 1em; + margin: 0.25em 1em; } .LC_breadcrumbs_component img { vertical-align: middle; @@ -5013,11 +5158,10 @@ td.LC_table_cell_checkbox { background: $sidebg; border-bottom: 1px solid $lg_border_color; line-height: 2.5em; - /* SD working here - height: 2.5em; - overflow: hidden; */ + overflow: hidden; margin: 0; padding: 0; + text-align: left; } /* Preliminary fix to hide breadcrumbs inside remote control window */ @@ -5029,7 +5173,7 @@ td.LC_table_cell_checkbox { clear:both; background: #F8F8F8; /* $sidebg; */ border: 1px solid $sidebg; - margin: 0 0 10px 0; + margin: 0 0 0 0; } .LC_fontsize_medium { @@ -5987,6 +6131,11 @@ fieldset > legend { padding: 0 5px 0 5px; } +div.LC_page_header { + background-color: $pgbg_or_bgcolor; + margin: 0 0 1.0em 0; +} + #LC_nav_bar { float: left; margin: 0.2em 0 0 0; @@ -6009,6 +6158,11 @@ ol.LC_primary_menu { margin: 0.2em 0 0 0; } +span.LC_new_message{ + font-weight:bold; + color: darkred; +} + ol#LC_PathBreadcrumbs { margin: 0; } @@ -6162,18 +6316,15 @@ ol#LC_MenuBreadcrumbs, ol#LC_PathBreadcrumbs { padding-left: 10px; margin: 0; - list-style-position: inside; - /* SD working here - white-space: nowrap; */ + margin: 0; + height: 2.5em; /* equal to #LC_breadcrumbs line-height */ } ol#LC_MenuBreadcrumbs li, ol#LC_PathBreadcrumbs li, ul.LC_CourseBreadcrumbs li { display: inline; - white-space: nowrap; - /* SD working here - white-space: normal; */ + white-space: normal; } ol#LC_MenuBreadcrumbs li a, @@ -6182,6 +6333,14 @@ ul.LC_CourseBreadcrumbs li a { font-size:90%; } +ol#LC_MenuBreadcrumbs h1 { + display: inline; + font-size: 90%; + line-height: 2.5em; + margin: 0; + padding: 0; +} + ol#LC_PathBreadcrumbs li a { text-decoration:none; font-size:100%; @@ -6426,6 +6585,11 @@ ul.LC_funclist { padding: 0.5em 1em 0.5em 0; } +ul.LC_funclist > li:first-child { + font-weight:bold; + margin-left:0.8em; +} + ul.LC_funclist + ul.LC_funclist { /* left border as a seperator if we have more than @@ -6452,10 +6616,11 @@ ul.LC_funclist li { background:#DAE0D2 url("/gcimenu_bg.gif") repeat-x bottom; font-size:93%; line-height:normal; + margin: 0.5em 0 0.5em 0; } #gciheader ul { margin:0; - padding:10px 10px 0; + padding:10px 5px 0; list-style:none; } #gciheader li { @@ -6770,8 +6935,8 @@ sub start_page { #if bread_crumbs_component exists show it as headline else show only the breadcrumbs if(exists($args->{'bread_crumbs_component'})){ $result .= &Apache::lonhtmlcommon::breadcrumbs($args->{'bread_crumbs_component'}); - }else{ - $result .= &Apache::lonhtmlcommon::breadcrumbs(); + } else { + $result .= &Apache::lonhtmlcommon::breadcrumbs(); } } return $result; @@ -7702,9 +7867,9 @@ sub user_picker { 'whse' => "When searching by last,first you must include at least one character in the first name.", 'thfo' => "The following need to be corrected before the search can be run:", ); - my $domform = &select_dom_form($currdom,'srchdomain',1,1); + my $domform = &select_dom_form($currdom,'srchdomain',undef,1); my $srchinsel = ' \n"; @@ -7763,9 +7929,9 @@ sub user_picker { ); $new_user_create = '

' .&mt("You are not authorized to create new $usertypetext{$usertype} users in this domain.") - .' ' - .&mt('Please contact the [_1]helpdesk[_2] for assistance.' - ,'','') + .'
' + .&mt('Enter a valid e-mail address as the username for the new user.').' '.&mt('Please contact the [_1]helpdesk[_2] for assistance.' + ,'','') .'


'; } } @@ -10050,19 +10216,19 @@ sub check_clone { my $clonehome=&Apache::lonnet::homeserver($clonecrsunum,$clonecrsudom); my $clonemsg; my $can_clone = 0; - my $lctype = lc($args->{'type'}); + my $lctype = lc($args->{'crstype'}); if ($lctype ne 'community') { $lctype = 'course'; } if ($clonehome eq 'no_host') { - if ($args->{'type'} eq 'Community') { + if ($args->{'crstype'} eq 'Community') { $clonemsg = &mt('No new community created.').$linefeed.&mt('A new community could not be cloned from the specified original - [_1] - because it is a non-existent community.',$args->{'clonecourse'}.':'.$args->{'clonedomain'}); } else { $clonemsg = &mt('No new course created.').$linefeed.&mt('A new course could not be cloned from the specified original - [_1] - because it is a non-existent course.',$args->{'clonecourse'}.':'.$args->{'clonedomain'}); } } else { my %clonedesc = &Apache::lonnet::coursedescription($cloneid,{'one_time' => 1}); - if ($args->{'type'} eq 'Community') { + if ($args->{'crstype'} eq 'Community') { if ($clonedesc{'type'} ne 'Community') { $clonemsg = &mt('No new community created.').$linefeed.&mt('A new community could not be cloned from the specified original - [_1] - because it is a course not a community.',$args->{'clonecourse'}.':'.$args->{'clonedomain'}); return ($can_clone, $clonemsg, $cloneid, $clonehome); @@ -10081,7 +10247,7 @@ sub check_clone { $can_clone = 1; } else { my $ccrole = 'cc'; - if ($args->{'type'} eq 'Community') { + if ($args->{'crstype'} eq 'Community') { $ccrole = 'co'; } my %roleshash = @@ -10092,7 +10258,7 @@ sub check_clone { if (($roleshash{$args->{'clonecourse'}.':'.$args->{'clonedomain'}.':'.$ccrole}) || (grep(/^\Q$args->{'ccuname'}\E:\Q$args->{'ccdomain'}\E$/,@cloners))) { $can_clone = 1; } else { - if ($args->{'type'} eq 'Community') { + if ($args->{'crstype'} eq 'Community') { $clonemsg = &mt('No new community created.').$linefeed.&mt('The new community could not be cloned from the existing community because the new community owner ([_1]) does not have cloning rights in the existing community ([_2]).',$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'}); } else { $clonemsg = &mt('No new course created.').$linefeed.&mt('The new course could not be cloned from the existing course because the new course owner ([_1]) does not have cloning rights in the existing course ([_2]).',$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'}); @@ -10431,6 +10597,21 @@ sub construct_course { $outcome .= ($fatal?$errtext:'write ok').$linefeed; } + if ($args->{'cloneroster'}) { + my ($numadded,$clisterror) = &Apache::lonclonecourse::copyroster($cloneid,$$courseid,$args->{'startaccess'},$args->{'endaccess'}); + if ($clisterror) { + $outcome .= "\0".&mt('An error occurred when copying the student roster from the old course to the new course; the error was: [_1].',$clisterror).$linefeed; + if ($numadded) { + $outcome .= &mt('Although [quant,_1,student] have received roles in the new course the roster does not report this. It is ').$linefeed; + } + } else { + if ($numadded) { + $outcome .= "\0".&mt('[quant,_1,student] copied from roster for old course to roster for new course.',$numadded).$linefeed; + } else { + $outcome .= "\0".&mt('No students have been enrolled in the new Concept Test.').' '.&mt('This is because either (a) an error occurred, or (b) there were no students with either current access or access which ended on/after the current default end date set for access to the old course.').$linefeed; + } + } + } return (1,$outcome); } @@ -10697,6 +10878,60 @@ sub _add_to_env { } } +sub new_roles_update { + my $rolecount = 0; + foreach my $envkey (keys(%env)) { + next unless ($envkey =~ /^user\.role\./); + $rolecount ++; + } + my $newrolecount = 0; + if (!$rolecount) { + my %userenv; + foreach my $crstype ('official','unofficial','community') { + $userenv{'canrequest.'.$crstype} = + &Apache::lonnet::usertools_access($env{'user.name'}, + $env{'user.domain'},$crstype,'reload','requestcourses'); + } + my $then=$env{'user.login.time'}; + my $refresh=time; + my (%userroles,%allroles,%allgroups,@newroles); + my %roleshash = + &Apache::lonnet::get_my_roles($env{'user.name'},$env{'user.domain'},'userroles',['active','future','previous'],undef,undef,1); + foreach my $item (keys(%roleshash)) { + my ($uname,$udom,$role,$section) = split(':',$item); + my $where = '/'.$udom.'/'.$uname; + my ($tstart,$tend) = split(':',$roleshash{$item}); + if ($section ne '') { + $where .= '/'.$section; + } + my $spec = $role.'.'.$where; + &Apache::lonnet::set_arearole($role,$where,$tstart,$tend, + $env{'user.domain'},$env{'user.name'}); + $userroles{'user.role.'.$spec} = $tstart.'.'.$tend; + $newrolecount ++; + unless (grep(/^\Q$role\E$/,@newroles)) { + push(@newroles,$role); + } + my $status = + &Apache::lonnet::curr_role_status($tstart,$tend,$refresh,$then); + if ($status eq 'active') { + &Apache::lonnet::gather_roleprivs(\%allroles,\%allgroups,\%userroles, + $where,$role,$tstart,$tend); + } + } + if (@newroles) { + my ($author,$adv) = &Apache::lonnet::set_userprivs(\%userroles,\%allroles, + \%allgroups); + &Apache::lonnet::appenv(\%userroles,[@newroles,'cm']); + $userenv{'user.adv'} = $adv; + $userenv{'user.author'} = $author; + $userenv{'user.refresh.time'} = $refresh; + } + &Apache::lonnet::appenv(\%userenv); + } + return $newrolecount; +} + # --- Get the symbolic name of a problem and the url sub get_symb { my ($request,$silent) = @_; @@ -10797,7 +11032,7 @@ sub existing_gcitest_courses { } else { next; } - my ($tstart,$tend) = split(':',$env{$envkey}); + my ($tstart,$tend) = split('.',$env{$envkey}); if (((!$tstart) || ($tstart < $now)) && ((!$tend) || ($tend > $now))) { my $descr = $env{'course.'.$cdom.'_'.$cnum.'.description'}; if ($descr ne '') { @@ -10808,6 +11043,81 @@ sub existing_gcitest_courses { return %courses; } +sub gcitest_switcher { + my ($role,$formname,%courses) = @_; + my $output; + my %Sortby; + foreach my $course (sort(keys(%courses))) { + next unless (ref($courses{$course}) eq 'HASH'); + my $clean_title = $courses{$course}{'description'}; + $clean_title =~ s/\W+//g; + if ($clean_title eq '') { + $clean_title = $courses{$course}{'description'}; + } + push(@{$Sortby{$clean_title}},$course); + } + my @sorted_courses = sort { lc($a) cmp lc($b) } (keys(%Sortby)); + my $default; + if (@sorted_courses > 1) { + if (($env{'request.course.id'}) && ($courses{$env{'request.course.id'}})) { + $default = &mt('Switch concept test ...'); + } else { + $default = &mt('Select a concept test ...'); + } + } else { + unless (($env{'request.course.id'}) && ($courses{$env{'request.course.id'}})) { + $default = &mt('Select concept test ...'); + } + } + if ($default) { + $output = '
'. + '
'; + } + return $output; +} + +sub gcitest_switcher_js { + my ($current,$numcourses,$formname) = @_; + my $output = <<"ENDJS"; + +function courseswitcher(caller) { + var numcourses = $numcourses; + var current = '$current'; + var choice = document.$formname.newrole.options[document.$formname.newrole.selectedIndex].value; + if (choice == '') { + if (caller == 'icon') { + alert('No Concept Test selected'); + } + document.$formname.selectrole.value = ''; + return; + } + if (choice == current) { + if ((caller != 'icon') && (numcourses > 1)) { + alert('You have selected the current course.\\nPlease select a different Concept Test course'); + } + document.$formname.newrole.selectedIndex = 0; + document.$formname.selectrole.value = ''; + return; + } + document.$formname.selectrole.value = '1'; + document.$formname.submit(); + return; +} + +ENDJS + return $output; +} + + + =pod =back