--- loncom/interface/lonhtmlcommon.pm 2011/06/03 13:00:39 1.290 +++ loncom/interface/lonhtmlcommon.pm 2022/07/08 16:04:35 1.358.2.19.2.3 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # a pile of common html routines # -# $Id: lonhtmlcommon.pm,v 1.290 2011/06/03 13:00:39 www Exp $ +# $Id: lonhtmlcommon.pm,v 1.358.2.19.2.3 2022/07/08 16:04:35 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -61,18 +61,28 @@ use Time::HiRes; use Apache::lonlocal; use Apache::lonnet; use HTML::Entities(); -use LONCAPA; +use LONCAPA qw(:DEFAULT :match); sub java_not_enabled { - return "\n".''. - &mt('The required Java applet could not be started. Please make sure to have Java installed and active in your browser.'). - "\n"; + if (($env{'browser.mobile'}) && ($env{'browser.mobile'} =~ /^ipad|ipod|iphone$/i)) { + return "\n".''. + &mt('The required Java applet could not be started, because Java is not supported by your mobile device.'). + "\n"; + } else { + return "\n".''. + &mt('The required Java applet could not be started. Please make sure to have Java installed and active in your browser.'). + "\n"; + } } sub coursepreflink { my ($text,$category)=@_; if (&Apache::lonnet::allowed('opa',$env{'request.course.id'})) { - return '&"').'">'.$text.''; + my $target =' target="_top"'; + if (($env{'request.deeplink.login'}) && ($env{'request.deeplink.target'} eq '_self')) { + $target = ''; + } + return '&"').'">'.$text.''; } else { return ''; } @@ -86,7 +96,7 @@ sub raw_href_to_link { sub entity_encode { my ($text)=@_; - return &HTML::Entities::encode($text, '<>&"'); + return &HTML::Entities::encode($text, '\'<>&"'); } sub direct_parm_link { @@ -95,7 +105,11 @@ sub direct_parm_link { $filter=&entity_encode($filter); $part=&entity_encode($part); if (($symb) && (&Apache::lonnet::allowed('opa')) && ($target ne 'tex')) { - return "$linktext"; + my $target=' target="_top"'; + if (($env{'request.deeplink.login'}) && ($env{'request.deeplink.target'} eq '_self')) { + $target = ''; + } + return "$linktext"; } else { return $linktext; } @@ -103,7 +117,7 @@ sub direct_parm_link { ############################################## ############################################## -=item confirm_success +=item &confirm_success() Successful completion of an operation message @@ -129,7 +143,7 @@ sub confirm_success { =pod -=item dragmath_button +=item &dragmath_button() Creates a button that launches a dragmath popup-window, in which an expression can be edited and pasted as LaTeX into a specified textarea. @@ -155,10 +169,11 @@ ENDDRAGMATH =pod -=item dragmath_js +=item &dragmath_js() Javascript used to open pop-up window containing dragmath applet which can be used to paste LaTeX into a textarea. + =cut sub dragmath_js { @@ -169,7 +184,7 @@ sub dragmath_js { function mathedit(textarea, doc) { targetEntry = textarea; targetDoc = doc; - newwin = window.open("/adm/dragmath/applet/$popup.html","","width=565,height=500,resizable"); + newwin = window.open("/adm/dragmath/$popup.html","","width=565,height=500,resizable"); } // ]]> @@ -177,13 +192,69 @@ sub dragmath_js { ENDDRAGMATHJS } +############################################## +############################################## + +=pod + +=item &dependencies_button() + +Creates a button that launches a popup-window, in which dependencies +for the web page in the main window can be added to, replaced or deleted. + +=cut + +sub dependencies_button { + my $buttontext=&mt('Manage Dependencies'); + return <<"END"; + +END +} + +############################################## + +=pod + +=item &dependencycheck_js() + +Javascript used to open pop-up window containing interface to manage +dependencies for a web page uploaded diretcly to a course. + +=cut + +sub dependencycheck_js { + my ($symb,$title,$url,$folderpath,$uri) = @_; + my $link; + if ($symb) { + $link = '/adm/dependencies?symb='.&HTML::Entities::encode($symb,'<>&"'); + } elsif ($folderpath) { + $link = '/adm/dependencies?folderpath='.&HTML::Entities::encode($folderpath,'<>&"'); + $url = $uri; + } elsif ($uri =~ m{^/public/$match_domain/$match_courseid/syllabus$}) { + $link = '/adm/dependencies'; + } + $link .= (($link=~/\?/)?'&':'?').'title='. + &HTML::Entities::encode($title,'<>&"'); + if ($url) { + $link .= '&url='.&HTML::Entities::encode($url,'<>&"'); + } + return < + // + +ENDJS +} ############################################## ############################################## =pod -=item authorbombs +=item &authorbombs() =cut @@ -317,7 +388,7 @@ sub get_recent_frozen { =pod -=item textbox +=item &textbox() =cut @@ -337,14 +408,14 @@ sub textbox { =pod -=item checkbox +=item &checkbox() =cut ############################################## ############################################## sub checkbox { - my ($name,$checked,$value) = @_; + my ($name,$checked,$value,$special) = @_; my $Str = ''; return $Str; } =pod -=item radiobutton +=item &radiobutton() =cut @@ -383,10 +454,10 @@ sub radio { =pod -=item &date_setter +=item &date_setter() &date_setter returns html and javascript for a compact date-setting form. -To retrieve values from it, use &get_date_from_form(). +To retrieve values from it, use &get_date_from_form. Inputs @@ -419,7 +490,36 @@ the date/time fields are left empty. =item $state Specifies the initial state of the form elements. Either 'disabled' or empty. -Defaults to empty, which indiciates the form elements are not disabled. +Defaults to empty, which indicates the form elements are not disabled. + +=item $no_hh_mm_ss + +If true, text boxes for hours, minutes and seconds are omitted. + +=item $defhour + +Default value for hours (a default of 0 is used otherwise). + +=item $defmin + +Default value for minutes (a default of 0 is used otherwise). + +=item defsec + +Default value for seconds (a default of 0 is used otherwise). + +=item $nolink + +If true, a "Select calendar" link (to pop-up a calendar) is not displayed +to the right of the items. + +=item $no_mm_ss + +If true, text boxes for minutes and seconds are omitted. + +=item $no_ss + +If true, text boxes for seconds are omitted. =back @@ -433,7 +533,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) = @_; + $no_hh_mm_ss,$defhour,$defmin,$defsec,$nolink,$no_mm_ss,$no_ss) = @_; my $now = time; my $tzname; @@ -442,6 +542,8 @@ sub date_setter { if (! defined($state) || $state ne 'disabled') { $state = ''; + } else { + $state = 'disabled="disabled"'; } if (! defined($no_hh_mm_ss)) { $no_hh_mm_ss = 0; @@ -577,7 +679,7 @@ ENDJS my $minuteselector = qq{}; my $secondselector= qq{}; my $cal_link; - if (!$nolink) { + unless (($nolink) || ($state eq 'disabled')) { $cal_link = qq{}; } # @@ -586,17 +688,24 @@ ENDJS $result .= &mt('[_1] [_2] [_3] ', $monthselector,$dayselector,$yearselector). $tzone; - if (!$nolink) { - $result .= &mt('[_1]Select Date[_2]',$cal_link,''); - } + } 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; - if (!$nolink) { - $result .= &mt('[_1]Select Date[_2]',$cal_link,''); - } + } + unless (($nolink) || ($state eq 'disabled')) { + $result .= &mt('[_1]Select Date[_2]',$cal_link,''); } $result .= "\n\n"; return $result; @@ -636,7 +745,7 @@ sub build_url { =pod -=item &get_date_from_form +=item &get_date_from_form() get_date_from_form retrieves the date specified in an &date_setter form. @@ -747,14 +856,14 @@ parameter setting wizard. ############################################## sub pjump_javascript_definition { my $Str = < 1, - 'bgcolor' => '#88DDFF', - 'js_ready' => 1}); - my $end_page = &Apache::loncommon::end_page({'js_ready' => 1}); - - #the whole function called through timeout is due to issues - #in mozilla Read BUG #2665 if you want to know the whole story - &r_print($r,&Apache::lonhtmlcommon::scripttag( - "var popwin; - function openpopwin () { - popwin=open(\'\',\'popwin\',\'width=400,height=100\');". - "popwin.document.writeln(\'".$start_page. - "

".&mt("$heading")."<\/h4>". - "
". - '<\\/form>'.$end_page. - "\');". - "popwin.document.close();}". - "\nwindow.setTimeout(openpopwin,0)" - )); - $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; - + &Apache::loncommon::LCprogressbar($r,$prog_state{'max'},$preamble); return %prog_state; } # update progress sub Update_PrgWin { my ($r,$prog_state,$displayString)=@_; - &r_print($r,&Apache::lonhtmlcommon::scripttag( - $$prog_state{'window'}.'.document.'. - $$prog_state{'formname'}.'.'. - $$prog_state{'inputname'}.'.value="'. - $displayString.'";' - )); + &Apache::loncommon::LCprogressbarUpdate($r,undef,$displayString,$$prog_state{'max'}); $$prog_state{'laststart'}=&Time::HiRes::time(); } @@ -1113,42 +1153,28 @@ sub Increment_PrgWin { $min, $sec, $lasttime); - - &r_print($r,&Apache::lonhtmlcommon::scripttag( - $$prog_state{'window'}.'.document.'. - $$prog_state{'formname'}.'.'. - $$prog_state{'inputname'}.'.value="'.$timeinfo.'";' - )); + my $percent=0; + if ($$prog_state{'max'}) { + $percent=int(100.*$current/$$prog_state{'max'}); + } + &Apache::loncommon::LCprogressbarUpdate($r,$percent,$timeinfo,$$prog_state{'max'}); $$prog_state{'laststart'}=&Time::HiRes::time(); } # close Progress Line sub Close_PrgWin { my ($r,$prog_state)=@_; - if ($$prog_state{'type'} eq 'popup') { - &r_print($r,&Apache::lonhtmlcommon::scripttag( - 'popwin.close()' - )); - } elsif ($$prog_state{'type'} eq 'inline') { - &Update_PrgWin($r,$prog_state,&mt('Done')); - } + &Apache::loncommon::LCprogressbarClose($r); undef(%$prog_state); } -sub r_print { - my ($r,$to_print)=@_; - if ($r) { - $r->print($to_print); - $r->rflush(); - } else { - print($to_print); - } -} # ------------------------------------------------------- Puts directory header sub crumbs { - my ($uri,$target,$prefix,$form,$skiplast)=@_; + my ($uri,$target,$prefix,$form,$skiplast,$onclick)=@_; +# You cannot crumbnify uploaded or adm resources + if ($uri=~/^\/*(uploaded|adm)\//) { return &mt('(Internal Course/Community Content)'); } if ($target) { $target = ' target="'. &Apache::loncommon::escape_single($target).'"'; @@ -1168,13 +1194,19 @@ sub crumbs { } else { $path.='/'; } + if ($path eq '/res/') { + unless (&Apache::lonnet::allowed('bre',$path)) { + $output.="$dir/"; + next; + } + } my $href_path = &HTML::Entities::encode($path,'<>&"'); &Apache::loncommon::inhibit_menu_check(\$href_path); if ($form) { my $href = 'javascript:'.$form.".action='".$href_path."';".$form.'.submit();'; - $output.=qq{$dir/}; + $output.=qq{$dir/}; } else { - $output.=qq{$dir/}; + $output.=qq{$dir/}; } } } else { @@ -1186,6 +1218,7 @@ sub crumbs { if ($uri !~ m|/$|) { $output=~s|/$||; } $output.=''; + return $output; } @@ -1244,9 +1277,19 @@ sub htmlareaheaders { ENDEDITOR } $s.=(< - - + + + + + + + + + + + + ENDJQUERY return $s; } @@ -1262,13 +1305,25 @@ sub htmlarea_lang { return $lang; } +# return javacsript to activate elements of .colorchooser with jpicker: +# Caller is responsible for enclosing this in '; return $output; @@ -1432,7 +1686,8 @@ sub show_return_link { unless ($env{'request.course.id'}) { return 0; } if ($env{'request.noversionuri'}=~m{^/priv/} || - $env{'request.uri'}=~m{^/~}) { return 1; } + $env{'request.uri'}=~m{^/priv/}) { return 1; } + return if ($env{'request.noversionuri'} eq '/adm/supplemental'); if (($env{'request.noversionuri'} =~ m{^/adm/(viewclasslist|navmaps)($|\?)}) || ($env{'request.noversionuri'} =~ m{^/adm/.*/aboutme($|\?)})) { @@ -1447,17 +1702,72 @@ sub show_return_link { (($env{'request.noversionuri'}=~/^\/adm\//) && ($env{'request.noversionuri'}!~/^\/adm\/wrapper\//) && ($env{'request.noversionuri'}!~ - m{^/adm/.*/(smppg|bulletinboard)($|\?)}) + m{^/adm/.*/(smppg|bulletinboard|ext\.tool)($|\?)}) )); } +## +# Set the dueDate variable...note this is done in the timezone +# of the browser. +# +# @param epoch relative time at which the problem is due. +# +# @return the javascript fragment to set the date: +# +sub set_due_date { + my $dueStamp = shift; + my $duems = $dueStamp * 1000; # Javascript Date object needs ms not seconds. + + my $now = time()*1000; + + # This slightly obscure bit of javascript sets the dueDate variable + # to the time in the browser at which the problem was due. + # The code should correct for gross differences between the server + # and client's time setting + + return <<"END"; + + + +END +} +## +# Sets the time at which the problem finished computing. +# This just updates the serverTime and clientTime variables above. +# Calling this in e.g. end_problem provides a better estimate of the +# difference beetween the server and client time setting as +# the difference contains less of the latency/problem compute time. +# +sub set_compute_end_time { + + my $now = time()*1000; # Javascript times are in ms. + return <<"END"; + + + +END +} + ############################################################ ############################################################ =pod -=item breadcrumbs +=item &breadcrumbs() Compiles the previously registered breadcrumbs into an series of links. Additionally supports a 'component', which will be displayed on the @@ -1467,19 +1777,27 @@ A link to help for the component will be All inputs can be undef without problems. Inputs: $component (the text on the right side of the breadcrumbs trail), - $component_help + $component_help (the help item filename (without .tex extension). $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. + $CourseBreadcrumbs (optional flag, 1 if &breadcrumbs called from &docs_breadcrumbs, + because breadcrumbs are being) + $topic_help (optional help item to be displayed on right side of the breadcrumbs + row, using loncommon::help_open_topic() to generate the link. + $topic_help_text (text to include in the link in the optional help item + on the right side of the breadcrumbs row. + $links_target optionally includes the target (_top, _parent or _self) + 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. @@ -1499,7 +1817,8 @@ returns: nothing my %tools = (); sub breadcrumbs { - my ($component,$component_help,$menulink,$helplink,$css_class,$no_mt, $CourseBreadcrumbs) = @_; + my ($component,$component_help,$menulink,$helplink,$css_class,$no_mt, + $CourseBreadcrumbs,$topic_help,$topic_help_text,$links_target) = @_; # $css_class ||= 'LC_breadcrumbs'; @@ -1515,6 +1834,16 @@ returns: nothing # The first one should be the course or a menu link if (!defined($menulink)) { $menulink=1; } if ($menulink) { + if ($env{'request.course.id'}) { + my ($menucoll,$deeplinkmenu,$menuref) = &Apache::loncommon::menucoll_in_effect(); + if (($menucoll) && (ref($menuref) eq 'HASH')) { + if ($menuref->{'main'} eq 'n') { + undef($menulink); + } + } + } + } + if ($menulink) { my $description = 'Menu'; my $no_mt_descr = 0; if ((exists($env{'request.course.id'})) && @@ -1523,10 +1852,24 @@ returns: nothing $description = $env{'course.'.$env{'request.course.id'}.'.description'}; $no_mt_descr = 1; + if ($env{'request.noversionuri'} =~ + m{^/?public/($match_domain)/($match_courseid)/syllabus$}) { + unless (($env{'course.'.$env{'request.course.id'}.'.domain'} eq $1) && + ($env{'course.'.$env{'request.course.id'}.'.num'} eq $2)) { + $description = 'Menu'; + $no_mt_descr = 0; + } + } + } + my $target = '_top'; + if ($links_target) { + $target = $links_target; + } elsif (($env{'request.deeplink.login'}) && ($env{'request.deeplink.target'} eq '_self')) { + $target = ''; } $menulink = { href =>'/adm/menu', title =>'Go to main menu', - target =>'_top', + target =>$target, text =>$description, no_mt =>$no_mt_descr, }; if($last) { @@ -1538,10 +1881,18 @@ returns: nothing } } my $links; - if ((&show_return_link) && (!$CourseBreadcrumbs)) { - $links=&htmltag( 'a',"", - { href => '/adm/flip?postdata=return:', - title => &mt("Back to most recent content resource") }); + if ((&show_return_link) && (!$CourseBreadcrumbs) && (ref($last) eq 'HASH')) { + my $alttext = &mt('Go Back'); + my $hashref = { href => '/adm/flip?postdata=return:', + title => &mt('Back to most recent content resource'), + class => 'LC_menubuttons_link', + }; + if ($links_target) { + $hashref->{'target'} = $links_target; + } + $links=&htmltag( 'a',''.$alttext.'', + $hashref); + $links=&htmltag('li',$links); } $links.= join "", map { @@ -1568,8 +1919,11 @@ returns: nothing # last breadcrumb is the first order heading of a page # for course breadcrumbs it's just bold - $links .= &htmltag( 'li', htmltag($CourseBreadcrumbs ? 'b' : 'h1', - $lasttext), {title => $lasttext}); + + if ($lasttext ne '') { + $links .= &htmltag( 'li', htmltag($CourseBreadcrumbs ? 'b' : 'h1', + $lasttext), {title => $lasttext}); + } my $icons = ''; $faq = $last->{'faq'} if (exists($last->{'faq'})); @@ -1585,34 +1939,61 @@ returns: nothing if ($faq ne '' || $component_help ne '' || $bug ne '') { $icons .= &Apache::loncommon::help_open_menu($component, $component_help, - $faq,$bug); + $faq,$bug,'','','','', + $links_target); + } + if ($topic_help && $topic_help_text) { + $icons .= ' '.&Apache::loncommon::help_open_topic($topic_help,&mt($topic_help_text),'', + undef,600,'',$links_target); } # - - unless ($CourseBreadcrumbs) { - $links = &htmltag('ol', $links, { id => "LC_MenuBreadcrumbs" }); - } else { - $links = &htmltag('ul', $links, { class => "LC_CourseBreadcrumbs" }); + + if ($links ne '') { + unless ($CourseBreadcrumbs) { + $links = &htmltag('ol', $links, { id => "LC_MenuBreadcrumbs" }); + } else { + $links = &htmltag('ul', $links, { class => "LC_CourseBreadcrumbs" }); + } } - if ($component) { + + if (($component) || ($topic_help && $topic_help_text)) { $links = &htmltag('span', ( $no_mt ? $component : mt($component) ). ( $icons ? $icons : '' ), { class => 'LC_breadcrumbs_component' } ) - .$links; + .$links +; + } + my $nav_and_tools = 0; + foreach my $item ('navigation','tools') { + if (ref($tools{$item}) eq 'ARRAY') { + $nav_and_tools += scalar(@{$tools{$item}}) + } + } + if (($links ne '') || ($nav_and_tools)) { + &render_tools(\$links); + $links = &htmltag('div', $links, + { id => "LC_breadcrumbs" }) unless ($CourseBreadcrumbs) ; + } + my $adv_tools = 0; + if (ref($tools{'advtools'}) eq 'ARRAY') { + $adv_tools = scalar(@{$tools{'advtools'}}); + } + if (($links ne '') || ($adv_tools)) { + &render_advtools(\$links); } - - &render_tools(\$links); - $links = &htmltag('div', $links, - { id => "LC_breadcrumbs" }) unless ($CourseBreadcrumbs) ; - &render_advtools(\$links); # Return the @Crumbs stack to what we started with push(@Crumbs,$last); shift(@Crumbs); + + # Return the breadcrumb's line + + + return "$links"; } @@ -1625,7 +2006,7 @@ returns: nothing push(@Crumbs,@_); } -=item add_breadcrumb_tool($category, $html) +=item &add_breadcrumb_tool($category, $html) Adds $html to $category of the breadcrumb toolbar container. @@ -1640,7 +2021,7 @@ Currently there are 3 possible values fo left of breadcrumbs line =item tools -right of breadcrumbs line +remaining items in right of breadcrumbs line =item advtools advanced tools shown in a separate box below breadcrumbs line @@ -1668,7 +2049,7 @@ returns: nothing push @{$tools{$category}}, @html; } -=item clear_breadcrumb_tools() +=item &clear_breadcrumb_tools() Clears the breadcrumb toolbar container. @@ -1680,7 +2061,17 @@ returns: nothing undef(%tools); } -=item render_tools(\$breadcrumbs) +=item ¤t_breadcrumb_tools() + +returns: a hash containing the current breadcrumb tools. + +=cut + + sub current_breadcrumb_tools { + return %tools; + } + +=item &render_tools(\$breadcrumbs) Creates html for breadcrumb tools (categories navigation and tools) and inserts \$breadcrumbs at the correct position. @@ -1689,6 +2080,7 @@ input: \$breadcrumbs - a reference to th breadcrumbs. returns: nothing + =cut #TODO might split this in separate functions for each category @@ -1704,7 +2096,9 @@ returns: nothing { listattr => { class=>'LC_breadcrumb_tools_outerlist' } }); } -=item render_advtools(\$breadcrumbs) +=pod + +=item &render_advtools(\$breadcrumbs) Creates html for advanced tools (category advtools) and inserts \$breadcrumbs at the correct position. @@ -1713,6 +2107,7 @@ input: \$breadcrumbs - a reference to th breadcrumbs (after render_tools call). returns: nothing + =cut sub render_advtools { @@ -1726,6 +2121,95 @@ returns: nothing } # End of scope for @Crumbs +sub docs_breadcrumbs { + my ($allowed,$crstype,$contenteditor,$title,$precleared,$checklinkprot)=@_; + my ($folderpath,@folders,$supplementalflag); + @folders = split('&',$env{'form.folderpath'}); + if ($env{'form.folderpath'} =~ /^supplemental/) { + $supplementalflag = 1; + } + my $plain=''; + my $container = 'sequence'; + my ($randompick,$isencrypted,$ishidden,$is_random_order) = (-1,0,0,0); + my @docs_crumbs; + while (@folders) { + my $folder=shift(@folders); + my $foldername=shift(@folders); + if ($folderpath) {$folderpath.='&';} + $folderpath.=$folder.'&'.$foldername; + my $url = $env{'request.use_absolute'}; + if ($allowed) { + $url .= '/adm/coursedocs?folderpath='; + } else { + $url .= '/adm/supplemental?folderpath='; + } + $url .= &escape($folderpath); + my $name=&unescape($foldername); +# each of randompick number, hidden, encrypted, random order, is_page +# are appended with ":"s to the foldername + $name=~s/\:(\d*)\:(\w*)\:(\w*):(\d*)\:?(\d*)$//; + unless ($supplementalflag) { + if ($contenteditor) { + if ($1 ne '') { + $randompick=$1; + } else { + $randompick=-1; + } + if ($2) { $ishidden=1; } + if ($3) { $isencrypted=1; } + if ($4 ne '') { $is_random_order = 1; } + if ($5 == 1) {$container = 'page'; } + } + } + if ($folder eq 'supplemental') { + $name = &mt('Supplemental Content'); + } + if ($contenteditor) { + $plain.=$name.' > '; + } + push(@docs_crumbs, + {'href' => $url, + 'title' => $name, + 'text' => $name, + 'no_mt' => 1, + }); + } + if ($title) { + push(@docs_crumbs, + {'title' => $title, + 'text' => $title, + 'no_mt' => 1,} + ); + } + if (wantarray) { + unless ($precleared) { + &clear_breadcrumbs(); + } + &add_breadcrumb(@docs_crumbs); + if ($contenteditor) { + $plain=~s/\>\;\s*$//; + } + my $menulink = 0; + if (!$allowed && !$contenteditor) { + $menulink = 1; + } + if ($checklinkprot) { + if ($env{'request.deeplink.login'}) { + my $linkprotout = &Apache::lonmenu::linkprot_exit(); + if ($linkprotout) { + &Apache::lonhtmlcommon::add_breadcrumb_tool('tools',$linkprotout); + } + } + } + return (&breadcrumbs(undef,undef,$menulink,'nohelp',undef,undef, + $contenteditor), + $randompick,$ishidden,$isencrypted,$plain, + $is_random_order,$container); + } else { + return \@docs_crumbs; + } +} + ############################################################ ############################################################ @@ -1786,15 +2270,19 @@ returns: nothing my @row_count; sub start_pick_box { - my ($css_class) = @_; + my ($css_class,$id) = @_; if (defined($css_class)) { $css_class = 'class="'.$css_class.'"'; } else { $css_class= 'class="LC_pick_box"'; } + my $table_id; + if (defined($id)) { + $table_id = ' id="'.$id.'"'; + } unshift(@row_count,0); my $output = <<"END"; - +
END return $output; } @@ -1949,14 +2437,14 @@ sub course_selection { my $courseform=''.&Apache::loncommon::selectcourse_link ($formname,'pickcourse','pickdomain','coursedesc','',1,$crstype).''; - $output .= ''.$allcrs.'
'; + $output .= '
'; if ($totcodes > 0) { my $numtitles = @$codetitles; if ($numtitles > 0) { - $output .= ''.&mt('Pick courses by category:').'
'; + $output .= '
'; $output .= '
'; @@ -1994,7 +2482,15 @@ sub course_selection { $output .= '
'.$$codetitles[0].'
'."\n". '
'.$$codetitles[$i].'
'."\n". ''."\n". '

'; } } - $output .= ''.$pickspec.' '.$courseform.'  selected.
'."\n"; + $output .= + '' + .' '.$courseform.'  ' + .&mt('[_1] selected.', + '' + .'') + .'
'."\n"; return $output; } @@ -2078,26 +2574,88 @@ sub course_custom_roles { sub resource_info_box { - my ($symb,$onlyfolderflag)=@_; + my ($symb,$onlyfolderflag,$stuvcurrent,$stuvdisp,$divforres)=@_; my $return=''; + if (($stuvcurrent ne '') || ($divforres)) { + $return = '
'; + } if ($symb) { - $return=&Apache::loncommon::start_data_table(); + $return.=&Apache::loncommon::start_data_table(); my ($map,$id,$resource)=&Apache::lonnet::decode_symb($symb); my $folder=&Apache::lonnet::gettitle($map); $return.=&Apache::loncommon::start_data_table_row(). - ''.&mt('Folder:').''.$folder.''. + ''.&mt('Folder:').''.$folder.''. &Apache::loncommon::end_data_table_row(); unless ($onlyfolderflag) { $return.=&Apache::loncommon::start_data_table_row(). - ''.&mt('Resource:').''.&Apache::lonnet::gettitle($symb).''. + ''.&mt('Resource:').''.&Apache::lonnet::gettitle($symb).''. + &Apache::loncommon::end_data_table_row(); + } + if ($stuvcurrent ne '') { + $return .= &Apache::loncommon::start_data_table_row(). + ''.&mt("Student's current version:").''.$stuvcurrent.''. + &Apache::loncommon::end_data_table_row(); + } + if ($stuvdisp ne '') { + $return .= &Apache::loncommon::start_data_table_row(). + ''.&mt("Student's version displayed:").''.$stuvdisp.''. &Apache::loncommon::end_data_table_row(); } $return.=&Apache::loncommon::end_data_table(); } else { $return='

'.&mt('No context provided.').'

'; } + if (($stuvcurrent ne '') || ($divforres)) { + $return .= '
'; + } return $return; +} +# display_usage +# +# Generates a div containing a block, filled to show percentage of current quota used +# +# Quotas available for user portfolios, group portfolios, authoring spaces, and course +# content stored directly within a course (i.e., excluding published content). +# + +sub display_usage { + my ($current_disk_usage,$disk_quota,$context) = @_; + my $usage = $current_disk_usage/1024; + my $quota = $disk_quota/1024; + my $percent; + if ($disk_quota == 0) { + $percent = 100.0; + } else { + $percent = 100*($current_disk_usage/$disk_quota); + } + $usage = sprintf("%.2f",$usage); + $quota = sprintf("%.2f",$quota); + $percent = sprintf("%.0f",$percent); + my ($color,$cssclass); + if ($percent <= 60) { + $color = '#00A000'; + } elsif ($percent > 60 && $percent < 90) { + $color = '#FFD300'; + $cssclass = 'class="LC_warning"'; + } elsif( $percent >= 90) { + $color = '#FF0000'; + $cssclass = 'class="LC_error"'; + } + my $prog_width = $percent; + if ($prog_width > 100) { + $prog_width = 100; + } + my $display = 'block'; + if ($context eq 'authoring') { + $display = 'inline'; + } + return ' +
'.&mt('Currently using [_1] of the [_2] available.',$usage.' MB ('.$percent.'%)',$quota.' MB')."\n". +'
'."\n". +'
'."\n". +'
'."\n". +'
'; } ############################################## @@ -2111,15 +2669,19 @@ sub resource_info_box { # 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 ($num,$title) = @_; + my ($num,$title,$id) = @_; my $number = ''; if ($num ne '') { $number = ''.$num.''; } - return '
'.$number.$title.'
'; + if ($id ne '') { + $id = 'id="'.$id.'"'; + } + return '
'.$number.$title.'
'; } ############################################## @@ -2338,18 +2900,687 @@ 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)?'); + &js_escape(\$overwritewarn); + 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?'); + &js_escape(\$delfilewarn); + 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,$tid) = @_; + my (%names,$paddingwfrac,$offsetwfrac,$offsetv,$minw,$minv); + if ($context eq 'docs') { + %names = ( + boxw => 'contenteditor', + item => 'contentlist', + header => 'uploadfileresult', + scroll => 'contentscroll', + boxh => 'contenteditor', + ); + $paddingwfrac = 0.09; + $offsetwfrac = 0.015; + $offsetv = 20; + $minw = 250; + $minv = 200; + } elsif ($context eq 'params') { + %names = ( + boxw => 'parameditor', + item => 'mapmenuinner', + header => 'parmstep1', + scroll => 'mapmenuscroll', + boxh => 'parmlevel', + ); + $paddingwfrac = 0.2; + $offsetwfrac = 0.015; + $offsetv = 80; + $minw = 100; + $minv = 100; + } + my $viewport_js = &Apache::loncommon::viewport_geometry_js(); + my $output = ' + +window.onresize=callResize; + +'; + if ($context eq 'docs') { + if ($env{'form.active'}) { + $output .= "\nvar activeTab = '$env{'form.active'}$tid';\n"; + } else { + $output .= "\nvar activeTab = '';\n"; + } + } + $output .= <<"FIRST"; + +$viewport_js + +function resize_scrollbox(scrollboxname,chkw,chkh) { + var scrollboxid = 'div_'+scrollboxname; + var scrolltableid = 'table_'+scrollboxname; + var scrollbox; + var scrolltable; + var ismobile = '$env{'browser.mobile'}'; + + if (document.getElementById("$names{'boxw'}") == null) { + return; + } + + if (document.getElementById(scrollboxid) == null) { + return; + } else { + scrollbox = document.getElementById(scrollboxid); + } + + + if (document.getElementById(scrolltableid) == null) { + return; + } else { + scrolltable = document.getElementById(scrolltableid); + } + + init_geometry(); + var vph = Geometry.getViewportHeight(); + var vpw = Geometry.getViewportWidth(); + +FIRST + if ($context eq 'docs') { + $output .= " + var alltabs = ['$tabidstr']; +"; + } elsif ($context eq 'params') { + $output .= " + if (document.getElementById('$names{'boxh'}') == null) { + return; + } +"; + } + $output .= <<"SECOND"; + var listwchange; + var scrollchange; + if (chkw == 1) { + var boxw = document.getElementById("$names{'boxw'}").offsetWidth; + var itemw; + var itemid = document.getElementById("$names{'item'}"); + if (itemid != null) { + itemw = itemid.offsetWidth; + } + var itemwstart = itemw; + + var scrollboxw = scrollbox.offsetWidth; + var scrollboxscrollw = scrollbox.scrollWidth; + var scrollstart = scrollboxw; + + var offsetw = parseInt(vpw * $offsetwfrac); + var paddingw = parseInt(vpw * $paddingwfrac); + + var minscrollboxw = $minw; + var maxcolw = 0; +SECOND + if ($context eq 'docs') { + $output .= <<"DOCSONE"; + var actabw = 0; + for (var i=0; i maxcolw) { + maxcolw = actabw; + } + } else { + if (document.getElementById(alltabs[i]) != null) { + var thistab = document.getElementById(alltabs[i]); + thistab.style.visibility = 'hidden'; + thistab.style.display = 'block'; + var tabw = document.getElementById(alltabs[i]).offsetWidth; + thistab.style.display = 'none'; + thistab.style.visibility = ''; + if (tabw > maxcolw) { + maxcolw = tabw; + } + } + } + } +DOCSONE + } elsif ($context eq 'params') { + $output .= <<"PARAMSONE"; + var parmlevelrows = new Array(); + var mapmenucells = new Array(); + parmlevelrows = document.getElementById("$names{'boxh'}").rows; + var numrows = parmlevelrows.length; + if (numrows > 1) { + mapmenucells = parmlevelrows[2].getElementsByTagName('td'); + } + maxcolw = mapmenucells[0].offsetWidth; +PARAMSONE + } + $output .= <<"THIRD"; + if (maxcolw > 0) { + var newscrollboxw; + if (maxcolw+paddingw+scrollboxscrollw scrollboxheight) { + if (freevspace > offsetv) { + newscrollboxheight = scrollboxheight+freevspace-offsetv; + if (newscrollboxheight < minvscrollbox) { + newscrollboxheight = minvscrollbox; + } + scrollbox.style.height = newscrollboxheight+"px"; + } + } + } + scrollboxheight = scrollbox.offsetHeight; + var itemh = document.getElementById("$names{'item'}").offsetHeight; + + if (scrollboxscrollheight <= scrollboxheight) { + if ((itemh+offsetv)&'); + if ($symb) { + $cfile .= '&symb='.&HTML::Entities::encode($symb,'"<>&'); + } elsif ($folderpath) { + $cfile .= '&folderpath='.&HTML::Entities::encode($folderpath,'"<>&'); + } + if ($forceedit) { + $cfile .= '&forceedit=1'; + } + if ($forcereg) { + $cfile .= '&register=1'; + } + $jscall = "need_switchserver('".&Apache::loncommon::escape_single($cfile)."');"; + } + } else { + unless ($cfile =~ m{^/priv/}) { + if ($cfile =~ m{^(/adm/wrapper/ext/([^#]+))(?:|#([^#]+))$}) { + $cfile = $1; + my $extlink = $2; + $anchor = $3; + $is_ext = 1; + if (($extlink !~ /^https:/) && ($ENV{'SERVER_PORT'} == 443)) { + unless ((&Apache::lonnet::uses_sts()) || (&Apache::lonnet::waf_allssl($hostname))) { + $usehttp = 1; + } + } elsif ($env{'request.use_absolute'}) { + if ($env{'request.use_absolute'} =~ m{^https://}) { + $usehttps = 1; + } + } + } elsif ($cfile =~ m{^/?public/($match_domain)/($match_courseid)/syllabus}) { + if ($ENV{'SERVER_PORT'} == 443) { + my ($cdom,$cnum) = ($1,$2); + if (($env{'request.course.id'}) && + ($env{'course.'.$env{'request.course.id'}.'.num'} eq $cnum) && + ($env{'course.'.$env{'request.course.id'}.'.domain'} eq $cdom)) { + if ($env{'course.'.$env{'request.course.id'}.'.externalsyllabus'} =~ m{^http://}) { + unless ((&Apache::lonnet::uses_sts()) || (&Apache::lonnet::waf_allssl($hostname))) { + $usehttp = 1; + } + } + } + } elsif ($env{'request.use_absolute'}) { + if ($env{'request.use_absolute'} =~ m{^https://}) { + $usehttps = 1; + } + } + } + if ($symb) { + if ($anchor ne '') { + if ($symb =~ m{^([^#]+)\Q#$anchor\E$}) { + $symb = $1.&escape(&escape('#')).$anchor; + } + } + $cfile .= (($cfile=~/\?/)?'&':'?')."symb=$symb"; + } elsif ($folderpath) { + $cfile .= (($cfile=~/\?/)?'&':'?'). + 'folderpath='.&HTML::Entities::encode(&escape($folderpath),'"<>&'); + if ($title) { + $cfile .= (($cfile=~/\?/)?'&':'?'). + 'title='.&HTML::Entities::encode(&escape($title),'"<>&'); + } + if ($idx) { + $cfile .= (($cfile=~/\?/)?'&':'?').'idx='.$idx; + } + if ($suppurl) { + $cfile .= (($cfile=~/\?/)?'&':'?'). + 'suppurl='.&HTML::Entities::encode(&escape($suppurl)); + } + } + if ($forceedit) { + $cfile .= (($cfile=~/\?/)?'&':'?').'forceedit=1'; + if ($usehttps) { + $cfile = $env{'request.use_absolute'}.(($cfile =~ /^\//)? '':'/').$cfile; + } + } elsif ($usehttp) { + if ($hostname ne '') { + $cfile = 'http://'.$hostname.(($cfile =~ /^\//)? '':'/').$cfile; + } + $cfile .= (($cfile=~/\?/)?'&':'?').'usehttp=1'; + } elsif ($usehttps) { + $cfile = $env{'request.use_absolute'}.(($cfile =~ /^\//)? '':'/').$cfile; + } + if ($forcereg) { + $cfile .= (($cfile=~/\?/)?'&':'?').'register=1'; + } + if ($todocs) { + $cfile .= (($cfile=~/\?/)?'&':'?').'todocs=1'; + } + if ($suppanchor ne '') { + $cfile .= (($cfile=~/\?/)?'&':'?').'anchor='. + &HTML::Entities::encode($suppanchor,'"<>&'); + } + } + if ($anchor ne '') { + $cfile .= '#'.$anchor; + } + $jscall = "go('".&Apache::loncommon::escape_single($cfile)."')"; + } + return $jscall; +} + +############################################## +############################################## + # javascript_valid_email # # Generates javascript to validate an e-mail address. -# Returns a javascript function which accetps a form field as argumnent, and +# Returns a javascript function which accepts a form field as argument, and # returns false if field.value does not satisfy two regular expression matches # for a valid e-mail address. Backwards compatible with old browsers without # support for javascript RegExp (just checks for @ in field.value in this case). sub javascript_valid_email { my $scripttag .= <<'END'; -function validmail(field) { +function validmail(field,suffix) { var str = field.value; + if (suffix != '' && suffix != undefined) { + str += suffix; + } if (window.RegExp) { var reg1str = "(@.*@)|(\\.\\.)|(@\\.)|(\\.@)|(^\\.)"; var reg2str = "^.+\\@(\\[?)[a-zA-Z0-9\\-\\.]+\\.([a-zA-Z]{2,3}|[0-9]{1,3})(\\]?)$"; //" @@ -2397,7 +3628,7 @@ END sub htmltag{ return qq|<$_[0]| - . join( '', map { qq| $_="${$_[2]}{$_}"| if ${$_[2]}{$_} } keys %{ $_[2] } ) + . join( '', map { qq| $_="${$_[2]}{$_}"| if ${$_[2]}{$_} } keys(%{ $_[2] }) ) . ($_[1] ? qq|>$_[1]| : qq|/>|). "\n"; }; @@ -2453,8 +3684,9 @@ sub scripttag { return htmltag('script', $content, {type => 'text/javascript'}); }; +=pod -=item list_from_array( \@array, { listattr =>{}, itemattr =>{} } ) +=item &list_from_array( \@array, { listattr =>{}, itemattr =>{} } ) Constructs a XHTML list from \@array. @@ -2545,7 +3777,8 @@ sub generate_menu { $$link{alttext} : $$link{linktext}) }), { href => $$link{url}, - title => mt($$link{linktitle}) + title => mt($$link{linktitle}), + class => 'LC_menubuttons_link' }). $a->(mt($$link{linktext}), { href => $$link{url}, @@ -2579,7 +3812,7 @@ sub generate_menu { =pod -=item &start_funclist +=item &start_funclist() Start list of available functions @@ -2619,7 +3852,7 @@ sub start_funclist { =pod -=item &add_item_funclist +=item &add_item_funclist() Adds an item to the list of available functions @@ -2645,7 +3878,7 @@ sub add_item_funclist { =pod -=item &end_funclist +=item &end_funclist() End list of available functions @@ -2658,6 +3891,7 @@ add_item_funclist Inputs: ./. Returns: HTML code with function list end + =cut sub end_funclist { @@ -2666,7 +3900,7 @@ sub end_funclist { =pod -=item funclist_from_array( \@array, {legend => 'text for legend'} ) +=item &funclist_from_array( \@array, {legend => 'text for legend'} ) Constructs a XHTML list from \@array with the first item being visually highlighted and set to the value of legend or 'Functions' if legend is @@ -2699,6 +3933,42 @@ sub funclist_from_array { { listattr => {class => 'LC_funclist'} }); } +=pod + +=over + +=item &actionbox( \@array ) + +Constructs a XHTML list from \@array with the first item being visually +highlighted and set to the value 'Actions'. The list is wrapped in a division. + +The actionlist is used to offer contextual actions, mostly at the bottom +of a page, on which the outcome of an processed action is shown, +e.g. a file operation in Authoring Space. + +=over + +=item \@array + +A reference to the array containing text. Details: sub funclist_from_array + +=back + +Returns: XHTML div as string. + +=back + +=cut + +sub actionbox { + my ($items) = @_; + return unless(ref($items) eq 'ARRAY'); + return + '
' + .&funclist_from_array($items, {legend => &mt('Actions')}) + .'
'; +} + 1; __END__ 500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.