--- loncom/interface/lonhtmlcommon.pm 2002/07/22 21:21:32 1.2 +++ loncom/interface/lonhtmlcommon.pm 2007/11/17 01:46:03 1.171 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # a pile of common html routines # -# $Id: lonhtmlcommon.pm,v 1.2 2002/07/22 21:21:32 www Exp $ +# $Id: lonhtmlcommon.pm,v 1.171 2007/11/17 01:46:03 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -25,250 +25,1867 @@ # # http://www.lon-capa.org/ # +###################################################################### +###################################################################### + +=pod + +=head1 NAME + +Apache::lonhtmlcommon - routines to do common html things + +=head1 SYNOPSIS + +Referenced by other mod_perl Apache modules. + +=head1 INTRODUCTION + +lonhtmlcommon is a collection of subroutines used to present information +in a consistent html format, or provide other functionality related to +html. + +=head2 General Subroutines + +=over 4 + +=cut + +###################################################################### +###################################################################### package Apache::lonhtmlcommon; use strict; +use Time::Local; +use Time::HiRes; +use Apache::lonlocal; +use Apache::lonnet; +use LONCAPA; -sub MapOptions { - my ($data, $page)=@_; - my $Str = ''; - $Str .= ''."\n"; +############################################## +############################################## - return $Str; +sub recent_filename { + my $area=shift; + return 'nohist_recent_'.&escape($area); } -sub StudentOptions { - my ($cache, $students, $selectedName, $page)=@_; +sub store_recent { + my ($area,$name,$value,$freeze)=@_; + my $file=&recent_filename($area); + my %recent=&Apache::lonnet::dump($file); + if (scalar(keys(%recent))>20) { +# remove oldest value + my $oldest=time(); + my $delkey=''; + foreach my $item (keys(%recent)) { + my $thistime=(split(/\&/,$recent{$item}))[0]; + if (($thistime ne "always_include") && ($thistime<$oldest)) { + $oldest=$thistime; + $delkey=$item; + } + } + &Apache::lonnet::del($file,[$delkey]); + } +# store new value + my $timestamp; + if ($freeze) { + $timestamp = "always_include"; + } else { + $timestamp = time(); + } + &Apache::lonnet::put($file,{ $name => + $timestamp.'&'.&escape($value) }); +} - my $Str = ''; - $Str = '\n"; + return $return; +} - foreach (@$students) { - $Str .= '{$_.':fullname'}; - $Str .= ''."\n"; } - $Str .= '= $n)) {last;} } - $Str .= '>No Student Selected'."\n"; - $Str .= ''."\n"; + return %return_hash; +} - return $Str; +sub get_recent_frozen { + my ($area) = @_; + my %recent=&Apache::lonnet::dump(&recent_filename($area)); + +# Create hash with all 'frozen' items + my %return_hash = (); + foreach my $item (keys(%recent)) { + my ($thistime,$thisvalue)=(split(/\&/,$recent{$item})); + if ($thistime eq 'always_include') { + $return_hash{$item} = &unescape($thisvalue); + } + } + return %return_hash; } -sub StatusOptions { - my ($status, $formName)=@_; - my $OpSel1 = ''; - my $OpSel2 = ''; - my $OpSel3 = ''; - - if($status eq 'Any') { $OpSel3 = ' selected'; } - elsif($status eq 'Expired' ) { $OpSel2 = ' selected'; } - else { $OpSel1 = ' selected'; } - my $Str = ''; - $Str .= ''."\n"; +=pod + +=item textbox + +=cut + +############################################## +############################################## +sub textbox { + my ($name,$value,$size,$special) = @_; + $size = 40 if (! defined($size)); + $value = &HTML::Entities::encode($value,'<>&"'); + my $Str = ''; + return $Str; } -sub Title { - my ($pageName)=@_; +############################################## +############################################## - my $Str = ''; +=pod + +=item checkbox - $Str .= ''.$pageName.''."\n"; - $Str .= ''."\n"; - $Str .= ''."\n"; - $Str .= '
'; - $Str .= '

Course: '; - $Str .= $ENV{'course.'.$ENV{'request.course.id'}.'.description'}; - $Str .= '

'."\n"; - $Str .= ''; - $Str .= '
'."\n"; -# $Str .= '

Current Time: '.localtime(time).'




'."\n"; +=cut +############################################## +############################################## +sub checkbox { + my ($name,$checked,$value) = @_; + my $Str = '{'reportSelected'} eq $reports->{$_}) { - $Str .= ' selected=""'; - } - $Str .= '>'.$reports->{$_}.''."\n"; - } - $Str .= ''."\n"; - - $Str .= ''; - $Str .= &StatusOptions($status, 'Statistics'); - $Str .= ''."\n"; +=item radiobutton - $Str .= ''."\n"; - $Str .= '
'."\n"; +=cut +############################################## +############################################## +sub radio { + my ($name,$checked,$value) = @_; + my $Str = '[$index]; - my $linkdata=$studentInformation->[$index]; - my $tempString = $displayString; - $tempString =~ s/LINKDATA/$linkdata/; - $tempString =~ s/DISPLAYDATA/$data/; - $Str .= $tempString; +############################################## +############################################## +sub date_setter { + my ($formname,$dname,$currentvalue,$special,$includeempty,$state, + $no_hh_mm_ss,$defhour,$defmin,$defsec,$nolink) = @_; + my $wasdefined=1; + if (! defined($state) || $state ne 'disabled') { + $state = ''; + } + if (! defined($no_hh_mm_ss)) { + $no_hh_mm_ss = 0; + } + if ($currentvalue eq 'now') { + $currentvalue=time; + } + if ((!defined($currentvalue)) || ($currentvalue eq '')) { + $wasdefined=0; + if ($includeempty) { + $currentvalue = 0; + } else { + $currentvalue = time; + } + } + # other potentially useful values: wkday,yrday,is_daylight_savings + my ($sec,$min,$hour,$mday,$month,$year)=('','',undef,'','',''); + if ($currentvalue) { + ($sec,$min,$hour,$mday,$month,$year,undef,undef,undef) = + localtime($currentvalue); + $year += 1900; + } + unless ($wasdefined) { + 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); + } elsif (!$includeempty) { + $sec=0; + $min=0; + $hour=0; + } + } + my $result = "\n\n"; + $result .= < + function $dname\_checkday() { + var day = document.$formname.$dname\_day.value; + var month = document.$formname.$dname\_month.value; + var year = document.$formname.$dname\_year.value; + var valid = true; + if (day < 1) { + document.$formname.$dname\_day.value = 1; + } + if (day > 31) { + document.$formname.$dname\_day.value = 31; + } + if ((month == 1) || (month == 3) || (month == 5) || + (month == 7) || (month == 8) || (month == 10) || + (month == 12)) { + if (day > 31) { + document.$formname.$dname\_day.value = 31; + day = 31; + } + } else if (month == 2 ) { + if ((year % 4 == 0) && (year % 100 != 0)) { + if (day > 29) { + document.$formname.$dname\_day.value = 29; + } + } else if (day > 29) { + document.$formname.$dname\_day.value = 28; + } + } else if (day > 30) { + document.$formname.$dname\_day.value = 30; + } + } + + function $dname\_disable() { + document.$formname.$dname\_month.disabled=true; + document.$formname.$dname\_day.disabled=true; + document.$formname.$dname\_year.disabled=true; + document.$formname.$dname\_hour.disabled=true; + document.$formname.$dname\_minute.disabled=true; + document.$formname.$dname\_second.disabled=true; + } + + function $dname\_enable() { + document.$formname.$dname\_month.disabled=false; + document.$formname.$dname\_day.disabled=false; + document.$formname.$dname\_year.disabled=false; + document.$formname.$dname\_hour.disabled=false; + document.$formname.$dname\_minute.disabled=false; + document.$formname.$dname\_second.disabled=false; + } + + function $dname\_opencalendar() { + if (! document.$formname.$dname\_month.disabled) { + var calwin=window.open( +"/adm/announcements?pickdate=yes&formname=$formname&element=$dname&month="+ +document.$formname.$dname\_month.value+"&year="+ +document.$formname.$dname\_year.value, + "LONCAPAcal", + "height=350,width=350,scrollbars=yes,resizable=yes,menubar=no"); + } + + } + +ENDJS + $result .= ' '; + my $monthselector = qq{'; + # Day + my $dayselector = qq{}; + # Year + my $yearselector = qq{}; + # + my $hourselector = qq{\n"; + my $minuteselector = qq{}; + my $secondselector= qq{}; + my $cal_link; + if (!$nolink) { + $cal_link = qq{}; } + # + if ($no_hh_mm_ss) { + $result .= &mt('[_1] [_2] [_3] ', + $monthselector,$dayselector,$yearselector); + if (!$nolink) { + $result .= &mt('[_1]Select Date[_2]',$cal_link,''); + } + } else { + $result .= &mt('[_1] [_2] [_3] [_4] [_5]m [_6]s ', + $monthselector,$dayselector,$yearselector, + $hourselector,$minuteselector,$secondselector); + if (!$nolink) { + $result .= &mt('[_1]Select Date[_2]',$cal_link,''); + } + } + $result .= "\n\n"; + return $result; +} + + +sub build_url { + my ($base, $fields)=@_; + my $url; + $url = $base.'?'; + foreach my $key (keys(%$fields)) { + $url.=&escape($key).'='.&escape($$fields{$key}).'&'; + } + $url =~ s/&$//; + return $url; +} + + +############################################## +############################################## + +=pod + +=item &get_date_from_form + +get_date_from_form retrieves the date specified in an &date_setter form. + +Inputs: + +=over 4 + +=item $dname +The name passed to &datesetter, which prefixes the form elements. + +=item $defaulttime + +The unix time to use as the default in case of poor inputs. + +=back + +Returns: Unix time represented in the form. + +=cut + +############################################## +############################################## +sub get_date_from_form { + my ($dname) = @_; + my ($sec,$min,$hour,$day,$month,$year); + # + if (defined($env{'form.'.$dname.'_second'})) { + my $tmpsec = $env{'form.'.$dname.'_second'}; + if (($tmpsec =~ /^\d+$/) && ($tmpsec >= 0) && ($tmpsec < 60)) { + $sec = $tmpsec; + } + if (!defined($tmpsec) || $tmpsec eq '') { $sec = 0; } + } else { + $sec = 0; + } + if (defined($env{'form.'.$dname.'_minute'})) { + my $tmpmin = $env{'form.'.$dname.'_minute'}; + if (($tmpmin =~ /^\d+$/) && ($tmpmin >= 0) && ($tmpmin < 60)) { + $min = $tmpmin; + } + if (!defined($tmpmin) || $tmpmin eq '') { $min = 0; } + } else { + $min = 0; + } + if (defined($env{'form.'.$dname.'_hour'})) { + my $tmphour = $env{'form.'.$dname.'_hour'}; + if (($tmphour =~ /^\d+$/) && ($tmphour >= 0) && ($tmphour < 24)) { + $hour = $tmphour; + } + } else { + $hour = 0; + } + if (defined($env{'form.'.$dname.'_day'})) { + my $tmpday = $env{'form.'.$dname.'_day'}; + if (($tmpday =~ /^\d+$/) && ($tmpday > 0) && ($tmpday < 32)) { + $day = $tmpday; + } + } + if (defined($env{'form.'.$dname.'_month'})) { + my $tmpmonth = $env{'form.'.$dname.'_month'}; + if (($tmpmonth =~ /^\d+$/) && ($tmpmonth > 0) && ($tmpmonth < 13)) { + $month = $tmpmonth - 1; + } + } + if (defined($env{'form.'.$dname.'_year'})) { + my $tmpyear = $env{'form.'.$dname.'_year'}; + if (($tmpyear =~ /^\d+$/) && ($tmpyear > 1900)) { + $year = $tmpyear - 1900; + } + } + if (($year<70) || ($year>137)) { 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); + } else { + return undef; + } +} + +############################################## +############################################## + +=pod + +=item &pjump_javascript_definition() + +Returns javascript defining the 'pjump' function, which opens up a +parameter setting wizard. + +=cut + +############################################## +############################################## +sub pjump_javascript_definition { + my $Str = <'."\n"; + } + + $Str .= ''."\n"; +} + +######################################################## +######################################################## + +=pod + +=item Progess Window Handling Routines + +These routines handle the creation, update, increment, and closure of +progress windows. The progress window reports to the user the number +of items completed and an estimate of the time required to complete the rest. + +=over 4 + + +=item &Create_PrgWin + +Writes javascript to the client to open a progress window and returns a +data structure used for bookkeeping. + +Inputs + +=over 4 + +=item $r Apache request + +=item $title The title of the progress window + +=item $heading A description (usually 1 line) of the process being initiated. + +=item $number_to_do The total number of items being processed. + +=item $type Either 'popup' or 'inline' (popup is assumed if nothing is + specified) + +=item $width Specify the width in charaters of the input field. + +=item $formname Only useful in the inline case, if a form already exists, this needs to be used and specfiy the name of the form, otherwise the Progress line will be created in a new form of it's own + +=item $inputname Only useful in the inline case, if a form and an input of type text exists, use this to specify the name of the input field + +=back + +Returns a hash containing the progress state data structure. + + +=item &Update_PrgWin + +Updates the text in the progress indicator. Does not increment the count. +See &Increment_PrgWin. -This function produces a formatted string of the student's information: -username, domain, section, full name, and PID. +Inputs: =over 4 -Input: $cache, $name, $studentInformation, $spacePadding +=item $r Apache request -$cache: This is a pointer to a hash that is tied to the cached data +=item $prog_state Pointer to the data structure returned by &Create_PrgWin -$name: The name and domain of the current student in name:domain format +=item $displaystring The string to write to the status indicator -$studentInformation: A pointer to an array holding the names used to +=back + +Returns: none + + +=item Increment_PrgWin -remove data from the hash. They represent the name of the data to be removed. +Increment the count of items completed for the progress window by 1. + +Inputs: + +=over 4 -$spacePadding: Extra spaces that represent the space between columns +=item $r Apache request -Output: $Str +=item $prog_state Pointer to the data structure returned by Create_PrgWin -$Str: Formatted string. +=item $extraInfo A description of the items being iterated over. Typically +'student'. + +=back + +Returns: none + + +=item Close_PrgWin + +Closes the progress window. + +Inputs: + +=over 4 + +=item $r Apache request + +=item $prog_state Pointer to the data structure returned by Create_PrgWin + +=back + +Returns: none =back =cut -sub FormatStudentInformation { - my ($cache,$name,$studentInformation,$spacePadding)=@_; - my $Str=''; - my $data; +######################################################## +######################################################## + +my $uniq=0; +sub get_uniq_name { + $uniq++; + return 'uniquename'.$uniq; +} + +# Create progress +sub Create_PrgWin { + my ($r, $title, $heading, $number_to_do,$type,$width,$formname, + $inputname)=@_; + if (!defined($type)) { $type='popup'; } + if (!defined($width)) { $width=55; } + my %prog_state; + $prog_state{'type'}=$type; + if ($type eq 'popup') { + $prog_state{'window'}='popwin'; + my $start_page = + &Apache::loncommon::start_page($title,undef, + {'only_body' => 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,'"); + $prog_state{'formname'}='popremain'; + $prog_state{'inputname'}="remaining"; + } elsif ($type eq 'inline') { + $prog_state{'window'}='window'; + if (!$formname) { + $prog_state{'formname'}=&get_uniq_name(); + &r_print($r,'
'); + } else { + $prog_state{'formname'}=$formname; + } + if (!$inputname) { + $prog_state{'inputname'}=&get_uniq_name(); + &r_print($r,&mt("$heading [_1]",' ')); + } else { + $prog_state{'inputname'}=$inputname; + + } + if (!$formname) { &r_print($r,'
'); } + &Update_PrgWin($r,\%prog_state,&mt('Starting')); + } + + $prog_state{'done'}=0; + $prog_state{'firststart'}=&Time::HiRes::time(); + $prog_state{'laststart'}=&Time::HiRes::time(); + $prog_state{'max'}=$number_to_do; + + return %prog_state; +} + +# update progress +sub Update_PrgWin { + my ($r,$prog_state,$displayString)=@_; + &r_print($r,''); + $$prog_state{'laststart'}=&Time::HiRes::time(); +} + +# increment progress state +sub Increment_PrgWin { + my ($r,$prog_state,$extraInfo)=@_; + $$prog_state{'done'}++; + my $time_est= (&Time::HiRes::time() - $$prog_state{'firststart'})/ + $$prog_state{'done'} * + ($$prog_state{'max'}-$$prog_state{'done'}); + $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); + } elsif ($lasttime < 0.01) { + $lasttime = 0; + } 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 = ''; + } + &r_print($r,''); + $$prog_state{'laststart'}=&Time::HiRes::time(); +} + +# close Progress Line +sub Close_PrgWin { + my ($r,$prog_state)=@_; + if ($$prog_state{'type'} eq 'popup') { + &r_print($r,''."\n"); + } elsif ($$prog_state{'type'} eq 'inline') { + &Update_PrgWin($r,$prog_state,&mt('Done')); + } + 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'; + } + if ($target) { + $target = ' target="'. + &Apache::loncommon::escape_single($target).'"'; + } + my $output=''; + unless ($noformat) { $output.='
'; } + $output.=''.$prefix.'/'; + if ($env{'user.adv'}) { + my $path=$prefix.'/'; + foreach my $dir (split('/',$uri)) { + if (! $dir) { next; } + $path .= $dir; + if ($path eq $uri) { + if ($skiplast) { + $output.=$dir; + last; + } + } else { + $path.='/'; + } + my $href_path = &HTML::Entities::encode($path,'<>&"'); + &Apache::loncommon::inhibit_menu_check(\$href_path); + if ($form) { + my $href = 'javascript:'.$form.".action='".$href_path."';".$form.'.submit();'; + $output.=qq{$dir/}; + } else { + $output.=qq{$dir/}; + } + } + } else { + foreach my $dir (split('/',$uri)) { + if (! $dir) { next; } + $output.=$dir.'/'; + } + } + if ($uri !~ m|/$|) { $output=~s|/$||; } + return $output.''.($noformat?'':'
'); +} + +# --------------------- A function that generates a window for the spellchecker + +sub spellheader { + my $start_page= + &Apache::loncommon::start_page('Speller Suggestions',undef, + {'only_body' => 1, + 'js_ready' => 1, + 'bgcolor' => '#DDDDDD', + 'add_entries' => { + 'onload' => + 'document.forms.spellcheckform.submit()', + } + }); + my $end_page= + &Apache::loncommon::end_page({'js_ready' => 1}); + + my $nothing=&javascript_nothing(); + return (< +// + +ENDCHECK +} + +# ---------------------------------- Generate link to spell checker for a field + +sub spelllink { + my ($form,$field)=@_; + my $linktext=&mt('Check Spelling'); + return (<$linktext +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; + } +} + +sub htmlareaheaders { + return if (&htmlareablocked()); + return if (!&htmlareabrowser()); + return (< +ENDHEADERS +} + +# ----------------------------------------------------------------- Preferences + +sub disablelink { + my @fields=@_; + if (defined($#fields)) { + unless ($#fields>=0) { return ''; } + } + return ''.&mt('Disable WYSIWYG Editor').''; +} + +sub enablelink { + my @fields=@_; + if (defined($#fields)) { + unless ($#fields>=0) { return ''; } + } + return ''.&mt('Enable WYSIWYG Editor').''; +} + +# ------------------------------------------------- lang to use in html editor +sub htmlarea_lang { + my $lang='en'; + if (&mt('htmlarea_lang') ne 'htmlarea_lang') { + $lang=&mt('htmlarea_lang'); + } + return $lang; +} + +# ----------------------------------------- Script to activate only some fields + +sub htmlareaselectactive { + my @fields=@_; + unless (&htmlareabrowser()) { return ''; } + if (&htmlareablocked()) { return '
'.&enablelink(@fields); } + my $output='
". + &disablelink(@fields); + return $output; +} + +# --------------------------------------------------------------------- Blocked + +sub htmlareablocked { + unless ($env{'environment.wysiwygeditor'} eq 'on') { return 1; } + return 0; +} + +# ---------------------------------------- Browser capable of running HTMLArea? + +sub htmlareabrowser { + return 1; +} + +############################################################ +############################################################ + +=pod + +=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). +A link to help for the component will be included if one is specified. - for(my $index=0; $index<(scalar @$studentInformation); $index++) { - if(!&ShouldShowColumn($cache, 'ChartHeading'.$index)) { +All inputs can be undef without problems. + +Inputs: $component (the large text on the right side of the table), + $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) +Returns a string containing breadcrumbs for the current page. + +=item clear_breadcrumbs + +Clears the previously stored breadcrumbs. + +=item add_breadcrumb + +Pushes a breadcrumb on the stack of crumbs. + +input: $breadcrumb, a hash reference. The keys 'href','title', and 'text' +are required. If present the keys 'faq' and 'bug' will be used to provide +links to the FAQ and bug sites. If the key 'no_mt' is present the 'title' +and 'text' values won't be sent through &mt() + +returns: nothing + +=cut + +############################################################ +############################################################ +{ + my @Crumbs; + + sub breadcrumbs { + my ($component,$component_help,$menulink,$helplink,$css_class) = @_; + # + $css_class ||= 'LC_breadcrumbs'; + my $Str = "\n".''; + # + if (defined($component)) { + $Str .= ''; + } + $Str .= '
'; + # + # Make the faq and bug data cascade + my $faq = ''; + my $bug = ''; + my $help=''; + # 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 ($menulink) { + my $description = 'Menu'; + if (exists($env{'request.course.id'}) && + $env{'request.course.id'} ne '') { + $description = + $env{'course.'.$env{'request.course.id'}.'.description'}; + } + unshift(@Crumbs,{ + href =>'/adm/menu', + title =>'Go to main menu', + target =>'_top', + text =>$description, + }); + } + my $links .= + join('->', + map { + $faq = $_->{'faq'} if (exists($_->{'faq'})); + $bug = $_->{'bug'} if (exists($_->{'bug'})); + $help = $_->{'help'} if (exists($_->{'help'})); + my $result = '{'target'}) && $_->{'target'} ne '') { + $result .= 'target="'.$_->{'target'}.'" '; + } + if ($_->{'no_mt'}) { + $result .='title="'.$_->{'title'}.'">'. + $_->{'text'}.''; + } else { + $result .='title="'.&mt($_->{'title'}).'">'. + &mt($_->{'text'}).''; + } + $result; + } @Crumbs + ); + $links .= '->' if ($links ne ''); + if ($last->{'no_mt'}) { + $links .= ''.$last->{'text'}.''; + } else { + $links .= ''.&mt($last->{'text'}).''; + } + # + my $icons = ''; + $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 '') { +# $icons .= &Apache::loncommon::help_open_faq($faq); +# } +# 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.''. + &mt($component); + if ($icons ne '') { + $Str .= ' '.$icons; + } + $Str .= '
'."\n"; + # + # Return the @Crumbs stack to what we started with + push(@Crumbs,$last); + shift(@Crumbs); + # + return $Str; + } + + sub clear_breadcrumbs { + undef(@Crumbs); + } + + sub add_breadcrumb { + push (@Crumbs,@_); + } + +} # End of scope for @Crumbs + +############################################################ +############################################################ + +# Nested table routines. +# +# Routines to display form items in a multi-row table with 2 columns. +# Uses nested tables to divide form elements into segments. +# For examples of use see loncom/interface/lonnotify.pm +# +# Can be used in following order: ... +# &start_pick_box() +# row1 +# row2 +# row3 ... etc. +# &submit_row(0 +# &end_pick_box() +# +# where row1, row 2 etc. are chosen from &role_select_row,&course_select_row, +# &status_select_row and &email_default_row +# +# Can also be used in following order: +# +# &start_pick_box() +# &row_title() +# &row_closure() +# &row_title() +# &row_closure() ... etc. +# &submit_row() +# &end_pick_box() +# +# In general a &submit_row() call should proceed the call to &end_pick_box(), +# as this routine adds a button for form submission. +# &submit_row() does not require a &row_closure after it. +# +# &start_pick_box() creates a bounding table with 1-pixel wide black border. +# rows should be placed between calls to &start_pick_box() and &end_pick_box. +# +# &row_title() adds a title in the left column for each segment. +# &row_closure() closes a row with a 1-pixel wide black line. +# +# &role_select_row() provides a select box from which to choose 1 or more roles +# &course_select_row provides ways of picking groups of courses +# radio buttons: all, by category or by picking from a course picker pop-up +# note: by category option is only displayed if a domain has implemented +# selection by year, semester, department, number etc. +# +# &status_select_row() provides a select box from which to choose 1 or more +# access types (current access, prior access, and future access) +# +# &email_default_row() provides text boxes for default e-mail suffixes for +# different authentication types in a domain. +# +# &row_title() and &row_closure() are called internally by the &*_select_row +# routines, but can also be called directly to start and end rows which have +# needs that are not accommodated by the *_select_row() routines. + +sub start_pick_box { + my ($css_class) = @_; + if (defined($css_class)) { + $css_class = 'class="'.$css_class.'"'; + } else { + $css_class= 'class="LC_pick_box"'; + } + my $output = <<"END"; + +END + return $output; +} + +sub end_pick_box { + my $output = <<"END"; +
+END + return $output; +} + +sub row_title { + my ($title,$css_title_class,$css_value_class) = @_; + $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.'"'; + + my $output = <<"ENDONE"; + + + $title: + + +ENDONE + return $output; +} + +sub row_closure { + my ($no_separator) =@_; + my $output = <<"ENDTWO"; + + +ENDTWO + if (!$no_separator) { + $output .= <<"ENDTWO"; + + + + +ENDTWO + } + return $output; +} + +sub role_select_row { + my ($roles,$title,$css_class,$show_separate_custom,$cdom,$cnum) = @_; + my $output; + if (defined($title)) { + $output = &row_title($title,$css_class); + } + $output .= qq| + \n|; + if (defined($title)) { + $output .= &row_closure(); + } + return $output; +} + +sub course_select_row { + my ($title,$formname,$totcodes,$codetitles,$idlist,$idlist_titles, + $css_class) = @_; + my $output = &row_title($title,$css_class); + $output .= &course_selection($formname,$totcodes,$codetitles,$idlist,$idlist_titles); + $output .= &row_closure(); + return $output; +} + +sub course_selection { + my ($formname,$totcodes,$codetitles,$idlist,$idlist_titles) = @_; + my $output = qq| + + |; + my $courseform=''.&Apache::loncommon::selectcourse_link + ($formname,'pickcourse','pickdomain','coursedesc','',1).''; + $output .= ''.&mt('All courses').'
'; + if ($totcodes > 0) { + my $numtitles = @$codetitles; + if ($numtitles > 0) { + $output .= ''.&mt('Pick courses by category:').'
'; + $output .= ''; + for (my $i=1; $i<$numtitles; $i++) { + $output .= ''; + } + $output .= '
'.$$codetitles[0].'
'."\n". + '
'.$$codetitles[$i].'
'."\n". + ''."\n". + '

'; + } + } + $output .= ''.&mt('Pick specific course(s):').' '.$courseform.'  selected.
'."\n"; + return $output; +} + +sub status_select_row { + my ($types,$title,$css_class) = @_; + my $output; + if (defined($title)) { + $output = &row_title($title,$css_class,'LC_pick_box_select'); + } + $output .= qq| + \n|; + if (defined($title)) { + $output .= &row_closure(); + } + return $output; +} + +sub email_default_row { + my ($authtypes,$title,$descrip,$css_class) = @_; + my $output = &row_title($title,$css_class); + $output .= $descrip. + &Apache::loncommon::start_data_table(). + &Apache::loncommon::start_data_table_header_row(). + ''.&mt('Authentication Method').''. + ''.&mt('Username -> e-mail conversion').''."\n". + &Apache::loncommon::end_data_table_header_row(); + my $rownum = 0; + foreach my $auth (sort(keys(%{$authtypes}))) { + my ($userentry,$size); + if ($auth =~ /^krb/) { + $userentry = ''; + $size = 25; + } else { + $userentry = 'username@'; + $size = 15; + } + $output .= &Apache::loncommon::start_data_table_row(). + ' '.$$authtypes{$auth}.''. + ''.$userentry. + ''. + &Apache::loncommon::end_data_table_row(); + } + $output .= &Apache::loncommon::end_data_table(); + $output .= &row_closure(); + return $output; +} + + +sub submit_row { + my ($title,$cmd,$submit_text,$css_class) = @_; + my $output = &row_title($title,$css_class,'LC_pick_box_submit'); + $output .= qq| +
+ +   +

+ \n|; + return $output; +} + +sub course_custom_roles { + my ($cdom,$cnum) = @_; + my %returnhash=(); + my %coursepersonnel=&Apache::lonnet::dump('nohist_userroles',$cdom,$cnum); + foreach my $person (sort(keys(%coursepersonnel))) { + my ($role) = ($person =~ /^([^:]+):/); + my ($end,$start) = split(/:/,$coursepersonnel{$person}); + if ($end == -1 && $start == -1) { next; } - $data=$cache->{$name.':'.$studentInformation->[$index]}; - $Str .= $data; + if ($role =~ m|^cr/[^/]+/[^/]+/[^/]|) { + $returnhash{$role} ++; + } + } + return %returnhash; +} - my @dataLength=split(//,$data); - my $length=scalar @dataLength; - $Str .= (' 'x($cache->{$studentInformation->[$index].'Length'}- - $length)); - $Str .= $spacePadding; + +############################################## +############################################## + +# echo_form_input +# +# Generates html markup to add form elements from the referrer page +# as hidden form elements (values encoded) in the new page. +# +# Intended to support two types of use +# (a) to allow backing up to earlier pages in a multi-page +# form submission process using a breadcrumb trail. +# +# (b) to allow the current page to be reloaded with form elements +# set on previous page to remain unchanged. An example would +# be where the a page containing a dynamically-built table of data is +# is to be redisplayed, with only the sort order of the data changed. +# +# Inputs: +# 1. Reference to array of form elements in the submitted form on +# the referrer page which are to be excluded from the echoed elements. +# +# 2. Reference to array of regular expressions, which if matched in the +# name of the form element n the referrer page will be omitted from echo. +# +# Outputs: A scalar containing the html markup for the echoed form +# elements (all as hidden elements, with values encoded). + + +sub echo_form_input { + my ($excluded,$regexps) = @_; + my $output = ''; + foreach my $key (keys(%env)) { + 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 (!$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"; + } + } + } + } } + return $output; +} - return $Str; +############################################## +############################################## + +# set_form_elements +# +# Generates javascript to set form elements to values based on +# corresponding values for the same form elements when the page was +# previously submitted. +# +# Last submission values are read from hidden form elements in referring +# page which have the same name, i.e., generated by &echo_form_input(). +# +# Intended to be called by onload event. +# +# Inputs: +# (a) Reference to hash of echoed form elements to be set. +# +# In the hash, keys are the form element names, and the values are the +# element type (selectbox, radio, checkbox or text -for textbox, textarea or +# hidden). +# +# (b) Optional reference to hash of stored elements to be set. +# +# If the page being displayed is a page which permits modification of +# previously stored data, e.g., the first page in a multi-page submission, +# then if stored is supplied, form elements will be set to the last stored +# values. If user supplied values are also available for the same elements +# these will replace the stored values. +# +# Output: +# +# javascript function - set_form_elements() which sets form elements, +# expects an argument: formname - the name of the form according to +# the DOM, e.g., document.compose + +sub set_form_elements { + my ($elements,$stored) = @_; + my %values; + my $output .= 'function setFormElements(courseForm) { +'; + if (defined($stored)) { + foreach my $name (keys(%{$stored})) { + if (exists($$elements{$name})) { + if (ref($$stored{$name}) eq 'ARRAY') { + $values{$name} = $$stored{$name}; + } else { + @{$values{$name}} = ($$stored{$name}); + } + } + } + } + + foreach my $key (keys(%env)) { + if ($key =~ /^form\.(.+)$/) { + my $name = $1; + if (exists($$elements{$name})) { + @{$values{$name}} = &Apache::loncommon::get_env_multiple($key); + } + } + } + + foreach my $name (keys(%values)) { + for (my $i=0; $i<@{$values{$name}}; $i++) { + $values{$name}[$i] = &HTML::Entities::decode($values{$name}[$i],'<>&"'); + $values{$name}[$i] =~ s/([\r\n\f]+)/\\n/g; + $values{$name}[$i] =~ s/"/\\"/g; + } + if ($$elements{$name} eq 'text') { + my $numvalues = @{$values{$name}}; + if ($numvalues > 1) { + my $valuestring = join('","',@{$values{$name}}); + $output .= qq| + var textvalues = new Array ("$valuestring"); + var total = courseForm.elements['$name'].length; + if (total > $numvalues) { + total = $numvalues; + } + for (var i=0; i= 0) { + return true; + } + return false; + } +} +END + return $scripttag; } 1; + __END__