".
- "$text ";
+ "$text ";
}
# Add the graphic
@@ -1050,7 +1173,7 @@ sub help_open_faq {
{
$template .=
"".
- "$text ";
+ "$text ";
}
# Add the graphic
@@ -1069,7 +1192,7 @@ ENDTEMPLATE
=pod
-=item * change_content_javascript():
+=item * &change_content_javascript():
This and the next function allow you to create small sections of an
otherwise static HTML page that you can update on the fly with
@@ -1124,7 +1247,7 @@ DOMBASED
=pod
-=item * changable_area($name, $origContent):
+=item * &changable_area($name,$origContent):
This provides a "changable area" that can be modified on the fly via
the Javascript code provided in C. $name is
@@ -1148,7 +1271,7 @@ sub changable_area {
=pod
-=item * viewport_geometry_js {
+=item * &viewport_geometry_js
Provides javascript object (Geometry) which can provide information about the viewport geometry for the client browser.
@@ -1195,7 +1318,7 @@ GEOMETRY
=pod
-=item * viewport_size_js {
+=item * &viewport_size_js()
Provides a javascript function to set values of two form elements - width and height (elements are passed in as arguments to the javascript function) to the dimensions of the user's browser window.
@@ -1219,7 +1342,7 @@ DIMS
=pod
-=item * resize_textarea_js
+=item * &resize_textarea_js()
emits the needed javascript to resize a textarea to be as big as possible
@@ -1228,6 +1351,7 @@ the id of the element to resize, second
surrounds everything that comes after the textarea, this routine needs
to be attached to the for the onload and onresize events.
+=back
=cut
@@ -1280,8 +1404,6 @@ RESIZE
=pod
-=back
-
=head1 Excel and CSV file utility routines
=over 4
@@ -1293,7 +1415,7 @@ RESIZE
=pod
-=item * csv_translate($text)
+=item * &csv_translate($text)
Translate $text to allow it to be output as a 'comma separated values'
format.
@@ -1314,7 +1436,7 @@ sub csv_translate {
=pod
-=item * define_excel_formats
+=item * &define_excel_formats()
Define some commonly used Excel cell formats.
@@ -1370,7 +1492,7 @@ sub define_excel_formats {
=pod
-=item * create_workbook
+=item * &create_workbook()
Create an Excel worksheet. If it fails, output message on the
request object and return undefs.
@@ -1413,7 +1535,7 @@ sub create_workbook {
=pod
-=item * create_text_file
+=item * &create_text_file()
Create a file to write to and eventually make available to the user.
If file creation fails, outputs an error message on the request object and
@@ -1438,9 +1560,9 @@ sub create_text_file {
$fh = Apache::File->new('>/home/httpd'.$filename);
if (! defined($fh)) {
$r->log_error("Couldn't open $filename for output $!");
- $r->print("Problems occured in creating the output file. ".
- "This error has been logged. ".
- "Please alert your LON-CAPA administrator.");
+ $r->print(&mt('Problems occurred in creating the output file. '
+ .'This error has been logged. '
+ .'Please alert your LON-CAPA administrator.'));
}
return ($fh,$filename)
}
@@ -1481,7 +1603,7 @@ sub domain_select {
=over 4
-=item * multiple_select_form($name,$value,$size,$hash,$order)
+=item * &multiple_select_form($name,$value,$size,$hash,$order)
Returns a string containing a element int multiple mode
@@ -1531,7 +1653,7 @@ sub multiple_select_form {
=pod
-=item * select_form($defdom,$name,%hash)
+=item * &select_form($defdom,$name,%hash)
Returns a string containing a form to
allow a user to select options from a hash option_name => displayed text.
@@ -1618,7 +1740,7 @@ sub select_level_form {
=pod
-=item * select_dom_form($defdom,$name,$includeempty,$showdomdesc)
+=item * &select_dom_form($defdom,$name,$includeempty,$showdomdesc)
Returns a string containing a form to
allow a user to select the domain to preform an operation in.
@@ -1658,7 +1780,7 @@ sub select_dom_form {
=pod
-=item * home_server_form_item($domain,$name,$defaultflag)
+=item * &home_server_form_item($domain,$name,$defaultflag)
input: 4 arguments (two required, two optional) -
$domain - domain of new user
@@ -1818,14 +1940,12 @@ sub decode_user_agent {
=over 4
-=item * authform_xxxxxx
+=item * &authform_xxxxxx()
The authform_xxxxxx subroutines provide javascript and html forms which
handle some of the conveniences required for authentication forms.
This is not an optimal method, but it works.
-See loncreateuser.pm for invocation and use examples.
-
=over 4
=item * authform_header
@@ -1842,7 +1962,7 @@ See loncreateuser.pm for invocation and
=back
-=back
+See loncreateuser.pm for invocation and use examples.
=cut
@@ -2305,14 +2425,20 @@ sub get_assignable_auth {
=pod
-=item * get_kerberos_defaults
+=item * &get_kerberos_defaults()
get_kerberos_defaults($target_domain) returns the default kerberos
version and domain. If not found, it defaults to version 4 and the
domain of the server.
+=over 4
+
($def_version, $def_krb_domain) = &get_kerberos_defaults($target_domain);
+=back
+
+=back
+
=cut
#-------------------------------------------
@@ -2332,11 +2458,6 @@ sub get_kerberos_defaults {
return ($krbdef,$krbdefdom);
}
-=pod
-
-=back
-
-=cut
###############################################################
## Thesaurus Functions ##
@@ -2348,7 +2469,7 @@ sub get_kerberos_defaults {
=over 4
-=item * initialize_keywords
+=item * &initialize_keywords()
Initializes the package variable %Keywords if it is empty. Uses the
package variable $thesaurus_db_file.
@@ -2393,7 +2514,7 @@ sub initialize_keywords {
=pod
-=item * keyword($word)
+=item * &keyword($word)
Returns true if $word is a keyword. A keyword is a word that appears more
than the average number of times in the thesaurus database. Calls
@@ -2414,7 +2535,7 @@ sub keyword {
=pod
-=item * get_related_words
+=item * &get_related_words()
Look up a word in the thesaurus. Takes a scalar argument and returns
an array of words. If the keyword is not in the thesaurus, an empty array
@@ -2472,7 +2593,7 @@ sub get_related_words {
=over 4
-=item * plainname($uname,$udom,$first)
+=item * &plainname($uname,$udom,$first)
Takes a users logon name and returns it as a string in
"first middle last generation" form
@@ -2501,7 +2622,7 @@ sub plainname {
# -------------------------------------------------------------------- Nickname
=pod
-=item * nickname($uname,$udom)
+=item * &nickname($uname,$udom)
Gets a users name and returns it as a string as
@@ -2551,18 +2672,21 @@ sub getnames {
}
# -------------------------------------------------------------------- getemails
+
=pod
-=item * getemails($uname,$udom)
+=item * &getemails($uname,$udom)
Gets a user's email information and returns it as a hash with keys:
notification, critnotification, permanentemail
For notification and critnotification, values are comma-separated lists
-of e-mail address(es); for permanentemail, value is a single e-mail address.
+of e-mail addresses; for permanentemail, value is a single e-mail address.
+
=cut
+
sub getemails {
my ($uname,$udom)=@_;
if ($udom eq 'public' && $uname eq 'public') {
@@ -2597,7 +2721,7 @@ sub flush_email_cache {
=pod
-=item * screenname($uname,$udom)
+=item * &screenname($uname,$udom)
Gets a users screenname and returns it as a string
@@ -2646,7 +2770,7 @@ sub aboutmewrapper {
sub syllabuswrapper {
my ($linktext,$coursedir,$domain,$fontcolor)=@_;
if ($fontcolor) {
- $linktext=''.$linktext.' ';
+ $linktext=''.$linktext.' ';
}
return qq{$linktext };
}
@@ -2693,7 +2817,7 @@ sub student_image_tag {
=over 4
-=item * languageids()
+=item * &languageids()
returns list of all language ids
@@ -2705,7 +2829,7 @@ sub languageids {
=pod
-=item * languagedescription()
+=item * &languagedescription()
returns description of a specified language id
@@ -2730,7 +2854,7 @@ sub supportedlanguagecode {
=pod
-=item * copyrightids()
+=item * ©rightids()
returns list of all copyrights
@@ -2742,7 +2866,7 @@ sub copyrightids {
=pod
-=item * copyrightdescription()
+=item * ©rightdescription()
returns description of a specified copyright id
@@ -2754,7 +2878,7 @@ sub copyrightdescription {
=pod
-=item * source_copyrightids()
+=item * &source_copyrightids()
returns list of all source copyrights
@@ -2766,7 +2890,7 @@ sub source_copyrightids {
=pod
-=item * source_copyrightdescription()
+=item * &source_copyrightdescription()
returns description of a specified source copyright id
@@ -2778,7 +2902,7 @@ sub source_copyrightdescription {
=pod
-=item * filecategories()
+=item * &filecategories()
returns list of all file categories
@@ -2790,7 +2914,7 @@ sub filecategories {
=pod
-=item * filecategorytypes()
+=item * &filecategorytypes()
returns list of file types belonging to a given file
category
@@ -2804,7 +2928,7 @@ sub filecategorytypes {
=pod
-=item * fileembstyle()
+=item * &fileembstyle()
returns embedding style for a specified file type
@@ -2828,7 +2952,7 @@ sub filecategoryselect {
=pod
-=item * filedescription()
+=item * &filedescription()
returns description for a specified file type
@@ -2842,7 +2966,7 @@ sub filedescription {
=pod
-=item * filedescriptionex()
+=item * &filedescriptionex()
returns description for a specified file type with
extra formatting
@@ -2874,7 +2998,7 @@ sub fileextensions {
sub display_languages {
my %languages=();
- foreach my $lang (&preferred_languages()) {
+ foreach my $lang (&Apache::lonlocal::preferred_languages()) {
$languages{$lang}=1;
}
&get_unprocessed_cgi($ENV{'QUERY_STRING'},['displaylanguage']);
@@ -2886,50 +3010,9 @@ sub display_languages {
return %languages;
}
-sub preferred_languages {
- my @languages=();
- if ($env{'course.'.$env{'request.course.id'}.'.languages'}) {
- @languages=(@languages,split(/\s*(\,|\;|\:)\s*/,
- $env{'course.'.$env{'request.course.id'}.'.languages'}));
- }
- if ($env{'environment.languages'}) {
- @languages=(@languages,
- split(/\s*(\,|\;|\:)\s*/,$env{'environment.languages'}));
- }
- my $browser=$ENV{'HTTP_ACCEPT_LANGUAGE'};
- if ($browser) {
- my @browser =
- map { (split(/\s*;\s*/,$_))[0] } (split(/\s*,\s*/,$browser));
- push(@languages,@browser);
- }
-
- foreach my $domtype ($env{'user.domain'},$env{'request.role.domain'},
- $Apache::lonnet::perlvar{'lonDefDomain'}) {
- if ($domtype ne '') {
- my %domdefs = &Apache::lonnet::get_domain_defaults($domtype);
- if ($domdefs{'lang_def'} ne '') {
- push(@languages,$domdefs{'lang_def'});
- }
- }
- }
-# turn "en-ca" into "en-ca,en"
- my @genlanguages;
- foreach my $lang (@languages) {
- unless ($lang=~/\w/) { next; }
- push(@genlanguages,$lang);
- if ($lang=~/(\-|\_)/) {
- push(@genlanguages,(split(/(\-|\_)/,$lang))[0]);
- }
- }
- #uniqueify the languages list
- my %count;
- @genlanguages = map { $count{$_}++ == 0 ? $_ : () } @genlanguages;
- return @genlanguages;
-}
-
sub languages {
my ($possible_langs) = @_;
- my @preferred_langs = &preferred_languages();
+ my @preferred_langs = &Apache::lonlocal::preferred_languages();
if (!ref($possible_langs)) {
if( wantarray ) {
return @preferred_langs;
@@ -2960,7 +3043,7 @@ sub languages {
=over 4
-=item * get_previous_attempt($symb, $username, $domain, $course,
+=item * &get_previous_attempt($symb, $username, $domain, $course,
$getattempt, $regexp, $gradesub)
Return string with previous attempt on problem. Arguments:
@@ -3104,7 +3187,7 @@ sub relative_to_absolute {
=pod
-=item * get_student_view
+=item * &get_student_view()
show a snapshot of what student was looking at
@@ -3123,7 +3206,7 @@ sub get_student_view {
}
if (defined($target)) { $form{'grade_target'} = $target; }
$feedurl=&Apache::lonnet::clutter($feedurl);
- my $userview=&Apache::lonnet::ssi_body($feedurl,%form);
+ my ($userview,$response)=&Apache::lonnet::ssi_body($feedurl,%form);
$userview=~s/\]*\>//gi;
$userview=~s/\<\/body\>//gi;
$userview=~s/\//gi;
@@ -3132,12 +3215,44 @@ sub get_student_view {
$userview=~s/\<\/head\>//gi;
$userview=~s/action\s*\=/would_be_action\=/gi;
$userview=&relative_to_absolute($feedurl,$userview);
- return $userview;
+ if (wantarray) {
+ return ($userview,$response);
+ } else {
+ return $userview;
+ }
+}
+
+sub get_student_view_with_retries {
+ my ($symb,$retries,$username,$domain,$courseid,$target,$moreenv) = @_;
+
+ my $ok = 0; # True if we got a good response.
+ my $content;
+ my $response;
+
+ # Try to get the student_view done. within the retries count:
+
+ do {
+ ($content, $response) = &get_student_view($symb,$username,$domain,$courseid,$target,$moreenv);
+ $ok = $response->is_success;
+ if (!$ok) {
+ &Apache::lonnet::logthis("Failed get_student_view_with_retries on $symb: ".$response->is_success.', '.$response->code.', '.$response->message);
+ }
+ $retries--;
+ } while (!$ok && ($retries > 0));
+
+ if (!$ok) {
+ $content = ''; # On error return an empty content.
+ }
+ if (wantarray) {
+ return ($content, $response);
+ } else {
+ return $content;
+ }
}
=pod
-=item * get_student_answers()
+=item * &get_student_answers()
show a snapshot of how student was answering problem
@@ -3241,16 +3356,21 @@ sub pprmlink {
sub timehash {
- my @ltime=localtime(shift);
- return ( 'seconds' => $ltime[0],
- 'minutes' => $ltime[1],
- 'hours' => $ltime[2],
- 'day' => $ltime[3],
- 'month' => $ltime[4]+1,
- 'year' => $ltime[5]+1900,
- 'weekday' => $ltime[6],
- 'dayyear' => $ltime[7]+1,
- 'dlsav' => $ltime[8] );
+ my ($thistime) = @_;
+ my $timezone = &Apache::lonlocal::gettimezone();
+ my $dt = DateTime->from_epoch(epoch => $thistime)
+ ->set_time_zone($timezone);
+ my $wday = $dt->day_of_week();
+ if ($wday == 7) { $wday = 0; }
+ return ( 'second' => $dt->second(),
+ 'minute' => $dt->minute(),
+ 'hour' => $dt->hour(),
+ 'day' => $dt->day_of_month(),
+ 'month' => $dt->month(),
+ 'year' => $dt->year(),
+ 'weekday' => $wday,
+ 'dayyear' => $dt->day_of_year(),
+ 'dlsav' => $dt->is_dst() );
}
sub utc_string {
@@ -3260,6 +3380,24 @@ sub utc_string {
sub maketime {
my %th=@_;
+ my ($epoch_time,$timezone,$dt);
+ $timezone = &Apache::lonlocal::gettimezone();
+ eval {
+ $dt = DateTime->new( year => $th{'year'},
+ month => $th{'month'},
+ day => $th{'day'},
+ hour => $th{'hour'},
+ minute => $th{'minute'},
+ second => $th{'second'},
+ time_zone => $timezone,
+ );
+ };
+ if (!$@) {
+ $epoch_time = $dt->epoch;
+ if ($epoch_time) {
+ return $epoch_time;
+ }
+ }
return POSIX::mktime(
($th{'seconds'},$th{'minutes'},$th{'hours'},
$th{'day'},$th{'month'}-1,$th{'year'}-1900,0,0,-1));
@@ -3640,6 +3778,60 @@ sub blocking_status {
###############################################
+sub check_ip_acc {
+ my ($acc)=@_;
+ &Apache::lonxml::debug("acc is $acc");
+ if (!defined($acc) || $acc =~ /^\s*$/ || $acc =~/^\s*no\s*$/i) {
+ return 1;
+ }
+ my $allowed=0;
+ my $ip=$env{'request.host'} || $ENV{'REMOTE_ADDR'};
+
+ my $name;
+ foreach my $pattern (split(',',$acc)) {
+ $pattern =~ s/^\s*//;
+ $pattern =~ s/\s*$//;
+ if ($pattern =~ /\*$/) {
+ #35.8.*
+ $pattern=~s/\*//;
+ if ($ip =~ /^\Q$pattern\E/) { $allowed=1; }
+ } elsif ($pattern =~ /(\d+\.\d+\.\d+)\.\[(\d+)-(\d+)\]$/) {
+ #35.8.3.[34-56]
+ my $low=$2;
+ my $high=$3;
+ $pattern=$1;
+ if ($ip =~ /^\Q$pattern\E/) {
+ my $last=(split(/\./,$ip))[3];
+ if ($last <=$high && $last >=$low) { $allowed=1; }
+ }
+ } elsif ($pattern =~ /^\*/) {
+ #*.msu.edu
+ $pattern=~s/\*//;
+ if (!defined($name)) {
+ use Socket;
+ my $netaddr=inet_aton($ip);
+ ($name)=gethostbyaddr($netaddr,AF_INET);
+ }
+ if ($name =~ /\Q$pattern\E$/i) { $allowed=1; }
+ } elsif ($pattern =~ /\d+\.\d+\.\d+\.\d+/) {
+ #127.0.0.1
+ if ($ip =~ /^\Q$pattern\E/) { $allowed=1; }
+ } else {
+ #some.name.com
+ if (!defined($name)) {
+ use Socket;
+ my $netaddr=inet_aton($ip);
+ ($name)=gethostbyaddr($netaddr,AF_INET);
+ }
+ if ($name =~ /\Q$pattern\E$/i) { $allowed=1; }
+ }
+ if ($allowed) { last; }
+ }
+ return $allowed;
+}
+
+###############################################
+
=pod
=head1 Domain Template Functions
@@ -3688,7 +3880,14 @@ sub get_domainconf {
if (ref($domconfig{'login'}) eq 'HASH') {
if (keys(%{$domconfig{'login'}})) {
foreach my $key (keys(%{$domconfig{'login'}})) {
- $designhash{$udom.'.login.'.$key}=$domconfig{'login'}{$key};
+ if (ref($domconfig{'login'}{$key}) eq 'HASH') {
+ foreach my $img (keys(%{$domconfig{'login'}{$key}})) {
+ $designhash{$udom.'.login.'.$key.'_'.$img} =
+ $domconfig{'login'}{$key}{$img};
+ }
+ } else {
+ $designhash{$udom.'.login.'.$key}=$domconfig{'login'}{$key};
+ }
}
} else {
$legacy{'login'} = 1;
@@ -3994,7 +4193,7 @@ ENDROLE
$dc_info = '('.$dc_info.')';
}
- if ($env{'environment.remote'} eq 'off') {
+ if (($env{'environment.remote'} eq 'off') || ($args->{'suppress_header_logos'})) {
# No Remote
if ($env{'request.state'} eq 'construct') {
$forcereg=1;
@@ -4021,7 +4220,7 @@ ENDROLE
.''.&mt('Construction Space').' : '
.''
.&Apache::lonmenu::constspaceform();
@@ -4195,6 +4394,8 @@ sub standard_css {
my $vlink = &designparm($function.'.vlink', $domain);
my $link = &designparm($function.'.link', $domain);
+ my $loginbg = &designparm('login.sidebg',$domain);
+
my $sans = 'Verdana,Arial,Helvetica,sans-serif';
my $mono = 'monospace';
my $data_table_head = $tabbg;
@@ -4212,6 +4413,7 @@ sub standard_css {
my $mail_other_hover = '#669999';
my $table_header = '#DDDDDD';
my $feedback_link_bg = '#BBBBBB';
+ my $lg_border_color = '#C8C8C8';
my $border = ($env{'browser.type'} eq 'explorer' ||
$env{'browser.type'} eq 'safari' ) ? '0px 2px 0px 2px'
@@ -4219,22 +4421,35 @@ sub standard_css {
return < td,
table.LC_aboutme_port tr td {
@@ -4529,7 +4764,7 @@ table.LC_nested tr.LC_empty_row td {
table.LC_nested_outer tr th {
font-weight: bold;
background-color: $data_table_head;
- font-size: smaller;
+ font-size: small;
border-bottom: 1px solid #000000;
}
table.LC_nested_outer tr td.LC_subheader {
@@ -4568,7 +4803,7 @@ table.LC_createuser {
}
table.LC_createuser tr.LC_section_row td {
- font-size: smaller;
+ font-size: small;
}
table.LC_createuser tr.LC_info_row td {
@@ -4624,24 +4859,6 @@ table.LC_mail_list tr.LC_mail_even {
table.LC_mail_list tr.LC_mail_odd {
}
-
-table#LC_portfolio_actions {
- width: auto;
- background: $pgbg;
- border: 0px;
- border-spacing: 2px 2px;
- padding: 0px;
- margin: 0px;
- border-collapse: separate;
-}
-table#LC_portfolio_actions td.LC_label {
- background: $tabbg;
- text-align: right;
-}
-table#LC_portfolio_actions td.LC_value {
- background: $tabbg;
-}
-
table#LC_cstr_controls {
width: 100%;
border-collapse: collapse;
@@ -4660,35 +4877,27 @@ table#LC_cstr_controls tr th {
font-size: smaller;
}
-table#LC_browser {
-
-}
-table#LC_browser tr th {
- background: $table_header;
-}
-table#LC_browser tr td {
- padding: 2px;
-}
-table#LC_browser tr.LC_browser_file,
-table#LC_browser tr.LC_browser_file_published {
+table.LC_data_table tr > td.LC_browser_file,
+table.LC_data_table tr > td.LC_browser_file_published {
background: #CCFF88;
}
-table#LC_browser tr.LC_browser_file_locked,
-table#LC_browser tr.LC_browser_file_unpublished {
+table.LC_data_table tr > td.LC_browser_file_locked,
+table.LC_data_table tr > td.LC_browser_file_unpublished {
background: #FFAA99;
}
-table#LC_browser tr.LC_browser_file_obsolete {
+table.LC_data_table tr > td.LC_browser_file_obsolete {
background: #AAAAAA;
}
-table#LC_browser tr.LC_browser_file_modified,
-table#LC_browser tr.LC_browser_file_metamodified {
+table.LC_data_table tr > td.LC_browser_file_modified,
+table.LC_data_table tr > td.LC_browser_file_metamodified {
background: #FFFF77;
}
-table#LC_browser tr.LC_browser_folder {
+table.LC_data_table tr.LC_browser_folder > td {
background: #CCCCFF;
}
+
span.LC_current_location {
- font-size: x-large;
+ font-size:larger;
background: $pgbg;
}
@@ -4790,6 +4999,14 @@ table.LC_pick_box td.LC_pick_box_title {
width: 184px;
padding: 8px;
}
+table.LC_pick_box td.LC_selfenroll_pick_box_title {
+ background: $tabbg;
+ font-weight: bold;
+ text-align: right;
+ width: 350px;
+ padding: 8px;
+}
+
table.LC_pick_box td.LC_pick_box_value {
text-align: left;
padding: 8px;
@@ -5135,7 +5352,8 @@ div.LC_grade_select_mode_selector {
float: left;
}
div.LC_grade_select_mode_selector_header {
- font: bold medium $sans;
+ font-weight: bold;
+ font-size: medium;
}
div.LC_grade_select_mode_type {
clear: left;
@@ -5148,7 +5366,8 @@ div.LC_grade_show_user {
div.LC_grade_user_name {
background: #DDDDEE;
border-bottom: 1px solid black;
- font: bold large $sans;
+ font-weight: bold;
+ font-size: large;
}
div.LC_grade_show_user_odd_row div.LC_grade_user_name {
background: #DDEEDD;
@@ -5167,7 +5386,8 @@ div.LC_grade_show_problem_header,
div.LC_grade_submissions_header,
div.LC_grade_message_center_header,
div.LC_grade_assign_header {
- font: bold large $sans;
+ font-weight: bold;
+ font-size: large;
}
div.LC_grade_show_problem_problem,
div.LC_grade_submissions_body,
@@ -5178,7 +5398,8 @@ div.LC_grade_assign_body {
background: #FFFFFF;
}
span.LC_grade_check_note {
- font: normal medium $sans;
+ font-weight: normal;
+ font-size: medium;
display: inline;
position: absolute;
right: 1em;
@@ -5188,12 +5409,13 @@ table.LC_scantron_action {
width: 100%;
}
table.LC_scantron_action tr th {
- font: normal bold $sans;
+ font-weight:bold;
+ font-style:normal;
}
-
-div.LC_edit_problem_header,
+.LC_edit_problem_header,
div.LC_edit_problem_footer {
- font: normal medium $sans;
+ font-weight: normal;
+ font-size: medium;
margin: 2px;
}
div.LC_edit_problem_header,
@@ -5210,12 +5432,14 @@ div.LC_edit_problem_header_edit_row {
margin-bottom: 5px;
}
div.LC_edit_problem_header_title {
- font: larger bold $sans;
+ font-weight: bold;
+ font-size: larger;
background: $tabbg;
padding: 3px;
}
table.LC_edit_problem_header_title {
- font: larger bold $sans;
+ font-size: larger;
+ font-weight: bold;
width: 100%;
border-color: $pgbg;
border-style: solid;
@@ -5241,6 +5465,329 @@ hr.LC_edit_problem_divide {
height: 3px;
border: 0px;
}
+img.stift{
+ border-width:0;
+ vertical-align:middle;
+}
+
+table#LC_mainmenu{
+ margin-top:10px;
+ width:80%;
+
+}
+
+table#LC_mainmenu td.LC_mainmenu_col_fieldset{
+ vertical-align: top;
+ width: 45%;
+}
+.LC_mainmenu_fieldset_category {
+ color: $font;
+ background: $pgbg;
+ font-family: $sans;
+ font-size: small;
+ font-weight: bold;
+}
+fieldset#LC_mainmenu_fieldset {
+ margin:0px 10px 10px 0px;
+
+}
+/* ---- Remove when done ----
+# The following styles is part of the redesign of LON-CAPA and are
+# subject to change during this project.
+# Don't rely on their current functionality as they might be
+# changed or removed.
+# --------------------------*/
+
+a:hover,
+ol.smallMenu a:hover,
+ol#MenuBreadcrumbs a:hover,
+ul#TabMainMenuContent a:hover,
+.FormSectionClearButton input:hover{
+ color:#BF2317;
+ text-decoration:none;
+}
+
+h1 {
+ padding:5px 10px 5px 0px;
+ line-height:130%;
+}
+
+h2,h3,h4,h5,h6
+{
+margin:5px 0px 5px 0px;
+line-height:130%;
+}
+.hcell{
+ padding:3px 15px 3px 15px;
+ margin:0px;
+ background-color:$tabbg;
+ border-bottom:solid 1px $lg_border_color;
+}
+.noBorder {
+ border:0px;
+}
+/*
+.bgLightGrey { background:URL(images/TabMenuBG.png) repeat-x left top; }
+.bgLightGreyYellow {background-color:#EFECE0;}
+*/
+
+
+/* Main Header with discription of Person, Course, etc. */
+.HeadRight {
+ text-align: right;
+ float: right;
+ margin: 0px;
+ padding: 0px;
+ right:0;
+ position:absolute;
+ overflow:hidden;
+}
+
+p {
+ padding: 10px;
+
+}
+.FormSectionClearButton input {
+ background-color:transparent;
+ border:0px;
+ cursor:pointer;
+ text-decoration:underline;
+}
+
+
+dl,ul,div,fieldset {
+ margin: 10px 10px 10px 0px;
+ overflow:hidden;
+}
+ol.smallMenu {
+ margin: 0px;
+}
+
+ol.smallMenu li {
+ display: inline;
+ padding: 5px 5px 0px 10px;
+ vertical-align: top;
+}
+
+ol.smallMenu li img {
+ vertical-align: bottom;
+}
+
+ol.smallMenu a {
+ font-size: 90%;
+ color: RGB(80, 80, 80);
+ text-decoration: none;
+}
+
+ol#TabMainMenuContent {
+
+ margin: 0px 0px 10px 0px;
+ padding: 0px;
+}
+
+ol#TabMainMenuContent li {
+ display: inline;
+ vertical-align: bottom;
+ border-bottom: solid 1px RGB(175, 175, 175);
+ border-right: solid 1px RGB(175, 175, 175);
+ padding: 5px 15px 5px 15px;
+ margin-right:4px;
+ line-height: 140%;
+ font-weight: bold;
+ overflow:hidden;
+/* background: RGB(211, 206, 205) URL(images/TabMenuBG.png) repeat-x left top;*/
+}
+
+ol#TabMainMenuContent li a{
+ color: RGB(47, 47, 47);
+ text-decoration: none;
+}
+
+ol#TabMainMenuContent div.columnSection {
+ margin-bottom: 0px;
+}
+
+ol#MenuBreadcrumbs, ol#PathBreadcrumbs {
+ border-top: solid 1px RGB(255, 255, 255);
+ height: 20px;
+ line-height: 20px;
+ vertical-align: bottom;
+ margin: 0px 0px 30px 0px;
+ padding-left: 10px;
+ list-style-position: inside;
+/* background: RGB(211, 206, 205) URL(images/TabMenuBG.png) repeat-x left
+ top;*/
+}
+
+ol#MenuBreadcrumbs li, ol#PathBreadcrumbs li {
+/* background: url(images/pfeil_white.png) no-repeat left center;*/
+ display: inline;
+ padding: 0px 0px 0px 10px;
+ vertical-align: bottom;
+ overflow:hidden;
+}
+
+ol#MenuBreadcrumbs li a {
+ text-decoration: none;
+ font-size:90%;
+}
+ol#PathBreadcrumbs li a{
+ text-decoration:none;
+ font-size:100%;
+ font-weight:bold;
+}
+
+.ContentBoxSpecial
+{
+ border: solid 1px $lg_border_color;
+}
+.ContentBox {
+ padding:10px;
+}
+.PopUp
+{
+ padding:10px;
+ border-left:solid 1px $lg_border_color;
+ border-top:solid 1px $lg_border_color;
+ border-bottom:outset 1px $lg_border_color;
+ border-right:outset 1px $lg_border_color;
+ display:none;
+ position:absolute;
+ right:0;
+ background-color:white;
+ z-index:5;
+}
+
+dl.ListStyleClean dt {
+ padding-right: 5px;
+ display: table-header-group;
+}
+
+dl.ListStyleClean dd {
+ display: table-row;
+}
+
+.ListStyleClean,
+.ListStyleSimple,
+.ListStyleNormal,
+.ListStyleNormal_Border,
+.ListStyleSpecial
+ {
+ /*display:block; */
+ list-style-position: inside;
+ list-style-type: none;
+ overflow: hidden;
+ padding: 0px;
+}
+
+.ListStyleSimple li,
+.ListStyleSimple dd,
+.ListStyleNormal li,
+.ListStyleNormal dd,
+.ListStyleSpecial li,
+.ListStyleSpecial dd
+ {
+ margin: 0px;
+ padding: 5px 5px 5px 10px;
+ clear: both;
+}
+
+.ListStyleClean li,
+.ListStyleClean dd {
+ padding-top: 0px;
+ padding-bottom: 0px;
+}
+
+.ListStyleSimple dd,
+.ListStyleSimple li{
+ border-bottom: solid 1px $lg_border_color;
+}
+
+.ListStyleSpecial li,
+.ListStyleSpecial dd {
+ list-style-type: none;
+ background-color: RGB(220, 220, 220);
+ margin-bottom: 4px;
+}
+
+table.SimpleTable {
+ margin:5px;
+ border:solid 1px $lg_border_color;
+ }
+
+table.SimpleTable tr {
+ padding:0px;
+ border:solid 1px $lg_border_color;
+}
+table.SimpleTable thead{
+ background:rgb(220,220,220);
+}
+
+div.columnSection {
+ display: block;
+ clear: both;
+ overflow: hidden;
+ margin:0px;
+}
+
+div.columnSection>* {
+ float: left;
+ margin: 10px 20px 10px 0px;
+ overflow:hidden;
+}
+div.columnSection > .ContentBox,
+div.columnSection > .ContentBoxSpecial
+ {
+ width: 400px;
+
+}
+
+.LC_loginpage_container {
+ text-align:left;
+ margin : 0 auto;
+ width:65%;
+ padding: 10px;
+ height: auto;
+# background-color:#FFFFFF;
+ background-color:$loginbg;
+ border:1px solid #CCCCCC;
+}
+
+
+.LC_loginpage_loginContainer {
+ float:left;
+ width:60%;
+}
+
+.LC_loginpage_loginInfo {
+ margin-top:20px;
+ margin-left:20px;
+ float:left;
+ width:30%;
+ border:1px solid #CCCCCC;
+ padding:10px;
+}
+
+.LC_loginpage_space {
+ clear:both;
+ margin-bottom:20px;
+ border-bottom: 1px solid #CCCCCC;
+}
+
+.LC_loginpage_fieldset{
+ border: 1px solid #CCCCCC;
+ margin: 0 auto;
+}
+
+.LC_loginpage_legend{
+ padding: 2px;
+ margin: 0px;
+ font-size:14px;
+ font-weight:bold;
+}
+
+
+
END
}
@@ -5334,10 +5881,7 @@ Inputs: none
sub font_settings {
my $headerstring='';
- if (($env{'browser.os'} eq 'mac') && (!$env{'browser.mathml'})) {
- $headerstring.=
- ' ';
- } elsif (!$env{'browser.mathml'} && $env{'browser.unicode'}) {
+ if (!$env{'browser.mathml'} && $env{'browser.unicode'}) {
$headerstring.=
' ';
}
@@ -5396,8 +5940,15 @@ sub endheadtag {
Returns a uniform complete .. section for LON-CAPA web pages.
-Inputs: $title - optional title for the page
- $head_extra - optional extra HTML to put inside the
+Inputs:
+
+=over 4
+
+$title - optional title for the page
+
+$head_extra - optional extra HTML to put inside the
+
+=back
=cut
@@ -5412,44 +5963,54 @@ sub head {
Returns a complete .. section for LON-CAPA web pages.
-Inputs: $title - optional title for the page
- $head_extra - optional extra HTML to incude inside the
- $args - additional optional args supported are:
- only_body -> is true will set &bodytag() onlybodytag
+Inputs:
+
+=over 4
+
+$title - optional title for the page
+
+$head_extra - optional extra HTML to incude inside the
+
+$args - additional optional args supported are:
+
+=over 8
+
+ only_body -> is true will set &bodytag() onlybodytag
arg on
- no_nav_bar -> is true will set &bodytag() notopbar arg on
- add_entries -> additional attributes to add to the
- domain -> force to color decorate a page for a
+ no_nav_bar -> is true will set &bodytag() notopbar arg on
+ add_entries -> additional attributes to add to the
+ domain -> force to color decorate a page for a
specific domain
- function -> force usage of a specific rolish color
+ function -> force usage of a specific rolish color
scheme
- redirect -> see &headtag()
- bgcolor -> override the default page bg color
- js_ready -> return a string ready for being used in
+ redirect -> see &headtag()
+ bgcolor -> override the default page bg color
+ js_ready -> return a string ready for being used in
a javascript writeln
- html_encode -> return a string ready for being used in
+ html_encode -> return a string ready for being used in
a html attribute
- force_register -> if is true will turn on the &bodytag()
+ force_register -> if is true will turn on the &bodytag()
$forcereg arg
- body_title -> alternate text to use instead of $title
+ body_title -> alternate text to use instead of $title
in the title box that appears, this text
is not auto translated like the $title is
- frameset -> if true will start with a
+ frameset -> if true will start with a
rather than
- no_title -> if true the title bar won't be shown
- skip_phases -> hash ref of
+ no_title -> if true the title bar won't be shown
+ skip_phases -> hash ref of
head -> skip the generation
body -> skip all generation
-
- no_inline_link -> if true and in remote mode, don't show the
+ no_inline_link -> if true and in remote mode, don't show the
'Switch To Inline Menu' link
-
- no_auto_mt_title -> prevent &mt()ing the title arg
-
- inherit_jsmath -> when creating popup window in a page,
+ 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
+=back
+
+=back
+
=cut
sub start_page {
@@ -6675,12 +7236,16 @@ sub instrule_disallow_msg {
$text{'action'} = 'IDs';
}
}
- $response = &mt("The $text{'item'} you chose $text{'match'} the format of $text{'items'} defined for [_1] , but the $text{'item'} $text{'do'} not exist in the institutional directory.",$domdesc).' ';
+ $response = &mt("The $text{'item'} you chose $text{'match'} the format of $text{'items'} defined for [_1], but the $text{'item'} $text{'do'} not exist in the institutional directory.",''.$domdesc.' ').' ';
if ($mode eq 'upload') {
if ($checkitem eq 'username') {
$response .= &mt("You will need to modify your upload file so it will include $text{'action'} with a different format -- $text{'one'} that will not conflict with 'official' institutional $text{'items'}.");
} elsif ($checkitem eq 'id') {
- $response .= &mt("Either upload a file which includes $text{'action'} with a different format -- $text{'one'} that will not conflict with 'official' institutional $text{'items'}, or when associating fields with data columns, omit an association for the ID/Student Number field.");
+ $response .= &mt("Either upload a file which includes $text{'action'} with a different format -- $text{'one'} that will not conflict with 'official' institutional $text{'items'}, or when associating fields with data columns, omit an association for the Student/Employee ID field.");
+ }
+ } elsif ($mode eq 'selfcreate') {
+ if ($checkitem eq 'id') {
+ $response .= &mt("You must either choose $text{'action'} with a different format -- $text{'one'} that will not conflict with 'official' institutional $text{'items'}, or leave the ID field blank.");
}
} else {
if ($checkitem eq 'username') {
@@ -6710,7 +7275,7 @@ sub sorted_inst_types {
my ($usertypes,$order) = &Apache::lonnet::retrieve_inst_usertypes($dom);
my $othertitle = &mt('All users');
if ($env{'request.course.id'}) {
- $othertitle = 'any';
+ $othertitle = &mt('Any users');
}
my @types;
if (ref($order) eq 'ARRAY') {
@@ -6723,13 +7288,51 @@ sub sorted_inst_types {
}
if (keys(%{$usertypes}) > 0) {
$othertitle = &mt('Other users');
- if ($env{'request.course.id'}) {
- $othertitle = 'other';
- }
}
return ($othertitle,$usertypes,\@types);
}
+sub get_institutional_codes {
+ my ($settings,$allcourses,$LC_code) = @_;
+# Get complete list of course sections to update
+ my @currsections = ();
+ my @currxlists = ();
+ my $coursecode = $$settings{'internal.coursecode'};
+
+ if ($$settings{'internal.sectionnums'} ne '') {
+ @currsections = split(/,/,$$settings{'internal.sectionnums'});
+ }
+
+ if ($$settings{'internal.crosslistings'} ne '') {
+ @currxlists = split(/,/,$$settings{'internal.crosslistings'});
+ }
+
+ if (@currxlists > 0) {
+ foreach (@currxlists) {
+ if (m/^([^:]+):(\w*)$/) {
+ unless (grep/^$1$/,@{$allcourses}) {
+ push @{$allcourses},$1;
+ $$LC_code{$1} = $2;
+ }
+ }
+ }
+ }
+
+ if (@currsections > 0) {
+ foreach (@currsections) {
+ if (m/^(\w+):(\w*)$/) {
+ my $sec = $coursecode.$1;
+ my $lc_sec = $2;
+ unless (grep/^$sec$/,@{$allcourses}) {
+ push @{$allcourses},$sec;
+ $$LC_code{$sec} = $lc_sec;
+ }
+ }
+ }
+ }
+ return;
+}
+
=pod
=back
@@ -6738,7 +7341,7 @@ sub sorted_inst_types {
=over 4
-=item * get_unprocessed_cgi($query,$possible_names)
+=item * &get_unprocessed_cgi($query,$possible_names)
Modify the %env hash to contain unprocessed CGI form parameters held in
$query. The parameters listed in $possible_names (an array reference),
@@ -6767,7 +7370,7 @@ sub get_unprocessed_cgi {
=pod
-=item * cacheheader()
+=item * &cacheheader()
returns cache-controlling header code
@@ -6784,7 +7387,7 @@ sub cacheheader {
=pod
-=item * no_cache($r)
+=item * &no_cache($r)
specifies header code to not have cache
@@ -6820,7 +7423,7 @@ sub content_type {
=pod
-=item * add_to_env($name,$value)
+=item * &add_to_env($name,$value)
adds $name to the %env hash with value
$value, if $name already exists, the entry is converted to an array
@@ -6847,7 +7450,7 @@ sub add_to_env {
=pod
-=item * get_env_multiple($name)
+=item * &get_env_multiple($name)
gets $name from the %env hash, it seemlessly handles the cases where multiple
values may be defined and end up as an array ref.
@@ -6870,6 +7473,232 @@ sub get_env_multiple {
return(@values);
}
+sub ask_for_embedded_content {
+ my ($actionurl,$state,$allfiles,$codebase,$args)=@_;
+ my $upload_output = '
+ ';
+ return $upload_output;
+}
+
+sub upload_embedded {
+ my ($context,$dirpath,$uname,$udom,$dir_root,$url_root,$group,$disk_quota,
+ $current_disk_usage) = @_;
+ my $output;
+ for (my $i=0; $i<$env{'form.number_embedded_items'}; $i++) {
+ next if (!exists($env{'form.embedded_item_'.$i.'.filename'}));
+ my $orig_uploaded_filename =
+ $env{'form.embedded_item_'.$i.'.filename'};
+
+ $env{'form.embedded_orig_'.$i} =
+ &unescape($env{'form.embedded_orig_'.$i});
+ my ($path,$fname) =
+ ($env{'form.embedded_orig_'.$i} =~ m{(.*/)([^/]*)});
+ # no path, whole string is fname
+ if (!$fname) { $fname = $env{'form.embedded_orig_'.$i} };
+
+ $path = $env{'form.currentpath'}.$path;
+ $fname = &Apache::lonnet::clean_filename($fname);
+ # See if there is anything left
+ next if ($fname eq '');
+
+ # Check if file already exists as a file or directory.
+ my ($state,$msg);
+ if ($context eq 'portfolio') {
+ my $port_path = $dirpath;
+ if ($group ne '') {
+ $port_path = "groups/$group/$port_path";
+ }
+ ($state,$msg) = &check_for_upload($path,$fname,$group,'embedded_item_'.$i,
+ $dir_root,$port_path,$disk_quota,
+ $current_disk_usage,$uname,$udom);
+ if ($state eq 'will_exceed_quota'
+ || $state eq 'file_locked'
+ || $state eq 'file_exists' ) {
+ $output .= $msg;
+ next;
+ }
+ } elsif (($context eq 'author') || ($context eq 'testbank')) {
+ ($state,$msg) = &check_for_existing($path,$fname,'embedded_item_'.$i);
+ if ($state eq 'exists') {
+ $output .= $msg;
+ next;
+ }
+ }
+ # Check if extension is valid
+ if (($fname =~ /\.(\w+)$/) &&
+ (&Apache::loncommon::fileembstyle($1) eq 'hdn')) {
+ $output .= &mt('Invalid file extension ([_1]) - reserved for LONCAPA use - rename the file with a different extension and re-upload. ',$1);
+ next;
+ } elsif (($fname =~ /\.(\w+)$/) &&
+ (!defined(&Apache::loncommon::fileembstyle($1)))) {
+ $output .= &mt('Unrecognized file extension ([_1]) - rename the file with a proper extension and re-upload.',$1);
+ next;
+ } elsif ($fname=~/\.(\d+)\.(\w+)$/) {
+ $output .= &mt('File name not allowed - rename the file to remove the number immediately before the file extension([_1]) and re-upload.',$2);
+ next;
+ }
+
+ $env{'form.embedded_item_'.$i.'.filename'}=$fname;
+ if ($context eq 'portfolio') {
+ my $result=
+ &Apache::lonnet::userfileupload('embedded_item_'.$i,'',
+ $dirpath.$path);
+ if ($result !~ m|^/uploaded/|) {
+ $output .= ''
+ .&mt('An error occurred ([_1]) while trying to upload [_2] for embedded element [_3].'
+ ,$result,$orig_uploaded_filename,$env{'form.embedded_orig_'.$i})
+ .' ';
+ next;
+ } else {
+ $output .= ''.&mt('Uploaded [_1]',''.
+ $path.$fname.' ').'
';
+ }
+ } else {
+# Save the file
+ my $target = $env{'form.embedded_item_'.$i};
+ my $fullpath = $dir_root.$dirpath.'/'.$path;
+ my $dest = $fullpath.$fname;
+ my $url = $url_root.$dirpath.'/'.$path.$fname;
+ my @parts=split(/\//,$fullpath);
+ my $count;
+ my $filepath = $dir_root;
+ for ($count=4;$count<=$#parts;$count++) {
+ $filepath .= "/$parts[$count]";
+ if ((-e $filepath)!=1) {
+ mkdir($filepath,0770);
+ }
+ }
+ my $fh;
+ if (!open($fh,'>'.$dest)) {
+ &Apache::lonnet::logthis('Failed to create '.$dest);
+ $output .= ''.
+ &mt('An error occurred while trying to upload [_1] for embedded element [_2].',$orig_uploaded_filename,$env{'form.embedded_orig_'.$i}).
+ ' ';
+ } else {
+ if (!print $fh $env{'form.embedded_item_'.$i}) {
+ &Apache::lonnet::logthis('Failed to write to '.$dest);
+ $output .= ''.
+ &mt('An error occurred while writing the file [_1] for embedded element [_2].',$orig_uploaded_filename,$env{'form.embedded_orig_'.$i}).
+ ' ';
+ } else {
+ if ($context eq 'testbank') {
+ $output .= &mt('Embedded file uploaded successfully:').
+ ' '.
+ $orig_uploaded_filename.' ';
+ } else {
+ $output .= ''.
+ &mt('View embedded file: [_1]',''.
+ $orig_uploaded_filename.' ').' ';
+ }
+ }
+ close($fh);
+ }
+ }
+ }
+ return $output;
+}
+
+sub check_for_existing {
+ my ($path,$fname,$element) = @_;
+ my ($state,$msg);
+ if (-d $path.'/'.$fname) {
+ $state = 'exists';
+ $msg = &mt('Unable to upload [_1]. A directory by that name was found in [_2].',''.$fname.' ',$path);
+ } elsif (-e $path.'/'.$fname) {
+ $state = 'exists';
+ $msg = &mt('Unable to upload [_1]. A file by that name was found in [_2].',''.$fname.' ',$path);
+ }
+ if ($state eq 'exists') {
+ $msg = ''.$msg.' ';
+ }
+ return ($state,$msg);
+}
+
+sub check_for_upload {
+ my ($path,$fname,$group,$element,$portfolio_root,$port_path,
+ $disk_quota,$current_disk_usage,$uname,$udom) = @_;
+ my $filesize = (length($env{'form.'.$element})) / 1000; #express in k (1024?)
+ my $getpropath = 1;
+ my @dir_list = &Apache::lonnet::dirlist($portfolio_root.$path,$udom,$uname,
+ $getpropath);
+ my $found_file = 0;
+ my $locked_file = 0;
+ foreach my $line (@dir_list) {
+ my ($file_name)=split(/\&/,$line,2);
+ if ($file_name eq $fname){
+ $file_name = $path.$file_name;
+ if ($group ne '') {
+ $file_name = $group.$file_name;
+ }
+ $found_file = 1;
+ if (&Apache::lonnet::is_locked($file_name,$udom,$uname) eq 'true') {
+ $locked_file = 1;
+ }
+ }
+ }
+ if (($current_disk_usage + $filesize) > $disk_quota){
+ my $msg = ''.
+ &mt('Unable to upload [_1]. (size = [_2] kilobytes). Disk quota will be exceeded.',''.$fname.' ',$filesize).' '.
+ ' '.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.',$disk_quota,$current_disk_usage);
+ return ('will_exceed_quota',$msg);
+ } elsif ($found_file) {
+ if ($locked_file) {
+ my $msg = '';
+ $msg .= &mt('Unable to upload [_1]. A locked file by that name was found in [_2].',''.$fname.' ',''.$port_path.$env{'form.currentpath'}.' ');
+ $msg .= ' ';
+ $msg .= &mt('You will be able to rename or delete existing [_1] after a grade has been assigned.',''.$fname.' ');
+ return ('file_locked',$msg);
+ } else {
+ my $msg = '';
+ $msg .= &mt('Unable to upload [_1]. A file by that name was found in [_2].',''.$fname.' ',$port_path.$env{'form.currentpath'});
+ $msg .= ' ';
+ $msg .= ' ';
+ $msg .= &mt('To upload, rename or delete existing [_1] in [_2].',''.$fname.' ', $port_path.$env{'form.currentpath'});
+ return ('file_exists',$msg);
+ }
+ }
+}
+
=pod
@@ -6879,7 +7708,7 @@ sub get_env_multiple {
=over 4
-=item * upfile_store($r)
+=item * &upfile_store($r)
Store uploaded file, $r should be the HTTP Request object,
needs $env{'form.upfile'}
@@ -6909,7 +7738,7 @@ sub upfile_store {
=pod
-=item * load_tmp_file($r)
+=item * &load_tmp_file($r)
Load uploaded file from tmp, $r should be the HTTP Request object,
needs $env{'form.datatoken'},
@@ -6933,7 +7762,7 @@ sub load_tmp_file {
=pod
-=item * upfile_record_sep()
+=item * &upfile_record_sep()
Separate uploaded file into records
returns array of records,
@@ -6955,7 +7784,7 @@ sub upfile_record_sep {
=pod
-=item * record_sep($record)
+=item * &record_sep($record)
Separate a record into fields $record should be an item from the upfile_record_sep(), needs $env{'form.upfiletype'}
@@ -7040,7 +7869,7 @@ sub record_sep {
=pod
-=item * upfile_select_html()
+=item * &upfile_select_html()
Return HTML code to select a file from the users machine and specify
the file type.
@@ -7087,7 +7916,7 @@ sub get_samples {
=pod
-=item * csv_print_samples($r,$records)
+=item * &csv_print_samples($r,$records)
Prints a table of sample values from each column uploaded $r is an
Apache Request ref, $records is an arrayref from
@@ -7099,7 +7928,7 @@ Apache Request ref, $records is an array
######################################################
sub csv_print_samples {
my ($r,$records) = @_;
- my $samples = &get_samples($records,3);
+ my $samples = &get_samples($records,5);
$r->print(&mt('Samples').' '.&start_data_table().
&start_data_table_header_row());
@@ -7123,7 +7952,7 @@ sub csv_print_samples {
=pod
-=item * csv_print_select_table($r,$records,$d)
+=item * &csv_print_select_table($r,$records,$d)
Prints a table to create associations between values and table columns.
@@ -7154,7 +7983,7 @@ sub csv_print_select_table {
foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) {
$r->print('Column '.($sample+1).' ');
+ '>'.&mt('Column [_1]',($sample+1)).'');
}
$r->print(' '.&end_data_table_row()."\n");
$i++;
@@ -7169,7 +7998,7 @@ sub csv_print_select_table {
=pod
-=item * csv_samples_select_table($r,$records,$d)
+=item * &csv_samples_select_table($r,$records,$d)
Prints a table of sample values from the upload and can make associate samples to internal names.
@@ -7185,7 +8014,8 @@ sub csv_samples_select_table {
my ($r,$records,$d) = @_;
my $i=0;
#
- my $samples = &get_samples($records,3);
+ my $max_samples = 5;
+ my $samples = &get_samples($records,$max_samples);
$r->print(&start_data_table().
&start_data_table_header_row().''.
&mt('Field').' '.&mt('Samples').' '.
@@ -7201,7 +8031,7 @@ sub csv_samples_select_table {
$display.'');
}
$r->print('');
- foreach my $line (0..2) {
+ foreach my $line (0..($max_samples-1)) {
if (defined($samples->[$line]{$key})) {
$r->print($samples->[$line]{$key}." \n");
}
@@ -7219,7 +8049,7 @@ sub csv_samples_select_table {
=pod
-=item clean_excel_name($name)
+=item * &clean_excel_name($name)
Returns a replacement for $name which does not contain any illegal characters.
@@ -7238,7 +8068,7 @@ sub clean_excel_name {
=pod
-=item * check_if_partid_hidden($id,$symb,$udom,$uname)
+=item * &check_if_partid_hidden($id,$symb,$udom,$uname)
Returns either 1 or undef
@@ -7279,7 +8109,7 @@ sub check_if_partid_hidden {
=over 4
-=item get_cgi_id
+=item * &get_cgi_id()
Inputs: none
@@ -7303,7 +8133,7 @@ sub get_cgi_id {
=pod
-=item DrawBarGraph
+=item * &DrawBarGraph()
Facilitates the plotting of data in a (stacked) bar graph.
Puts plot definition data into the users environment in order for
@@ -7438,7 +8268,7 @@ sub DrawBarGraph {
$ValuesHash{$id.'.'.$key} = $value;
}
#
- &Apache::lonnet::appenv(%ValuesHash);
+ &Apache::lonnet::appenv(\%ValuesHash);
return ' ';
}
@@ -7447,7 +8277,7 @@ sub DrawBarGraph {
=pod
-=item DrawXYGraph
+=item * &DrawXYGraph()
Facilitates the plotting of data in an XY graph.
Puts plot definition data into the users environment in order for
@@ -7528,7 +8358,7 @@ sub DrawXYGraph {
$ValuesHash{$id.'.'.$key} = $value;
}
#
- &Apache::lonnet::appenv(%ValuesHash);
+ &Apache::lonnet::appenv(\%ValuesHash);
return ' ';
}
@@ -7537,7 +8367,7 @@ sub DrawXYGraph {
=pod
-=item DrawXYYGraph
+=item * &DrawXYYGraph()
Facilitates the plotting of data in an XY graph with two Y axes.
Puts plot definition data into the users environment in order for
@@ -7630,7 +8460,7 @@ sub DrawXYYGraph {
$ValuesHash{$id.'.'.$key} = $value;
}
#
- &Apache::lonnet::appenv(%ValuesHash);
+ &Apache::lonnet::appenv(\%ValuesHash);
return ' ';
}
@@ -7647,7 +8477,7 @@ Bad place for them but what the hell.
=over 4
-=item &chartlink
+=item * &chartlink()
Returns a link to the chart for a specific student.
@@ -7686,9 +8516,9 @@ sub chartlink {
=over 4
-=item &restore_course_settings
+=item * &restore_course_settings()
-=item &store_course_settings
+=item * &store_course_settings()
Restores/Store indicated form parameters from the course environment.
Will not overwrite existing values of the form parameters.
@@ -7762,7 +8592,7 @@ sub store_settings {
'got error:'.$put_result);
}
# Make sure these settings stick around in this session, too
- &Apache::lonnet::appenv(%AppHash);
+ &Apache::lonnet::appenv(\%AppHash);
return;
}
@@ -7799,7 +8629,7 @@ sub restore_settings {
=over 4
-=item &build_recipient_list
+=item * &build_recipient_list()
Build recipient lists for three types of e-mail:
(a) Error Reports, (b) Package Updates, (c) Help requests, generated by
@@ -7812,7 +8642,9 @@ defdom (domain for which to retrieve con
origmail (scalar - email address of recipient from loncapa.conf,
i.e., predates configuration by DC via domainprefs.pm
-Returns: comma separated list of addresses to which to send e-mail.
+Returns: comma separated list of addresses to which to send e-mail.
+
+=back
=cut
@@ -7840,8 +8672,10 @@ sub build_recipient_list {
} elsif ($origmail ne '') {
push(@recipients,$origmail);
}
- if ($defmail ne '') {
- push(@recipients,$defmail);
+ if (defined($defmail)) {
+ if ($defmail ne '') {
+ push(@recipients,$defmail);
+ }
}
if ($otheremails) {
my @others;
@@ -7863,13 +8697,347 @@ sub build_recipient_list {
############################################################
############################################################
+=pod
+
+=head1 Course Catalog Routines
+
+=over 4
+
+=item * &gather_categories()
+
+Converts category definitions - keys of categories hash stored in
+coursecategories in configuration.db on the primary library server in a
+domain - to an array. Also generates javascript and idx hash used to
+generate Domain Coordinator interface for editing Course Categories.
+
+Inputs:
+
+categories (reference to hash of category definitions).
+
+cats (reference to array of arrays/hashes which encapsulates hierarchy of
+ categories and subcategories).
+
+idx (reference to hash of counters used in Domain Coordinator interface for
+ editing Course Categories).
+
+jsarray (reference to array of categories used to create Javascript arrays for
+ Domain Coordinator interface for editing Course Categories).
+
+Returns: nothing
+
+Side effects: populates cats, idx and jsarray.
+
+=cut
+
+sub gather_categories {
+ my ($categories,$cats,$idx,$jsarray) = @_;
+ my %counters;
+ my $num = 0;
+ foreach my $item (keys(%{$categories})) {
+ my ($cat,$container,$depth) = map { &unescape($_); } split(/:/,$item);
+ if ($container eq '' && $depth == 0) {
+ $cats->[$depth][$categories->{$item}] = $cat;
+ } else {
+ $cats->[$depth]{$container}[$categories->{$item}] = $cat;
+ }
+ my ($escitem,$tail) = split(/:/,$item,2);
+ if ($counters{$tail} eq '') {
+ $counters{$tail} = $num;
+ $num ++;
+ }
+ if (ref($idx) eq 'HASH') {
+ $idx->{$item} = $counters{$tail};
+ }
+ if (ref($jsarray) eq 'ARRAY') {
+ push(@{$jsarray->[$counters{$tail}]},$item);
+ }
+ }
+ return;
+}
+
+=pod
+
+=item * &extract_categories()
+
+Used to generate breadcrumb trails for course categories.
+
+Inputs:
+
+categories (reference to hash of category definitions).
+
+cats (reference to array of arrays/hashes which encapsulates hierarchy of
+ categories and subcategories).
+
+trails (reference to array of breacrumb trails for each category).
+
+allitems (reference to hash - key is category key
+ (format: escaped(name):escaped(parent category):depth in hierarchy).
+
+idx (reference to hash of counters used in Domain Coordinator interface for
+ editing Course Categories).
+
+jsarray (reference to array of categories used to create Javascript arrays for
+ Domain Coordinator interface for editing Course Categories).
+
+subcats (reference to hash of arrays containing all subcategories within each
+ category, -recursive)
+
+Returns: nothing
+
+Side effects: populates trails and allitems hash references.
+
+=cut
+
+sub extract_categories {
+ my ($categories,$cats,$trails,$allitems,$idx,$jsarray,$subcats) = @_;
+ if (ref($categories) eq 'HASH') {
+ &gather_categories($categories,$cats,$idx,$jsarray);
+ if (ref($cats->[0]) eq 'ARRAY') {
+ for (my $i=0; $i<@{$cats->[0]}; $i++) {
+ my $name = $cats->[0][$i];
+ my $item = &escape($name).'::0';
+ my $trailstr;
+ if ($name eq 'instcode') {
+ $trailstr = &mt('Official courses (with institutional codes)');
+ } else {
+ $trailstr = $name;
+ }
+ if ($allitems->{$item} eq '') {
+ push(@{$trails},$trailstr);
+ $allitems->{$item} = scalar(@{$trails})-1;
+ }
+ my @parents = ($name);
+ if (ref($cats->[1]{$name}) eq 'ARRAY') {
+ for (my $j=0; $j<@{$cats->[1]{$name}}; $j++) {
+ my $category = $cats->[1]{$name}[$j];
+ if (ref($subcats) eq 'HASH') {
+ push(@{$subcats->{$item}},&escape($category).':'.&escape($name).':1');
+ }
+ &recurse_categories($cats,2,$category,$trails,$allitems,\@parents,$subcats);
+ }
+ } else {
+ if (ref($subcats) eq 'HASH') {
+ $subcats->{$item} = [];
+ }
+ }
+ }
+ }
+ }
+ return;
+}
+
+=pod
+
+=item *&recurse_categories()
+
+Recursively used to generate breadcrumb trails for course categories.
+
+Inputs:
+
+cats (reference to array of arrays/hashes which encapsulates hierarchy of
+ categories and subcategories).
+
+depth (current depth in hierarchy of categories and sub-categories - 0 indexed).
+
+category (current course category, for which breadcrumb trail is being generated).
+
+trails (reference to array of breadcrumb trails for each category).
+
+allitems (reference to hash - key is category key
+ (format: escaped(name):escaped(parent category):depth in hierarchy).
+
+parents (array containing containers directories for current category,
+ back to top level).
+
+Returns: nothing
+
+Side effects: populates trails and allitems hash references
+
+=cut
+
+sub recurse_categories {
+ my ($cats,$depth,$category,$trails,$allitems,$parents,$subcats) = @_;
+ my $shallower = $depth - 1;
+ if (ref($cats->[$depth]{$category}) eq 'ARRAY') {
+ for (my $k=0; $k<@{$cats->[$depth]{$category}}; $k++) {
+ my $name = $cats->[$depth]{$category}[$k];
+ my $item = &escape($category).':'.&escape($parents->[-1]).':'.$shallower;
+ my $trailstr = join(' -> ',(@{$parents},$category));
+ if ($allitems->{$item} eq '') {
+ push(@{$trails},$trailstr);
+ $allitems->{$item} = scalar(@{$trails})-1;
+ }
+ my $deeper = $depth+1;
+ push(@{$parents},$category);
+ if (ref($subcats) eq 'HASH') {
+ my $subcat = &escape($name).':'.$category.':'.$depth;
+ for (my $j=@{$parents}; $j>=0; $j--) {
+ my $higher;
+ if ($j > 0) {
+ $higher = &escape($parents->[$j]).':'.
+ &escape($parents->[$j-1]).':'.$j;
+ } else {
+ $higher = &escape($parents->[$j]).'::'.$j;
+ }
+ push(@{$subcats->{$higher}},$subcat);
+ }
+ }
+ &recurse_categories($cats,$deeper,$name,$trails,$allitems,$parents,
+ $subcats);
+ pop(@{$parents});
+ }
+ } else {
+ my $item = &escape($category).':'.&escape($parents->[-1]).':'.$shallower;
+ my $trailstr = join(' -> ',(@{$parents},$category));
+ if ($allitems->{$item} eq '') {
+ push(@{$trails},$trailstr);
+ $allitems->{$item} = scalar(@{$trails})-1;
+ }
+ }
+ return;
+}
+
+=pod
+
+=item *&assign_categories_table()
+
+Create a datatable for display of hierarchical categories in a domain,
+with checkboxes to allow a course to be categorized.
+
+Inputs:
+
+cathash - reference to hash of categories defined for the domain (from
+ configuration.db)
+
+currcat - scalar with an & separated list of categories assigned to a course.
+
+Returns: $output (markup to be displayed)
+
+=cut
+
+sub assign_categories_table {
+ my ($cathash,$currcat) = @_;
+ my $output;
+ if (ref($cathash) eq 'HASH') {
+ my (@cats,@trails,%allitems,%idx,@jsarray,@path,$maxdepth);
+ &extract_categories($cathash,\@cats,\@trails,\%allitems,\%idx,\@jsarray);
+ $maxdepth = scalar(@cats);
+ if (@cats > 0) {
+ my $itemcount = 0;
+ if (ref($cats[0]) eq 'ARRAY') {
+ $output = &Apache::loncommon::start_data_table();
+ my @currcategories;
+ if ($currcat ne '') {
+ @currcategories = split('&',$currcat);
+ }
+ for (my $i=0; $i<@{$cats[0]}; $i++) {
+ my $parent = $cats[0][$i];
+ my $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ next if ($parent eq 'instcode');
+ my $item = &escape($parent).'::0';
+ my $checked = '';
+ if (@currcategories > 0) {
+ if (grep(/^\Q$item\E$/,@currcategories)) {
+ $checked = ' checked="checked" ';
+ }
+ }
+ $output .= ' '.
+ ' '.$parent.' '.
+ ' ';
+ my $depth = 1;
+ push(@path,$parent);
+ $output .= &assign_category_rows($itemcount,\@cats,$depth,$parent,\@path,\@currcategories);
+ pop(@path);
+ $output .= ' ';
+ $itemcount ++;
+ }
+ $output .= &Apache::loncommon::end_data_table();
+ }
+ }
+ }
+ return $output;
+}
+
+=pod
+
+=item *&assign_category_rows()
+
+Create a datatable row for display of nested categories in a domain,
+with checkboxes to allow a course to be categorized,called recursively.
+
+Inputs:
+
+itemcount - track row number for alternating colors
+
+cats - reference to array of arrays/hashes which encapsulates hierarchy of
+ categories and subcategories.
+
+depth - current depth in hierarchy of categories and sub-categories - 0 indexed.
+
+parent - parent of current category item
+
+path - Array containing all categories back up through the hierarchy from the
+ current category to the top level.
+
+currcategories - reference to array of current categories assigned to the course
+
+Returns: $output (markup to be displayed).
+
+=cut
+
+sub assign_category_rows {
+ my ($itemcount,$cats,$depth,$parent,$path,$currcategories) = @_;
+ my ($text,$name,$item,$chgstr);
+ if (ref($cats) eq 'ARRAY') {
+ my $maxdepth = scalar(@{$cats});
+ if (ref($cats->[$depth]) eq 'HASH') {
+ if (ref($cats->[$depth]{$parent}) eq 'ARRAY') {
+ my $numchildren = @{$cats->[$depth]{$parent}};
+ my $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ $text .= ' ';
+ }
+ }
+ }
+ return $text;
+}
+
+############################################################
+############################################################
+
+
sub commit_customrole {
- my ($udom,$uname,$url,$three,$four,$five,$start,$end) = @_;
+ my ($udom,$uname,$url,$three,$four,$five,$start,$end,$context) = @_;
my $output = &mt('Assigning custom role').' "'.$five.'" by '.$four.':'.$three.' in '.$url.
($start?', '.&mt('starting').' '.localtime($start):'').
($end?', ending '.localtime($end):'').': '.
&Apache::lonnet::assigncustomrole(
- $udom,$uname,$url,$three,$four,$five,$end,$start).
+ $udom,$uname,$url,$three,$four,$five,$end,$start,undef,undef,$context).
' ';
return $output;
}
@@ -7904,7 +9072,7 @@ sub commit_standardrole {
$output = &mt('Assigning').' '.$three.' in '.$url.
($start?', '.&mt('starting').' '.localtime($start):'').
($end?', '.&mt('ending').' '.localtime($end):'').': ';
- my $result = &Apache::lonnet::assignrole($udom,$uname,$url,$three,$end,$start);
+ my $result = &Apache::lonnet::assignrole($udom,$uname,$url,$three,$end,$start,'','',$context);
if ($context eq 'auto') {
$output .= $result.$linefeed;
} else {
@@ -7939,7 +9107,7 @@ sub commit_studentrole {
}
$oldsecurl = $uurl;
$expire_role_result =
- &Apache::lonnet::assignrole($udom,$uname,$uurl,'st',$now);
+ &Apache::lonnet::assignrole($udom,$uname,$uurl,'st',$now,'','',$context);
if ($env{'request.course.sec'} ne '') {
if ($expire_role_result eq 'refused') {
my @roles = ('st');
@@ -7962,7 +9130,7 @@ sub commit_studentrole {
}
}
if (($expire_role_result eq 'ok') || ($secchange == 0)) {
- $modify_section_result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,'','',$cid);
+ $modify_section_result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,'','',$cid,'',$context);
if ($modify_section_result =~ /^ok/) {
if ($secchange == 1) {
if ($sec eq '') {
@@ -8371,10 +9539,10 @@ sub construct_course {
$outcome .= ($fatal?$errtext:'read ok').' - ';
my $title; my $url;
if ($args->{'firstres'} eq 'syl') {
- $title='Syllabus';
+ $title=&mt('Syllabus');
$url='/public/'.$$crsudom.'/'.$$crsunum.'/syllabus';
} else {
- $title='Navigate Contents';
+ $title=&mt('Navigate Contents');
$url='/adm/navmaps';
}
@@ -8428,28 +9596,14 @@ sub icon {
return &lonhttpdurl($iconname);
}
-sub lonhttpd_port {
- my $lonhttpd_port=$Apache::lonnet::perlvar{'lonhttpdPort'};
- if (!defined($lonhttpd_port)) { $lonhttpd_port='8080'; }
- # IE doesn't like a secure page getting images from a non-secure
- # port (when logging we haven't parsed the browser type so default
- # back to secure
- if ((!exists($env{'browser.type'}) || $env{'browser.type'} eq 'explorer')
- && $ENV{'SERVER_PORT'} == 443) {
- return 443;
- }
- return $lonhttpd_port;
-
-}
-
sub lonhttpdurl {
+#
+# Had been used for "small fry" static images on separate port 8080.
+# Modify here if lightweight http functionality desired again.
+# Currently eliminated due to increasing firewall issues.
+#
my ($url)=@_;
-
- my $lonhttpd_port = &lonhttpd_port();
- if ($lonhttpd_port == 443) {
- return 'https://'.$ENV{'SERVER_NAME'}.$url;
- }
- return 'http://'.$ENV{'SERVER_NAME'}.':'.$lonhttpd_port.$url;
+ return $url;
}
sub connection_aborted {
@@ -8527,7 +9681,7 @@ sub init_user_environment {
}
# Give them a new cookie
my $id = ($args->{'robot'} ? 'robot'.$args->{'robot'}
- : $now);
+ : $now.$$.int(rand(10000)));
$cookie="$username\_$id\_$domain\_$authhost";
# Initialize roles
@@ -8627,8 +9781,8 @@ sub init_user_environment {
}
untie(%disk_env);
} else {
- &Apache::lonnet::logthis("WARNING: ".
- 'Could not create environment storage in lonauth: '.$!.' ');
+ &Apache::lonnet::logthis("WARNING: ".
+ 'Could not create environment storage in lonauth: '.$!.' ');
return 'error: '.$!;
}
}
@@ -8642,12 +9796,52 @@ sub init_user_environment {
sub _add_to_env {
my ($idf,$env_data,$prefix) = @_;
- while (my ($key,$value) = each(%$env_data)) {
- $idf->{$prefix.$key} = $value;
- $env{$prefix.$key} = $value;
+ if (ref($env_data) eq 'HASH') {
+ while (my ($key,$value) = each(%$env_data)) {
+ $idf->{$prefix.$key} = $value;
+ $env{$prefix.$key} = $value;
+ }
+ }
+}
+
+# --- Get the symbolic name of a problem and the url
+sub get_symb {
+ my ($request,$silent) = @_;
+ (my $url=$env{'form.url'}) =~ s-^http://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;
+ my $symb=($env{'form.symb'} ne '' ? $env{'form.symb'} : (&Apache::lonnet::symbread($url)));
+ if ($symb eq '') {
+ if (!$silent) {
+ $request->print("Unable to handle ambiguous references:$url:.");
+ return ();
+ }
}
+ &Apache::lonenc::check_decrypt(\$symb);
+ return ($symb);
}
+# --------------------------------------------------------------Get annotation
+
+sub get_annotation {
+ my ($symb,$enc) = @_;
+
+ my $key = $symb;
+ if (!$enc) {
+ $key =
+ &Apache::lonnet::clutter((&Apache::lonnet::decode_symb($symb))[2]);
+ }
+ my %annotation=&Apache::lonnet::get('nohist_annotations',[$key]);
+ return $annotation{$key};
+}
+
+sub clean_symb {
+ my ($symb) = @_;
+
+ &Apache::lonenc::check_decrypt(\$symb);
+ my $enc = $env{'request.enc'};
+ delete($env{'request.enc'});
+
+ return ($symb,$enc);
+}
=pod