--- loncom/interface/lonhtmlcommon.pm 2002/07/22 20:35:05 1.1 +++ loncom/interface/lonhtmlcommon.pm 2021/06/07 06:15:55 1.399 @@ -1,246 +1,4086 @@ +# The LearningOnline Network with CAPA +# a pile of common html routines +# +# $Id: lonhtmlcommon.pm,v 1.399 2021/06/07 06:15:55 raeburn Exp $ +# +# Copyright Michigan State University Board of Trustees +# +# This file is part of the LearningOnline Network with CAPA (LON-CAPA). +# +# LON-CAPA is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# LON-CAPA is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with LON-CAPA; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# /home/httpd/html/adm/gpl.txt +# +# 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 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 MapOptions { - my ($data, $page)=@_; - my $Str = ''; - $Str .= ''."\n"; +=item &confirm_success() + +Successful completion of an operation message + +=cut + +sub confirm_success { + my ($message,$failure)=@_; + if ($failure) { + return ''."\n" + .''.&mt('Error').' '."\n" + .$message."\n" + .''."\n"; + } else { + return ''."\n" + .''.&mt('OK').' '."\n" + .$message."\n" + .''."\n"; + } +} + +############################################## +############################################## + +=pod + +=item &dragmath_button() + +Creates a button that launches a dragmath popup-window, in which an +expression can be edited and pasted as LaTeX into a specified textarea. + + textarea - Name of the textarea to edit. + helpicon - If true, show a help icon to the right of the button. + +=cut + +sub dragmath_button { + my ($textarea,$helpicon) = @_; + my $help_text; + if ($helpicon) { + $help_text = &Apache::loncommon::help_open_topic('Authoring_Math_Editor',undef,undef,undef,undef,'mathhelpicon_'.$textarea); + } + my $buttontext=&mt('Edit Math'); + return <$help_text +ENDDRAGMATH +} + +############################################## + +=pod + +=item &dragmath_js() + +Javascript used to open pop-up window containing dragmath applet which +can be used to paste LaTeX into a textarea. + +=cut + +sub dragmath_js { + my ($popup) = @_; + return < + // + + +ENDDRAGMATHJS +} + +############################################## +############################################## + +=pod + +=item &dependencies_button() +Creates a button that launches a popup-window, in which dependencies +for the web page in the main window can be added to, replaced or deleted. + +=cut + +sub dependencies_button { + my $buttontext=&mt('Manage Dependencies'); + return <<"END"; + +END +} + +############################################## + +=pod + +=item &dependencycheck_js() + +Javascript used to open pop-up window containing interface to manage +dependencies for a web page uploaded diretcly to a course. + +=cut + +sub dependencycheck_js { + my ($symb,$title,$url,$folderpath,$uri) = @_; + my $link; + if ($symb) { + $link = '/adm/dependencies?symb='.&HTML::Entities::encode($symb,'<>&"'); + } elsif ($folderpath) { + $link = '/adm/dependencies?folderpath='.&HTML::Entities::encode($folderpath,'<>&"'); + $url = $uri; + } elsif ($uri =~ m{^/public/$match_domain/$match_courseid/syllabus$}) { + $link = '/adm/dependencies'; + } + $link .= (($link=~/\?/)?'&':'?').'title='. + &HTML::Entities::encode($title,'<>&"'); + if ($url) { + $link .= '&url='.&HTML::Entities::encode($url,'<>&"'); + } + return < + // + +ENDJS +} + +############################################## +############################################## + +=pod + +=item &authorbombs() + +=cut + +############################################## +############################################## + +sub authorbombs { + my $url=shift; + $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 my $bomb (keys(%bombs)) { + if ($bomb =~ /^$udom\/$uname\//) { + return ''.&mt('Bomb').''. + &Apache::loncommon::help_open_topic('About_Bombs'); + } + } + return ''; +} + +############################################## +############################################## + +sub recent_filename { + my $area=shift; + return 'nohist_recent_'.&escape($area); +} + +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) }); +} + +sub remove_recent { + my ($area,$names)=@_; + my $file=&recent_filename($area); + return &Apache::lonnet::del($file,$names); +} + +sub select_recent { + my ($area,$fieldname,$event)=@_; + my %recent=&Apache::lonnet::dump(&recent_filename($area)); + my $return="\n\n"; + return $return; +} + +sub get_recent { + my ($area, $n) = @_; + my %recent=&Apache::lonnet::dump(&recent_filename($area)); + +# Create hash with key as time and recent as value +# Begin filling return_hash with any 'always_include' option + my %time_hash = (); + my %return_hash = (); + foreach my $item (keys(%recent)) { + my ($thistime,$thisvalue)=(split(/\&/,$recent{$item})); + if ($thistime eq 'always_include') { + $return_hash{$item} = &unescape($thisvalue); + $n--; + } else { + $time_hash{$thistime} = $item; + } + } + +# Sort by decreasing time and return key value pairs + my $idx = 1; + foreach my $item (reverse(sort(keys(%time_hash)))) { + $return_hash{$time_hash{$item}} = + &unescape((split(/\&/,$recent{$time_hash{$item}}))[1]); + if ($n && ($idx++ >= $n)) {last;} + } + + return %return_hash; +} + +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; +} + + + +=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 StudentOptions { - my ($cache, $students, $selectedName, $page)=@_; +############################################## +############################################## - my $Str = ''; - $Str = ''; + return $Str; +} + + +=pod + +=item &radiobutton() + +=cut + +############################################## +############################################## +sub radio { + my ($name,$checked,$value) = @_; + my $Str = ' +// 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; } - $Str .= '>All Students'."\n"; - foreach (@$students) { - $Str .= '{$_.':fullname'}; - $Str .= ''."\n"; + + } +// ]]> + +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; + unless (($nolink) || ($state eq 'disabled')) { + $cal_link = qq{}; + } + # + my $tzone = ' '.$tzname.' '; + if ($no_hh_mm_ss) { + $result .= &mt('[_1] [_2] [_3] ', + $monthselector,$dayselector,$yearselector). + $tzone; + } elsif ($no_mm_ss) { + $result .= &mt('[_1] [_2] [_3] [_4]', + $monthselector,$dayselector,$yearselector, + $hourselector). + $tzone; + + } elsif ($no_ss) { + $result .= &mt('[_1] [_2] [_3] [_4] [_5]m', + $monthselector,$dayselector,$yearselector, + $hourselector,$minuteselector). + $tzone; + + } else { + $result .= &mt('[_1] [_2] [_3] [_4] [_5]m [_6]s ', + $monthselector,$dayselector,$yearselector, + $hourselector,$minuteselector,$secondselector). + $tzone; + } + unless (($nolink) || ($state eq 'disabled')) { + $result .= &mt('[_1]Select Date[_2]',$cal_link,''); + } + $result .= "\n\n"; + 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); +} - $Str .= '= 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; + } + } + if (defined($env{'form.'.$dname.'_year'})) { + my $tmpyear = $env{'form.'.$dname.'_year'}; + if (($tmpyear =~ /^\d+$/) && ($tmpyear >= 1970)) { + $year = $tmpyear; + } + } + if (($year<1970) || ($year>2037)) { return undef; } + if (defined($sec) && defined($min) && defined($hour) && + 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; + } +} + +############################################## +############################################## + +=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 = <Active'."\n"; - $Str .= 'Expired'."\n"; - $Str .= 'Any'."\n"; + foreach my $type (['Active', &mt('Currently Has Access')], + ['Future', &mt('Will Have Future Access')], + ['Expired', &mt('Previously Had Access')], + ['Any', &mt('Any Access Status')]) { + my ($name,$label) = @$type; + $Str .= '