--- loncom/interface/lonhtmlcommon.pm 2004/11/19 19:31:13 1.96
+++ loncom/interface/lonhtmlcommon.pm 2023/02/03 04:29:22 1.358.2.19.2.7
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# a pile of common html routines
#
-# $Id: lonhtmlcommon.pm,v 1.96 2004/11/19 19:31:13 albertel Exp $
+# $Id: lonhtmlcommon.pm,v 1.358.2.19.2.7 2023/02/03 04:29:22 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -55,17 +55,206 @@ html.
package Apache::lonhtmlcommon;
+use strict;
use Time::Local;
use Time::HiRes;
use Apache::lonlocal;
-use strict;
+use Apache::lonnet;
+use HTML::Entities();
+use LONCAPA qw(:DEFAULT :match);
+
+sub java_not_enabled {
+ if (($env{'browser.mobile'}) && ($env{'browser.mobile'} =~ /^ipad|ipod|iphone$/i)) {
+ return "\n".''.
+ &mt('The required Java applet could not be started, because Java is not supported by your mobile device.').
+ "\n";
+ } else {
+ return "\n".''.
+ &mt('The required Java applet could not be started. Please make sure to have Java installed and active in your browser.').
+ "\n";
+ }
+}
+
+sub coursepreflink {
+ my ($text,$category)=@_;
+ if (&Apache::lonnet::allowed('opa',$env{'request.course.id'})) {
+ my $target =' target="_top"';
+ if (($env{'request.deeplink.login'}) && ($env{'request.deeplink.target'} eq '_self')) {
+ $target = '';
+ }
+ return '&"').'">'.$text.'';
+ } else {
+ return '';
+ }
+}
+
+sub raw_href_to_link {
+ my ($message)=@_;
+ $message=~s/(https?\:\/\/[^\s\'\"\<]+)([\s\<]|$)/$1<\/tt><\/a>$2/gi;
+ return $message;
+}
+
+sub entity_encode {
+ my ($text)=@_;
+ return &HTML::Entities::encode($text, '\'<>&"');
+}
+
+sub direct_parm_link {
+ my ($linktext,$symb,$filter,$part,$target)=@_;
+ $symb=&entity_encode($symb);
+ $filter=&entity_encode($filter);
+ $part=&entity_encode($part);
+ if (($symb) && (&Apache::lonnet::allowed('opa')) && ($target ne 'tex')) {
+ my $target=' target="_top"';
+ if (($env{'request.deeplink.login'}) && ($env{'request.deeplink.target'} eq '_self')) {
+ $target = '';
+ }
+ return "$linktext";
+ } else {
+ return $linktext;
+ }
+}
+##############################################
+##############################################
+
+=item &confirm_success()
+
+Successful completion of an operation message
+
+=cut
+
+sub confirm_success {
+ my ($message,$failure)=@_;
+ if ($failure) {
+ return ''."\n"
+ .' '."\n"
+ .$message."\n"
+ .''."\n";
+ } else {
+ return ''."\n"
+ .' '."\n"
+ .$message."\n"
+ .''."\n";
+ }
+}
+
+##############################################
+##############################################
+
+=pod
+
+=item &dragmath_button()
+
+Creates a button that launches a dragmath popup-window, in which an
+expression can be edited and pasted as LaTeX into a specified textarea.
+
+ textarea - Name of the textarea to edit.
+ helpicon - If true, show a help icon to the right of the button.
+
+=cut
+
+sub dragmath_button {
+ my ($textarea,$helpicon) = @_;
+ my $help_text;
+ if ($helpicon) {
+ $help_text = &Apache::loncommon::help_open_topic('Authoring_Math_Editor',undef,undef,undef,undef,'mathhelpicon_'.$textarea);
+ }
+ my $buttontext=&mt('Edit Math');
+ return <$help_text
+ENDDRAGMATH
+}
+
+##############################################
+
+=pod
+
+=item &dragmath_js()
+
+Javascript used to open pop-up window containing dragmath applet which
+can be used to paste LaTeX into a textarea.
+
+=cut
+
+sub dragmath_js {
+ my ($popup) = @_;
+ return <
+ //
+
+
+ENDDRAGMATHJS
+}
+
+##############################################
+##############################################
+
+=pod
+
+=item &dependencies_button()
+
+Creates a button that launches a popup-window, in which dependencies
+for the web page in the main window can be added to, replaced or deleted.
+
+=cut
+
+sub dependencies_button {
+ my $buttontext=&mt('Manage Dependencies');
+ return <<"END";
+
+END
+}
+
+##############################################
+
+=pod
+
+=item &dependencycheck_js()
+
+Javascript used to open pop-up window containing interface to manage
+dependencies for a web page uploaded diretcly to a course.
+
+=cut
+
+sub dependencycheck_js {
+ my ($symb,$title,$url,$folderpath,$uri) = @_;
+ my $link;
+ if ($symb) {
+ $link = '/adm/dependencies?symb='.&HTML::Entities::encode($symb,'<>&"');
+ } elsif ($folderpath) {
+ $link = '/adm/dependencies?folderpath='.&HTML::Entities::encode($folderpath,'<>&"');
+ $url = $uri;
+ } elsif ($uri =~ m{^/public/$match_domain/$match_courseid/syllabus$}) {
+ $link = '/adm/dependencies';
+ }
+ $link .= (($link=~/\?/)?'&':'?').'title='.
+ &HTML::Entities::encode($title,'<>&"');
+ if ($url) {
+ $link .= '&url='.&HTML::Entities::encode($url,'<>&"');
+ }
+ return <
+ //
+
+ENDJS
+}
##############################################
##############################################
=pod
-=item authorbombs
+=item &authorbombs()
=cut
@@ -75,12 +264,12 @@ use strict;
sub authorbombs {
my $url=shift;
$url=&Apache::lonnet::declutter($url);
- my ($udom,$uname)=($url=~/^(\w+)\/(\w+)\//);
+ my ($udom,$uname)=($url=~m{^($LONCAPA::domain_re)/($LONCAPA::username_re)/});
my %bombs=&Apache::lonmsg::all_url_author_res_msg($uname,$udom);
- foreach (keys %bombs) {
- if ($_=~/^$udom\/$uname\//) {
+ foreach my $bomb (keys(%bombs)) {
+ if ($bomb =~ /^$udom\/$uname\//) {
return ''.
+ '">'.
&Apache::loncommon::help_open_topic('About_Bombs');
}
}
@@ -92,29 +281,35 @@ sub authorbombs {
sub recent_filename {
my $area=shift;
- return 'nohist_recent_'.&Apache::lonnet::escape($area);
+ return 'nohist_recent_'.&escape($area);
}
sub store_recent {
- my ($area,$name,$value)=@_;
+ my ($area,$name,$value,$freeze)=@_;
my $file=&recent_filename($area);
my %recent=&Apache::lonnet::dump($file);
- if (scalar(keys(%recent))>10) {
+ if (scalar(keys(%recent))>20) {
# remove oldest value
- my $oldest=time;
+ my $oldest=time();
my $delkey='';
- foreach (keys %recent) {
- my $thistime=(split(/\&/,$recent{$_}))[0];
- if ($thistime<$oldest) {
+ foreach my $item (keys(%recent)) {
+ my $thistime=(split(/\&/,$recent{$item}))[0];
+ if (($thistime ne "always_include") && ($thistime<$oldest)) {
$oldest=$thistime;
- $delkey=$_;
+ $delkey=$item;
}
}
&Apache::lonnet::del($file,[$delkey]);
}
# store new value
+ my $timestamp;
+ if ($freeze) {
+ $timestamp = "always_include";
+ } else {
+ $timestamp = time();
+ }
&Apache::lonnet::put($file,{ $name =>
- time.'&'.&Apache::lonnet::escape($value) });
+ $timestamp.'&'.&escape($value) });
}
sub remove_recent {
@@ -129,11 +324,15 @@ sub select_recent {
my $return="\n'."\n";
}
@@ -625,7 +1005,7 @@ of items completed and an estimate of th
=over 4
-=item &Create_PrgWin
+=item &Create_PrgWin()
Writes javascript to the client to open a progress window and returns a
data structure used for bookkeeping.
@@ -636,27 +1016,17 @@ Inputs
=item $r Apache request
-=item $title The title of the progress window
-
-=item $heading A description (usually 1 line) of the process being initiated.
-
=item $number_to_do The total number of items being processed.
-=item $type Either 'popup' or 'inline' (popup is assumed if nothing is
- specified)
-
-=item $width Specify the width in charaters of the input field.
-
-=item $formname Only useful in the inline case, if a form already exists, this needs to be used and specfiy the name of the form, otherwise the Progress line will be created in a new form of it's own
-
-=item $inputname Only useful in the inline case, if a form and an input of type text exists, use this to specify the name of the input field
+=item $preamble Optional HTML to display before the progress bar.
=back
Returns a hash containing the progress state data structure.
+If $number_to_do is zero or null, an indeterminate progress bar will
+be used.
-
-=item &Update_PrgWin
+=item &Update_PrgWin()
Updates the text in the progress indicator. Does not increment the count.
See &Increment_PrgWin.
@@ -676,9 +1046,9 @@ Inputs:
Returns: none
-=item Increment_PrgWin
+=item Increment_PrgWin()
-Increment the count of items completed for the progress window by 1.
+Increment the count of items completed for the progress window by $step or 1 if no step is provided.
Inputs:
@@ -691,12 +1061,14 @@ Inputs:
=item $extraInfo A description of the items being iterated over. Typically
'student'.
+=item $step (optional) counter step. Will be set to default 1 if ommited. step must be greater than 0 or empty.
+
=back
Returns: none
-=item Close_PrgWin
+=item &Close_PrgWin()
Closes the progress window.
@@ -719,103 +1091,47 @@ Returns: none
########################################################
########################################################
-my $uniq=0;
-sub get_uniq_name {
- $uniq++;
- return 'uniquename'.$uniq;
-}
# Create progress
sub Create_PrgWin {
- my ($r, $title, $heading, $number_to_do,$type,$width,$formname,
- $inputname)=@_;
- if (!defined($type)) { $type='popup'; }
- if (!defined($width)) { $width=55; }
+ my ($r,$number_to_do,$preamble)=@_;
my %prog_state;
- $prog_state{'type'}=$type;
- if ($type eq 'popup') {
- $prog_state{'window'}='popwin';
- #the whole function called through timeout is due to issues
- #in mozilla Read BUG #2665 if you want to know the whole story
- &r_print($r,'");
- $prog_state{'formname'}='popremain';
- $prog_state{'inputname'}="remaining";
- } elsif ($type eq 'inline') {
- $prog_state{'window'}='window';
- if (!$formname) {
- $prog_state{'formname'}=&get_uniq_name();
- &r_print($r,'
'); }
- &Update_PrgWin($r,\%prog_state,&mt('Starting'));
- }
-
$prog_state{'done'}=0;
$prog_state{'firststart'}=&Time::HiRes::time();
$prog_state{'laststart'}=&Time::HiRes::time();
$prog_state{'max'}=$number_to_do;
-
+ &Apache::loncommon::LCprogressbar($r,$prog_state{'max'},$preamble);
return %prog_state;
}
# update progress
sub Update_PrgWin {
my ($r,$prog_state,$displayString)=@_;
- &r_print($r,'');
+ &Apache::loncommon::LCprogressbarUpdate($r,undef,$displayString,$$prog_state{'max'});
$$prog_state{'laststart'}=&Time::HiRes::time();
}
# increment progress state
sub Increment_PrgWin {
- my ($r,$prog_state,$extraInfo)=@_;
- $$prog_state{'done'}++;
+ my ($r,$prog_state,$extraInfo,$step)=@_;
+ $step = $step > 0 ? $step : 1;
+ $$prog_state{'done'} += $step;
+
+ # Catch (max modulo step) <> 0
+ my $current = $$prog_state{'done'};
+ my $last = ($$prog_state{'max'} - $current);
+ if ($last <= 0) {
+ $last = 1;
+ $current = $$prog_state{'max'};
+ }
+
my $time_est= (&Time::HiRes::time() - $$prog_state{'firststart'})/
- $$prog_state{'done'} *
- ($$prog_state{'max'}-$$prog_state{'done'});
+ $current * $last;
$time_est = int($time_est);
#
my $min = int($time_est/60);
my $sec = $time_est % 60;
- #
- my $str;
- if ($min == 0 && $sec > 1) {
- $str = '[_2] seconds';
- } elsif ($min == 1 && $sec > 1) {
- $str = '1 minute [_2] seconds';
- } elsif ($min == 1 && $sec < 2) {
- $str = '1 minute';
- } elsif ($min < 10 && $sec > 1) {
- $str = '[_1] minutes, [_2] seconds';
- } elsif ($min >= 10 || $sec < 2) {
- $str = '[_1] minutes';
- }
- $time_est = &mt($str,$min,$sec);
- #
+
my $lasttime = &Time::HiRes::time()-$$prog_state{'laststart'};
if ($lasttime > 9) {
$lasttime = int($lasttime);
@@ -824,97 +1140,119 @@ sub Increment_PrgWin {
} else {
$lasttime = sprintf("%3.2f",$lasttime);
}
- if ($lasttime == 1) {
- $lasttime = '('.$lasttime.' '.&mt('second for').' '.$extraInfo.')';
- } else {
- $lasttime = '('.$lasttime.' '.&mt('seconds for').' '.$extraInfo.')';
- }
- #
- my $user_browser = $ENV{'browser.type'} if (exists($ENV{'browser.type'}));
- my $user_os = $ENV{'browser.os'} if (exists($ENV{'browser.os'}));
- if (! defined($user_browser) || ! defined($user_os)) {
- (undef,$user_browser,undef,undef,undef,$user_os) =
- &Apache::loncommon::decode_user_agent();
- }
- if ($user_browser eq 'explorer' && $user_os =~ 'mac') {
- $lasttime = '';
+
+ $sec = 0 if ($min >= 10); # Don't show seconds if remaining time >= 10 min.
+ $sec = 1 if ( ($min == 0) && ($sec == 0) ); # Little cheating: pretend to have 1 second remaining instead of 0 to have something to display
+
+ my $timeinfo =
+ &mt('[_1]/[_2]:'
+ .' [quant,_3,minute,minutes,] [quant,_4,second ,seconds ,]remaining'
+ .' ([quant,_5,second] for '.$extraInfo.')',
+ $current,
+ $$prog_state{'max'},
+ $min,
+ $sec,
+ $lasttime);
+ my $percent=0;
+ if ($$prog_state{'max'}) {
+ $percent=int(100.*$current/$$prog_state{'max'});
}
- &r_print($r,'');
+ &Apache::loncommon::LCprogressbarUpdate($r,$percent,$timeinfo,$$prog_state{'max'});
$$prog_state{'laststart'}=&Time::HiRes::time();
}
# close Progress Line
sub Close_PrgWin {
my ($r,$prog_state)=@_;
- if ($$prog_state{'type'} eq 'popup') {
- &r_print($r,''."\n");
- } elsif ($$prog_state{'type'} eq 'inline') {
- &Update_PrgWin($r,$prog_state,&mt('Done'));
- }
+ &Apache::loncommon::LCprogressbarClose($r);
undef(%$prog_state);
}
-sub r_print {
- my ($r,$to_print)=@_;
- if ($r) {
- $r->print($to_print);
- $r->rflush();
- } else {
- print($to_print);
- }
-}
# ------------------------------------------------------- Puts directory header
sub crumbs {
- my ($uri,$target,$prefix,$form,$size,$noformat)=@_;
- if (! defined($size)) {
- $size = '+2';
- }
- my $output='';
- unless ($noformat) { $output.=' '; }
- $output.=''.$prefix.'/';
- if ($ENV{'user.adv'}) {
- my $path=$prefix.'/';
- foreach (split('/',$uri)) {
- unless ($_) { next; }
- $path.=$_;
- unless ($path eq $uri) { $path.='/'; }
- my $linkpath=$path;
- if ($form) {
- my $escaped_path = &Apache::loncommon::escape_single($path);
- $linkpath="javascript:$form.action='$escaped_path';$form.submit();";
- }
- my $escaped_linkpath = &Apache::loncommon::escape_single($linkpath);
- my $escaped_target = &Apache::loncommon::escape_single($target);
- $output.=''.$_.'/';
- }
+ my ($uri,$target,$prefix,$form,$skiplast,$onclick)=@_;
+# You cannot crumbnify uploaded or adm resources
+ if ($uri=~/^\/*(uploaded|adm)\//) { return &mt('(Internal Course/Community Content)'); }
+ if ($target) {
+ $target = ' target="'.
+ &Apache::loncommon::escape_single($target).'"';
+ }
+ my $output='';
+ $output.=$prefix.'/';
+ if (($env{'user.adv'}) || ($env{'user.author'})) {
+ my $path=$prefix.'/';
+ foreach my $dir (split('/',$uri)) {
+ if (! $dir) { next; }
+ $path .= $dir;
+ if ($path eq $uri) {
+ if ($skiplast) {
+ $output.=$dir;
+ last;
+ }
+ } else {
+ $path.='/';
+ }
+ if ($path eq '/res/') {
+ unless (&Apache::lonnet::allowed('bre',$path)) {
+ $output.="$dir/";
+ next;
+ }
+ }
+ my $href_path = &HTML::Entities::encode($path,'<>&"');
+ &Apache::loncommon::inhibit_menu_check(\$href_path);
+ if ($form) {
+ my $href = 'javascript:'.$form.".action='".$href_path."';".$form.'.submit();';
+ $output.=qq{$dir/};
+ } else {
+ $output.=qq{$dir/};
+ }
+ }
} else {
- $output.=$uri;
+ foreach my $dir (split('/',$uri)) {
+ if (! $dir) { next; }
+ $output.=$dir.'/';
+ }
}
- unless ($uri=~/\/$/) { $output=~s/\/$//; }
- return $output.''.($noformat?'':' ');
+ if ($uri !~ m|/$|) { $output=~s|/$||; }
+ $output.='';
+
+
+ return $output;
}
# --------------------- A function that generates a window for the spellchecker
sub spellheader {
- my $nothing = &javascript_nothing();
+ my $start_page=
+ &Apache::loncommon::start_page('Speller Suggestions',undef,
+ {'only_body' => 1,
+ 'js_ready' => 1,
+ 'bgcolor' => '#DDDDDD',
+ 'add_entries' => {
+ 'onload' =>
+ 'document.forms.spellcheckform.submit()',
+ }
+ });
+ my $end_page=
+ &Apache::loncommon::end_page({'js_ready' => 1});
+
+ my $nothing=&javascript_nothing();
return (<
+//