--- loncom/interface/lonhtmlcommon.pm 2009/11/14 18:54:17 1.243
+++ loncom/interface/lonhtmlcommon.pm 2025/03/03 22:03:02 1.419
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# a pile of common html routines
#
-# $Id: lonhtmlcommon.pm,v 1.243 2009/11/14 18:54:17 amueller Exp $
+# $Id: lonhtmlcommon.pm,v 1.419 2025/03/03 22:03:02 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -60,14 +60,66 @@ use Time::Local;
use Time::HiRes;
use Apache::lonlocal;
use Apache::lonnet;
-use LONCAPA;
+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.lti.login'}) && ($env{'request.lti.target'} eq 'iframe')) ||
+ (($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.lti.login'}) && ($env{'request.lti.target'} eq 'iframe')) ||
+ (($env{'request.deeplink.login'}) && ($env{'request.deeplink.target'} eq '_self'))) {
+ $target='';
+ }
+ return "$linktext";
+ } else {
+ return $linktext;
+ }
+}
##############################################
##############################################
-=pod
-
-=item confirm_success
+=item &confirm_success()
Successful completion of an operation message
@@ -76,7 +128,7 @@ Successful completion of an operation me
sub confirm_success {
my ($message,$failure)=@_;
if ($failure) {
- return ''."\n"
+ return ''."\n"
.' '."\n"
.$message."\n"
.''."\n";
@@ -93,7 +145,7 @@ sub confirm_success {
=pod
-=item dragmath_button
+=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.
@@ -107,11 +159,11 @@ sub dragmath_button {
my ($textarea,$helpicon) = @_;
my $help_text;
if ($helpicon) {
- $help_text = &Apache::loncommon::help_open_topic('Authoring_Math_Editor');
+ $help_text = &Apache::loncommon::help_open_topic('Authoring_Math_Editor',undef,undef,undef,undef,'mathhelpicon_'.$textarea);
}
my $buttontext=&mt('Edit Math');
return <$help_text
+ $help_text
ENDDRAGMATH
}
@@ -119,11 +171,11 @@ ENDDRAGMATH
=pod
-=item dragmath_js
+=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 {
@@ -134,7 +186,7 @@ sub dragmath_js {
function mathedit(textarea, doc) {
targetEntry = textarea;
targetDoc = doc;
- newwin = window.open("/adm/dragmath/applet/$popup.html","","width=565,height=500,resizable");
+ newwin = window.open("/adm/dragmath/$popup.html","","width=565,height=500,resizable");
}
// ]]>
@@ -142,13 +194,70 @@ sub dragmath_js {
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,'<>&"');
+ }
+ &js_escape(\$link);
+ return <
+ //
+
+ENDJS
+}
##############################################
##############################################
=pod
-=item authorbombs
+=item &authorbombs()
=cut
@@ -222,6 +331,9 @@ sub select_recent {
unless ($value =~/^error\:/) {
my $escaped = &Apache::loncommon::escape_url($value);
&Apache::loncommon::inhibit_menu_check(\$escaped);
+ if ($area eq 'residx') {
+ next if ((!&Apache::lonnet::allowed('bre',$value)) && (!&Apache::lonnet::allowed('bro',$value)));
+ }
$return.="\n';
@@ -279,7 +391,7 @@ sub get_recent_frozen {
=pod
-=item textbox
+=item &textbox()
=cut
@@ -299,14 +411,14 @@ sub textbox {
=pod
-=item checkbox
+=item &checkbox()
=cut
##############################################
##############################################
sub checkbox {
- my ($name,$checked,$value) = @_;
+ my ($name,$checked,$value,$special) = @_;
my $Str = '';
return $Str;
}
=pod
-=item radiobutton
+=item &radiobutton()
=cut
@@ -345,15 +457,17 @@ sub radio {
=pod
-=item &date_setter
+=item &date_setter()
&date_setter returns html and javascript for a compact date-setting form.
-To retrieve values from it, use &get_date_from_form().
-
-Inputs
+To retrieve values from it, use &get_date_from_form.
=over 4
+=item Inputs
+
+=over
+
=item $dname
The name to prepend to the form elements.
@@ -364,7 +478,8 @@ dname_hour, dname_min, and dname_sec.
The current setting for this time parameter. A unix format time
(time in seconds since the beginning of Jan 1st, 1970, GMT.
-An undefined value is taken to indicate the value is the current time.
+An undefined value is taken to indicate the value is the current time
+unless it is requested to leave it empty. See $includeempty.
Also, to be explicit, a value of 'now' also indicates the current time.
=item $special
@@ -374,60 +489,98 @@ the date_setter. See lonparmset for exa
=item $includeempty
+If it is set (true) and no date/time value is provided,
+the date/time fields are left empty.
+
=item $state
Specifies the initial state of the form elements. Either 'disabled' or empty.
-Defaults to empty, which indiciates the form elements are not disabled.
+Defaults to empty, which indicates the form elements are not disabled.
+
+=item $no_hh_mm_ss
+
+If true, text boxes for hours, minutes and seconds are omitted.
+
+=item $defhour
+
+Default value for hours (a default of 0 is used otherwise).
+
+=item $defmin
+
+Default value for minutes (a default of 0 is used otherwise).
+
+=item defsec
+
+Default value for seconds (a default of 0 is used otherwise).
+
+=item $nolink
+
+If true, a "Select calendar" link (to pop-up a calendar) is not displayed
+to the right of the items.
+
+=item $no_mm_ss
+
+If true, text boxes for minutes and seconds are omitted.
+
+=item $no_ss
+
+If true, text boxes for seconds are omitted.
=back
-Bugs
+=item Bugs
The method used to restrict user input will fail in the year 2400.
+=back
+
=cut
##############################################
##############################################
sub date_setter {
my ($formname,$dname,$currentvalue,$special,$includeempty,$state,
- $no_hh_mm_ss,$defhour,$defmin,$defsec,$nolink) = @_;
+ $no_hh_mm_ss,$defhour,$defmin,$defsec,$nolink,$no_mm_ss,$no_ss) = @_;
my $now = time;
- my $wasdefined=1;
+ my %labels = &Apache::lonlocal::texthash(
+ day => 'day',
+ month => 'month',
+ year => 'year',
+ sec => 'seconds',
+ min => 'minutes',
+ hour => 'hours',
+ );
+ my $tzname;
+ my ($sec,$min,$hour,$mday,$month,$year) = ('', '', undef,''.''.'');
+ #other potentially useful values: wkday,yrday,is_daylight_savings
+
if (! defined($state) || $state ne 'disabled') {
$state = '';
+ } else {
+ $state = 'disabled="disabled"';
}
if (! defined($no_hh_mm_ss)) {
$no_hh_mm_ss = 0;
}
if ($currentvalue eq 'now') {
- $currentvalue = $now;
+ $currentvalue = $now;
}
- if ((!defined($currentvalue)) || ($currentvalue eq '')) {
- $wasdefined=0;
- if ($includeempty) {
- $currentvalue = 0;
- } else {
- $currentvalue = $now;
- }
+
+ # Default value: Set empty date field to current time
+ # unless empty inclusion is requested
+ if ((!$includeempty) && (!$currentvalue)) {
+ $currentvalue = $now;
}
- # other potentially useful values: wkday,yrday,is_daylight_savings
- my $tzname;
- my ($sec,$min,$hour,$mday,$month,$year)=('','',undef,'','','');
+ # Do we have a date? Split it!
if ($currentvalue) {
- ($tzname,$sec,$min,$hour,$mday,$month,$year) = &get_timedates($currentvalue);
- }
- unless ($wasdefined) {
- ($tzname,$sec,$min,$hour,$mday,$month,$year) = &get_timedates($now);
- if (($defhour) || ($defmin) || ($defsec)) {
- $sec=($defsec?$defsec:0);
- $min=($defmin?$defmin:0);
- $hour=($defhour?$defhour:0);
- } elsif (!$includeempty) {
- $sec=0;
- $min=0;
- $hour=0;
- }
+ ($tzname,$sec,$min,$hour,$mday,$month,$year) = &get_timedates($currentvalue);
+
+ #No values provided for hour, min, sec? Use default 0
+ if (($defhour) || ($defmin) || ($defsec)) {
+ $sec = ($defsec ? $defsec : 0);
+ $min = ($defmin ? $defmin : 0);
+ $hour = ($defhour ? $defhour : 0);
+ }
}
my $result = "\n\n";
$result .= <
ENDJS
$result .= ' ';
- my $monthselector = qq{');
- }
+ }
+ unless (($nolink) || ($state eq 'disabled')) {
+ $result .= &mt('[_1]Select Date[_2]',$cal_link,'');
}
$result .= "\n\n";
return $result;
@@ -599,11 +761,13 @@ sub build_url {
=pod
-=item &get_date_from_form
+=item &get_date_from_form()
get_date_from_form retrieves the date specified in an &date_setter form.
-Inputs:
+=over
+
+=item Inputs:
=over 4
@@ -617,6 +781,8 @@ The unix time to use as the default in c
=back
+=back
+
Returns: Unix time represented in the form.
=cut
@@ -710,14 +876,14 @@ parameter setting wizard.
##############################################
sub pjump_javascript_definition {
my $Str = < 1,
- 'bgcolor' => '#88DDFF',
- 'js_ready' => 1});
- my $end_page = &Apache::loncommon::end_page({'js_ready' => 1});
-
- #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,&Apache::lonhtmlcommon::scripttag(
- "var popwin;
- function openpopwin () {
- popwin=open(\'\',\'popwin\',\'width=400,height=100\');".
- "popwin.document.writeln(\'".$start_page.
- "
".&mt("$heading")."<\/h4>".
- "
'); }
- &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::lonhtmlcommon::scripttag(
- $$prog_state{'window'}.'.document.'.
- $$prog_state{'formname'}.'.'.
- $$prog_state{'inputname'}.'.value="'.
- $displayString.'";'
- ));
+ &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);
@@ -1066,98 +1187,86 @@ 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::lonhtmlcommon::scripttag(
- $$prog_state{'window'}.'.document.'.
- $$prog_state{'formname'}.'.'.
- $$prog_state{'inputname'}.'.value="'.
- $$prog_state{'done'}.'/'.$$prog_state{'max'}.
- ': '.$time_est.' '.&mt('remaining').' '.$lasttime.'";'
- ));
+ &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,&Apache::lonhtmlcommon::scripttag(
- 'popwin.close()'
- ));
- } 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,$skiplast)=@_;
- if (! defined($size)) {
- $size = '+2';
- }
+ 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='';
- unless ($noformat) { $output.=' '; }
- $output.=''.$prefix.'/';
- if (($env{'user.adv'}) | ($env{'user.author'})) {
- my $path=$prefix.'/';
- foreach my $dir (split('/',$uri)) {
+ 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;
+ if ($path eq $uri) {
+ if ($skiplast) {
+ $output.=$dir;
last;
- }
- } else {
- $path.='/';
- }
+ }
+ } 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/};
- }
- }
+ &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 {
- foreach my $dir (split('/',$uri)) {
+ foreach my $dir (split('/',$uri)) {
if (! $dir) { next; }
- $output.=$dir.'/';
- }
+ $output.=$dir.'/';
+ }
}
if ($uri !~ m|/$|) { $output=~s|/$||; }
- return $output.''.($noformat?'':' ');
+ $output.='';
+
+
+ return $output;
}
# --------------------- A function that generates a window for the spellchecker
@@ -1205,49 +1314,34 @@ sub spelllink {
ENDLINK
}
-# ------------------------------------------------- Output headers for HTMLArea
-
-{
- my @htmlareafields;
- sub init_htmlareafields {
- undef(@htmlareafields);
- }
-
- sub add_htmlareafields {
- my (@newfields) = @_;
- push(@htmlareafields,@newfields);
- }
-
- sub get_htmlareafields {
- return @htmlareafields;
- }
-}
+# ------------------------------------------------- Output headers for CKEditor
sub htmlareaheaders {
- return if (&htmlareablocked());
- return if (!&htmlareabrowser());
- return (<
-ENDHEADERS
-}
-
-# ----------------------------------------------------------------- Preferences
+ my $s="";
+ if (&htmlareabrowser()) {
+ $s.=(<
+ENDEDITOR
+ }
+ $s.=(<
+
+
+
+
+
+
+
+
+
+
-sub disablelink {
- my @fields=@_;
- if (defined($#fields)) {
- unless ($#fields>=0) { return ''; }
- }
- return ''.&mt('Disable WYSIWYG Editor').'';
+ENDJQUERY
+ return $s;
}
-sub enablelink {
- my @fields=@_;
- if (defined($#fields)) {
- unless ($#fields>=0) { return ''; }
- }
- return ''.&mt('Enable WYSIWYG Editor').'';
-}
+# ----------------------------------------------------------------- Preferences
# ------------------------------------------------- lang to use in html editor
sub htmlarea_lang {
@@ -1258,30 +1352,374 @@ sub htmlarea_lang {
return $lang;
}
+# return javacsript to activate elements of .colorchooser with jpicker:
+# Caller is responsible for enclosing this in '.
- &disablelink(@fields);
+ .'';
return $output;
}
@@ -1298,12 +1736,162 @@ sub htmlareabrowser {
return 1;
}
+#
+# Should the "return to content" link be shown?
+#
+
+sub show_return_link {
+
+ unless ($env{'request.course.id'}) { return 0; }
+ if ($env{'request.noversionuri'}=~m{^/priv/} ||
+ $env{'request.uri'}=~m{^/priv/}) { return 1; }
+ return if (($env{'request.noversionuri'} eq '/adm/supplemental') &&
+ ($env{'form.folder'} ne 'supplemental'));
+ return if (($env{'form.folderpath'} ne '') &&
+ (($env{'request.noversionuri'} =~ m{^/adm/$match_domain/$match_username/aboutme$}) ||
+ ($env{'request.noversionuri'} =~ m{^/public/$match_domain/$match_courseid/syllabus$})));
+ return if (($env{'course.'.$env{'request.course.id'}.'.type'} eq 'Placement') &&
+ (!$env{'request.role.adv'}));
+ if (($env{'request.noversionuri'} =~ m{^/adm/viewclasslist($|\?)})
+ || ($env{'request.noversionuri'} =~ m{^/adm/.*/aboutme($|\?)})) {
+
+ return if ($env{'form.register'});
+ }
+ if ((($env{'request.symb'} ne '') || ($env{'form.folderpath'} ne '')) &&
+ ($env{'request.noversionuri'} =~m{^/adm/coursedocs/showdoc/uploaded/($match_domain)/($match_courseid)/(docs|supplemental)/})) {
+ my ($cdom,$cnum,$area) = ($1,$2,$3);
+ if (($env{'course.'.$env{'request.course.id'}.'.domain'} eq $cdom) &&
+ ($env{'course.'.$env{'request.course.id'}.'.num'} eq $cnum)) {
+ if (($env{'request.symb'}) && ($area eq 'docs')) {
+ my ($map,$resid,$url) = &Apache::lonnet::decode_symb($env{'request.symb'});
+ return if ($env{'request.noversionuri'} eq '/adm/coursedocs/showdoc/'.$url);
+ } elsif (($env{'form.folderpath'}) && ($area eq 'supplemental')) {
+ return;
+ }
+ }
+ }
+ return (($env{'request.noversionuri'}=~m{^/(res|public)/} &&
+ $env{'request.symb'} eq '')
+ ||
+ ($env{'request.noversionuri'}=~ m{^/cgi-bin/printout.pl})
+ ||
+ (($env{'request.noversionuri'}=~/^\/adm\//) &&
+ ($env{'request.noversionuri'}!~/^\/adm\/wrapper\//) &&
+ ($env{'request.noversionuri'}!~
+ m{^/adm/.*/(smppg|bulletinboard|ext\.tool)($|\?)})
+ ));
+}
+
+
+##
+# Set the dueDate variable...note this is done in the timezone
+# of the browser.
+#
+# @param epoch relative time at which the problem is due.
+#
+# @return the javascript fragment to set the date:
+#
+sub set_due_date {
+ my $dueStamp = shift;
+ my $duems = $dueStamp * 1000; # Javascript Date object needs ms not seconds.
+
+ my $now = time()*1000;
+
+ # This slightly obscure bit of javascript sets the dueDate variable
+ # to the time in the browser at which the problem was due.
+ # The code should correct for gross differences between the server
+ # and client's time setting
+
+ return <<"END";
+
+
+
+END
+}
+##
+# Sets the time at which the problem finished computing.
+# This just updates the serverTime and clientTime variables above.
+# Calling this in e.g. end_problem provides a better estimate of the
+# difference beetween the server and client time setting as
+# the difference contains less of the latency/problem compute time.
+#
+sub set_compute_end_time {
+
+ my $now = time()*1000; # Javascript times are in ms.
+ return <<"END";
+
+
+
+END
+}
+
+##
+# Client-side javascript to convert any dashes in text pasted
+# into textbox(es) for numericalresponse item(s) to a standard
+# minus, i.e., - . Calls to dash_to_minus_js() in end_problem()
+# and in loncommon::endbodytag() for a .page (arg: dashjs => 1)
+#
+# Will apply to any input tag with class: LC_numresponse_text.
+# Currently set in start_textline for numericalresponse items.
+#
+
+sub dash_to_minus_js {
+ return <<'ENDJS';
+
+
+
+ENDJS
+}
+
############################################################
############################################################
=pod
-=item breadcrumbs
+=item &breadcrumbs()
Compiles the previously registered breadcrumbs into an series of links.
Additionally supports a 'component', which will be displayed on the
@@ -1312,20 +1900,70 @@ A link to help for the component will be
All inputs can be undef without problems.
-Inputs: $component (the text on the right side of the breadcrumbs trail),
- $component_help
- $menulink (boolean, controls whether to include a link to /adm/menu)
- $helplink (if 'nohelp' don't include the orange help link)
- $css_class (optional name for the class to apply to the table for CSS)
- $no_mt (optional flag, 1 if &mt() is _not_ to be applied to $component
- when including the text on the right.
+=over
+
+=item Inputs:
+
+=over
+
+=item $component
+
+the text on the right side of the breadcrumbs trail
+
+=item $component_help
+
+the help item filename (without .tex extension).
+
+=item $menulink
+
+boolean, controls whether to include a link to /adm/menu
+
+=item $helplink
+
+if 'nohelp' don't include the orange help link
+
+=item $crumbs_style
+
+optional style attribute for div containing breadcrumbs
+unless called from docs_breadcrumbs
+
+=item $no_mt
+
+optional flag, 1 if &mt() is _not_ to be applied to $component when including the text on the right
+
+=item $CourseBreadcrumbs
+
+optional flag, 1 if &breadcrumbs called from &docs_breadcrumbs, because breadcrumbs are being
+used to display hierarchy for current folder shown in the Course Editor.
+
+=item $topic_help
+
+optional help item to be displayed on right side of the breadcrumbs row, using
+loncommon::help_open_topic() to generate the link.
+
+=item $topic_help_text
+
+text to include in the link in the optional help item ($topic_help) on the right
+side of the breadcrumbs row.
+
+=item $links_target
+
+optionally includes the target (_top, _parent or _self) for (i) initial
+$menulink item in the breadcrumbs (if present), (ii) return to last location
+(if present), and (iii) help item at the right side of breadcrumbs menu,
+created by loncommon::help_open_topic() or loncommon::help_open_menu().
+
+=back
+
+=back
+
Returns a string containing breadcrumbs for the current page.
-=item clear_breadcrumbs
+=item &clear_breadcrumbs()
Clears the previously stored breadcrumbs.
-=item add_breadcrumb
+=item &add_breadcrumb()
Pushes a breadcrumb on the stack of crumbs.
@@ -1345,10 +1983,9 @@ returns: nothing
my %tools = ();
sub breadcrumbs {
- my ($component,$component_help,$menulink,$helplink,$css_class,$no_mt, $CourseBreadcrumbs) = @_;
+ my ($component,$component_help,$menulink,$helplink,$crumbs_style,$no_mt,
+ $CourseBreadcrumbs,$topic_help,$topic_help_text,$links_target) = @_;
#
- $css_class ||= 'LC_breadcrumbs';
-
# Make the faq and bug data cascade
my $faq = '';
my $bug = '';
@@ -1361,17 +1998,43 @@ returns: nothing
# The first one should be the course or a menu link
if (!defined($menulink)) { $menulink=1; }
if ($menulink) {
+ if ($env{'request.course.id'}) {
+ my ($menucoll,$deeplinkmenu,$menuref) = &Apache::loncommon::menucoll_in_effect();
+ if (($menucoll) && (ref($menuref) eq 'HASH')) {
+ if ($menuref->{'main'} eq 'n') {
+ undef($menulink);
+ }
+ }
+ }
+ }
+ if ($menulink) {
my $description = 'Menu';
my $no_mt_descr = 0;
- if (exists($env{'request.course.id'}) &&
- $env{'request.course.id'} ne '') {
+ if ((exists($env{'request.course.id'})) &&
+ ($env{'request.course.id'} ne '') &&
+ ($env{'course.'.$env{'request.course.id'}.'.description'} ne '')) {
$description =
$env{'course.'.$env{'request.course.id'}.'.description'};
$no_mt_descr = 1;
+ if ($env{'request.noversionuri'} =~
+ m{^/?public/($match_domain)/($match_courseid)/syllabus$}) {
+ unless (($env{'course.'.$env{'request.course.id'}.'.domain'} eq $1) &&
+ ($env{'course.'.$env{'request.course.id'}.'.num'} eq $2)) {
+ $description = 'Menu';
+ $no_mt_descr = 0;
+ }
+ }
+ }
+ my $target = '_top';
+ if ($links_target) {
+ $target = $links_target;
+ } elsif ((($env{'request.lti.login'}) && ($env{'request.lti.target'} eq 'iframe')) ||
+ (($env{'request.deeplink.login'}) && ($env{'request.deeplink.target'} eq '_self'))) {
+ $target='';
}
$menulink = { href =>'/adm/menu',
title =>'Go to main menu',
- target =>'_top',
+ target =>$target,
text =>$description,
no_mt =>$no_mt_descr, };
if($last) {
@@ -1382,29 +2045,50 @@ returns: nothing
$last = $menulink;
}
}
- my $links = join "",
- map {
- $faq = $_->{'faq'} if (exists($_->{'faq'}));
- $bug = $_->{'bug'} if (exists($_->{'bug'}));
- $help = $_->{'help'} if (exists($_->{'help'}));
-
- my $result = htmltag( 'a',
- $_->{no_mt} ?
- $_->{text} : mt($_->{text}),
- {
- href => $_->{href},
- title => $_->{no_mt} ?
- $_->{title} : mt($_->{title}),
- target => $_->{target},
- });
- $result = htmltag( 'li', "$result $crumbsymbol");
- } @Crumbs;
+ my $links;
+ if ((&show_return_link) && (!$CourseBreadcrumbs) && (ref($last) eq 'HASH')) {
+ my $alttext = &mt('Go Back');
+ my $hashref = { href => '/adm/flip?postdata=return:',
+ title => &mt('Back to most recent content resource'),
+ class => 'LC_menubuttons_link',
+ };
+ if ($links_target) {
+ $hashref->{'target'} = $links_target;
+ }
+ $links=&htmltag( 'a','',
+ $hashref);
+ $links=&htmltag('li',$links);
+ }
+ $links.= join "",
+ map {
+ $faq = $_->{'faq'} if (exists($_->{'faq'}));
+ $bug = $_->{'bug'} if (exists($_->{'bug'}));
+ $help = $_->{'help'} if (exists($_->{'help'}));
+
+ my $result = $_->{no_mt} ? $_->{text} : &mt($_->{text});
+
+ if ($_->{href}){
+ $result = &htmltag( 'a', $result,
+ { href => $_->{href},
+ title => $_->{no_mt} ? $_->{title} : &mt($_->{title}),
+ target => $_->{target}, });
+ }
+
+ $result = &htmltag( 'li', "$result $crumbsymbol");
+ } @Crumbs;
#should the last Element be translated?
- $links .= htmltag( 'li',
- htmltag( 'b',
- $last->{'no_mt'} ?
- $last->{'text'} : mt($last->{'text'}) ));
+
+ my $lasttext = $last->{'no_mt'} ? $last->{'text'}
+ : mt( $last->{'text'} );
+
+ # last breadcrumb is the first order heading of a page
+ # for course breadcrumbs it's just bold
+
+ if ($lasttext ne '') {
+ $links .= &htmltag( 'li', htmltag($CourseBreadcrumbs ? 'b' : 'h1',
+ $lasttext));
+ }
my $icons = '';
$faq = $last->{'faq'} if (exists($last->{'faq'}));
@@ -1420,37 +2104,66 @@ returns: nothing
if ($faq ne '' || $component_help ne '' || $bug ne '') {
$icons .= &Apache::loncommon::help_open_menu($component,
$component_help,
- $faq,$bug);
+ $faq,$bug,'','','','',
+ $links_target);
+ }
+ if ($topic_help && $topic_help_text) {
+ $icons .= ' '.&Apache::loncommon::help_open_topic($topic_help,&mt($topic_help_text),'',
+ undef,600,'',$links_target);
}
#
-
- unless ($CourseBreadcrumbs) {
- $links = htmltag('ol', $links, { id => "LC_MenuBreadcrumbs" });
- } else {
- $links = htmltag('ul', $links, { class => "LC_CourseBreadcrumbs" });
+
+ if ($links ne '') {
+ unless ($CourseBreadcrumbs) {
+ $links = &htmltag('ol', $links, { id => "LC_MenuBreadcrumbs" });
+ } else {
+ $links = &htmltag('ul', $links, { class => "LC_CourseBreadcrumbs" });
+ }
}
- if ($component) {
- $links = htmltag('span',
+
+ if (($component) || ($topic_help && $topic_help_text)) {
+ $links = &htmltag('span',
( $no_mt ? $component : mt($component) ).
( $icons ? $icons : '' ),
{ class => 'LC_breadcrumbs_component' } )
- .$links;
+ .$links
+;
+ }
+ my $nav_and_tools = 0;
+ foreach my $item ('navigation','tools') {
+ if (ref($tools{$item}) eq 'ARRAY') {
+ $nav_and_tools += scalar(@{$tools{$item}})
+ }
+ }
+ if (($links ne '') || ($nav_and_tools)) {
+ &render_tools(\$links);
+ unless ($CourseBreadcrumbs) {
+ my $args = { id => 'LC_breadcrumbs' };
+ if ($crumbs_style ne '') {
+ $args->{'style'} = $crumbs_style;
+ }
+ $links = &htmltag('div', $links, $args);
+ }
+ }
+ my $adv_tools = 0;
+ if (ref($tools{'advtools'}) eq 'ARRAY') {
+ $adv_tools = scalar(@{$tools{'advtools'}});
+ }
+ if (($links ne '') || ($adv_tools)) {
+ &render_advtools(\$links);
}
-
- #SD START (work in progress!)
- add_tools(\$links);
- #SD END
- $links = htmltag('div', $links,
- { id => "LC_breadcrumbs" }) unless ($CourseBreadcrumbs) ;
- add_advtools(\$links);
# Return the @Crumbs stack to what we started with
push(@Crumbs,$last);
shift(@Crumbs);
+
+
# Return the breadcrumb's line
- return "$links";
+
+ my $labeltext = &HTML::Entities::encode(&mt('Links for navigation and information'));
+ return '
'.$links.'
';
}
sub clear_breadcrumbs {
@@ -1462,54 +2175,234 @@ returns: nothing
push(@Crumbs,@_);
}
+=item &add_breadcrumb_tool($category, $html)
+
+Adds $html to $category of the breadcrumb toolbar container.
+
+$html is usually a link to a page that invokes a function on the currently
+displayed data (e.g. print when viewing a problem)
+
+=over
+
+=item Currently there are 3 possible values for $category:
+
+=over
+
+=item navigation
+left of breadcrumbs line
+
+=item tools
+remaining items in right of breadcrumbs line
+
+=item advtools
+advanced tools shown in a separate box below breadcrumbs line
+
+=back
+
+=back
+
+returns: nothing
+
+=cut
- #SD START (work in progress!)
sub add_breadcrumb_tool {
- my ($category, $html) = @_;
- return unless $html;
- if (!defined(%tools)) {
- my %tools = ( A => [], B => [], C => []);
- }
- push @{$tools{$category}}, $html;
- }
-
- sub add_tools {
- my ($links) = @_;
- return unless defined %tools;
- my $html = '
';
- for my $category ('A','B') {
- $html .= '
'
- . '
";
- for my $item (@{$tools{$category}}){
- #SD ugly! I'll fix that later on
- $item =~ s/align="(right|left)"//;
- $item =~ s///;
- $html .= "
$item
";
- }
- $html .= '
';
- if ($category eq 'A') { $html .= "
$$links
"; }
- }
- $$links = $html.'';
- }
-
- sub add_advtools {
- my ($links) = @_;
- return unless (defined $tools{'C'}) and (scalar (@{$tools{'C'}}) > 0);
- my $html = start_funclist();
- for my $item (@{$tools{'C'}}){
- next unless $item;
- $item =~ s/align="(right|left)"//;
- $html .= add_item_funclist($item);
- }
- $html .= end_funclist();
- $html = Apache::loncommon::head_subbox($html);
- $$links .= $html;
+ my ($category, @html) = @_;
+ return unless @html;
+ if (!keys(%tools)) {
+ %tools = ( navigation => [], tools => [], advtools => []);
+ }
+
+ #this cleans data received from lonmenu::innerregister
+ @html = grep {defined $_ && $_ ne ''} @html;
+ for (@html) {
+ s/align="(right|left)"//;
+# s/// if $category ne 'advtools';
+ }
+
+ push @{$tools{$category}}, @html;
+ }
+
+=item &clear_breadcrumb_tools()
+
+Clears the breadcrumb toolbar container.
+
+returns: nothing
+
+=cut
+
+ sub clear_breadcrumb_tools {
+ undef(%tools);
+ }
+
+=item ¤t_breadcrumb_tools()
+
+returns: a hash containing the current breadcrumb tools.
+
+=cut
+
+ sub current_breadcrumb_tools {
+ return %tools;
+ }
+
+=item &render_tools(\$breadcrumbs)
+
+Creates html for breadcrumb tools (categories navigation and tools) and inserts
+\$breadcrumbs at the correct position.
+
+=over
+
+=item input:
+
+=over
+
+=item \$breadcrumbs - a reference to the string containing prepared breadcrumbs.
+
+=back
+
+=back
+
+returns: nothing
+
+=cut
+
+#TODO might split this in separate functions for each category
+ sub render_tools {
+ my ($breadcrumbs) = @_;
+ return unless (keys(%tools));
+
+ my $navigation = list_from_array($tools{navigation},
+ { listattr => { class=>"LC_breadcrumb_tools_navigation" } });
+ my $tools = list_from_array($tools{tools},
+ { listattr => { class=>"LC_breadcrumb_tools_tools" } });
+ $$breadcrumbs = list_from_array([$navigation, $tools, $$breadcrumbs],
+ { listattr => { class=>'LC_breadcrumb_tools_outerlist' } });
+ }
+
+=pod
+
+=item &render_advtools(\$breadcrumbs)
+
+Creates html for advanced tools (category advtools) and inserts \$breadcrumbs
+at the correct position.
+
+=over
+
+=item input:
+
+=over
+
+=item \$breadcrumbs - a reference to the string containing prepared breadcrumbs (after render_tools call).
+
+=back
+
+=back
+
+returns: nothing
+
+=cut
+
+ sub render_advtools {
+ my ($breadcrumbs) = @_;
+ return unless (defined $tools{'advtools'})
+ and (scalar(@{$tools{'advtools'}}) > 0);
+
+ $$breadcrumbs .= Apache::loncommon::head_subbox(
+ funclist_from_array($tools{'advtools'}) );
}
- #SD END
} # End of scope for @Crumbs
+sub docs_breadcrumbs {
+ my ($allowed,$crstype,$contenteditor,$title,$precleared,$checklinkprot)=@_;
+ my ($folderpath,@folders,$supplementalflag);
+ @folders = split('&',$env{'form.folderpath'});
+ if ($env{'form.folderpath'} =~ /^supplemental/) {
+ $supplementalflag = 1;
+ }
+ my $plain='';
+ my $container = 'sequence';
+ my ($randompick,$isencrypted,$ishidden,$is_random_order) = (-1,0,0,0);
+ my @docs_crumbs;
+ while (@folders) {
+ my $folder=shift(@folders);
+ my $foldername=shift(@folders);
+ if ($folderpath) {$folderpath.='&';}
+ $folderpath.=$folder.'&'.$foldername;
+ my $url = $env{'request.use_absolute'};
+ if ($allowed) {
+ $url .= '/adm/coursedocs?folderpath=';
+ } else {
+ $url .= '/adm/supplemental?folderpath=';
+ }
+ $url .= &escape($folderpath);
+ my $name=&unescape($foldername);
+# each of randompick number, hidden, encrypted, random order, is_page
+# are appended with ":"s to the foldername
+ $name=~s/\:(\d*)\:(\w*)\:(\w*):(\d*)\:?(\d*)$//;
+ if ($contenteditor) {
+ if ($supplementalflag) {
+ if ($2) { $ishidden=1; }
+ } else {
+ if ($1 ne '') {
+ $randompick=$1;
+ } else {
+ $randompick=-1;
+ }
+ if ($2) { $ishidden=1; }
+ if ($3) { $isencrypted=1; }
+ if ($4 ne '') { $is_random_order = 1; }
+ if ($5 == 1) {$container = 'page'; }
+ }
+ }
+ if ($folder eq 'supplemental') {
+ $name = &mt('Supplemental Content');
+ }
+ if ($contenteditor) {
+ $plain.=$name.' > ';
+ }
+ push(@docs_crumbs,
+ {'href' => $url,
+ 'title' => $name,
+ 'text' => $name,
+ 'no_mt' => 1,
+ });
+ }
+ if ($title) {
+ push(@docs_crumbs,
+ {'title' => $title,
+ 'text' => $title,
+ 'no_mt' => 1,}
+ );
+ }
+ if (wantarray) {
+ unless ($precleared) {
+ &clear_breadcrumbs();
+ }
+ &add_breadcrumb(@docs_crumbs);
+ if ($contenteditor) {
+ $plain=~s/\>\;\s*$//;
+ }
+ my $menulink = 0;
+ if (!$allowed && !$contenteditor && !$supplementalflag) {
+ $menulink = 1;
+ }
+ if ($checklinkprot) {
+ if ($env{'request.deeplink.login'}) {
+ my $linkprotout = &Apache::lonmenu::linkprot_exit();
+ if ($linkprotout) {
+ &Apache::lonhtmlcommon::add_breadcrumb_tool('tools',$linkprotout);
+ }
+ }
+ }
+ return (&breadcrumbs(undef,undef,$menulink,'nohelp',undef,undef,
+ $contenteditor),
+ $randompick,$ishidden,$isencrypted,$plain,
+ $is_random_order,$container);
+ } else {
+ return \@docs_crumbs;
+ }
+}
+
############################################################
############################################################
@@ -1570,15 +2463,19 @@ returns: nothing
my @row_count;
sub start_pick_box {
- my ($css_class) = @_;
+ my ($css_class,$id) = @_;
if (defined($css_class)) {
$css_class = 'class="'.$css_class.'"';
} else {
$css_class= 'class="LC_pick_box"';
}
+ my $table_id;
+ if (defined($id)) {
+ $table_id = ' id="'.$id.'"';
+ }
unshift(@row_count,0);
my $output = <<"END";
-
+
END
return $output;
}
@@ -1599,7 +2496,7 @@ END
}
sub row_title {
- my ($title,$css_title_class,$css_value_class, $css_value_furtherAttributes) = @_;
+ my ($title,$css_title_class,$css_value_class,$css_value_furtherAttributes,$nocolon) = @_;
$row_count[0]++;
my $css_class = ($row_count[0] % 2)?'LC_odd_row':'LC_even_row';
$css_title_class ||= 'LC_pick_box_title';
@@ -1607,14 +2504,14 @@ sub row_title {
$css_value_class ||= 'LC_pick_box_value';
- if ($title ne '') {
+ if (($title ne '') && (!$nocolon)) {
$title .= ':';
}
my $output = <<"ENDONE";
-
+
$title
-
+
ENDONE
return $output;
@@ -1639,7 +2536,6 @@ ENDTWO
} # End: row_count block for pick_box
-
sub role_select_row {
my ($roles,$title,$css_class,$show_separate_custom,$cdom,$cnum) = @_;
my $crstype = 'Course';
@@ -1685,15 +2581,15 @@ sub role_select_row {
sub course_select_row {
my ($title,$formname,$totcodes,$codetitles,$idlist,$idlist_titles,
- $css_class,$crstype) = @_;
+ $css_class,$crstype,$standardnames) = @_;
my $output = &row_title($title,$css_class);
- $output .= &course_selection($formname,$totcodes,$codetitles,$idlist,$idlist_titles,$crstype);
+ $output .= &course_selection($formname,$totcodes,$codetitles,$idlist,$idlist_titles,$crstype,$standardnames);
$output .= &row_closure();
return $output;
}
sub course_selection {
- my ($formname,$totcodes,$codetitles,$idlist,$idlist_titles,$crstype) = @_;
+ my ($formname,$totcodes,$codetitles,$idlist,$idlist_titles,$crstype,$standardnames) = @_;
my $output = qq|
+
+$arrayindexofjs
+
+ENDSCRIPT
+}
+
+##############################################
+##############################################
+
+sub resize_scrollbox_js {
+ my ($context,$tabidstr,$tid) = @_;
+ my (%names,$paddingwfrac,$offsetwfrac,$offsetv,$minw,$minv);
+ if ($context eq 'docs') {
+ %names = (
+ boxw => 'contenteditor',
+ item => 'contentlist',
+ header => 'uploadfileresult',
+ scroll => 'contentscroll',
+ boxh => 'contenteditor',
+ );
+ $paddingwfrac = 0.09;
+ $offsetwfrac = 0.015;
+ $offsetv = 20;
+ $minw = 250;
+ $minv = 200;
+ } elsif ($context eq 'params') {
+ %names = (
+ boxw => 'parameditor',
+ item => 'mapmenuinner',
+ header => 'parmstep1',
+ scroll => 'mapmenuscroll',
+ boxh => 'parmlevel',
+ );
+ $paddingwfrac = 0.2;
+ $offsetwfrac = 0.015;
+ $offsetv = 80;
+ $minw = 100;
+ $minv = 100;
+ }
+ my $viewport_js = &Apache::loncommon::viewport_geometry_js();
+ my $output = '
+
+window.onresize=callResize;
+
+';
+ if ($context eq 'docs') {
+ if ($env{'form.active'}) {
+ $output .= "\nvar activeTab = '$env{'form.active'}$tid';\n";
+ } else {
+ $output .= "\nvar activeTab = '';\n";
+ }
+ }
+ $output .= <<"FIRST";
+
+$viewport_js
+
+function resize_scrollbox(scrollboxname,chkw,chkh) {
+ var scrollboxid = 'div_'+scrollboxname;
+ var scrolltableid = 'table_'+scrollboxname;
+ var scrollbox;
+ var scrolltable;
+ var ismobile = '$env{'browser.mobile'}';
+
+ if (document.getElementById("$names{'boxw'}") == null) {
+ return;
+ }
+
+ if (document.getElementById(scrollboxid) == null) {
+ return;
+ } else {
+ scrollbox = document.getElementById(scrollboxid);
+ }
+
+
+ if (document.getElementById(scrolltableid) == null) {
+ return;
+ } else {
+ scrolltable = document.getElementById(scrolltableid);
+ }
+
+ init_geometry();
+ var vph = Geometry.getViewportHeight();
+ var vpw = Geometry.getViewportWidth();
+
+FIRST
+ if ($context eq 'docs') {
+ $output .= "
+ var alltabs = ['$tabidstr'];
+";
+ } elsif ($context eq 'params') {
+ $output .= "
+ if (document.getElementById('$names{'boxh'}') == null) {
+ return;
+ }
+";
+ }
+ $output .= <<"SECOND";
+ var listwchange;
+ var scrollchange;
+ if (chkw == 1) {
+ var boxw = document.getElementById("$names{'boxw'}").offsetWidth;
+ var itemw;
+ var itemid = document.getElementById("$names{'item'}");
+ if (itemid != null) {
+ itemw = itemid.offsetWidth;
+ }
+ var itemwstart = itemw;
+
+ var scrollboxw = scrollbox.offsetWidth;
+ var scrollboxscrollw = scrollbox.scrollWidth;
+ var scrollstart = scrollboxw;
+
+ var offsetw = parseInt(vpw * $offsetwfrac);
+ var paddingw = parseInt(vpw * $paddingwfrac);
+
+ var minscrollboxw = $minw;
+ var maxcolw = 0;
+SECOND
+ if ($context eq 'docs') {
+ $output .= <<"DOCSONE";
+ var actabw = 0;
+ for (var i=0; i maxcolw) {
+ maxcolw = actabw;
+ }
+ } else {
+ if (document.getElementById(alltabs[i]) != null) {
+ var thistab = document.getElementById(alltabs[i]);
+ thistab.style.visibility = 'hidden';
+ thistab.style.display = 'block';
+ var tabw = document.getElementById(alltabs[i]).offsetWidth;
+ thistab.style.display = 'none';
+ thistab.style.visibility = '';
+ if (tabw > maxcolw) {
+ maxcolw = tabw;
+ }
+ }
+ }
+ }
+DOCSONE
+ } elsif ($context eq 'params') {
+ $output .= <<"PARAMSONE";
+ var parmlevelrows = new Array();
+ var mapmenucells = new Array();
+ parmlevelrows = document.getElementById("$names{'boxh'}").rows;
+ var numrows = parmlevelrows.length;
+ if (numrows > 1) {
+ mapmenucells = parmlevelrows[2].getElementsByTagName('td');
+ }
+ maxcolw = mapmenucells[0].offsetWidth;
+PARAMSONE
+ }
+ $output .= <<"THIRD";
+ if (maxcolw > 0) {
+ var newscrollboxw;
+ if (maxcolw+paddingw+scrollboxscrollw scrollboxheight) {
+ if (freevspace > offsetv) {
+ newscrollboxheight = scrollboxheight+freevspace-offsetv;
+ if (newscrollboxheight < minvscrollbox) {
+ newscrollboxheight = minvscrollbox;
+ }
+ scrollbox.style.height = newscrollboxheight+"px";
+ }
+ }
+ }
+ scrollboxheight = scrollbox.offsetHeight;
+ var itemh = document.getElementById("$names{'item'}").offsetHeight;
+
+ if (scrollboxscrollheight <= scrollboxheight) {
+ if ((itemh+offsetv)&');
+ if ($shownsymb) {
+ $cfile .= '&symb='.&HTML::Entities::encode($shownsymb,'"<>&');
+ if ($resedit) {
+ $cfile .= '&edit=1';
+ }
+ } elsif ($folderpath) {
+ $cfile .= '&folderpath='.&HTML::Entities::encode($folderpath,'"<>&');
+ }
+ if ($forceedit) {
+ $cfile .= '&forceedit=1';
+ }
+ if ($forcereg) {
+ $cfile .= '®ister=1';
+ }
+ $jscall = "need_switchserver('".&Apache::loncommon::escape_single($cfile)."','$target')";
+ }
+ } else {
+ unless ($cfile =~ m{^/priv/}) {
+ if ($cfile =~ m{^(/adm/wrapper/ext/([^#]+))(?:|#([^#]+))$}) {
+ $cfile = $1;
+ my $extlink = $2;
+ $anchor = $3;
+ $is_ext = 1;
+ if (($extlink !~ /^https:/) && ($ENV{'SERVER_PORT'} == 443)) {
+ unless ((&Apache::lonnet::uses_sts()) || (&Apache::lonnet::waf_allssl($hostname))) {
+ $usehttp = 1;
+ }
+ } elsif ($env{'request.use_absolute'}) {
+ if ($env{'request.use_absolute'} =~ m{^https://}) {
+ $usehttps = 1;
+ }
+ }
+ } elsif ($cfile =~ m{^/?public/($match_domain)/($match_courseid)/syllabus}) {
+ if ($ENV{'SERVER_PORT'} == 443) {
+ my ($cdom,$cnum) = ($1,$2);
+ if (($env{'request.course.id'}) &&
+ ($env{'course.'.$env{'request.course.id'}.'.num'} eq $cnum) &&
+ ($env{'course.'.$env{'request.course.id'}.'.domain'} eq $cdom)) {
+ if ($env{'course.'.$env{'request.course.id'}.'.externalsyllabus'} =~ m{^http://}) {
+ unless ((&Apache::lonnet::uses_sts()) || (&Apache::lonnet::waf_allssl($hostname))) {
+ $usehttp = 1;
+ }
+ }
+ }
+ } elsif ($env{'request.use_absolute'}) {
+ if ($env{'request.use_absolute'} =~ m{^https://}) {
+ $usehttps = 1;
+ }
+ }
+ }
+ if ($symb) {
+ if ($anchor ne '') {
+ if ($symb =~ m{^([^#]+)\Q#$anchor\E$}) {
+ $symb = $1.&escape(&escape('#')).$anchor;
+ }
+ }
+ $cfile .= (($cfile=~/\?/)?'&':'?')."symb=$symb";
+ } elsif ($folderpath) {
+ $cfile .= (($cfile=~/\?/)?'&':'?').
+ 'folderpath='.&HTML::Entities::encode(&escape($folderpath),'"<>&');
+ if ($title) {
+ $cfile .= (($cfile=~/\?/)?'&':'?').
+ 'title='.&HTML::Entities::encode(&escape($title),'"<>&');
+ }
+ if ($idx) {
+ $cfile .= (($cfile=~/\?/)?'&':'?').'idx='.$idx;
+ }
+ if ($suppurl) {
+ $cfile .= (($cfile=~/\?/)?'&':'?').
+ 'suppurl='.&HTML::Entities::encode(&escape($suppurl));
+ }
+ }
+ if ($forceedit) {
+ $cfile .= (($cfile=~/\?/)?'&':'?').'forceedit=1';
+ if ($usehttps) {
+ $cfile = $env{'request.use_absolute'}.(($cfile =~ /^\//)? '':'/').$cfile;
+ }
+ } elsif ($usehttp) {
+ if ($hostname ne '') {
+ $cfile = 'http://'.$hostname.(($cfile =~ /^\//)? '':'/').$cfile;
+ }
+ $cfile .= (($cfile=~/\?/)?'&':'?').'usehttp=1';
+ } elsif ($usehttps) {
+ $cfile = $env{'request.use_absolute'}.(($cfile =~ /^\//)? '':'/').$cfile;
+ }
+ if ($forcereg) {
+ $cfile .= (($cfile=~/\?/)?'&':'?').'register=1';
+ }
+ if ($todocs) {
+ $cfile .= (($cfile=~/\?/)?'&':'?').'todocs=1';
+ }
+ if ($suppanchor ne '') {
+ $cfile .= (($cfile=~/\?/)?'&':'?').'anchor='.
+ &HTML::Entities::encode($suppanchor,'"<>&');
+ }
+ }
+ if ($anchor ne '') {
+ $cfile .= '#'.$anchor;
+ }
+ $jscall = "go('".&Apache::loncommon::escape_single($cfile)."')";
+ }
+ return $jscall;
+}
+
+##############################################
+##############################################
+
# javascript_valid_email
#
# Generates javascript to validate an e-mail address.
-# Returns a javascript function which accetps a form field as argumnent, and
+# Returns a javascript function which accepts a form field as argument, and
# returns false if field.value does not satisfy two regular expression matches
# for a valid e-mail address. Backwards compatible with old browsers without
# support for javascript RegExp (just checks for @ in field.value in this case).
sub javascript_valid_email {
my $scripttag .= <<'END';
-function validmail(field) {
+function validmail(field,suffix) {
var str = field.value;
+ if (suffix != '' && suffix != undefined) {
+ str += suffix;
+ }
if (window.RegExp) {
var reg1str = "(@.*@)|(\\.\\.)|(@\\.)|(\\.@)|(^\\.)";
var reg2str = "^.+\\@(\\[?)[a-zA-Z0-9\\-\\.]+\\.([a-zA-Z]{2,3}|[0-9]{1,3})(\\]?)$"; //"
@@ -2162,7 +3848,7 @@ END
sub htmltag{
return
qq|<$_[0]|
- . join( '', map { qq| $_="${$_[2]}{$_}"| if ${$_[2]}{$_} } keys %{ $_[2] } )
+ . join( '', map { qq| $_="${$_[2]}{$_}"| if ${$_[2]}{$_} } keys(%{ $_[2] }) )
. ($_[1] ? qq|>$_[1]$_[0]>| : qq|/>|). "\n";
};
@@ -2170,7 +3856,7 @@ sub htmltag{
# USAGE: inittags(@tags);
#
# EXAMPLES:
-# - my ($h1, $h2, $h3) = initTags( qw( h1 h2 h3 ) )
+# - my ($h1, $h2, $h3) = inittags( qw( h1 h2 h3 ) )
# $h1->("This is a headline") #Returns:
This is a headline
#
# NOTES: See sub htmltag for further information.
@@ -2218,6 +3904,45 @@ sub scripttag {
return htmltag('script', $content, {type => 'text/javascript'});
};
+=pod
+
+=item &list_from_array( \@array, { listattr =>{}, itemattr =>{} } )
+
+Constructs a XHTML list from \@array.
+
+=over
+
+=item input:
+
+=over
+
+=item \@array
+
+A reference to the array containing text that will be wrapped in tags.
+
+=item { listattr => {}, itemattr =>{} }
+
+Attributes for
and
passed in as hash references.
+See htmltag() for more details.
+
+=back
+
+=back
+
+returns: XHTML list as String.
+
+=cut
+
+# \@items, {listattr => { class => 'abc', id => 'xyx' }, itemattr => {class => 'abc', id => 'xyx'}}
+sub list_from_array {
+ my ($items, $args) = @_;
+ return unless (ref($items) eq 'ARRAY');
+ return unless scalar @$items;
+ my ($ul, $li) = inittags( qw(ul li) );
+ my $listitems = join '', map { $li->($_, $args->{itemattr}) } @$items;
+ return $ul->( $listitems, $args->{listattr} );
+}
+
##############################################
##############################################
@@ -2248,16 +3973,10 @@ sub scripttag {
#
# Outputs: A scalar containing the html markup for the menu.
-# ---- Remove when done ----
-# This routine is part of the redesign of LON-CAPA and it's
-# subject to change during this project.
-# Don't rely on its current functionality as it might be
-# changed or removed.
-# --------------------------
sub generate_menu {
my @menu = @_;
# subs for specific html elements
- my ($h3, $div, $ul, $li, $a, $img) = inittags( qw(h3 div ul li a img) );
+ my ($h2, $div, $ul, $li, $a, $img) = inittags( qw(h2 div ul li a img) );
my @categories; # each element represents the entire markup for a category
@@ -2269,16 +3988,21 @@ sub generate_menu {
# create the markup for the current $link and push it into @links.
# each entry consists of an image and a text optionally followed
# by a help link.
+ my $src;
+ if ($$link{icon} ne '') {
+ $src = '/res/adm/pages/'.$$link{icon};
+ }
push(@links,$li->(
$a->(
$img->("", {
class => "LC_noBorder LC_middle",
- src => "/res/adm/pages/$$link{icon}",
+ src => $src,
alt => mt(defined($$link{alttext}) ?
$$link{alttext} : $$link{linktext})
}), {
href => $$link{url},
- title => mt($$link{linktitle})
+ title => mt($$link{linktitle}),
+ class => 'LC_menubuttons_link'
}).
$a->(mt($$link{linktext}), {
href => $$link{url},
@@ -2290,15 +4014,15 @@ sub generate_menu {
{class => "LC_menubuttons_inline_text"}));
}
- # wrap categorytitle in
, concatenate with
+ # wrap categorytitle in
, concatenate with
# joined and in
tags wrapped @links
# and wrap everything in an enclosing
and push it into
# @categories
# such that each element looks like:
- #
title
...
...
+ #
title
...
...
# the category won't be added if there aren't any links
push(@categories,
- $div->($h3->(mt($$category{categorytitle}), {class=>"LC_hcell"}).
+ $div->($h2->(mt($$category{categorytitle}), {class=>'LC_hcell LC_heading_2'}).
$ul->(join('' ,@links), {class =>"LC_ListStyleNormal" }),
{class=>"LC_Box LC_400Box"})) if scalar(@links);
}
@@ -2312,7 +4036,7 @@ sub generate_menu {
=pod
-=item &start_funclist
+=item &start_funclist()
Start list of available functions
@@ -2323,13 +4047,19 @@ should be included in this list.
If the optional headline text is not provided, a default text will be used.
+=over
+
+=item Related routines:
-Related routines:
=over 4
-add_item_funclist
-end_funclist
+
+=item add_item_funclist
+
+=item end_funclist
+
=back
+=back
Inputs: (optional) headline text
@@ -2343,8 +4073,7 @@ Returns: HTML code with function list st
sub start_funclist {
my($legendtext)=@_;
$legendtext=&mt('Functions') if !$legendtext;
- return "\n";
+ return "\n";
+}
+
+=pod
+
+=item &funclist_from_array( \@array, {legend => 'text for legend'} )
+
+Constructs a XHTML list from \@array with the first item being visually
+highlighted and set to the value of legend or 'Functions' if legend is
+empty.
+
+=over
+
+=item \@array
+
+A reference to the array containing text that will be wrapped in tags.
+
+=item { legend => 'text' }
+
+A string that's used as visually highlighted first item. 'Functions' is used if
+it's value evaluates to false.
+
+=back
+
+returns: XHTML list as string.
+
+=back
+
+=cut
+
+sub funclist_from_array {
+ my ($items, $args) = @_;
+ return unless(ref($items) eq 'ARRAY');
+ $args->{legend} ||= mt('Functions');
+ return list_from_array( [$args->{legend}, @$items],
+ { listattr => {class => 'LC_funclist'} });
+}
+
+=pod
+
+=over
+
+=item &actionbox( \@array )
+
+Constructs a XHTML list from \@array with the first item being visually
+highlighted and set to the value 'Actions'. The list is wrapped in a division.
+
+The actionlist is used to offer contextual actions, mostly at the bottom
+of a page, on which the outcome of an processed action is shown,
+e.g. a file operation in Authoring Space.
+
+=over
+
+=item \@array
+
+A reference to the array containing text. Details: sub funclist_from_array
+
+=back
+
+Returns: XHTML div as string.
+
+=back
+
+=cut
+
+sub actionbox {
+ my ($items) = @_;
+ return unless(ref($items) eq 'ARRAY');
+ return
+ '