--- loncom/interface/loncommon.pm 2014/01/27 02:21:30 1.1172
+++ loncom/interface/loncommon.pm 2015/02/25 19:22:24 1.1206
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# a pile of common routines
#
-# $Id: loncommon.pm,v 1.1172 2014/01/27 02:21:30 raeburn Exp $
+# $Id: loncommon.pm,v 1.1206 2015/02/25 19:22:24 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -69,12 +69,15 @@ use Apache::lontexconvert();
use Apache::lonclonecourse();
use Apache::lonuserutils();
use Apache::lonuserstate();
+use Apache::courseclassifier();
use LONCAPA qw(:DEFAULT :match);
use DateTime::TimeZone;
use DateTime::Locale::Catalog;
use Text::Aspell;
use Authen::Captcha;
use Captcha::reCAPTCHA;
+use Crypt::DES;
+use DynaLoader; # for Crypt::DES version
# ---------------------------------------------- Designs
use vars qw(%defaultdesign);
@@ -1313,8 +1316,10 @@ sub helpLatexCheatsheet {
.&help_open_topic('Other_Symbols',&mt('Other Symbols'),$stayOnPage,undef,600)
.'';
unless ($not_author) {
- $out .= ' '
- .&help_open_topic('Authoring_Output_Tags',&mt('Output Tags'),$stayOnPage,undef,600)
+ $out .= ''
+ .&help_open_topic('Authoring_Output_Tags',&mt('Output Tags'),$stayOnPage,undef,600)
+ .' '
+ .&help_open_topic('Authoring_Multilingual_Problems',&mt('How to create problems in different languages'),$stayOnPage,undef,600)
.'';
}
$out .= ''; # End cheatsheet
@@ -1752,6 +1757,241 @@ RESIZE
}
+sub colorfuleditor_js {
+ return <<"COLORFULEDIT"
+
+COLORFULEDIT
+}
+
+sub xmleditor_js {
+ return <'.&mt('History').' ';
- my (%typeparts,%lasthidden);
+ my (%typeparts,%lasthidden,%regraded,%hidestatus);
my $showsurv=&Apache::lonnet::allowed('vas',$env{'request.course.id'});
foreach my $key (sort(keys(%lasthash))) {
my ($ign,@parts) = split(/\./,$key);
@@ -3809,6 +4063,18 @@ sub get_previous_attempt {
$lasthidden{$ign.'.'.$id} = 1;
}
}
+ if ($identifier ne '') {
+ my $id = join(',',@parts);
+ if (&Apache::lonnet::EXT("resource.$id.problemstatus",$symb,
+ $domain,$username,$usec,undef,$course) =~ /^no/) {
+ $hidestatus{$ign.'.'.$id} = 1;
+ }
+ }
+ } elsif ($data eq 'regrader') {
+ if (($identifier ne '') && (@parts)) {
+ my $id = join(',',@parts);
+ $regraded{$ign.'.'.$id} = 1;
+ }
}
} else {
if ($#parts == 0) {
@@ -3820,17 +4086,60 @@ sub get_previous_attempt {
}
$prevattempts.=&end_data_table_header_row();
if ($getattempt eq '') {
+ my (%solved,%resets,%probstatus);
+ if (($identifier ne '') && (keys(%regraded) > 0)) {
+ for ($version=1;$version<=$returnhash{'version'};$version++) {
+ foreach my $id (keys(%regraded)) {
+ if (($returnhash{$version.':'.$id.'.regrader'}) &&
+ ($returnhash{$version.':'.$id.'.tries'} eq '') &&
+ ($returnhash{$version.':'.$id.'.award'} eq '')) {
+ push(@{$resets{$id}},$version);
+ }
+ }
+ }
+ }
for ($version=1;$version<=$returnhash{'version'};$version++) {
- my @hidden;
+ my (@hidden,@unsolved);
if (%typeparts) {
foreach my $id (keys(%typeparts)) {
- if (($returnhash{$version.':'.$id.'.type'} eq 'anonsurvey') || ($returnhash{$version.':'.$id.'.type'} eq 'anonsurveycred')) {
+ if (($returnhash{$version.':'.$id.'.type'} eq 'anonsurvey') ||
+ ($returnhash{$version.':'.$id.'.type'} eq 'anonsurveycred')) {
push(@hidden,$id);
+ } elsif ($identifier ne '') {
+ unless (($returnhash{$version.':'.$id.'.type'} eq 'survey') ||
+ ($returnhash{$version.':'.$id.'.type'} eq 'surveycred') ||
+ ($hidestatus{$id})) {
+ next if ((ref($resets{$id}) eq 'ARRAY') && grep(/^\Q$version\E$/,@{$resets{$id}}));
+ if ($returnhash{$version.':'.$id.'.solved'} eq 'correct_by_student') {
+ push(@{$solved{$id}},$version);
+ } elsif (($returnhash{$version.':'.$id.'.solved'} ne '') &&
+ (ref($solved{$id}) eq 'ARRAY')) {
+ my $skip;
+ if (ref($resets{$id}) eq 'ARRAY') {
+ foreach my $reset (@{$resets{$id}}) {
+ if ($reset > $solved{$id}[-1]) {
+ $skip=1;
+ last;
+ }
+ }
+ }
+ unless ($skip) {
+ my ($ign,$partslist) = split(/\./,$id,2);
+ push(@unsolved,$partslist);
+ }
+ }
+ }
}
}
}
$prevattempts.=&start_data_table_row().
- ''.&mt('Transaction [_1]',$version).' ';
+ ''.&mt('Transaction [_1]',$version);
+ if (@unsolved) {
+ $prevattempts .= '';
+ }
+ $prevattempts .= ' ';
if (@hidden) {
foreach my $key (sort(keys(%lasthash))) {
next if ($key =~ /\.foilorder$/);
@@ -3846,7 +4155,7 @@ sub get_previous_attempt {
if (($data eq 'award') || ($data eq 'awarddetail')) {
my $value = &format_previous_attempt_value($key,
$returnhash{$version.':'.$key});
- $prevattempts.=''.&HTML::Entities::encode($value, '"<>&').' ';
+ $prevattempts.=''.$value.' ';
} else {
$prevattempts.=' ';
}
@@ -3854,7 +4163,7 @@ sub get_previous_attempt {
if ($key =~ /\./) {
my $value = &format_previous_attempt_value($key,
$returnhash{$version.':'.$key});
- $prevattempts.=''.&HTML::Entities::encode($value, '"<>&').' ';
+ $prevattempts.=''.$value.' ';
} else {
$prevattempts.=' ';
}
@@ -3865,7 +4174,7 @@ sub get_previous_attempt {
next if ($key =~ /\.foilorder$/);
my $value = &format_previous_attempt_value($key,
$returnhash{$version.':'.$key});
- $prevattempts.=''.&HTML::Entities::encode($value, '"<>&').' ';
+ $prevattempts.=''.$value.' ';
}
}
$prevattempts.=&end_data_table_row();
@@ -3890,7 +4199,7 @@ sub get_previous_attempt {
if ($key =~/$regexp$/ && (defined &$gradesub)) {
$value = &$gradesub($value);
}
- $prevattempts.=''. &HTML::Entities::encode($value, '"<>&').' ';
+ $prevattempts.=''. $value.' ';
} else {
$prevattempts.=' ';
}
@@ -3899,14 +4208,14 @@ sub get_previous_attempt {
if ($key =~/$regexp$/ && (defined &$gradesub)) {
$value = &$gradesub($value);
}
- $prevattempts.=''.&HTML::Entities::encode($value, '"<>&').' ';
+ $prevattempts.=''.$value.' ';
}
} else {
my $value = &format_previous_attempt_value($key,$lasthash{$key});
if ($key =~/$regexp$/ && (defined &$gradesub)) {
$value = &$gradesub($value);
}
- $prevattempts.=''.&HTML::Entities::encode($value, '"<>&').' ';
+ $prevattempts.=''.$value.' ';
}
}
$prevattempts.= &end_data_table_row().&end_data_table();
@@ -3927,11 +4236,13 @@ sub get_previous_attempt {
sub format_previous_attempt_value {
my ($key,$value) = @_;
if (($key =~ /timestamp/) || ($key=~/duedate/)) {
- $value = &Apache::lonlocal::locallocaltime($value);
+ $value = &Apache::lonlocal::locallocaltime($value);
} elsif (ref($value) eq 'ARRAY') {
- $value = '('.join(', ', @{ $value }).')';
+ $value = &HTML::Entities::encode('('.join(', ', @{ $value }).')','"<>&');
} elsif ($key =~ /answerstring$/) {
my %answers = &Apache::lonnet::str2hash($value);
+ my @answer = %answers;
+ %answers = map {&HTML::Entities::encode($_, '"<>&')} @answer;
my @anskeys = sort(keys(%answers));
if (@anskeys == 1) {
my $answer = $answers{$anskeys[0]};
@@ -3954,7 +4265,7 @@ sub format_previous_attempt_value {
}
}
} else {
- $value = &unescape($value);
+ $value = &HTML::Entities::encode(&unescape($value), '"<>&');
}
return $value;
}
@@ -4315,23 +4626,20 @@ sub findallcourses {
###############################################
sub blockcheck {
- my ($setters,$activity,$uname,$udom,$url) = @_;
+ my ($setters,$activity,$uname,$udom,$url,$is_course) = @_;
- if (!defined($udom)) {
+ if (defined($udom) && defined($uname)) {
+ # If uname and udom are for a course, check for blocks in the course.
+ if (($is_course) || (&Apache::lonnet::is_course($udom,$uname))) {
+ my ($startblock,$endblock,$triggerblock) =
+ &get_blocks($setters,$activity,$udom,$uname,$url);
+ return ($startblock,$endblock,$triggerblock);
+ }
+ } else {
$udom = $env{'user.domain'};
- }
- if (!defined($uname)) {
$uname = $env{'user.name'};
}
- # If uname and udom are for a course, check for blocks in the course.
-
- if (&Apache::lonnet::is_course($udom,$uname)) {
- my ($startblock,$endblock,$triggerblock) =
- &get_blocks($setters,$activity,$udom,$uname,$url);
- return ($startblock,$endblock,$triggerblock);
- }
-
my $startblock = 0;
my $endblock = 0;
my $triggerblock = '';
@@ -4341,7 +4649,8 @@ sub blockcheck {
# boards, chat or groups, check for blocking in current course only.
if (($activity eq 'boards' || $activity eq 'chat' ||
- $activity eq 'groups') && ($env{'request.course.id'})) {
+ $activity eq 'groups' || $activity eq 'printout') &&
+ ($env{'request.course.id'})) {
foreach my $key (keys(%live_courses)) {
if ($key ne $env{'request.course.id'}) {
delete($live_courses{$key});
@@ -4605,12 +4914,12 @@ sub parse_block_record {
}
sub blocking_status {
- my ($activity,$uname,$udom,$url) = @_;
+ my ($activity,$uname,$udom,$url,$is_course) = @_;
my %setters;
# check for active blocking
my ($startblock,$endblock,$triggerblock) =
- &blockcheck(\%setters,$activity,$uname,$udom,$url);
+ &blockcheck(\%setters,$activity,$uname,$udom,$url,$is_course);
my $blocked = 0;
if ($startblock && $endblock) {
$blocked = 1;
@@ -4665,13 +4974,13 @@ END_BLOCK
###############################################
sub check_ip_acc {
- my ($acc)=@_;
+ my ($acc,$clientip)=@_;
&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 $ip=$env{'request.host'} || $ENV{'REMOTE_ADDR'} || $clientip;
my $name;
foreach my $pattern (split(',',$acc)) {
@@ -5147,7 +5456,10 @@ sub bodytag {
@design{keys(%$addentries)} = @$addentries{keys(%$addentries)};
# role and realm
- my ($role,$realm) = split(/\./,$env{'request.role'},2);
+ my ($role,$realm) = split(m{\./},$env{'request.role'},2);
+ if ($realm) {
+ $realm = '/'.$realm;
+ }
if ($role eq 'ca') {
my ($rdom,$rname) = ($realm =~ m{^/($match_domain)/($match_username)$});
$realm = &plainname($rname,$rdom);
@@ -6329,6 +6641,10 @@ span.LC_cusr_subheading {
font-size: 85%;
}
+span.LC_math-error {
+ border: solid 1px red; min-width: 1px;
+}
+
div.LC_docs_entry_move {
border: 1px solid #BBBBBB;
background: #DDDDDD;
@@ -6478,6 +6794,7 @@ div.LC_edit_problem_footer div,
div.LC_edit_problem_editxml_header,
div.LC_edit_problem_editxml_header div {
margin-top: 5px;
+ z-index: 100;
}
div.LC_edit_problem_header_title {
@@ -6495,7 +6812,12 @@ table.LC_edit_problem_header_title {
div.LC_edit_problem_discards {
float: left;
- padding-bottom: 5px;
+}
+
+div.LC_edit_actionbar {
+ margin: -5px 0px 0px 0px !important;
+ background-color: $sidebg;
+ height: 31px;
}
div.LC_edit_problem_saves {
@@ -6516,6 +6838,10 @@ div.LC_edit_problem_saves {
margin-left: 40px;
}
+#LC_edit_problem_codemirror div{
+ margin-left: 0px;
+}
+
img.stift {
border-width: 0;
vertical-align: middle;
@@ -6630,7 +6956,6 @@ fieldset > legend {
ol.LC_primary_menu {
margin: 0;
padding: 0;
- background-color: $pgbg_or_bgcolor;
}
ol#LC_PathBreadcrumbs {
@@ -6642,23 +6967,48 @@ ol.LC_primary_menu li {
vertical-align: middle;
text-align: left;
list-style: none;
+ position: relative;
float: left;
+ z-index: 100; /* will be displayed above codemirror and underneath the help-layer */
+ line-height: 1.5em;
}
-ol.LC_primary_menu li a {
+ol.LC_primary_menu li a,
+ol.LC_primary_menu li p {
display: block;
margin: 0;
padding: 0 5px 0 10px;
text-decoration: none;
}
-ol.LC_primary_menu li ul {
+ol.LC_primary_menu li p span.LC_primary_menu_innertitle {
+ display: inline-block;
+ width: 95%;
+ text-align: left;
+}
+
+ol.LC_primary_menu li p span.LC_primary_menu_innerarrow {
+ display: inline-block;
+ width: 5%;
+ float: right;
+ text-align: right;
+ font-size: 70%;
+}
+
+ol.LC_primary_menu ul {
display: none;
- width: 10em;
+ width: 15em;
background-color: $data_table_light;
+ position: absolute;
+ top: 100%;
}
-ol.LC_primary_menu li:hover ul, ol.LC_primary_menu li.hover ul {
+ol.LC_primary_menu ul ul {
+ left: 100%;
+ top: 0;
+}
+
+ol.LC_primary_menu li:hover > ul, ol.LC_primary_menu li.hover > ul {
display: block;
position: absolute;
margin: 0;
@@ -6667,15 +7017,21 @@ ol.LC_primary_menu li:hover ul, ol.LC_pr
}
ol.LC_primary_menu li:hover li, ol.LC_primary_menu li.hover li {
+/* First Submenu -> size should be smaller than the menu title of the whole menu */
font-size: 90%;
vertical-align: top;
float: none;
border-left: 1px solid black;
border-right: 1px solid black;
+/* A dark bottom border to visualize different menu options;
+overwritten in the create_submenu routine for the last border-bottom of the menu */
+ border-bottom: 1px solid $data_table_dark;
}
-ol.LC_primary_menu li:hover li a, ol.LC_primary_menu li.hover li a {
- background-color:$data_table_light;
+ol.LC_primary_menu li li p:hover {
+ color:$button_hover;
+ text-decoration:none;
+ background-color:$data_table_dark;
}
ol.LC_primary_menu li li a:hover {
@@ -6683,6 +7039,11 @@ ol.LC_primary_menu li li a:hover {
background-color:$data_table_dark;
}
+/* Font-size equal to the size of the predecessors*/
+ol.LC_primary_menu li:hover li li {
+ font-size: 100%;
+}
+
ol.LC_primary_menu li img {
vertical-align: bottom;
height: 1.1em;
@@ -7294,7 +7655,10 @@ sub headtag {
''.
&font_settings($args);
- my $inhibitprint = &print_suppression();
+ my $inhibitprint;
+ if ($args->{'print_suppress'}) {
+ $inhibitprint = &print_suppression();
+ }
if (!$args->{'frameset'}) {
$result .= &Apache::lonhtmlcommon::htmlareaheaders();
@@ -7420,7 +7784,7 @@ sub print_suppression {
}
my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
- my $blocked = &blocking_status('printout',$cnum,$cdom);
+ my $blocked = &blocking_status('printout',$cnum,$cdom,undef,1);
if ($blocked) {
my $checkrole = "cm./$cdom/$cnum";
if ($env{'request.course.sec'} ne '') {
@@ -7652,9 +8016,13 @@ function set_wishlistlink(title, path) {
title = document.title;
title = title.replace(/^LON-CAPA /,'');
}
+ title = encodeURIComponent(title);
+ title = title.replace("'","\\\'");
if (!path) {
path = location.pathname;
}
+ path = encodeURIComponent(path);
+ path = path.replace("'","\\\'");
Win = window.open('/adm/wishlist?mode=newLink&setTitle='+title+'&setPath='+path,
'wishlistNewLink','width=560,height=350,scrollbars=0');
}
@@ -7697,10 +8065,11 @@ var modalWindow = {
};
var openMyModal = function(source,width,height,scrolling,transparency,style)
{
+ source = source.replace("'","'");
modalWindow.windowId = "myModal";
modalWindow.width = width;
modalWindow.height = height;
- modalWindow.content = "
'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.', + $disk_quota,$current_disk_usage).'
'; return ('will_exceed_quota',$msg); } } @@ -10924,21 +11308,21 @@ sub check_for_upload { } } 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('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 = ''; + 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(' A file by that name: [_1] was found in [_2].',''.$fname.'',$port_path.$env{'form.currentpath'}); - $msg .= '
'; + $msg .= ''; return ('existingfile',$msg); } } @@ -11036,7 +11420,7 @@ sub decompress_form { "$topdir/media/player.swf", "$topdir/media/swfobject.js", "$topdir/media/expressInstall.swf"); - my @camtasia8 = ("$topdir/","$topdir/$topdir.html", + my @camtasia8_1 = ("$topdir/","$topdir/$topdir.html", "$topdir/$topdir.mp4", "$topdir/$topdir\_config.xml", "$topdir/$topdir\_controller.swf", @@ -11058,13 +11442,36 @@ sub decompress_form { "$topdir/skins/express_show/", "$topdir/skins/express_show/player-min.css", "$topdir/skins/express_show/spritesheet.png"); + my @camtasia8_4 = ("$topdir/","$topdir/$topdir.html", + "$topdir/$topdir.mp4", + "$topdir/$topdir\_config.xml", + "$topdir/$topdir\_controller.swf", + "$topdir/$topdir\_embed.css", + "$topdir/$topdir\_First_Frame.png", + "$topdir/$topdir\_player.html", + "$topdir/$topdir\_Thumbnails.png", + "$topdir/playerProductInstall.swf", + "$topdir/scripts/", + "$topdir/scripts/config_xml.js", + "$topdir/scripts/techsmith-smart-player.min.js", + "$topdir/skins/", + "$topdir/skins/configuration_express.xml", + "$topdir/skins/express_show/", + "$topdir/skins/express_show/spritesheet.min.css", + "$topdir/skins/express_show/spritesheet.png", + "$topdir/skins/express_show/techsmith-smart-player.min.css"); my @diffs = &compare_arrays(\@paths,\@camtasia6); if (@diffs == 0) { $is_camtasia = 6; } else { - @diffs = &compare_arrays(\@paths,\@camtasia8); + @diffs = &compare_arrays(\@paths,\@camtasia8_1); if (@diffs == 0) { $is_camtasia = 8; + } else { + @diffs = &compare_arrays(\@paths,\@camtasia8_4); + if (@diffs == 0) { + $is_camtasia = 8; + } } } } @@ -11263,7 +11670,7 @@ sub decompress_uploaded_file { sub process_decompression { my ($docudom,$docuname,$file,$destination,$dir_root,$hiddenelem) = @_; my ($dir,$error,$warning,$output); - if ($file !~ /\.(zip|tar|bz2|gz|tar.gz|tar.bz2|tgz)$/) { + if ($file !~ /\.(zip|tar|bz2|gz|tar.gz|tar.bz2|tgz)$/i) { $error = &mt('Filename not a supported archive file type.'). '