");
+ $("#LC_rt_"+id).click(editorHandler);
+ });
+ $.fn.jPicker.defaults.images.clientPath="/adm/jpicker/images/";
+ $(".colorchooser").jPicker();
+
+
+ });
+';
+ # Code to put a due date countdown in 'duedatecountdown' span.
+ # This is currently located in the breadcrumb headers.
+ # note that the dueDateLayout is internatinoalized below.
+ # Here document is used to support the substitution into the javascript below.
+ # ..which unforunately necessitates escaping the $'s in the javascript.
+ # There are several times of importance
+ #
+ # serverDueDate - The absolute time at which the problem expires.
+ # serverTime - The server's time when the problem finished computing.
+ # clientTime - The client's time...as close to serverTime as possible.
+ # The clientTime will be slightly later due to
+ # 1. The latency between problem computation and
+ # the first network action.
+ # 2. The time required between the page load-start and the actual
+ # initial javascript execution that got clientTime.
+ # These are used as follows:
+ # The difference between clientTime and serverTime are used to
+ # correct for differences in clock settings between the browser's system and the
+ # server's.
+ #
+ # The difference between clientTime and the time at which the ready() method
+ # starts executing is used to estimate latencies for page load and submission.
+ # Since this is an estimate, it is doubled. The latency estimate + one minute
+ # is used to determine when the countdown timer turns red to warn the user
+ # to think about submitting.
+
+ my $dueDateLayout = &mt('Due in: {dn} {dl} {hnn}{sep}{mnn}{sep}{snn} [_1]',"");
+ my $early = '- '.&mt('Submit Early').'';
+ my $pastdue = '- '.&mt('Past Due').'';
+ $output .= <'."\n"
+ .'';
return $output;
}
@@ -1257,23 +1450,104 @@ 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; }
+
+ if (($env{'request.noversionuri'} =~ m{^/adm/(viewclasslist|navmaps)($|\?)})
+ || ($env{'request.noversionuri'} =~ m{^/adm/.*/aboutme($|\?)})) {
+
+ return if ($env{'form.register'});
+ }
+ 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)($|\?)})
+ ));
+}
+
+
+##
+# 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
+}
+
############################################################
############################################################
=pod
-=item breadcrumbs
+=item &breadcrumbs()
Compiles the previously registered breadcrumbs into an series of links.
-FAQ and BUG links will be placed on the left side of the table if they
-are defined for the last registered breadcrumb.
Additionally supports a 'component', which will be displayed on the
-right side of the table (without a link).
+right side of the breadcrumbs enclosing div (without a link).
A link to help for the component will be included if one is specified.
All inputs can be undef without problems.
-Inputs: $component (the large text on the right side of the table),
+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)
@@ -1282,11 +1556,11 @@ Inputs: $component (the large text on th
when including the text on the right.
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.
@@ -1303,72 +1577,90 @@ returns: nothing
############################################################
{
my @Crumbs;
+ my %tools = ();
sub breadcrumbs {
- my ($component,$component_help,$menulink,$helplink,$css_class,$no_mt) = @_;
- #
- $css_class ||= 'LC_breadcrumbs';
- my $Str1 = '';
- my $Str = '';
+ my ($component,$component_help,$menulink,$helplink,$css_class,$no_mt,
+ $CourseBreadcrumbs) = @_;
#
+ $css_class ||= 'LC_breadcrumbs';
+
# Make the faq and bug data cascade
- my $faq = '';
- my $bug = '';
- my $help='';
- # Crumb Symbol
- my $crumbsymbol = '» ';
+ my $faq = '';
+ my $bug = '';
+ my $help = '';
+ # Crumb Symbol
+ my $crumbsymbol = '»';
# The last breadcrumb does not have a link, so handle it separately.
my $last = pop(@Crumbs);
#
# The first one should be the course or a menu link
- if (!defined($menulink)) { $menulink=1; }
+ if (!defined($menulink)) { $menulink=1; }
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;
}
- unshift(@Crumbs,{
- href =>'/adm/menu',
- title =>'Go to main menu',
- target =>'_top',
- text =>$description,
- no_mt =>$no_mt_descr,
- });
- }
- my $links .= '
';
+ }
+ return $return;
+}
+
##############################################
##############################################
# topic_bar
#
-# Generates a div containing a numbered (static image) followed by a title
-# with a background color defined in the corresponding CSS: LC_topic_bar
-#
+# Generates a div containing an (optional) number with a white background followed by a
+# title with a background color defined in the corresponding CSS: LC_topic_bar
+# Inputs:
+# 1. number to display.
+# If input for number is empty only the title will be displayed.
+# 2. title text to display.
+# 3. optional id for the
+# Outputs - a scalar containing html mark-up for the div.
+
sub topic_bar {
- my ($imgnum,$title) = @_;
- return '
-
-
- '.$title.'
-
-';
+ my ($num,$title,$id) = @_;
+ my $number = '';
+ if ($num ne '') {
+ $number = ''.$num.'';
+ }
+ if ($id ne '') {
+ $id = 'id="'.$id.'"';
+ }
+ return '
'.$number.$title.'
';
}
##############################################
##############################################
-
# echo_form_input
#
# Generates html markup to add form elements from the referrer page
@@ -1807,30 +2278,30 @@ sub echo_form_input {
if ($key =~ /^form\.(.+)$/) {
my $name = $1;
my $match = 0;
- if ((!@{$excluded}) || (!grep/^$name$/,@{$excluded})) {
- if (defined($regexps)) {
- if (@{$regexps} > 0) {
- foreach my $regexp (@{$regexps}) {
- if ($name =~ /\Q$regexp\E/) {
- $match = 1;
- last;
- }
+ if (ref($excluded) eq 'ARRAY') {
+ next if (grep(/^\Q$name\E$/,@{$excluded}));
+ }
+ if (ref($regexps) eq 'ARRAY') {
+ if (@{$regexps} > 0) {
+ foreach my $regexp (@{$regexps}) {
+ if ($name =~ /$regexp/) {
+ $match = 1;
+ last;
}
}
}
- if (!$match) {
- if (ref($env{$key})) {
- foreach my $value (@{$env{$key}}) {
- $value = &HTML::Entities::encode($value,'<>&"');
- $output .= ''."\n";
- }
- } else {
- my $value = &HTML::Entities::encode($env{$key},'<>&"');
- $output .= ''."\n";
- }
+ }
+ next if ($match);
+ if (ref($env{$key}) eq 'ARRAY') {
+ foreach my $value (@{$env{$key}}) {
+ $value = &HTML::Entities::encode($value,'<>&"');
+ $output .= ''."\n";
}
+ } else {
+ my $value = &HTML::Entities::encode($env{$key},'<>&"');
+ $output .= ''."\n";
}
}
}
@@ -1839,7 +2310,6 @@ sub echo_form_input {
##############################################
##############################################
-
# set_form_elements
#
# Generates javascript to set form elements to values based on
@@ -1904,7 +2374,7 @@ sub set_form_elements {
$values{$name}[$i] =~ s/([\r\n\f]+)/\\n/g;
$values{$name}[$i] =~ s/"/\\"/g;
}
- if ($$elements{$name} eq 'text') {
+ if (($$elements{$name} eq 'text') || ($$elements{$name} eq 'hidden')) {
my $numvalues = @{$values{$name}};
if ($numvalues > 1) {
my $valuestring = join('","',@{$values{$name}});
@@ -1939,6 +2409,8 @@ sub set_form_elements {
$output .= qq|
if (courseForm.elements['$name'].value == "$value") {
courseForm.elements['$name'].checked = true;
+ } else {
+ courseForm.elements['$name'].checked = false;
}|;
}
}
@@ -1980,6 +2452,7 @@ sub set_form_elements {
}
}
$output .= "
+ return;
}\n";
return $output;
}
@@ -1987,6 +2460,515 @@ sub set_form_elements {
##############################################
##############################################
+sub file_submissionchk_js {
+ my ($turninpaths,$multiples) = @_;
+ my $overwritewarn = &mt('File(s) you uploaded for your submission will overwrite existing file(s) submitted for this item').'\\n'.
+ &mt('Continue submission and overwrite the file(s)?');
+ my $delfilewarn = &mt('You have indicated you wish to remove some files previously included in your submission.').'\\n'.
+ &mt('Continue submission with these files removed?');
+ my ($turninpathtext,$multtext,$arrayindexofjs);
+ if (ref($turninpaths) eq 'HASH') {
+ foreach my $key (sort(keys(%{$turninpaths}))) {
+ $turninpathtext .= " if (prefix == '$key') {\n".
+ " return '$turninpaths->{$key}';\n".
+ " }\n";
+ }
+ }
+ $turninpathtext .= " return '';\n";
+ if (ref($multiples) eq 'HASH') {
+ foreach my $key (sort(keys(%{$multiples}))) {
+ $multtext .= " if (prefix == '$key') {\n".
+ " return '$multiples->{$key}';\n".
+ " }\n";
+ }
+ }
+ $multtext .= " return '';\n";
+
+ $arrayindexofjs = &Apache::loncommon::javascript_array_indexof();
+ return <<"ENDSCRIPT";
+
+
+$arrayindexofjs
+
+ENDSCRIPT
+}
+
+##############################################
+##############################################
+
+sub resize_scrollbox_js {
+ my ($context,$tabidstr) = @_;
+ 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') {
+ $output .= '
+var activeTab;
+';
+ }
+ $output .= <<"FIRST";
+
+$viewport_js
+
+function resize_scrollbox(scrollboxname,chkw,chkh) {
+ var scrollboxid = 'div_'+scrollboxname;
+ var scrolltableid = 'table_'+scrollboxname;
+ var scrollbox;
+ var scrolltable;
+
+ 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;
+ 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 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) value,...});
+#
+# EXAMPLES:
+# - htmltag('a', 'this is an anchor', {href => 'www.example.com',
+# title => 'this is a title'})
+#
+# - You might want to set up needed tags like:
+#
+# my $h3 = sub { return htmltag( "h3", @_ ) };
+#
+# ... and use them: $h3->("This is a headline")
+#
+# - To set up a couple of tags, see sub inittags
+#
+# NOTES:
+# - Empty elements, such as are correctly terminated,
+# i.e. htmltag('br') returns
+# - Empty attributes (title="") are filtered out.
+# - The function will not check for deprecated attributes.
+#
+# OUTPUT: content enclosed in xhtml conform tags
+sub htmltag{
+ return
+ qq|<$_[0]|
+ . join( '', map { qq| $_="${$_[2]}{$_}"| if ${$_[2]}{$_} } keys %{ $_[2] } )
+ . ($_[1] ? qq|>$_[1]$_[0]>| : qq|/>|). "\n";
+};
+
+
+# USAGE: inittags(@tags);
+#
+# EXAMPLES:
+# - 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.
+#
+# OUTPUT: List of subroutines.
+sub inittags {
+ my @tags = @_;
+ return map { my $tag = $_;
+ sub { return htmltag( $tag, @_ ) }
+ } @tags;
+}
+
+
+# USAGE: scripttag(scriptcode, [start|end|both]);
+#
+# EXAMPLES:
+# - scripttag("alert('Hello World!')", 'both')
+# returns:
+#
+#
+# NOTES:
+# - works currently only for javascripts
+#
+# OUTPUT:
+# Scriptcode properly enclosed in