![]() ![]() | ![]() |
- lots of \w -> probper regexp replacements
1: # The LearningOnline Network with CAPA 2: # a pile of common html routines 3: # 4: # $Id: lonhtmlcommon.pm,v 1.155 2006/12/05 02:55:53 albertel 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 authorbombs 71: 72: =cut 73: 74: ############################################## 75: ############################################## 76: 77: sub authorbombs { 78: my $url=shift; 79: $url=&Apache::lonnet::declutter($url); 80: my ($udom,$uname)=($url=~m{^($LONCAPA::domain_re)/($LONCAPA::username_re)/}); 81: my %bombs=&Apache::lonmsg::all_url_author_res_msg($uname,$udom); 82: foreach (keys %bombs) { 83: if ($_=~/^$udom\/$uname\//) { 84: return '<a href="/adm/bombs/'.$url. 85: '"><img src="'.&Apache::loncommon::lonhttpdurl('/adm/lonMisc/bomb.gif').'" border="0" /></a>'. 86: &Apache::loncommon::help_open_topic('About_Bombs'); 87: } 88: } 89: return ''; 90: } 91: 92: ############################################## 93: ############################################## 94: 95: sub recent_filename { 96: my $area=shift; 97: return 'nohist_recent_'.&escape($area); 98: } 99: 100: sub store_recent { 101: my ($area,$name,$value,$freeze)=@_; 102: my $file=&recent_filename($area); 103: my %recent=&Apache::lonnet::dump($file); 104: if (scalar(keys(%recent))>20) { 105: # remove oldest value 106: my $oldest=time(); 107: my $delkey=''; 108: foreach my $item (keys(%recent)) { 109: my $thistime=(split(/\&/,$recent{$item}))[0]; 110: if (($thistime ne "always_include") && ($thistime<$oldest)) { 111: $oldest=$thistime; 112: $delkey=$item; 113: } 114: } 115: &Apache::lonnet::del($file,[$delkey]); 116: } 117: # store new value 118: my $timestamp; 119: if ($freeze) { 120: $timestamp = "always_include"; 121: } else { 122: $timestamp = time(); 123: } 124: &Apache::lonnet::put($file,{ $name => 125: $timestamp.'&'.&escape($value) }); 126: } 127: 128: sub remove_recent { 129: my ($area,$names)=@_; 130: my $file=&recent_filename($area); 131: return &Apache::lonnet::del($file,$names); 132: } 133: 134: sub select_recent { 135: my ($area,$fieldname,$event)=@_; 136: my %recent=&Apache::lonnet::dump(&recent_filename($area)); 137: my $return="\n<select name='$fieldname'". 138: ($event?" onchange='$event'":''). 139: ">\n<option value=''>--- ".&mt('Recent')." ---</option>"; 140: foreach my $value (sort(keys(%recent))) { 141: unless ($value =~/^error\:/) { 142: my $escaped = &Apache::loncommon::escape_url($value); 143: $return.="\n<option value='$escaped'>". 144: &unescape((split(/\&/,$recent{$value}))[1]). 145: '</option>'; 146: } 147: } 148: $return.="\n</select>\n"; 149: return $return; 150: } 151: 152: sub get_recent { 153: my ($area, $n) = @_; 154: my %recent=&Apache::lonnet::dump(&recent_filename($area)); 155: 156: # Create hash with key as time and recent as value 157: # Begin filling return_hash with any 'always_include' option 158: my %time_hash = (); 159: my %return_hash = (); 160: foreach my $item (keys %recent) { 161: my ($thistime,$thisvalue)=(split(/\&/,$recent{$item})); 162: if ($thistime eq 'always_include') { 163: $return_hash{$item} = &unescape($thisvalue); 164: $n--; 165: } else { 166: $time_hash{$thistime} = $item; 167: } 168: } 169: 170: # Sort by decreasing time and return key value pairs 171: my $idx = 1; 172: foreach my $item (reverse(sort(keys(%time_hash)))) { 173: $return_hash{$time_hash{$item}} = 174: &unescape((split(/\&/,$recent{$time_hash{$item}}))[1]); 175: if ($n && ($idx++ >= $n)) {last;} 176: } 177: 178: return %return_hash; 179: } 180: 181: sub get_recent_frozen { 182: my ($area) = @_; 183: my %recent=&Apache::lonnet::dump(&recent_filename($area)); 184: 185: # Create hash with all 'frozen' items 186: my %return_hash = (); 187: foreach my $item (keys(%recent)) { 188: my ($thistime,$thisvalue)=(split(/\&/,$recent{$item})); 189: if ($thistime eq 'always_include') { 190: $return_hash{$item} = &unescape($thisvalue); 191: } 192: } 193: return %return_hash; 194: } 195: 196: 197: 198: =pod 199: 200: =item textbox 201: 202: =cut 203: 204: ############################################## 205: ############################################## 206: sub textbox { 207: my ($name,$value,$size,$special) = @_; 208: $size = 40 if (! defined($size)); 209: $value = &HTML::Entities::encode($value,'<>&"'); 210: my $Str = '<input type="text" name="'.$name.'" size="'.$size.'" '. 211: 'value="'.$value.'" '.$special.' />'; 212: return $Str; 213: } 214: 215: ############################################## 216: ############################################## 217: 218: =pod 219: 220: =item checkbox 221: 222: =cut 223: 224: ############################################## 225: ############################################## 226: sub checkbox { 227: my ($name,$checked,$value) = @_; 228: my $Str = '<input type="checkbox" name="'.$name.'" '; 229: if (defined($value)) { 230: $Str .= 'value="'.$value.'"'; 231: } 232: if ($checked) { 233: $Str .= ' checked="1"'; 234: } 235: $Str .= ' />'; 236: return $Str; 237: } 238: 239: 240: =pod 241: 242: =item radiobutton 243: 244: =cut 245: 246: ############################################## 247: ############################################## 248: sub radio { 249: my ($name,$checked,$value) = @_; 250: my $Str = '<input type="radio" name="'.$name.'" '; 251: if (defined($value)) { 252: $Str .= 'value="'.$value.'"'; 253: } 254: if ($checked eq $value) { 255: $Str .= ' checked="1"'; 256: } 257: $Str .= ' />'; 258: return $Str; 259: } 260: 261: ############################################## 262: ############################################## 263: 264: =pod 265: 266: =item &date_setter 267: 268: &date_setter returns html and javascript for a compact date-setting form. 269: To retrieve values from it, use &get_date_from_form(). 270: 271: Inputs 272: 273: =over 4 274: 275: =item $dname 276: 277: The name to prepend to the form elements. 278: The form elements defined will be dname_year, dname_month, dname_day, 279: dname_hour, dname_min, and dname_sec. 280: 281: =item $currentvalue 282: 283: The current setting for this time parameter. A unix format time 284: (time in seconds since the beginning of Jan 1st, 1970, GMT. 285: An undefined value is taken to indicate the value is the current time. 286: Also, to be explicit, a value of 'now' also indicates the current time. 287: 288: =item $special 289: 290: Additional html/javascript to be associated with each element in 291: the date_setter. See lonparmset for example usage. 292: 293: =item $includeempty 294: 295: =item $state 296: 297: Specifies the initial state of the form elements. Either 'disabled' or empty. 298: Defaults to empty, which indiciates the form elements are not disabled. 299: 300: =back 301: 302: Bugs 303: 304: The method used to restrict user input will fail in the year 2400. 305: 306: =cut 307: 308: ############################################## 309: ############################################## 310: sub date_setter { 311: my ($formname,$dname,$currentvalue,$special,$includeempty,$state, 312: $no_hh_mm_ss,$defhour,$defmin,$defsec,$nolink) = @_; 313: my $wasdefined=1; 314: if (! defined($state) || $state ne 'disabled') { 315: $state = ''; 316: } 317: if (! defined($no_hh_mm_ss)) { 318: $no_hh_mm_ss = 0; 319: } 320: if ($currentvalue eq 'now') { 321: $currentvalue=time; 322: } 323: if ((!defined($currentvalue)) || ($currentvalue eq '')) { 324: $wasdefined=0; 325: if ($includeempty) { 326: $currentvalue = 0; 327: } else { 328: $currentvalue = time; 329: } 330: } 331: # other potentially useful values: wkday,yrday,is_daylight_savings 332: my ($sec,$min,$hour,$mday,$month,$year)=('','',undef,'','',''); 333: if ($currentvalue) { 334: ($sec,$min,$hour,$mday,$month,$year,undef,undef,undef) = 335: localtime($currentvalue); 336: $year += 1900; 337: } 338: unless ($wasdefined) { 339: if (($defhour) || ($defmin) || ($defsec)) { 340: ($sec,$min,$hour,$mday,$month,$year,undef,undef,undef) = 341: localtime(time); 342: $year += 1900; 343: $sec=($defsec?$defsec:0); 344: $min=($defmin?$defmin:0); 345: $hour=($defhour?$defhour:0); 346: } elsif (!$includeempty) { 347: $sec=0; 348: $min=0; 349: $hour=0; 350: } 351: } 352: my $result = "\n<!-- $dname date setting form -->\n"; 353: $result .= <<ENDJS; 354: <script type="text/javascript"> 355: function $dname\_checkday() { 356: var day = document.$formname.$dname\_day.value; 357: var month = document.$formname.$dname\_month.value; 358: var year = document.$formname.$dname\_year.value; 359: var valid = true; 360: if (day < 1) { 361: document.$formname.$dname\_day.value = 1; 362: } 363: if (day > 31) { 364: document.$formname.$dname\_day.value = 31; 365: } 366: if ((month == 1) || (month == 3) || (month == 5) || 367: (month == 7) || (month == 8) || (month == 10) || 368: (month == 12)) { 369: if (day > 31) { 370: document.$formname.$dname\_day.value = 31; 371: day = 31; 372: } 373: } else if (month == 2 ) { 374: if ((year % 4 == 0) && (year % 100 != 0)) { 375: if (day > 29) { 376: document.$formname.$dname\_day.value = 29; 377: } 378: } else if (day > 29) { 379: document.$formname.$dname\_day.value = 28; 380: } 381: } else if (day > 30) { 382: document.$formname.$dname\_day.value = 30; 383: } 384: } 385: 386: function $dname\_disable() { 387: document.$formname.$dname\_month.disabled=true; 388: document.$formname.$dname\_day.disabled=true; 389: document.$formname.$dname\_year.disabled=true; 390: document.$formname.$dname\_hour.disabled=true; 391: document.$formname.$dname\_minute.disabled=true; 392: document.$formname.$dname\_second.disabled=true; 393: } 394: 395: function $dname\_enable() { 396: document.$formname.$dname\_month.disabled=false; 397: document.$formname.$dname\_day.disabled=false; 398: document.$formname.$dname\_year.disabled=false; 399: document.$formname.$dname\_hour.disabled=false; 400: document.$formname.$dname\_minute.disabled=false; 401: document.$formname.$dname\_second.disabled=false; 402: } 403: 404: function $dname\_opencalendar() { 405: if (! document.$formname.$dname\_month.disabled) { 406: var calwin=window.open( 407: "/adm/announcements?pickdate=yes&formname=$formname&element=$dname&month="+ 408: document.$formname.$dname\_month.value+"&year="+ 409: document.$formname.$dname\_year.value, 410: "LONCAPAcal", 411: "height=350,width=350,scrollbars=yes,resizable=yes,menubar=no"); 412: } 413: 414: } 415: </script> 416: ENDJS 417: $result .= ' <span style="white-space: nowrap;">'; 418: my $monthselector = qq{<select name="$dname\_month" $special $state onchange="javascript:$dname\_checkday()" >}; 419: # Month 420: my @Months = qw/January February March April May June 421: July August September October November December/; 422: # Pad @Months with a bogus value to make indexing easier 423: unshift(@Months,'If you can read this an error occurred'); 424: if ($includeempty) { $monthselector.="<option value=''></option>"; } 425: for(my $m = 1;$m <=$#Months;$m++) { 426: $monthselector .= qq{ <option value="$m" }; 427: $monthselector .= "selected " if ($m-1 eq $month); 428: $monthselector .= '> '.&mt($Months[$m]).' </option>'; 429: } 430: $monthselector.= ' </select>'; 431: # Day 432: my $dayselector = qq{<input type="text" name="$dname\_day" $state value="$mday" size="3" $special onchange="javascript:$dname\_checkday()" />}; 433: # Year 434: my $yearselector = qq{<input type="year" name="$dname\_year" $state value="$year" size="5" $special onchange="javascript:$dname\_checkday()" />}; 435: # 436: my $hourselector = qq{<select name="$dname\_hour" $special $state >}; 437: if ($includeempty) { 438: $hourselector.=qq{<option value=''></option>}; 439: } 440: for (my $h = 0;$h<24;$h++) { 441: $hourselector .= qq{<option value="$h" }; 442: $hourselector .= "selected " if (defined($hour) && $hour == $h); 443: $hourselector .= ">"; 444: my $timest=''; 445: if ($h == 0) { 446: $timest .= "12 am"; 447: } elsif($h == 12) { 448: $timest .= "12 noon"; 449: } elsif($h < 12) { 450: $timest .= "$h am"; 451: } else { 452: $timest .= $h-12 ." pm"; 453: } 454: $timest=&mt($timest); 455: $hourselector .= $timest." </option>\n"; 456: } 457: $hourselector .= " </select>\n"; 458: my $minuteselector = qq{<input type="text" name="$dname\_minute" $special $state value="$min" size="3" />}; 459: my $secondselector= qq{<input type="text" name="$dname\_second" $special $state value="$sec" size="3" />}; 460: my $cal_link; 461: if (!$nolink) { 462: $cal_link = qq{<a href="javascript:$dname\_opencalendar()">}; 463: } 464: # 465: if ($no_hh_mm_ss) { 466: $result .= &mt('[_1] [_2] [_3] ', 467: $monthselector,$dayselector,$yearselector); 468: if (!$nolink) { 469: $result .= &mt('[_1]Select Date[_2]',$cal_link,'</a>'); 470: } 471: } else { 472: $result .= &mt('[_1] [_2] [_3] [_4] [_5]m [_6]s ', 473: $monthselector,$dayselector,$yearselector, 474: $hourselector,$minuteselector,$secondselector); 475: if (!$nolink) { 476: $result .= &mt('[_1]Select Date[_2]',$cal_link,'</a>'); 477: } 478: } 479: $result .= "</span>\n<!-- end $dname date setting form -->\n"; 480: return $result; 481: } 482: 483: ############################################## 484: ############################################## 485: 486: =pod 487: 488: =item &get_date_from_form 489: 490: get_date_from_form retrieves the date specified in an &date_setter form. 491: 492: Inputs: 493: 494: =over 4 495: 496: =item $dname 497: 498: The name passed to &datesetter, which prefixes the form elements. 499: 500: =item $defaulttime 501: 502: The unix time to use as the default in case of poor inputs. 503: 504: =back 505: 506: Returns: Unix time represented in the form. 507: 508: =cut 509: 510: ############################################## 511: ############################################## 512: sub get_date_from_form { 513: my ($dname) = @_; 514: my ($sec,$min,$hour,$day,$month,$year); 515: # 516: if (defined($env{'form.'.$dname.'_second'})) { 517: my $tmpsec = $env{'form.'.$dname.'_second'}; 518: if (($tmpsec =~ /^\d+$/) && ($tmpsec >= 0) && ($tmpsec < 60)) { 519: $sec = $tmpsec; 520: } 521: if (!defined($tmpsec) || $tmpsec eq '') { $sec = 0; } 522: } else { 523: $sec = 0; 524: } 525: if (defined($env{'form.'.$dname.'_minute'})) { 526: my $tmpmin = $env{'form.'.$dname.'_minute'}; 527: if (($tmpmin =~ /^\d+$/) && ($tmpmin >= 0) && ($tmpmin < 60)) { 528: $min = $tmpmin; 529: } 530: if (!defined($tmpmin) || $tmpmin eq '') { $min = 0; } 531: } else { 532: $min = 0; 533: } 534: if (defined($env{'form.'.$dname.'_hour'})) { 535: my $tmphour = $env{'form.'.$dname.'_hour'}; 536: if (($tmphour =~ /^\d+$/) && ($tmphour >= 0) && ($tmphour < 24)) { 537: $hour = $tmphour; 538: } 539: } else { 540: $hour = 0; 541: } 542: if (defined($env{'form.'.$dname.'_day'})) { 543: my $tmpday = $env{'form.'.$dname.'_day'}; 544: if (($tmpday =~ /^\d+$/) && ($tmpday > 0) && ($tmpday < 32)) { 545: $day = $tmpday; 546: } 547: } 548: if (defined($env{'form.'.$dname.'_month'})) { 549: my $tmpmonth = $env{'form.'.$dname.'_month'}; 550: if (($tmpmonth =~ /^\d+$/) && ($tmpmonth > 0) && ($tmpmonth < 13)) { 551: $month = $tmpmonth - 1; 552: } 553: } 554: if (defined($env{'form.'.$dname.'_year'})) { 555: my $tmpyear = $env{'form.'.$dname.'_year'}; 556: if (($tmpyear =~ /^\d+$/) && ($tmpyear > 1900)) { 557: $year = $tmpyear - 1900; 558: } 559: } 560: if (($year<70) || ($year>137)) { return undef; } 561: if (defined($sec) && defined($min) && defined($hour) && 562: defined($day) && defined($month) && defined($year) && 563: eval('&timelocal($sec,$min,$hour,$day,$month,$year)')) { 564: return &timelocal($sec,$min,$hour,$day,$month,$year); 565: } else { 566: return undef; 567: } 568: } 569: 570: ############################################## 571: ############################################## 572: 573: =pod 574: 575: =item &pjump_javascript_definition() 576: 577: Returns javascript defining the 'pjump' function, which opens up a 578: parameter setting wizard. 579: 580: =cut 581: 582: ############################################## 583: ############################################## 584: sub pjump_javascript_definition { 585: my $Str = <<END; 586: function pjump(type,dis,value,marker,ret,call,hour,min,sec) { 587: parmwin=window.open("/adm/rat/parameter.html?type="+escape(type) 588: +"&value="+escape(value)+"&marker="+escape(marker) 589: +"&return="+escape(ret) 590: +"&call="+escape(call)+"&name="+escape(dis) 591: +"&defhour="+escape(hour)+"&defmin="+escape(min) 592: +"&defsec="+escape(sec),"LONCAPAparms", 593: "height=350,width=350,scrollbars=no,menubar=no"); 594: } 595: END 596: return $Str; 597: } 598: 599: ############################################## 600: ############################################## 601: 602: =pod 603: 604: =item &javascript_nothing() 605: 606: Return an appropriate null for the users browser. This is used 607: as the first arguement for window.open calls when you want a blank 608: window that you can then write to. 609: 610: =cut 611: 612: ############################################## 613: ############################################## 614: sub javascript_nothing { 615: # mozilla and other browsers work with "''", but IE on mac does not. 616: my $nothing = "''"; 617: my $user_browser; 618: my $user_os; 619: $user_browser = $env{'browser.type'} if (exists($env{'browser.type'})); 620: $user_os = $env{'browser.os'} if (exists($env{'browser.os'})); 621: if (! defined($user_browser) || ! defined($user_os)) { 622: (undef,$user_browser,undef,undef,undef,$user_os) = 623: &Apache::loncommon::decode_user_agent(); 624: } 625: if ($user_browser eq 'explorer' && $user_os =~ 'mac') { 626: $nothing = "'javascript:void(0);'"; 627: } 628: return $nothing; 629: } 630: 631: ############################################## 632: ############################################## 633: sub javascript_docopen { 634: # safari does not understand document.open() and loads "text/html" 635: my $nothing = "''"; 636: my $user_browser; 637: my $user_os; 638: $user_browser = $env{'browser.type'} if (exists($env{'browser.type'})); 639: $user_os = $env{'browser.os'} if (exists($env{'browser.os'})); 640: if (! defined($user_browser) || ! defined($user_os)) { 641: (undef,$user_browser,undef,undef,undef,$user_os) = 642: &Apache::loncommon::decode_user_agent(); 643: } 644: if ($user_browser eq 'safari' && $user_os =~ 'mac') { 645: $nothing = "document.clear()"; 646: } else { 647: $nothing = "document.open('text/html','replace')"; 648: } 649: return $nothing; 650: } 651: 652: 653: ############################################## 654: ############################################## 655: 656: =pod 657: 658: =item &StatusOptions() 659: 660: Returns html for a selection box which allows the user to choose the 661: enrollment status of students. The selection box name is 'Status'. 662: 663: Inputs: 664: 665: $status: the currently selected status. If undefined the value of 666: $env{'form.Status'} is taken. If that is undefined, a value of 'Active' 667: is used. 668: 669: $formname: The name of the form. If defined the onchange attribute of 670: the selection box is set to document.$formname.submit(). 671: 672: $size: the size (number of lines) of the selection box. 673: 674: $onchange: javascript to use when the value is changed. Enclosed in 675: double quotes, ""s, not single quotes. 676: 677: Returns: a perl string as described. 678: 679: =cut 680: 681: ############################################## 682: ############################################## 683: sub StatusOptions { 684: my ($status, $formName,$size,$onchange)=@_; 685: $size = 1 if (!defined($size)); 686: if (! defined($status)) { 687: $status = 'Active'; 688: $status = $env{'form.Status'} if (exists($env{'form.Status'})); 689: } 690: 691: my $Str = ''; 692: $Str .= '<select name="Status"'; 693: if(defined($formName) && $formName ne '' && ! defined($onchange)) { 694: $Str .= ' onchange="document.'.$formName.'.submit()"'; 695: } 696: if (defined($onchange)) { 697: $Str .= ' onchange="'.$onchange.'"'; 698: } 699: $Str .= ' size="'.$size.'" '; 700: $Str .= '>'."\n"; 701: foreach my $type (['Active', &mt('Currently Has Access')], 702: ['Future', &mt('Will Have Future Access')], 703: ['Expired', &mt('Previously Had Access')], 704: ['Any', &mt('Any Access Status')]) { 705: my ($name,$label) = @$type; 706: $Str .= '<option value="'.$name.'" '; 707: if ($status eq $name) { 708: $Str .= 'selected="selected" '; 709: } 710: $Str .= '>'.$label.'</option>'."\n"; 711: } 712: 713: $Str .= '</select>'."\n"; 714: } 715: 716: ######################################################## 717: ######################################################## 718: 719: =pod 720: 721: =item Progess Window Handling Routines 722: 723: These routines handle the creation, update, increment, and closure of 724: progress windows. The progress window reports to the user the number 725: of items completed and an estimate of the time required to complete the rest. 726: 727: =over 4 728: 729: 730: =item &Create_PrgWin 731: 732: Writes javascript to the client to open a progress window and returns a 733: data structure used for bookkeeping. 734: 735: Inputs 736: 737: =over 4 738: 739: =item $r Apache request 740: 741: =item $title The title of the progress window 742: 743: =item $heading A description (usually 1 line) of the process being initiated. 744: 745: =item $number_to_do The total number of items being processed. 746: 747: =item $type Either 'popup' or 'inline' (popup is assumed if nothing is 748: specified) 749: 750: =item $width Specify the width in charaters of the input field. 751: 752: =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 753: 754: =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 755: 756: =back 757: 758: Returns a hash containing the progress state data structure. 759: 760: 761: =item &Update_PrgWin 762: 763: Updates the text in the progress indicator. Does not increment the count. 764: See &Increment_PrgWin. 765: 766: Inputs: 767: 768: =over 4 769: 770: =item $r Apache request 771: 772: =item $prog_state Pointer to the data structure returned by &Create_PrgWin 773: 774: =item $displaystring The string to write to the status indicator 775: 776: =back 777: 778: Returns: none 779: 780: 781: =item Increment_PrgWin 782: 783: Increment the count of items completed for the progress window by 1. 784: 785: Inputs: 786: 787: =over 4 788: 789: =item $r Apache request 790: 791: =item $prog_state Pointer to the data structure returned by Create_PrgWin 792: 793: =item $extraInfo A description of the items being iterated over. Typically 794: 'student'. 795: 796: =back 797: 798: Returns: none 799: 800: 801: =item Close_PrgWin 802: 803: Closes the progress window. 804: 805: Inputs: 806: 807: =over 4 808: 809: =item $r Apache request 810: 811: =item $prog_state Pointer to the data structure returned by Create_PrgWin 812: 813: =back 814: 815: Returns: none 816: 817: =back 818: 819: =cut 820: 821: ######################################################## 822: ######################################################## 823: 824: my $uniq=0; 825: sub get_uniq_name { 826: $uniq++; 827: return 'uniquename'.$uniq; 828: } 829: 830: # Create progress 831: sub Create_PrgWin { 832: my ($r, $title, $heading, $number_to_do,$type,$width,$formname, 833: $inputname)=@_; 834: if (!defined($type)) { $type='popup'; } 835: if (!defined($width)) { $width=55; } 836: my %prog_state; 837: $prog_state{'type'}=$type; 838: if ($type eq 'popup') { 839: $prog_state{'window'}='popwin'; 840: my $start_page = 841: &Apache::loncommon::start_page($title,undef, 842: {'only_body' => 1, 843: 'bgcolor' => '#88DDFF', 844: 'js_ready' => 1}); 845: my $end_page = &Apache::loncommon::end_page({'js_ready' => 1}); 846: 847: #the whole function called through timeout is due to issues 848: #in mozilla Read BUG #2665 if you want to know the whole story 849: &r_print($r,'<script type="text/javascript">'. 850: "var popwin; 851: function openpopwin () { 852: popwin=open(\'\',\'popwin\',\'width=400,height=100\');". 853: "popwin.document.writeln(\'".$start_page. 854: "<h4>$heading<\/h4>". 855: "<form name=\"popremain\" method=\"post\">". 856: '<input type="text" size="'.$width.'" name="remaining" value="'. 857: &mt('Starting').'" /><\\/form>'.$end_page. 858: "\');". 859: "popwin.document.close();}". 860: "\nwindow.setTimeout(openpopwin,0)</script>"); 861: $prog_state{'formname'}='popremain'; 862: $prog_state{'inputname'}="remaining"; 863: } elsif ($type eq 'inline') { 864: $prog_state{'window'}='window'; 865: if (!$formname) { 866: $prog_state{'formname'}=&get_uniq_name(); 867: &r_print($r,'<form name="'.$prog_state{'formname'}.'">'); 868: } else { 869: $prog_state{'formname'}=$formname; 870: } 871: if (!$inputname) { 872: $prog_state{'inputname'}=&get_uniq_name(); 873: &r_print($r,$heading.' <input type="text" name="'.$prog_state{'inputname'}. 874: '" size="'.$width.'" />'); 875: } else { 876: $prog_state{'inputname'}=$inputname; 877: 878: } 879: if (!$formname) { &r_print($r,'</form>'); } 880: &Update_PrgWin($r,\%prog_state,&mt('Starting')); 881: } 882: 883: $prog_state{'done'}=0; 884: $prog_state{'firststart'}=&Time::HiRes::time(); 885: $prog_state{'laststart'}=&Time::HiRes::time(); 886: $prog_state{'max'}=$number_to_do; 887: 888: return %prog_state; 889: } 890: 891: # update progress 892: sub Update_PrgWin { 893: my ($r,$prog_state,$displayString)=@_; 894: &r_print($r,'<script>'.$$prog_state{'window'}.'.document.'. 895: $$prog_state{'formname'}.'.'. 896: $$prog_state{'inputname'}.'.value="'. 897: $displayString.'";</script>'); 898: $$prog_state{'laststart'}=&Time::HiRes::time(); 899: } 900: 901: # increment progress state 902: sub Increment_PrgWin { 903: my ($r,$prog_state,$extraInfo)=@_; 904: $$prog_state{'done'}++; 905: my $time_est= (&Time::HiRes::time() - $$prog_state{'firststart'})/ 906: $$prog_state{'done'} * 907: ($$prog_state{'max'}-$$prog_state{'done'}); 908: $time_est = int($time_est); 909: # 910: my $min = int($time_est/60); 911: my $sec = $time_est % 60; 912: # 913: my $str; 914: if ($min == 0 && $sec > 1) { 915: $str = '[_2] seconds'; 916: } elsif ($min == 1 && $sec > 1) { 917: $str = '1 minute [_2] seconds'; 918: } elsif ($min == 1 && $sec < 2) { 919: $str = '1 minute'; 920: } elsif ($min < 10 && $sec > 1) { 921: $str = '[_1] minutes, [_2] seconds'; 922: } elsif ($min >= 10 || $sec < 2) { 923: $str = '[_1] minutes'; 924: } 925: $time_est = &mt($str,$min,$sec); 926: # 927: my $lasttime = &Time::HiRes::time()-$$prog_state{'laststart'}; 928: if ($lasttime > 9) { 929: $lasttime = int($lasttime); 930: } elsif ($lasttime < 0.01) { 931: $lasttime = 0; 932: } else { 933: $lasttime = sprintf("%3.2f",$lasttime); 934: } 935: if ($lasttime == 1) { 936: $lasttime = '('.$lasttime.' '.&mt('second for').' '.$extraInfo.')'; 937: } else { 938: $lasttime = '('.$lasttime.' '.&mt('seconds for').' '.$extraInfo.')'; 939: } 940: # 941: my $user_browser = $env{'browser.type'} if (exists($env{'browser.type'})); 942: my $user_os = $env{'browser.os'} if (exists($env{'browser.os'})); 943: if (! defined($user_browser) || ! defined($user_os)) { 944: (undef,$user_browser,undef,undef,undef,$user_os) = 945: &Apache::loncommon::decode_user_agent(); 946: } 947: if ($user_browser eq 'explorer' && $user_os =~ 'mac') { 948: $lasttime = ''; 949: } 950: &r_print($r,'<script>'.$$prog_state{'window'}.'.document.'. 951: $$prog_state{'formname'}.'.'. 952: $$prog_state{'inputname'}.'.value="'. 953: $$prog_state{'done'}.'/'.$$prog_state{'max'}. 954: ': '.$time_est.' '.&mt('remaining').' '.$lasttime.'";'.'</script>'); 955: $$prog_state{'laststart'}=&Time::HiRes::time(); 956: } 957: 958: # close Progress Line 959: sub Close_PrgWin { 960: my ($r,$prog_state)=@_; 961: if ($$prog_state{'type'} eq 'popup') { 962: &r_print($r,'<script>popwin.close()</script>'."\n"); 963: } elsif ($$prog_state{'type'} eq 'inline') { 964: &Update_PrgWin($r,$prog_state,&mt('Done')); 965: } 966: undef(%$prog_state); 967: } 968: 969: sub r_print { 970: my ($r,$to_print)=@_; 971: if ($r) { 972: $r->print($to_print); 973: $r->rflush(); 974: } else { 975: print($to_print); 976: } 977: } 978: 979: # ------------------------------------------------------- Puts directory header 980: 981: sub crumbs { 982: my ($uri,$target,$prefix,$form,$size,$noformat,$skiplast)=@_; 983: if (! defined($size)) { 984: $size = '+2'; 985: } 986: if ($target) { 987: $target = ' target="'. 988: &Apache::loncommon::escape_single($target).'"'; 989: } 990: my $output=''; 991: unless ($noformat) { $output.='<br /><tt><b>'; } 992: $output.='<font size="'.$size.'">'.$prefix.'/'; 993: if ($env{'user.adv'}) { 994: my $path=$prefix.'/'; 995: foreach my $dir (split('/',$uri)) { 996: if (! $dir) { next; } 997: $path .= $dir; 998: if ($path eq $uri) { 999: if ($skiplast) { 1000: $output.=$dir; 1001: last; 1002: } 1003: } else { 1004: $path.='/'; 1005: } 1006: my $linkpath = &Apache::loncommon::escape_single($path); 1007: if ($form) { 1008: $linkpath= 1009: qq{javascript:$form.action='$linkpath';$form.submit();}; 1010: } 1011: $output.=qq{<a href="$linkpath" $target>$dir</a>/}; 1012: } 1013: } else { 1014: foreach my $dir (split('/',$uri)) { 1015: if (! $dir) { next; } 1016: $output.=$dir.'/'; 1017: } 1018: } 1019: if ($uri !~ m|/$|) { $output=~s|/$||; } 1020: return $output.'</font>'.($noformat?'':'</b></tt><br />'); 1021: } 1022: 1023: # --------------------- A function that generates a window for the spellchecker 1024: 1025: sub spellheader { 1026: my $start_page= 1027: &Apache::loncommon::start_page('Speller Suggestions',undef, 1028: {'only_body' => 1, 1029: 'js_ready' => 1, 1030: 'bgcolor' => '#DDDDDD', 1031: 'add_entries' => { 1032: 'onload' => 1033: 'document.forms.spellcheckform.submit()', 1034: } 1035: }); 1036: my $end_page= 1037: &Apache::loncommon::end_page({'js_ready' => 1}); 1038: 1039: my $nothing=&javascript_nothing(); 1040: return (<<ENDCHECK); 1041: <script type="text/javascript"> 1042: //<!-- BEGIN LON-CAPA Internal 1043: var checkwin; 1044: 1045: function spellcheckerwindow(string) { 1046: var esc_string = string.replace(/\"/g,'"'); 1047: checkwin=window.open($nothing,'spellcheckwin','height=320,width=280,resizable=yes,scrollbars=yes,location=no,menubar=no,toolbar=no'); 1048: checkwin.document.writeln('$start_page<form name="spellcheckform" action="/adm/spellcheck" method="post"><input type="hidden" name="text" value="'+esc_string+'" /><\\/form>$end_page'); 1049: checkwin.document.close(); 1050: } 1051: // END LON-CAPA Internal --> 1052: </script> 1053: ENDCHECK 1054: } 1055: 1056: # ---------------------------------- Generate link to spell checker for a field 1057: 1058: sub spelllink { 1059: my ($form,$field)=@_; 1060: my $linktext=&mt('Check Spelling'); 1061: return (<<ENDLINK); 1062: <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> 1063: ENDLINK 1064: } 1065: 1066: # ------------------------------------------------- Output headers for HTMLArea 1067: 1068: { 1069: my @htmlareafields; 1070: sub init_htmlareafields { 1071: undef(@htmlareafields); 1072: } 1073: 1074: sub add_htmlareafields { 1075: my (@newfields) = @_; 1076: push(@htmlareafields,@newfields); 1077: } 1078: 1079: sub get_htmlareafields { 1080: return @htmlareafields; 1081: } 1082: } 1083: 1084: sub htmlareaheaders { 1085: if (&htmlareablocked()) { return ''; } 1086: unless (&htmlareabrowser()) { return ''; } 1087: my $lang='en'; 1088: if (&mt('htmlarea_lang') ne 'htmlarea_lang') { 1089: $lang=&mt('htmlarea_lang'); 1090: } 1091: return (<<ENDHEADERS); 1092: <script type="text/javascript"> 1093: _editor_url='/htmlarea/'; 1094: _editor_lang='$lang'; 1095: </script> 1096: <script type="text/javascript" src="/htmlarea/htmlarea.js"></script> 1097: <link rel="stylesheet" type="text/css" href="/htmlarea/htmlarea.css" /> 1098: ENDHEADERS 1099: } 1100: 1101: # ------------------------------------------------- Activate additional buttons 1102: 1103: sub htmlareaaddbuttons { 1104: if (&htmlareablocked()) { return ''; } 1105: unless (&htmlareabrowser()) { return ''; } 1106: return (<<ENDADDBUTTON); 1107: var config=new HTMLArea.Config(); 1108: config.registerButton('ed_math','LaTeX Inline', 1109: '/htmlarea/images/ed_math.gif',false, 1110: function(editor,id) { 1111: editor.surroundHTML(' <m>\$','\$</m> '); 1112: } 1113: ); 1114: config.registerButton('ed_math_eqn','LaTeX Equation', 1115: '/htmlarea/images/ed_math_eqn.gif',false, 1116: function(editor,id) { 1117: editor.surroundHTML( 1118: ' \\n<center><m>\\\\[','\\\\]</m></center>\\n '); 1119: } 1120: ); 1121: config.toolbar.push(['ed_math','ed_math_eqn']); 1122: ENDADDBUTTON 1123: } 1124: 1125: # ----------------------------------------------------------------- Preferences 1126: 1127: sub disablelink { 1128: my @fields=@_; 1129: if (defined($#fields)) { 1130: unless ($#fields>=0) { return ''; } 1131: } 1132: return '<a href="'.&HTML::Entities::encode('/adm/preferences?action=set_wysiwyg&wysiwyg=off&returnurl=','<>&"').&escape($ENV{'REQUEST_URI'}).'">'.&mt('Disable WYSIWYG Editor').'</a>'; 1133: } 1134: 1135: sub enablelink { 1136: my @fields=@_; 1137: if (defined($#fields)) { 1138: unless ($#fields>=0) { return ''; } 1139: } 1140: return '<a href="'.&HTML::Entities::encode('/adm/preferences?action=set_wysiwyg&wysiwyg=on&returnurl=','<>&"').&escape($ENV{'REQUEST_URI'}).'">'.&mt('Enable WYSIWYG Editor').'</a>'; 1141: } 1142: 1143: # ----------------------------------------- Script to activate only some fields 1144: 1145: sub htmlareaselectactive { 1146: my @fields=@_; 1147: unless (&htmlareabrowser()) { return ''; } 1148: if (&htmlareablocked()) { return '<br />'.&enablelink(@fields); } 1149: my $output='<script type="text/javascript" defer="1">'. 1150: &htmlareaaddbuttons(); 1151: foreach(@fields) { 1152: $output.="\nHTMLArea.replace('$_',config);"; 1153: } 1154: $output.="\nwindow.status='Activated Editfields';\n</script><br />". 1155: &disablelink(@fields); 1156: return $output; 1157: } 1158: 1159: # --------------------------------------------------------------------- Blocked 1160: 1161: sub htmlareablocked { 1162: unless ($env{'environment.wysiwygeditor'} eq 'on') { return 1; } 1163: return 0; 1164: } 1165: 1166: # ---------------------------------------- Browser capable of running HTMLArea? 1167: 1168: sub htmlareabrowser { 1169: return 1; 1170: } 1171: 1172: ############################################################ 1173: ############################################################ 1174: 1175: =pod 1176: 1177: =item breadcrumbs 1178: 1179: Compiles the previously registered breadcrumbs into an series of links. 1180: FAQ and BUG links will be placed on the left side of the table if they 1181: are defined for the last registered breadcrumb. 1182: Additionally supports a 'component', which will be displayed on the 1183: right side of the table (without a link). 1184: A link to help for the component will be included if one is specified. 1185: 1186: All inputs can be undef without problems. 1187: 1188: Inputs: $component (the large text on the right side of the table), 1189: $component_help 1190: $menulink (boolean, controls whether to include a link to /adm/menu) 1191: $helplink (if 'nohelp' don't include the orange help link) 1192: $css_class (optional name for the class to apply to the table for CSS) 1193: Returns a string containing breadcrumbs for the current page. 1194: 1195: =item clear_breadcrumbs 1196: 1197: Clears the previously stored breadcrumbs. 1198: 1199: =item add_breadcrumb 1200: 1201: Pushes a breadcrumb on the stack of crumbs. 1202: 1203: input: $breadcrumb, a hash reference. The keys 'href','title', and 'text' 1204: are required. If present the keys 'faq' and 'bug' will be used to provide 1205: links to the FAQ and bug sites. 1206: 1207: returns: nothing 1208: 1209: =cut 1210: 1211: ############################################################ 1212: ############################################################ 1213: { 1214: my @Crumbs; 1215: 1216: sub breadcrumbs { 1217: my ($component,$component_help,$menulink,$helplink,$css_class) = @_; 1218: # 1219: $css_class ||= 'LC_breadcrumbs'; 1220: my $Str = "\n".'<table class="'.$css_class.'"><tr><td>'; 1221: # 1222: # Make the faq and bug data cascade 1223: my $faq = ''; 1224: my $bug = ''; 1225: my $help=''; 1226: # The last breadcrumb does not have a link, so handle it separately. 1227: my $last = pop(@Crumbs); 1228: # 1229: # The first one should be the course or a menu link 1230: if (!defined($menulink)) { $menulink=1; } 1231: if ($menulink) { 1232: my $description = 'Menu'; 1233: if (exists($env{'request.course.id'}) && 1234: $env{'request.course.id'} ne '') { 1235: $description = 1236: $env{'course.'.$env{'request.course.id'}.'.description'}; 1237: } 1238: unshift(@Crumbs,{ 1239: href =>'/adm/menu', 1240: title =>'Go to main menu', 1241: target =>'_top', 1242: text =>$description, 1243: }); 1244: } 1245: my $links .= 1246: join('->', 1247: map { 1248: $faq = $_->{'faq'} if (exists($_->{'faq'})); 1249: $bug = $_->{'bug'} if (exists($_->{'bug'})); 1250: $help = $_->{'help'} if (exists($_->{'help'})); 1251: my $result = '<a href="'.$_->{'href'}.'" '; 1252: if (defined($_->{'target'}) && $_->{'target'} ne '') { 1253: $result .= 'target="'.$_->{'target'}.'" '; 1254: } 1255: $result .='title="'.&mt($_->{'title'}).'">'. 1256: &mt($_->{'text'}).'</a>'; 1257: $result; 1258: } @Crumbs 1259: ); 1260: $links .= '->' if ($links ne ''); 1261: $links .= '<b>'.&mt($last->{'text'}).'</b>'; 1262: # 1263: my $icons = ''; 1264: $faq = $last->{'faq'} if (exists($last->{'faq'})); 1265: $bug = $last->{'bug'} if (exists($last->{'bug'})); 1266: $help = $last->{'help'} if (exists($last->{'help'})); 1267: $component_help=($component_help?$component_help:$help); 1268: # if ($faq ne '') { 1269: # $icons .= &Apache::loncommon::help_open_faq($faq); 1270: # } 1271: # if ($bug ne '') { 1272: # $icons .= &Apache::loncommon::help_open_bug($bug); 1273: # } 1274: if ($faq ne '' || $component_help ne '' || $bug ne '') { 1275: $icons .= &Apache::loncommon::help_open_menu($component, 1276: $component_help, 1277: $faq,$bug); 1278: } 1279: # 1280: $Str .= $links.'</td>'; 1281: # 1282: if (defined($component)) { 1283: $Str .= '<td class="'.$css_class.'_component">'. 1284: &mt($component); 1285: if ($icons ne '') { 1286: $Str .= ' '.$icons; 1287: } 1288: $Str .= '</td>'; 1289: } 1290: $Str .= '</tr></table>'."\n"; 1291: # 1292: # Return the @Crumbs stack to what we started with 1293: push(@Crumbs,$last); 1294: shift(@Crumbs); 1295: # 1296: return $Str; 1297: } 1298: 1299: sub clear_breadcrumbs { 1300: undef(@Crumbs); 1301: } 1302: 1303: sub add_breadcrumb { 1304: push (@Crumbs,@_); 1305: } 1306: 1307: } # End of scope for @Crumbs 1308: 1309: ############################################################ 1310: ############################################################ 1311: 1312: # Nested table routines. 1313: # 1314: # Routines to display form items in a multi-row table with 2 columns. 1315: # Uses nested tables to divide form elements into segments. 1316: # For examples of use see loncom/interface/lonnotify.pm 1317: # 1318: # Can be used in following order: ... 1319: # &start_pick_box() 1320: # row1 1321: # row2 1322: # row3 ... etc. 1323: # &submit_row(0 1324: # &end_pickbox() 1325: # 1326: # where row1, row 2 etc. are chosen from &role_select_row,&course_select_row, 1327: # &status_select_row and &email_default_row 1328: # 1329: # Can also be used in following order: 1330: # 1331: # &start_pick_box() 1332: # &row_title() 1333: # &row_closure() 1334: # &row_title() 1335: # &row_closure() ... etc. 1336: # &submit_row() 1337: # &end_pick_box() 1338: # 1339: # In general a &submit_row() call should proceed the call to &end_pick_box(), 1340: # as this routine adds a button for form submission. 1341: # &submit_row() does not require a &row_closure after it. 1342: # 1343: # &start_pick_box() creates a bounding table with 1-pixel wide black border. 1344: # rows should be placed between calls to &start_pick_box() and &end_pick_box. 1345: # 1346: # &row_title() adds a title in the left column for each segment. 1347: # &row_closure() closes a row with a 1-pixel wide black line. 1348: # 1349: # &role_select_row() provides a select box from which to choose 1 or more roles 1350: # &course_select_row provides ways of picking groups of courses 1351: # radio buttons: all, by category or by picking from a course picker pop-up 1352: # note: by category option is only displayed if a domain has implemented 1353: # selection by year, semester, department, number etc. 1354: # 1355: # &status_select_row() provides a select box from which to choose 1 or more 1356: # access types (current access, prior access, and future access) 1357: # 1358: # &email_default_row() provides text boxes for default e-mail suffixes for 1359: # different authentication types in a domain. 1360: # 1361: # &row_title() and &row_closure() are called internally by the &*_select_row 1362: # routines, but can also be called directly to start and end rows which have 1363: # needs that are not accommodated by the *_select_row() routines. 1364: 1365: sub start_pick_box { 1366: my ($css_class) = @_; 1367: if (defined($css_class)) { 1368: $css_class = 'class="'.$css_class.'"'; 1369: } else { 1370: $css_class= 'class="LC_pick_box"'; 1371: } 1372: my $output = <<"END"; 1373: <table $css_class> 1374: END 1375: return $output; 1376: } 1377: 1378: sub end_pick_box { 1379: my $output = <<"END"; 1380: </table> 1381: END 1382: return $output; 1383: } 1384: 1385: sub row_title { 1386: my ($title,$css_title_class,$css_value_class) = @_; 1387: $css_title_class ||= 'LC_pick_box_title'; 1388: $css_title_class = 'class="'.$css_title_class.'"'; 1389: 1390: $css_value_class ||= 'LC_pick_box_value'; 1391: $css_value_class = 'class="'.$css_value_class.'"'; 1392: 1393: my $output = <<"ENDONE"; 1394: <tr class="LC_pick_box_row"> 1395: <td $css_title_class> 1396: $title: 1397: </td> 1398: <td $css_value_class> 1399: ENDONE 1400: return $output; 1401: } 1402: 1403: sub row_closure { 1404: my ($no_separator) =@_; 1405: my $output = <<"ENDTWO"; 1406: </td> 1407: </tr> 1408: ENDTWO 1409: if (!$no_separator) { 1410: $output .= <<"ENDTWO"; 1411: <tr> 1412: <td colspan="2" class="LC_pick_box_separator"> 1413: </td> 1414: </tr> 1415: ENDTWO 1416: } 1417: return $output; 1418: } 1419: 1420: sub role_select_row { 1421: my ($roles,$title,$css_class,$show_separate_custom,$cdom,$cnum) = @_; 1422: my $output; 1423: if (defined($title)) { 1424: $output = &row_title($title,$css_class); 1425: } 1426: $output .= qq| 1427: <select name="roles" multiple >\n|; 1428: foreach my $role (@$roles) { 1429: my $plrole; 1430: if ($role eq 'ow') { 1431: $plrole = &mt('Course Owner'); 1432: } elsif ($role eq 'cr') { 1433: if ($show_separate_custom) { 1434: if ($cdom ne '' && $cnum ne '') { 1435: my %course_customroles = &course_custom_roles($cdom,$cnum); 1436: foreach my $crrole (sort(keys(%course_customroles))) { 1437: my ($plcrrole) = ($crrole =~ m|^cr/[^/]+/[^/]+/(.+)$|); 1438: $output .= ' <option value="'.$crrole.'">'.$plcrrole. 1439: '</option>'; 1440: } 1441: } 1442: } else { 1443: $plrole = &mt('Custom Role'); 1444: } 1445: } else { 1446: $plrole=&Apache::lonnet::plaintext($role); 1447: } 1448: if (($role ne 'cr') || (!$show_separate_custom)) { 1449: $output .= ' <option value="'.$role.'">'.$plrole.'</option>'; 1450: } 1451: } 1452: $output .= qq| </select>\n|; 1453: if (defined($title)) { 1454: $output .= &row_closure(); 1455: } 1456: return $output; 1457: } 1458: 1459: sub course_select_row { 1460: my ($title,$formname,$totcodes,$codetitles,$idlist,$idlist_titles, 1461: $css_class) = @_; 1462: my $output = &row_title($title,$css_class); 1463: $output .= qq| 1464: <script type="text/javascript"> 1465: function coursePick (formname) { 1466: for (var i=0; i<formname.coursepick.length; i++) { 1467: if (formname.coursepick[i].value == 'category') { 1468: courseSet(''); 1469: } 1470: if (!formname.coursepick[i].checked) { 1471: if (formname.coursepick[i].value == 'specific') { 1472: formname.coursetotal.value = 0; 1473: formname.courselist = ''; 1474: } 1475: } 1476: } 1477: } 1478: function setPick (formname) { 1479: for (var i=0; i<formname.coursepick.length; i++) { 1480: if (formname.coursepick[i].value == 'category') { 1481: formname.coursepick[i].checked = true; 1482: } 1483: formname.coursetotal.value = 0; 1484: formname.courselist = ''; 1485: } 1486: } 1487: </script> 1488: |; 1489: my $courseform='<b>'.&Apache::loncommon::selectcourse_link 1490: ($formname,'pickcourse','pickdomain','coursedesc','',1).'</b>'; 1491: $output .= '<input type="radio" name="coursepick" value="all" onclick="coursePick(this.form)" />'.&mt('All courses').'<br />'; 1492: if ($totcodes > 0) { 1493: my $numtitles = @$codetitles; 1494: if ($numtitles > 0) { 1495: $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 />'; 1496: $output .= '<table><tr><td>'.$$codetitles[0].'<br />'."\n". 1497: '<select name="'.$$codetitles[0]. 1498: '" onChange="setPick(this.form);courseSet('."'$$codetitles[0]'".')">'."\n". 1499: ' <option value="-1" />Select'."\n"; 1500: my @items = (); 1501: my @longitems = (); 1502: if ($$idlist{$$codetitles[0]} =~ /","/) { 1503: @items = split(/","/,$$idlist{$$codetitles[0]}); 1504: } else { 1505: $items[0] = $$idlist{$$codetitles[0]}; 1506: } 1507: if (defined($$idlist_titles{$$codetitles[0]})) { 1508: if ($$idlist_titles{$$codetitles[0]} =~ /","/) { 1509: @longitems = split(/","/,$$idlist_titles{$$codetitles[0]}); 1510: } else { 1511: $longitems[0] = $$idlist_titles{$$codetitles[0]}; 1512: } 1513: for (my $i=0; $i<@longitems; $i++) { 1514: if ($longitems[$i] eq '') { 1515: $longitems[$i] = $items[$i]; 1516: } 1517: } 1518: } else { 1519: @longitems = @items; 1520: } 1521: for (my $i=0; $i<@items; $i++) { 1522: $output .= ' <option value="'.$items[$i].'">'.$longitems[$i].'</option>'; 1523: } 1524: $output .= '</select></td>'; 1525: for (my $i=1; $i<$numtitles; $i++) { 1526: $output .= '<td>'.$$codetitles[$i].'<br />'."\n". 1527: '<select name="'.$$codetitles[$i]. 1528: '" onChange="courseSet('."'$$codetitles[$i]'".')">'."\n". 1529: '<option value="-1"><-Pick '.$$codetitles[$i-1].'</option>'."\n". 1530: '</select>'."\n". 1531: '</td>'; 1532: } 1533: $output .= '</tr></table><br />'; 1534: } 1535: } 1536: $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"; 1537: $output .= &row_closure(); 1538: return $output; 1539: } 1540: 1541: sub status_select_row { 1542: my ($types,$title,$css_class) = @_; 1543: my $output; 1544: if (defined($title)) { 1545: $output = &row_title($title,$css_class,'LC_pick_box_select'); 1546: } 1547: $output .= qq| 1548: <select name="types" multiple>\n|; 1549: foreach my $status_type (sort(keys(%{$types}))) { 1550: $output .= ' <option value="'.$status_type.'">'.$$types{$status_type}.'</option>'; 1551: } 1552: $output .= qq| </select>\n|; 1553: if (defined($title)) { 1554: $output .= &row_closure(); 1555: } 1556: return $output; 1557: } 1558: 1559: sub email_default_row { 1560: my ($authtypes,$title,$descrip,$css_class) = @_; 1561: my $output = &row_title($title,$css_class); 1562: my @rowcols = ('#eeeeee','#dddddd'); 1563: $output .= $descrip. 1564: &Apache::loncommon::start_data_table(). 1565: &Apache::loncommon::start_data_table_header_row(). 1566: '<th>'.&mt('Authentication Method').'</th>'. 1567: '<th align="right">'.&mt('Username -> e-mail conversion').'</th>'."\n". 1568: &Apache::loncommon::end_data_table_header_row(); 1569: my $rownum = 0; 1570: foreach my $auth (sort(keys(%{$authtypes}))) { 1571: my ($userentry,$size); 1572: if ($auth =~ /^krb/) { 1573: $userentry = ''; 1574: $size = 25; 1575: } else { 1576: $userentry = 'username@'; 1577: $size = 15; 1578: } 1579: $output .= &Apache::loncommon::start_data_table_row(). 1580: '<td> '.$$authtypes{$auth}.'</td>'. 1581: '<td align="right">'.$userentry. 1582: '<input type="text" name="'.$auth.'" size="'.$size.'" /></td>'. 1583: &Apache::loncommon::end_data_table_row(); 1584: } 1585: $output .= &Apache::loncommon::end_data_table(); 1586: $output .= &row_closure(); 1587: return $output; 1588: } 1589: 1590: 1591: sub submit_row { 1592: my ($title,$cmd,$submit_text,$css_class) = @_; 1593: my $output = &row_title($title,$css_class,'LC_pick_box_submit'); 1594: $output .= qq| 1595: <br /> 1596: <input type="hidden" name="command" value="$cmd" /> 1597: <input type="submit" value="$submit_text"/> 1598: <br /><br /> 1599: \n|; 1600: return $output; 1601: } 1602: 1603: sub course_custom_roles { 1604: my ($cdom,$cnum) = @_; 1605: my %returnhash=(); 1606: my %coursepersonnel=&Apache::lonnet::dump('nohist_userroles',$cdom,$cnum); 1607: foreach my $person (sort(keys(%coursepersonnel))) { 1608: my ($role) = ($person =~ /^([^:]+):/); 1609: my ($end,$start) = split(/:/,$coursepersonnel{$person}); 1610: if ($end == -1 && $start == -1) { 1611: next; 1612: } 1613: if ($role =~ m|^cr/[^/]+/[^/]+/[^/]|) { 1614: $returnhash{$role} ++; 1615: } 1616: } 1617: return %returnhash; 1618: } 1619: 1620: 1621: ############################################## 1622: ############################################## 1623: 1624: # echo_form_input 1625: # 1626: # Generates html markup to add form elements from the referrer page 1627: # as hidden form elements (values encoded) in the new page. 1628: # 1629: # Intended to support two types of use 1630: # (a) to allow backing up to earlier pages in a multi-page 1631: # form submission process using a breadcrumb trail. 1632: # 1633: # (b) to allow the current page to be reloaded with form elements 1634: # set on previous page to remain unchanged. An example would 1635: # be where the a page containing a dynamically-built table of data is 1636: # is to be redisplayed, with only the sort order of the data changed. 1637: # 1638: # Inputs: 1639: # 1. Reference to array of form elements in the submitted form on 1640: # the referrer page which are to be excluded from the echoed elements. 1641: # 1642: # 2. Reference to array of regular expressions, which if matched in the 1643: # name of the form element n the referrer page will be omitted from echo. 1644: # 1645: # Outputs: A scalar containing the html markup for the echoed form 1646: # elements (all as hidden elements, with values encoded). 1647: 1648: 1649: sub echo_form_input { 1650: my ($excluded,$regexps) = @_; 1651: my $output = ''; 1652: foreach my $key (keys(%env)) { 1653: if ($key =~ /^form\.(.+)$/) { 1654: my $name = $1; 1655: my $match = 0; 1656: if ((!@{$excluded}) || (!grep/^$name$/,@{$excluded})) { 1657: if (defined($regexps)) { 1658: if (@{$regexps} > 0) { 1659: foreach my $regexp (@{$regexps}) { 1660: if ($name =~ /\Q$regexp\E/) { 1661: $match = 1; 1662: last; 1663: } 1664: } 1665: } 1666: } 1667: if (!$match) { 1668: if (ref($env{$key})) { 1669: foreach my $value (@{$env{$key}}) { 1670: $value = &HTML::Entities::encode($value,'<>&"'); 1671: $output .= '<input type="hidden" name="'.$name. 1672: '" value="'.$value.'" />'."\n"; 1673: } 1674: } else { 1675: my $value = &HTML::Entities::encode($env{$key},'<>&"'); 1676: $output .= '<input type="hidden" name="'.$name. 1677: '" value="'.$value.'" />'."\n"; 1678: } 1679: } 1680: } 1681: } 1682: } 1683: return $output; 1684: } 1685: 1686: ############################################## 1687: ############################################## 1688: 1689: # set_form_elements 1690: # 1691: # Generates javascript to set form elements to values based on 1692: # corresponding values for the same form elements when the page was 1693: # previously submitted. 1694: # 1695: # Last submission values are read from hidden form elements in referring 1696: # page which have the same name, i.e., generated by &echo_form_input(). 1697: # 1698: # Intended to be called by onload event. 1699: # 1700: # Inputs: 1701: # (a) Reference to hash of echoed form elements to be set. 1702: # 1703: # In the hash, keys are the form element names, and the values are the 1704: # element type (selectbox, radio, checkbox or text -for textbox, textarea or 1705: # hidden). 1706: # 1707: # (b) Optional reference to hash of stored elements to be set. 1708: # 1709: # If the page being displayed is a page which permits modification of 1710: # previously stored data, e.g., the first page in a multi-page submission, 1711: # then if stored is supplied, form elements will be set to the last stored 1712: # values. If user supplied values are also available for the same elements 1713: # these will replace the stored values. 1714: # 1715: # Output: 1716: # 1717: # javascript function - set_form_elements() which sets form elements, 1718: # expects an argument: formname - the name of the form according to 1719: # the DOM, e.g., document.compose 1720: 1721: sub set_form_elements { 1722: my ($elements,$stored) = @_; 1723: my %values; 1724: my $output .= 'function setFormElements(courseForm) { 1725: '; 1726: if (defined($stored)) { 1727: foreach my $name (keys(%{$stored})) { 1728: if (exists($$elements{$name})) { 1729: if (ref($$stored{$name}) eq 'ARRAY') { 1730: $values{$name} = $$stored{$name}; 1731: } else { 1732: @{$values{$name}} = ($$stored{$name}); 1733: } 1734: } 1735: } 1736: } 1737: 1738: foreach my $key (keys(%env)) { 1739: if ($key =~ /^form\.(.+)$/) { 1740: my $name = $1; 1741: if (exists($$elements{$name})) { 1742: @{$values{$name}} = &Apache::loncommon::get_env_multiple($key); 1743: } 1744: } 1745: } 1746: 1747: foreach my $name (keys(%values)) { 1748: for (my $i=0; $i<@{$values{$name}}; $i++) { 1749: $values{$name}[$i] = &HTML::Entities::decode($values{$name}[$i],'<>&"'); 1750: $values{$name}[$i] =~ s/([\r\n\f]+)/\\n/g; 1751: $values{$name}[$i] =~ s/"/\\"/g; 1752: } 1753: if ($$elements{$name} eq 'text') { 1754: my $numvalues = @{$values{$name}}; 1755: if ($numvalues > 1) { 1756: my $valuestring = join('","',@{$values{$name}}); 1757: $output .= qq| 1758: var textvalues = new Array ("$valuestring"); 1759: var total = courseForm.elements['$name'].length; 1760: if (total > $numvalues) { 1761: total = $numvalues; 1762: } 1763: for (var i=0; i<total; i++) { 1764: courseForm.elements['$name']\[i].value = textvalues[i]; 1765: } 1766: |; 1767: } else { 1768: $output .= qq| 1769: courseForm.elements['$name'].value = "$values{$name}[0]"; 1770: |; 1771: } 1772: } else { 1773: $output .= qq| 1774: var elementLength = courseForm.elements['$name'].length; 1775: if (elementLength==undefined) { 1776: |; 1777: foreach my $value (@{$values{$name}}) { 1778: if ($$elements{$name} eq 'selectbox') { 1779: $output .= qq| 1780: if (courseForm.elements['$name'].options[0].value == "$value") { 1781: courseForm.elements['$name'].options[0].selected = true; 1782: }|; 1783: } elsif (($$elements{$name} eq 'radio') || 1784: ($$elements{$name} eq 'checkbox')) { 1785: $output .= qq| 1786: if (courseForm.elements['$name'].value == "$value") { 1787: courseForm.elements['$name'].checked = true; 1788: }|; 1789: } 1790: } 1791: $output .= qq| 1792: } 1793: else { 1794: for (var i=0; i<courseForm.elements['$name'].length; i++) { 1795: |; 1796: if ($$elements{$name} eq 'selectbox') { 1797: $output .= qq| 1798: courseForm.elements['$name'].options[i].selected = false;|; 1799: } elsif (($$elements{$name} eq 'radio') || 1800: ($$elements{$name} eq 'checkbox')) { 1801: $output .= qq| 1802: courseForm.elements['$name']\[i].checked = false;|; 1803: } 1804: $output .= qq| 1805: } 1806: for (var j=0; j<courseForm.elements['$name'].length; j++) { 1807: |; 1808: foreach my $value (@{$values{$name}}) { 1809: if ($$elements{$name} eq 'selectbox') { 1810: $output .= qq| 1811: if (courseForm.elements['$name'].options[j].value == "$value") { 1812: courseForm.elements['$name'].options[j].selected = true; 1813: }|; 1814: } elsif (($$elements{$name} eq 'radio') || 1815: ($$elements{$name} eq 'checkbox')) { 1816: $output .= qq| 1817: if (courseForm.elements['$name']\[j].value == "$value") { 1818: courseForm.elements['$name']\[j].checked = true; 1819: }|; 1820: } 1821: } 1822: $output .= qq| 1823: } 1824: } 1825: |; 1826: } 1827: } 1828: $output .= " 1829: }\n"; 1830: return $output; 1831: } 1832: 1833: 1; 1834: 1835: __END__