--- loncom/interface/lonhtmlcommon.pm 2007/11/06 04:39:19 1.169 +++ loncom/interface/lonhtmlcommon.pm 2009/11/21 22:36:23 1.247 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # a pile of common html routines # -# $Id: lonhtmlcommon.pm,v 1.169 2007/11/06 04:39:19 raeburn Exp $ +# $Id: lonhtmlcommon.pm,v 1.247 2009/11/21 22:36:23 www Exp $ # # Copyright Michigan State University Board of Trustees # @@ -62,6 +62,97 @@ use Apache::lonlocal; use Apache::lonnet; use LONCAPA; + +sub coursepreflink { + my ($text,$category)=@_; + if (&Apache::lonnet::allowed('opa',$env{'request.course.id'})) { + return '<a href="/adm/courseprefs?phase=display&actions='.$category.'">'.$text.'</a>'; + } else { + return ''; + } +} + +############################################## +############################################## + +=pod + +=item confirm_success + +Successful completion of an operation message + +=cut + +sub confirm_success { + my ($message,$failure)=@_; + if ($failure) { + return '<span class="LC_error">'."\n" + .'<img src="/adm/lonIcons/navmap.wrong.gif" alt="'.&mt('Error').'" /> '."\n" + .$message."\n" + .'</span>'."\n"; + } else { + return '<span class="LC_success">'."\n" + .'<img src="/adm/lonIcons/navmap.correct.gif" alt="'.&mt('OK').'" /> '."\n" + .$message."\n" + .'</span>'."\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'); + } + my $buttontext=&mt('Edit Math'); + return <<ENDDRAGMATH; + <input type="button" value="$buttontext" onclick="javascript:mathedit('$textarea',document)" />$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; + <script type="text/javascript"> + // <![CDATA[ + function mathedit(textarea, doc) { + targetEntry = textarea; + targetDoc = doc; + newwin = window.open("/adm/dragmath/applet/$popup.html","","width=565,height=500,resizable"); + } + // ]]> + </script> + +ENDDRAGMATHJS +} + + ############################################## ############################################## @@ -79,10 +170,10 @@ sub authorbombs { $url=&Apache::lonnet::declutter($url); 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 '<a href="/adm/bombs/'.$url. - '"><img src="'.&Apache::loncommon::lonhttpdurl('/adm/lonMisc/bomb.gif').'" border="0" /></a>'. + '"><img src="'.&Apache::loncommon::lonhttpdurl('/adm/lonMisc/bomb.gif').'" alt="'.&mt('Bomb').'" border="0" /></a>'. &Apache::loncommon::help_open_topic('About_Bombs'); } } @@ -158,7 +249,7 @@ sub get_recent { # Begin filling return_hash with any 'always_include' option my %time_hash = (); my %return_hash = (); - foreach my $item (keys %recent) { + foreach my $item (keys(%recent)) { my ($thistime,$thisvalue)=(split(/\&/,$recent{$item})); if ($thistime eq 'always_include') { $return_hash{$item} = &unescape($thisvalue); @@ -231,7 +322,7 @@ sub checkbox { $Str .= 'value="'.$value.'"'; } if ($checked) { - $Str .= ' checked="1"'; + $Str .= ' checked="checked"'; } $Str .= ' />'; return $Str; @@ -253,7 +344,7 @@ sub radio { $Str .= 'value="'.$value.'"'; } if ($checked eq $value) { - $Str .= ' checked="1"'; + $Str .= ' checked="checked"'; } $Str .= ' />'; return $Str; @@ -311,6 +402,7 @@ The method used to restrict user input w sub date_setter { my ($formname,$dname,$currentvalue,$special,$includeempty,$state, $no_hh_mm_ss,$defhour,$defmin,$defsec,$nolink) = @_; + my $now = time; my $wasdefined=1; if (! defined($state) || $state ne 'disabled') { $state = ''; @@ -319,28 +411,25 @@ sub date_setter { $no_hh_mm_ss = 0; } if ($currentvalue eq 'now') { - $currentvalue=time; + $currentvalue = $now; } if ((!defined($currentvalue)) || ($currentvalue eq '')) { $wasdefined=0; if ($includeempty) { $currentvalue = 0; } else { - $currentvalue = time; + $currentvalue = $now; } } # other potentially useful values: wkday,yrday,is_daylight_savings + my $tzname; my ($sec,$min,$hour,$mday,$month,$year)=('','',undef,'','',''); if ($currentvalue) { - ($sec,$min,$hour,$mday,$month,$year,undef,undef,undef) = - localtime($currentvalue); - $year += 1900; + ($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,$min,$hour,$mday,$month,$year,undef,undef,undef) = - localtime(time); - $year += 1900; $sec=($defsec?$defsec:0); $min=($defmin?$defmin:0); $hour=($defhour?$defhour:0); @@ -353,6 +442,7 @@ sub date_setter { my $result = "\n<!-- $dname date setting form -->\n"; $result .= <<ENDJS; <script type="text/javascript"> +// <![CDATA[ function $dname\_checkday() { var day = document.$formname.$dname\_day.value; var month = document.$formname.$dname\_month.value; @@ -413,9 +503,10 @@ document.$formname.$dname\_year.value, } } +// ]]> </script> ENDJS - $result .= ' <span style="white-space: nowrap;">'; + $result .= ' <span class="LC_nobreak">'; my $monthselector = qq{<select name="$dname\_month" $special $state onchange="javascript:$dname\_checkday()" >}; # Month my @Months = qw/January February March April May June @@ -424,23 +515,23 @@ ENDJS unshift(@Months,'If you can read this an error occurred'); if ($includeempty) { $monthselector.="<option value=''></option>"; } for(my $m = 1;$m <=$#Months;$m++) { - $monthselector .= qq{ <option value="$m" }; - $monthselector .= "selected " if ($m-1 eq $month); - $monthselector .= '> '.&mt($Months[$m]).' </option>'; + $monthselector .= qq{ <option value="$m"}; + $monthselector .= ' selected="selected"' if ($m-1 eq $month); + $monthselector .= '> '.&mt($Months[$m]).' </option>'."\n"; } $monthselector.= ' </select>'; # Day my $dayselector = qq{<input type="text" name="$dname\_day" $state value="$mday" size="3" $special onchange="javascript:$dname\_checkday()" />}; # Year - my $yearselector = qq{<input type="year" name="$dname\_year" $state value="$year" size="5" $special onchange="javascript:$dname\_checkday()" />}; + my $yearselector = qq{<input type="text" name="$dname\_year" $state value="$year" size="5" $special onchange="javascript:$dname\_checkday()" />}; # my $hourselector = qq{<select name="$dname\_hour" $special $state >}; if ($includeempty) { $hourselector.=qq{<option value=''></option>}; } for (my $h = 0;$h<24;$h++) { - $hourselector .= qq{<option value="$h" }; - $hourselector .= "selected " if (defined($hour) && $hour == $h); + $hourselector .= qq{<option value="$h"}; + $hourselector .= ' selected="selected"' if (defined($hour) && $hour == $h); $hourselector .= ">"; my $timest=''; if ($h == 0) { @@ -463,16 +554,19 @@ ENDJS $cal_link = qq{<a href="javascript:$dname\_opencalendar()">}; } # + my $tzone = ' '.$tzname.' '; if ($no_hh_mm_ss) { $result .= &mt('[_1] [_2] [_3] ', - $monthselector,$dayselector,$yearselector); + $monthselector,$dayselector,$yearselector). + $tzone; if (!$nolink) { $result .= &mt('[_1]Select Date[_2]',$cal_link,'</a>'); } } else { $result .= &mt('[_1] [_2] [_3] [_4] [_5]m [_6]s ', $monthselector,$dayselector,$yearselector, - $hourselector,$minuteselector,$secondselector); + $hourselector,$minuteselector,$secondselector). + $tzone; if (!$nolink) { $result .= &mt('[_1]Select Date[_2]',$cal_link,'</a>'); } @@ -481,6 +575,22 @@ ENDJS return $result; } +sub get_timedates { + my ($epoch) = @_; + my $dt = DateTime->from_epoch(epoch => $epoch) + ->set_time_zone(&Apache::lonlocal::gettimezone()); + my $tzname = $dt->time_zone_short_name(); + my $sec = $dt->second; + my $min = $dt->minute; + my $hour = $dt->hour; + my $mday = $dt->day; + my $month = $dt->month; + if ($month) { + $month --; + } + my $year = $dt->year; + return ($tzname,$sec,$min,$hour,$mday,$month,$year); +} sub build_url { my ($base, $fields)=@_; @@ -509,7 +619,7 @@ Inputs: =item $dname -The name passed to &datesetter, which prefixes the form elements. +The name passed to &date_setter, which prefixes the form elements. =item $defaulttime @@ -562,20 +672,33 @@ sub get_date_from_form { if (defined($env{'form.'.$dname.'_month'})) { my $tmpmonth = $env{'form.'.$dname.'_month'}; if (($tmpmonth =~ /^\d+$/) && ($tmpmonth > 0) && ($tmpmonth < 13)) { - $month = $tmpmonth - 1; + $month = $tmpmonth; } } if (defined($env{'form.'.$dname.'_year'})) { my $tmpyear = $env{'form.'.$dname.'_year'}; - if (($tmpyear =~ /^\d+$/) && ($tmpyear > 1900)) { - $year = $tmpyear - 1900; + if (($tmpyear =~ /^\d+$/) && ($tmpyear >= 1970)) { + $year = $tmpyear; } } - if (($year<70) || ($year>137)) { return undef; } + if (($year<1970) || ($year>2037)) { return undef; } if (defined($sec) && defined($min) && defined($hour) && - defined($day) && defined($month) && defined($year) && - eval('&timelocal($sec,$min,$hour,$day,$month,$year)')) { - return &timelocal($sec,$min,$hour,$day,$month,$year); + defined($day) && defined($month) && defined($year)) { + my $timezone = &Apache::lonlocal::gettimezone(); + my $dt = DateTime->new( year => $year, + month => $month, + day => $day, + hour => $hour, + minute => $min, + second => $sec, + time_zone => $timezone, + ); + my $epoch_time = $dt->epoch; + if ($epoch_time ne '') { + return $epoch_time; + } else { + return undef; + } } else { return undef; } @@ -645,6 +768,8 @@ sub javascript_nothing { ############################################## ############################################## sub javascript_docopen { + my ($mimetype) = @_; + $mimetype ||= 'text/html'; # safari does not understand document.open() and loads "text/html" my $nothing = "''"; my $user_browser; @@ -658,7 +783,7 @@ sub javascript_docopen { if ($user_browser eq 'safari' && $user_os =~ 'mac') { $nothing = "document.clear()"; } else { - $nothing = "document.open('text/html','replace')"; + $nothing = "document.open('$mimetype','replace')"; } return $nothing; } @@ -863,18 +988,19 @@ sub Create_PrgWin { #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,'<script type="text/javascript">'. + &r_print($r,&Apache::lonhtmlcommon::scripttag( "var popwin; function openpopwin () { popwin=open(\'\',\'popwin\',\'width=400,height=100\');". "popwin.document.writeln(\'".$start_page. - "<h4>$heading<\/h4>". - "<form action= \"\" name=\"popremain\" method=\"post\">". + "<h4>".&mt("$heading")."<\/h4>". + "<form action=\"\" name=\"popremain\" method=\"post\">". '<input type="text" size="'.$width.'" name="remaining" value="'. &mt('Starting').'" /><\\/form>'.$end_page. "\');". "popwin.document.close();}". - "\nwindow.setTimeout(openpopwin,0)</script>"); + "\nwindow.setTimeout(openpopwin,0)" + )); $prog_state{'formname'}='popremain'; $prog_state{'inputname'}="remaining"; } elsif ($type eq 'inline') { @@ -887,8 +1013,7 @@ sub Create_PrgWin { } if (!$inputname) { $prog_state{'inputname'}=&get_uniq_name(); - &r_print($r,$heading.' <input type="text" name="'.$prog_state{'inputname'}. - '" size="'.$width.'" />'); + &r_print($r,&mt("$heading [_1]",' <input type="text" name="'.$prog_state{'inputname'}.'" size="'.$width.'" />')); } else { $prog_state{'inputname'}=$inputname; @@ -908,10 +1033,12 @@ sub Create_PrgWin { # update progress sub Update_PrgWin { my ($r,$prog_state,$displayString)=@_; - &r_print($r,'<script type="text/javascript">'.$$prog_state{'window'}.'.document.'. - $$prog_state{'formname'}.'.'. - $$prog_state{'inputname'}.'.value="'. - $displayString.'";</script>'); + &r_print($r,&Apache::lonhtmlcommon::scripttag( + $$prog_state{'window'}.'.document.'. + $$prog_state{'formname'}.'.'. + $$prog_state{'inputname'}.'.value="'. + $displayString.'";' + )); $$prog_state{'laststart'}=&Time::HiRes::time(); } @@ -964,11 +1091,13 @@ sub Increment_PrgWin { if ($user_browser eq 'explorer' && $user_os =~ 'mac') { $lasttime = ''; } - &r_print($r,'<script>'.$$prog_state{'window'}.'.document.'. - $$prog_state{'formname'}.'.'. - $$prog_state{'inputname'}.'.value="'. - $$prog_state{'done'}.'/'.$$prog_state{'max'}. - ': '.$time_est.' '.&mt('remaining').' '.$lasttime.'";'.'</script>'); + &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.'";' + )); $$prog_state{'laststart'}=&Time::HiRes::time(); } @@ -976,7 +1105,9 @@ sub Increment_PrgWin { sub Close_PrgWin { my ($r,$prog_state)=@_; if ($$prog_state{'type'} eq 'popup') { - &r_print($r,'<script>popwin.close()</script>'."\n"); + &r_print($r,&Apache::lonhtmlcommon::scripttag( + 'popwin.close()' + )); } elsif ($$prog_state{'type'} eq 'inline') { &Update_PrgWin($r,$prog_state,&mt('Done')); } @@ -1007,7 +1138,7 @@ sub crumbs { my $output=''; unless ($noformat) { $output.='<br /><tt><b>'; } $output.='<font size="'.$size.'">'.$prefix.'/'; - if ($env{'user.adv'}) { + if (($env{'user.adv'}) | ($env{'user.author'})) { my $path=$prefix.'/'; foreach my $dir (split('/',$uri)) { if (! $dir) { next; } @@ -1058,6 +1189,7 @@ sub spellheader { my $nothing=&javascript_nothing(); return (<<ENDCHECK); <script type="text/javascript"> +// <![CDATA[ //<!-- BEGIN LON-CAPA Internal var checkwin; @@ -1068,6 +1200,7 @@ function spellcheckerwindow(string) { checkwin.document.close(); } // END LON-CAPA Internal --> +// ]]> </script> ENDCHECK } @@ -1141,7 +1274,8 @@ sub htmlareaselectactive { my @fields=@_; unless (&htmlareabrowser()) { return ''; } if (&htmlareablocked()) { return '<br />'.&enablelink(@fields); } - my $output='<script type="text/javascript" defer="1">'; + my $output='<script type="text/javascript" defer="1">'."\n" + .'// <![CDATA['."\n"; my $lang = &htmlarea_lang(); foreach my $field (@fields) { $output.=" @@ -1154,7 +1288,9 @@ sub htmlareaselectactive { oFCKeditor.Config['DefaultLanguage'] = '$lang'; }"; } - $output.="\nwindow.status='Activated Editfields';\n</script><br />". + $output.="\nwindow.status='Activated Editfields';\n" + .'// ]]>'."\n" + .'</script><br />'. &disablelink(@fields); return $output; } @@ -1180,19 +1316,19 @@ sub htmlareabrowser { =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) $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. Returns a string containing breadcrumbs for the current page. =item clear_breadcrumbs @@ -1216,66 +1352,73 @@ returns: nothing ############################################################ { my @Crumbs; + my %tools = (); sub breadcrumbs { - my ($component,$component_help,$menulink,$helplink,$css_class) = @_; - # - $css_class ||= 'LC_breadcrumbs'; - my $Str = "\n".'<table class="'.$css_class.'"><tr><td>'; + 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=''; + 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 '') { $description = $env{'course.'.$env{'request.course.id'}.'.description'}; + $no_mt_descr = 1; + } + $menulink = { href =>'/adm/menu', + title =>'Go to main menu', + target =>'_top', + text =>$description, + no_mt =>$no_mt_descr, }; + if($last) { + #$last set, so we have some crumbs + unshift(@Crumbs,$menulink); + } else { + #only menulink crumb present + $last = $menulink; } - unshift(@Crumbs,{ - href =>'/adm/menu', - title =>'Go to main menu', - target =>'_top', - text =>$description, - }); } - my $links .= - join('->', + my $links = join "", map { - $faq = $_->{'faq'} if (exists($_->{'faq'})); - $bug = $_->{'bug'} if (exists($_->{'bug'})); + $faq = $_->{'faq'} if (exists($_->{'faq'})); + $bug = $_->{'bug'} if (exists($_->{'bug'})); $help = $_->{'help'} if (exists($_->{'help'})); - my $result = '<a href="'.$_->{'href'}.'" '; - if (defined($_->{'target'}) && $_->{'target'} ne '') { - $result .= 'target="'.$_->{'target'}.'" '; - } - if ($_->{'no_mt'}) { - $result .='title="'.$_->{'title'}.'">'. - $_->{'text'}.'</a>'; - } else { - $result .='title="'.&mt($_->{'title'}).'">'. - &mt($_->{'text'}).'</a>'; - } - $result; - } @Crumbs - ); - $links .= '->' if ($links ne ''); - if ($last->{'no_mt'}) { - $links .= '<b>'.$last->{'text'}.'</b>'; - } else { - $links .= '<b>'.&mt($last->{'text'}).'</b>'; - } - # + + 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; + + #should the last Element be translated? + $links .= htmltag( 'li', + htmltag( 'b', + $last->{'no_mt'} ? + $last->{'text'} : mt($last->{'text'}) )); + my $icons = ''; - $faq = $last->{'faq'} if (exists($last->{'faq'})); - $bug = $last->{'bug'} if (exists($last->{'bug'})); + $faq = $last->{'faq'} if (exists($last->{'faq'})); + $bug = $last->{'bug'} if (exists($last->{'bug'})); $help = $last->{'help'} if (exists($last->{'help'})); $component_help=($component_help?$component_help:$help); # if ($faq ne '') { @@ -1284,39 +1427,101 @@ returns: nothing # if ($bug ne '') { # $icons .= &Apache::loncommon::help_open_bug($bug); # } - if ($faq ne '' || $component_help ne '' || $bug ne '') { - $icons .= &Apache::loncommon::help_open_menu($component, - $component_help, - $faq,$bug); - } - # - $Str .= $links.'</td>'; - # - if (defined($component)) { - $Str .= '<td class="'.$css_class.'_component">'. - &mt($component); - if ($icons ne '') { - $Str .= ' '.$icons; - } - $Str .= '</td>'; + if ($faq ne '' || $component_help ne '' || $bug ne '') { + $icons .= &Apache::loncommon::help_open_menu($component, + $component_help, + $faq,$bug); } - $Str .= '</tr></table>'."\n"; # + + + unless ($CourseBreadcrumbs) { + $links = htmltag('ol', $links, { id => "LC_MenuBreadcrumbs" }); + } else { + $links = htmltag('ul', $links, { class => "LC_CourseBreadcrumbs" }); + } + + if ($component) { + $links = htmltag('span', + ( $no_mt ? $component : mt($component) ). + ( $icons ? $icons : '' ), + { class => 'LC_breadcrumbs_component' } ) + .$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 $Str; + # Return the breadcrumb's line + return "$links"; } sub clear_breadcrumbs { undef(@Crumbs); + undef(%tools); } sub add_breadcrumb { - push (@Crumbs,@_); + push(@Crumbs,@_); + } + + + #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 clear_breadcrumb_tools { + undef(%tools); + } + + sub add_tools { + my ($links) = @_; + return unless defined %tools; + my $html = '<ul class="LC_bct">'; + for my $category ('A','B') { + $html .= '<li class="LC_breadcrumb_tools">' + . '<ul class="LC_breadcrumb_tools' + . " LC_breadcrumb_tools_$category\">"; + for my $item (@{$tools{$category}}){ + #SD ugly! I'll fix that later on + $item =~ s/align="(right|left)"//; + $item =~ s/<span(.*?)\/span>//; + $html .= "<li>$item</li>"; + } + $html .= '</li></ul>'; + if ($category eq 'A') { $html .= "<li>$$links</li>"; } + } + $$links = $html.'</ul>'; } + 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; + } + #SD END + } # End of scope for @Crumbs ############################################################ @@ -1333,7 +1538,7 @@ returns: nothing # row1 # row2 # row3 ... etc. -# &submit_row(0 +# &submit_row() # &end_pick_box() # # where row1, row 2 etc. are chosen from &role_select_row,&course_select_row, @@ -1375,6 +1580,9 @@ returns: nothing # routines, but can also be called directly to start and end rows which have # needs that are not accommodated by the *_select_row() routines. +{ # Start: row_count block for pick_box +my @row_count; + sub start_pick_box { my ($css_class) = @_; if (defined($css_class)) { @@ -1382,6 +1590,7 @@ sub start_pick_box { } else { $css_class= 'class="LC_pick_box"'; } + unshift(@row_count,0); my $output = <<"END"; <table $css_class> END @@ -1389,26 +1598,38 @@ END } sub end_pick_box { + shift(@row_count); my $output = <<"END"; </table> END return $output; } +sub row_headline { + my $output = <<"END"; + <tr><td colspan="2"> +END + return $output; +} + sub row_title { - my ($title,$css_title_class,$css_value_class) = @_; + my ($title,$css_title_class,$css_value_class, $css_value_furtherAttributes) = @_; + $row_count[0]++; + my $css_class = ($row_count[0] % 2)?'LC_odd_row':'LC_even_row'; $css_title_class ||= 'LC_pick_box_title'; $css_title_class = 'class="'.$css_title_class.'"'; $css_value_class ||= 'LC_pick_box_value'; - $css_value_class = 'class="'.$css_value_class.'"'; + if ($title ne '') { + $title .= ':'; + } my $output = <<"ENDONE"; - <tr class="LC_pick_box_row"> + <tr class="LC_pick_box_row" $css_value_furtherAttributes> <td $css_title_class> - $title: + $title </td> - <td $css_value_class> + <td class="$css_value_class $css_class"> ENDONE return $output; } @@ -1430,14 +1651,21 @@ ENDTWO return $output; } +} # End: row_count block for pick_box + + sub role_select_row { my ($roles,$title,$css_class,$show_separate_custom,$cdom,$cnum) = @_; + my $crstype = 'Course'; + if ($cdom ne '' && $cnum ne '') { + $crstype = &Apache::loncommon::course_type($cdom.'_'.$cnum); + } my $output; if (defined($title)) { $output = &row_title($title,$css_class); } $output .= qq| - <select name="roles" multiple >\n|; + <select name="roles" multiple="multiple">\n|; foreach my $role (@$roles) { my $plrole; if ($role eq 'ow') { @@ -1456,7 +1684,7 @@ sub role_select_row { $plrole = &mt('Custom Role'); } } else { - $plrole=&Apache::lonnet::plaintext($role); + $plrole=&Apache::lonnet::plaintext($role,$crstype); } if (($role ne 'cr') || (!$show_separate_custom)) { $output .= ' <option value="'.$role.'">'.$plrole.'</option>'; @@ -1471,17 +1699,18 @@ sub role_select_row { sub course_select_row { my ($title,$formname,$totcodes,$codetitles,$idlist,$idlist_titles, - $css_class) = @_; + $css_class,$crstype) = @_; my $output = &row_title($title,$css_class); - $output .= &course_selection($formname,$totcodes,$codetitles,$idlist,$idlist_titles); + $output .= &course_selection($formname,$totcodes,$codetitles,$idlist,$idlist_titles,$crstype); $output .= &row_closure(); return $output; } sub course_selection { - my ($formname,$totcodes,$codetitles,$idlist,$idlist_titles) = @_; + my ($formname,$totcodes,$codetitles,$idlist,$idlist_titles,$crstype) = @_; my $output = qq| <script type="text/javascript"> +// <![CDATA[ function coursePick (formname) { for (var i=0; i<formname.coursepick.length; i++) { if (formname.coursepick[i].value == 'category') { @@ -1504,11 +1733,22 @@ sub course_selection { formname.courselist = ''; } } +// ]]> </script> |; + + my ($allcrs,$pickspec); + if ($crstype eq 'Community') { + $allcrs = &mt('All communities'); + $pickspec = &mt('Pick specific communities:'); + } else { + $allcrs = &mt('All courses'); + $pickspec = &mt('Pick specific course(s):'); + } + my $courseform='<b>'.&Apache::loncommon::selectcourse_link - ($formname,'pickcourse','pickdomain','coursedesc','',1).'</b>'; - $output .= '<input type="radio" name="coursepick" value="all" onclick="coursePick(this.form)" />'.&mt('All courses').'<br />'; + ($formname,'pickcourse','pickdomain','coursedesc','',1,$crstype).'</b>'; + $output .= '<input type="radio" name="coursepick" value="all" onclick="coursePick(this.form)" />'.$allcrs.'<br />'; if ($totcodes > 0) { my $numtitles = @$codetitles; if ($numtitles > 0) { @@ -1553,7 +1793,7 @@ sub course_selection { $output .= '</tr></table><br />'; } } - $output .= '<input type="radio" name="coursepick" value="specific" onclick="coursePick(this.form);opencrsbrowser('."'".$formname."','dccourse','dcdomain','coursedesc','','1'".')" />'.&mt('Pick specific course(s):').' '.$courseform.' <input type="text" value="0" size="4" name="coursetotal" /><input type="hidden" name="courselist" value="" />selected.<br />'."\n"; + $output .= '<input type="radio" name="coursepick" value="specific" onclick="coursePick(this.form);opencrsbrowser('."'".$formname."','dccourse','dcdomain','coursedesc','','1','$crstype'".')" />'.$pickspec.' '.$courseform.' <input type="text" value="0" size="4" name="coursetotal" /><input type="hidden" name="courselist" value="" />selected.<br />'."\n"; return $output; } @@ -1564,7 +1804,7 @@ sub status_select_row { $output = &row_title($title,$css_class,'LC_pick_box_select'); } $output .= qq| - <select name="types" multiple>\n|; + <select name="types" multiple="multiple">\n|; foreach my $status_type (sort(keys(%{$types}))) { $output .= ' <option value="'.$status_type.'">'.$$types{$status_type}.'</option>'; } @@ -1638,6 +1878,29 @@ sub course_custom_roles { ############################################## ############################################## + +# topic_bar +# +# Generates a div containing an (optional) numbered (static) image followed by a +# title with a background color defined in the corresponding CSS: LC_topic_bar +# Inputs: +# 1. number to display (corresponding static image should exist). +# img tag will be included if arg is an integer in the range 1 to 9. +# 2. title text to display. +# Outputs - a scalar containing html mark-up for the div. + +sub topic_bar { + my ($imgnum,$title) = @_; + my $imgtag; + if ($imgnum =~ /^[1-9]$/) { + $imgtag = '<img src="/res/adm/pages/bl_step'.$imgnum.'.gif"'. + ' alt="'.&mt('Step [_1]',$imgnum).'" /> '; + } + return '<div class="LC_topic_bar">'.$imgtag.$title.'</div>'; +} + +############################################## +############################################## # echo_form_input # @@ -1768,7 +2031,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}}); @@ -1803,6 +2066,8 @@ sub set_form_elements { $output .= qq| if (courseForm.elements['$name'].value == "$value") { courseForm.elements['$name'].checked = true; + } else { + courseForm.elements['$name'].checked = false; }|; } } @@ -1844,6 +2109,7 @@ sub set_form_elements { } } $output .= " + return; }\n"; return $output; } @@ -1885,6 +2151,273 @@ END return $scripttag; } + +# USAGE: htmltag(element, content, {attribute => 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 <br/> are correctly terminated, +# i.e. htmltag('br') returns <br/> +# - 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: <h1>This is a headline</h1> +# +# 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: +# <script type="text/javascript"> +# // BEGIN LON-CAPA Internal +# alert(Hello World!') +# // END LON-CAPA Internal +# </script> +# +# NOTES: +# - works currently only for javascripts +# +# OUTPUT: +# Scriptcode properly enclosed in <script> and CDATA tags (and LC +# Internal markers if 2nd argument is given) +sub scripttag { + my ( $content, $marker ) = @_; + return unless defined $content; + + my $begin = "\n// BEGIN LON-CAPA Internal\n"; + my $end = "\n// END LON-CAPA Internal\n"; + + if ($marker) { + $content = $begin . $content if $marker eq 'start' or $marker eq 'both'; + $content .= $end if $marker eq 'end' or $marker eq 'both'; + } + + $content = "\n// <![CDATA[\n$content\n// ]]>\n"; + + return htmltag('script', $content, {type => 'text/javascript'}); +}; + + +############################################## +############################################## + +# generate_menu +# +# Generates html markup for a menu. +# +# Inputs: +# An array of following structure: +# ({ categorytitle => 'Categorytitle', +# items => [ +# { +# linktext => 'Text to be displayed', +# url => 'URL the link is pointing to, i.e. /adm/site?action=dosomething', +# permission => 'Contains permissions as returned from lonnet::allowed(), +# must evaluate to true in order to activate the link', +# icon => 'icon filename', +# alttext => 'alt text for the icon', +# help => 'Name of the corresponding helpfile', +# linktitle => 'Description of the link (used for title tag)' +# }, +# ... +# ] +# }, +# ... +# ) +# +# 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 @categories; # each element represents the entire markup for a category + + foreach my $category (@menu) { + my @links; # contains the links for the current $category + foreach my $link (@{$$category{items}}) { + next unless $$link{permission}; + + # 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. + push(@links,$li->( + $a->( + $img->("", { + class => "LC_noBorder LC_middle", + src => "/res/adm/pages/$$link{icon}", + alt => mt(defined($$link{alttext}) ? + $$link{alttext} : $$link{linktext}) + }), { + href => $$link{url}, + title => mt($$link{linktitle}) + }). + $a->(mt($$link{linktext}), { + href => $$link{url}, + title => mt($$link{linktitle}), + class => "LC_menubuttons_link" + }). + (defined($$link{help}) ? + Apache::loncommon::help_open_topic($$link{help}) : ''), + {class => "LC_menubuttons_inline_text"})); + } + + # wrap categorytitle in <h3>, concatenate with + # joined and in <ul> tags wrapped @links + # and wrap everything in an enclosing <div> and push it into + # @categories + # such that each element looks like: + # <div><h3>title</h3><ul><li>...</li>...</ul></div> + # the category won't be added if there aren't any links + push(@categories, + $div->($h3->(mt($$category{categorytitle}), {class=>"LC_hcell"}). + $ul->(join('' ,@links), {class =>"LC_ListStyleNormal" }), + {class=>"LC_Box LC_400Box"})) if scalar(@links); + } + + # wrap the joined @categories in another <div> (column layout) + return $div->(join('', @categories), {class => "LC_columnSection"}); +} + +############################################## +############################################## + +=pod + +=item &start_funclist + +Start list of available functions + +Typically used to offer a simple list of available functions +at top or bottom of page. +All available functions/actions for the current page +should be included in this list. + +If the optional headline text is not provided, a default text will be used. + + +Related routines: +=over 4 +add_item_funclist +end_funclist +=back + + +Inputs: (optional) headline text + +Returns: HTML code with function list start + +=cut + +############################################## +############################################## + +sub start_funclist { + my($legendtext)=@_; + $legendtext=&mt('Functions') if !$legendtext; + return '<ul class="LC_funclist"><li style="font-weight:bold; margin-left:0.8em;">'.$legendtext.'</li>'."\n"; +} + + +############################################## +############################################## + +=pod + +=item &add_item_funclist + +Adds an item to the list of available functions + +Related routines: +=over 4 +start_funclist +end_funclist +=back + +Inputs: content item with text and link to function + +Returns: HTML code with list item for funclist + +=cut + +############################################## +############################################## + +sub add_item_funclist { + my($content) = @_; + return '<li>'.$content.'</li>'."\n"; +} + +############################################## +############################################## + +=pod + +=item &end_funclist + +End list of available functions + +Related routines: +=over 4 +start_funclist +add_item_funclist +=back + +Inputs: ./. + +Returns: HTML code with function list end + +=cut + +############################################## +############################################## + +sub end_funclist { + return "</ul>\n"; +} + 1; __END__