![]() ![]() | ![]() |
- javascript style: - return from function.
1: # The LearningOnline Network with CAPA 2: # a pile of common html routines 3: # 4: # $Id: lonhtmlcommon.pm,v 1.235 2009/09/08 20:48:34 raeburn Exp $ 5: # 6: # Copyright Michigan State University Board of Trustees 7: # 8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA). 9: # 10: # LON-CAPA is free software; you can redistribute it and/or modify 11: # it under the terms of the GNU General Public License as published by 12: # the Free Software Foundation; either version 2 of the License, or 13: # (at your option) any later version. 14: # 15: # LON-CAPA is distributed in the hope that it will be useful, 16: # but WITHOUT ANY WARRANTY; without even the implied warranty of 17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18: # GNU General Public License for more details. 19: # 20: # You should have received a copy of the GNU General Public License 21: # along with LON-CAPA; if not, write to the Free Software 22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23: # 24: # /home/httpd/html/adm/gpl.txt 25: # 26: # http://www.lon-capa.org/ 27: # 28: ###################################################################### 29: ###################################################################### 30: 31: =pod 32: 33: =head1 NAME 34: 35: Apache::lonhtmlcommon - routines to do common html things 36: 37: =head1 SYNOPSIS 38: 39: Referenced by other mod_perl Apache modules. 40: 41: =head1 INTRODUCTION 42: 43: lonhtmlcommon is a collection of subroutines used to present information 44: in a consistent html format, or provide other functionality related to 45: html. 46: 47: =head2 General Subroutines 48: 49: =over 4 50: 51: =cut 52: 53: ###################################################################### 54: ###################################################################### 55: 56: package Apache::lonhtmlcommon; 57: 58: use strict; 59: use Time::Local; 60: use Time::HiRes; 61: use Apache::lonlocal; 62: use Apache::lonnet; 63: use LONCAPA; 64: 65: ############################################## 66: ############################################## 67: 68: =pod 69: 70: =item confirm_success 71: 72: Successful completion of an operation message 73: 74: =cut 75: 76: sub confirm_success { 77: my ($message,$failure)=@_; 78: if ($failure) { 79: return '<span class="LC_error">'."\n" 80: .'<img src="/adm/lonIcons/navmap.wrong.gif" alt="'.&mt('Error').'" /> '."\n" 81: .$message."\n" 82: .'</span>'."\n"; 83: } else { 84: return '<span class="LC_success">'."\n" 85: .'<img src="/adm/lonIcons/navmap.correct.gif" alt="'.&mt('OK').'" /> '."\n" 86: .$message."\n" 87: .'</span>'."\n"; 88: } 89: } 90: 91: ############################################## 92: ############################################## 93: 94: =pod 95: 96: =item dragmath_button 97: 98: Creates a button that launches a dragmath popup-window, in which an 99: expression can be edited and pasted as LaTeX into a specified textarea. 100: 101: textarea - Name of the textarea to edit. 102: helpicon - If true, show a help icon to the right of the button. 103: 104: =cut 105: 106: sub dragmath_button { 107: my ($textarea,$helpicon) = @_; 108: my $help_text; 109: if ($helpicon) { 110: $help_text = &Apache::loncommon::help_open_topic('Authoring_Math_Editor'); 111: } 112: my $buttontext=&mt('Edit Math'); 113: return <<ENDDRAGMATH; 114: <input type="button" value="$buttontext", onclick="javascript:mathedit('$textarea',document)" />$help_text 115: ENDDRAGMATH 116: } 117: 118: ############################################## 119: 120: =pod 121: 122: =item dragmath_js 123: 124: Javascript used to open pop-up window containing dragmath applet which 125: can be used to paste LaTeX into a textarea. 126: 127: =cut 128: 129: sub dragmath_js { 130: my ($popup) = @_; 131: return <<ENDDRAGMATHJS; 132: <script type="text/javascript"> 133: // <![CDATA[ 134: function mathedit(textarea, doc) { 135: targetEntry = textarea; 136: targetDoc = doc; 137: newwin = window.open("/adm/dragmath/applet/$popup.html","","width=565,height=500,resizable"); 138: } 139: // ]]> 140: </script> 141: 142: ENDDRAGMATHJS 143: } 144: 145: 146: ############################################## 147: ############################################## 148: 149: =pod 150: 151: =item authorbombs 152: 153: =cut 154: 155: ############################################## 156: ############################################## 157: 158: sub authorbombs { 159: my $url=shift; 160: $url=&Apache::lonnet::declutter($url); 161: my ($udom,$uname)=($url=~m{^($LONCAPA::domain_re)/($LONCAPA::username_re)/}); 162: my %bombs=&Apache::lonmsg::all_url_author_res_msg($uname,$udom); 163: foreach my $bomb (keys(%bombs)) { 164: if ($bomb =~ /^$udom\/$uname\//) { 165: return '<a href="/adm/bombs/'.$url. 166: '"><img src="'.&Apache::loncommon::lonhttpdurl('/adm/lonMisc/bomb.gif').'" alt="'.&mt('Bomb').'" border="0" /></a>'. 167: &Apache::loncommon::help_open_topic('About_Bombs'); 168: } 169: } 170: return ''; 171: } 172: 173: ############################################## 174: ############################################## 175: 176: sub recent_filename { 177: my $area=shift; 178: return 'nohist_recent_'.&escape($area); 179: } 180: 181: sub store_recent { 182: my ($area,$name,$value,$freeze)=@_; 183: my $file=&recent_filename($area); 184: my %recent=&Apache::lonnet::dump($file); 185: if (scalar(keys(%recent))>20) { 186: # remove oldest value 187: my $oldest=time(); 188: my $delkey=''; 189: foreach my $item (keys(%recent)) { 190: my $thistime=(split(/\&/,$recent{$item}))[0]; 191: if (($thistime ne "always_include") && ($thistime<$oldest)) { 192: $oldest=$thistime; 193: $delkey=$item; 194: } 195: } 196: &Apache::lonnet::del($file,[$delkey]); 197: } 198: # store new value 199: my $timestamp; 200: if ($freeze) { 201: $timestamp = "always_include"; 202: } else { 203: $timestamp = time(); 204: } 205: &Apache::lonnet::put($file,{ $name => 206: $timestamp.'&'.&escape($value) }); 207: } 208: 209: sub remove_recent { 210: my ($area,$names)=@_; 211: my $file=&recent_filename($area); 212: return &Apache::lonnet::del($file,$names); 213: } 214: 215: sub select_recent { 216: my ($area,$fieldname,$event)=@_; 217: my %recent=&Apache::lonnet::dump(&recent_filename($area)); 218: my $return="\n<select name='$fieldname'". 219: ($event?" onchange='$event'":''). 220: ">\n<option value=''>--- ".&mt('Recent')." ---</option>"; 221: foreach my $value (sort(keys(%recent))) { 222: unless ($value =~/^error\:/) { 223: my $escaped = &Apache::loncommon::escape_url($value); 224: &Apache::loncommon::inhibit_menu_check(\$escaped); 225: $return.="\n<option value='$escaped'>". 226: &unescape((split(/\&/,$recent{$value}))[1]). 227: '</option>'; 228: } 229: } 230: $return.="\n</select>\n"; 231: return $return; 232: } 233: 234: sub get_recent { 235: my ($area, $n) = @_; 236: my %recent=&Apache::lonnet::dump(&recent_filename($area)); 237: 238: # Create hash with key as time and recent as value 239: # Begin filling return_hash with any 'always_include' option 240: my %time_hash = (); 241: my %return_hash = (); 242: foreach my $item (keys(%recent)) { 243: my ($thistime,$thisvalue)=(split(/\&/,$recent{$item})); 244: if ($thistime eq 'always_include') { 245: $return_hash{$item} = &unescape($thisvalue); 246: $n--; 247: } else { 248: $time_hash{$thistime} = $item; 249: } 250: } 251: 252: # Sort by decreasing time and return key value pairs 253: my $idx = 1; 254: foreach my $item (reverse(sort(keys(%time_hash)))) { 255: $return_hash{$time_hash{$item}} = 256: &unescape((split(/\&/,$recent{$time_hash{$item}}))[1]); 257: if ($n && ($idx++ >= $n)) {last;} 258: } 259: 260: return %return_hash; 261: } 262: 263: sub get_recent_frozen { 264: my ($area) = @_; 265: my %recent=&Apache::lonnet::dump(&recent_filename($area)); 266: 267: # Create hash with all 'frozen' items 268: my %return_hash = (); 269: foreach my $item (keys(%recent)) { 270: my ($thistime,$thisvalue)=(split(/\&/,$recent{$item})); 271: if ($thistime eq 'always_include') { 272: $return_hash{$item} = &unescape($thisvalue); 273: } 274: } 275: return %return_hash; 276: } 277: 278: 279: 280: =pod 281: 282: =item textbox 283: 284: =cut 285: 286: ############################################## 287: ############################################## 288: sub textbox { 289: my ($name,$value,$size,$special) = @_; 290: $size = 40 if (! defined($size)); 291: $value = &HTML::Entities::encode($value,'<>&"'); 292: my $Str = '<input type="text" name="'.$name.'" size="'.$size.'" '. 293: 'value="'.$value.'" '.$special.' />'; 294: return $Str; 295: } 296: 297: ############################################## 298: ############################################## 299: 300: =pod 301: 302: =item checkbox 303: 304: =cut 305: 306: ############################################## 307: ############################################## 308: sub checkbox { 309: my ($name,$checked,$value) = @_; 310: my $Str = '<input type="checkbox" name="'.$name.'" '; 311: if (defined($value)) { 312: $Str .= 'value="'.$value.'"'; 313: } 314: if ($checked) { 315: $Str .= ' checked="checked"'; 316: } 317: $Str .= ' />'; 318: return $Str; 319: } 320: 321: 322: =pod 323: 324: =item radiobutton 325: 326: =cut 327: 328: ############################################## 329: ############################################## 330: sub radio { 331: my ($name,$checked,$value) = @_; 332: my $Str = '<input type="radio" name="'.$name.'" '; 333: if (defined($value)) { 334: $Str .= 'value="'.$value.'"'; 335: } 336: if ($checked eq $value) { 337: $Str .= ' checked="checked"'; 338: } 339: $Str .= ' />'; 340: return $Str; 341: } 342: 343: ############################################## 344: ############################################## 345: 346: =pod 347: 348: =item &date_setter 349: 350: &date_setter returns html and javascript for a compact date-setting form. 351: To retrieve values from it, use &get_date_from_form(). 352: 353: Inputs 354: 355: =over 4 356: 357: =item $dname 358: 359: The name to prepend to the form elements. 360: The form elements defined will be dname_year, dname_month, dname_day, 361: dname_hour, dname_min, and dname_sec. 362: 363: =item $currentvalue 364: 365: The current setting for this time parameter. A unix format time 366: (time in seconds since the beginning of Jan 1st, 1970, GMT. 367: An undefined value is taken to indicate the value is the current time. 368: Also, to be explicit, a value of 'now' also indicates the current time. 369: 370: =item $special 371: 372: Additional html/javascript to be associated with each element in 373: the date_setter. See lonparmset for example usage. 374: 375: =item $includeempty 376: 377: =item $state 378: 379: Specifies the initial state of the form elements. Either 'disabled' or empty. 380: Defaults to empty, which indiciates the form elements are not disabled. 381: 382: =back 383: 384: Bugs 385: 386: The method used to restrict user input will fail in the year 2400. 387: 388: =cut 389: 390: ############################################## 391: ############################################## 392: sub date_setter { 393: my ($formname,$dname,$currentvalue,$special,$includeempty,$state, 394: $no_hh_mm_ss,$defhour,$defmin,$defsec,$nolink) = @_; 395: my $now = time; 396: my $wasdefined=1; 397: if (! defined($state) || $state ne 'disabled') { 398: $state = ''; 399: } 400: if (! defined($no_hh_mm_ss)) { 401: $no_hh_mm_ss = 0; 402: } 403: if ($currentvalue eq 'now') { 404: $currentvalue = $now; 405: } 406: if ((!defined($currentvalue)) || ($currentvalue eq '')) { 407: $wasdefined=0; 408: if ($includeempty) { 409: $currentvalue = 0; 410: } else { 411: $currentvalue = $now; 412: } 413: } 414: # other potentially useful values: wkday,yrday,is_daylight_savings 415: my $tzname; 416: my ($sec,$min,$hour,$mday,$month,$year)=('','',undef,'','',''); 417: if ($currentvalue) { 418: ($tzname,$sec,$min,$hour,$mday,$month,$year) = &get_timedates($currentvalue); 419: } 420: unless ($wasdefined) { 421: ($tzname,$sec,$min,$hour,$mday,$month,$year) = &get_timedates($now); 422: if (($defhour) || ($defmin) || ($defsec)) { 423: $sec=($defsec?$defsec:0); 424: $min=($defmin?$defmin:0); 425: $hour=($defhour?$defhour:0); 426: } elsif (!$includeempty) { 427: $sec=0; 428: $min=0; 429: $hour=0; 430: } 431: } 432: my $result = "\n<!-- $dname date setting form -->\n"; 433: $result .= <<ENDJS; 434: <script type="text/javascript"> 435: // <![CDATA[ 436: function $dname\_checkday() { 437: var day = document.$formname.$dname\_day.value; 438: var month = document.$formname.$dname\_month.value; 439: var year = document.$formname.$dname\_year.value; 440: var valid = true; 441: if (day < 1) { 442: document.$formname.$dname\_day.value = 1; 443: } 444: if (day > 31) { 445: document.$formname.$dname\_day.value = 31; 446: } 447: if ((month == 1) || (month == 3) || (month == 5) || 448: (month == 7) || (month == 8) || (month == 10) || 449: (month == 12)) { 450: if (day > 31) { 451: document.$formname.$dname\_day.value = 31; 452: day = 31; 453: } 454: } else if (month == 2 ) { 455: if ((year % 4 == 0) && (year % 100 != 0)) { 456: if (day > 29) { 457: document.$formname.$dname\_day.value = 29; 458: } 459: } else if (day > 29) { 460: document.$formname.$dname\_day.value = 28; 461: } 462: } else if (day > 30) { 463: document.$formname.$dname\_day.value = 30; 464: } 465: } 466: 467: function $dname\_disable() { 468: document.$formname.$dname\_month.disabled=true; 469: document.$formname.$dname\_day.disabled=true; 470: document.$formname.$dname\_year.disabled=true; 471: document.$formname.$dname\_hour.disabled=true; 472: document.$formname.$dname\_minute.disabled=true; 473: document.$formname.$dname\_second.disabled=true; 474: } 475: 476: function $dname\_enable() { 477: document.$formname.$dname\_month.disabled=false; 478: document.$formname.$dname\_day.disabled=false; 479: document.$formname.$dname\_year.disabled=false; 480: document.$formname.$dname\_hour.disabled=false; 481: document.$formname.$dname\_minute.disabled=false; 482: document.$formname.$dname\_second.disabled=false; 483: } 484: 485: function $dname\_opencalendar() { 486: if (! document.$formname.$dname\_month.disabled) { 487: var calwin=window.open( 488: "/adm/announcements?pickdate=yes&formname=$formname&element=$dname&month="+ 489: document.$formname.$dname\_month.value+"&year="+ 490: document.$formname.$dname\_year.value, 491: "LONCAPAcal", 492: "height=350,width=350,scrollbars=yes,resizable=yes,menubar=no"); 493: } 494: 495: } 496: // ]]> 497: </script> 498: ENDJS 499: $result .= ' <span class="LC_nobreak">'; 500: my $monthselector = qq{<select name="$dname\_month" $special $state onchange="javascript:$dname\_checkday()" >}; 501: # Month 502: my @Months = qw/January February March April May June 503: July August September October November December/; 504: # Pad @Months with a bogus value to make indexing easier 505: unshift(@Months,'If you can read this an error occurred'); 506: if ($includeempty) { $monthselector.="<option value=''></option>"; } 507: for(my $m = 1;$m <=$#Months;$m++) { 508: $monthselector .= qq{ <option value="$m"}; 509: $monthselector .= ' selected="selected"' if ($m-1 eq $month); 510: $monthselector .= '> '.&mt($Months[$m]).' </option>'."\n"; 511: } 512: $monthselector.= ' </select>'; 513: # Day 514: my $dayselector = qq{<input type="text" name="$dname\_day" $state value="$mday" size="3" $special onchange="javascript:$dname\_checkday()" />}; 515: # Year 516: my $yearselector = qq{<input type="text" name="$dname\_year" $state value="$year" size="5" $special onchange="javascript:$dname\_checkday()" />}; 517: # 518: my $hourselector = qq{<select name="$dname\_hour" $special $state >}; 519: if ($includeempty) { 520: $hourselector.=qq{<option value=''></option>}; 521: } 522: for (my $h = 0;$h<24;$h++) { 523: $hourselector .= qq{<option value="$h"}; 524: $hourselector .= ' selected="selected"' if (defined($hour) && $hour == $h); 525: $hourselector .= ">"; 526: my $timest=''; 527: if ($h == 0) { 528: $timest .= "12 am"; 529: } elsif($h == 12) { 530: $timest .= "12 noon"; 531: } elsif($h < 12) { 532: $timest .= "$h am"; 533: } else { 534: $timest .= $h-12 ." pm"; 535: } 536: $timest=&mt($timest); 537: $hourselector .= $timest." </option>\n"; 538: } 539: $hourselector .= " </select>\n"; 540: my $minuteselector = qq{<input type="text" name="$dname\_minute" $special $state value="$min" size="3" />}; 541: my $secondselector= qq{<input type="text" name="$dname\_second" $special $state value="$sec" size="3" />}; 542: my $cal_link; 543: if (!$nolink) { 544: $cal_link = qq{<a href="javascript:$dname\_opencalendar()">}; 545: } 546: # 547: my $tzone = ' '.$tzname.' '; 548: if ($no_hh_mm_ss) { 549: $result .= &mt('[_1] [_2] [_3] ', 550: $monthselector,$dayselector,$yearselector). 551: $tzone; 552: if (!$nolink) { 553: $result .= &mt('[_1]Select Date[_2]',$cal_link,'</a>'); 554: } 555: } else { 556: $result .= &mt('[_1] [_2] [_3] [_4] [_5]m [_6]s ', 557: $monthselector,$dayselector,$yearselector, 558: $hourselector,$minuteselector,$secondselector). 559: $tzone; 560: if (!$nolink) { 561: $result .= &mt('[_1]Select Date[_2]',$cal_link,'</a>'); 562: } 563: } 564: $result .= "</span>\n<!-- end $dname date setting form -->\n"; 565: return $result; 566: } 567: 568: sub get_timedates { 569: my ($epoch) = @_; 570: my $dt = DateTime->from_epoch(epoch => $epoch) 571: ->set_time_zone(&Apache::lonlocal::gettimezone()); 572: my $tzname = $dt->time_zone_short_name(); 573: my $sec = $dt->second; 574: my $min = $dt->minute; 575: my $hour = $dt->hour; 576: my $mday = $dt->day; 577: my $month = $dt->month; 578: if ($month) { 579: $month --; 580: } 581: my $year = $dt->year; 582: return ($tzname,$sec,$min,$hour,$mday,$month,$year); 583: } 584: 585: sub build_url { 586: my ($base, $fields)=@_; 587: my $url; 588: $url = $base.'?'; 589: foreach my $key (keys(%$fields)) { 590: $url.=&escape($key).'='.&escape($$fields{$key}).'&'; 591: } 592: $url =~ s/&$//; 593: return $url; 594: } 595: 596: 597: ############################################## 598: ############################################## 599: 600: =pod 601: 602: =item &get_date_from_form 603: 604: get_date_from_form retrieves the date specified in an &date_setter form. 605: 606: Inputs: 607: 608: =over 4 609: 610: =item $dname 611: 612: The name passed to &date_setter, which prefixes the form elements. 613: 614: =item $defaulttime 615: 616: The unix time to use as the default in case of poor inputs. 617: 618: =back 619: 620: Returns: Unix time represented in the form. 621: 622: =cut 623: 624: ############################################## 625: ############################################## 626: sub get_date_from_form { 627: my ($dname) = @_; 628: my ($sec,$min,$hour,$day,$month,$year); 629: # 630: if (defined($env{'form.'.$dname.'_second'})) { 631: my $tmpsec = $env{'form.'.$dname.'_second'}; 632: if (($tmpsec =~ /^\d+$/) && ($tmpsec >= 0) && ($tmpsec < 60)) { 633: $sec = $tmpsec; 634: } 635: if (!defined($tmpsec) || $tmpsec eq '') { $sec = 0; } 636: } else { 637: $sec = 0; 638: } 639: if (defined($env{'form.'.$dname.'_minute'})) { 640: my $tmpmin = $env{'form.'.$dname.'_minute'}; 641: if (($tmpmin =~ /^\d+$/) && ($tmpmin >= 0) && ($tmpmin < 60)) { 642: $min = $tmpmin; 643: } 644: if (!defined($tmpmin) || $tmpmin eq '') { $min = 0; } 645: } else { 646: $min = 0; 647: } 648: if (defined($env{'form.'.$dname.'_hour'})) { 649: my $tmphour = $env{'form.'.$dname.'_hour'}; 650: if (($tmphour =~ /^\d+$/) && ($tmphour >= 0) && ($tmphour < 24)) { 651: $hour = $tmphour; 652: } 653: } else { 654: $hour = 0; 655: } 656: if (defined($env{'form.'.$dname.'_day'})) { 657: my $tmpday = $env{'form.'.$dname.'_day'}; 658: if (($tmpday =~ /^\d+$/) && ($tmpday > 0) && ($tmpday < 32)) { 659: $day = $tmpday; 660: } 661: } 662: if (defined($env{'form.'.$dname.'_month'})) { 663: my $tmpmonth = $env{'form.'.$dname.'_month'}; 664: if (($tmpmonth =~ /^\d+$/) && ($tmpmonth > 0) && ($tmpmonth < 13)) { 665: $month = $tmpmonth; 666: } 667: } 668: if (defined($env{'form.'.$dname.'_year'})) { 669: my $tmpyear = $env{'form.'.$dname.'_year'}; 670: if (($tmpyear =~ /^\d+$/) && ($tmpyear >= 1970)) { 671: $year = $tmpyear; 672: } 673: } 674: if (($year<1970) || ($year>2037)) { return undef; } 675: if (defined($sec) && defined($min) && defined($hour) && 676: defined($day) && defined($month) && defined($year)) { 677: my $timezone = &Apache::lonlocal::gettimezone(); 678: my $dt = DateTime->new( year => $year, 679: month => $month, 680: day => $day, 681: hour => $hour, 682: minute => $min, 683: second => $sec, 684: time_zone => $timezone, 685: ); 686: my $epoch_time = $dt->epoch; 687: if ($epoch_time ne '') { 688: return $epoch_time; 689: } else { 690: return undef; 691: } 692: } else { 693: return undef; 694: } 695: } 696: 697: ############################################## 698: ############################################## 699: 700: =pod 701: 702: =item &pjump_javascript_definition() 703: 704: Returns javascript defining the 'pjump' function, which opens up a 705: parameter setting wizard. 706: 707: =cut 708: 709: ############################################## 710: ############################################## 711: sub pjump_javascript_definition { 712: my $Str = <<END; 713: function pjump(type,dis,value,marker,ret,call,hour,min,sec) { 714: parmwin=window.open("/adm/rat/parameter.html?type="+escape(type) 715: +"&value="+escape(value)+"&marker="+escape(marker) 716: +"&return="+escape(ret) 717: +"&call="+escape(call)+"&name="+escape(dis) 718: +"&defhour="+escape(hour)+"&defmin="+escape(min) 719: +"&defsec="+escape(sec),"LONCAPAparms", 720: "height=350,width=350,scrollbars=no,menubar=no"); 721: } 722: END 723: return $Str; 724: } 725: 726: ############################################## 727: ############################################## 728: 729: =pod 730: 731: =item &javascript_nothing() 732: 733: Return an appropriate null for the users browser. This is used 734: as the first arguement for window.open calls when you want a blank 735: window that you can then write to. 736: 737: =cut 738: 739: ############################################## 740: ############################################## 741: sub javascript_nothing { 742: # mozilla and other browsers work with "''", but IE on mac does not. 743: my $nothing = "''"; 744: my $user_browser; 745: my $user_os; 746: $user_browser = $env{'browser.type'} if (exists($env{'browser.type'})); 747: $user_os = $env{'browser.os'} if (exists($env{'browser.os'})); 748: if (! defined($user_browser) || ! defined($user_os)) { 749: (undef,$user_browser,undef,undef,undef,$user_os) = 750: &Apache::loncommon::decode_user_agent(); 751: } 752: if ($user_browser eq 'explorer' && $user_os =~ 'mac') { 753: $nothing = "'javascript:void(0);'"; 754: } 755: return $nothing; 756: } 757: 758: ############################################## 759: ############################################## 760: sub javascript_docopen { 761: my ($mimetype) = @_; 762: $mimetype ||= 'text/html'; 763: # safari does not understand document.open() and loads "text/html" 764: my $nothing = "''"; 765: my $user_browser; 766: my $user_os; 767: $user_browser = $env{'browser.type'} if (exists($env{'browser.type'})); 768: $user_os = $env{'browser.os'} if (exists($env{'browser.os'})); 769: if (! defined($user_browser) || ! defined($user_os)) { 770: (undef,$user_browser,undef,undef,undef,$user_os) = 771: &Apache::loncommon::decode_user_agent(); 772: } 773: if ($user_browser eq 'safari' && $user_os =~ 'mac') { 774: $nothing = "document.clear()"; 775: } else { 776: $nothing = "document.open('$mimetype','replace')"; 777: } 778: return $nothing; 779: } 780: 781: 782: ############################################## 783: ############################################## 784: 785: =pod 786: 787: =item &StatusOptions() 788: 789: Returns html for a selection box which allows the user to choose the 790: enrollment status of students. The selection box name is 'Status'. 791: 792: Inputs: 793: 794: $status: the currently selected status. If undefined the value of 795: $env{'form.Status'} is taken. If that is undefined, a value of 'Active' 796: is used. 797: 798: $formname: The name of the form. If defined the onchange attribute of 799: the selection box is set to document.$formname.submit(). 800: 801: $size: the size (number of lines) of the selection box. 802: 803: $onchange: javascript to use when the value is changed. Enclosed in 804: double quotes, ""s, not single quotes. 805: 806: Returns: a perl string as described. 807: 808: =cut 809: 810: ############################################## 811: ############################################## 812: sub StatusOptions { 813: my ($status, $formName,$size,$onchange,$mult)=@_; 814: $size = 1 if (!defined($size)); 815: if (! defined($status)) { 816: $status = 'Active'; 817: $status = $env{'form.Status'} if (exists($env{'form.Status'})); 818: } 819: 820: my $Str = ''; 821: $Str .= '<select name="Status"'; 822: if (defined($mult)){ 823: $Str .= ' multiple="multiple" '; 824: } 825: if(defined($formName) && $formName ne '' && ! defined($onchange)) { 826: $Str .= ' onchange="document.'.$formName.'.submit()"'; 827: } 828: if (defined($onchange)) { 829: $Str .= ' onchange="'.$onchange.'"'; 830: } 831: $Str .= ' size="'.$size.'" '; 832: $Str .= '>'."\n"; 833: foreach my $type (['Active', &mt('Currently Has Access')], 834: ['Future', &mt('Will Have Future Access')], 835: ['Expired', &mt('Previously Had Access')], 836: ['Any', &mt('Any Access Status')]) { 837: my ($name,$label) = @$type; 838: $Str .= '<option value="'.$name.'" '; 839: if ($status eq $name) { 840: $Str .= 'selected="selected" '; 841: } 842: $Str .= '>'.$label.'</option>'."\n"; 843: } 844: 845: $Str .= '</select>'."\n"; 846: } 847: 848: ######################################################## 849: ######################################################## 850: 851: =pod 852: 853: =item Progess Window Handling Routines 854: 855: These routines handle the creation, update, increment, and closure of 856: progress windows. The progress window reports to the user the number 857: of items completed and an estimate of the time required to complete the rest. 858: 859: =over 4 860: 861: 862: =item &Create_PrgWin 863: 864: Writes javascript to the client to open a progress window and returns a 865: data structure used for bookkeeping. 866: 867: Inputs 868: 869: =over 4 870: 871: =item $r Apache request 872: 873: =item $title The title of the progress window 874: 875: =item $heading A description (usually 1 line) of the process being initiated. 876: 877: =item $number_to_do The total number of items being processed. 878: 879: =item $type Either 'popup' or 'inline' (popup is assumed if nothing is 880: specified) 881: 882: =item $width Specify the width in charaters of the input field. 883: 884: =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 885: 886: =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 887: 888: =back 889: 890: Returns a hash containing the progress state data structure. 891: 892: 893: =item &Update_PrgWin 894: 895: Updates the text in the progress indicator. Does not increment the count. 896: See &Increment_PrgWin. 897: 898: Inputs: 899: 900: =over 4 901: 902: =item $r Apache request 903: 904: =item $prog_state Pointer to the data structure returned by &Create_PrgWin 905: 906: =item $displaystring The string to write to the status indicator 907: 908: =back 909: 910: Returns: none 911: 912: 913: =item Increment_PrgWin 914: 915: Increment the count of items completed for the progress window by 1. 916: 917: Inputs: 918: 919: =over 4 920: 921: =item $r Apache request 922: 923: =item $prog_state Pointer to the data structure returned by Create_PrgWin 924: 925: =item $extraInfo A description of the items being iterated over. Typically 926: 'student'. 927: 928: =back 929: 930: Returns: none 931: 932: 933: =item Close_PrgWin 934: 935: Closes the progress window. 936: 937: Inputs: 938: 939: =over 4 940: 941: =item $r Apache request 942: 943: =item $prog_state Pointer to the data structure returned by Create_PrgWin 944: 945: =back 946: 947: Returns: none 948: 949: =back 950: 951: =cut 952: 953: ######################################################## 954: ######################################################## 955: 956: my $uniq=0; 957: sub get_uniq_name { 958: $uniq++; 959: return 'uniquename'.$uniq; 960: } 961: 962: # Create progress 963: sub Create_PrgWin { 964: my ($r, $title, $heading, $number_to_do,$type,$width,$formname, 965: $inputname)=@_; 966: if (!defined($type)) { $type='popup'; } 967: if (!defined($width)) { $width=55; } 968: my %prog_state; 969: $prog_state{'type'}=$type; 970: if ($type eq 'popup') { 971: $prog_state{'window'}='popwin'; 972: my $start_page = 973: &Apache::loncommon::start_page($title,undef, 974: {'only_body' => 1, 975: 'bgcolor' => '#88DDFF', 976: 'js_ready' => 1}); 977: my $end_page = &Apache::loncommon::end_page({'js_ready' => 1}); 978: 979: #the whole function called through timeout is due to issues 980: #in mozilla Read BUG #2665 if you want to know the whole story 981: &r_print($r,&Apache::lonhtmlcommon::scripttag( 982: "var popwin; 983: function openpopwin () { 984: popwin=open(\'\',\'popwin\',\'width=400,height=100\');". 985: "popwin.document.writeln(\'".$start_page. 986: "<h4>".&mt("$heading")."<\/h4>". 987: "<form action=\"\" name=\"popremain\" method=\"post\">". 988: '<input type="text" size="'.$width.'" name="remaining" value="'. 989: &mt('Starting').'" /><\\/form>'.$end_page. 990: "\');". 991: "popwin.document.close();}". 992: "\nwindow.setTimeout(openpopwin,0)" 993: )); 994: $prog_state{'formname'}='popremain'; 995: $prog_state{'inputname'}="remaining"; 996: } elsif ($type eq 'inline') { 997: $prog_state{'window'}='window'; 998: if (!$formname) { 999: $prog_state{'formname'}=&get_uniq_name(); 1000: &r_print($r,'<form action="" name="'.$prog_state{'formname'}.'">'); 1001: } else { 1002: $prog_state{'formname'}=$formname; 1003: } 1004: if (!$inputname) { 1005: $prog_state{'inputname'}=&get_uniq_name(); 1006: &r_print($r,&mt("$heading [_1]",' <input type="text" name="'.$prog_state{'inputname'}.'" size="'.$width.'" />')); 1007: } else { 1008: $prog_state{'inputname'}=$inputname; 1009: 1010: } 1011: if (!$formname) { &r_print($r,'</form>'); } 1012: &Update_PrgWin($r,\%prog_state,&mt('Starting')); 1013: } 1014: 1015: $prog_state{'done'}=0; 1016: $prog_state{'firststart'}=&Time::HiRes::time(); 1017: $prog_state{'laststart'}=&Time::HiRes::time(); 1018: $prog_state{'max'}=$number_to_do; 1019: 1020: return %prog_state; 1021: } 1022: 1023: # update progress 1024: sub Update_PrgWin { 1025: my ($r,$prog_state,$displayString)=@_; 1026: &r_print($r,&Apache::lonhtmlcommon::scripttag( 1027: $$prog_state{'window'}.'.document.'. 1028: $$prog_state{'formname'}.'.'. 1029: $$prog_state{'inputname'}.'.value="'. 1030: $displayString.'";' 1031: )); 1032: $$prog_state{'laststart'}=&Time::HiRes::time(); 1033: } 1034: 1035: # increment progress state 1036: sub Increment_PrgWin { 1037: my ($r,$prog_state,$extraInfo)=@_; 1038: $$prog_state{'done'}++; 1039: my $time_est= (&Time::HiRes::time() - $$prog_state{'firststart'})/ 1040: $$prog_state{'done'} * 1041: ($$prog_state{'max'}-$$prog_state{'done'}); 1042: $time_est = int($time_est); 1043: # 1044: my $min = int($time_est/60); 1045: my $sec = $time_est % 60; 1046: # 1047: my $str; 1048: if ($min == 0 && $sec > 1) { 1049: $str = '[_2] seconds'; 1050: } elsif ($min == 1 && $sec > 1) { 1051: $str = '1 minute [_2] seconds'; 1052: } elsif ($min == 1 && $sec < 2) { 1053: $str = '1 minute'; 1054: } elsif ($min < 10 && $sec > 1) { 1055: $str = '[_1] minutes, [_2] seconds'; 1056: } elsif ($min >= 10 || $sec < 2) { 1057: $str = '[_1] minutes'; 1058: } 1059: $time_est = &mt($str,$min,$sec); 1060: # 1061: my $lasttime = &Time::HiRes::time()-$$prog_state{'laststart'}; 1062: if ($lasttime > 9) { 1063: $lasttime = int($lasttime); 1064: } elsif ($lasttime < 0.01) { 1065: $lasttime = 0; 1066: } else { 1067: $lasttime = sprintf("%3.2f",$lasttime); 1068: } 1069: if ($lasttime == 1) { 1070: $lasttime = '('.$lasttime.' '.&mt('second for').' '.$extraInfo.')'; 1071: } else { 1072: $lasttime = '('.$lasttime.' '.&mt('seconds for').' '.$extraInfo.')'; 1073: } 1074: # 1075: my $user_browser = $env{'browser.type'} if (exists($env{'browser.type'})); 1076: my $user_os = $env{'browser.os'} if (exists($env{'browser.os'})); 1077: if (! defined($user_browser) || ! defined($user_os)) { 1078: (undef,$user_browser,undef,undef,undef,$user_os) = 1079: &Apache::loncommon::decode_user_agent(); 1080: } 1081: if ($user_browser eq 'explorer' && $user_os =~ 'mac') { 1082: $lasttime = ''; 1083: } 1084: &r_print($r,&Apache::lonhtmlcommon::scripttag( 1085: $$prog_state{'window'}.'.document.'. 1086: $$prog_state{'formname'}.'.'. 1087: $$prog_state{'inputname'}.'.value="'. 1088: $$prog_state{'done'}.'/'.$$prog_state{'max'}. 1089: ': '.$time_est.' '.&mt('remaining').' '.$lasttime.'";' 1090: )); 1091: $$prog_state{'laststart'}=&Time::HiRes::time(); 1092: } 1093: 1094: # close Progress Line 1095: sub Close_PrgWin { 1096: my ($r,$prog_state)=@_; 1097: if ($$prog_state{'type'} eq 'popup') { 1098: &r_print($r,&Apache::lonhtmlcommon::scripttag( 1099: 'popwin.close()' 1100: )); 1101: } elsif ($$prog_state{'type'} eq 'inline') { 1102: &Update_PrgWin($r,$prog_state,&mt('Done')); 1103: } 1104: undef(%$prog_state); 1105: } 1106: 1107: sub r_print { 1108: my ($r,$to_print)=@_; 1109: if ($r) { 1110: $r->print($to_print); 1111: $r->rflush(); 1112: } else { 1113: print($to_print); 1114: } 1115: } 1116: 1117: # ------------------------------------------------------- Puts directory header 1118: 1119: sub crumbs { 1120: my ($uri,$target,$prefix,$form,$size,$noformat,$skiplast)=@_; 1121: if (! defined($size)) { 1122: $size = '+2'; 1123: } 1124: if ($target) { 1125: $target = ' target="'. 1126: &Apache::loncommon::escape_single($target).'"'; 1127: } 1128: my $output=''; 1129: unless ($noformat) { $output.='<br /><tt><b>'; } 1130: $output.='<font size="'.$size.'">'.$prefix.'/'; 1131: if ($env{'user.adv'}) { 1132: my $path=$prefix.'/'; 1133: foreach my $dir (split('/',$uri)) { 1134: if (! $dir) { next; } 1135: $path .= $dir; 1136: if ($path eq $uri) { 1137: if ($skiplast) { 1138: $output.=$dir; 1139: last; 1140: } 1141: } else { 1142: $path.='/'; 1143: } 1144: my $href_path = &HTML::Entities::encode($path,'<>&"'); 1145: &Apache::loncommon::inhibit_menu_check(\$href_path); 1146: if ($form) { 1147: my $href = 'javascript:'.$form.".action='".$href_path."';".$form.'.submit();'; 1148: $output.=qq{<a href="$href" $target>$dir</a>/}; 1149: } else { 1150: $output.=qq{<a href="$href_path" $target>$dir</a>/}; 1151: } 1152: } 1153: } else { 1154: foreach my $dir (split('/',$uri)) { 1155: if (! $dir) { next; } 1156: $output.=$dir.'/'; 1157: } 1158: } 1159: if ($uri !~ m|/$|) { $output=~s|/$||; } 1160: return $output.'</font>'.($noformat?'':'</b></tt><br />'); 1161: } 1162: 1163: # --------------------- A function that generates a window for the spellchecker 1164: 1165: sub spellheader { 1166: my $start_page= 1167: &Apache::loncommon::start_page('Speller Suggestions',undef, 1168: {'only_body' => 1, 1169: 'js_ready' => 1, 1170: 'bgcolor' => '#DDDDDD', 1171: 'add_entries' => { 1172: 'onload' => 1173: 'document.forms.spellcheckform.submit()', 1174: } 1175: }); 1176: my $end_page= 1177: &Apache::loncommon::end_page({'js_ready' => 1}); 1178: 1179: my $nothing=&javascript_nothing(); 1180: return (<<ENDCHECK); 1181: <script type="text/javascript"> 1182: // <![CDATA[ 1183: //<!-- BEGIN LON-CAPA Internal 1184: var checkwin; 1185: 1186: function spellcheckerwindow(string) { 1187: var esc_string = string.replace(/\"/g,'"'); 1188: checkwin=window.open($nothing,'spellcheckwin','height=320,width=280,resizable=yes,scrollbars=yes,location=no,menubar=no,toolbar=no'); 1189: checkwin.document.writeln('$start_page<form name="spellcheckform" action="/adm/spellcheck" method="post"><input type="hidden" name="text" value="'+esc_string+'" /><\\/form>$end_page'); 1190: checkwin.document.close(); 1191: } 1192: // END LON-CAPA Internal --> 1193: // ]]> 1194: </script> 1195: ENDCHECK 1196: } 1197: 1198: # ---------------------------------- Generate link to spell checker for a field 1199: 1200: sub spelllink { 1201: my ($form,$field)=@_; 1202: my $linktext=&mt('Check Spelling'); 1203: return (<<ENDLINK); 1204: <a href="javascript:if (typeof(document.$form.onsubmit)!='undefined') { if (document.$form.onsubmit!=null) { document.$form.onsubmit();}};spellcheckerwindow(this.document.forms.$form.$field.value);">$linktext</a> 1205: ENDLINK 1206: } 1207: 1208: # ------------------------------------------------- Output headers for HTMLArea 1209: 1210: { 1211: my @htmlareafields; 1212: sub init_htmlareafields { 1213: undef(@htmlareafields); 1214: } 1215: 1216: sub add_htmlareafields { 1217: my (@newfields) = @_; 1218: push(@htmlareafields,@newfields); 1219: } 1220: 1221: sub get_htmlareafields { 1222: return @htmlareafields; 1223: } 1224: } 1225: 1226: sub htmlareaheaders { 1227: return if (&htmlareablocked()); 1228: return if (!&htmlareabrowser()); 1229: return (<<ENDHEADERS); 1230: <script type="text/javascript" src="/fckeditor/fckeditor.js"></script> 1231: ENDHEADERS 1232: } 1233: 1234: # ----------------------------------------------------------------- Preferences 1235: 1236: sub disablelink { 1237: my @fields=@_; 1238: if (defined($#fields)) { 1239: unless ($#fields>=0) { return ''; } 1240: } 1241: return '<a href="'.&HTML::Entities::encode('/adm/preferences?action=set_wysiwyg&wysiwyg=off&returnurl=','<>&"').&escape($ENV{'REQUEST_URI'}).'">'.&mt('Disable WYSIWYG Editor').'</a>'; 1242: } 1243: 1244: sub enablelink { 1245: my @fields=@_; 1246: if (defined($#fields)) { 1247: unless ($#fields>=0) { return ''; } 1248: } 1249: return '<a href="'.&HTML::Entities::encode('/adm/preferences?action=set_wysiwyg&wysiwyg=on&returnurl=','<>&"').&escape($ENV{'REQUEST_URI'}).'">'.&mt('Enable WYSIWYG Editor').'</a>'; 1250: } 1251: 1252: # ------------------------------------------------- lang to use in html editor 1253: sub htmlarea_lang { 1254: my $lang='en'; 1255: if (&mt('htmlarea_lang') ne 'htmlarea_lang') { 1256: $lang=&mt('htmlarea_lang'); 1257: } 1258: return $lang; 1259: } 1260: 1261: # ----------------------------------------- Script to activate only some fields 1262: 1263: sub htmlareaselectactive { 1264: my @fields=@_; 1265: unless (&htmlareabrowser()) { return ''; } 1266: if (&htmlareablocked()) { return '<br />'.&enablelink(@fields); } 1267: my $output='<script type="text/javascript" defer="1">'."\n" 1268: .'// <![CDATA['."\n"; 1269: my $lang = &htmlarea_lang(); 1270: foreach my $field (@fields) { 1271: $output.=" 1272: { 1273: var oFCKeditor = new FCKeditor('$field'); 1274: oFCKeditor.Config['CustomConfigurationsPath'] = 1275: '/fckeditor/loncapaconfig.js'; 1276: oFCKeditor.ReplaceTextarea(); 1277: oFCKeditor.Config['AutoDetectLanguage'] = false; 1278: oFCKeditor.Config['DefaultLanguage'] = '$lang'; 1279: }"; 1280: } 1281: $output.="\nwindow.status='Activated Editfields';\n" 1282: .'// ]]>'."\n" 1283: .'</script><br />'. 1284: &disablelink(@fields); 1285: return $output; 1286: } 1287: 1288: # --------------------------------------------------------------------- Blocked 1289: 1290: sub htmlareablocked { 1291: unless ($env{'environment.wysiwygeditor'} eq 'on') { return 1; } 1292: return 0; 1293: } 1294: 1295: # ---------------------------------------- Browser capable of running HTMLArea? 1296: 1297: sub htmlareabrowser { 1298: return 1; 1299: } 1300: 1301: ############################################################ 1302: ############################################################ 1303: 1304: =pod 1305: 1306: =item breadcrumbs 1307: 1308: Compiles the previously registered breadcrumbs into an series of links. 1309: Additionally supports a 'component', which will be displayed on the 1310: right side of the breadcrumbs enclosing div (without a link). 1311: A link to help for the component will be included if one is specified. 1312: 1313: All inputs can be undef without problems. 1314: 1315: Inputs: $component (the text on the right side of the breadcrumbs trail), 1316: $component_help 1317: $menulink (boolean, controls whether to include a link to /adm/menu) 1318: $helplink (if 'nohelp' don't include the orange help link) 1319: $css_class (optional name for the class to apply to the table for CSS) 1320: $no_mt (optional flag, 1 if &mt() is _not_ to be applied to $component 1321: when including the text on the right. 1322: Returns a string containing breadcrumbs for the current page. 1323: 1324: =item clear_breadcrumbs 1325: 1326: Clears the previously stored breadcrumbs. 1327: 1328: =item add_breadcrumb 1329: 1330: Pushes a breadcrumb on the stack of crumbs. 1331: 1332: input: $breadcrumb, a hash reference. The keys 'href','title', and 'text' 1333: are required. If present the keys 'faq' and 'bug' will be used to provide 1334: links to the FAQ and bug sites. If the key 'no_mt' is present the 'title' 1335: and 'text' values won't be sent through &mt() 1336: 1337: returns: nothing 1338: 1339: =cut 1340: 1341: ############################################################ 1342: ############################################################ 1343: { 1344: my @Crumbs; 1345: 1346: sub breadcrumbs { 1347: my ($component,$component_help,$menulink,$helplink,$css_class,$no_mt, $CourseBreadcrumbs) = @_; 1348: # 1349: $css_class ||= 'LC_breadcrumbs'; 1350: 1351: # Make the faq and bug data cascade 1352: my $faq = ''; 1353: my $bug = ''; 1354: my $help = ''; 1355: # Crumb Symbol 1356: my $crumbsymbol = '»'; 1357: # The last breadcrumb does not have a link, so handle it separately. 1358: my $last = pop(@Crumbs); 1359: # 1360: # The first one should be the course or a menu link 1361: if (!defined($menulink)) { $menulink=1; } 1362: if ($menulink) { 1363: my $description = 'Menu'; 1364: my $no_mt_descr = 0; 1365: if (exists($env{'request.course.id'}) && 1366: $env{'request.course.id'} ne '') { 1367: $description = 1368: $env{'course.'.$env{'request.course.id'}.'.description'}; 1369: $no_mt_descr = 1; 1370: } 1371: $menulink = { href =>'/adm/menu', 1372: title =>'Go to main menu', 1373: target =>'_top', 1374: text =>$description, 1375: no_mt =>$no_mt_descr, }; 1376: if($last) { 1377: #$last set, so we have some crumbs 1378: unshift(@Crumbs,$menulink); 1379: } else { 1380: #only menulink crumb present 1381: $last = $menulink; 1382: } 1383: } 1384: my $links = join "", 1385: map { 1386: $faq = $_->{'faq'} if (exists($_->{'faq'})); 1387: $bug = $_->{'bug'} if (exists($_->{'bug'})); 1388: $help = $_->{'help'} if (exists($_->{'help'})); 1389: 1390: my $result = htmltag( 'a', 1391: $_->{no_mt} ? 1392: $_->{text} : mt($_->{text}), 1393: { 1394: href => $_->{href}, 1395: title => $_->{no_mt} ? 1396: $_->{title} : mt($_->{title}), 1397: target => $_->{target}, 1398: }); 1399: $result = htmltag( 'li', "$result $crumbsymbol"); 1400: } @Crumbs; 1401: 1402: #should the last Element be translated? 1403: $links .= htmltag( 'li', 1404: htmltag( 'b', 1405: $last->{'no_mt'} ? 1406: $last->{'text'} : mt($last->{'text'}) )); 1407: 1408: my $icons = ''; 1409: $faq = $last->{'faq'} if (exists($last->{'faq'})); 1410: $bug = $last->{'bug'} if (exists($last->{'bug'})); 1411: $help = $last->{'help'} if (exists($last->{'help'})); 1412: $component_help=($component_help?$component_help:$help); 1413: # if ($faq ne '') { 1414: # $icons .= &Apache::loncommon::help_open_faq($faq); 1415: # } 1416: # if ($bug ne '') { 1417: # $icons .= &Apache::loncommon::help_open_bug($bug); 1418: # } 1419: if ($faq ne '' || $component_help ne '' || $bug ne '') { 1420: $icons .= &Apache::loncommon::help_open_menu($component, 1421: $component_help, 1422: $faq,$bug); 1423: } 1424: # 1425: 1426: 1427: unless ($CourseBreadcrumbs) { 1428: $links = htmltag('ol', $links, { id => "LC_MenuBreadcrumbs" }); 1429: } else { 1430: $links = htmltag('ul', $links, { class => "LC_CourseBreadcrumbs" }); 1431: } 1432: 1433: if ($component) { 1434: $links = htmltag('span', 1435: ( $no_mt ? $component : mt($component) ). 1436: ( $icons ? $icons : '' ), 1437: { class => 'LC_breadcrumbs_component' } ) 1438: .$links; 1439: } 1440: 1441: $links = htmltag('div', $links, 1442: { id => "LC_breadcrumbs" }) unless ($CourseBreadcrumbs) ; 1443: 1444: # Return the @Crumbs stack to what we started with 1445: push(@Crumbs,$last); 1446: shift(@Crumbs); 1447: # Return the breadcrumb's line 1448: return "$links"; 1449: } 1450: 1451: sub clear_breadcrumbs { 1452: undef(@Crumbs); 1453: } 1454: 1455: sub add_breadcrumb { 1456: push(@Crumbs,@_); 1457: } 1458: 1459: } # End of scope for @Crumbs 1460: 1461: ############################################################ 1462: ############################################################ 1463: 1464: # Nested table routines. 1465: # 1466: # Routines to display form items in a multi-row table with 2 columns. 1467: # Uses nested tables to divide form elements into segments. 1468: # For examples of use see loncom/interface/lonnotify.pm 1469: # 1470: # Can be used in following order: ... 1471: # &start_pick_box() 1472: # row1 1473: # row2 1474: # row3 ... etc. 1475: # &submit_row() 1476: # &end_pick_box() 1477: # 1478: # where row1, row 2 etc. are chosen from &role_select_row,&course_select_row, 1479: # &status_select_row and &email_default_row 1480: # 1481: # Can also be used in following order: 1482: # 1483: # &start_pick_box() 1484: # &row_title() 1485: # &row_closure() 1486: # &row_title() 1487: # &row_closure() ... etc. 1488: # &submit_row() 1489: # &end_pick_box() 1490: # 1491: # In general a &submit_row() call should proceed the call to &end_pick_box(), 1492: # as this routine adds a button for form submission. 1493: # &submit_row() does not require a &row_closure after it. 1494: # 1495: # &start_pick_box() creates a bounding table with 1-pixel wide black border. 1496: # rows should be placed between calls to &start_pick_box() and &end_pick_box. 1497: # 1498: # &row_title() adds a title in the left column for each segment. 1499: # &row_closure() closes a row with a 1-pixel wide black line. 1500: # 1501: # &role_select_row() provides a select box from which to choose 1 or more roles 1502: # &course_select_row provides ways of picking groups of courses 1503: # radio buttons: all, by category or by picking from a course picker pop-up 1504: # note: by category option is only displayed if a domain has implemented 1505: # selection by year, semester, department, number etc. 1506: # 1507: # &status_select_row() provides a select box from which to choose 1 or more 1508: # access types (current access, prior access, and future access) 1509: # 1510: # &email_default_row() provides text boxes for default e-mail suffixes for 1511: # different authentication types in a domain. 1512: # 1513: # &row_title() and &row_closure() are called internally by the &*_select_row 1514: # routines, but can also be called directly to start and end rows which have 1515: # needs that are not accommodated by the *_select_row() routines. 1516: 1517: { # Start: row_count block for pick_box 1518: my @row_count; 1519: 1520: sub start_pick_box { 1521: my ($css_class) = @_; 1522: if (defined($css_class)) { 1523: $css_class = 'class="'.$css_class.'"'; 1524: } else { 1525: $css_class= 'class="LC_pick_box"'; 1526: } 1527: unshift(@row_count,0); 1528: my $output = <<"END"; 1529: <table $css_class> 1530: END 1531: return $output; 1532: } 1533: 1534: sub end_pick_box { 1535: shift(@row_count); 1536: my $output = <<"END"; 1537: </table> 1538: END 1539: return $output; 1540: } 1541: 1542: sub row_headline { 1543: my $output = <<"END"; 1544: <tr><td colspan="2"> 1545: END 1546: return $output; 1547: } 1548: 1549: sub row_title { 1550: my ($title,$css_title_class,$css_value_class) = @_; 1551: $row_count[0]++; 1552: my $css_class = ($row_count[0] % 2)?'LC_odd_row':'LC_even_row'; 1553: $css_title_class ||= 'LC_pick_box_title'; 1554: $css_title_class = 'class="'.$css_title_class.'"'; 1555: 1556: $css_value_class ||= 'LC_pick_box_value'; 1557: 1558: if ($title ne '') { 1559: $title .= ':'; 1560: } 1561: my $output = <<"ENDONE"; 1562: <tr class="LC_pick_box_row"> 1563: <td $css_title_class> 1564: $title 1565: </td> 1566: <td class="$css_value_class $css_class"> 1567: ENDONE 1568: return $output; 1569: } 1570: 1571: sub row_closure { 1572: my ($no_separator) =@_; 1573: my $output = <<"ENDTWO"; 1574: </td> 1575: </tr> 1576: ENDTWO 1577: if (!$no_separator) { 1578: $output .= <<"ENDTWO"; 1579: <tr> 1580: <td colspan="2" class="LC_pick_box_separator"> 1581: </td> 1582: </tr> 1583: ENDTWO 1584: } 1585: return $output; 1586: } 1587: 1588: } # End: row_count block for pick_box 1589: 1590: 1591: sub role_select_row { 1592: my ($roles,$title,$css_class,$show_separate_custom,$cdom,$cnum) = @_; 1593: my $output; 1594: if (defined($title)) { 1595: $output = &row_title($title,$css_class); 1596: } 1597: $output .= qq| 1598: <select name="roles" multiple="multiple">\n|; 1599: foreach my $role (@$roles) { 1600: my $plrole; 1601: if ($role eq 'ow') { 1602: $plrole = &mt('Course Owner'); 1603: } elsif ($role eq 'cr') { 1604: if ($show_separate_custom) { 1605: if ($cdom ne '' && $cnum ne '') { 1606: my %course_customroles = &course_custom_roles($cdom,$cnum); 1607: foreach my $crrole (sort(keys(%course_customroles))) { 1608: my ($plcrrole) = ($crrole =~ m|^cr/[^/]+/[^/]+/(.+)$|); 1609: $output .= ' <option value="'.$crrole.'">'.$plcrrole. 1610: '</option>'; 1611: } 1612: } 1613: } else { 1614: $plrole = &mt('Custom Role'); 1615: } 1616: } else { 1617: $plrole=&Apache::lonnet::plaintext($role); 1618: } 1619: if (($role ne 'cr') || (!$show_separate_custom)) { 1620: $output .= ' <option value="'.$role.'">'.$plrole.'</option>'; 1621: } 1622: } 1623: $output .= qq| </select>\n|; 1624: if (defined($title)) { 1625: $output .= &row_closure(); 1626: } 1627: return $output; 1628: } 1629: 1630: sub course_select_row { 1631: my ($title,$formname,$totcodes,$codetitles,$idlist,$idlist_titles, 1632: $css_class) = @_; 1633: my $output = &row_title($title,$css_class); 1634: $output .= &course_selection($formname,$totcodes,$codetitles,$idlist,$idlist_titles); 1635: $output .= &row_closure(); 1636: return $output; 1637: } 1638: 1639: sub course_selection { 1640: my ($formname,$totcodes,$codetitles,$idlist,$idlist_titles) = @_; 1641: my $output = qq| 1642: <script type="text/javascript"> 1643: // <![CDATA[ 1644: function coursePick (formname) { 1645: for (var i=0; i<formname.coursepick.length; i++) { 1646: if (formname.coursepick[i].value == 'category') { 1647: courseSet(''); 1648: } 1649: if (!formname.coursepick[i].checked) { 1650: if (formname.coursepick[i].value == 'specific') { 1651: formname.coursetotal.value = 0; 1652: formname.courselist = ''; 1653: } 1654: } 1655: } 1656: } 1657: function setPick (formname) { 1658: for (var i=0; i<formname.coursepick.length; i++) { 1659: if (formname.coursepick[i].value == 'category') { 1660: formname.coursepick[i].checked = true; 1661: } 1662: formname.coursetotal.value = 0; 1663: formname.courselist = ''; 1664: } 1665: } 1666: // ]]> 1667: </script> 1668: |; 1669: my $courseform='<b>'.&Apache::loncommon::selectcourse_link 1670: ($formname,'pickcourse','pickdomain','coursedesc','',1).'</b>'; 1671: $output .= '<input type="radio" name="coursepick" value="all" onclick="coursePick(this.form)" />'.&mt('All courses').'<br />'; 1672: if ($totcodes > 0) { 1673: my $numtitles = @$codetitles; 1674: if ($numtitles > 0) { 1675: $output .= '<input type="radio" name="coursepick" value="category" onclick="coursePick(this.form);alert('."'".&mt('Choose categories, from left to right')."'".')" />'.&mt('Pick courses by category:').' <br />'; 1676: $output .= '<table><tr><td>'.$$codetitles[0].'<br />'."\n". 1677: '<select name="'.$$codetitles[0]. 1678: '" onChange="setPick(this.form);courseSet('."'$$codetitles[0]'".')">'."\n". 1679: ' <option value="-1" />Select'."\n"; 1680: my @items = (); 1681: my @longitems = (); 1682: if ($$idlist{$$codetitles[0]} =~ /","/) { 1683: @items = split(/","/,$$idlist{$$codetitles[0]}); 1684: } else { 1685: $items[0] = $$idlist{$$codetitles[0]}; 1686: } 1687: if (defined($$idlist_titles{$$codetitles[0]})) { 1688: if ($$idlist_titles{$$codetitles[0]} =~ /","/) { 1689: @longitems = split(/","/,$$idlist_titles{$$codetitles[0]}); 1690: } else { 1691: $longitems[0] = $$idlist_titles{$$codetitles[0]}; 1692: } 1693: for (my $i=0; $i<@longitems; $i++) { 1694: if ($longitems[$i] eq '') { 1695: $longitems[$i] = $items[$i]; 1696: } 1697: } 1698: } else { 1699: @longitems = @items; 1700: } 1701: for (my $i=0; $i<@items; $i++) { 1702: $output .= ' <option value="'.$items[$i].'">'.$longitems[$i].'</option>'; 1703: } 1704: $output .= '</select></td>'; 1705: for (my $i=1; $i<$numtitles; $i++) { 1706: $output .= '<td>'.$$codetitles[$i].'<br />'."\n". 1707: '<select name="'.$$codetitles[$i]. 1708: '" onChange="courseSet('."'$$codetitles[$i]'".')">'."\n". 1709: '<option value="-1"><-Pick '.$$codetitles[$i-1].'</option>'."\n". 1710: '</select>'."\n". 1711: '</td>'; 1712: } 1713: $output .= '</tr></table><br />'; 1714: } 1715: } 1716: $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"; 1717: return $output; 1718: } 1719: 1720: sub status_select_row { 1721: my ($types,$title,$css_class) = @_; 1722: my $output; 1723: if (defined($title)) { 1724: $output = &row_title($title,$css_class,'LC_pick_box_select'); 1725: } 1726: $output .= qq| 1727: <select name="types" multiple="multiple">\n|; 1728: foreach my $status_type (sort(keys(%{$types}))) { 1729: $output .= ' <option value="'.$status_type.'">'.$$types{$status_type}.'</option>'; 1730: } 1731: $output .= qq| </select>\n|; 1732: if (defined($title)) { 1733: $output .= &row_closure(); 1734: } 1735: return $output; 1736: } 1737: 1738: sub email_default_row { 1739: my ($authtypes,$title,$descrip,$css_class) = @_; 1740: my $output = &row_title($title,$css_class); 1741: $output .= $descrip. 1742: &Apache::loncommon::start_data_table(). 1743: &Apache::loncommon::start_data_table_header_row(). 1744: '<th>'.&mt('Authentication Method').'</th>'. 1745: '<th align="right">'.&mt('Username -> e-mail conversion').'</th>'."\n". 1746: &Apache::loncommon::end_data_table_header_row(); 1747: my $rownum = 0; 1748: foreach my $auth (sort(keys(%{$authtypes}))) { 1749: my ($userentry,$size); 1750: if ($auth =~ /^krb/) { 1751: $userentry = ''; 1752: $size = 25; 1753: } else { 1754: $userentry = 'username@'; 1755: $size = 15; 1756: } 1757: $output .= &Apache::loncommon::start_data_table_row(). 1758: '<td> '.$$authtypes{$auth}.'</td>'. 1759: '<td align="right">'.$userentry. 1760: '<input type="text" name="'.$auth.'" size="'.$size.'" /></td>'. 1761: &Apache::loncommon::end_data_table_row(); 1762: } 1763: $output .= &Apache::loncommon::end_data_table(); 1764: $output .= &row_closure(); 1765: return $output; 1766: } 1767: 1768: 1769: sub submit_row { 1770: my ($title,$cmd,$submit_text,$css_class) = @_; 1771: my $output = &row_title($title,$css_class,'LC_pick_box_submit'); 1772: $output .= qq| 1773: <br /> 1774: <input type="hidden" name="command" value="$cmd" /> 1775: <input type="submit" value="$submit_text"/> 1776: <br /><br /> 1777: \n|; 1778: return $output; 1779: } 1780: 1781: sub course_custom_roles { 1782: my ($cdom,$cnum) = @_; 1783: my %returnhash=(); 1784: my %coursepersonnel=&Apache::lonnet::dump('nohist_userroles',$cdom,$cnum); 1785: foreach my $person (sort(keys(%coursepersonnel))) { 1786: my ($role) = ($person =~ /^([^:]+):/); 1787: my ($end,$start) = split(/:/,$coursepersonnel{$person}); 1788: if ($end == -1 && $start == -1) { 1789: next; 1790: } 1791: if ($role =~ m|^cr/[^/]+/[^/]+/[^/]|) { 1792: $returnhash{$role} ++; 1793: } 1794: } 1795: return %returnhash; 1796: } 1797: 1798: 1799: ############################################## 1800: ############################################## 1801: 1802: # topic_bar 1803: # 1804: # Generates a div containing a numbered (static image) followed by a title 1805: # with a background color defined in the corresponding CSS: LC_topic_bar 1806: # 1807: sub topic_bar { 1808: my ($imgnum,$title) = @_; 1809: return '<div class="LC_topic_bar">' 1810: .'<img src="/res/adm/pages/bl_step'.$imgnum.'.gif"' 1811: .' alt="'.&mt('Step [_1]',$imgnum).'" />' 1812: .' '.$title 1813: .'</div>'; 1814: } 1815: 1816: ############################################## 1817: ############################################## 1818: 1819: # echo_form_input 1820: # 1821: # Generates html markup to add form elements from the referrer page 1822: # as hidden form elements (values encoded) in the new page. 1823: # 1824: # Intended to support two types of use 1825: # (a) to allow backing up to earlier pages in a multi-page 1826: # form submission process using a breadcrumb trail. 1827: # 1828: # (b) to allow the current page to be reloaded with form elements 1829: # set on previous page to remain unchanged. An example would 1830: # be where the a page containing a dynamically-built table of data is 1831: # is to be redisplayed, with only the sort order of the data changed. 1832: # 1833: # Inputs: 1834: # 1. Reference to array of form elements in the submitted form on 1835: # the referrer page which are to be excluded from the echoed elements. 1836: # 1837: # 2. Reference to array of regular expressions, which if matched in the 1838: # name of the form element n the referrer page will be omitted from echo. 1839: # 1840: # Outputs: A scalar containing the html markup for the echoed form 1841: # elements (all as hidden elements, with values encoded). 1842: 1843: 1844: sub echo_form_input { 1845: my ($excluded,$regexps) = @_; 1846: my $output = ''; 1847: foreach my $key (keys(%env)) { 1848: if ($key =~ /^form\.(.+)$/) { 1849: my $name = $1; 1850: my $match = 0; 1851: if ((!@{$excluded}) || (!grep/^$name$/,@{$excluded})) { 1852: if (defined($regexps)) { 1853: if (@{$regexps} > 0) { 1854: foreach my $regexp (@{$regexps}) { 1855: if ($name =~ /\Q$regexp\E/) { 1856: $match = 1; 1857: last; 1858: } 1859: } 1860: } 1861: } 1862: if (!$match) { 1863: if (ref($env{$key})) { 1864: foreach my $value (@{$env{$key}}) { 1865: $value = &HTML::Entities::encode($value,'<>&"'); 1866: $output .= '<input type="hidden" name="'.$name. 1867: '" value="'.$value.'" />'."\n"; 1868: } 1869: } else { 1870: my $value = &HTML::Entities::encode($env{$key},'<>&"'); 1871: $output .= '<input type="hidden" name="'.$name. 1872: '" value="'.$value.'" />'."\n"; 1873: } 1874: } 1875: } 1876: } 1877: } 1878: return $output; 1879: } 1880: 1881: ############################################## 1882: ############################################## 1883: 1884: # set_form_elements 1885: # 1886: # Generates javascript to set form elements to values based on 1887: # corresponding values for the same form elements when the page was 1888: # previously submitted. 1889: # 1890: # Last submission values are read from hidden form elements in referring 1891: # page which have the same name, i.e., generated by &echo_form_input(). 1892: # 1893: # Intended to be called by onload event. 1894: # 1895: # Inputs: 1896: # (a) Reference to hash of echoed form elements to be set. 1897: # 1898: # In the hash, keys are the form element names, and the values are the 1899: # element type (selectbox, radio, checkbox or text -for textbox, textarea or 1900: # hidden). 1901: # 1902: # (b) Optional reference to hash of stored elements to be set. 1903: # 1904: # If the page being displayed is a page which permits modification of 1905: # previously stored data, e.g., the first page in a multi-page submission, 1906: # then if stored is supplied, form elements will be set to the last stored 1907: # values. If user supplied values are also available for the same elements 1908: # these will replace the stored values. 1909: # 1910: # Output: 1911: # 1912: # javascript function - set_form_elements() which sets form elements, 1913: # expects an argument: formname - the name of the form according to 1914: # the DOM, e.g., document.compose 1915: 1916: sub set_form_elements { 1917: my ($elements,$stored) = @_; 1918: my %values; 1919: my $output .= 'function setFormElements(courseForm) { 1920: '; 1921: if (defined($stored)) { 1922: foreach my $name (keys(%{$stored})) { 1923: if (exists($$elements{$name})) { 1924: if (ref($$stored{$name}) eq 'ARRAY') { 1925: $values{$name} = $$stored{$name}; 1926: } else { 1927: @{$values{$name}} = ($$stored{$name}); 1928: } 1929: } 1930: } 1931: } 1932: 1933: foreach my $key (keys(%env)) { 1934: if ($key =~ /^form\.(.+)$/) { 1935: my $name = $1; 1936: if (exists($$elements{$name})) { 1937: @{$values{$name}} = &Apache::loncommon::get_env_multiple($key); 1938: } 1939: } 1940: } 1941: 1942: foreach my $name (keys(%values)) { 1943: for (my $i=0; $i<@{$values{$name}}; $i++) { 1944: $values{$name}[$i] = &HTML::Entities::decode($values{$name}[$i],'<>&"'); 1945: $values{$name}[$i] =~ s/([\r\n\f]+)/\\n/g; 1946: $values{$name}[$i] =~ s/"/\\"/g; 1947: } 1948: if (($$elements{$name} eq 'text') || ($$elements{$name} eq 'hidden')) { 1949: my $numvalues = @{$values{$name}}; 1950: if ($numvalues > 1) { 1951: my $valuestring = join('","',@{$values{$name}}); 1952: $output .= qq| 1953: var textvalues = new Array ("$valuestring"); 1954: var total = courseForm.elements['$name'].length; 1955: if (total > $numvalues) { 1956: total = $numvalues; 1957: } 1958: for (var i=0; i<total; i++) { 1959: courseForm.elements['$name']\[i].value = textvalues[i]; 1960: } 1961: |; 1962: } else { 1963: $output .= qq| 1964: courseForm.elements['$name'].value = "$values{$name}[0]"; 1965: |; 1966: } 1967: } else { 1968: $output .= qq| 1969: var elementLength = courseForm.elements['$name'].length; 1970: if (elementLength==undefined) { 1971: |; 1972: foreach my $value (@{$values{$name}}) { 1973: if ($$elements{$name} eq 'selectbox') { 1974: $output .= qq| 1975: if (courseForm.elements['$name'].options[0].value == "$value") { 1976: courseForm.elements['$name'].options[0].selected = true; 1977: }|; 1978: } elsif (($$elements{$name} eq 'radio') || 1979: ($$elements{$name} eq 'checkbox')) { 1980: $output .= qq| 1981: if (courseForm.elements['$name'].value == "$value") { 1982: courseForm.elements['$name'].checked = true; 1983: } else { 1984: courseForm.elements['$name'].checked = false; 1985: }|; 1986: } 1987: } 1988: $output .= qq| 1989: } 1990: else { 1991: for (var i=0; i<courseForm.elements['$name'].length; i++) { 1992: |; 1993: if ($$elements{$name} eq 'selectbox') { 1994: $output .= qq| 1995: courseForm.elements['$name'].options[i].selected = false;|; 1996: } elsif (($$elements{$name} eq 'radio') || 1997: ($$elements{$name} eq 'checkbox')) { 1998: $output .= qq| 1999: courseForm.elements['$name']\[i].checked = false;|; 2000: } 2001: $output .= qq| 2002: } 2003: for (var j=0; j<courseForm.elements['$name'].length; j++) { 2004: |; 2005: foreach my $value (@{$values{$name}}) { 2006: if ($$elements{$name} eq 'selectbox') { 2007: $output .= qq| 2008: if (courseForm.elements['$name'].options[j].value == "$value") { 2009: courseForm.elements['$name'].options[j].selected = true; 2010: }|; 2011: } elsif (($$elements{$name} eq 'radio') || 2012: ($$elements{$name} eq 'checkbox')) { 2013: $output .= qq| 2014: if (courseForm.elements['$name']\[j].value == "$value") { 2015: courseForm.elements['$name']\[j].checked = true; 2016: }|; 2017: } 2018: } 2019: $output .= qq| 2020: } 2021: } 2022: |; 2023: } 2024: } 2025: $output .= " 2026: return; 2027: }\n"; 2028: return $output; 2029: } 2030: 2031: ############################################## 2032: ############################################## 2033: 2034: # javascript_valid_email 2035: # 2036: # Generates javascript to validate an e-mail address. 2037: # Returns a javascript function which accetps a form field as argumnent, and 2038: # returns false if field.value does not satisfy two regular expression matches 2039: # for a valid e-mail address. Backwards compatible with old browsers without 2040: # support for javascript RegExp (just checks for @ in field.value in this case). 2041: 2042: sub javascript_valid_email { 2043: my $scripttag .= <<'END'; 2044: function validmail(field) { 2045: var str = field.value; 2046: if (window.RegExp) { 2047: var reg1str = "(@.*@)|(\\.\\.)|(@\\.)|(\\.@)|(^\\.)"; 2048: var reg2str = "^.+\\@(\\[?)[a-zA-Z0-9\\-\\.]+\\.([a-zA-Z]{2,3}|[0-9]{1,3})(\\]?)$"; //" 2049: var reg1 = new RegExp(reg1str); 2050: var reg2 = new RegExp(reg2str); 2051: if (!reg1.test(str) && reg2.test(str)) { 2052: return true; 2053: } 2054: return false; 2055: } 2056: else 2057: { 2058: if(str.indexOf("@") >= 0) { 2059: return true; 2060: } 2061: return false; 2062: } 2063: } 2064: END 2065: return $scripttag; 2066: } 2067: 2068: 2069: # USAGE: htmltag(element, content, {attribute => value,...}); 2070: # 2071: # EXAMPLES: 2072: # - htmltag('a', 'this is an anchor', {href => 'www.example.com', 2073: # title => 'this is a title'}) 2074: # 2075: # - You might want to set up needed tags like: 2076: # 2077: # my $h3 = sub { return htmltag( "h3", @_ ) }; 2078: # 2079: # ... and use them: $h3->("This is a headline") 2080: # 2081: # - To set up a couple of tags, see sub inittags 2082: # 2083: # NOTES: 2084: # - Empty elements, such as <br/> are correctly terminated, 2085: # i.e. htmltag('br') returns <br/> 2086: # - Empty attributes (title="") are filtered out. 2087: # - The function will not check for deprecated attributes. 2088: # 2089: # OUTPUT: content enclosed in xhtml conform tags 2090: sub htmltag{ 2091: return 2092: qq|<$_[0]| 2093: . join( '', map { qq| $_="${$_[2]}{$_}"| if ${$_[2]}{$_} } keys %{ $_[2] } ) 2094: . ($_[1] ? qq|>$_[1]</$_[0]>| : qq|/>|). "\n"; 2095: }; 2096: 2097: 2098: # USAGE: inittags(@tags); 2099: # 2100: # EXAMPLES: 2101: # - my ($h1, $h2, $h3) = initTags( qw( h1 h2 h3 ) ) 2102: # $h1->("This is a headline") #Returns: <h1>This is a headline</h1> 2103: # 2104: # NOTES: See sub htmltag for further information. 2105: # 2106: # OUTPUT: List of subroutines. 2107: sub inittags { 2108: my @tags = @_; 2109: return map { my $tag = $_; 2110: sub { return htmltag( $tag, @_ ) } 2111: } @tags; 2112: } 2113: 2114: 2115: # USAGE: scripttag(scriptcode, [start|end|both]); 2116: # 2117: # EXAMPLES: 2118: # - scripttag("alert('Hello World!')", 'both') 2119: # returns: 2120: # <script type="text/javascript"> 2121: # // BEGIN LON-CAPA Internal 2122: # alert(Hello World!') 2123: # // END LON-CAPA Internal 2124: # </script> 2125: # 2126: # NOTES: 2127: # - works currently only for javascripts 2128: # 2129: # OUTPUT: 2130: # Scriptcode properly enclosed in <script> and CDATA tags (and LC 2131: # Internal markers if 2nd argument is given) 2132: sub scripttag { 2133: my ( $content, $marker ) = @_; 2134: return unless defined $content; 2135: 2136: my $begin = "\n// BEGIN LON-CAPA Internal\n"; 2137: my $end = "\n// END LON-CAPA Internal\n"; 2138: 2139: if ($marker) { 2140: $content = $begin . $content if $marker eq 'start' or $marker eq 'both'; 2141: $content .= $end if $marker eq 'end' or $marker eq 'both'; 2142: } 2143: 2144: $content = "\n// <![CDATA[\n$content\n// ]]>\n"; 2145: 2146: return htmltag('script', $content, {type => 'text/javascript'}); 2147: }; 2148: 2149: 2150: ############################################## 2151: ############################################## 2152: 2153: # generate_menu 2154: # 2155: # Generates html markup for a menu. 2156: # 2157: # Inputs: 2158: # An array of following structure: 2159: # ({ categorytitle => 'Categorytitle', 2160: # items => [ 2161: # { 2162: # linktext => 'Text to be displayed', 2163: # url => 'URL the link is pointing to, i.e. /adm/site?action=dosomething', 2164: # permission => 'Contains permissions as returned from lonnet::allowed(), 2165: # must evaluate to true in order to activate the link', 2166: # icon => 'icon filename', 2167: # alttext => 'alt text for the icon', 2168: # help => 'Name of the corresponding helpfile', 2169: # linktitle => 'Description of the link (used for title tag)' 2170: # }, 2171: # ... 2172: # ] 2173: # }, 2174: # ... 2175: # ) 2176: # 2177: # Outputs: A scalar containing the html markup for the menu. 2178: 2179: # ---- Remove when done ---- 2180: # This routine is part of the redesign of LON-CAPA and it's 2181: # subject to change during this project. 2182: # Don't rely on its current functionality as it might be 2183: # changed or removed. 2184: # -------------------------- 2185: sub generate_menu { 2186: my @menu = @_; 2187: # subs for specific html elements 2188: my ($h3, $div, $ul, $li, $a, $img) = inittags( qw(h3 div ul li a img) ); 2189: 2190: my @categories; # each element represents the entire markup for a category 2191: 2192: foreach my $category (@menu) { 2193: my @links; # contains the links for the current $category 2194: foreach my $link (@{$$category{items}}) { 2195: next unless $$link{permission}; 2196: 2197: # create the markup for the current $link and push it into @links. 2198: # each entry consists of an image and a text optionally followed 2199: # by a help link. 2200: push(@links,$li->( 2201: $a->( 2202: $img->("", { 2203: class => "LC_noBorder LC_middle", 2204: src => "/res/adm/pages/$$link{icon}", 2205: alt => mt(defined($$link{alttext}) ? 2206: $$link{alttext} : $$link{linktext}) 2207: }), { 2208: href => $$link{url}, 2209: title => mt($$link{linktitle}) 2210: }). 2211: $a->(mt($$link{linktext}), { 2212: href => $$link{url}, 2213: title => mt($$link{linktitle}), 2214: class => "LC_menubuttons_link" 2215: }). 2216: (defined($$link{help}) ? 2217: Apache::loncommon::help_open_topic($$link{help}) : ''), 2218: {class => "LC_menubuttons_inline_text"})); 2219: } 2220: 2221: # wrap categorytitle in <h3>, concatenate with 2222: # joined and in <ul> tags wrapped @links 2223: # and wrap everything in an enclosing <div> and push it into 2224: # @categories 2225: # such that each element looks like: 2226: # <div><h3>title</h3><ul><li>...</li>...</ul></div> 2227: # the category won't be added if there aren't any links 2228: push(@categories, 2229: $div->($h3->(mt($$category{categorytitle}), {class=>"LC_hcell"}). 2230: $ul->(join('' ,@links), {class =>"LC_ListStyleNormal" }), 2231: {class=>"LC_Box LC_400Box"})) if scalar(@links); 2232: } 2233: 2234: # wrap the joined @categories in another <div> (column layout) 2235: return $div->(join('', @categories), {class => "LC_columnSection"}); 2236: } 2237: 2238: ############################################## 2239: ############################################## 2240: 2241: =pod 2242: 2243: =item &start_funclist 2244: 2245: Start list of available functions 2246: 2247: Typically used to offer a simple list of available functions 2248: at top or bottom of page. 2249: All available functions/actions for the current page 2250: should be included in this list. 2251: 2252: If the optional headline text is not provided, a default text will be used. 2253: 2254: 2255: Related routines: 2256: =over 4 2257: add_item_funclist 2258: end_funclist 2259: =back 2260: 2261: 2262: Inputs: (optional) headline text 2263: 2264: Returns: HTML code with function list start 2265: 2266: =cut 2267: 2268: ############################################## 2269: ############################################## 2270: 2271: sub start_funclist { 2272: my($legendtext)=@_; 2273: $legendtext=&mt('Functions') if !$legendtext; 2274: return "<fieldset>\n<legend>$legendtext</legend>\n" 2275: .'<ul class="LC_funclist">'."\n"; 2276: } 2277: 2278: 2279: ############################################## 2280: ############################################## 2281: 2282: =pod 2283: 2284: =item &add_item_funclist 2285: 2286: Adds an item to the list of available functions 2287: 2288: Related routines: 2289: =over 4 2290: start_funclist 2291: end_funclist 2292: =back 2293: 2294: Inputs: content item with text and link to function 2295: 2296: Returns: HTML code with list item for funclist 2297: 2298: =cut 2299: 2300: ############################################## 2301: ############################################## 2302: 2303: sub add_item_funclist { 2304: my($content) = @_; 2305: return '<li>'.$content.'</li>'."\n"; 2306: } 2307: 2308: ############################################## 2309: ############################################## 2310: 2311: =pod 2312: 2313: =item &end_funclist 2314: 2315: End list of available functions 2316: 2317: Related routines: 2318: =over 4 2319: start_funclist 2320: add_item_funclist 2321: =back 2322: 2323: Inputs: ./. 2324: 2325: Returns: HTML code with function list end 2326: 2327: =cut 2328: 2329: ############################################## 2330: ############################################## 2331: 2332: sub end_funclist { 2333: my($r)=@_; 2334: return "</ul>\n</fieldset>\n"; 2335: } 2336: 2337: 1; 2338: 2339: __END__