Annotation of loncom/interface/loncommon.pm, revision 1.948.2.16
1.10 albertel 1: # The LearningOnline Network with CAPA
1.1 albertel 2: # a pile of common routines
1.10 albertel 3: #
1.948.2.16! raeburn 4: # $Id: loncommon.pm,v 1.948.2.15 2010/12/19 22:59:22 raeburn Exp $
1.10 albertel 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: #
1.1 albertel 28:
29: # Makes a table out of the previous attempts
1.2 albertel 30: # Inputs result_from_symbread, user, domain, course_id
1.16 harris41 31: # Reads in non-network-related .tab files
1.1 albertel 32:
1.35 matthew 33: # POD header:
34:
1.45 matthew 35: =pod
36:
1.35 matthew 37: =head1 NAME
38:
39: Apache::loncommon - pile of common routines
40:
41: =head1 SYNOPSIS
42:
1.112 bowersj2 43: Common routines for manipulating connections, student answers,
44: domains, common Javascript fragments, etc.
1.35 matthew 45:
1.112 bowersj2 46: =head1 OVERVIEW
1.35 matthew 47:
1.112 bowersj2 48: A collection of commonly used subroutines that don't have a natural
49: home anywhere else. This collection helps remove
1.35 matthew 50: redundancy from other modules and increase efficiency of memory usage.
51:
52: =cut
53:
54: # End of POD header
1.1 albertel 55: package Apache::loncommon;
56:
57: use strict;
1.258 albertel 58: use Apache::lonnet;
1.46 matthew 59: use GDBM_File;
1.51 www 60: use POSIX qw(strftime mktime);
1.82 www 61: use Apache::lonmenu();
1.498 albertel 62: use Apache::lonenc();
1.117 www 63: use Apache::lonlocal;
1.685 tempelho 64: use Apache::lonnet();
1.139 matthew 65: use HTML::Entities;
1.334 albertel 66: use Apache::lonhtmlcommon();
67: use Apache::loncoursedata();
1.344 albertel 68: use Apache::lontexconvert();
1.444 albertel 69: use Apache::lonclonecourse();
1.479 albertel 70: use LONCAPA qw(:DEFAULT :match);
1.657 raeburn 71: use DateTime::TimeZone;
1.687 raeburn 72: use DateTime::Locale::Catalog;
1.117 www 73:
1.517 raeburn 74: # ---------------------------------------------- Designs
75: use vars qw(%defaultdesign);
76:
1.22 www 77: my $readit;
78:
1.517 raeburn 79:
1.157 matthew 80: ##
81: ## Global Variables
82: ##
1.46 matthew 83:
1.643 foxr 84:
85: # ----------------------------------------------- SSI with retries:
86: #
87:
88: =pod
89:
1.648 raeburn 90: =head1 Server Side include with retries:
1.643 foxr 91:
92: =over 4
93:
1.648 raeburn 94: =item * &ssi_with_retries(resource,retries form)
1.643 foxr 95:
96: Performs an ssi with some number of retries. Retries continue either
97: until the result is ok or until the retry count supplied by the
98: caller is exhausted.
99:
100: Inputs:
1.648 raeburn 101:
102: =over 4
103:
1.643 foxr 104: resource - Identifies the resource to insert.
1.648 raeburn 105:
1.643 foxr 106: retries - Count of the number of retries allowed.
1.648 raeburn 107:
1.643 foxr 108: form - Hash that identifies the rendering options.
109:
1.648 raeburn 110: =back
111:
112: Returns:
113:
114: =over 4
115:
1.643 foxr 116: content - The content of the response. If retries were exhausted this is empty.
1.648 raeburn 117:
1.643 foxr 118: response - The response from the last attempt (which may or may not have been successful.
119:
1.648 raeburn 120: =back
121:
122: =back
123:
1.643 foxr 124: =cut
125:
126: sub ssi_with_retries {
127: my ($resource, $retries, %form) = @_;
128:
129:
130: my $ok = 0; # True if we got a good response.
131: my $content;
132: my $response;
133:
134: # Try to get the ssi done. within the retries count:
135:
136: do {
137: ($content, $response) = &Apache::lonnet::ssi($resource, %form);
138: $ok = $response->is_success;
1.650 www 139: if (!$ok) {
140: &Apache::lonnet::logthis("Failed ssi_with_retries on $resource: ".$response->is_success.', '.$response->code.', '.$response->message);
141: }
1.643 foxr 142: $retries--;
143: } while (!$ok && ($retries > 0));
144:
145: if (!$ok) {
146: $content = ''; # On error return an empty content.
147: }
148: return ($content, $response);
149:
150: }
151:
152:
153:
1.20 www 154: # ----------------------------------------------- Filetypes/Languages/Copyright
1.12 harris41 155: my %language;
1.124 www 156: my %supported_language;
1.12 harris41 157: my %cprtag;
1.192 taceyjo1 158: my %scprtag;
1.351 www 159: my %fe; my %fd; my %fm;
1.41 ng 160: my %category_extensions;
1.12 harris41 161:
1.46 matthew 162: # ---------------------------------------------- Thesaurus variables
1.144 matthew 163: #
164: # %Keywords:
165: # A hash used by &keyword to determine if a word is considered a keyword.
166: # $thesaurus_db_file
167: # Scalar containing the full path to the thesaurus database.
1.46 matthew 168:
169: my %Keywords;
170: my $thesaurus_db_file;
171:
1.144 matthew 172: #
173: # Initialize values from language.tab, copyright.tab, filetypes.tab,
174: # thesaurus.tab, and filecategories.tab.
175: #
1.18 www 176: BEGIN {
1.46 matthew 177: # Variable initialization
178: $thesaurus_db_file = $Apache::lonnet::perlvar{'lonTabDir'}."/thesaurus.db";
179: #
1.22 www 180: unless ($readit) {
1.12 harris41 181: # ------------------------------------------------------------------- languages
182: {
1.158 raeburn 183: my $langtabfile = $Apache::lonnet::perlvar{'lonTabDir'}.
184: '/language.tab';
185: if ( open(my $fh,"<$langtabfile") ) {
1.356 albertel 186: while (my $line = <$fh>) {
187: next if ($line=~/^\#/);
188: chomp($line);
189: my ($key,$two,$country,$three,$enc,$val,$sup)=(split(/\t/,$line));
1.158 raeburn 190: $language{$key}=$val.' - '.$enc;
191: if ($sup) {
192: $supported_language{$key}=$sup;
193: }
194: }
195: close($fh);
196: }
1.12 harris41 197: }
198: # ------------------------------------------------------------------ copyrights
199: {
1.158 raeburn 200: my $copyrightfile = $Apache::lonnet::perlvar{'lonIncludes'}.
201: '/copyright.tab';
202: if ( open (my $fh,"<$copyrightfile") ) {
1.356 albertel 203: while (my $line = <$fh>) {
204: next if ($line=~/^\#/);
205: chomp($line);
206: my ($key,$val)=(split(/\s+/,$line,2));
1.158 raeburn 207: $cprtag{$key}=$val;
208: }
209: close($fh);
210: }
1.12 harris41 211: }
1.351 www 212: # ----------------------------------------------------------- source copyrights
1.192 taceyjo1 213: {
214: my $sourcecopyrightfile = $Apache::lonnet::perlvar{'lonIncludes'}.
215: '/source_copyright.tab';
216: if ( open (my $fh,"<$sourcecopyrightfile") ) {
1.356 albertel 217: while (my $line = <$fh>) {
218: next if ($line =~ /^\#/);
219: chomp($line);
220: my ($key,$val)=(split(/\s+/,$line,2));
1.192 taceyjo1 221: $scprtag{$key}=$val;
222: }
223: close($fh);
224: }
225: }
1.63 www 226:
1.517 raeburn 227: # -------------------------------------------------------------- default domain designs
1.63 www 228: my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors';
1.517 raeburn 229: my $designfile = $designdir.'/default.tab';
230: if ( open (my $fh,"<$designfile") ) {
231: while (my $line = <$fh>) {
232: next if ($line =~ /^\#/);
233: chomp($line);
234: my ($key,$val)=(split(/\=/,$line));
235: if ($val) { $defaultdesign{$key}=$val; }
236: }
237: close($fh);
1.63 www 238: }
239:
1.15 harris41 240: # ------------------------------------------------------------- file categories
241: {
1.158 raeburn 242: my $categoryfile = $Apache::lonnet::perlvar{'lonTabDir'}.
243: '/filecategories.tab';
244: if ( open (my $fh,"<$categoryfile") ) {
1.356 albertel 245: while (my $line = <$fh>) {
246: next if ($line =~ /^\#/);
247: chomp($line);
248: my ($extension,$category)=(split(/\s+/,$line,2));
1.158 raeburn 249: push @{$category_extensions{lc($category)}},$extension;
250: }
251: close($fh);
252: }
253:
1.15 harris41 254: }
1.12 harris41 255: # ------------------------------------------------------------------ file types
256: {
1.158 raeburn 257: my $typesfile = $Apache::lonnet::perlvar{'lonTabDir'}.
258: '/filetypes.tab';
259: if ( open (my $fh,"<$typesfile") ) {
1.356 albertel 260: while (my $line = <$fh>) {
261: next if ($line =~ /^\#/);
262: chomp($line);
263: my ($ending,$emb,$mime,$descr)=split(/\s+/,$line,4);
1.158 raeburn 264: if ($descr ne '') {
265: $fe{$ending}=lc($emb);
266: $fd{$ending}=$descr;
1.351 www 267: if ($mime ne 'unk') { $fm{$ending}=$mime; }
1.158 raeburn 268: }
269: }
270: close($fh);
271: }
1.12 harris41 272: }
1.22 www 273: &Apache::lonnet::logthis(
1.705 tempelho 274: "<span style='color:yellow;'>INFO: Read file types</span>");
1.22 www 275: $readit=1;
1.46 matthew 276: } # end of unless($readit)
1.32 matthew 277:
278: }
1.112 bowersj2 279:
1.42 matthew 280: ###############################################################
281: ## HTML and Javascript Helper Functions ##
282: ###############################################################
283:
284: =pod
285:
1.112 bowersj2 286: =head1 HTML and Javascript Functions
1.42 matthew 287:
1.112 bowersj2 288: =over 4
289:
1.648 raeburn 290: =item * &browser_and_searcher_javascript()
1.112 bowersj2 291:
292: X<browsing, javascript>X<searching, javascript>Returns a string
293: containing javascript with two functions, C<openbrowser> and
294: C<opensearcher>. Returned string does not contain E<lt>scriptE<gt>
295: tags.
1.42 matthew 296:
1.648 raeburn 297: =item * &openbrowser(formname,elementname,only,omit) [javascript]
1.42 matthew 298:
299: inputs: formname, elementname, only, omit
300:
301: formname and elementname indicate the name of the html form and name of
302: the element that the results of the browsing selection are to be placed in.
303:
304: Specifying 'only' will restrict the browser to displaying only files
1.185 www 305: with the given extension. Can be a comma separated list.
1.42 matthew 306:
307: Specifying 'omit' will restrict the browser to NOT displaying files
1.185 www 308: with the given extension. Can be a comma separated list.
1.42 matthew 309:
1.648 raeburn 310: =item * &opensearcher(formname,elementname) [javascript]
1.42 matthew 311:
312: Inputs: formname, elementname
313:
314: formname and elementname specify the name of the html form and the name
315: of the element the selection from the search results will be placed in.
1.542 raeburn 316:
1.42 matthew 317: =cut
318:
319: sub browser_and_searcher_javascript {
1.199 albertel 320: my ($mode)=@_;
321: if (!defined($mode)) { $mode='edit'; }
1.453 albertel 322: my $resurl=&escape_single(&lastresurl());
1.42 matthew 323: return <<END;
1.219 albertel 324: // <!-- BEGIN LON-CAPA Internal
1.50 matthew 325: var editbrowser = null;
1.135 albertel 326: function openbrowser(formname,elementname,only,omit,titleelement) {
1.170 www 327: var url = '$resurl/?';
1.42 matthew 328: if (editbrowser == null) {
329: url += 'launch=1&';
330: }
331: url += 'catalogmode=interactive&';
1.199 albertel 332: url += 'mode=$mode&';
1.611 albertel 333: url += 'inhibitmenu=yes&';
1.42 matthew 334: url += 'form=' + formname + '&';
335: if (only != null) {
336: url += 'only=' + only + '&';
1.217 albertel 337: } else {
338: url += 'only=&';
339: }
1.42 matthew 340: if (omit != null) {
341: url += 'omit=' + omit + '&';
1.217 albertel 342: } else {
343: url += 'omit=&';
344: }
1.135 albertel 345: if (titleelement != null) {
346: url += 'titleelement=' + titleelement + '&';
1.217 albertel 347: } else {
348: url += 'titleelement=&';
349: }
1.42 matthew 350: url += 'element=' + elementname + '';
351: var title = 'Browser';
1.435 albertel 352: var options = 'scrollbars=1,resizable=1,menubar=0,toolbar=1,location=1';
1.42 matthew 353: options += ',width=700,height=600';
354: editbrowser = open(url,title,options,'1');
355: editbrowser.focus();
356: }
357: var editsearcher;
1.135 albertel 358: function opensearcher(formname,elementname,titleelement) {
1.42 matthew 359: var url = '/adm/searchcat?';
360: if (editsearcher == null) {
361: url += 'launch=1&';
362: }
363: url += 'catalogmode=interactive&';
1.199 albertel 364: url += 'mode=$mode&';
1.42 matthew 365: url += 'form=' + formname + '&';
1.135 albertel 366: if (titleelement != null) {
367: url += 'titleelement=' + titleelement + '&';
1.217 albertel 368: } else {
369: url += 'titleelement=&';
370: }
1.42 matthew 371: url += 'element=' + elementname + '';
372: var title = 'Search';
1.435 albertel 373: var options = 'scrollbars=1,resizable=1,menubar=0,toolbar=1,location=1';
1.42 matthew 374: options += ',width=700,height=600';
375: editsearcher = open(url,title,options,'1');
376: editsearcher.focus();
377: }
1.219 albertel 378: // END LON-CAPA Internal -->
1.42 matthew 379: END
1.170 www 380: }
381:
382: sub lastresurl {
1.258 albertel 383: if ($env{'environment.lastresurl'}) {
384: return $env{'environment.lastresurl'}
1.170 www 385: } else {
386: return '/res';
387: }
388: }
389:
390: sub storeresurl {
391: my $resurl=&Apache::lonnet::clutter(shift);
392: unless ($resurl=~/^\/res/) { return 0; }
393: $resurl=~s/\/$//;
394: &Apache::lonnet::put('environment',{'lastresurl' => $resurl});
1.646 raeburn 395: &Apache::lonnet::appenv({'environment.lastresurl' => $resurl});
1.170 www 396: return 1;
1.42 matthew 397: }
398:
1.74 www 399: sub studentbrowser_javascript {
1.111 www 400: unless (
1.258 albertel 401: (($env{'request.course.id'}) &&
1.302 albertel 402: (&Apache::lonnet::allowed('srm',$env{'request.course.id'})
403: || &Apache::lonnet::allowed('srm',$env{'request.course.id'}.
404: '/'.$env{'request.course.sec'})
405: ))
1.258 albertel 406: || ($env{'request.role'}=~/^(au|dc|su)/)
1.111 www 407: ) { return ''; }
1.74 www 408: return (<<'ENDSTDBRW');
1.776 bisitz 409: <script type="text/javascript" language="Javascript">
1.824 bisitz 410: // <![CDATA[
1.74 www 411: var stdeditbrowser;
1.793 raeburn 412: function openstdbrowser(formname,uname,udom,roleflag,ignorefilter,courseadvonly) {
1.74 www 413: var url = '/adm/pickstudent?';
414: var filter;
1.558 albertel 415: if (!ignorefilter) {
416: eval('filter=document.'+formname+'.'+uname+'.value;');
417: }
1.74 www 418: if (filter != null) {
419: if (filter != '') {
420: url += 'filter='+filter+'&';
421: }
422: }
423: url += 'form=' + formname + '&unameelement='+uname+
424: '&udomelement='+udom;
1.111 www 425: if (roleflag) { url+="&roles=1"; }
1.793 raeburn 426: if (courseadvonly) { url+="&courseadvonly=1"; }
1.102 www 427: var title = 'Student_Browser';
1.74 www 428: var options = 'scrollbars=1,resizable=1,menubar=0';
429: options += ',width=700,height=600';
430: stdeditbrowser = open(url,title,options,'1');
431: stdeditbrowser.focus();
432: }
1.824 bisitz 433: // ]]>
1.74 www 434: </script>
435: ENDSTDBRW
436: }
1.42 matthew 437:
1.74 www 438: sub selectstudent_link {
1.793 raeburn 439: my ($form,$unameele,$udomele,$courseadvonly)=@_;
440: my $callargs = "'".$form."','".$unameele."','".$udomele."'";
1.258 albertel 441: if ($env{'request.course.id'}) {
1.302 albertel 442: if (!&Apache::lonnet::allowed('srm',$env{'request.course.id'})
443: && !&Apache::lonnet::allowed('srm',$env{'request.course.id'}.
444: '/'.$env{'request.course.sec'})) {
1.111 www 445: return '';
446: }
1.793 raeburn 447: if ($courseadvonly) {
448: $callargs .= ",'',1,1";
449: }
450: return '<span class="LC_nobreak">'.
451: '<a href="javascript:openstdbrowser('.$callargs.');">'.
452: &mt('Select User').'</a></span>';
1.74 www 453: }
1.258 albertel 454: if ($env{'request.role'}=~/^(au|dc|su)/) {
1.793 raeburn 455: $callargs .= ",1";
456: return '<span class="LC_nobreak">'.
457: '<a href="javascript:openstdbrowser('.$callargs.');">'.
458: &mt('Select User').'</a></span>';
1.111 www 459: }
460: return '';
1.91 www 461: }
462:
1.653 raeburn 463: sub authorbrowser_javascript {
464: return <<"ENDAUTHORBRW";
1.776 bisitz 465: <script type="text/javascript" language="JavaScript">
1.824 bisitz 466: // <![CDATA[
1.653 raeburn 467: var stdeditbrowser;
468:
469: function openauthorbrowser(formname,udom) {
470: var url = '/adm/pickauthor?';
471: url += 'form='+formname+'&roledom='+udom;
472: var title = 'Author_Browser';
473: var options = 'scrollbars=1,resizable=1,menubar=0';
474: options += ',width=700,height=600';
475: stdeditbrowser = open(url,title,options,'1');
476: stdeditbrowser.focus();
477: }
478:
1.824 bisitz 479: // ]]>
1.653 raeburn 480: </script>
481: ENDAUTHORBRW
482: }
483:
1.91 www 484: sub coursebrowser_javascript {
1.909 raeburn 485: my ($domainfilter,$sec_element,$formname,$role_element,$crstype) = @_;
1.932 raeburn 486: my $wintitle = 'Course_Browser';
1.931 raeburn 487: if ($crstype eq 'Community') {
1.932 raeburn 488: $wintitle = 'Community_Browser';
1.909 raeburn 489: }
1.876 raeburn 490: my $id_functions = &javascript_index_functions();
491: my $output = '
1.776 bisitz 492: <script type="text/javascript" language="JavaScript">
1.824 bisitz 493: // <![CDATA[
1.468 raeburn 494: var stdeditbrowser;'."\n";
1.876 raeburn 495:
496: $output .= <<"ENDSTDBRW";
1.909 raeburn 497: function opencrsbrowser(formname,uname,udom,desc,extra_element,multflag,type,type_elem) {
1.91 www 498: var url = '/adm/pickcourse?';
1.895 raeburn 499: var formid = getFormIdByName(formname);
1.876 raeburn 500: var domainfilter = getDomainFromSelectbox(formname,udom);
1.128 albertel 501: if (domainfilter != null) {
502: if (domainfilter != '') {
503: url += 'domainfilter='+domainfilter+'&';
504: }
505: }
1.91 www 506: url += 'form=' + formname + '&cnumelement='+uname+
1.187 albertel 507: '&cdomelement='+udom+
508: '&cnameelement='+desc;
1.468 raeburn 509: if (extra_element !=null && extra_element != '') {
1.594 raeburn 510: if (formname == 'rolechoice' || formname == 'studentform') {
1.468 raeburn 511: url += '&roleelement='+extra_element;
512: if (domainfilter == null || domainfilter == '') {
513: url += '&domainfilter='+extra_element;
514: }
1.234 raeburn 515: }
1.468 raeburn 516: else {
517: if (formname == 'portform') {
518: url += '&setroles='+extra_element;
1.800 raeburn 519: } else {
520: if (formname == 'rules') {
521: url += '&fixeddom='+extra_element;
522: }
1.468 raeburn 523: }
524: }
1.230 raeburn 525: }
1.909 raeburn 526: if (type != null && type != '') {
527: url += '&type='+type;
528: }
529: if (type_elem != null && type_elem != '') {
530: url += '&typeelement='+type_elem;
531: }
1.872 raeburn 532: if (formname == 'ccrs') {
533: var ownername = document.forms[formid].ccuname.value;
534: var ownerdom = document.forms[formid].ccdomain.options[document.forms[formid].ccdomain.selectedIndex].value;
535: url += '&cloner='+ownername+':'+ownerdom;
536: }
1.293 raeburn 537: if (multflag !=null && multflag != '') {
538: url += '&multiple='+multflag;
539: }
1.909 raeburn 540: var title = '$wintitle';
1.91 www 541: var options = 'scrollbars=1,resizable=1,menubar=0';
542: options += ',width=700,height=600';
543: stdeditbrowser = open(url,title,options,'1');
544: stdeditbrowser.focus();
545: }
1.876 raeburn 546: $id_functions
547: ENDSTDBRW
1.905 raeburn 548: if (($sec_element ne '') || ($role_element ne '')) {
549: $output .= &setsec_javascript($sec_element,$formname,$role_element);
1.876 raeburn 550: }
551: $output .= '
552: // ]]>
553: </script>';
554: return $output;
555: }
556:
557: sub javascript_index_functions {
558: return <<"ENDJS";
559:
560: function getFormIdByName(formname) {
561: for (var i=0;i<document.forms.length;i++) {
562: if (document.forms[i].name == formname) {
563: return i;
564: }
565: }
566: return -1;
567: }
568:
569: function getIndexByName(formid,item) {
570: for (var i=0;i<document.forms[formid].elements.length;i++) {
571: if (document.forms[formid].elements[i].name == item) {
572: return i;
573: }
574: }
575: return -1;
576: }
1.468 raeburn 577:
1.876 raeburn 578: function getDomainFromSelectbox(formname,udom) {
579: var userdom;
580: var formid = getFormIdByName(formname);
581: if (formid > -1) {
582: var domid = getIndexByName(formid,udom);
583: if (domid > -1) {
584: if (document.forms[formid].elements[domid].type == 'select-one') {
585: userdom=document.forms[formid].elements[domid].options[document.forms[formid].elements[domid].selectedIndex].value;
586: }
587: if (document.forms[formid].elements[domid].type == 'hidden') {
588: userdom=document.forms[formid].elements[domid].value;
1.468 raeburn 589: }
590: }
591: }
1.876 raeburn 592: return userdom;
593: }
594:
595: ENDJS
1.468 raeburn 596:
1.876 raeburn 597: }
598:
599: sub userbrowser_javascript {
600: my $id_functions = &javascript_index_functions();
601: return <<"ENDUSERBRW";
602:
1.888 raeburn 603: function openuserbrowser(formname,uname,udom,ulast,ufirst,uemail,hideudom,crsdom,caller) {
1.876 raeburn 604: var url = '/adm/pickuser?';
605: var userdom = getDomainFromSelectbox(formname,udom);
606: if (userdom != null) {
607: if (userdom != '') {
608: url += 'srchdom='+userdom+'&';
609: }
610: }
611: url += 'form=' + formname + '&unameelement='+uname+
612: '&udomelement='+udom+
613: '&ulastelement='+ulast+
614: '&ufirstelement='+ufirst+
615: '&uemailelement='+uemail+
1.881 raeburn 616: '&hideudomelement='+hideudom+
617: '&coursedom='+crsdom;
1.888 raeburn 618: if ((caller != null) && (caller != undefined)) {
619: url += '&caller='+caller;
620: }
1.876 raeburn 621: var title = 'User_Browser';
622: var options = 'scrollbars=1,resizable=1,menubar=0';
623: options += ',width=700,height=600';
624: var stdeditbrowser = open(url,title,options,'1');
625: stdeditbrowser.focus();
626: }
627:
1.888 raeburn 628: function fix_domain (formname,udom,origdom,uname) {
1.876 raeburn 629: var formid = getFormIdByName(formname);
630: if (formid > -1) {
1.888 raeburn 631: var unameid = getIndexByName(formid,uname);
1.876 raeburn 632: var domid = getIndexByName(formid,udom);
633: var hidedomid = getIndexByName(formid,origdom);
634: if (hidedomid > -1) {
635: var fixeddom = document.forms[formid].elements[hidedomid].value;
1.888 raeburn 636: var unameval = document.forms[formid].elements[unameid].value;
637: if ((fixeddom != '') && (fixeddom != undefined) && (fixeddom != null) && (unameval != '') && (unameval != undefined) && (unameval != null)) {
638: if (domid > -1) {
639: var slct = document.forms[formid].elements[domid];
640: if (slct.type == 'select-one') {
641: var i;
642: for (i=0;i<slct.length;i++) {
643: if (slct.options[i].value==fixeddom) { slct.selectedIndex=i; }
644: }
645: }
646: if (slct.type == 'hidden') {
647: slct.value = fixeddom;
1.876 raeburn 648: }
649: }
1.468 raeburn 650: }
651: }
652: }
1.876 raeburn 653: return;
654: }
655:
656: $id_functions
657: ENDUSERBRW
1.468 raeburn 658: }
659:
660: sub setsec_javascript {
1.905 raeburn 661: my ($sec_element,$formname,$role_element) = @_;
662: my (@courserolenames,@communityrolenames,$rolestr,$courserolestr,
663: $communityrolestr);
664: if ($role_element ne '') {
665: my @allroles = ('st','ta','ep','in','ad');
666: foreach my $crstype ('Course','Community') {
667: if ($crstype eq 'Community') {
668: foreach my $role (@allroles) {
669: push(@communityrolenames,&Apache::lonnet::plaintext($role,$crstype));
670: }
671: push(@communityrolenames,&Apache::lonnet::plaintext('co'));
672: } else {
673: foreach my $role (@allroles) {
674: push(@courserolenames,&Apache::lonnet::plaintext($role,$crstype));
675: }
676: push(@courserolenames,&Apache::lonnet::plaintext('cc'));
677: }
678: }
679: $rolestr = '"'.join('","',@allroles).'"';
680: $courserolestr = '"'.join('","',@courserolenames).'"';
681: $communityrolestr = '"'.join('","',@communityrolenames).'"';
682: }
1.468 raeburn 683: my $setsections = qq|
684: function setSect(sectionlist) {
1.629 raeburn 685: var sectionsArray = new Array();
686: if ((sectionlist != '') && (typeof sectionlist != "undefined")) {
687: sectionsArray = sectionlist.split(",");
688: }
1.468 raeburn 689: var numSections = sectionsArray.length;
690: document.$formname.$sec_element.length = 0;
691: if (numSections == 0) {
692: document.$formname.$sec_element.multiple=false;
693: document.$formname.$sec_element.size=1;
694: document.$formname.$sec_element.options[0] = new Option('No existing sections','',false,false)
695: } else {
696: if (numSections == 1) {
697: document.$formname.$sec_element.multiple=false;
698: document.$formname.$sec_element.size=1;
699: document.$formname.$sec_element.options[0] = new Option('Select','',true,true);
700: document.$formname.$sec_element.options[1] = new Option('No section','',false,false)
701: document.$formname.$sec_element.options[2] = new Option(sectionsArray[0],sectionsArray[0],false,false);
702: } else {
703: for (var i=0; i<numSections; i++) {
704: document.$formname.$sec_element.options[i] = new Option(sectionsArray[i],sectionsArray[i],false,false)
705: }
706: document.$formname.$sec_element.multiple=true
707: if (numSections < 3) {
708: document.$formname.$sec_element.size=numSections;
709: } else {
710: document.$formname.$sec_element.size=3;
711: }
712: document.$formname.$sec_element.options[0].selected = false
713: }
714: }
1.91 www 715: }
1.905 raeburn 716:
717: function setRole(crstype) {
1.468 raeburn 718: |;
1.905 raeburn 719: if ($role_element eq '') {
720: $setsections .= ' return;
721: }
722: ';
723: } else {
724: $setsections .= qq|
725: var elementLength = document.$formname.$role_element.length;
726: var allroles = Array($rolestr);
727: var courserolenames = Array($courserolestr);
728: var communityrolenames = Array($communityrolestr);
729: if (elementLength != undefined) {
730: if (document.$formname.$role_element.options[5].value == 'cc') {
731: if (crstype == 'Course') {
732: return;
733: } else {
734: allroles[5] = 'co';
735: for (var i=0; i<6; i++) {
736: document.$formname.$role_element.options[i].value = allroles[i];
737: document.$formname.$role_element.options[i].text = communityrolenames[i];
738: }
739: }
740: } else {
741: if (crstype == 'Community') {
742: return;
743: } else {
744: allroles[5] = 'cc';
745: for (var i=0; i<6; i++) {
746: document.$formname.$role_element.options[i].value = allroles[i];
747: document.$formname.$role_element.options[i].text = courserolenames[i];
748: }
749: }
750: }
751: }
752: return;
753: }
754: |;
755: }
1.468 raeburn 756: return $setsections;
757: }
758:
1.91 www 759: sub selectcourse_link {
1.909 raeburn 760: my ($form,$unameele,$udomele,$desc,$extra_element,$multflag,$selecttype,
761: $typeelement) = @_;
762: my $type = $selecttype;
1.871 raeburn 763: my $linktext = &mt('Select Course');
764: if ($selecttype eq 'Community') {
1.909 raeburn 765: $linktext = &mt('Select Community');
1.906 raeburn 766: } elsif ($selecttype eq 'Course/Community') {
767: $linktext = &mt('Select Course/Community');
1.909 raeburn 768: $type = '';
1.871 raeburn 769: }
1.787 bisitz 770: return '<span class="LC_nobreak">'
771: ."<a href='"
772: .'javascript:opencrsbrowser("'.$form.'","'.$unameele
773: .'","'.$udomele.'","'.$desc.'","'.$extra_element
1.909 raeburn 774: .'","'.$multflag.'","'.$type.'","'.$typeelement.'");'
1.871 raeburn 775: ."'>".$linktext.'</a>'
1.787 bisitz 776: .'</span>';
1.74 www 777: }
1.42 matthew 778:
1.653 raeburn 779: sub selectauthor_link {
780: my ($form,$udom)=@_;
781: return '<a href="javascript:openauthorbrowser('."'$form','$udom'".');">'.
782: &mt('Select Author').'</a>';
783: }
784:
1.876 raeburn 785: sub selectuser_link {
1.881 raeburn 786: my ($form,$unameelem,$domelem,$lastelem,$firstelem,$emailelem,$hdomelem,
1.888 raeburn 787: $coursedom,$linktext,$caller) = @_;
1.876 raeburn 788: return '<a href="javascript:openuserbrowser('."'$form','$unameelem','$domelem',".
1.888 raeburn 789: "'$lastelem','$firstelem','$emailelem','$hdomelem','$coursedom','$caller'".
1.881 raeburn 790: ');">'.$linktext.'</a>';
1.876 raeburn 791: }
792:
1.273 raeburn 793: sub check_uncheck_jscript {
794: my $jscript = <<"ENDSCRT";
795: function checkAll(field) {
796: if (field.length > 0) {
797: for (i = 0; i < field.length; i++) {
798: field[i].checked = true ;
799: }
800: } else {
801: field.checked = true
802: }
803: }
804:
805: function uncheckAll(field) {
806: if (field.length > 0) {
807: for (i = 0; i < field.length; i++) {
808: field[i].checked = false ;
1.543 albertel 809: }
810: } else {
1.273 raeburn 811: field.checked = false ;
812: }
813: }
814: ENDSCRT
815: return $jscript;
816: }
817:
1.656 www 818: sub select_timezone {
1.659 raeburn 819: my ($name,$selected,$onchange,$includeempty)=@_;
820: my $output='<select name="'.$name.'" '.$onchange.'>'."\n";
821: if ($includeempty) {
822: $output .= '<option value=""';
823: if (($selected eq '') || ($selected eq 'local')) {
824: $output .= ' selected="selected" ';
825: }
826: $output .= '> </option>';
827: }
1.657 raeburn 828: my @timezones = DateTime::TimeZone->all_names;
829: foreach my $tzone (@timezones) {
830: $output.= '<option value="'.$tzone.'"';
831: if ($tzone eq $selected) {
832: $output.=' selected="selected"';
833: }
834: $output.=">$tzone</option>\n";
1.656 www 835: }
836: $output.="</select>";
837: return $output;
838: }
1.273 raeburn 839:
1.687 raeburn 840: sub select_datelocale {
841: my ($name,$selected,$onchange,$includeempty)=@_;
842: my $output='<select name="'.$name.'" '.$onchange.'>'."\n";
843: if ($includeempty) {
844: $output .= '<option value=""';
845: if ($selected eq '') {
846: $output .= ' selected="selected" ';
847: }
848: $output .= '> </option>';
849: }
850: my (@possibles,%locale_names);
851: my @locales = DateTime::Locale::Catalog::Locales;
852: foreach my $locale (@locales) {
853: if (ref($locale) eq 'HASH') {
854: my $id = $locale->{'id'};
855: if ($id ne '') {
856: my $en_terr = $locale->{'en_territory'};
857: my $native_terr = $locale->{'native_territory'};
1.695 raeburn 858: my @languages = &Apache::lonlocal::preferred_languages();
1.687 raeburn 859: if (grep(/^en$/,@languages) || !@languages) {
860: if ($en_terr ne '') {
861: $locale_names{$id} = '('.$en_terr.')';
862: } elsif ($native_terr ne '') {
863: $locale_names{$id} = $native_terr;
864: }
865: } else {
866: if ($native_terr ne '') {
867: $locale_names{$id} = $native_terr.' ';
868: } elsif ($en_terr ne '') {
869: $locale_names{$id} = '('.$en_terr.')';
870: }
871: }
872: push (@possibles,$id);
873: }
874: }
875: }
876: foreach my $item (sort(@possibles)) {
877: $output.= '<option value="'.$item.'"';
878: if ($item eq $selected) {
879: $output.=' selected="selected"';
880: }
881: $output.=">$item";
882: if ($locale_names{$item} ne '') {
883: $output.=" $locale_names{$item}</option>\n";
884: }
885: $output.="</option>\n";
886: }
887: $output.="</select>";
888: return $output;
889: }
890:
1.792 raeburn 891: sub select_language {
892: my ($name,$selected,$includeempty) = @_;
893: my %langchoices;
894: if ($includeempty) {
895: %langchoices = ('' => 'No language preference');
896: }
897: foreach my $id (&languageids()) {
898: my $code = &supportedlanguagecode($id);
899: if ($code) {
900: $langchoices{$code} = &plainlanguagedescription($id);
901: }
902: }
1.948.2.7 raeburn 903: return &select_form($selected,$name,\%langchoices);
1.792 raeburn 904: }
905:
1.42 matthew 906: =pod
1.36 matthew 907:
1.648 raeburn 908: =item * &linked_select_forms(...)
1.36 matthew 909:
910: linked_select_forms returns a string containing a <script></script> block
911: and html for two <select> menus. The select menus will be linked in that
912: changing the value of the first menu will result in new values being placed
913: in the second menu. The values in the select menu will appear in alphabetical
1.609 raeburn 914: order unless a defined order is provided.
1.36 matthew 915:
916: linked_select_forms takes the following ordered inputs:
917:
918: =over 4
919:
1.112 bowersj2 920: =item * $formname, the name of the <form> tag
1.36 matthew 921:
1.112 bowersj2 922: =item * $middletext, the text which appears between the <select> tags
1.36 matthew 923:
1.112 bowersj2 924: =item * $firstdefault, the default value for the first menu
1.36 matthew 925:
1.112 bowersj2 926: =item * $firstselectname, the name of the first <select> tag
1.36 matthew 927:
1.112 bowersj2 928: =item * $secondselectname, the name of the second <select> tag
1.36 matthew 929:
1.112 bowersj2 930: =item * $hashref, a reference to a hash containing the data for the menus.
1.36 matthew 931:
1.609 raeburn 932: =item * $menuorder, the order of values in the first menu
933:
1.41 ng 934: =back
935:
1.36 matthew 936: Below is an example of such a hash. Only the 'text', 'default', and
937: 'select2' keys must appear as stated. keys(%menu) are the possible
938: values for the first select menu. The text that coincides with the
1.41 ng 939: first menu value is given in $menu{$choice1}->{'text'}. The values
1.36 matthew 940: and text for the second menu are given in the hash pointed to by
941: $menu{$choice1}->{'select2'}.
942:
1.112 bowersj2 943: my %menu = ( A1 => { text =>"Choice A1" ,
944: default => "B3",
945: select2 => {
946: B1 => "Choice B1",
947: B2 => "Choice B2",
948: B3 => "Choice B3",
949: B4 => "Choice B4"
1.609 raeburn 950: },
951: order => ['B4','B3','B1','B2'],
1.112 bowersj2 952: },
953: A2 => { text =>"Choice A2" ,
954: default => "C2",
955: select2 => {
956: C1 => "Choice C1",
957: C2 => "Choice C2",
958: C3 => "Choice C3"
1.609 raeburn 959: },
960: order => ['C2','C1','C3'],
1.112 bowersj2 961: },
962: A3 => { text =>"Choice A3" ,
963: default => "D6",
964: select2 => {
965: D1 => "Choice D1",
966: D2 => "Choice D2",
967: D3 => "Choice D3",
968: D4 => "Choice D4",
969: D5 => "Choice D5",
970: D6 => "Choice D6",
971: D7 => "Choice D7"
1.609 raeburn 972: },
973: order => ['D4','D3','D2','D1','D7','D6','D5'],
1.112 bowersj2 974: }
975: );
1.36 matthew 976:
977: =cut
978:
979: sub linked_select_forms {
980: my ($formname,
981: $middletext,
982: $firstdefault,
983: $firstselectname,
984: $secondselectname,
1.609 raeburn 985: $hashref,
986: $menuorder,
1.36 matthew 987: ) = @_;
988: my $second = "document.$formname.$secondselectname";
989: my $first = "document.$formname.$firstselectname";
990: # output the javascript to do the changing
991: my $result = '';
1.776 bisitz 992: $result.='<script type="text/javascript" language="JavaScript">'."\n";
1.824 bisitz 993: $result.="// <![CDATA[\n";
1.36 matthew 994: $result.="var select2data = new Object();\n";
995: $" = '","';
996: my $debug = '';
997: foreach my $s1 (sort(keys(%$hashref))) {
998: $result.="select2data.d_$s1 = new Object();\n";
999: $result.="select2data.d_$s1.def = new String('".
1000: $hashref->{$s1}->{'default'}."');\n";
1.609 raeburn 1001: $result.="select2data.d_$s1.values = new Array(";
1.36 matthew 1002: my @s2values = sort(keys( %{ $hashref->{$s1}->{'select2'} } ));
1.609 raeburn 1003: if (ref($hashref->{$s1}->{'order'}) eq 'ARRAY') {
1004: @s2values = @{$hashref->{$s1}->{'order'}};
1005: }
1.36 matthew 1006: $result.="\"@s2values\");\n";
1007: $result.="select2data.d_$s1.texts = new Array(";
1008: my @s2texts;
1009: foreach my $value (@s2values) {
1010: push @s2texts, $hashref->{$s1}->{'select2'}->{$value};
1011: }
1012: $result.="\"@s2texts\");\n";
1013: }
1014: $"=' ';
1015: $result.= <<"END";
1016:
1017: function select1_changed() {
1018: // Determine new choice
1019: var newvalue = "d_" + $first.value;
1020: // update select2
1021: var values = select2data[newvalue].values;
1022: var texts = select2data[newvalue].texts;
1023: var select2def = select2data[newvalue].def;
1024: var i;
1025: // out with the old
1026: for (i = 0; i < $second.options.length; i++) {
1027: $second.options[i] = null;
1028: }
1029: // in with the nuclear
1030: for (i=0;i<values.length; i++) {
1031: $second.options[i] = new Option(values[i]);
1.143 matthew 1032: $second.options[i].value = values[i];
1.36 matthew 1033: $second.options[i].text = texts[i];
1034: if (values[i] == select2def) {
1035: $second.options[i].selected = true;
1036: }
1037: }
1038: }
1.824 bisitz 1039: // ]]>
1.36 matthew 1040: </script>
1041: END
1042: # output the initial values for the selection lists
1043: $result .= "<select size=\"1\" name=\"$firstselectname\" onchange=\"select1_changed()\">\n";
1.609 raeburn 1044: my @order = sort(keys(%{$hashref}));
1045: if (ref($menuorder) eq 'ARRAY') {
1046: @order = @{$menuorder};
1047: }
1048: foreach my $value (@order) {
1.36 matthew 1049: $result.=" <option value=\"$value\" ";
1.253 albertel 1050: $result.=" selected=\"selected\" " if ($value eq $firstdefault);
1.119 www 1051: $result.=">".&mt($hashref->{$value}->{'text'})."</option>\n";
1.36 matthew 1052: }
1053: $result .= "</select>\n";
1054: my %select2 = %{$hashref->{$firstdefault}->{'select2'}};
1055: $result .= $middletext;
1056: $result .= "<select size=\"1\" name=\"$secondselectname\">\n";
1057: my $seconddefault = $hashref->{$firstdefault}->{'default'};
1.609 raeburn 1058:
1059: my @secondorder = sort(keys(%select2));
1060: if (ref($hashref->{$firstdefault}->{'order'}) eq 'ARRAY') {
1061: @secondorder = @{$hashref->{$firstdefault}->{'order'}};
1062: }
1063: foreach my $value (@secondorder) {
1.36 matthew 1064: $result.=" <option value=\"$value\" ";
1.253 albertel 1065: $result.=" selected=\"selected\" " if ($value eq $seconddefault);
1.119 www 1066: $result.=">".&mt($select2{$value})."</option>\n";
1.36 matthew 1067: }
1068: $result .= "</select>\n";
1069: # return $debug;
1070: return $result;
1071: } # end of sub linked_select_forms {
1072:
1.45 matthew 1073: =pod
1.44 bowersj2 1074:
1.948.2.7 raeburn 1075: =item * &help_open_topic($topic,$text,$stayOnPage,$width,$height,$imgid)
1.44 bowersj2 1076:
1.112 bowersj2 1077: Returns a string corresponding to an HTML link to the given help
1078: $topic, where $topic corresponds to the name of a .tex file in
1079: /home/httpd/html/adm/help/tex, with underscores replaced by
1080: spaces.
1081:
1082: $text will optionally be linked to the same topic, allowing you to
1083: link text in addition to the graphic. If you do not want to link
1084: text, but wish to specify one of the later parameters, pass an
1085: empty string.
1086:
1087: $stayOnPage is a value that will be interpreted as a boolean. If true,
1088: the link will not open a new window. If false, the link will open
1089: a new window using Javascript. (Default is false.)
1090:
1091: $width and $height are optional numerical parameters that will
1092: override the width and height of the popped up window, which may
1093: be useful for certain help topics with big pictures included.
1.44 bowersj2 1094:
1095: =cut
1096:
1097: sub help_open_topic {
1.948.2.7 raeburn 1098: my ($topic, $text, $stayOnPage, $width, $height, $imgid) = @_;
1.48 bowersj2 1099: $text = "" if (not defined $text);
1.44 bowersj2 1100: $stayOnPage = 0 if (not defined $stayOnPage);
1101: $width = 350 if (not defined $width);
1102: $height = 400 if (not defined $height);
1103: my $filename = $topic;
1104: $filename =~ s/ /_/g;
1105:
1.48 bowersj2 1106: my $template = "";
1107: my $link;
1.572 banghart 1108:
1.159 www 1109: $topic=~s/\W/\_/g;
1.44 bowersj2 1110:
1.572 banghart 1111: if (!$stayOnPage) {
1.72 bowersj2 1112: $link = "javascript:void(open('/adm/help/${filename}.hlp', 'Help_for_$topic', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))";
1.572 banghart 1113: } else {
1.48 bowersj2 1114: $link = "/adm/help/${filename}.hlp";
1115: }
1116:
1117: # Add the text
1.755 neumanie 1118: if ($text ne "") {
1.763 bisitz 1119: $template.='<span class="LC_help_open_topic">'
1120: .'<a target="_top" href="'.$link.'">'
1121: .$text.'</a>';
1.48 bowersj2 1122: }
1123:
1.763 bisitz 1124: # (Always) Add the graphic
1.179 matthew 1125: my $title = &mt('Online Help');
1.667 raeburn 1126: my $helpicon=&lonhttpdurl("/adm/help/help.png");
1.948.2.7 raeburn 1127: if ($imgid ne '') {
1128: $imgid = ' id="'.$imgid.'"';
1129: }
1.763 bisitz 1130: $template.=' <a target="_top" href="'.$link.'" title="'.$title.'">'
1131: .'<img src="'.$helpicon.'" border="0"'
1132: .' alt="'.&mt('Help: [_1]',$topic).'"'
1.948.2.7 raeburn 1133: .' title="'.$title.'" style="vertical-align:middle;"'.$imgid
1.763 bisitz 1134: .' /></a>';
1.948.2.7 raeburn 1135: if ($text ne "") {
1.763 bisitz 1136: $template.='</span>';
1137: }
1.44 bowersj2 1138: return $template;
1139:
1.106 bowersj2 1140: }
1141:
1142: # This is a quicky function for Latex cheatsheet editing, since it
1143: # appears in at least four places
1144: sub helpLatexCheatsheet {
1.732 raeburn 1145: my ($topic,$text,$not_author) = @_;
1146: my $out;
1.106 bowersj2 1147: my $addOther = '';
1.732 raeburn 1148: if ($topic) {
1.763 bisitz 1149: $addOther = '<span>'.&Apache::loncommon::help_open_topic($topic,&mt($text),
1150: undef, undef, 600).
1151: '</span> ';
1152: }
1153: $out = '<span>' # Start cheatsheet
1154: .$addOther
1155: .'<span>'
1156: .&Apache::loncommon::help_open_topic('Greek_Symbols',&mt('Greek Symbols'),
1157: undef,undef,600)
1158: .'</span> <span>'
1159: .&Apache::loncommon::help_open_topic('Other_Symbols',&mt('Other Symbols'),
1160: undef,undef,600)
1161: .'</span>';
1.732 raeburn 1162: unless ($not_author) {
1.763 bisitz 1163: $out .= ' <span>'
1164: .&Apache::loncommon::help_open_topic('Authoring_Output_Tags',&mt('Output Tags'),
1165: undef,undef,600)
1166: .'</span>';
1.732 raeburn 1167: }
1.763 bisitz 1168: $out .= '</span>'; # End cheatsheet
1.732 raeburn 1169: return $out;
1.172 www 1170: }
1171:
1.430 albertel 1172: sub general_help {
1173: my $helptopic='Student_Intro';
1174: if ($env{'request.role'}=~/^(ca|au)/) {
1175: $helptopic='Authoring_Intro';
1.907 raeburn 1176: } elsif ($env{'request.role'}=~/^(cc|co)/) {
1.430 albertel 1177: $helptopic='Course_Coordination_Intro';
1.672 raeburn 1178: } elsif ($env{'request.role'}=~/^dc/) {
1179: $helptopic='Domain_Coordination_Intro';
1.430 albertel 1180: }
1181: return $helptopic;
1182: }
1183:
1184: sub update_help_link {
1185: my ($topic,$component_help,$faq,$bug,$stayOnPage) = @_;
1186: my $origurl = $ENV{'REQUEST_URI'};
1187: $origurl=~s|^/~|/priv/|;
1188: my $timestamp = time;
1189: foreach my $datum (\$topic,\$component_help,\$faq,\$bug,\$origurl) {
1190: $$datum = &escape($$datum);
1191: }
1192:
1193: my $banner_link = "/adm/helpmenu?page=banner&topic=$topic&component_help=$component_help&faq=$faq&bug=$bug&origurl=$origurl&stamp=$timestamp&stayonpage=$stayOnPage";
1194: my $output .= <<"ENDOUTPUT";
1195: <script type="text/javascript">
1.824 bisitz 1196: // <![CDATA[
1.430 albertel 1197: banner_link = '$banner_link';
1.824 bisitz 1198: // ]]>
1.430 albertel 1199: </script>
1200: ENDOUTPUT
1201: return $output;
1202: }
1203:
1204: # now just updates the help link and generates a blue icon
1.193 raeburn 1205: sub help_open_menu {
1.430 albertel 1206: my ($topic,$component_help,$faq,$bug,$stayOnPage,$width,$height,$text)
1.552 banghart 1207: = @_;
1.430 albertel 1208: $stayOnPage = 0 if (not defined $stayOnPage);
1.572 banghart 1209: # only use pop-up help (stayOnPage == 0)
1.552 banghart 1210: # if environment.remote is on (using remote control UI)
1.798 tempelho 1211: if ($env{'environment.remote'} eq 'off' ) {
1.552 banghart 1212: $stayOnPage=1;
1.430 albertel 1213: }
1214: my $output;
1215: if ($component_help) {
1216: if (!$text) {
1217: $output=&help_open_topic($component_help,undef,$stayOnPage,
1218: $width,$height);
1219: } else {
1220: my $help_text;
1221: $help_text=&unescape($topic);
1222: $output='<table><tr><td>'.
1223: &help_open_topic($component_help,$help_text,$stayOnPage,
1224: $width,$height).'</td></tr></table>';
1225: }
1226: }
1227: my $banner_link = &update_help_link($topic,$component_help,$faq,$bug,$stayOnPage);
1228: return $output.$banner_link;
1229: }
1230:
1231: sub top_nav_help {
1232: my ($text) = @_;
1.436 albertel 1233: $text = &mt($text);
1.572 banghart 1234: my $stay_on_page =
1.798 tempelho 1235: ($env{'environment.remote'} eq 'off' );
1.572 banghart 1236: my $link = ($stay_on_page) ? "javascript:helpMenu('display')"
1.436 albertel 1237: : "javascript:helpMenu('open')";
1.572 banghart 1238: my $banner_link = &update_help_link(undef,undef,undef,undef,$stay_on_page);
1.436 albertel 1239:
1.201 raeburn 1240: my $title = &mt('Get help');
1.436 albertel 1241:
1242: return <<"END";
1243: $banner_link
1244: <a href="$link" title="$title">$text</a>
1245: END
1246: }
1247:
1248: sub help_menu_js {
1249: my ($text) = @_;
1250:
1251: my $stayOnPage =
1.798 tempelho 1252: ($env{'environment.remote'} eq 'off' );
1.436 albertel 1253:
1254: my $width = 620;
1255: my $height = 600;
1.430 albertel 1256: my $helptopic=&general_help();
1257: my $details_link = '/adm/help/'.$helptopic.'.hlp';
1.261 albertel 1258: my $nothing=&Apache::lonhtmlcommon::javascript_nothing();
1.331 albertel 1259: my $start_page =
1260: &Apache::loncommon::start_page('Help Menu', undef,
1261: {'frameset' => 1,
1262: 'js_ready' => 1,
1263: 'add_entries' => {
1264: 'border' => '0',
1.579 raeburn 1265: 'rows' => "110,*",},});
1.331 albertel 1266: my $end_page =
1267: &Apache::loncommon::end_page({'frameset' => 1,
1268: 'js_ready' => 1,});
1269:
1.436 albertel 1270: my $template .= <<"ENDTEMPLATE";
1271: <script type="text/javascript">
1.877 bisitz 1272: // <![CDATA[
1.253 albertel 1273: // <!-- BEGIN LON-CAPA Internal
1.430 albertel 1274: var banner_link = '';
1.243 raeburn 1275: function helpMenu(target) {
1276: var caller = this;
1277: if (target == 'open') {
1278: var newWindow = null;
1279: try {
1.262 albertel 1280: newWindow = window.open($nothing,"helpmenu","HEIGHT=$height,WIDTH=$width,resizable=yes,scrollbars=yes" )
1.243 raeburn 1281: }
1282: catch(error) {
1283: writeHelp(caller);
1284: return;
1285: }
1286: if (newWindow) {
1287: caller = newWindow;
1288: }
1.193 raeburn 1289: }
1.243 raeburn 1290: writeHelp(caller);
1291: return;
1292: }
1293: function writeHelp(caller) {
1.430 albertel 1294: caller.document.writeln('$start_page<frame name="bannerframe" src="'+banner_link+'" /><frame name="bodyframe" src="$details_link" /> $end_page')
1.243 raeburn 1295: caller.document.close()
1296: caller.focus()
1.193 raeburn 1297: }
1.877 bisitz 1298: // END LON-CAPA Internal -->
1.253 albertel 1299: // ]]>
1.436 albertel 1300: </script>
1.193 raeburn 1301: ENDTEMPLATE
1302: return $template;
1303: }
1304:
1.172 www 1305: sub help_open_bug {
1306: my ($topic, $text, $stayOnPage, $width, $height) = @_;
1.258 albertel 1307: unless ($env{'user.adv'}) { return ''; }
1.172 www 1308: unless ($Apache::lonnet::perlvar{'BugzillaHost'}) { return ''; }
1309: $text = "" if (not defined $text);
1310: $stayOnPage = 0 if (not defined $stayOnPage);
1.798 tempelho 1311: if ($env{'environment.remote'} eq 'off' ) {
1.172 www 1312: $stayOnPage=1;
1313: }
1.184 albertel 1314: $width = 600 if (not defined $width);
1315: $height = 600 if (not defined $height);
1.172 www 1316:
1317: $topic=~s/\W+/\+/g;
1318: my $link='';
1319: my $template='';
1.379 albertel 1320: my $url=$Apache::lonnet::perlvar{'BugzillaHost'}.'enter_bug.cgi?product=LON-CAPA&bug_file_loc='.
1321: &escape($ENV{'REQUEST_URI'}).'&component='.$topic;
1.172 www 1322: if (!$stayOnPage)
1323: {
1324: $link = "javascript:void(open('$url', 'Bugzilla', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))";
1325: }
1326: else
1327: {
1328: $link = $url;
1329: }
1330: # Add the text
1331: if ($text ne "")
1332: {
1333: $template .=
1334: "<table bgcolor='#AA3333' cellspacing='1' cellpadding='1' border='0'><tr>".
1.705 tempelho 1335: "<td bgcolor='#FF5555'><a target=\"_top\" href=\"$link\"><span style=\"color:#FFFFFF;font-size:10pt;\">$text</span></a>";
1.172 www 1336: }
1337:
1338: # Add the graphic
1.179 matthew 1339: my $title = &mt('Report a Bug');
1.215 albertel 1340: my $bugicon=&lonhttpdurl("/adm/lonMisc/smallBug.gif");
1.172 www 1341: $template .= <<"ENDTEMPLATE";
1.436 albertel 1342: <a target="_top" href="$link" title="$title"><img src="$bugicon" border="0" alt="(Bug: $topic)" /></a>
1.172 www 1343: ENDTEMPLATE
1344: if ($text ne '') { $template.='</td></tr></table>' };
1345: return $template;
1346:
1347: }
1348:
1349: sub help_open_faq {
1350: my ($topic, $text, $stayOnPage, $width, $height) = @_;
1.258 albertel 1351: unless ($env{'user.adv'}) { return ''; }
1.172 www 1352: unless ($Apache::lonnet::perlvar{'FAQHost'}) { return ''; }
1353: $text = "" if (not defined $text);
1354: $stayOnPage = 0 if (not defined $stayOnPage);
1.798 tempelho 1355: if ($env{'environment.remote'} eq 'off' ) {
1.172 www 1356: $stayOnPage=1;
1357: }
1358: $width = 350 if (not defined $width);
1359: $height = 400 if (not defined $height);
1360:
1361: $topic=~s/\W+/\+/g;
1362: my $link='';
1363: my $template='';
1364: my $url=$Apache::lonnet::perlvar{'FAQHost'}.'/fom/cache/'.$topic.'.html';
1365: if (!$stayOnPage)
1366: {
1367: $link = "javascript:void(open('$url', 'FAQ-O-Matic', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))";
1368: }
1369: else
1370: {
1371: $link = $url;
1372: }
1373:
1374: # Add the text
1375: if ($text ne "")
1376: {
1377: $template .=
1.173 www 1378: "<table bgcolor='#337733' cellspacing='1' cellpadding='1' border='0'><tr>".
1.705 tempelho 1379: "<td bgcolor='#448844'><a target=\"_top\" href=\"$link\"><span style=\"color:#FFFFFF; font-size:10pt;\">$text</span></a>";
1.172 www 1380: }
1381:
1382: # Add the graphic
1.179 matthew 1383: my $title = &mt('View the FAQ');
1.215 albertel 1384: my $faqicon=&lonhttpdurl("/adm/lonMisc/smallFAQ.gif");
1.172 www 1385: $template .= <<"ENDTEMPLATE";
1.436 albertel 1386: <a target="_top" href="$link" title="$title"><img src="$faqicon" border="0" alt="(FAQ: $topic)" /></a>
1.172 www 1387: ENDTEMPLATE
1388: if ($text ne '') { $template.='</td></tr></table>' };
1389: return $template;
1390:
1.44 bowersj2 1391: }
1.37 matthew 1392:
1.180 matthew 1393: ###############################################################
1394: ###############################################################
1395:
1.45 matthew 1396: =pod
1397:
1.648 raeburn 1398: =item * &change_content_javascript():
1.256 matthew 1399:
1400: This and the next function allow you to create small sections of an
1401: otherwise static HTML page that you can update on the fly with
1402: Javascript, even in Netscape 4.
1403:
1404: The Javascript fragment returned by this function (no E<lt>scriptE<gt> tag)
1405: must be written to the HTML page once. It will prove the Javascript
1406: function "change(name, content)". Calling the change function with the
1407: name of the section
1408: you want to update, matching the name passed to C<changable_area>, and
1409: the new content you want to put in there, will put the content into
1410: that area.
1411:
1412: B<Note>: Netscape 4 only reserves enough space for the changable area
1413: to contain room for the original contents. You need to "make space"
1414: for whatever changes you wish to make, and be B<sure> to check your
1415: code in Netscape 4. This feature in Netscape 4 is B<not> powerful;
1416: it's adequate for updating a one-line status display, but little more.
1417: This script will set the space to 100% width, so you only need to
1418: worry about height in Netscape 4.
1419:
1420: Modern browsers are much less limiting, and if you can commit to the
1421: user not using Netscape 4, this feature may be used freely with
1422: pretty much any HTML.
1423:
1424: =cut
1425:
1426: sub change_content_javascript {
1427: # If we're on Netscape 4, we need to use Layer-based code
1.258 albertel 1428: if ($env{'browser.type'} eq 'netscape' &&
1429: $env{'browser.version'} =~ /^4\./) {
1.256 matthew 1430: return (<<NETSCAPE4);
1431: function change(name, content) {
1432: doc = document.layers[name+"___escape"].layers[0].document;
1433: doc.open();
1434: doc.write(content);
1435: doc.close();
1436: }
1437: NETSCAPE4
1438: } else {
1439: # Otherwise, we need to use semi-standards-compliant code
1440: # (technically, "innerHTML" isn't standard but the equivalent
1441: # is really scary, and every useful browser supports it
1442: return (<<DOMBASED);
1443: function change(name, content) {
1444: element = document.getElementById(name);
1445: element.innerHTML = content;
1446: }
1447: DOMBASED
1448: }
1449: }
1450:
1451: =pod
1452:
1.648 raeburn 1453: =item * &changable_area($name,$origContent):
1.256 matthew 1454:
1455: This provides a "changable area" that can be modified on the fly via
1456: the Javascript code provided in C<change_content_javascript>. $name is
1457: the name you will use to reference the area later; do not repeat the
1458: same name on a given HTML page more then once. $origContent is what
1459: the area will originally contain, which can be left blank.
1460:
1461: =cut
1462:
1463: sub changable_area {
1464: my ($name, $origContent) = @_;
1465:
1.258 albertel 1466: if ($env{'browser.type'} eq 'netscape' &&
1467: $env{'browser.version'} =~ /^4\./) {
1.256 matthew 1468: # If this is netscape 4, we need to use the Layer tag
1469: return "<ilayer width='100%' id='${name}___escape' overflow='none'><layer width='100%' id='$name' overflow='none'>$origContent</layer></ilayer>";
1470: } else {
1471: return "<span id='$name'>$origContent</span>";
1472: }
1473: }
1474:
1475: =pod
1476:
1.648 raeburn 1477: =item * &viewport_geometry_js
1.590 raeburn 1478:
1479: Provides javascript object (Geometry) which can provide information about the viewport geometry for the client browser.
1480:
1481: =cut
1482:
1483:
1484: sub viewport_geometry_js {
1485: return <<"GEOMETRY";
1486: var Geometry = {};
1487: function init_geometry() {
1488: if (Geometry.init) { return };
1489: Geometry.init=1;
1490: if (window.innerHeight) {
1491: Geometry.getViewportHeight = function() { return window.innerHeight; };
1492: Geometry.getViewportWidth = function() { return window.innerWidth; };
1493: Geometry.getHorizontalScroll = function() { return window.pageXOffset; };
1494: Geometry.getVerticalScroll = function() { return window.pageYOffset; };
1495: }
1496: else if (document.documentElement && document.documentElement.clientHeight) {
1497: Geometry.getViewportHeight =
1498: function() { return document.documentElement.clientHeight; };
1499: Geometry.getViewportWidth =
1500: function() { return document.documentElement.clientWidth; };
1501:
1502: Geometry.getHorizontalScroll =
1503: function() { return document.documentElement.scrollLeft; };
1504: Geometry.getVerticalScroll =
1505: function() { return document.documentElement.scrollTop; };
1506: }
1507: else if (document.body.clientHeight) {
1508: Geometry.getViewportHeight =
1509: function() { return document.body.clientHeight; };
1510: Geometry.getViewportWidth =
1511: function() { return document.body.clientWidth; };
1512: Geometry.getHorizontalScroll =
1513: function() { return document.body.scrollLeft; };
1514: Geometry.getVerticalScroll =
1515: function() { return document.body.scrollTop; };
1516: }
1517: }
1518:
1519: GEOMETRY
1520: }
1521:
1522: =pod
1523:
1.648 raeburn 1524: =item * &viewport_size_js()
1.590 raeburn 1525:
1526: Provides a javascript function to set values of two form elements - width and height (elements are passed in as arguments to the javascript function) to the dimensions of the user's browser window.
1527:
1528: =cut
1529:
1530: sub viewport_size_js {
1531: my $geometry = &viewport_geometry_js();
1532: return <<"DIMS";
1533:
1534: $geometry
1535:
1536: function getViewportDims(width,height) {
1537: init_geometry();
1538: width.value = Geometry.getViewportWidth();
1539: height.value = Geometry.getViewportHeight();
1540: return;
1541: }
1542:
1543: DIMS
1544: }
1545:
1546: =pod
1547:
1.648 raeburn 1548: =item * &resize_textarea_js()
1.565 albertel 1549:
1550: emits the needed javascript to resize a textarea to be as big as possible
1551:
1552: creates a function resize_textrea that takes two IDs first should be
1553: the id of the element to resize, second should be the id of a div that
1554: surrounds everything that comes after the textarea, this routine needs
1555: to be attached to the <body> for the onload and onresize events.
1556:
1.648 raeburn 1557: =back
1.565 albertel 1558:
1559: =cut
1560:
1561: sub resize_textarea_js {
1.590 raeburn 1562: my $geometry = &viewport_geometry_js();
1.565 albertel 1563: return <<"RESIZE";
1564: <script type="text/javascript">
1.824 bisitz 1565: // <![CDATA[
1.590 raeburn 1566: $geometry
1.565 albertel 1567:
1.588 albertel 1568: function getX(element) {
1569: var x = 0;
1570: while (element) {
1571: x += element.offsetLeft;
1572: element = element.offsetParent;
1573: }
1574: return x;
1575: }
1576: function getY(element) {
1577: var y = 0;
1578: while (element) {
1579: y += element.offsetTop;
1580: element = element.offsetParent;
1581: }
1582: return y;
1583: }
1584:
1585:
1.565 albertel 1586: function resize_textarea(textarea_id,bottom_id) {
1587: init_geometry();
1588: var textarea = document.getElementById(textarea_id);
1589: //alert(textarea);
1590:
1.588 albertel 1591: var textarea_top = getY(textarea);
1.565 albertel 1592: var textarea_height = textarea.offsetHeight;
1593: var bottom = document.getElementById(bottom_id);
1.588 albertel 1594: var bottom_top = getY(bottom);
1.565 albertel 1595: var bottom_height = bottom.offsetHeight;
1596: var window_height = Geometry.getViewportHeight();
1.588 albertel 1597: var fudge = 23;
1.565 albertel 1598: var new_height = window_height-fudge-textarea_top-bottom_height;
1599: if (new_height < 300) {
1600: new_height = 300;
1601: }
1602: textarea.style.height=new_height+'px';
1603: }
1.824 bisitz 1604: // ]]>
1.565 albertel 1605: </script>
1606: RESIZE
1607:
1608: }
1609:
1610: =pod
1611:
1.256 matthew 1612: =head1 Excel and CSV file utility routines
1613:
1614: =over 4
1615:
1616: =cut
1617:
1618: ###############################################################
1619: ###############################################################
1620:
1621: =pod
1622:
1.648 raeburn 1623: =item * &csv_translate($text)
1.37 matthew 1624:
1.185 www 1625: Translate $text to allow it to be output as a 'comma separated values'
1.37 matthew 1626: format.
1627:
1628: =cut
1629:
1.180 matthew 1630: ###############################################################
1631: ###############################################################
1.37 matthew 1632: sub csv_translate {
1633: my $text = shift;
1634: $text =~ s/\"/\"\"/g;
1.209 albertel 1635: $text =~ s/\n/ /g;
1.37 matthew 1636: return $text;
1637: }
1.180 matthew 1638:
1639: ###############################################################
1640: ###############################################################
1641:
1642: =pod
1643:
1.648 raeburn 1644: =item * &define_excel_formats()
1.180 matthew 1645:
1646: Define some commonly used Excel cell formats.
1647:
1648: Currently supported formats:
1649:
1650: =over 4
1651:
1652: =item header
1653:
1654: =item bold
1655:
1656: =item h1
1657:
1658: =item h2
1659:
1660: =item h3
1661:
1.256 matthew 1662: =item h4
1663:
1664: =item i
1665:
1.180 matthew 1666: =item date
1667:
1668: =back
1669:
1670: Inputs: $workbook
1671:
1672: Returns: $format, a hash reference.
1673:
1674: =cut
1675:
1676: ###############################################################
1677: ###############################################################
1678: sub define_excel_formats {
1679: my ($workbook) = @_;
1680: my $format;
1681: $format->{'header'} = $workbook->add_format(bold => 1,
1682: bottom => 1,
1683: align => 'center');
1684: $format->{'bold'} = $workbook->add_format(bold=>1);
1685: $format->{'h1'} = $workbook->add_format(bold=>1, size=>18);
1686: $format->{'h2'} = $workbook->add_format(bold=>1, size=>16);
1687: $format->{'h3'} = $workbook->add_format(bold=>1, size=>14);
1.255 matthew 1688: $format->{'h4'} = $workbook->add_format(bold=>1, size=>12);
1.246 matthew 1689: $format->{'i'} = $workbook->add_format(italic=>1);
1.180 matthew 1690: $format->{'date'} = $workbook->add_format(num_format=>
1.207 matthew 1691: 'mm/dd/yyyy hh:mm:ss');
1.180 matthew 1692: return $format;
1693: }
1694:
1695: ###############################################################
1696: ###############################################################
1.113 bowersj2 1697:
1698: =pod
1699:
1.648 raeburn 1700: =item * &create_workbook()
1.255 matthew 1701:
1702: Create an Excel worksheet. If it fails, output message on the
1703: request object and return undefs.
1704:
1705: Inputs: Apache request object
1706:
1707: Returns (undef) on failure,
1708: Excel worksheet object, scalar with filename, and formats
1709: from &Apache::loncommon::define_excel_formats on success
1710:
1711: =cut
1712:
1713: ###############################################################
1714: ###############################################################
1715: sub create_workbook {
1716: my ($r) = @_;
1717: #
1718: # Create the excel spreadsheet
1719: my $filename = '/prtspool/'.
1.258 albertel 1720: $env{'user.name'}.'_'.$env{'user.domain'}.'_'.
1.255 matthew 1721: time.'_'.rand(1000000000).'.xls';
1722: my $workbook = Spreadsheet::WriteExcel->new('/home/httpd'.$filename);
1723: if (! defined($workbook)) {
1724: $r->log_error("Error creating excel spreadsheet $filename: $!");
1.928 bisitz 1725: $r->print(
1726: '<p class="LC_error">'
1727: .&mt('Problems occurred in creating the new Excel file.')
1728: .' '.&mt('This error has been logged.')
1729: .' '.&mt('Please alert your LON-CAPA administrator.')
1730: .'</p>'
1731: );
1.255 matthew 1732: return (undef);
1733: }
1734: #
1735: $workbook->set_tempdir('/home/httpd/perl/tmp');
1736: #
1737: my $format = &Apache::loncommon::define_excel_formats($workbook);
1738: return ($workbook,$filename,$format);
1739: }
1740:
1741: ###############################################################
1742: ###############################################################
1743:
1744: =pod
1745:
1.648 raeburn 1746: =item * &create_text_file()
1.113 bowersj2 1747:
1.542 raeburn 1748: Create a file to write to and eventually make available to the user.
1.256 matthew 1749: If file creation fails, outputs an error message on the request object and
1750: return undefs.
1.113 bowersj2 1751:
1.256 matthew 1752: Inputs: Apache request object, and file suffix
1.113 bowersj2 1753:
1.256 matthew 1754: Returns (undef) on failure,
1755: Filehandle and filename on success.
1.113 bowersj2 1756:
1757: =cut
1758:
1.256 matthew 1759: ###############################################################
1760: ###############################################################
1761: sub create_text_file {
1762: my ($r,$suffix) = @_;
1763: if (! defined($suffix)) { $suffix = 'txt'; };
1764: my $fh;
1765: my $filename = '/prtspool/'.
1.258 albertel 1766: $env{'user.name'}.'_'.$env{'user.domain'}.'_'.
1.256 matthew 1767: time.'_'.rand(1000000000).'.'.$suffix;
1768: $fh = Apache::File->new('>/home/httpd'.$filename);
1769: if (! defined($fh)) {
1770: $r->log_error("Couldn't open $filename for output $!");
1.928 bisitz 1771: $r->print(
1772: '<p class="LC_error">'
1773: .&mt('Problems occurred in creating the output file.')
1774: .' '.&mt('This error has been logged.')
1775: .' '.&mt('Please alert your LON-CAPA administrator.')
1776: .'</p>'
1777: );
1.113 bowersj2 1778: }
1.256 matthew 1779: return ($fh,$filename)
1.113 bowersj2 1780: }
1781:
1782:
1.256 matthew 1783: =pod
1.113 bowersj2 1784:
1785: =back
1786:
1787: =cut
1.37 matthew 1788:
1789: ###############################################################
1.33 matthew 1790: ## Home server <option> list generating code ##
1791: ###############################################################
1.35 matthew 1792:
1.169 www 1793: # ------------------------------------------
1794:
1795: sub domain_select {
1796: my ($name,$value,$multiple)=@_;
1797: my %domains=map {
1.514 albertel 1798: $_ => $_.' '. &Apache::lonnet::domain($_,'description')
1.512 albertel 1799: } &Apache::lonnet::all_domains();
1.169 www 1800: if ($multiple) {
1801: $domains{''}=&mt('Any domain');
1.550 albertel 1802: $domains{'select_form_order'} = [sort {lc($a) cmp lc($b) } (keys(%domains))];
1.287 albertel 1803: return &multiple_select_form($name,$value,4,\%domains);
1.169 www 1804: } else {
1.550 albertel 1805: $domains{'select_form_order'} = [sort {lc($a) cmp lc($b) } (keys(%domains))];
1.948.2.7 raeburn 1806: return &select_form($name,$value,\%domains);
1.169 www 1807: }
1808: }
1809:
1.282 albertel 1810: #-------------------------------------------
1811:
1812: =pod
1813:
1.519 raeburn 1814: =head1 Routines for form select boxes
1815:
1816: =over 4
1817:
1.648 raeburn 1818: =item * &multiple_select_form($name,$value,$size,$hash,$order)
1.282 albertel 1819:
1820: Returns a string containing a <select> element int multiple mode
1821:
1822:
1823: Args:
1824: $name - name of the <select> element
1.506 raeburn 1825: $value - scalar or array ref of values that should already be selected
1.282 albertel 1826: $size - number of rows long the select element is
1.283 albertel 1827: $hash - the elements should be 'option' => 'shown text'
1.282 albertel 1828: (shown text should already have been &mt())
1.506 raeburn 1829: $order - (optional) array ref of the order to show the elements in
1.283 albertel 1830:
1.282 albertel 1831: =cut
1832:
1833: #-------------------------------------------
1.169 www 1834: sub multiple_select_form {
1.284 albertel 1835: my ($name,$value,$size,$hash,$order)=@_;
1.169 www 1836: my %selected = map { $_ => 1 } ref($value)?@{$value}:($value);
1837: my $output='';
1.191 matthew 1838: if (! defined($size)) {
1839: $size = 4;
1.283 albertel 1840: if (scalar(keys(%$hash))<4) {
1841: $size = scalar(keys(%$hash));
1.191 matthew 1842: }
1843: }
1.734 bisitz 1844: $output.="\n".'<select name="'.$name.'" size="'.$size.'" multiple="multiple">';
1.501 banghart 1845: my @order;
1.506 raeburn 1846: if (ref($order) eq 'ARRAY') {
1847: @order = @{$order};
1848: } else {
1849: @order = sort(keys(%$hash));
1.501 banghart 1850: }
1851: if (exists($$hash{'select_form_order'})) {
1852: @order = @{$$hash{'select_form_order'}};
1853: }
1854:
1.284 albertel 1855: foreach my $key (@order) {
1.356 albertel 1856: $output.='<option value="'.&HTML::Entities::encode($key,'"<>&').'" ';
1.284 albertel 1857: $output.='selected="selected" ' if ($selected{$key});
1858: $output.='>'.$hash->{$key}."</option>\n";
1.169 www 1859: }
1860: $output.="</select>\n";
1861: return $output;
1862: }
1863:
1.88 www 1864: #-------------------------------------------
1865:
1866: =pod
1867:
1.948.2.7 raeburn 1868: =item * &select_form($defdom,$name,$hashref,$onchange)
1.88 www 1869:
1870: Returns a string containing a <select name='$name' size='1'> form to
1.948.2.7 raeburn 1871: allow a user to select options from a ref to a hash containing:
1872: option_name => displayed text. An optional $onchange can include
1873: a javascript onchange item, e.g., onchange="this.form.submit();"
1874:
1.88 www 1875: See lonrights.pm for an example invocation and use.
1876:
1877: =cut
1878:
1879: #-------------------------------------------
1880: sub select_form {
1.948.2.7 raeburn 1881: my ($def,$name,$hashref,$onchange) = @_;
1882: return unless (ref($hashref) eq 'HASH');
1883: if ($onchange) {
1884: $onchange = ' onchange="'.$onchange.'"';
1885: }
1886: my $selectform = "<select name=\"$name\" size=\"1\"$onchange>\n";
1.128 albertel 1887: my @keys;
1.948.2.7 raeburn 1888: if (exists($hashref->{'select_form_order'})) {
1889: @keys=@{$hashref->{'select_form_order'}};
1.128 albertel 1890: } else {
1.948.2.7 raeburn 1891: @keys=sort(keys(%{$hashref}));
1.128 albertel 1892: }
1.356 albertel 1893: foreach my $key (@keys) {
1894: $selectform.=
1895: '<option value="'.&HTML::Entities::encode($key,'"<>&').'" '.
1896: ($key eq $def ? 'selected="selected" ' : '').
1.948.2.7 raeburn 1897: ">".$hashref->{$key}."</option>\n";
1.88 www 1898: }
1899: $selectform.="</select>";
1900: return $selectform;
1901: }
1902:
1.475 www 1903: # For display filters
1904:
1905: sub display_filter {
1906: if (!$env{'form.show'}) { $env{'form.show'}=10; }
1.477 www 1907: if (!$env{'form.displayfilter'}) { $env{'form.displayfilter'}='currentfolder'; }
1.714 bisitz 1908: return '<span class="LC_nobreak"><label>'.&mt('Records [_1]',
1.475 www 1909: &Apache::lonmeta::selectbox('show',$env{'form.show'},undef,
1910: (&mt('all'),10,20,50,100,1000,10000))).
1.714 bisitz 1911: '</label></span> <span class="LC_nobreak">'.
1.475 www 1912: &mt('Filter [_1]',
1.477 www 1913: &select_form($env{'form.displayfilter'},
1914: 'displayfilter',
1.948.2.7 raeburn 1915: {'currentfolder' => 'Current folder/page',
1.477 www 1916: 'containing' => 'Containing phrase',
1.948.2.7 raeburn 1917: 'none' => 'None'})).
1.714 bisitz 1918: '<input type="text" name="containingphrase" size="30" value="'.&HTML::Entities::encode($env{'form.containingphrase'}).'" /></span>';
1.475 www 1919: }
1920:
1.167 www 1921: sub gradeleveldescription {
1922: my $gradelevel=shift;
1923: my %gradelevels=(0 => 'Not specified',
1924: 1 => 'Grade 1',
1925: 2 => 'Grade 2',
1926: 3 => 'Grade 3',
1927: 4 => 'Grade 4',
1928: 5 => 'Grade 5',
1929: 6 => 'Grade 6',
1930: 7 => 'Grade 7',
1931: 8 => 'Grade 8',
1932: 9 => 'Grade 9',
1933: 10 => 'Grade 10',
1934: 11 => 'Grade 11',
1935: 12 => 'Grade 12',
1936: 13 => 'Grade 13',
1937: 14 => '100 Level',
1938: 15 => '200 Level',
1939: 16 => '300 Level',
1940: 17 => '400 Level',
1941: 18 => 'Graduate Level');
1942: return &mt($gradelevels{$gradelevel});
1943: }
1944:
1.163 www 1945: sub select_level_form {
1946: my ($deflevel,$name)=@_;
1947: unless ($deflevel) { $deflevel=0; }
1.167 www 1948: my $selectform = "<select name=\"$name\" size=\"1\">\n";
1949: for (my $i=0; $i<=18; $i++) {
1950: $selectform.="<option value=\"$i\" ".
1.253 albertel 1951: ($i==$deflevel ? 'selected="selected" ' : '').
1.167 www 1952: ">".&gradeleveldescription($i)."</option>\n";
1953: }
1954: $selectform.="</select>";
1955: return $selectform;
1.163 www 1956: }
1.167 www 1957:
1.35 matthew 1958: #-------------------------------------------
1959:
1.45 matthew 1960: =pod
1961:
1.910 raeburn 1962: =item * &select_dom_form($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms)
1.35 matthew 1963:
1964: Returns a string containing a <select name='$name' size='1'> form to
1965: allow a user to select the domain to preform an operation in.
1966: See loncreateuser.pm for an example invocation and use.
1967:
1.90 www 1968: If the $includeempty flag is set, it also includes an empty choice ("no domain
1969: selected");
1970:
1.743 raeburn 1971: If the $showdomdesc flag is set, the domain name is followed by the domain description.
1972:
1.910 raeburn 1973: The optional $onchange argument specifies what should occur if the domain selector is changed, e.g., 'this.form.submit()' if the form is to be automatically submitted.
1974:
1975: The optional $incdoms is a reference to an array of domains which will be the only available options.
1.563 raeburn 1976:
1.35 matthew 1977: =cut
1978:
1979: #-------------------------------------------
1.34 matthew 1980: sub select_dom_form {
1.910 raeburn 1981: my ($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms) = @_;
1.872 raeburn 1982: if ($onchange) {
1.874 raeburn 1983: $onchange = ' onchange="'.$onchange.'"';
1.743 raeburn 1984: }
1.910 raeburn 1985: my @domains;
1986: if (ref($incdoms) eq 'ARRAY') {
1987: @domains = sort {lc($a) cmp lc($b)} (@{$incdoms});
1988: } else {
1989: @domains = sort {lc($a) cmp lc($b)} (&Apache::lonnet::all_domains());
1990: }
1.90 www 1991: if ($includeempty) { @domains=('',@domains); }
1.743 raeburn 1992: my $selectdomain = "<select name=\"$name\" size=\"1\"$onchange>\n";
1.356 albertel 1993: foreach my $dom (@domains) {
1994: $selectdomain.="<option value=\"$dom\" ".
1.563 raeburn 1995: ($dom eq $defdom ? 'selected="selected" ' : '').'>'.$dom;
1996: if ($showdomdesc) {
1997: if ($dom ne '') {
1998: my $domdesc = &Apache::lonnet::domain($dom,'description');
1999: if ($domdesc ne '') {
2000: $selectdomain .= ' ('.$domdesc.')';
2001: }
2002: }
2003: }
2004: $selectdomain .= "</option>\n";
1.34 matthew 2005: }
2006: $selectdomain.="</select>";
2007: return $selectdomain;
2008: }
2009:
1.35 matthew 2010: #-------------------------------------------
2011:
1.45 matthew 2012: =pod
2013:
1.648 raeburn 2014: =item * &home_server_form_item($domain,$name,$defaultflag)
1.35 matthew 2015:
1.586 raeburn 2016: input: 4 arguments (two required, two optional) -
2017: $domain - domain of new user
2018: $name - name of form element
2019: $default - Value of 'default' causes a default item to be first
2020: option, and selected by default.
2021: $hide - Value of 'hide' causes hiding of the name of the server,
2022: if 1 server found, or default, if 0 found.
1.594 raeburn 2023: output: returns 2 items:
1.586 raeburn 2024: (a) form element which contains either:
2025: (i) <select name="$name">
2026: <option value="$hostid1">$hostid $servers{$hostid}</option>
2027: <option value="$hostid2">$hostid $servers{$hostid}</option>
2028: </select>
2029: form item if there are multiple library servers in $domain, or
2030: (ii) an <input type="hidden" name="$name" value="$hostid" /> form item
2031: if there is only one library server in $domain.
2032:
2033: (b) number of library servers found.
2034:
2035: See loncreateuser.pm for example of use.
1.35 matthew 2036:
2037: =cut
2038:
2039: #-------------------------------------------
1.586 raeburn 2040: sub home_server_form_item {
2041: my ($domain,$name,$default,$hide) = @_;
1.513 albertel 2042: my %servers = &Apache::lonnet::get_servers($domain,'library');
1.586 raeburn 2043: my $result;
2044: my $numlib = keys(%servers);
2045: if ($numlib > 1) {
2046: $result .= '<select name="'.$name.'" />'."\n";
2047: if ($default) {
1.804 bisitz 2048: $result .= '<option value="default" selected="selected">'.&mt('default').
1.586 raeburn 2049: '</option>'."\n";
2050: }
2051: foreach my $hostid (sort(keys(%servers))) {
2052: $result.= '<option value="'.$hostid.'">'.
2053: $hostid.' '.$servers{$hostid}."</option>\n";
2054: }
2055: $result .= '</select>'."\n";
2056: } elsif ($numlib == 1) {
2057: my $hostid;
2058: foreach my $item (keys(%servers)) {
2059: $hostid = $item;
2060: }
2061: $result .= '<input type="hidden" name="'.$name.'" value="'.
2062: $hostid.'" />';
2063: if (!$hide) {
2064: $result .= $hostid.' '.$servers{$hostid};
2065: }
2066: $result .= "\n";
2067: } elsif ($default) {
2068: $result .= '<input type="hidden" name="'.$name.
2069: '" value="default" />';
2070: if (!$hide) {
2071: $result .= &mt('default');
2072: }
2073: $result .= "\n";
1.33 matthew 2074: }
1.586 raeburn 2075: return ($result,$numlib);
1.33 matthew 2076: }
1.112 bowersj2 2077:
2078: =pod
2079:
1.534 albertel 2080: =back
2081:
1.112 bowersj2 2082: =cut
1.87 matthew 2083:
2084: ###############################################################
1.112 bowersj2 2085: ## Decoding User Agent ##
1.87 matthew 2086: ###############################################################
2087:
2088: =pod
2089:
1.112 bowersj2 2090: =head1 Decoding the User Agent
2091:
2092: =over 4
2093:
2094: =item * &decode_user_agent()
1.87 matthew 2095:
2096: Inputs: $r
2097:
2098: Outputs:
2099:
2100: =over 4
2101:
1.112 bowersj2 2102: =item * $httpbrowser
1.87 matthew 2103:
1.112 bowersj2 2104: =item * $clientbrowser
1.87 matthew 2105:
1.112 bowersj2 2106: =item * $clientversion
1.87 matthew 2107:
1.112 bowersj2 2108: =item * $clientmathml
1.87 matthew 2109:
1.112 bowersj2 2110: =item * $clientunicode
1.87 matthew 2111:
1.112 bowersj2 2112: =item * $clientos
1.87 matthew 2113:
2114: =back
2115:
1.157 matthew 2116: =back
2117:
1.87 matthew 2118: =cut
2119:
2120: ###############################################################
2121: ###############################################################
2122: sub decode_user_agent {
1.247 albertel 2123: my ($r)=@_;
1.87 matthew 2124: my @browsertype=split(/\&/,$Apache::lonnet::perlvar{"lonBrowsDet"});
2125: my %mathcap=split(/\&/,$$Apache::lonnet::perlvar{"lonMathML"});
2126: my $httpbrowser=$ENV{"HTTP_USER_AGENT"};
1.247 albertel 2127: if (!$httpbrowser && $r) { $httpbrowser=$r->header_in('User-Agent'); }
1.87 matthew 2128: my $clientbrowser='unknown';
2129: my $clientversion='0';
2130: my $clientmathml='';
2131: my $clientunicode='0';
2132: for (my $i=0;$i<=$#browsertype;$i++) {
2133: my ($bname,$match,$notmatch,$vreg,$minv,$univ)=split(/\:/,$browsertype[$i]);
2134: if (($httpbrowser=~/$match/i) && ($httpbrowser!~/$notmatch/i)) {
2135: $clientbrowser=$bname;
2136: $httpbrowser=~/$vreg/i;
2137: $clientversion=$1;
2138: $clientmathml=($clientversion>=$minv);
2139: $clientunicode=($clientversion>=$univ);
2140: }
2141: }
2142: my $clientos='unknown';
2143: if (($httpbrowser=~/linux/i) ||
2144: ($httpbrowser=~/unix/i) ||
2145: ($httpbrowser=~/ux/i) ||
2146: ($httpbrowser=~/solaris/i)) { $clientos='unix'; }
2147: if (($httpbrowser=~/vax/i) ||
2148: ($httpbrowser=~/vms/i)) { $clientos='vms'; }
2149: if ($httpbrowser=~/next/i) { $clientos='next'; }
2150: if (($httpbrowser=~/mac/i) ||
2151: ($httpbrowser=~/powerpc/i)) { $clientos='mac'; }
2152: if ($httpbrowser=~/win/i) { $clientos='win'; }
2153: if ($httpbrowser=~/embed/i) { $clientos='pda'; }
2154: return ($httpbrowser,$clientbrowser,$clientversion,$clientmathml,
2155: $clientunicode,$clientos,);
2156: }
2157:
1.32 matthew 2158: ###############################################################
2159: ## Authentication changing form generation subroutines ##
2160: ###############################################################
2161: ##
2162: ## All of the authform_xxxxxxx subroutines take their inputs in a
2163: ## hash, and have reasonable default values.
2164: ##
2165: ## formname = the name given in the <form> tag.
1.35 matthew 2166: #-------------------------------------------
2167:
1.45 matthew 2168: =pod
2169:
1.112 bowersj2 2170: =head1 Authentication Routines
2171:
2172: =over 4
2173:
1.648 raeburn 2174: =item * &authform_xxxxxx()
1.35 matthew 2175:
2176: The authform_xxxxxx subroutines provide javascript and html forms which
2177: handle some of the conveniences required for authentication forms.
2178: This is not an optimal method, but it works.
2179:
2180: =over 4
2181:
1.112 bowersj2 2182: =item * authform_header
1.35 matthew 2183:
1.112 bowersj2 2184: =item * authform_authorwarning
1.35 matthew 2185:
1.112 bowersj2 2186: =item * authform_nochange
1.35 matthew 2187:
1.112 bowersj2 2188: =item * authform_kerberos
1.35 matthew 2189:
1.112 bowersj2 2190: =item * authform_internal
1.35 matthew 2191:
1.112 bowersj2 2192: =item * authform_filesystem
1.35 matthew 2193:
2194: =back
2195:
1.648 raeburn 2196: See loncreateuser.pm for invocation and use examples.
1.157 matthew 2197:
1.35 matthew 2198: =cut
2199:
2200: #-------------------------------------------
1.32 matthew 2201: sub authform_header{
2202: my %in = (
2203: formname => 'cu',
1.80 albertel 2204: kerb_def_dom => '',
1.32 matthew 2205: @_,
2206: );
2207: $in{'formname'} = 'document.' . $in{'formname'};
2208: my $result='';
1.80 albertel 2209:
2210: #---------------------------------------------- Code for upper case translation
2211: my $Javascript_toUpperCase;
2212: unless ($in{kerb_def_dom}) {
2213: $Javascript_toUpperCase =<<"END";
2214: switch (choice) {
2215: case 'krb': currentform.elements[choicearg].value =
2216: currentform.elements[choicearg].value.toUpperCase();
2217: break;
2218: default:
2219: }
2220: END
2221: } else {
2222: $Javascript_toUpperCase = "";
2223: }
2224:
1.165 raeburn 2225: my $radioval = "'nochange'";
1.591 raeburn 2226: if (defined($in{'curr_authtype'})) {
2227: if ($in{'curr_authtype'} ne '') {
2228: $radioval = "'".$in{'curr_authtype'}."arg'";
2229: }
1.174 matthew 2230: }
1.165 raeburn 2231: my $argfield = 'null';
1.591 raeburn 2232: if (defined($in{'mode'})) {
1.165 raeburn 2233: if ($in{'mode'} eq 'modifycourse') {
1.591 raeburn 2234: if (defined($in{'curr_autharg'})) {
2235: if ($in{'curr_autharg'} ne '') {
1.165 raeburn 2236: $argfield = "'$in{'curr_autharg'}'";
2237: }
2238: }
2239: }
2240: }
2241:
1.32 matthew 2242: $result.=<<"END";
2243: var current = new Object();
1.165 raeburn 2244: current.radiovalue = $radioval;
2245: current.argfield = $argfield;
1.32 matthew 2246:
2247: function changed_radio(choice,currentform) {
2248: var choicearg = choice + 'arg';
2249: // If a radio button in changed, we need to change the argfield
2250: if (current.radiovalue != choice) {
2251: current.radiovalue = choice;
2252: if (current.argfield != null) {
2253: currentform.elements[current.argfield].value = '';
2254: }
2255: if (choice == 'nochange') {
2256: current.argfield = null;
2257: } else {
2258: current.argfield = choicearg;
2259: switch(choice) {
2260: case 'krb':
2261: currentform.elements[current.argfield].value =
2262: "$in{'kerb_def_dom'}";
2263: break;
2264: default:
2265: break;
2266: }
2267: }
2268: }
2269: return;
2270: }
1.22 www 2271:
1.32 matthew 2272: function changed_text(choice,currentform) {
2273: var choicearg = choice + 'arg';
2274: if (currentform.elements[choicearg].value !='') {
1.80 albertel 2275: $Javascript_toUpperCase
1.32 matthew 2276: // clear old field
2277: if ((current.argfield != choicearg) && (current.argfield != null)) {
2278: currentform.elements[current.argfield].value = '';
2279: }
2280: current.argfield = choicearg;
2281: }
2282: set_auth_radio_buttons(choice,currentform);
2283: return;
1.20 www 2284: }
1.32 matthew 2285:
2286: function set_auth_radio_buttons(newvalue,currentform) {
1.948.2.13 raeburn 2287: var numauthchoices = currentform.login.length;
2288: if (typeof numauthchoices == "undefined") {
2289: return;
2290: }
1.32 matthew 2291: var i=0;
1.948.2.13 raeburn 2292: while (i < numauthchoices) {) {
1.32 matthew 2293: if (currentform.login[i].value == newvalue) { break; }
2294: i++;
2295: }
1.948.2.13 raeburn 2296: if (i == numauthchoices) {
1.32 matthew 2297: return;
2298: }
2299: current.radiovalue = newvalue;
2300: currentform.login[i].checked = true;
2301: return;
2302: }
2303: END
2304: return $result;
2305: }
2306:
2307: sub authform_authorwarning{
2308: my $result='';
1.144 matthew 2309: $result='<i>'.
2310: &mt('As a general rule, only authors or co-authors should be '.
2311: 'filesystem authenticated '.
2312: '(which allows access to the server filesystem).')."</i>\n";
1.32 matthew 2313: return $result;
2314: }
2315:
2316: sub authform_nochange{
2317: my %in = (
2318: formname => 'document.cu',
2319: kerb_def_dom => 'MSU.EDU',
2320: @_,
2321: );
1.586 raeburn 2322: my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
2323: my $result;
2324: if (keys(%can_assign) == 0) {
2325: $result = &mt('Under you current role you are not permitted to change login settings for this user');
2326: } else {
2327: $result = '<label>'.&mt('[_1] Do not change login data',
2328: '<input type="radio" name="login" value="nochange" '.
2329: 'checked="checked" onclick="'.
1.281 albertel 2330: "javascript:changed_radio('nochange',$in{'formname'});".'" />').
2331: '</label>';
1.586 raeburn 2332: }
1.32 matthew 2333: return $result;
2334: }
2335:
1.591 raeburn 2336: sub authform_kerberos {
1.32 matthew 2337: my %in = (
2338: formname => 'document.cu',
2339: kerb_def_dom => 'MSU.EDU',
1.80 albertel 2340: kerb_def_auth => 'krb4',
1.32 matthew 2341: @_,
2342: );
1.586 raeburn 2343: my ($check4,$check5,$krbcheck,$krbarg,$krbver,$result,$authtype,
2344: $autharg,$jscall);
2345: my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
1.80 albertel 2346: if ($in{'kerb_def_auth'} eq 'krb5') {
1.772 bisitz 2347: $check5 = ' checked="checked"';
1.80 albertel 2348: } else {
1.772 bisitz 2349: $check4 = ' checked="checked"';
1.80 albertel 2350: }
1.165 raeburn 2351: $krbarg = $in{'kerb_def_dom'};
1.591 raeburn 2352: if (defined($in{'curr_authtype'})) {
2353: if ($in{'curr_authtype'} eq 'krb') {
1.772 bisitz 2354: $krbcheck = ' checked="checked"';
1.623 raeburn 2355: if (defined($in{'mode'})) {
2356: if ($in{'mode'} eq 'modifyuser') {
2357: $krbcheck = '';
2358: }
2359: }
1.591 raeburn 2360: if (defined($in{'curr_kerb_ver'})) {
2361: if ($in{'curr_krb_ver'} eq '5') {
1.772 bisitz 2362: $check5 = ' checked="checked"';
1.591 raeburn 2363: $check4 = '';
2364: } else {
1.772 bisitz 2365: $check4 = ' checked="checked"';
1.591 raeburn 2366: $check5 = '';
2367: }
1.586 raeburn 2368: }
1.591 raeburn 2369: if (defined($in{'curr_autharg'})) {
1.165 raeburn 2370: $krbarg = $in{'curr_autharg'};
2371: }
1.586 raeburn 2372: if (!$can_assign{'krb4'} && !$can_assign{'krb5'}) {
1.591 raeburn 2373: if (defined($in{'curr_autharg'})) {
1.586 raeburn 2374: $result =
2375: &mt('Currently Kerberos authenticated with domain [_1] Version [_2].',
2376: $in{'curr_autharg'},$krbver);
2377: } else {
2378: $result =
2379: &mt('Currently Kerberos authenticated, Version [_1].',$krbver);
2380: }
2381: return $result;
2382: }
2383: }
2384: } else {
2385: if ($authnum == 1) {
1.784 bisitz 2386: $authtype = '<input type="hidden" name="login" value="krb" />';
1.165 raeburn 2387: }
2388: }
1.586 raeburn 2389: if (!$can_assign{'krb4'} && !$can_assign{'krb5'}) {
2390: return;
1.587 raeburn 2391: } elsif ($authtype eq '') {
1.591 raeburn 2392: if (defined($in{'mode'})) {
1.587 raeburn 2393: if ($in{'mode'} eq 'modifycourse') {
2394: if ($authnum == 1) {
1.784 bisitz 2395: $authtype = '<input type="hidden" name="login" value="krb" />';
1.587 raeburn 2396: }
2397: }
2398: }
1.586 raeburn 2399: }
2400: $jscall = "javascript:changed_radio('krb',$in{'formname'});";
2401: if ($authtype eq '') {
2402: $authtype = '<input type="radio" name="login" value="krb" '.
2403: 'onclick="'.$jscall.'" onchange="'.$jscall.'"'.
2404: $krbcheck.' />';
2405: }
2406: if (($can_assign{'krb4'} && $can_assign{'krb5'}) ||
2407: ($can_assign{'krb4'} && !$can_assign{'krb5'} &&
2408: $in{'curr_authtype'} eq 'krb5') ||
2409: (!$can_assign{'krb4'} && $can_assign{'krb5'} &&
2410: $in{'curr_authtype'} eq 'krb4')) {
2411: $result .= &mt
1.144 matthew 2412: ('[_1] Kerberos authenticated with domain [_2] '.
1.281 albertel 2413: '[_3] Version 4 [_4] Version 5 [_5]',
1.586 raeburn 2414: '<label>'.$authtype,
1.281 albertel 2415: '</label><input type="text" size="10" name="krbarg" '.
1.165 raeburn 2416: 'value="'.$krbarg.'" '.
1.144 matthew 2417: 'onchange="'.$jscall.'" />',
1.281 albertel 2418: '<label><input type="radio" name="krbver" value="4" '.$check4.' />',
2419: '</label><label><input type="radio" name="krbver" value="5" '.$check5.' />',
2420: '</label>');
1.586 raeburn 2421: } elsif ($can_assign{'krb4'}) {
2422: $result .= &mt
2423: ('[_1] Kerberos authenticated with domain [_2] '.
2424: '[_3] Version 4 [_4]',
2425: '<label>'.$authtype,
2426: '</label><input type="text" size="10" name="krbarg" '.
2427: 'value="'.$krbarg.'" '.
2428: 'onchange="'.$jscall.'" />',
2429: '<label><input type="hidden" name="krbver" value="4" />',
2430: '</label>');
2431: } elsif ($can_assign{'krb5'}) {
2432: $result .= &mt
2433: ('[_1] Kerberos authenticated with domain [_2] '.
2434: '[_3] Version 5 [_4]',
2435: '<label>'.$authtype,
2436: '</label><input type="text" size="10" name="krbarg" '.
2437: 'value="'.$krbarg.'" '.
2438: 'onchange="'.$jscall.'" />',
2439: '<label><input type="hidden" name="krbver" value="5" />',
2440: '</label>');
2441: }
1.32 matthew 2442: return $result;
2443: }
2444:
2445: sub authform_internal{
1.586 raeburn 2446: my %in = (
1.32 matthew 2447: formname => 'document.cu',
2448: kerb_def_dom => 'MSU.EDU',
2449: @_,
2450: );
1.586 raeburn 2451: my ($intcheck,$intarg,$result,$authtype,$autharg,$jscall);
2452: my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
1.591 raeburn 2453: if (defined($in{'curr_authtype'})) {
2454: if ($in{'curr_authtype'} eq 'int') {
1.586 raeburn 2455: if ($can_assign{'int'}) {
1.772 bisitz 2456: $intcheck = 'checked="checked" ';
1.623 raeburn 2457: if (defined($in{'mode'})) {
2458: if ($in{'mode'} eq 'modifyuser') {
2459: $intcheck = '';
2460: }
2461: }
1.591 raeburn 2462: if (defined($in{'curr_autharg'})) {
1.586 raeburn 2463: $intarg = $in{'curr_autharg'};
2464: }
2465: } else {
2466: $result = &mt('Currently internally authenticated.');
2467: return $result;
1.165 raeburn 2468: }
2469: }
1.586 raeburn 2470: } else {
2471: if ($authnum == 1) {
1.784 bisitz 2472: $authtype = '<input type="hidden" name="login" value="int" />';
1.586 raeburn 2473: }
2474: }
2475: if (!$can_assign{'int'}) {
2476: return;
1.587 raeburn 2477: } elsif ($authtype eq '') {
1.591 raeburn 2478: if (defined($in{'mode'})) {
1.587 raeburn 2479: if ($in{'mode'} eq 'modifycourse') {
2480: if ($authnum == 1) {
1.784 bisitz 2481: $authtype = '<input type="hidden" name="login" value="int" />';
1.587 raeburn 2482: }
2483: }
2484: }
1.165 raeburn 2485: }
1.586 raeburn 2486: $jscall = "javascript:changed_radio('int',$in{'formname'});";
2487: if ($authtype eq '') {
2488: $authtype = '<input type="radio" name="login" value="int" '.$intcheck.
2489: ' onchange="'.$jscall.'" onclick="'.$jscall.'" />';
2490: }
1.605 bisitz 2491: $autharg = '<input type="password" size="10" name="intarg" value="'.
1.586 raeburn 2492: $intarg.'" onchange="'.$jscall.'" />';
2493: $result = &mt
1.144 matthew 2494: ('[_1] Internally authenticated (with initial password [_2])',
1.586 raeburn 2495: '<label>'.$authtype,'</label>'.$autharg);
1.824 bisitz 2496: $result.="<label><input type=\"checkbox\" name=\"visible\" onclick='if (this.checked) { this.form.intarg.type=\"text\" } else { this.form.intarg.type=\"password\" }' />".&mt('Visible input').'</label>';
1.32 matthew 2497: return $result;
2498: }
2499:
2500: sub authform_local{
2501: my %in = (
2502: formname => 'document.cu',
2503: kerb_def_dom => 'MSU.EDU',
2504: @_,
2505: );
1.586 raeburn 2506: my ($loccheck,$locarg,$result,$authtype,$autharg,$jscall);
2507: my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
1.591 raeburn 2508: if (defined($in{'curr_authtype'})) {
2509: if ($in{'curr_authtype'} eq 'loc') {
1.586 raeburn 2510: if ($can_assign{'loc'}) {
1.772 bisitz 2511: $loccheck = 'checked="checked" ';
1.623 raeburn 2512: if (defined($in{'mode'})) {
2513: if ($in{'mode'} eq 'modifyuser') {
2514: $loccheck = '';
2515: }
2516: }
1.591 raeburn 2517: if (defined($in{'curr_autharg'})) {
1.586 raeburn 2518: $locarg = $in{'curr_autharg'};
2519: }
2520: } else {
2521: $result = &mt('Currently using local (institutional) authentication.');
2522: return $result;
1.165 raeburn 2523: }
2524: }
1.586 raeburn 2525: } else {
2526: if ($authnum == 1) {
1.784 bisitz 2527: $authtype = '<input type="hidden" name="login" value="loc" />';
1.586 raeburn 2528: }
2529: }
2530: if (!$can_assign{'loc'}) {
2531: return;
1.587 raeburn 2532: } elsif ($authtype eq '') {
1.591 raeburn 2533: if (defined($in{'mode'})) {
1.587 raeburn 2534: if ($in{'mode'} eq 'modifycourse') {
2535: if ($authnum == 1) {
1.784 bisitz 2536: $authtype = '<input type="hidden" name="login" value="loc" />';
1.587 raeburn 2537: }
2538: }
2539: }
1.165 raeburn 2540: }
1.586 raeburn 2541: $jscall = "javascript:changed_radio('loc',$in{'formname'});";
2542: if ($authtype eq '') {
2543: $authtype = '<input type="radio" name="login" value="loc" '.
2544: $loccheck.' onchange="'.$jscall.'" onclick="'.
2545: $jscall.'" />';
2546: }
2547: $autharg = '<input type="text" size="10" name="locarg" value="'.
2548: $locarg.'" onchange="'.$jscall.'" />';
2549: $result = &mt('[_1] Local Authentication with argument [_2]',
2550: '<label>'.$authtype,'</label>'.$autharg);
1.32 matthew 2551: return $result;
2552: }
2553:
2554: sub authform_filesystem{
2555: my %in = (
2556: formname => 'document.cu',
2557: kerb_def_dom => 'MSU.EDU',
2558: @_,
2559: );
1.586 raeburn 2560: my ($fsyscheck,$result,$authtype,$autharg,$jscall);
2561: my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
1.591 raeburn 2562: if (defined($in{'curr_authtype'})) {
2563: if ($in{'curr_authtype'} eq 'fsys') {
1.586 raeburn 2564: if ($can_assign{'fsys'}) {
1.772 bisitz 2565: $fsyscheck = 'checked="checked" ';
1.623 raeburn 2566: if (defined($in{'mode'})) {
2567: if ($in{'mode'} eq 'modifyuser') {
2568: $fsyscheck = '';
2569: }
2570: }
1.586 raeburn 2571: } else {
2572: $result = &mt('Currently Filesystem Authenticated.');
2573: return $result;
2574: }
2575: }
2576: } else {
2577: if ($authnum == 1) {
1.784 bisitz 2578: $authtype = '<input type="hidden" name="login" value="fsys" />';
1.586 raeburn 2579: }
2580: }
2581: if (!$can_assign{'fsys'}) {
2582: return;
1.587 raeburn 2583: } elsif ($authtype eq '') {
1.591 raeburn 2584: if (defined($in{'mode'})) {
1.587 raeburn 2585: if ($in{'mode'} eq 'modifycourse') {
2586: if ($authnum == 1) {
1.784 bisitz 2587: $authtype = '<input type="hidden" name="login" value="fsys" />';
1.587 raeburn 2588: }
2589: }
2590: }
1.586 raeburn 2591: }
2592: $jscall = "javascript:changed_radio('fsys',$in{'formname'});";
2593: if ($authtype eq '') {
2594: $authtype = '<input type="radio" name="login" value="fsys" '.
2595: $fsyscheck.' onchange="'.$jscall.'" onclick="'.
2596: $jscall.'" />';
2597: }
2598: $autharg = '<input type="text" size="10" name="fsysarg" value=""'.
2599: ' onchange="'.$jscall.'" />';
2600: $result = &mt
1.144 matthew 2601: ('[_1] Filesystem Authenticated (with initial password [_2])',
1.281 albertel 2602: '<label><input type="radio" name="login" value="fsys" '.
1.586 raeburn 2603: $fsyscheck.'onchange="'.$jscall.'" onclick="'.$jscall.'" />',
1.605 bisitz 2604: '</label><input type="password" size="10" name="fsysarg" value="" '.
1.144 matthew 2605: 'onchange="'.$jscall.'" />');
1.32 matthew 2606: return $result;
2607: }
2608:
1.586 raeburn 2609: sub get_assignable_auth {
2610: my ($dom) = @_;
2611: if ($dom eq '') {
2612: $dom = $env{'request.role.domain'};
2613: }
2614: my %can_assign = (
2615: krb4 => 1,
2616: krb5 => 1,
2617: int => 1,
2618: loc => 1,
2619: );
2620: my %domconfig = &Apache::lonnet::get_dom('configuration',['usercreation'],$dom);
2621: if (ref($domconfig{'usercreation'}) eq 'HASH') {
2622: if (ref($domconfig{'usercreation'}{'authtypes'}) eq 'HASH') {
2623: my $authhash = $domconfig{'usercreation'}{'authtypes'};
2624: my $context;
2625: if ($env{'request.role'} =~ /^au/) {
2626: $context = 'author';
2627: } elsif ($env{'request.role'} =~ /^dc/) {
2628: $context = 'domain';
2629: } elsif ($env{'request.course.id'}) {
2630: $context = 'course';
2631: }
2632: if ($context) {
2633: if (ref($authhash->{$context}) eq 'HASH') {
2634: %can_assign = %{$authhash->{$context}};
2635: }
2636: }
2637: }
2638: }
2639: my $authnum = 0;
2640: foreach my $key (keys(%can_assign)) {
2641: if ($can_assign{$key}) {
2642: $authnum ++;
2643: }
2644: }
2645: if ($can_assign{'krb4'} && $can_assign{'krb5'}) {
2646: $authnum --;
2647: }
2648: return ($authnum,%can_assign);
2649: }
2650:
1.80 albertel 2651: ###############################################################
2652: ## Get Kerberos Defaults for Domain ##
2653: ###############################################################
2654: ##
2655: ## Returns default kerberos version and an associated argument
2656: ## as listed in file domain.tab. If not listed, provides
2657: ## appropriate default domain and kerberos version.
2658: ##
2659: #-------------------------------------------
2660:
2661: =pod
2662:
1.648 raeburn 2663: =item * &get_kerberos_defaults()
1.80 albertel 2664:
2665: get_kerberos_defaults($target_domain) returns the default kerberos
1.641 raeburn 2666: version and domain. If not found, it defaults to version 4 and the
2667: domain of the server.
1.80 albertel 2668:
1.648 raeburn 2669: =over 4
2670:
1.80 albertel 2671: ($def_version, $def_krb_domain) = &get_kerberos_defaults($target_domain);
2672:
1.648 raeburn 2673: =back
2674:
2675: =back
2676:
1.80 albertel 2677: =cut
2678:
2679: #-------------------------------------------
2680: sub get_kerberos_defaults {
2681: my $domain=shift;
1.641 raeburn 2682: my ($krbdef,$krbdefdom);
2683: my %domdefaults = &Apache::lonnet::get_domain_defaults($domain);
2684: if (($domdefaults{'auth_def'} =~/^krb(4|5)$/) && ($domdefaults{'auth_arg_def'} ne '')) {
2685: $krbdef = $domdefaults{'auth_def'};
2686: $krbdefdom = $domdefaults{'auth_arg_def'};
2687: } else {
1.80 albertel 2688: $ENV{'SERVER_NAME'}=~/(\w+\.\w+)$/;
2689: my $krbdefdom=$1;
2690: $krbdefdom=~tr/a-z/A-Z/;
2691: $krbdef = "krb4";
2692: }
2693: return ($krbdef,$krbdefdom);
2694: }
1.112 bowersj2 2695:
1.32 matthew 2696:
1.46 matthew 2697: ###############################################################
2698: ## Thesaurus Functions ##
2699: ###############################################################
1.20 www 2700:
1.46 matthew 2701: =pod
1.20 www 2702:
1.112 bowersj2 2703: =head1 Thesaurus Functions
2704:
2705: =over 4
2706:
1.648 raeburn 2707: =item * &initialize_keywords()
1.46 matthew 2708:
2709: Initializes the package variable %Keywords if it is empty. Uses the
2710: package variable $thesaurus_db_file.
2711:
2712: =cut
2713:
2714: ###################################################
2715:
2716: sub initialize_keywords {
2717: return 1 if (scalar keys(%Keywords));
2718: # If we are here, %Keywords is empty, so fill it up
2719: # Make sure the file we need exists...
2720: if (! -e $thesaurus_db_file) {
2721: &Apache::lonnet::logthis("Attempt to access $thesaurus_db_file".
2722: " failed because it does not exist");
2723: return 0;
2724: }
2725: # Set up the hash as a database
2726: my %thesaurus_db;
2727: if (! tie(%thesaurus_db,'GDBM_File',
1.53 albertel 2728: $thesaurus_db_file,&GDBM_READER(),0640)){
1.46 matthew 2729: &Apache::lonnet::logthis("Could not tie \%thesaurus_db to ".
2730: $thesaurus_db_file);
2731: return 0;
2732: }
2733: # Get the average number of appearances of a word.
2734: my $avecount = $thesaurus_db{'average.count'};
2735: # Put keywords (those that appear > average) into %Keywords
2736: while (my ($word,$data)=each (%thesaurus_db)) {
2737: my ($count,undef) = split /:/,$data;
2738: $Keywords{$word}++ if ($count > $avecount);
2739: }
2740: untie %thesaurus_db;
2741: # Remove special values from %Keywords.
1.356 albertel 2742: foreach my $value ('total.count','average.count') {
2743: delete($Keywords{$value}) if (exists($Keywords{$value}));
1.586 raeburn 2744: }
1.46 matthew 2745: return 1;
2746: }
2747:
2748: ###################################################
2749:
2750: =pod
2751:
1.648 raeburn 2752: =item * &keyword($word)
1.46 matthew 2753:
2754: Returns true if $word is a keyword. A keyword is a word that appears more
2755: than the average number of times in the thesaurus database. Calls
2756: &initialize_keywords
2757:
2758: =cut
2759:
2760: ###################################################
1.20 www 2761:
2762: sub keyword {
1.46 matthew 2763: return if (!&initialize_keywords());
2764: my $word=lc(shift());
2765: $word=~s/\W//g;
2766: return exists($Keywords{$word});
1.20 www 2767: }
1.46 matthew 2768:
2769: ###############################################################
2770:
2771: =pod
1.20 www 2772:
1.648 raeburn 2773: =item * &get_related_words()
1.46 matthew 2774:
1.160 matthew 2775: Look up a word in the thesaurus. Takes a scalar argument and returns
1.46 matthew 2776: an array of words. If the keyword is not in the thesaurus, an empty array
2777: will be returned. The order of the words returned is determined by the
2778: database which holds them.
2779:
2780: Uses global $thesaurus_db_file.
2781:
2782: =cut
2783:
2784: ###############################################################
2785: sub get_related_words {
2786: my $keyword = shift;
2787: my %thesaurus_db;
2788: if (! -e $thesaurus_db_file) {
2789: &Apache::lonnet::logthis("Attempt to access $thesaurus_db_file ".
2790: "failed because the file does not exist");
2791: return ();
2792: }
2793: if (! tie(%thesaurus_db,'GDBM_File',
1.53 albertel 2794: $thesaurus_db_file,&GDBM_READER(),0640)){
1.46 matthew 2795: return ();
2796: }
2797: my @Words=();
1.429 www 2798: my $count=0;
1.46 matthew 2799: if (exists($thesaurus_db{$keyword})) {
1.356 albertel 2800: # The first element is the number of times
2801: # the word appears. We do not need it now.
1.429 www 2802: my (undef,@RelatedWords) = (split(/:/,$thesaurus_db{$keyword}));
2803: my (undef,$mostfrequentcount)=split(/\,/,$RelatedWords[0]);
2804: my $threshold=$mostfrequentcount/10;
2805: foreach my $possibleword (@RelatedWords) {
2806: my ($word,$wordcount)=split(/\,/,$possibleword);
2807: if ($wordcount>$threshold) {
2808: push(@Words,$word);
2809: $count++;
2810: if ($count>10) { last; }
2811: }
1.20 www 2812: }
2813: }
1.46 matthew 2814: untie %thesaurus_db;
2815: return @Words;
1.14 harris41 2816: }
1.46 matthew 2817:
1.112 bowersj2 2818: =pod
2819:
2820: =back
2821:
2822: =cut
1.61 www 2823:
2824: # -------------------------------------------------------------- Plaintext name
1.81 albertel 2825: =pod
2826:
1.112 bowersj2 2827: =head1 User Name Functions
2828:
2829: =over 4
2830:
1.648 raeburn 2831: =item * &plainname($uname,$udom,$first)
1.81 albertel 2832:
1.112 bowersj2 2833: Takes a users logon name and returns it as a string in
1.226 albertel 2834: "first middle last generation" form
2835: if $first is set to 'lastname' then it returns it as
2836: 'lastname generation, firstname middlename' if their is a lastname
1.81 albertel 2837:
2838: =cut
1.61 www 2839:
1.295 www 2840:
1.81 albertel 2841: ###############################################################
1.61 www 2842: sub plainname {
1.226 albertel 2843: my ($uname,$udom,$first)=@_;
1.537 albertel 2844: return if (!defined($uname) || !defined($udom));
1.295 www 2845: my %names=&getnames($uname,$udom);
1.226 albertel 2846: my $name=&Apache::lonnet::format_name($names{'firstname'},
2847: $names{'middlename'},
2848: $names{'lastname'},
2849: $names{'generation'},$first);
2850: $name=~s/^\s+//;
1.62 www 2851: $name=~s/\s+$//;
2852: $name=~s/\s+/ /g;
1.353 albertel 2853: if ($name !~ /\S/) { $name=$uname.':'.$udom; }
1.62 www 2854: return $name;
1.61 www 2855: }
1.66 www 2856:
2857: # -------------------------------------------------------------------- Nickname
1.81 albertel 2858: =pod
2859:
1.648 raeburn 2860: =item * &nickname($uname,$udom)
1.81 albertel 2861:
2862: Gets a users name and returns it as a string as
2863:
2864: ""nickname""
1.66 www 2865:
1.81 albertel 2866: if the user has a nickname or
2867:
2868: "first middle last generation"
2869:
2870: if the user does not
2871:
2872: =cut
1.66 www 2873:
2874: sub nickname {
2875: my ($uname,$udom)=@_;
1.537 albertel 2876: return if (!defined($uname) || !defined($udom));
1.295 www 2877: my %names=&getnames($uname,$udom);
1.68 albertel 2878: my $name=$names{'nickname'};
1.66 www 2879: if ($name) {
2880: $name='"'.$name.'"';
2881: } else {
2882: $name=$names{'firstname'}.' '.$names{'middlename'}.' '.
2883: $names{'lastname'}.' '.$names{'generation'};
2884: $name=~s/\s+$//;
2885: $name=~s/\s+/ /g;
2886: }
2887: return $name;
2888: }
2889:
1.295 www 2890: sub getnames {
2891: my ($uname,$udom)=@_;
1.537 albertel 2892: return if (!defined($uname) || !defined($udom));
1.433 albertel 2893: if ($udom eq 'public' && $uname eq 'public') {
2894: return ('lastname' => &mt('Public'));
2895: }
1.295 www 2896: my $id=$uname.':'.$udom;
2897: my ($names,$cached)=&Apache::lonnet::is_cached_new('namescache',$id);
2898: if ($cached) {
2899: return %{$names};
2900: } else {
2901: my %loadnames=&Apache::lonnet::get('environment',
2902: ['firstname','middlename','lastname','generation','nickname'],
2903: $udom,$uname);
2904: &Apache::lonnet::do_cache_new('namescache',$id,\%loadnames);
2905: return %loadnames;
2906: }
2907: }
1.61 www 2908:
1.542 raeburn 2909: # -------------------------------------------------------------------- getemails
1.648 raeburn 2910:
1.542 raeburn 2911: =pod
2912:
1.648 raeburn 2913: =item * &getemails($uname,$udom)
1.542 raeburn 2914:
2915: Gets a user's email information and returns it as a hash with keys:
2916: notification, critnotification, permanentemail
2917:
2918: For notification and critnotification, values are comma-separated lists
1.648 raeburn 2919: of e-mail addresses; for permanentemail, value is a single e-mail address.
1.542 raeburn 2920:
1.648 raeburn 2921:
1.542 raeburn 2922: =cut
2923:
1.648 raeburn 2924:
1.466 albertel 2925: sub getemails {
2926: my ($uname,$udom)=@_;
2927: if ($udom eq 'public' && $uname eq 'public') {
2928: return;
2929: }
1.467 www 2930: if (!$udom) { $udom=$env{'user.domain'}; }
2931: if (!$uname) { $uname=$env{'user.name'}; }
1.466 albertel 2932: my $id=$uname.':'.$udom;
2933: my ($names,$cached)=&Apache::lonnet::is_cached_new('emailscache',$id);
2934: if ($cached) {
2935: return %{$names};
2936: } else {
2937: my %loadnames=&Apache::lonnet::get('environment',
2938: ['notification','critnotification',
2939: 'permanentemail'],
2940: $udom,$uname);
2941: &Apache::lonnet::do_cache_new('emailscache',$id,\%loadnames);
2942: return %loadnames;
2943: }
2944: }
2945:
1.551 albertel 2946: sub flush_email_cache {
2947: my ($uname,$udom)=@_;
2948: if (!$udom) { $udom =$env{'user.domain'}; }
2949: if (!$uname) { $uname=$env{'user.name'}; }
2950: return if ($udom eq 'public' && $uname eq 'public');
2951: my $id=$uname.':'.$udom;
2952: &Apache::lonnet::devalidate_cache_new('emailscache',$id);
2953: }
2954:
1.728 raeburn 2955: # -------------------------------------------------------------------- getlangs
2956:
2957: =pod
2958:
2959: =item * &getlangs($uname,$udom)
2960:
2961: Gets a user's language preference and returns it as a hash with key:
2962: language.
2963:
2964: =cut
2965:
2966:
2967: sub getlangs {
2968: my ($uname,$udom) = @_;
2969: if (!$udom) { $udom =$env{'user.domain'}; }
2970: if (!$uname) { $uname=$env{'user.name'}; }
2971: my $id=$uname.':'.$udom;
2972: my ($langs,$cached)=&Apache::lonnet::is_cached_new('userlangs',$id);
2973: if ($cached) {
2974: return %{$langs};
2975: } else {
2976: my %loadlangs=&Apache::lonnet::get('environment',['languages'],
2977: $udom,$uname);
2978: &Apache::lonnet::do_cache_new('userlangs',$id,\%loadlangs);
2979: return %loadlangs;
2980: }
2981: }
2982:
2983: sub flush_langs_cache {
2984: my ($uname,$udom)=@_;
2985: if (!$udom) { $udom =$env{'user.domain'}; }
2986: if (!$uname) { $uname=$env{'user.name'}; }
2987: return if ($udom eq 'public' && $uname eq 'public');
2988: my $id=$uname.':'.$udom;
2989: &Apache::lonnet::devalidate_cache_new('userlangs',$id);
2990: }
2991:
1.61 www 2992: # ------------------------------------------------------------------ Screenname
1.81 albertel 2993:
2994: =pod
2995:
1.648 raeburn 2996: =item * &screenname($uname,$udom)
1.81 albertel 2997:
2998: Gets a users screenname and returns it as a string
2999:
3000: =cut
1.61 www 3001:
3002: sub screenname {
3003: my ($uname,$udom)=@_;
1.258 albertel 3004: if ($uname eq $env{'user.name'} &&
3005: $udom eq $env{'user.domain'}) {return $env{'environment.screenname'};}
1.212 albertel 3006: my %names=&Apache::lonnet::get('environment',['screenname'],$udom,$uname);
1.68 albertel 3007: return $names{'screenname'};
1.62 www 3008: }
3009:
1.212 albertel 3010:
1.802 bisitz 3011: # ------------------------------------------------------------- Confirm Wrapper
3012: =pod
3013:
3014: =item confirmwrapper
3015:
3016: Wrap messages about completion of operation in box
3017:
3018: =cut
3019:
3020: sub confirmwrapper {
3021: my ($message)=@_;
3022: if ($message) {
3023: return "\n".'<div class="LC_confirm_box">'."\n"
3024: .$message."\n"
3025: .'</div>'."\n";
3026: } else {
3027: return $message;
3028: }
3029: }
3030:
1.62 www 3031: # ------------------------------------------------------------- Message Wrapper
3032:
3033: sub messagewrapper {
1.369 www 3034: my ($link,$username,$domain,$subject,$text)=@_;
1.62 www 3035: return
1.441 albertel 3036: '<a href="/adm/email?compose=individual&'.
3037: 'recname='.$username.'&recdom='.$domain.
3038: '&subject='.&escape($subject).'&text='.&escape($text).'" '.
1.200 matthew 3039: 'title="'.&mt('Send message').'">'.$link.'</a>';
1.74 www 3040: }
1.802 bisitz 3041:
1.74 www 3042: # --------------------------------------------------------------- Notes Wrapper
3043:
3044: sub noteswrapper {
3045: my ($link,$un,$do)=@_;
3046: return
1.896 amueller 3047: "<a href='/adm/email?recordftf=retrieve&recname=$un&recdom=$do'>$link</a>";
1.62 www 3048: }
1.802 bisitz 3049:
1.62 www 3050: # ------------------------------------------------------------- Aboutme Wrapper
3051:
3052: sub aboutmewrapper {
1.166 www 3053: my ($link,$username,$domain,$target)=@_;
1.447 raeburn 3054: if (!defined($username) && !defined($domain)) {
3055: return;
3056: }
1.892 amueller 3057: return '<a href="/adm/'.$domain.'/'.$username.'/aboutme?forcestudent=1"'.
1.756 weissno 3058: ($target?' target="$target"':'').' title="'.&mt("View this user's personal information page").'">'.$link.'</a>';
1.62 www 3059: }
3060:
3061: # ------------------------------------------------------------ Syllabus Wrapper
3062:
3063: sub syllabuswrapper {
1.707 bisitz 3064: my ($linktext,$coursedir,$domain)=@_;
1.208 matthew 3065: return qq{<a href="/public/$domain/$coursedir/syllabus">$linktext</a>};
1.61 www 3066: }
1.14 harris41 3067:
1.802 bisitz 3068: # -----------------------------------------------------------------------------
3069:
1.208 matthew 3070: sub track_student_link {
1.887 raeburn 3071: my ($linktext,$sname,$sdom,$target,$start,$only_body) = @_;
1.268 albertel 3072: my $link ="/adm/trackstudent?";
1.208 matthew 3073: my $title = 'View recent activity';
3074: if (defined($sname) && $sname !~ /^\s*$/ &&
3075: defined($sdom) && $sdom !~ /^\s*$/) {
1.268 albertel 3076: $link .= "selected_student=$sname:$sdom";
1.208 matthew 3077: $title .= ' of this student';
1.268 albertel 3078: }
1.208 matthew 3079: if (defined($target) && $target !~ /^\s*$/) {
3080: $target = qq{target="$target"};
3081: } else {
3082: $target = '';
3083: }
1.268 albertel 3084: if ($start) { $link.='&start='.$start; }
1.887 raeburn 3085: if ($only_body) { $link .= '&only_body=1'; }
1.554 albertel 3086: $title = &mt($title);
3087: $linktext = &mt($linktext);
1.448 albertel 3088: return qq{<a href="$link" title="$title" $target>$linktext</a>}.
3089: &help_open_topic('View_recent_activity');
1.208 matthew 3090: }
3091:
1.781 raeburn 3092: sub slot_reservations_link {
3093: my ($linktext,$sname,$sdom,$target) = @_;
3094: my $link ="/adm/slotrequest?command=showresv&origin=aboutme";
3095: my $title = 'View slot reservation history';
3096: if (defined($sname) && $sname !~ /^\s*$/ &&
3097: defined($sdom) && $sdom !~ /^\s*$/) {
3098: $link .= "&uname=$sname&udom=$sdom";
3099: $title .= ' of this student';
3100: }
3101: if (defined($target) && $target !~ /^\s*$/) {
3102: $target = qq{target="$target"};
3103: } else {
3104: $target = '';
3105: }
3106: $title = &mt($title);
3107: $linktext = &mt($linktext);
3108: return qq{<a href="$link" title="$title" $target>$linktext</a>};
3109: # FIXME uncomment when help item created: &help_open_topic('Slot_Reservation_History');
3110:
3111: }
3112:
1.508 www 3113: # ===================================================== Display a student photo
3114:
3115:
1.509 albertel 3116: sub student_image_tag {
1.508 www 3117: my ($domain,$user)=@_;
3118: my $imgsrc=&Apache::lonnet::studentphoto($domain,$user,'jpg');
3119: if (($imgsrc) && ($imgsrc ne '/adm/lonKaputt/lonlogo_broken.gif')) {
3120: return '<img src="'.$imgsrc.'" align="right" />';
3121: } else {
3122: return '';
3123: }
3124: }
3125:
1.112 bowersj2 3126: =pod
3127:
3128: =back
3129:
3130: =head1 Access .tab File Data
3131:
3132: =over 4
3133:
1.648 raeburn 3134: =item * &languageids()
1.112 bowersj2 3135:
3136: returns list of all language ids
3137:
3138: =cut
3139:
1.14 harris41 3140: sub languageids {
1.16 harris41 3141: return sort(keys(%language));
1.14 harris41 3142: }
3143:
1.112 bowersj2 3144: =pod
3145:
1.648 raeburn 3146: =item * &languagedescription()
1.112 bowersj2 3147:
3148: returns description of a specified language id
3149:
3150: =cut
3151:
1.14 harris41 3152: sub languagedescription {
1.125 www 3153: my $code=shift;
3154: return ($supported_language{$code}?'* ':'').
3155: $language{$code}.
1.126 www 3156: ($supported_language{$code}?' ('.&mt('interface available').')':'');
1.145 www 3157: }
3158:
3159: sub plainlanguagedescription {
3160: my $code=shift;
3161: return $language{$code};
3162: }
3163:
3164: sub supportedlanguagecode {
3165: my $code=shift;
3166: return $supported_language{$code};
1.97 www 3167: }
3168:
1.112 bowersj2 3169: =pod
3170:
1.648 raeburn 3171: =item * ©rightids()
1.112 bowersj2 3172:
3173: returns list of all copyrights
3174:
3175: =cut
3176:
3177: sub copyrightids {
3178: return sort(keys(%cprtag));
3179: }
3180:
3181: =pod
3182:
1.648 raeburn 3183: =item * ©rightdescription()
1.112 bowersj2 3184:
3185: returns description of a specified copyright id
3186:
3187: =cut
3188:
3189: sub copyrightdescription {
1.166 www 3190: return &mt($cprtag{shift(@_)});
1.112 bowersj2 3191: }
1.197 matthew 3192:
3193: =pod
3194:
1.648 raeburn 3195: =item * &source_copyrightids()
1.192 taceyjo1 3196:
3197: returns list of all source copyrights
3198:
3199: =cut
3200:
3201: sub source_copyrightids {
3202: return sort(keys(%scprtag));
3203: }
3204:
3205: =pod
3206:
1.648 raeburn 3207: =item * &source_copyrightdescription()
1.192 taceyjo1 3208:
3209: returns description of a specified source copyright id
3210:
3211: =cut
3212:
3213: sub source_copyrightdescription {
3214: return &mt($scprtag{shift(@_)});
3215: }
1.112 bowersj2 3216:
3217: =pod
3218:
1.648 raeburn 3219: =item * &filecategories()
1.112 bowersj2 3220:
3221: returns list of all file categories
3222:
3223: =cut
3224:
3225: sub filecategories {
3226: return sort(keys(%category_extensions));
3227: }
3228:
3229: =pod
3230:
1.648 raeburn 3231: =item * &filecategorytypes()
1.112 bowersj2 3232:
3233: returns list of file types belonging to a given file
3234: category
3235:
3236: =cut
3237:
3238: sub filecategorytypes {
1.356 albertel 3239: my ($cat) = @_;
3240: return @{$category_extensions{lc($cat)}};
1.112 bowersj2 3241: }
3242:
3243: =pod
3244:
1.648 raeburn 3245: =item * &fileembstyle()
1.112 bowersj2 3246:
3247: returns embedding style for a specified file type
3248:
3249: =cut
3250:
3251: sub fileembstyle {
3252: return $fe{lc(shift(@_))};
1.169 www 3253: }
3254:
1.351 www 3255: sub filemimetype {
3256: return $fm{lc(shift(@_))};
3257: }
3258:
1.169 www 3259:
3260: sub filecategoryselect {
3261: my ($name,$value)=@_;
1.189 matthew 3262: return &select_form($value,$name,
1.169 www 3263: '' => &mt('Any category'),
1.948.2.7 raeburn 3264: {'' => &mt('Any category'), map { $_,$_ } sort(keys(%category_extensions))});
1.112 bowersj2 3265: }
3266:
3267: =pod
3268:
1.648 raeburn 3269: =item * &filedescription()
1.112 bowersj2 3270:
3271: returns description for a specified file type
3272:
3273: =cut
3274:
3275: sub filedescription {
1.188 matthew 3276: my $file_description = $fd{lc(shift())};
3277: $file_description =~ s:([\[\]]):~$1:g;
3278: return &mt($file_description);
1.112 bowersj2 3279: }
3280:
3281: =pod
3282:
1.648 raeburn 3283: =item * &filedescriptionex()
1.112 bowersj2 3284:
3285: returns description for a specified file type with
3286: extra formatting
3287:
3288: =cut
3289:
3290: sub filedescriptionex {
3291: my $ex=shift;
1.188 matthew 3292: my $file_description = $fd{lc($ex)};
3293: $file_description =~ s:([\[\]]):~$1:g;
3294: return '.'.$ex.' '.&mt($file_description);
1.112 bowersj2 3295: }
3296:
3297: # End of .tab access
3298: =pod
3299:
3300: =back
3301:
3302: =cut
3303:
3304: # ------------------------------------------------------------------ File Types
3305: sub fileextensions {
3306: return sort(keys(%fe));
3307: }
3308:
1.97 www 3309: # ----------------------------------------------------------- Display Languages
3310: # returns a hash with all desired display languages
3311: #
3312:
3313: sub display_languages {
3314: my %languages=();
1.695 raeburn 3315: foreach my $lang (&Apache::lonlocal::preferred_languages()) {
1.356 albertel 3316: $languages{$lang}=1;
1.97 www 3317: }
3318: &get_unprocessed_cgi($ENV{'QUERY_STRING'},['displaylanguage']);
1.258 albertel 3319: if ($env{'form.displaylanguage'}) {
1.356 albertel 3320: foreach my $lang (split(/\s*(\,|\;|\:)\s*/,$env{'form.displaylanguage'})) {
3321: $languages{$lang}=1;
1.97 www 3322: }
3323: }
3324: return %languages;
1.14 harris41 3325: }
3326:
1.582 albertel 3327: sub languages {
3328: my ($possible_langs) = @_;
1.695 raeburn 3329: my @preferred_langs = &Apache::lonlocal::preferred_languages();
1.582 albertel 3330: if (!ref($possible_langs)) {
3331: if( wantarray ) {
3332: return @preferred_langs;
3333: } else {
3334: return $preferred_langs[0];
3335: }
3336: }
3337: my %possibilities = map { $_ => 1 } (@$possible_langs);
3338: my @preferred_possibilities;
3339: foreach my $preferred_lang (@preferred_langs) {
3340: if (exists($possibilities{$preferred_lang})) {
3341: push(@preferred_possibilities, $preferred_lang);
3342: }
3343: }
3344: if( wantarray ) {
3345: return @preferred_possibilities;
3346: }
3347: return $preferred_possibilities[0];
3348: }
3349:
1.742 raeburn 3350: sub user_lang {
3351: my ($touname,$toudom,$fromcid) = @_;
3352: my @userlangs;
3353: if (($fromcid ne '') && ($env{'course.'.$fromcid.'.languages'} ne '')) {
3354: @userlangs=(@userlangs,split(/\s*(\,|\;|\:)\s*/,
3355: $env{'course.'.$fromcid.'.languages'}));
3356: } else {
3357: my %langhash = &getlangs($touname,$toudom);
3358: if ($langhash{'languages'} ne '') {
3359: @userlangs = split(/\s*(\,|\;|\:)\s*/,$langhash{'languages'});
3360: } else {
3361: my %domdefs = &Apache::lonnet::get_domain_defaults($toudom);
3362: if ($domdefs{'lang_def'} ne '') {
3363: @userlangs = ($domdefs{'lang_def'});
3364: }
3365: }
3366: }
3367: my @languages=&Apache::lonlocal::get_genlanguages(@userlangs);
3368: my $user_lh = Apache::localize->get_handle(@languages);
3369: return $user_lh;
3370: }
3371:
3372:
1.112 bowersj2 3373: ###############################################################
3374: ## Student Answer Attempts ##
3375: ###############################################################
3376:
3377: =pod
3378:
3379: =head1 Alternate Problem Views
3380:
3381: =over 4
3382:
1.648 raeburn 3383: =item * &get_previous_attempt($symb, $username, $domain, $course,
1.112 bowersj2 3384: $getattempt, $regexp, $gradesub)
3385:
3386: Return string with previous attempt on problem. Arguments:
3387:
3388: =over 4
3389:
3390: =item * $symb: Problem, including path
3391:
3392: =item * $username: username of the desired student
3393:
3394: =item * $domain: domain of the desired student
1.14 harris41 3395:
1.112 bowersj2 3396: =item * $course: Course ID
1.14 harris41 3397:
1.112 bowersj2 3398: =item * $getattempt: Leave blank for all attempts, otherwise put
3399: something
1.14 harris41 3400:
1.112 bowersj2 3401: =item * $regexp: if string matches this regexp, the string will be
3402: sent to $gradesub
1.14 harris41 3403:
1.112 bowersj2 3404: =item * $gradesub: routine that processes the string if it matches $regexp
1.14 harris41 3405:
1.112 bowersj2 3406: =back
1.14 harris41 3407:
1.112 bowersj2 3408: The output string is a table containing all desired attempts, if any.
1.16 harris41 3409:
1.112 bowersj2 3410: =cut
1.1 albertel 3411:
3412: sub get_previous_attempt {
1.43 ng 3413: my ($symb,$username,$domain,$course,$getattempt,$regexp,$gradesub)=@_;
1.1 albertel 3414: my $prevattempts='';
1.43 ng 3415: no strict 'refs';
1.1 albertel 3416: if ($symb) {
1.3 albertel 3417: my (%returnhash)=
3418: &Apache::lonnet::restore($symb,$course,$domain,$username);
1.1 albertel 3419: if ($returnhash{'version'}) {
3420: my %lasthash=();
3421: my $version;
3422: for ($version=1;$version<=$returnhash{'version'};$version++) {
1.356 albertel 3423: foreach my $key (sort(split(/\:/,$returnhash{$version.':keys'}))) {
3424: $lasthash{$key}=$returnhash{$version.':'.$key};
1.19 harris41 3425: }
1.1 albertel 3426: }
1.596 albertel 3427: $prevattempts=&start_data_table().&start_data_table_header_row();
3428: $prevattempts.='<th>'.&mt('History').'</th>';
1.948.2.8 raeburn 3429: my (%typeparts,%lasthidden);
1.945 raeburn 3430: my $showsurv=&Apache::lonnet::allowed('vas',$env{'request.course.id'});
1.356 albertel 3431: foreach my $key (sort(keys(%lasthash))) {
3432: my ($ign,@parts) = split(/\./,$key);
1.41 ng 3433: if ($#parts > 0) {
1.31 albertel 3434: my $data=$parts[-1];
1.948.2.15 raeburn 3435: next if ($data eq 'foilorder');
1.31 albertel 3436: pop(@parts);
1.945 raeburn 3437: if ($data eq 'type') {
3438: unless ($showsurv) {
3439: my $id = join(',',@parts);
3440: $typeparts{$ign.'.'.$id} = $lasthash{$key};
1.948.2.8 raeburn 3441: if (($lasthash{$key} eq 'anonsurvey') || ($lasthash{$key} eq 'anonsurveycred')) {
3442: $lasthidden{$ign.'.'.$id} = 1;
3443: }
1.945 raeburn 3444: }
3445: delete($lasthash{$key});
3446: } else {
3447: $prevattempts.='<th>'.&mt('Part ').join('.',@parts).'<br />'.$data.' </th>';
3448: }
1.31 albertel 3449: } else {
1.41 ng 3450: if ($#parts == 0) {
3451: $prevattempts.='<th>'.$parts[0].'</th>';
3452: } else {
3453: $prevattempts.='<th>'.$ign.'</th>';
3454: }
1.31 albertel 3455: }
1.16 harris41 3456: }
1.596 albertel 3457: $prevattempts.=&end_data_table_header_row();
1.40 ng 3458: if ($getattempt eq '') {
3459: for ($version=1;$version<=$returnhash{'version'};$version++) {
1.945 raeburn 3460: my @hidden;
3461: if (%typeparts) {
3462: foreach my $id (keys(%typeparts)) {
3463: if (($returnhash{$version.':'.$id.'.type'} eq 'anonsurvey') || ($returnhash{$version.':'.$id.'.type'} eq 'anonsurveycred')) {
3464: push(@hidden,$id);
3465: }
3466: }
3467: }
3468: $prevattempts.=&start_data_table_row().
3469: '<td>'.&mt('Transaction [_1]',$version).'</td>';
3470: if (@hidden) {
3471: foreach my $key (sort(keys(%lasthash))) {
1.948.2.15 raeburn 3472: next if ($key =~ /\.foilorder$/);
1.945 raeburn 3473: my $hide;
3474: foreach my $id (@hidden) {
3475: if ($key =~ /^\Q$id\E/) {
3476: $hide = 1;
3477: last;
3478: }
3479: }
3480: if ($hide) {
3481: my ($id,$data) = ($key =~ /^(.+)\.([^.]+)$/);
3482: if (($data eq 'award') || ($data eq 'awarddetail')) {
3483: my $value = &format_previous_attempt_value($key,
3484: $returnhash{$version.':'.$key});
3485: $prevattempts.='<td>'.$value.' </td>';
3486: } else {
3487: $prevattempts.='<td> </td>';
3488: }
3489: } else {
3490: if ($key =~ /\./) {
3491: my $value = &format_previous_attempt_value($key,
3492: $returnhash{$version.':'.$key});
3493: $prevattempts.='<td>'.$value.' </td>';
3494: } else {
3495: $prevattempts.='<td> </td>';
3496: }
3497: }
3498: }
3499: } else {
3500: foreach my $key (sort(keys(%lasthash))) {
1.948.2.15 raeburn 3501: next if ($key =~ /\.foilorder$/);
1.945 raeburn 3502: my $value = &format_previous_attempt_value($key,
3503: $returnhash{$version.':'.$key});
3504: $prevattempts.='<td>'.$value.' </td>';
3505: }
3506: }
3507: $prevattempts.=&end_data_table_row();
1.40 ng 3508: }
1.1 albertel 3509: }
1.945 raeburn 3510: my @currhidden = keys(%lasthidden);
1.596 albertel 3511: $prevattempts.=&start_data_table_row().'<td>'.&mt('Current').'</td>';
1.356 albertel 3512: foreach my $key (sort(keys(%lasthash))) {
1.948.2.15 raeburn 3513: next if ($key =~ /\.foilorder$/);
1.945 raeburn 3514: if (%typeparts) {
3515: my $hidden;
3516: foreach my $id (@currhidden) {
3517: if ($key =~ /^\Q$id\E/) {
3518: $hidden = 1;
3519: last;
3520: }
3521: }
3522: if ($hidden) {
3523: my ($id,$data) = ($key =~ /^(.+)\.([^.]+)$/);
3524: if (($data eq 'award') || ($data eq 'awarddetail')) {
3525: my $value = &format_previous_attempt_value($key,$lasthash{$key});
3526: if ($key =~/$regexp$/ && (defined &$gradesub)) {
3527: $value = &$gradesub($value);
3528: }
3529: $prevattempts.='<td>'.$value.' </td>';
3530: } else {
3531: $prevattempts.='<td> </td>';
3532: }
3533: } else {
3534: my $value = &format_previous_attempt_value($key,$lasthash{$key});
3535: if ($key =~/$regexp$/ && (defined &$gradesub)) {
3536: $value = &$gradesub($value);
3537: }
3538: $prevattempts.='<td>'.$value.' </td>';
3539: }
3540: } else {
3541: my $value = &format_previous_attempt_value($key,$lasthash{$key});
3542: if ($key =~/$regexp$/ && (defined &$gradesub)) {
3543: $value = &$gradesub($value);
3544: }
3545: $prevattempts.='<td>'.$value.' </td>';
3546: }
1.16 harris41 3547: }
1.596 albertel 3548: $prevattempts.= &end_data_table_row().&end_data_table();
1.1 albertel 3549: } else {
1.596 albertel 3550: $prevattempts=
3551: &start_data_table().&start_data_table_row().
3552: '<td>'.&mt('Nothing submitted - no attempts.').'</td>'.
3553: &end_data_table_row().&end_data_table();
1.1 albertel 3554: }
3555: } else {
1.596 albertel 3556: $prevattempts=
3557: &start_data_table().&start_data_table_row().
3558: '<td>'.&mt('No data.').'</td>'.
3559: &end_data_table_row().&end_data_table();
1.1 albertel 3560: }
1.10 albertel 3561: }
3562:
1.581 albertel 3563: sub format_previous_attempt_value {
3564: my ($key,$value) = @_;
3565: if ($key =~ /timestamp/) {
3566: $value = &Apache::lonlocal::locallocaltime($value);
3567: } elsif (ref($value) eq 'ARRAY') {
3568: $value = '('.join(', ', @{ $value }).')';
1.948.2.14 raeburn 3569: } elsif ($key =~ /answerstring$/) {
3570: my %answers = &Apache::lonnet::str2hash($value);
3571: my @anskeys = sort(keys(%answers));
3572: if (@anskeys == 1) {
3573: my $answer = $answers{$anskeys[0]};
3574: if ($answer =~ m{\Q\0\E}) {
3575: $answer =~ s{\Q\0\E}{, }g;
3576: }
3577: my $tag_internal_answer_name = 'INTERNAL';
3578: if ($anskeys[0] eq $tag_internal_answer_name) {
3579: $value = $answer;
3580: } else {
3581: $value = $anskeys[0].'='.$answer;
3582: }
3583: } else {
3584: foreach my $ans (@anskeys) {
3585: my $answer = $answers{$ans};
3586: if ($answer =~ m{\Q\0\E}) {
3587: $answer =~ s{\Q\0\E}{, }g;
3588: }
3589: $value .= $ans.'='.$answer.'<br />';;
3590: }
3591: }
1.581 albertel 3592: } else {
3593: $value = &unescape($value);
3594: }
3595: return $value;
3596: }
3597:
3598:
1.107 albertel 3599: sub relative_to_absolute {
3600: my ($url,$output)=@_;
3601: my $parser=HTML::TokeParser->new(\$output);
3602: my $token;
3603: my $thisdir=$url;
3604: my @rlinks=();
3605: while ($token=$parser->get_token) {
3606: if ($token->[0] eq 'S') {
3607: if ($token->[1] eq 'a') {
3608: if ($token->[2]->{'href'}) {
3609: $rlinks[$#rlinks+1]=$token->[2]->{'href'};
3610: }
3611: } elsif ($token->[1] eq 'img' || $token->[1] eq 'embed' ) {
3612: $rlinks[$#rlinks+1]=$token->[2]->{'src'};
3613: } elsif ($token->[1] eq 'base') {
3614: $thisdir=$token->[2]->{'href'};
3615: }
3616: }
3617: }
3618: $thisdir=~s-/[^/]*$--;
1.356 albertel 3619: foreach my $link (@rlinks) {
1.726 raeburn 3620: unless (($link=~/^https?\:\/\//i) ||
1.356 albertel 3621: ($link=~/^\//) ||
3622: ($link=~/^javascript:/i) ||
3623: ($link=~/^mailto:/i) ||
3624: ($link=~/^\#/)) {
3625: my $newlocation=&Apache::lonnet::hreflocation($thisdir,$link);
3626: $output=~s/(\"|\'|\=\s*)\Q$link\E(\"|\'|\s|\>)/$1$newlocation$2/;
1.107 albertel 3627: }
3628: }
3629: # -------------------------------------------------- Deal with Applet codebases
3630: $output=~s/(\<applet[^\>]+)(codebase\=[^\S\>]+)*([^\>]*)\>/$1.($2?$2:' codebase="'.$thisdir.'"').$3.'>'/gei;
3631: return $output;
3632: }
3633:
1.112 bowersj2 3634: =pod
3635:
1.648 raeburn 3636: =item * &get_student_view()
1.112 bowersj2 3637:
3638: show a snapshot of what student was looking at
3639:
3640: =cut
3641:
1.10 albertel 3642: sub get_student_view {
1.186 albertel 3643: my ($symb,$username,$domain,$courseid,$target,$moreenv) = @_;
1.114 www 3644: my ($map,$id,$feedurl) = &Apache::lonnet::decode_symb($symb);
1.186 albertel 3645: my (%form);
1.10 albertel 3646: my @elements=('symb','courseid','domain','username');
3647: foreach my $element (@elements) {
1.186 albertel 3648: $form{'grade_'.$element}=eval '$'.$element #'
1.10 albertel 3649: }
1.186 albertel 3650: if (defined($moreenv)) {
3651: %form=(%form,%{$moreenv});
3652: }
1.236 albertel 3653: if (defined($target)) { $form{'grade_target'} = $target; }
1.107 albertel 3654: $feedurl=&Apache::lonnet::clutter($feedurl);
1.650 www 3655: my ($userview,$response)=&Apache::lonnet::ssi_body($feedurl,%form);
1.11 albertel 3656: $userview=~s/\<body[^\>]*\>//gi;
3657: $userview=~s/\<\/body\>//gi;
3658: $userview=~s/\<html\>//gi;
3659: $userview=~s/\<\/html\>//gi;
3660: $userview=~s/\<head\>//gi;
3661: $userview=~s/\<\/head\>//gi;
3662: $userview=~s/action\s*\=/would_be_action\=/gi;
1.107 albertel 3663: $userview=&relative_to_absolute($feedurl,$userview);
1.650 www 3664: if (wantarray) {
3665: return ($userview,$response);
3666: } else {
3667: return $userview;
3668: }
3669: }
3670:
3671: sub get_student_view_with_retries {
3672: my ($symb,$retries,$username,$domain,$courseid,$target,$moreenv) = @_;
3673:
3674: my $ok = 0; # True if we got a good response.
3675: my $content;
3676: my $response;
3677:
3678: # Try to get the student_view done. within the retries count:
3679:
3680: do {
3681: ($content, $response) = &get_student_view($symb,$username,$domain,$courseid,$target,$moreenv);
3682: $ok = $response->is_success;
3683: if (!$ok) {
3684: &Apache::lonnet::logthis("Failed get_student_view_with_retries on $symb: ".$response->is_success.', '.$response->code.', '.$response->message);
3685: }
3686: $retries--;
3687: } while (!$ok && ($retries > 0));
3688:
3689: if (!$ok) {
3690: $content = ''; # On error return an empty content.
3691: }
1.651 www 3692: if (wantarray) {
3693: return ($content, $response);
3694: } else {
3695: return $content;
3696: }
1.11 albertel 3697: }
3698:
1.112 bowersj2 3699: =pod
3700:
1.648 raeburn 3701: =item * &get_student_answers()
1.112 bowersj2 3702:
3703: show a snapshot of how student was answering problem
3704:
3705: =cut
3706:
1.11 albertel 3707: sub get_student_answers {
1.100 sakharuk 3708: my ($symb,$username,$domain,$courseid,%form) = @_;
1.114 www 3709: my ($map,$id,$feedurl) = &Apache::lonnet::decode_symb($symb);
1.186 albertel 3710: my (%moreenv);
1.11 albertel 3711: my @elements=('symb','courseid','domain','username');
3712: foreach my $element (@elements) {
1.186 albertel 3713: $moreenv{'grade_'.$element}=eval '$'.$element #'
1.10 albertel 3714: }
1.186 albertel 3715: $moreenv{'grade_target'}='answer';
3716: %moreenv=(%form,%moreenv);
1.497 raeburn 3717: $feedurl = &Apache::lonnet::clutter($feedurl);
3718: my $userview=&Apache::lonnet::ssi($feedurl,%moreenv);
1.10 albertel 3719: return $userview;
1.1 albertel 3720: }
1.116 albertel 3721:
3722: =pod
3723:
3724: =item * &submlink()
3725:
1.242 albertel 3726: Inputs: $text $uname $udom $symb $target
1.116 albertel 3727:
3728: Returns: A link to grades.pm such as to see the SUBM view of a student
3729:
3730: =cut
3731:
3732: ###############################################
3733: sub submlink {
1.242 albertel 3734: my ($text,$uname,$udom,$symb,$target)=@_;
1.116 albertel 3735: if (!($uname && $udom)) {
3736: (my $cursymb, my $courseid,$udom,$uname)=
1.463 albertel 3737: &Apache::lonnet::whichuser($symb);
1.116 albertel 3738: if (!$symb) { $symb=$cursymb; }
3739: }
1.254 matthew 3740: if (!$symb) { $symb=&Apache::lonnet::symbread(); }
1.369 www 3741: $symb=&escape($symb);
1.948.2.4 raeburn 3742: if ($target) { $target=" target=\"$target\""; }
3743: return
3744: '<a href="/adm/grades?command=submission'.
3745: '&symb='.$symb.
3746: '&student='.$uname.
3747: '&userdom='.$udom.'"'.
3748: $target.'>'.$text.'</a>';
1.242 albertel 3749: }
3750: ##############################################
3751:
3752: =pod
3753:
3754: =item * &pgrdlink()
3755:
3756: Inputs: $text $uname $udom $symb $target
3757:
3758: Returns: A link to grades.pm such as to see the PGRD view of a student
3759:
3760: =cut
3761:
3762: ###############################################
3763: sub pgrdlink {
3764: my $link=&submlink(@_);
3765: $link=~s/(&command=submission)/$1&showgrading=yes/;
3766: return $link;
3767: }
3768: ##############################################
3769:
3770: =pod
3771:
3772: =item * &pprmlink()
3773:
3774: Inputs: $text $uname $udom $symb $target
3775:
3776: Returns: A link to parmset.pm such as to see the PPRM view of a
1.283 albertel 3777: student and a specific resource
1.242 albertel 3778:
3779: =cut
3780:
3781: ###############################################
3782: sub pprmlink {
3783: my ($text,$uname,$udom,$symb,$target)=@_;
3784: if (!($uname && $udom)) {
3785: (my $cursymb, my $courseid,$udom,$uname)=
1.463 albertel 3786: &Apache::lonnet::whichuser($symb);
1.242 albertel 3787: if (!$symb) { $symb=$cursymb; }
3788: }
1.254 matthew 3789: if (!$symb) { $symb=&Apache::lonnet::symbread(); }
1.369 www 3790: $symb=&escape($symb);
1.242 albertel 3791: if ($target) { $target="target=\"$target\""; }
1.595 albertel 3792: return '<a href="/adm/parmset?command=set&'.
3793: 'symb='.$symb.'&uname='.$uname.
3794: '&udom='.$udom.'" '.$target.'>'.$text.'</a>';
1.116 albertel 3795: }
3796: ##############################################
1.37 matthew 3797:
1.112 bowersj2 3798: =pod
3799:
3800: =back
3801:
3802: =cut
3803:
1.37 matthew 3804: ###############################################
1.51 www 3805:
3806:
3807: sub timehash {
1.687 raeburn 3808: my ($thistime) = @_;
3809: my $timezone = &Apache::lonlocal::gettimezone();
3810: my $dt = DateTime->from_epoch(epoch => $thistime)
3811: ->set_time_zone($timezone);
3812: my $wday = $dt->day_of_week();
3813: if ($wday == 7) { $wday = 0; }
3814: return ( 'second' => $dt->second(),
3815: 'minute' => $dt->minute(),
3816: 'hour' => $dt->hour(),
3817: 'day' => $dt->day_of_month(),
3818: 'month' => $dt->month(),
3819: 'year' => $dt->year(),
3820: 'weekday' => $wday,
3821: 'dayyear' => $dt->day_of_year(),
3822: 'dlsav' => $dt->is_dst() );
1.51 www 3823: }
3824:
1.370 www 3825: sub utc_string {
3826: my ($date)=@_;
1.371 www 3827: return strftime("%Y%m%dT%H%M%SZ",gmtime($date));
1.370 www 3828: }
3829:
1.51 www 3830: sub maketime {
3831: my %th=@_;
1.687 raeburn 3832: my ($epoch_time,$timezone,$dt);
3833: $timezone = &Apache::lonlocal::gettimezone();
3834: eval {
3835: $dt = DateTime->new( year => $th{'year'},
3836: month => $th{'month'},
3837: day => $th{'day'},
3838: hour => $th{'hour'},
3839: minute => $th{'minute'},
3840: second => $th{'second'},
3841: time_zone => $timezone,
3842: );
3843: };
3844: if (!$@) {
3845: $epoch_time = $dt->epoch;
3846: if ($epoch_time) {
3847: return $epoch_time;
3848: }
3849: }
1.51 www 3850: return POSIX::mktime(
3851: ($th{'seconds'},$th{'minutes'},$th{'hours'},
1.210 www 3852: $th{'day'},$th{'month'}-1,$th{'year'}-1900,0,0,-1));
1.70 www 3853: }
3854:
3855: #########################################
1.51 www 3856:
3857: sub findallcourses {
1.482 raeburn 3858: my ($roles,$uname,$udom) = @_;
1.355 albertel 3859: my %roles;
3860: if (ref($roles)) { %roles = map { $_ => 1 } @{$roles}; }
1.348 albertel 3861: my %courses;
1.51 www 3862: my $now=time;
1.482 raeburn 3863: if (!defined($uname)) {
3864: $uname = $env{'user.name'};
3865: }
3866: if (!defined($udom)) {
3867: $udom = $env{'user.domain'};
3868: }
3869: if (($uname ne $env{'user.name'}) || ($udom ne $env{'user.domain'})) {
1.948.2.11 raeburn 3870: my $extra = &Apache::lonnet::freeze_escape({'skipcheck' => 1});
3871: my %roleshash = &Apache::lonnet::dump('roles',$udom,$uname,'.',undef,
3872: $extra);
1.482 raeburn 3873: if (!%roles) {
3874: %roles = (
3875: cc => 1,
1.907 raeburn 3876: co => 1,
1.482 raeburn 3877: in => 1,
3878: ep => 1,
3879: ta => 1,
3880: cr => 1,
3881: st => 1,
3882: );
3883: }
3884: foreach my $entry (keys(%roleshash)) {
3885: my ($trole,$tend,$tstart) = split(/_/,$roleshash{$entry});
3886: if ($trole =~ /^cr/) {
3887: next if (!exists($roles{$trole}) && !exists($roles{'cr'}));
3888: } else {
3889: next if (!exists($roles{$trole}));
3890: }
3891: if ($tend) {
3892: next if ($tend < $now);
3893: }
3894: if ($tstart) {
3895: next if ($tstart > $now);
3896: }
3897: my ($cdom,$cnum,$sec,$cnumpart,$secpart,$role,$realsec);
3898: (undef,$cdom,$cnumpart,$secpart) = split(/\//,$entry);
3899: if ($secpart eq '') {
3900: ($cnum,$role) = split(/_/,$cnumpart);
3901: $sec = 'none';
3902: $realsec = '';
3903: } else {
3904: $cnum = $cnumpart;
3905: ($sec,$role) = split(/_/,$secpart);
3906: $realsec = $sec;
1.490 raeburn 3907: }
1.482 raeburn 3908: $courses{$cdom.'_'.$cnum}{$sec} = $trole.'/'.$cdom.'/'.$cnum.'/'.$realsec;
3909: }
3910: } else {
3911: foreach my $key (keys(%env)) {
1.483 albertel 3912: if ( $key=~m{^user\.role\.(\w+)\./($match_domain)/($match_courseid)/?(\w*)$} ||
3913: $key=~m{^user\.role\.(cr/$match_domain/$match_username/\w+)\./($match_domain)/($match_courseid)/?(\w*)$}) {
1.482 raeburn 3914: my ($role,$cdom,$cnum,$sec) = ($1,$2,$3,$4);
3915: next if ($role eq 'ca' || $role eq 'aa');
3916: next if (%roles && !exists($roles{$role}));
3917: my ($starttime,$endtime)=split(/\./,$env{$key});
3918: my $active=1;
3919: if ($starttime) {
3920: if ($now<$starttime) { $active=0; }
3921: }
3922: if ($endtime) {
3923: if ($now>$endtime) { $active=0; }
3924: }
3925: if ($active) {
3926: if ($sec eq '') {
3927: $sec = 'none';
3928: }
3929: $courses{$cdom.'_'.$cnum}{$sec} =
3930: $role.'/'.$cdom.'/'.$cnum.'/'.$sec;
1.474 raeburn 3931: }
3932: }
1.51 www 3933: }
3934: }
1.474 raeburn 3935: return %courses;
1.51 www 3936: }
1.37 matthew 3937:
1.54 www 3938: ###############################################
1.474 raeburn 3939:
3940: sub blockcheck {
1.482 raeburn 3941: my ($setters,$activity,$uname,$udom) = @_;
1.490 raeburn 3942:
3943: if (!defined($udom)) {
3944: $udom = $env{'user.domain'};
3945: }
3946: if (!defined($uname)) {
3947: $uname = $env{'user.name'};
3948: }
3949:
3950: # If uname and udom are for a course, check for blocks in the course.
3951:
3952: if (&Apache::lonnet::is_course($udom,$uname)) {
3953: my %records = &Apache::lonnet::dump('comm_block',$udom,$uname);
1.502 raeburn 3954: my ($startblock,$endblock)=&get_blocks($setters,$activity,$udom,$uname);
1.490 raeburn 3955: return ($startblock,$endblock);
3956: }
1.474 raeburn 3957:
1.502 raeburn 3958: my $startblock = 0;
3959: my $endblock = 0;
1.482 raeburn 3960: my %live_courses = &findallcourses(undef,$uname,$udom);
1.474 raeburn 3961:
1.490 raeburn 3962: # If uname is for a user, and activity is course-specific, i.e.,
3963: # boards, chat or groups, check for blocking in current course only.
1.474 raeburn 3964:
1.490 raeburn 3965: if (($activity eq 'boards' || $activity eq 'chat' ||
3966: $activity eq 'groups') && ($env{'request.course.id'})) {
3967: foreach my $key (keys(%live_courses)) {
3968: if ($key ne $env{'request.course.id'}) {
3969: delete($live_courses{$key});
3970: }
3971: }
3972: }
3973:
3974: my $otheruser = 0;
3975: my %own_courses;
3976: if ((($uname ne $env{'user.name'})) || ($udom ne $env{'user.domain'})) {
3977: # Resource belongs to user other than current user.
3978: $otheruser = 1;
3979: # Gather courses for current user
3980: %own_courses =
3981: &findallcourses(undef,$env{'user.name'},$env{'user.domain'});
3982: }
3983:
3984: # Gather active course roles - course coordinator, instructor,
3985: # exam proctor, ta, student, or custom role.
1.474 raeburn 3986:
3987: foreach my $course (keys(%live_courses)) {
1.482 raeburn 3988: my ($cdom,$cnum);
3989: if ((defined($env{'course.'.$course.'.domain'})) && (defined($env{'course.'.$course.'.num'}))) {
3990: $cdom = $env{'course.'.$course.'.domain'};
3991: $cnum = $env{'course.'.$course.'.num'};
3992: } else {
1.490 raeburn 3993: ($cdom,$cnum) = split(/_/,$course);
1.482 raeburn 3994: }
3995: my $no_ownblock = 0;
3996: my $no_userblock = 0;
1.533 raeburn 3997: if ($otheruser && $activity ne 'com') {
1.490 raeburn 3998: # Check if current user has 'evb' priv for this
3999: if (defined($own_courses{$course})) {
4000: foreach my $sec (keys(%{$own_courses{$course}})) {
4001: my $checkrole = 'cm./'.$cdom.'/'.$cnum;
4002: if ($sec ne 'none') {
4003: $checkrole .= '/'.$sec;
4004: }
4005: if (&Apache::lonnet::allowed('evb',undef,undef,$checkrole)) {
4006: $no_ownblock = 1;
4007: last;
4008: }
4009: }
4010: }
4011: # if they have 'evb' priv and are currently not playing student
4012: next if (($no_ownblock) &&
4013: ($env{'request.role'} !~ m{^st\./$cdom/$cnum}));
4014: }
1.474 raeburn 4015: foreach my $sec (keys(%{$live_courses{$course}})) {
1.482 raeburn 4016: my $checkrole = 'cm./'.$cdom.'/'.$cnum;
1.474 raeburn 4017: if ($sec ne 'none') {
1.482 raeburn 4018: $checkrole .= '/'.$sec;
1.474 raeburn 4019: }
1.490 raeburn 4020: if ($otheruser) {
4021: # Resource belongs to user other than current user.
4022: # Assemble privs for that user, and check for 'evb' priv.
1.482 raeburn 4023: my ($trole,$tdom,$tnum,$tsec);
4024: my $entry = $live_courses{$course}{$sec};
4025: if ($entry =~ /^cr/) {
4026: ($trole,$tdom,$tnum,$tsec) =
4027: ($entry =~ m|^(cr/$match_domain/$match_username/\w+)\./($match_domain)/($match_username)/?(\w*)$|);
4028: } else {
4029: ($trole,$tdom,$tnum,$tsec) = split(/\//,$entry);
4030: }
4031: my ($spec,$area,$trest,%allroles,%userroles);
4032: $area = '/'.$tdom.'/'.$tnum;
4033: $trest = $tnum;
4034: if ($tsec ne '') {
4035: $area .= '/'.$tsec;
4036: $trest .= '/'.$tsec;
4037: }
4038: $spec = $trole.'.'.$area;
4039: if ($trole =~ /^cr/) {
4040: &Apache::lonnet::custom_roleprivs(\%allroles,$trole,
4041: $tdom,$spec,$trest,$area);
4042: } else {
4043: &Apache::lonnet::standard_roleprivs(\%allroles,$trole,
4044: $tdom,$spec,$trest,$area);
4045: }
4046: my ($author,$adv) = &Apache::lonnet::set_userprivs(\%userroles,\%allroles);
1.486 raeburn 4047: if ($userroles{'user.priv.'.$checkrole} =~ /evb\&([^\:]*)/) {
4048: if ($1) {
4049: $no_userblock = 1;
4050: last;
4051: }
4052: }
1.490 raeburn 4053: } else {
4054: # Resource belongs to current user
4055: # Check for 'evb' priv via lonnet::allowed().
1.482 raeburn 4056: if (&Apache::lonnet::allowed('evb',undef,undef,$checkrole)) {
4057: $no_ownblock = 1;
4058: last;
4059: }
1.474 raeburn 4060: }
4061: }
4062: # if they have the evb priv and are currently not playing student
1.482 raeburn 4063: next if (($no_ownblock) &&
1.491 albertel 4064: ($env{'request.role'} !~ m{^st\./\Q$cdom\E/\Q$cnum\E}));
1.482 raeburn 4065: next if ($no_userblock);
1.474 raeburn 4066:
1.866 kalberla 4067: # Retrieve blocking times and identity of locker for course
1.490 raeburn 4068: # of specified user, unless user has 'evb' privilege.
1.502 raeburn 4069:
4070: my ($start,$end)=&get_blocks($setters,$activity,$cdom,$cnum);
4071: if (($start != 0) &&
4072: (($startblock == 0) || ($startblock > $start))) {
4073: $startblock = $start;
4074: }
4075: if (($end != 0) &&
4076: (($endblock == 0) || ($endblock < $end))) {
4077: $endblock = $end;
4078: }
1.490 raeburn 4079: }
4080: return ($startblock,$endblock);
4081: }
4082:
4083: sub get_blocks {
4084: my ($setters,$activity,$cdom,$cnum) = @_;
4085: my $startblock = 0;
4086: my $endblock = 0;
4087: my $course = $cdom.'_'.$cnum;
4088: $setters->{$course} = {};
4089: $setters->{$course}{'staff'} = [];
4090: $setters->{$course}{'times'} = [];
4091: my %records = &Apache::lonnet::dump('comm_block',$cdom,$cnum);
4092: foreach my $record (keys(%records)) {
4093: my ($start,$end) = ($record =~ m/^(\d+)____(\d+)$/);
4094: if ($start <= time && $end >= time) {
4095: my ($staff_name,$staff_dom,$title,$blocks) =
4096: &parse_block_record($records{$record});
4097: if ($blocks->{$activity} eq 'on') {
4098: push(@{$$setters{$course}{'staff'}},[$staff_name,$staff_dom]);
4099: push(@{$$setters{$course}{'times'}}, [$start,$end]);
1.491 albertel 4100: if ( ($startblock == 0) || ($startblock > $start) ) {
4101: $startblock = $start;
1.490 raeburn 4102: }
1.491 albertel 4103: if ( ($endblock == 0) || ($endblock < $end) ) {
4104: $endblock = $end;
1.474 raeburn 4105: }
4106: }
4107: }
4108: }
4109: return ($startblock,$endblock);
4110: }
4111:
4112: sub parse_block_record {
4113: my ($record) = @_;
4114: my ($setuname,$setudom,$title,$blocks);
4115: if (ref($record) eq 'HASH') {
4116: ($setuname,$setudom) = split(/:/,$record->{'setter'});
4117: $title = &unescape($record->{'event'});
4118: $blocks = $record->{'blocks'};
4119: } else {
4120: my @data = split(/:/,$record,3);
4121: if (scalar(@data) eq 2) {
4122: $title = $data[1];
4123: ($setuname,$setudom) = split(/@/,$data[0]);
4124: } else {
4125: ($setuname,$setudom,$title) = @data;
4126: }
4127: $blocks = { 'com' => 'on' };
4128: }
4129: return ($setuname,$setudom,$title,$blocks);
4130: }
4131:
1.854 kalberla 4132: sub blocking_status {
4133: my ($activity,$uname,$udom) = @_;
1.867 kalberla 4134: my %setters;
1.890 droeschl 4135:
4136: # check for active blocking
1.867 kalberla 4137: my ($startblock,$endblock)=&blockcheck(\%setters,$activity,$uname,$udom);
1.854 kalberla 4138:
1.890 droeschl 4139: my $blocked = $startblock && $endblock ? 1 : 0;
4140:
4141: # caller just wants to know whether a block is active
4142: if (!wantarray) { return $blocked; }
4143:
4144: # build a link to a popup window containing the details
4145: my $querystring = "?activity=$activity";
4146: # $uname and $udom decide whose portfolio the user is trying to look at
4147: $querystring .= "&udom=$udom" if $udom;
4148: $querystring .= "&uname=$uname" if $uname;
4149:
4150: my $output .= <<'END_MYBLOCK';
1.854 kalberla 4151: function openWindow(url, wdwName, w, h, toolbar,scrollbar) {
4152: var options = "width=" + w + ",height=" + h + ",";
4153: options += "resizable=yes,scrollbars="+scrollbar+",status=no,";
4154: options += "menubar=no,toolbar="+toolbar+",location=no,directories=no";
4155: var newWin = window.open(url, wdwName, options);
4156: newWin.focus();
4157: }
1.890 droeschl 4158: END_MYBLOCK
1.854 kalberla 4159:
1.890 droeschl 4160: $output = Apache::lonhtmlcommon::scripttag($output);
4161:
1.854 kalberla 4162: my $popupUrl = "/adm/blockingstatus/$querystring";
1.890 droeschl 4163: my $text = mt('Communication Blocked');
4164:
1.867 kalberla 4165: $output .= <<"END_BLOCK";
4166: <div class='LC_comblock'>
1.869 kalberla 4167: <a onclick='openWindow("$popupUrl","Blocking Table",600,300,"no","no");return false;' href='/adm/blockingstatus/$querystring'
1.890 droeschl 4168: title='$text'>
4169: <img class='LC_noBorder LC_middle' title='$text' src='/res/adm/pages/comblock.png' alt='$text'/></a>
1.869 kalberla 4170: <a onclick='openWindow("$popupUrl","Blocking Table",600,300,"no","no");return false;' href='/adm/blockingstatus/$querystring'
1.890 droeschl 4171: title='$text'>$text</a>
1.867 kalberla 4172: </div>
4173:
4174: END_BLOCK
1.474 raeburn 4175:
1.854 kalberla 4176: return ($blocked, $output);
4177: }
1.490 raeburn 4178:
1.60 matthew 4179: ###############################################
4180:
1.682 raeburn 4181: sub check_ip_acc {
4182: my ($acc)=@_;
4183: &Apache::lonxml::debug("acc is $acc");
4184: if (!defined($acc) || $acc =~ /^\s*$/ || $acc =~/^\s*no\s*$/i) {
4185: return 1;
4186: }
4187: my $allowed=0;
4188: my $ip=$env{'request.host'} || $ENV{'REMOTE_ADDR'};
4189:
4190: my $name;
4191: foreach my $pattern (split(',',$acc)) {
4192: $pattern =~ s/^\s*//;
4193: $pattern =~ s/\s*$//;
4194: if ($pattern =~ /\*$/) {
4195: #35.8.*
4196: $pattern=~s/\*//;
4197: if ($ip =~ /^\Q$pattern\E/) { $allowed=1; }
4198: } elsif ($pattern =~ /(\d+\.\d+\.\d+)\.\[(\d+)-(\d+)\]$/) {
4199: #35.8.3.[34-56]
4200: my $low=$2;
4201: my $high=$3;
4202: $pattern=$1;
4203: if ($ip =~ /^\Q$pattern\E/) {
4204: my $last=(split(/\./,$ip))[3];
4205: if ($last <=$high && $last >=$low) { $allowed=1; }
4206: }
4207: } elsif ($pattern =~ /^\*/) {
4208: #*.msu.edu
4209: $pattern=~s/\*//;
4210: if (!defined($name)) {
4211: use Socket;
4212: my $netaddr=inet_aton($ip);
4213: ($name)=gethostbyaddr($netaddr,AF_INET);
4214: }
4215: if ($name =~ /\Q$pattern\E$/i) { $allowed=1; }
4216: } elsif ($pattern =~ /\d+\.\d+\.\d+\.\d+/) {
4217: #127.0.0.1
4218: if ($ip =~ /^\Q$pattern\E/) { $allowed=1; }
4219: } else {
4220: #some.name.com
4221: if (!defined($name)) {
4222: use Socket;
4223: my $netaddr=inet_aton($ip);
4224: ($name)=gethostbyaddr($netaddr,AF_INET);
4225: }
4226: if ($name =~ /\Q$pattern\E$/i) { $allowed=1; }
4227: }
4228: if ($allowed) { last; }
4229: }
4230: return $allowed;
4231: }
4232:
4233: ###############################################
4234:
1.60 matthew 4235: =pod
4236:
1.112 bowersj2 4237: =head1 Domain Template Functions
4238:
4239: =over 4
4240:
4241: =item * &determinedomain()
1.60 matthew 4242:
4243: Inputs: $domain (usually will be undef)
4244:
1.63 www 4245: Returns: Determines which domain should be used for designs
1.60 matthew 4246:
4247: =cut
1.54 www 4248:
1.60 matthew 4249: ###############################################
1.63 www 4250: sub determinedomain {
4251: my $domain=shift;
1.531 albertel 4252: if (! $domain) {
1.60 matthew 4253: # Determine domain if we have not been given one
1.893 raeburn 4254: $domain = &Apache::lonnet::default_login_domain();
1.258 albertel 4255: if ($env{'user.domain'}) { $domain=$env{'user.domain'}; }
4256: if ($env{'request.role.domain'}) {
4257: $domain=$env{'request.role.domain'};
1.60 matthew 4258: }
4259: }
1.63 www 4260: return $domain;
4261: }
4262: ###############################################
1.517 raeburn 4263:
1.518 albertel 4264: sub devalidate_domconfig_cache {
4265: my ($udom)=@_;
4266: &Apache::lonnet::devalidate_cache_new('domainconfig',$udom);
4267: }
4268:
4269: # ---------------------- Get domain configuration for a domain
4270: sub get_domainconf {
4271: my ($udom) = @_;
4272: my $cachetime=1800;
4273: my ($result,$cached)=&Apache::lonnet::is_cached_new('domainconfig',$udom);
4274: if (defined($cached)) { return %{$result}; }
4275:
4276: my %domconfig = &Apache::lonnet::get_dom('configuration',
1.948 raeburn 4277: ['login','rolecolors','autoenroll'],$udom);
1.632 raeburn 4278: my (%designhash,%legacy);
1.518 albertel 4279: if (keys(%domconfig) > 0) {
4280: if (ref($domconfig{'login'}) eq 'HASH') {
1.632 raeburn 4281: if (keys(%{$domconfig{'login'}})) {
4282: foreach my $key (keys(%{$domconfig{'login'}})) {
1.699 raeburn 4283: if (ref($domconfig{'login'}{$key}) eq 'HASH') {
1.946 raeburn 4284: if ($key eq 'loginvia') {
4285: if (ref($domconfig{'login'}{'loginvia'}) eq 'HASH') {
4286: my @ids = &Apache::lonnet::current_machine_ids();
4287: foreach my $hostname (@ids) {
1.948 raeburn 4288: if (ref($domconfig{'login'}{'loginvia'}{$hostname}) eq 'HASH') {
4289: if ($domconfig{'login'}{'loginvia'}{$hostname}{'server'}) {
4290: my $server = $domconfig{'login'}{'loginvia'}{$hostname}{'server'};
4291: $designhash{$udom.'.login.loginvia'} = $server;
4292: if ($domconfig{'login'}{'loginvia'}{$hostname}{'serverpath'} eq 'custom') {
4293:
4294: $designhash{$udom.'.login.loginvia_'.$hostname} = $server.':'.$domconfig{'login'}{'loginvia'}{$hostname}{'custompath'};
4295: } else {
4296: $designhash{$udom.'.login.loginvia_'.$hostname} = $server.':'.$domconfig{'login'}{'loginvia'}{$hostname}{'serverpath'};
4297: }
4298: if ($domconfig{'login'}{'loginvia'}{$hostname}{'exempt'}) {
4299: $designhash{$udom.'.login.loginvia_exempt_'.$hostname} = $domconfig{'login'}{'loginvia'}{$hostname}{'exempt'};
4300: }
1.946 raeburn 4301: }
4302: }
4303: }
4304: }
4305: } else {
4306: foreach my $img (keys(%{$domconfig{'login'}{$key}})) {
4307: $designhash{$udom.'.login.'.$key.'_'.$img} =
4308: $domconfig{'login'}{$key}{$img};
4309: }
1.699 raeburn 4310: }
4311: } else {
4312: $designhash{$udom.'.login.'.$key}=$domconfig{'login'}{$key};
4313: }
1.632 raeburn 4314: }
4315: } else {
4316: $legacy{'login'} = 1;
1.518 albertel 4317: }
1.632 raeburn 4318: } else {
4319: $legacy{'login'} = 1;
1.518 albertel 4320: }
4321: if (ref($domconfig{'rolecolors'}) eq 'HASH') {
1.632 raeburn 4322: if (keys(%{$domconfig{'rolecolors'}})) {
4323: foreach my $role (keys(%{$domconfig{'rolecolors'}})) {
4324: if (ref($domconfig{'rolecolors'}{$role}) eq 'HASH') {
4325: foreach my $item (keys(%{$domconfig{'rolecolors'}{$role}})) {
4326: $designhash{$udom.'.'.$role.'.'.$item}=$domconfig{'rolecolors'}{$role}{$item};
4327: }
1.518 albertel 4328: }
4329: }
1.632 raeburn 4330: } else {
4331: $legacy{'rolecolors'} = 1;
1.518 albertel 4332: }
1.632 raeburn 4333: } else {
4334: $legacy{'rolecolors'} = 1;
1.518 albertel 4335: }
1.948 raeburn 4336: if (ref($domconfig{'autoenroll'}) eq 'HASH') {
4337: if ($domconfig{'autoenroll'}{'co-owners'}) {
4338: $designhash{$udom.'.autoassign.co-owners'}=$domconfig{'autoenroll'}{'co-owners'};
4339: }
4340: }
1.632 raeburn 4341: if (keys(%legacy) > 0) {
4342: my %legacyhash = &get_legacy_domconf($udom);
4343: foreach my $item (keys(%legacyhash)) {
4344: if ($item =~ /^\Q$udom\E\.login/) {
4345: if ($legacy{'login'}) {
4346: $designhash{$item} = $legacyhash{$item};
4347: }
4348: } else {
4349: if ($legacy{'rolecolors'}) {
4350: $designhash{$item} = $legacyhash{$item};
4351: }
1.518 albertel 4352: }
4353: }
4354: }
1.632 raeburn 4355: } else {
4356: %designhash = &get_legacy_domconf($udom);
1.518 albertel 4357: }
4358: &Apache::lonnet::do_cache_new('domainconfig',$udom,\%designhash,
4359: $cachetime);
4360: return %designhash;
4361: }
4362:
1.632 raeburn 4363: sub get_legacy_domconf {
4364: my ($udom) = @_;
4365: my %legacyhash;
4366: my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors';
4367: my $designfile = $designdir.'/'.$udom.'.tab';
4368: if (-e $designfile) {
4369: if ( open (my $fh,"<$designfile") ) {
4370: while (my $line = <$fh>) {
4371: next if ($line =~ /^\#/);
4372: chomp($line);
4373: my ($key,$val)=(split(/\=/,$line));
4374: if ($val) { $legacyhash{$udom.'.'.$key}=$val; }
4375: }
4376: close($fh);
4377: }
4378: }
4379: if (-e '/home/httpd/html/adm/lonDomLogos/'.$udom.'.gif') {
4380: $legacyhash{$udom.'.login.domlogo'} = "/adm/lonDomLogos/$udom.gif";
4381: }
4382: return %legacyhash;
4383: }
4384:
1.63 www 4385: =pod
4386:
1.112 bowersj2 4387: =item * &domainlogo()
1.63 www 4388:
4389: Inputs: $domain (usually will be undef)
4390:
4391: Returns: A link to a domain logo, if the domain logo exists.
4392: If the domain logo does not exist, a description of the domain.
4393:
4394: =cut
1.112 bowersj2 4395:
1.63 www 4396: ###############################################
4397: sub domainlogo {
1.517 raeburn 4398: my $domain = &determinedomain(shift);
1.518 albertel 4399: my %designhash = &get_domainconf($domain);
1.517 raeburn 4400: # See if there is a logo
4401: if ($designhash{$domain.'.login.domlogo'} ne '') {
1.519 raeburn 4402: my $imgsrc = $designhash{$domain.'.login.domlogo'};
1.538 albertel 4403: if ($imgsrc =~ m{^/(adm|res)/}) {
4404: if ($imgsrc =~ m{^/res/}) {
4405: my $local_name = &Apache::lonnet::filelocation('',$imgsrc);
4406: &Apache::lonnet::repcopy($local_name);
4407: }
4408: $imgsrc = &lonhttpdurl($imgsrc);
1.519 raeburn 4409: }
4410: return '<img src="'.$imgsrc.'" alt="'.$domain.'" />';
1.514 albertel 4411: } elsif (defined(&Apache::lonnet::domain($domain,'description'))) {
4412: return &Apache::lonnet::domain($domain,'description');
1.59 www 4413: } else {
1.60 matthew 4414: return '';
1.59 www 4415: }
4416: }
1.63 www 4417: ##############################################
4418:
4419: =pod
4420:
1.112 bowersj2 4421: =item * &designparm()
1.63 www 4422:
4423: Inputs: $which parameter; $domain (usually will be undef)
4424:
4425: Returns: value of designparamter $which
4426:
4427: =cut
1.112 bowersj2 4428:
1.397 albertel 4429:
1.400 albertel 4430: ##############################################
1.397 albertel 4431: sub designparm {
4432: my ($which,$domain)=@_;
4433: if (exists($env{'environment.color.'.$which})) {
1.817 bisitz 4434: return $env{'environment.color.'.$which};
1.96 www 4435: }
1.63 www 4436: $domain=&determinedomain($domain);
1.518 albertel 4437: my %domdesign = &get_domainconf($domain);
1.520 raeburn 4438: my $output;
1.517 raeburn 4439: if ($domdesign{$domain.'.'.$which} ne '') {
1.817 bisitz 4440: $output = $domdesign{$domain.'.'.$which};
1.63 www 4441: } else {
1.520 raeburn 4442: $output = $defaultdesign{$which};
4443: }
4444: if (($which =~ /^(student|coordinator|author|admin)\.img$/) ||
1.635 raeburn 4445: ($which =~ /login\.(img|logo|domlogo|login)/)) {
1.538 albertel 4446: if ($output =~ m{^/(adm|res)/}) {
1.817 bisitz 4447: if ($output =~ m{^/res/}) {
4448: my $local_name = &Apache::lonnet::filelocation('',$output);
4449: &Apache::lonnet::repcopy($local_name);
4450: }
1.520 raeburn 4451: $output = &lonhttpdurl($output);
4452: }
1.63 www 4453: }
1.520 raeburn 4454: return $output;
1.63 www 4455: }
1.59 www 4456:
1.822 bisitz 4457: ##############################################
4458: =pod
4459:
1.832 bisitz 4460: =item * &authorspace()
4461:
4462: Inputs: ./.
4463:
4464: Returns: Path to the Construction Space of the current user's
4465: accessed author space
4466: The author space will be that of the current user
4467: when accessing the own author space
4468: and that of the co-author/assistent co-author
4469: when accessing the co-author's/assistent co-author's
4470: space
4471:
4472: =cut
4473:
4474: sub authorspace {
4475: my $caname = '';
4476: if ($env{'request.role'} =~ /^ca|^aa/) {
4477: (undef,$caname) =
4478: ($env{'request.role'}=~/($match_domain)\/($match_username)$/);
4479: } else {
4480: $caname = $env{'user.name'};
4481: }
4482: return '/priv/'.$caname.'/';
4483: }
4484:
4485: ##############################################
4486: =pod
4487:
1.822 bisitz 4488: =item * &head_subbox()
4489:
4490: Inputs: $content (contains HTML code with page functions, etc.)
4491:
4492: Returns: HTML div with $content
4493: To be included in page header
4494:
4495: =cut
4496:
4497: sub head_subbox {
4498: my ($content)=@_;
4499: my $output =
1.844 bisitz 4500: '<div id="LC_head_subbox">'
1.822 bisitz 4501: .$content
4502: .'</div>'
4503: }
4504:
4505: ##############################################
4506: =pod
4507:
4508: =item * &CSTR_pageheader()
4509:
4510: Inputs: ./.
4511:
4512: Returns: HTML div with CSTR path and recent box
4513: To be included on Construction Space pages
4514:
4515: =cut
4516:
4517: sub CSTR_pageheader {
4518: # this is for resources; directories have customtitle, and crumbs
4519: # and select recent are created in lonpubdir.pm
4520: my ($uname,$thisdisfn)=
4521: ($env{'request.filename'} =~ m|^/home/([^/]+)/public_html/(.*)|);
4522: my $formaction='/priv/'.$uname.'/'.$thisdisfn;
4523: $formaction=~s/\/+/\//g;
4524:
4525: my $parentpath = '';
4526: my $lastitem = '';
4527: if ($thisdisfn =~ m-(.+/)([^/]*)$-) {
4528: $parentpath = $1;
4529: $lastitem = $2;
4530: } else {
4531: $lastitem = $thisdisfn;
4532: }
1.921 bisitz 4533:
4534: my $output =
1.822 bisitz 4535: '<div>'
4536: .&Apache::loncommon::help_open_menu('','',3,'Authoring') #FIXME: Broken? Where is it?
4537: .'<b>'.&mt('Construction Space:').'</b> '
4538: .'<form name="dirs" method="post" action="'.$formaction
1.921 bisitz 4539: .'" target="_top">' #FIXME lonpubdir: target="_parent"
4540: .&Apache::lonhtmlcommon::crumbs($uname.'/'.$parentpath,'_top','/priv',undef,undef);
4541:
4542: if ($lastitem) {
4543: $output .=
4544: '<span class="LC_filename">'
4545: .$lastitem
4546: .'</span>';
4547: }
4548: $output .=
4549: '<br />'
1.822 bisitz 4550: #FIXME lonpubdir: &Apache::lonhtmlcommon::crumbs($uname.$thisdisfn.'/','_top','/priv','','+1',1)."</b></tt><br />"
4551: .&Apache::lonhtmlcommon::select_recent('construct','recent','this.form.action=this.form.recent.value;this.form.submit()')
4552: .'</form>'
4553: .&Apache::lonmenu::constspaceform()
4554: .'</div>';
1.921 bisitz 4555:
4556: return $output;
1.822 bisitz 4557: }
4558:
1.60 matthew 4559: ###############################################
4560: ###############################################
4561:
4562: =pod
4563:
1.112 bowersj2 4564: =back
4565:
1.549 albertel 4566: =head1 HTML Helpers
1.112 bowersj2 4567:
4568: =over 4
4569:
4570: =item * &bodytag()
1.60 matthew 4571:
4572: Returns a uniform header for LON-CAPA web pages.
4573:
4574: Inputs:
4575:
1.112 bowersj2 4576: =over 4
4577:
4578: =item * $title, A title to be displayed on the page.
4579:
4580: =item * $function, the current role (can be undef).
4581:
4582: =item * $addentries, extra parameters for the <body> tag.
4583:
4584: =item * $bodyonly, if defined, only return the <body> tag.
4585:
4586: =item * $domain, if defined, force a given domain.
4587:
4588: =item * $forcereg, if page should register as content page (relevant for
1.86 www 4589: text interface only)
1.60 matthew 4590:
1.814 bisitz 4591: =item * $no_nav_bar, if true, keep the 'what is this' info but remove the
4592: navigational links
1.317 albertel 4593:
1.338 albertel 4594: =item * $bgcolor, used to override the bgcolor on a webpage to a specific value
4595:
1.361 albertel 4596: =item * $no_inline_link, if true and in remote mode, don't show the
4597: 'Switch To Inline Menu' link
4598:
1.460 albertel 4599: =item * $args, optional argument valid values are
4600: no_auto_mt_title -> prevents &mt()ing the title arg
1.562 albertel 4601: inherit_jsmath -> when creating popup window in a page,
4602: should it have jsmath forced on by the
4603: current page
1.460 albertel 4604:
1.112 bowersj2 4605: =back
4606:
1.60 matthew 4607: Returns: A uniform header for LON-CAPA web pages.
4608: If $bodyonly is nonzero, a string containing a <body> tag will be returned.
4609: If $bodyonly is undef or zero, an html string containing a <body> tag and
4610: other decorations will be returned.
4611:
4612: =cut
4613:
1.54 www 4614: sub bodytag {
1.831 bisitz 4615: my ($title,$function,$addentries,$bodyonly,$domain,$forcereg,
1.816 bisitz 4616: $no_nav_bar,$bgcolor,$no_inline_link,$args)=@_;
1.339 albertel 4617:
1.948.2.2 raeburn 4618: my $public;
4619: if ((($env{'user.name'} eq 'public') && ($env{'user.domain'} eq 'public'))
4620: || ($env{'user.name'} eq '') && ($env{'user.domain'} eq '')) {
4621: $public = 1;
4622: }
1.460 albertel 4623: if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); }
1.339 albertel 4624:
1.183 matthew 4625: $function = &get_users_function() if (!$function);
1.339 albertel 4626: my $img = &designparm($function.'.img',$domain);
4627: my $font = &designparm($function.'.font',$domain);
4628: my $pgbg = $bgcolor || &designparm($function.'.pgbg',$domain);
4629:
1.803 bisitz 4630: my %design = ( 'style' => 'margin-top: 0',
1.535 albertel 4631: 'bgcolor' => $pgbg,
1.339 albertel 4632: 'text' => $font,
4633: 'alink' => &designparm($function.'.alink',$domain),
4634: 'vlink' => &designparm($function.'.vlink',$domain),
4635: 'link' => &designparm($function.'.link',$domain),);
1.438 albertel 4636: @design{keys(%$addentries)} = @$addentries{keys(%$addentries)};
1.339 albertel 4637:
1.63 www 4638: # role and realm
1.378 raeburn 4639: my ($role,$realm) = split(/\./,$env{'request.role'},2);
4640: if ($role eq 'ca') {
1.479 albertel 4641: my ($rdom,$rname) = ($realm =~ m{^/($match_domain)/($match_username)$});
1.500 albertel 4642: $realm = &plainname($rname,$rdom);
1.378 raeburn 4643: }
1.55 www 4644: # realm
1.258 albertel 4645: if ($env{'request.course.id'}) {
1.378 raeburn 4646: if ($env{'request.role'} !~ /^cr/) {
4647: $role = &Apache::lonnet::plaintext($role,&course_type());
4648: }
1.898 raeburn 4649: if ($env{'request.course.sec'}) {
4650: $role .= (' 'x2).'- '.&mt('section:').' '.$env{'request.course.sec'};
4651: }
1.359 albertel 4652: $realm = $env{'course.'.$env{'request.course.id'}.'.description'};
1.378 raeburn 4653: } else {
4654: $role = &Apache::lonnet::plaintext($role);
1.54 www 4655: }
1.433 albertel 4656:
1.359 albertel 4657: if (!$realm) { $realm=' '; }
1.55 www 4658: # Set messages
1.60 matthew 4659: my $messages=&domainlogo($domain);
1.330 albertel 4660:
1.438 albertel 4661: my $extra_body_attr = &make_attr_string($forcereg,\%design);
1.329 albertel 4662:
1.101 www 4663: # construct main body tag
1.359 albertel 4664: my $bodytag = "<body $extra_body_attr>".
1.562 albertel 4665: &Apache::lontexconvert::init_math_support($args->{'inherit_jsmath'});
1.252 albertel 4666:
1.530 albertel 4667: if ($bodyonly) {
1.60 matthew 4668: return $bodytag;
1.798 tempelho 4669: }
1.359 albertel 4670:
1.410 albertel 4671: my $name = &plainname($env{'user.name'},$env{'user.domain'});
1.948.2.2 raeburn 4672: if ($public) {
1.433 albertel 4673: undef($role);
1.434 albertel 4674: } else {
4675: $name = &aboutmewrapper($name,$env{'user.name'},$env{'user.domain'});
1.433 albertel 4676: }
1.948.2.2 raeburn 4677:
1.762 bisitz 4678: my $titleinfo = '<h1>'.$title.'</h1>';
1.359 albertel 4679: #
4680: # Extra info if you are the DC
4681: my $dc_info = '';
4682: if ($env{'user.adv'} && exists($env{'user.role.dc./'.
4683: $env{'course.'.$env{'request.course.id'}.
4684: '.domain'}.'/'})) {
4685: my $cid = $env{'request.course.id'};
1.917 raeburn 4686: $dc_info = $cid.' '.$env{'course.'.$cid.'.internal.coursecode'};
1.380 www 4687: $dc_info =~ s/\s+$//;
1.359 albertel 4688: }
4689:
1.898 raeburn 4690: $role = '<span class="LC_nobreak">('.$role.')</span>' if $role;
1.853 droeschl 4691: &get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['inhibitmenu']);
4692:
1.837 bisitz 4693: if ($env{'environment.remote'} eq 'off') {
1.359 albertel 4694: # No Remote
1.916 droeschl 4695: if ($no_nav_bar || $env{'form.inhibitmenu'} eq 'yes') {
4696: return $bodytag;
4697: }
1.903 droeschl 4698:
4699: if ($env{'request.state'} eq 'construct') { $forcereg=1; }
4700:
4701: # if ($env{'request.state'} eq 'construct') {
4702: # $titleinfo = &CSTR_pageheader(); #FIXME: Will be removed once all scripts have their own calls
4703: # }
4704:
1.359 albertel 4705:
4706:
1.916 droeschl 4707: if ($env{'request.noversionuri'} =~ m{^/res/adm/pages/}) {
1.917 raeburn 4708: if ($dc_info) {
4709: $dc_info = qq|<span class="LC_cusr_subheading">$dc_info</span>|;
4710: }
1.916 droeschl 4711: $bodytag .= qq|<div id="LC_nav_bar">$name $role<br />
4712: <em>$realm</em> $dc_info</div>|;
1.903 droeschl 4713: return $bodytag;
4714: }
1.894 droeschl 4715:
1.927 raeburn 4716: unless ($env{'request.symb'} =~ m/\.page___\d+___/) {
4717: $bodytag .= qq|<div id="LC_nav_bar">$name $role</div>|;
4718: }
1.916 droeschl 4719:
1.903 droeschl 4720: $bodytag .= Apache::lonhtmlcommon::scripttag(
4721: Apache::lonmenu::utilityfunctions(), 'start');
1.816 bisitz 4722:
1.903 droeschl 4723: $bodytag .= Apache::lonmenu::primary_menu();
1.852 droeschl 4724:
1.917 raeburn 4725: if ($dc_info) {
4726: $dc_info = &dc_courseid_toggle($dc_info);
4727: }
4728: $bodytag .= qq|<div id="LC_realm">$realm $dc_info</div>|;
1.916 droeschl 4729:
1.903 droeschl 4730: #don't show menus for public users
1.948.2.2 raeburn 4731: if (!$public){
1.903 droeschl 4732: $bodytag .= Apache::lonmenu::secondary_menu();
4733: $bodytag .= Apache::lonmenu::serverform();
1.920 raeburn 4734: $bodytag .= Apache::lonhtmlcommon::scripttag('', 'end');
4735: if ($env{'request.state'} eq 'construct') {
4736: $bodytag .= &Apache::lonmenu::innerregister($forcereg,'',
4737: $args->{'bread_crumbs'});
4738: } elsif ($forcereg) {
4739: $bodytag .= &Apache::lonmenu::innerregister($forcereg);
4740: }
1.903 droeschl 4741: }else{
4742: # this is to seperate menu from content when there's no secondary
4743: # menu. Especially needed for public accessible ressources.
4744: $bodytag .= '<hr style="clear:both" />';
4745: $bodytag .= Apache::lonhtmlcommon::scripttag('', 'end');
1.235 raeburn 4746: }
1.903 droeschl 4747:
1.235 raeburn 4748: return $bodytag;
1.94 www 4749: }
1.95 www 4750:
1.93 www 4751: #
1.95 www 4752: # Top frame rendering, Remote is up
1.93 www 4753: #
1.359 albertel 4754:
1.517 raeburn 4755: my $imgsrc = $img;
4756: if ($img =~ /^\/adm/) {
1.575 albertel 4757: $imgsrc = &lonhttpdurl($img);
1.517 raeburn 4758: }
4759: my $upperleft='<img src="'.$imgsrc.'" alt="'.$function.'" />';
1.359 albertel 4760:
1.305 www 4761: # Explicit link to get inline menu
1.361 albertel 4762: my $menu= ($no_inline_link?''
1.883 droeschl 4763: :'<a href="/adm/remote?action=collapse" target="_top">'.&mt('Switch to Inline Menu Mode').'</a>');
1.917 raeburn 4764:
4765: if ($dc_info) {
4766: $dc_info = qq|<span class="LC_cusr_subheading">($dc_info)</span>|;
4767: }
4768:
1.916 droeschl 4769: $bodytag .= qq|<div id="LC_nav_bar">$name $role</div>
1.897 wenzelju 4770: <ol class="LC_primary_menu LC_right">
1.853 droeschl 4771: <li>$menu</li>
1.917 raeburn 4772: </ol><div id="LC_realm"> $realm $dc_info</div>| unless $env{'form.inhibitmenu'};
1.94 www 4773: return(<<ENDBODY);
1.60 matthew 4774: $bodytag
1.359 albertel 4775: <table id="LC_title_bar" class="LC_with_remote">
1.791 tempelho 4776: <tr><td>$upperleft</td>
4777: <td>$messages </td>
1.54 www 4778: </tr>
1.359 albertel 4779: <tr><td>$titleinfo $dc_info $menu</td>
1.368 albertel 4780: </tr>
1.356 albertel 4781: </table>
1.54 www 4782: ENDBODY
1.182 matthew 4783: }
4784:
1.917 raeburn 4785: sub dc_courseid_toggle {
4786: my ($dc_info) = @_;
1.948.2.10 raeburn 4787: return ' <span id="dccidtext" class="LC_cusr_subheading LC_nobreak">'.
1.917 raeburn 4788: '<a href="javascript:showCourseID();">'.
4789: &mt('(More ...)').'</a></span>'.
4790: '<div id="dccid" class="LC_dccid">'.$dc_info.'</div>';
4791: }
4792:
1.330 albertel 4793: sub make_attr_string {
4794: my ($register,$attr_ref) = @_;
4795:
4796: if ($attr_ref && !ref($attr_ref)) {
4797: die("addentries Must be a hash ref ".
4798: join(':',caller(1))." ".
4799: join(':',caller(0))." ");
4800: }
4801:
4802: if ($register) {
1.339 albertel 4803: my ($on_load,$on_unload);
4804: foreach my $key (keys(%{$attr_ref})) {
4805: if (lc($key) eq 'onload') {
4806: $on_load.=$attr_ref->{$key}.';';
4807: delete($attr_ref->{$key});
4808:
4809: } elsif (lc($key) eq 'onunload') {
4810: $on_unload.=$attr_ref->{$key}.';';
4811: delete($attr_ref->{$key});
4812: }
4813: }
4814: $attr_ref->{'onload'} =
4815: &Apache::lonmenu::loadevents(). $on_load;
4816: $attr_ref->{'onunload'}=
4817: &Apache::lonmenu::unloadevents().$on_unload;
4818: }
4819:
4820: # Accessibility font enhance
4821: if ($env{'browser.fontenhance'} eq 'on') {
4822: my $style;
4823: foreach my $key (keys(%{$attr_ref})) {
4824: if (lc($key) eq 'style') {
4825: $style.=$attr_ref->{$key}.';';
4826: delete($attr_ref->{$key});
4827: }
4828: }
4829: $attr_ref->{'style'}=$style.'; font-size: x-large;';
1.330 albertel 4830: }
1.339 albertel 4831:
1.330 albertel 4832: my $attr_string;
4833: foreach my $attr (keys(%$attr_ref)) {
4834: $attr_string .= " $attr=\"".$attr_ref->{$attr}.'" ';
4835: }
4836: return $attr_string;
4837: }
4838:
4839:
1.182 matthew 4840: ###############################################
1.251 albertel 4841: ###############################################
4842:
4843: =pod
4844:
4845: =item * &endbodytag()
4846:
4847: Returns a uniform footer for LON-CAPA web pages.
4848:
1.635 raeburn 4849: Inputs: 1 - optional reference to an args hash
4850: If in the hash, key for noredirectlink has a value which evaluates to true,
4851: a 'Continue' link is not displayed if the page contains an
4852: internal redirect in the <head></head> section,
4853: i.e., $env{'internal.head.redirect'} exists
1.251 albertel 4854:
4855: =cut
4856:
4857: sub endbodytag {
1.635 raeburn 4858: my ($args) = @_;
1.251 albertel 4859: my $endbodytag='</body>';
1.269 albertel 4860: $endbodytag=&Apache::lontexconvert::jsMath_process()."\n".$endbodytag;
1.315 albertel 4861: if ( exists( $env{'internal.head.redirect'} ) ) {
1.635 raeburn 4862: if (!(ref($args) eq 'HASH' && $args->{'noredirectlink'})) {
4863: $endbodytag=
4864: "<br /><a href=\"$env{'internal.head.redirect'}\">".
4865: &mt('Continue').'</a>'.
4866: $endbodytag;
4867: }
1.315 albertel 4868: }
1.251 albertel 4869: return $endbodytag;
4870: }
4871:
1.352 albertel 4872: =pod
4873:
4874: =item * &standard_css()
4875:
4876: Returns a style sheet
4877:
4878: Inputs: (all optional)
4879: domain -> force to color decorate a page for a specific
4880: domain
4881: function -> force usage of a specific rolish color scheme
4882: bgcolor -> override the default page bgcolor
4883:
4884: =cut
4885:
1.343 albertel 4886: sub standard_css {
1.345 albertel 4887: my ($function,$domain,$bgcolor) = @_;
1.352 albertel 4888: $function = &get_users_function() if (!$function);
4889: my $img = &designparm($function.'.img', $domain);
4890: my $tabbg = &designparm($function.'.tabbg', $domain);
4891: my $font = &designparm($function.'.font', $domain);
1.801 tempelho 4892: my $fontmenu = &designparm($function.'.fontmenu', $domain);
1.791 tempelho 4893: #second colour for later usage
1.345 albertel 4894: my $sidebg = &designparm($function.'.sidebg',$domain);
1.382 albertel 4895: my $pgbg_or_bgcolor =
4896: $bgcolor ||
1.352 albertel 4897: &designparm($function.'.pgbg', $domain);
1.382 albertel 4898: my $pgbg = &designparm($function.'.pgbg', $domain);
1.352 albertel 4899: my $alink = &designparm($function.'.alink', $domain);
4900: my $vlink = &designparm($function.'.vlink', $domain);
4901: my $link = &designparm($function.'.link', $domain);
4902:
1.602 albertel 4903: my $sans = 'Verdana,Arial,Helvetica,sans-serif';
1.395 albertel 4904: my $mono = 'monospace';
1.850 bisitz 4905: my $data_table_head = $sidebg;
4906: my $data_table_light = '#FAFAFA';
4907: my $data_table_dark = '#F0F0F0';
1.470 banghart 4908: my $data_table_darker = '#CCCCCC';
1.349 albertel 4909: my $data_table_highlight = '#FFFF00';
1.352 albertel 4910: my $mail_new = '#FFBB77';
4911: my $mail_new_hover = '#DD9955';
4912: my $mail_read = '#BBBB77';
4913: my $mail_read_hover = '#999944';
4914: my $mail_replied = '#AAAA88';
4915: my $mail_replied_hover = '#888855';
4916: my $mail_other = '#99BBBB';
4917: my $mail_other_hover = '#669999';
1.391 albertel 4918: my $table_header = '#DDDDDD';
1.489 raeburn 4919: my $feedback_link_bg = '#BBBBBB';
1.911 bisitz 4920: my $lg_border_color = '#C8C8C8';
1.948.2.1 raeburn 4921: my $button_hover = '#BF2317';
1.392 albertel 4922:
1.608 albertel 4923: my $border = ($env{'browser.type'} eq 'explorer' ||
1.911 bisitz 4924: $env{'browser.type'} eq 'safari' ) ? '0 2px 0 2px'
4925: : '0 3px 0 4px';
1.448 albertel 4926:
1.343 albertel 4927: return <<END;
1.947 droeschl 4928:
4929: /* needed for iframe to allow 100% height in FF */
4930: body, html {
4931: margin: 0;
4932: padding: 0 0.5%;
4933: height: 99%; /* to avoid scrollbars */
4934: }
4935:
1.795 www 4936: body {
1.911 bisitz 4937: font-family: $sans;
4938: line-height:130%;
4939: font-size:0.83em;
4940: color:$font;
1.795 www 4941: }
4942:
1.948.2.9 raeburn 4943: a:focus,
4944: a:focus img {
1.795 www 4945: color: red;
1.911 bisitz 4946: background: yellow;
1.795 www 4947: }
1.698 harmsja 4948:
1.911 bisitz 4949: form, .inline {
4950: display: inline;
1.795 www 4951: }
1.721 harmsja 4952:
1.795 www 4953: .LC_right {
1.911 bisitz 4954: text-align:right;
1.795 www 4955: }
4956:
4957: .LC_middle {
1.911 bisitz 4958: vertical-align:middle;
1.795 www 4959: }
1.721 harmsja 4960:
1.911 bisitz 4961: .LC_400Box {
4962: width:400px;
4963: }
1.721 harmsja 4964:
1.947 droeschl 4965: .LC_iframecontainer {
4966: width: 98%;
4967: margin: 0;
4968: position: fixed;
4969: top: 8.5em;
4970: bottom: 0;
4971: }
4972:
4973: .LC_iframecontainer iframe{
4974: border: none;
4975: width: 100%;
4976: height: 100%;
4977: }
4978:
1.778 bisitz 4979: .LC_filename {
4980: font-family: $mono;
4981: white-space:pre;
1.921 bisitz 4982: font-size: 120%;
1.778 bisitz 4983: }
4984:
4985: .LC_fileicon {
4986: border: none;
4987: height: 1.3em;
4988: vertical-align: text-bottom;
4989: margin-right: 0.3em;
4990: text-decoration:none;
4991: }
4992:
1.350 albertel 4993: .LC_error {
4994: color: red;
4995: font-size: larger;
4996: }
1.795 www 4997:
1.457 albertel 4998: .LC_warning,
4999: .LC_diff_removed {
1.733 bisitz 5000: color: red;
1.394 albertel 5001: }
1.532 albertel 5002:
5003: .LC_info,
1.457 albertel 5004: .LC_success,
5005: .LC_diff_added {
1.350 albertel 5006: color: green;
5007: }
1.795 www 5008:
1.802 bisitz 5009: div.LC_confirm_box {
5010: background-color: #FAFAFA;
5011: border: 1px solid $lg_border_color;
5012: margin-right: 0;
5013: padding: 5px;
5014: }
5015:
5016: div.LC_confirm_box .LC_error img,
5017: div.LC_confirm_box .LC_success img {
5018: vertical-align: middle;
5019: }
5020:
1.440 albertel 5021: .LC_icon {
1.771 droeschl 5022: border: none;
1.790 droeschl 5023: vertical-align: middle;
1.771 droeschl 5024: }
5025:
1.543 albertel 5026: .LC_docs_spacer {
5027: width: 25px;
5028: height: 1px;
1.771 droeschl 5029: border: none;
1.543 albertel 5030: }
1.346 albertel 5031:
1.532 albertel 5032: .LC_internal_info {
1.735 bisitz 5033: color: #999999;
1.532 albertel 5034: }
5035:
1.794 www 5036: .LC_discussion {
1.911 bisitz 5037: background: $tabbg;
5038: border: 1px solid black;
5039: margin: 2px;
1.794 www 5040: }
5041:
5042: .LC_disc_action_links_bar {
1.911 bisitz 5043: background: $tabbg;
5044: border: none;
5045: margin: 4px;
1.794 www 5046: }
5047:
5048: .LC_disc_action_left {
1.911 bisitz 5049: text-align: left;
1.794 www 5050: }
5051:
5052: .LC_disc_action_right {
1.911 bisitz 5053: text-align: right;
1.794 www 5054: }
5055:
5056: .LC_disc_new_item {
1.911 bisitz 5057: background: white;
5058: border: 2px solid red;
5059: margin: 2px;
1.794 www 5060: }
5061:
5062: .LC_disc_old_item {
1.911 bisitz 5063: background: white;
5064: border: 1px solid black;
5065: margin: 2px;
1.794 www 5066: }
5067:
1.458 albertel 5068: table.LC_pastsubmission {
5069: border: 1px solid black;
5070: margin: 2px;
5071: }
5072:
1.924 bisitz 5073: table#LC_menubuttons {
1.345 albertel 5074: width: 100%;
5075: background: $pgbg;
1.392 albertel 5076: border: 2px;
1.402 albertel 5077: border-collapse: separate;
1.803 bisitz 5078: padding: 0;
1.345 albertel 5079: }
1.392 albertel 5080:
1.801 tempelho 5081: table#LC_title_bar a {
5082: color: $fontmenu;
5083: }
1.836 bisitz 5084:
1.807 droeschl 5085: table#LC_title_bar {
1.819 tempelho 5086: clear: both;
1.836 bisitz 5087: display: none;
1.807 droeschl 5088: }
5089:
1.795 www 5090: table#LC_title_bar,
1.933 droeschl 5091: table.LC_breadcrumbs, /* obsolete? */
1.393 albertel 5092: table#LC_title_bar.LC_with_remote {
1.359 albertel 5093: width: 100%;
1.392 albertel 5094: border-color: $pgbg;
5095: border-style: solid;
5096: border-width: $border;
1.379 albertel 5097: background: $pgbg;
1.801 tempelho 5098: color: $fontmenu;
1.392 albertel 5099: border-collapse: collapse;
1.803 bisitz 5100: padding: 0;
1.819 tempelho 5101: margin: 0;
1.359 albertel 5102: }
1.795 www 5103:
1.933 droeschl 5104: ul.LC_breadcrumb_tools_outerlist {
1.913 droeschl 5105: margin: 0;
5106: padding: 0;
1.933 droeschl 5107: position: relative;
5108: list-style: none;
1.913 droeschl 5109: }
1.933 droeschl 5110: ul.LC_breadcrumb_tools_outerlist li {
1.913 droeschl 5111: display: inline;
5112: }
1.933 droeschl 5113:
5114: .LC_breadcrumb_tools_navigation {
1.913 droeschl 5115: padding: 0;
1.933 droeschl 5116: margin: 0;
5117: float: left;
1.913 droeschl 5118: }
1.933 droeschl 5119: .LC_breadcrumb_tools_tools {
5120: padding: 0;
5121: margin: 0;
1.913 droeschl 5122: float: right;
5123: }
5124:
1.359 albertel 5125: table#LC_title_bar td {
5126: background: $tabbg;
5127: }
1.795 www 5128:
1.911 bisitz 5129: table#LC_menubuttons img {
1.803 bisitz 5130: border: none;
1.346 albertel 5131: }
1.795 www 5132:
1.842 droeschl 5133: .LC_breadcrumbs_component {
1.911 bisitz 5134: float: right;
5135: margin: 0 1em;
1.357 albertel 5136: }
1.842 droeschl 5137: .LC_breadcrumbs_component img {
1.911 bisitz 5138: vertical-align: middle;
1.777 tempelho 5139: }
1.795 www 5140:
1.383 albertel 5141: td.LC_table_cell_checkbox {
5142: text-align: center;
5143: }
1.795 www 5144:
5145: .LC_fontsize_small {
1.911 bisitz 5146: font-size: 70%;
1.705 tempelho 5147: }
5148:
1.844 bisitz 5149: #LC_breadcrumbs {
1.911 bisitz 5150: clear:both;
5151: background: $sidebg;
5152: border-bottom: 1px solid $lg_border_color;
5153: line-height: 2.5em;
1.933 droeschl 5154: overflow: hidden;
1.911 bisitz 5155: margin: 0;
5156: padding: 0;
1.819 tempelho 5157: }
1.862 bisitz 5158:
1.839 droeschl 5159: /* Preliminary fix to hide breadcrumbs inside remote control window */
1.844 bisitz 5160: #LC_remote #LC_breadcrumbs {
1.911 bisitz 5161: display:none;
1.839 droeschl 5162: }
1.819 tempelho 5163:
1.844 bisitz 5164: #LC_head_subbox {
1.911 bisitz 5165: clear:both;
5166: background: #F8F8F8; /* $sidebg; */
1.915 droeschl 5167: border: 1px solid $sidebg;
5168: margin: 0 0 10px 0;
1.948.2.6 raeburn 5169: padding: 3px;
1.822 bisitz 5170: }
5171:
1.795 www 5172: .LC_fontsize_medium {
1.911 bisitz 5173: font-size: 85%;
1.705 tempelho 5174: }
5175:
1.795 www 5176: .LC_fontsize_large {
1.911 bisitz 5177: font-size: 120%;
1.705 tempelho 5178: }
5179:
1.346 albertel 5180: .LC_menubuttons_inline_text {
5181: color: $font;
1.698 harmsja 5182: font-size: 90%;
1.701 harmsja 5183: padding-left:3px;
1.346 albertel 5184: }
5185:
1.934 droeschl 5186: .LC_menubuttons_inline_text img{
5187: vertical-align: middle;
5188: }
5189:
1.948.2.1 raeburn 5190: li.LC_menubuttons_inline_text img,a {
5191: cursor:pointer;
5192: }
5193:
1.526 www 5194: .LC_menubuttons_link {
5195: text-decoration: none;
5196: }
1.795 www 5197:
1.522 albertel 5198: .LC_menubuttons_category {
1.521 www 5199: color: $font;
1.526 www 5200: background: $pgbg;
1.521 www 5201: font-size: larger;
5202: font-weight: bold;
5203: }
5204:
1.346 albertel 5205: td.LC_menubuttons_text {
1.911 bisitz 5206: color: $font;
1.346 albertel 5207: }
1.706 harmsja 5208:
1.346 albertel 5209: .LC_current_location {
5210: background: $tabbg;
5211: }
1.795 www 5212:
1.938 bisitz 5213: table.LC_data_table {
1.347 albertel 5214: border: 1px solid #000000;
1.402 albertel 5215: border-collapse: separate;
1.426 albertel 5216: border-spacing: 1px;
1.610 albertel 5217: background: $pgbg;
1.347 albertel 5218: }
1.795 www 5219:
1.422 albertel 5220: .LC_data_table_dense {
5221: font-size: small;
5222: }
1.795 www 5223:
1.507 raeburn 5224: table.LC_nested_outer {
5225: border: 1px solid #000000;
1.589 raeburn 5226: border-collapse: collapse;
1.803 bisitz 5227: border-spacing: 0;
1.507 raeburn 5228: width: 100%;
5229: }
1.795 www 5230:
1.879 raeburn 5231: table.LC_innerpickbox,
1.507 raeburn 5232: table.LC_nested {
1.803 bisitz 5233: border: none;
1.589 raeburn 5234: border-collapse: collapse;
1.803 bisitz 5235: border-spacing: 0;
1.507 raeburn 5236: width: 100%;
5237: }
1.795 www 5238:
1.930 faziophi 5239: .ui-accordion,
5240: .ui-accordion table.LC_data_table,
5241: .ui-accordion table.LC_nested_outer{
5242: border: 0px;
5243: border-spacing: 0px;
5244: margin: 3px;
5245: }
5246:
1.911 bisitz 5247: table.LC_data_table tr th,
5248: table.LC_calendar tr th,
1.879 raeburn 5249: table.LC_prior_tries tr th,
5250: table.LC_innerpickbox tr th {
1.349 albertel 5251: font-weight: bold;
5252: background-color: $data_table_head;
1.801 tempelho 5253: color:$fontmenu;
1.701 harmsja 5254: font-size:90%;
1.347 albertel 5255: }
1.795 www 5256:
1.879 raeburn 5257: table.LC_innerpickbox tr th,
5258: table.LC_innerpickbox tr td {
5259: vertical-align: top;
5260: }
5261:
1.711 raeburn 5262: table.LC_data_table tr.LC_info_row > td {
1.735 bisitz 5263: background-color: #CCCCCC;
1.711 raeburn 5264: font-weight: bold;
5265: text-align: left;
5266: }
1.795 www 5267:
1.912 bisitz 5268: table.LC_data_table tr.LC_odd_row > td {
5269: background-color: $data_table_light;
5270: padding: 2px;
5271: vertical-align: top;
5272: }
5273:
1.809 bisitz 5274: table.LC_pick_box tr > td.LC_odd_row {
1.349 albertel 5275: background-color: $data_table_light;
1.912 bisitz 5276: vertical-align: top;
5277: }
5278:
5279: table.LC_data_table tr.LC_even_row > td {
5280: background-color: $data_table_dark;
1.425 albertel 5281: padding: 2px;
1.900 bisitz 5282: vertical-align: top;
1.347 albertel 5283: }
1.795 www 5284:
1.809 bisitz 5285: table.LC_pick_box tr > td.LC_even_row {
1.349 albertel 5286: background-color: $data_table_dark;
1.900 bisitz 5287: vertical-align: top;
1.347 albertel 5288: }
1.795 www 5289:
1.425 albertel 5290: table.LC_data_table tr.LC_data_table_highlight td {
5291: background-color: $data_table_darker;
5292: }
1.795 www 5293:
1.639 raeburn 5294: table.LC_data_table tr td.LC_leftcol_header {
5295: background-color: $data_table_head;
5296: font-weight: bold;
5297: }
1.795 www 5298:
1.451 albertel 5299: table.LC_data_table tr.LC_empty_row td,
1.507 raeburn 5300: table.LC_nested tr.LC_empty_row td {
1.421 albertel 5301: font-weight: bold;
5302: font-style: italic;
5303: text-align: center;
5304: padding: 8px;
1.347 albertel 5305: }
1.795 www 5306:
1.940 bisitz 5307: table.LC_data_table tr.LC_empty_row td {
5308: background-color: $sidebg;
5309: }
5310:
5311: table.LC_nested tr.LC_empty_row td {
5312: background-color: #FFFFFF;
5313: }
5314:
1.890 droeschl 5315: table.LC_caption {
5316: }
5317:
1.507 raeburn 5318: table.LC_nested tr.LC_empty_row td {
1.465 albertel 5319: padding: 4ex
5320: }
1.795 www 5321:
1.507 raeburn 5322: table.LC_nested_outer tr th {
5323: font-weight: bold;
1.801 tempelho 5324: color:$fontmenu;
1.507 raeburn 5325: background-color: $data_table_head;
1.701 harmsja 5326: font-size: small;
1.507 raeburn 5327: border-bottom: 1px solid #000000;
5328: }
1.795 www 5329:
1.507 raeburn 5330: table.LC_nested_outer tr td.LC_subheader {
5331: background-color: $data_table_head;
5332: font-weight: bold;
5333: font-size: small;
5334: border-bottom: 1px solid #000000;
5335: text-align: right;
1.451 albertel 5336: }
1.795 www 5337:
1.507 raeburn 5338: table.LC_nested tr.LC_info_row td {
1.735 bisitz 5339: background-color: #CCCCCC;
1.451 albertel 5340: font-weight: bold;
5341: font-size: small;
1.507 raeburn 5342: text-align: center;
5343: }
1.795 www 5344:
1.589 raeburn 5345: table.LC_nested tr.LC_info_row td.LC_left_item,
5346: table.LC_nested_outer tr th.LC_left_item {
1.507 raeburn 5347: text-align: left;
1.451 albertel 5348: }
1.795 www 5349:
1.507 raeburn 5350: table.LC_nested td {
1.735 bisitz 5351: background-color: #FFFFFF;
1.451 albertel 5352: font-size: small;
1.507 raeburn 5353: }
1.795 www 5354:
1.507 raeburn 5355: table.LC_nested_outer tr th.LC_right_item,
5356: table.LC_nested tr.LC_info_row td.LC_right_item,
5357: table.LC_nested tr.LC_odd_row td.LC_right_item,
5358: table.LC_nested tr td.LC_right_item {
1.451 albertel 5359: text-align: right;
5360: }
5361:
1.930 faziophi 5362: .ui-accordion table.LC_nested tr.LC_odd_row td.LC_left_item,
5363: .ui-accordion table.LC_nested tr.LC_even_row td.LC_left_item {
5364: text-align: right;
5365: width: 40%;
5366: padding-right:10px;
5367: vertical-align: top;
5368: padding: 5px;
5369: }
5370:
5371: .ui-accordion table.LC_nested tr.LC_odd_row td.LC_right_item,
5372: .ui-accordion table.LC_nested tr.LC_even_row td.LC_right_item {
5373: text-align: left;
5374: width: 60%;
5375: padding: 2px 4px;
5376: }
5377:
1.507 raeburn 5378: table.LC_nested tr.LC_odd_row td {
1.735 bisitz 5379: background-color: #EEEEEE;
1.451 albertel 5380: }
5381:
1.473 raeburn 5382: table.LC_createuser {
5383: }
5384:
5385: table.LC_createuser tr.LC_section_row td {
1.701 harmsja 5386: font-size: small;
1.473 raeburn 5387: }
5388:
5389: table.LC_createuser tr.LC_info_row td {
1.735 bisitz 5390: background-color: #CCCCCC;
1.473 raeburn 5391: font-weight: bold;
5392: text-align: center;
5393: }
5394:
1.349 albertel 5395: table.LC_calendar {
5396: border: 1px solid #000000;
5397: border-collapse: collapse;
1.917 raeburn 5398: width: 98%;
1.349 albertel 5399: }
1.795 www 5400:
1.349 albertel 5401: table.LC_calendar_pickdate {
5402: font-size: xx-small;
5403: }
1.795 www 5404:
1.349 albertel 5405: table.LC_calendar tr td {
5406: border: 1px solid #000000;
5407: vertical-align: top;
1.917 raeburn 5408: width: 14%;
1.349 albertel 5409: }
1.795 www 5410:
1.349 albertel 5411: table.LC_calendar tr td.LC_calendar_day_empty {
5412: background-color: $data_table_dark;
5413: }
1.795 www 5414:
1.779 bisitz 5415: table.LC_calendar tr td.LC_calendar_day_current {
5416: background-color: $data_table_highlight;
1.777 tempelho 5417: }
1.795 www 5418:
1.938 bisitz 5419: table.LC_data_table tr td.LC_mail_new {
1.349 albertel 5420: background-color: $mail_new;
5421: }
1.795 www 5422:
1.938 bisitz 5423: table.LC_data_table tr.LC_mail_new:hover {
1.349 albertel 5424: background-color: $mail_new_hover;
5425: }
1.795 www 5426:
1.938 bisitz 5427: table.LC_data_table tr td.LC_mail_read {
1.349 albertel 5428: background-color: $mail_read;
5429: }
1.795 www 5430:
1.938 bisitz 5431: /*
5432: table.LC_data_table tr.LC_mail_read:hover {
1.349 albertel 5433: background-color: $mail_read_hover;
5434: }
1.938 bisitz 5435: */
1.795 www 5436:
1.938 bisitz 5437: table.LC_data_table tr td.LC_mail_replied {
1.349 albertel 5438: background-color: $mail_replied;
5439: }
1.795 www 5440:
1.938 bisitz 5441: /*
5442: table.LC_data_table tr.LC_mail_replied:hover {
1.349 albertel 5443: background-color: $mail_replied_hover;
5444: }
1.938 bisitz 5445: */
1.795 www 5446:
1.938 bisitz 5447: table.LC_data_table tr td.LC_mail_other {
1.349 albertel 5448: background-color: $mail_other;
5449: }
1.795 www 5450:
1.938 bisitz 5451: /*
5452: table.LC_data_table tr.LC_mail_other:hover {
1.349 albertel 5453: background-color: $mail_other_hover;
5454: }
1.938 bisitz 5455: */
1.494 raeburn 5456:
1.777 tempelho 5457: table.LC_data_table tr > td.LC_browser_file,
5458: table.LC_data_table tr > td.LC_browser_file_published {
1.899 bisitz 5459: background: #AAEE77;
1.389 albertel 5460: }
1.795 www 5461:
1.777 tempelho 5462: table.LC_data_table tr > td.LC_browser_file_locked,
5463: table.LC_data_table tr > td.LC_browser_file_unpublished {
1.389 albertel 5464: background: #FFAA99;
1.387 albertel 5465: }
1.795 www 5466:
1.777 tempelho 5467: table.LC_data_table tr > td.LC_browser_file_obsolete {
1.899 bisitz 5468: background: #888888;
1.779 bisitz 5469: }
1.795 www 5470:
1.777 tempelho 5471: table.LC_data_table tr > td.LC_browser_file_modified,
1.779 bisitz 5472: table.LC_data_table tr > td.LC_browser_file_metamodified {
1.899 bisitz 5473: background: #F8F866;
1.777 tempelho 5474: }
1.795 www 5475:
1.696 bisitz 5476: table.LC_data_table tr.LC_browser_folder > td {
1.899 bisitz 5477: background: #E0E8FF;
1.387 albertel 5478: }
1.696 bisitz 5479:
1.707 bisitz 5480: table.LC_data_table tr > td.LC_roles_is {
1.911 bisitz 5481: /* background: #77FF77; */
1.707 bisitz 5482: }
1.795 www 5483:
1.707 bisitz 5484: table.LC_data_table tr > td.LC_roles_future {
1.939 bisitz 5485: border-right: 8px solid #FFFF77;
1.707 bisitz 5486: }
1.795 www 5487:
1.707 bisitz 5488: table.LC_data_table tr > td.LC_roles_will {
1.939 bisitz 5489: border-right: 8px solid #FFAA77;
1.707 bisitz 5490: }
1.795 www 5491:
1.707 bisitz 5492: table.LC_data_table tr > td.LC_roles_expired {
1.939 bisitz 5493: border-right: 8px solid #FF7777;
1.707 bisitz 5494: }
1.795 www 5495:
1.707 bisitz 5496: table.LC_data_table tr > td.LC_roles_will_not {
1.939 bisitz 5497: border-right: 8px solid #AAFF77;
1.707 bisitz 5498: }
1.795 www 5499:
1.707 bisitz 5500: table.LC_data_table tr > td.LC_roles_selected {
1.939 bisitz 5501: border-right: 8px solid #11CC55;
1.707 bisitz 5502: }
5503:
1.388 albertel 5504: span.LC_current_location {
1.701 harmsja 5505: font-size:larger;
1.388 albertel 5506: background: $pgbg;
5507: }
1.387 albertel 5508:
1.395 albertel 5509: span.LC_parm_menu_item {
5510: font-size: larger;
5511: }
1.795 www 5512:
1.395 albertel 5513: span.LC_parm_scope_all {
5514: color: red;
5515: }
1.795 www 5516:
1.395 albertel 5517: span.LC_parm_scope_folder {
5518: color: green;
5519: }
1.795 www 5520:
1.395 albertel 5521: span.LC_parm_scope_resource {
5522: color: orange;
5523: }
1.795 www 5524:
1.395 albertel 5525: span.LC_parm_part {
5526: color: blue;
5527: }
1.795 www 5528:
1.911 bisitz 5529: span.LC_parm_folder,
5530: span.LC_parm_symb {
1.395 albertel 5531: font-size: x-small;
5532: font-family: $mono;
5533: color: #AAAAAA;
5534: }
5535:
1.948.2.8 raeburn 5536: ul.LC_parm_parmlist li {
5537: display: inline-block;
5538: padding: 0.3em 0.8em;
5539: vertical-align: top;
5540: width: 150px;
5541: border-top:1px solid $lg_border_color;
5542: }
5543:
1.795 www 5544: td.LC_parm_overview_level_menu,
5545: td.LC_parm_overview_map_menu,
5546: td.LC_parm_overview_parm_selectors,
5547: td.LC_parm_overview_restrictions {
1.396 albertel 5548: border: 1px solid black;
5549: border-collapse: collapse;
5550: }
1.795 www 5551:
1.396 albertel 5552: table.LC_parm_overview_restrictions td {
5553: border-width: 1px 4px 1px 4px;
5554: border-style: solid;
5555: border-color: $pgbg;
5556: text-align: center;
5557: }
1.795 www 5558:
1.396 albertel 5559: table.LC_parm_overview_restrictions th {
5560: background: $tabbg;
5561: border-width: 1px 4px 1px 4px;
5562: border-style: solid;
5563: border-color: $pgbg;
5564: }
1.795 www 5565:
1.398 albertel 5566: table#LC_helpmenu {
1.803 bisitz 5567: border: none;
1.398 albertel 5568: height: 55px;
1.803 bisitz 5569: border-spacing: 0;
1.398 albertel 5570: }
5571:
5572: table#LC_helpmenu fieldset legend {
5573: font-size: larger;
5574: }
1.795 www 5575:
1.397 albertel 5576: table#LC_helpmenu_links {
5577: width: 100%;
5578: border: 1px solid black;
5579: background: $pgbg;
1.803 bisitz 5580: padding: 0;
1.397 albertel 5581: border-spacing: 1px;
5582: }
1.795 www 5583:
1.397 albertel 5584: table#LC_helpmenu_links tr td {
5585: padding: 1px;
5586: background: $tabbg;
1.399 albertel 5587: text-align: center;
5588: font-weight: bold;
1.397 albertel 5589: }
1.396 albertel 5590:
1.795 www 5591: table#LC_helpmenu_links a:link,
5592: table#LC_helpmenu_links a:visited,
1.397 albertel 5593: table#LC_helpmenu_links a:active {
5594: text-decoration: none;
5595: color: $font;
5596: }
1.795 www 5597:
1.397 albertel 5598: table#LC_helpmenu_links a:hover {
5599: text-decoration: underline;
5600: color: $vlink;
5601: }
1.396 albertel 5602:
1.417 albertel 5603: .LC_chrt_popup_exists {
5604: border: 1px solid #339933;
5605: margin: -1px;
5606: }
1.795 www 5607:
1.417 albertel 5608: .LC_chrt_popup_up {
5609: border: 1px solid yellow;
5610: margin: -1px;
5611: }
1.795 www 5612:
1.417 albertel 5613: .LC_chrt_popup {
5614: border: 1px solid #8888FF;
5615: background: #CCCCFF;
5616: }
1.795 www 5617:
1.421 albertel 5618: table.LC_pick_box {
5619: border-collapse: separate;
5620: background: white;
5621: border: 1px solid black;
5622: border-spacing: 1px;
5623: }
1.795 www 5624:
1.421 albertel 5625: table.LC_pick_box td.LC_pick_box_title {
1.850 bisitz 5626: background: $sidebg;
1.421 albertel 5627: font-weight: bold;
1.900 bisitz 5628: text-align: left;
1.740 bisitz 5629: vertical-align: top;
1.421 albertel 5630: width: 184px;
5631: padding: 8px;
5632: }
1.795 www 5633:
1.579 raeburn 5634: table.LC_pick_box td.LC_pick_box_value {
5635: text-align: left;
5636: padding: 8px;
5637: }
1.795 www 5638:
1.579 raeburn 5639: table.LC_pick_box td.LC_pick_box_select {
5640: text-align: left;
5641: padding: 8px;
5642: }
1.795 www 5643:
1.424 albertel 5644: table.LC_pick_box td.LC_pick_box_separator {
1.803 bisitz 5645: padding: 0;
1.421 albertel 5646: height: 1px;
5647: background: black;
5648: }
1.795 www 5649:
1.421 albertel 5650: table.LC_pick_box td.LC_pick_box_submit {
5651: text-align: right;
5652: }
1.795 www 5653:
1.579 raeburn 5654: table.LC_pick_box td.LC_evenrow_value {
5655: text-align: left;
5656: padding: 8px;
5657: background-color: $data_table_light;
5658: }
1.795 www 5659:
1.579 raeburn 5660: table.LC_pick_box td.LC_oddrow_value {
5661: text-align: left;
5662: padding: 8px;
5663: background-color: $data_table_light;
5664: }
1.795 www 5665:
1.579 raeburn 5666: span.LC_helpform_receipt_cat {
5667: font-weight: bold;
5668: }
1.795 www 5669:
1.424 albertel 5670: table.LC_group_priv_box {
5671: background: white;
5672: border: 1px solid black;
5673: border-spacing: 1px;
5674: }
1.795 www 5675:
1.424 albertel 5676: table.LC_group_priv_box td.LC_pick_box_title {
5677: background: $tabbg;
5678: font-weight: bold;
5679: text-align: right;
5680: width: 184px;
5681: }
1.795 www 5682:
1.424 albertel 5683: table.LC_group_priv_box td.LC_groups_fixed {
5684: background: $data_table_light;
5685: text-align: center;
5686: }
1.795 www 5687:
1.424 albertel 5688: table.LC_group_priv_box td.LC_groups_optional {
5689: background: $data_table_dark;
5690: text-align: center;
5691: }
1.795 www 5692:
1.424 albertel 5693: table.LC_group_priv_box td.LC_groups_functionality {
5694: background: $data_table_darker;
5695: text-align: center;
5696: font-weight: bold;
5697: }
1.795 www 5698:
1.424 albertel 5699: table.LC_group_priv td {
5700: text-align: left;
1.803 bisitz 5701: padding: 0;
1.424 albertel 5702: }
5703:
1.421 albertel 5704: table.LC_notify_front_page {
5705: background: white;
5706: border: 1px solid black;
5707: padding: 8px;
5708: }
1.795 www 5709:
1.421 albertel 5710: table.LC_notify_front_page td {
5711: padding: 8px;
5712: }
1.795 www 5713:
1.424 albertel 5714: .LC_navbuttons {
5715: margin: 2ex 0ex 2ex 0ex;
5716: }
1.795 www 5717:
1.423 albertel 5718: .LC_topic_bar {
5719: font-weight: bold;
5720: background: $tabbg;
1.918 wenzelju 5721: margin: 1em 0em 1em 2em;
1.805 bisitz 5722: padding: 3px;
1.918 wenzelju 5723: font-size: 1.2em;
1.423 albertel 5724: }
1.795 www 5725:
1.423 albertel 5726: .LC_topic_bar span {
1.918 wenzelju 5727: left: 0.5em;
5728: position: absolute;
1.423 albertel 5729: vertical-align: middle;
1.918 wenzelju 5730: font-size: 1.2em;
1.423 albertel 5731: }
1.795 www 5732:
1.423 albertel 5733: table.LC_course_group_status {
5734: margin: 20px;
5735: }
1.795 www 5736:
1.423 albertel 5737: table.LC_status_selector td {
5738: vertical-align: top;
5739: text-align: center;
1.424 albertel 5740: padding: 4px;
5741: }
1.795 www 5742:
1.599 albertel 5743: div.LC_feedback_link {
1.616 albertel 5744: clear: both;
1.829 kalberla 5745: background: $sidebg;
1.779 bisitz 5746: width: 100%;
1.829 kalberla 5747: padding-bottom: 10px;
5748: border: 1px $tabbg solid;
1.833 kalberla 5749: height: 22px;
5750: line-height: 22px;
5751: padding-top: 5px;
5752: }
5753:
5754: div.LC_feedback_link img {
5755: height: 22px;
1.867 kalberla 5756: vertical-align:middle;
1.829 kalberla 5757: }
5758:
1.911 bisitz 5759: div.LC_feedback_link a {
1.829 kalberla 5760: text-decoration: none;
1.489 raeburn 5761: }
1.795 www 5762:
1.867 kalberla 5763: div.LC_comblock {
1.911 bisitz 5764: display:inline;
1.867 kalberla 5765: color:$font;
5766: font-size:90%;
5767: }
5768:
5769: div.LC_feedback_link div.LC_comblock {
5770: padding-left:5px;
5771: }
5772:
5773: div.LC_feedback_link div.LC_comblock a {
5774: color:$font;
5775: }
5776:
1.489 raeburn 5777: span.LC_feedback_link {
1.858 bisitz 5778: /* background: $feedback_link_bg; */
1.599 albertel 5779: font-size: larger;
5780: }
1.795 www 5781:
1.599 albertel 5782: span.LC_message_link {
1.858 bisitz 5783: /* background: $feedback_link_bg; */
1.599 albertel 5784: font-size: larger;
5785: position: absolute;
5786: right: 1em;
1.489 raeburn 5787: }
1.421 albertel 5788:
1.515 albertel 5789: table.LC_prior_tries {
1.524 albertel 5790: border: 1px solid #000000;
5791: border-collapse: separate;
5792: border-spacing: 1px;
1.515 albertel 5793: }
1.523 albertel 5794:
1.515 albertel 5795: table.LC_prior_tries td {
1.524 albertel 5796: padding: 2px;
1.515 albertel 5797: }
1.523 albertel 5798:
5799: .LC_answer_correct {
1.795 www 5800: background: lightgreen;
5801: color: darkgreen;
5802: padding: 6px;
1.523 albertel 5803: }
1.795 www 5804:
1.523 albertel 5805: .LC_answer_charged_try {
1.797 www 5806: background: #FFAAAA;
1.795 www 5807: color: darkred;
5808: padding: 6px;
1.523 albertel 5809: }
1.795 www 5810:
1.779 bisitz 5811: .LC_answer_not_charged_try,
1.523 albertel 5812: .LC_answer_no_grade,
5813: .LC_answer_late {
1.795 www 5814: background: lightyellow;
1.523 albertel 5815: color: black;
1.795 www 5816: padding: 6px;
1.523 albertel 5817: }
1.795 www 5818:
1.523 albertel 5819: .LC_answer_previous {
1.795 www 5820: background: lightblue;
5821: color: darkblue;
5822: padding: 6px;
1.523 albertel 5823: }
1.795 www 5824:
1.779 bisitz 5825: .LC_answer_no_message {
1.777 tempelho 5826: background: #FFFFFF;
5827: color: black;
1.795 www 5828: padding: 6px;
1.779 bisitz 5829: }
1.795 www 5830:
1.779 bisitz 5831: .LC_answer_unknown {
5832: background: orange;
5833: color: black;
1.795 www 5834: padding: 6px;
1.777 tempelho 5835: }
1.795 www 5836:
1.529 albertel 5837: span.LC_prior_numerical,
5838: span.LC_prior_string,
5839: span.LC_prior_custom,
5840: span.LC_prior_reaction,
5841: span.LC_prior_math {
1.925 bisitz 5842: font-family: $mono;
1.523 albertel 5843: white-space: pre;
5844: }
5845:
1.525 albertel 5846: span.LC_prior_string {
1.925 bisitz 5847: font-family: $mono;
1.525 albertel 5848: white-space: pre;
5849: }
5850:
1.523 albertel 5851: table.LC_prior_option {
5852: width: 100%;
5853: border-collapse: collapse;
5854: }
1.795 www 5855:
1.911 bisitz 5856: table.LC_prior_rank,
1.795 www 5857: table.LC_prior_match {
1.528 albertel 5858: border-collapse: collapse;
5859: }
1.795 www 5860:
1.528 albertel 5861: table.LC_prior_option tr td,
5862: table.LC_prior_rank tr td,
5863: table.LC_prior_match tr td {
1.524 albertel 5864: border: 1px solid #000000;
1.515 albertel 5865: }
5866:
1.855 bisitz 5867: .LC_nobreak {
1.544 albertel 5868: white-space: nowrap;
1.519 raeburn 5869: }
5870:
1.576 raeburn 5871: span.LC_cusr_emph {
5872: font-style: italic;
5873: }
5874:
1.633 raeburn 5875: span.LC_cusr_subheading {
5876: font-weight: normal;
5877: font-size: 85%;
5878: }
5879:
1.861 bisitz 5880: div.LC_docs_entry_move {
1.859 bisitz 5881: border: 1px solid #BBBBBB;
1.545 albertel 5882: background: #DDDDDD;
1.861 bisitz 5883: width: 22px;
1.859 bisitz 5884: padding: 1px;
5885: margin: 0;
1.545 albertel 5886: }
5887:
1.861 bisitz 5888: table.LC_data_table tr > td.LC_docs_entry_commands,
5889: table.LC_data_table tr > td.LC_docs_entry_parameter {
1.545 albertel 5890: background: #DDDDDD;
5891: font-size: x-small;
5892: }
1.795 www 5893:
1.861 bisitz 5894: .LC_docs_entry_parameter {
5895: white-space: nowrap;
5896: }
5897:
1.544 albertel 5898: .LC_docs_copy {
1.545 albertel 5899: color: #000099;
1.544 albertel 5900: }
1.795 www 5901:
1.544 albertel 5902: .LC_docs_cut {
1.545 albertel 5903: color: #550044;
1.544 albertel 5904: }
1.795 www 5905:
1.544 albertel 5906: .LC_docs_rename {
1.545 albertel 5907: color: #009900;
1.544 albertel 5908: }
1.795 www 5909:
1.544 albertel 5910: .LC_docs_remove {
1.545 albertel 5911: color: #990000;
5912: }
5913:
1.547 albertel 5914: .LC_docs_reinit_warn,
5915: .LC_docs_ext_edit {
5916: font-size: x-small;
5917: }
5918:
1.545 albertel 5919: table.LC_docs_adddocs td,
5920: table.LC_docs_adddocs th {
5921: border: 1px solid #BBBBBB;
5922: padding: 4px;
5923: background: #DDDDDD;
1.543 albertel 5924: }
5925:
1.584 albertel 5926: table.LC_sty_begin {
5927: background: #BBFFBB;
5928: }
1.795 www 5929:
1.584 albertel 5930: table.LC_sty_end {
5931: background: #FFBBBB;
5932: }
5933:
1.589 raeburn 5934: table.LC_double_column {
1.803 bisitz 5935: border-width: 0;
1.589 raeburn 5936: border-collapse: collapse;
5937: width: 100%;
5938: padding: 2px;
5939: }
5940:
5941: table.LC_double_column tr td.LC_left_col {
1.590 raeburn 5942: top: 2px;
1.589 raeburn 5943: left: 2px;
5944: width: 47%;
5945: vertical-align: top;
5946: }
5947:
5948: table.LC_double_column tr td.LC_right_col {
5949: top: 2px;
1.779 bisitz 5950: right: 2px;
1.589 raeburn 5951: width: 47%;
5952: vertical-align: top;
5953: }
5954:
1.591 raeburn 5955: div.LC_left_float {
5956: float: left;
5957: padding-right: 5%;
1.597 albertel 5958: padding-bottom: 4px;
1.591 raeburn 5959: }
5960:
5961: div.LC_clear_float_header {
1.597 albertel 5962: padding-bottom: 2px;
1.591 raeburn 5963: }
5964:
5965: div.LC_clear_float_footer {
1.597 albertel 5966: padding-top: 10px;
1.591 raeburn 5967: clear: both;
5968: }
5969:
1.597 albertel 5970: div.LC_grade_show_user {
1.941 bisitz 5971: /* border-left: 5px solid $sidebg; */
5972: border-top: 5px solid #000000;
5973: margin: 50px 0 0 0;
1.936 bisitz 5974: padding: 15px 0 5px 10px;
1.597 albertel 5975: }
1.795 www 5976:
1.936 bisitz 5977: div.LC_grade_show_user_odd_row {
1.941 bisitz 5978: /* border-left: 5px solid #000000; */
5979: }
5980:
5981: div.LC_grade_show_user div.LC_Box {
5982: margin-right: 50px;
1.597 albertel 5983: }
5984:
5985: div.LC_grade_submissions,
5986: div.LC_grade_message_center,
1.936 bisitz 5987: div.LC_grade_info_links {
1.597 albertel 5988: margin: 5px;
5989: width: 99%;
5990: background: #FFFFFF;
5991: }
1.795 www 5992:
1.597 albertel 5993: div.LC_grade_submissions_header,
1.936 bisitz 5994: div.LC_grade_message_center_header {
1.705 tempelho 5995: font-weight: bold;
5996: font-size: large;
1.597 albertel 5997: }
1.795 www 5998:
1.597 albertel 5999: div.LC_grade_submissions_body,
1.936 bisitz 6000: div.LC_grade_message_center_body {
1.597 albertel 6001: border: 1px solid black;
6002: width: 99%;
6003: background: #FFFFFF;
6004: }
1.795 www 6005:
1.613 albertel 6006: table.LC_scantron_action {
6007: width: 100%;
6008: }
1.795 www 6009:
1.613 albertel 6010: table.LC_scantron_action tr th {
1.698 harmsja 6011: font-weight:bold;
6012: font-style:normal;
1.613 albertel 6013: }
1.795 www 6014:
1.779 bisitz 6015: .LC_edit_problem_header,
1.614 albertel 6016: div.LC_edit_problem_footer {
1.705 tempelho 6017: font-weight: normal;
6018: font-size: medium;
1.602 albertel 6019: margin: 2px;
1.600 albertel 6020: }
1.795 www 6021:
1.600 albertel 6022: div.LC_edit_problem_header,
1.602 albertel 6023: div.LC_edit_problem_header div,
1.614 albertel 6024: div.LC_edit_problem_footer,
6025: div.LC_edit_problem_footer div,
1.602 albertel 6026: div.LC_edit_problem_editxml_header,
6027: div.LC_edit_problem_editxml_header div {
1.600 albertel 6028: margin-top: 5px;
6029: }
1.795 www 6030:
1.600 albertel 6031: div.LC_edit_problem_header_title {
1.705 tempelho 6032: font-weight: bold;
6033: font-size: larger;
1.602 albertel 6034: background: $tabbg;
6035: padding: 3px;
6036: }
1.795 www 6037:
1.602 albertel 6038: table.LC_edit_problem_header_title {
6039: width: 100%;
1.600 albertel 6040: background: $tabbg;
1.602 albertel 6041: }
6042:
6043: div.LC_edit_problem_discards {
6044: float: left;
6045: padding-bottom: 5px;
6046: }
1.795 www 6047:
1.602 albertel 6048: div.LC_edit_problem_saves {
6049: float: right;
6050: padding-bottom: 5px;
1.600 albertel 6051: }
1.795 www 6052:
1.911 bisitz 6053: img.stift {
1.803 bisitz 6054: border-width: 0;
6055: vertical-align: middle;
1.677 riegler 6056: }
1.680 riegler 6057:
1.923 bisitz 6058: table td.LC_mainmenu_col_fieldset {
1.680 riegler 6059: vertical-align: top;
1.777 tempelho 6060: }
1.795 www 6061:
1.716 raeburn 6062: div.LC_createcourse {
1.911 bisitz 6063: margin: 10px 10px 10px 10px;
1.716 raeburn 6064: }
6065:
1.917 raeburn 6066: .LC_dccid {
6067: margin: 0.2em 0 0 0;
6068: padding: 0;
6069: font-size: 90%;
6070: display:none;
6071: }
6072:
1.698 harmsja 6073: a:hover,
1.897 wenzelju 6074: ol.LC_primary_menu a:hover,
1.721 harmsja 6075: ol#LC_MenuBreadcrumbs a:hover,
6076: ol#LC_PathBreadcrumbs a:hover,
1.897 wenzelju 6077: ul#LC_secondary_menu a:hover,
1.721 harmsja 6078: .LC_FormSectionClearButton input:hover
1.795 www 6079: ul.LC_TabContent li:hover a {
1.948.2.1 raeburn 6080: color:$button_hover;
1.911 bisitz 6081: text-decoration:none;
1.693 droeschl 6082: }
6083:
1.779 bisitz 6084: h1 {
1.911 bisitz 6085: padding: 0;
6086: line-height:130%;
1.693 droeschl 6087: }
1.698 harmsja 6088:
1.911 bisitz 6089: h2,
6090: h3,
6091: h4,
6092: h5,
6093: h6 {
6094: margin: 5px 0 5px 0;
6095: padding: 0;
6096: line-height:130%;
1.693 droeschl 6097: }
1.795 www 6098:
6099: .LC_hcell {
1.911 bisitz 6100: padding:3px 15px 3px 15px;
6101: margin: 0;
6102: background-color:$tabbg;
6103: color:$fontmenu;
6104: border-bottom:solid 1px $lg_border_color;
1.693 droeschl 6105: }
1.795 www 6106:
1.840 bisitz 6107: .LC_Box > .LC_hcell {
1.911 bisitz 6108: margin: 0 -10px 10px -10px;
1.835 bisitz 6109: }
6110:
1.721 harmsja 6111: .LC_noBorder {
1.911 bisitz 6112: border: 0;
1.698 harmsja 6113: }
1.693 droeschl 6114:
1.721 harmsja 6115: .LC_FormSectionClearButton input {
1.911 bisitz 6116: background-color:transparent;
6117: border: none;
6118: cursor:pointer;
6119: text-decoration:underline;
1.693 droeschl 6120: }
1.763 bisitz 6121:
6122: .LC_help_open_topic {
1.911 bisitz 6123: color: #FFFFFF;
6124: background-color: #EEEEFF;
6125: margin: 1px;
6126: padding: 4px;
6127: border: 1px solid #000033;
6128: white-space: nowrap;
6129: /* vertical-align: middle; */
1.759 neumanie 6130: }
1.693 droeschl 6131:
1.911 bisitz 6132: dl,
6133: ul,
6134: div,
6135: fieldset {
6136: margin: 10px 10px 10px 0;
6137: /* overflow: hidden; */
1.693 droeschl 6138: }
1.795 www 6139:
1.838 bisitz 6140: fieldset > legend {
1.911 bisitz 6141: font-weight: bold;
6142: padding: 0 5px 0 5px;
1.838 bisitz 6143: }
6144:
1.813 bisitz 6145: #LC_nav_bar {
1.911 bisitz 6146: float: left;
1.948.2.6 raeburn 6147: margin: 0 0 2px 0;
1.807 droeschl 6148: }
6149:
1.916 droeschl 6150: #LC_realm {
6151: margin: 0.2em 0 0 0;
6152: padding: 0;
6153: font-weight: bold;
6154: text-align: center;
6155: }
6156:
1.911 bisitz 6157: #LC_nav_bar em {
6158: font-weight: bold;
6159: font-style: normal;
1.807 droeschl 6160: }
6161:
1.948.2.6 raeburn 6162: /* Preliminary fix to hide nav_bar inside bookmarks window */
6163: #LC_bookmarks #LC_nav_bar {
6164: display:none;
6165: }
6166:
1.897 wenzelju 6167: ol.LC_primary_menu {
1.911 bisitz 6168: float: right;
1.934 droeschl 6169: margin: 0;
1.807 droeschl 6170: }
6171:
1.929 wenzelju 6172: span.LC_new_message{
6173: font-weight:bold;
6174: color: darkred;
6175: }
6176:
1.852 droeschl 6177: ol#LC_PathBreadcrumbs {
1.911 bisitz 6178: margin: 0;
1.693 droeschl 6179: }
6180:
1.897 wenzelju 6181: ol.LC_primary_menu li {
1.911 bisitz 6182: display: inline;
6183: padding: 5px 5px 0 10px;
6184: vertical-align: top;
1.693 droeschl 6185: }
6186:
1.897 wenzelju 6187: ol.LC_primary_menu li img {
1.911 bisitz 6188: vertical-align: bottom;
1.934 droeschl 6189: height: 1.1em;
1.693 droeschl 6190: }
6191:
1.897 wenzelju 6192: ol.LC_primary_menu a {
1.911 bisitz 6193: color: RGB(80, 80, 80);
6194: text-decoration: none;
1.693 droeschl 6195: }
1.795 www 6196:
1.948.2.7 raeburn 6197: ol.LC_docs_parameters {
6198: margin-left: 0;
6199: padding: 0;
6200: list-style: none;
6201: }
6202:
6203: ol.LC_docs_parameters li {
6204: margin: 0;
6205: padding-right: 20px;
6206: display: inline;
6207: }
6208:
6209: ol.LC_docs_parameters li:before {
6210: content: "\\002022 \\0020";
6211: }
6212:
6213: li.LC_docs_parameters_title {
6214: font-weight: bold;
6215: }
6216:
6217: ol.LC_docs_parameters li.LC_docs_parameters_title:before {
6218: content: "";
6219: }
6220:
1.897 wenzelju 6221: ul#LC_secondary_menu {
1.911 bisitz 6222: clear: both;
6223: color: $fontmenu;
6224: background: $tabbg;
6225: list-style: none;
6226: padding: 0;
6227: margin: 0;
6228: width: 100%;
1.808 droeschl 6229: }
6230:
1.897 wenzelju 6231: ul#LC_secondary_menu li {
1.911 bisitz 6232: font-weight: bold;
6233: line-height: 1.8em;
6234: padding: 0 0.8em;
6235: border-right: 1px solid black;
6236: display: inline;
6237: vertical-align: middle;
1.807 droeschl 6238: }
6239:
1.847 tempelho 6240: ul.LC_TabContent {
1.911 bisitz 6241: display:block;
6242: background: $sidebg;
6243: border-bottom: solid 1px $lg_border_color;
6244: list-style:none;
6245: margin: 0 -10px;
6246: padding: 0;
1.693 droeschl 6247: }
6248:
1.795 www 6249: ul.LC_TabContent li,
6250: ul.LC_TabContentBigger li {
1.911 bisitz 6251: float:left;
1.741 harmsja 6252: }
1.795 www 6253:
1.897 wenzelju 6254: ul#LC_secondary_menu li a {
1.911 bisitz 6255: color: $fontmenu;
6256: text-decoration: none;
1.693 droeschl 6257: }
1.795 www 6258:
1.721 harmsja 6259: ul.LC_TabContent {
1.948.2.1 raeburn 6260: min-height:20px;
1.721 harmsja 6261: }
1.795 www 6262:
6263: ul.LC_TabContent li {
1.911 bisitz 6264: vertical-align:middle;
1.948.2.3 raeburn 6265: padding: 0 16px 0 10px;
1.911 bisitz 6266: background-color:$tabbg;
6267: border-bottom:solid 1px $lg_border_color;
1.948.2.1 raeburn 6268: border-right: solid 1px $font;
1.721 harmsja 6269: }
1.795 www 6270:
1.847 tempelho 6271: ul.LC_TabContent .right {
1.911 bisitz 6272: float:right;
1.847 tempelho 6273: }
6274:
1.911 bisitz 6275: ul.LC_TabContent li a,
6276: ul.LC_TabContent li {
6277: color:rgb(47,47,47);
6278: text-decoration:none;
6279: font-size:95%;
6280: font-weight:bold;
1.948.2.1 raeburn 6281: min-height:20px;
6282: }
6283:
1.948.2.3 raeburn 6284: ul.LC_TabContent li a:hover,
6285: ul.LC_TabContent li a:focus {
1.948.2.1 raeburn 6286: color: $button_hover;
1.948.2.3 raeburn 6287: background:none;
6288: outline:none;
1.948.2.1 raeburn 6289: }
6290:
6291: ul.LC_TabContent li:hover {
6292: color: $button_hover;
6293: cursor:pointer;
1.721 harmsja 6294: }
1.795 www 6295:
1.911 bisitz 6296: ul.LC_TabContent li.active {
1.948.2.1 raeburn 6297: color: $font;
1.911 bisitz 6298: background:#FFFFFF url(/adm/lonIcons/open.gif) no-repeat scroll right center;
1.948.2.1 raeburn 6299: border-bottom:solid 1px #FFFFFF;
6300: cursor: default;
1.744 ehlerst 6301: }
1.795 www 6302:
1.948.2.3 raeburn 6303: ul.LC_TabContent li.active a {
6304: color:$font;
6305: background:#FFFFFF;
6306: outline: none;
6307: }
1.870 tempelho 6308: #maincoursedoc {
1.911 bisitz 6309: clear:both;
1.870 tempelho 6310: }
6311:
6312: ul.LC_TabContentBigger {
1.911 bisitz 6313: display:block;
6314: list-style:none;
6315: padding: 0;
1.870 tempelho 6316: }
6317:
1.795 www 6318: ul.LC_TabContentBigger li {
1.911 bisitz 6319: vertical-align:bottom;
6320: height: 30px;
6321: font-size:110%;
6322: font-weight:bold;
6323: color: #737373;
1.841 tempelho 6324: }
6325:
1.948.2.3 raeburn 6326: ul.LC_TabContentBigger li.active {
6327: position: relative;
6328: top: 1px;
6329: }
1.870 tempelho 6330:
6331: ul.LC_TabContentBigger li a {
1.911 bisitz 6332: background:url('/adm/lonIcons/tabbgleft.gif') left bottom no-repeat;
6333: height: 30px;
6334: line-height: 30px;
6335: text-align: center;
6336: display: block;
6337: text-decoration: none;
1.948.2.3 raeburn 6338: outline: none;
1.741 harmsja 6339: }
1.795 www 6340:
1.870 tempelho 6341: ul.LC_TabContentBigger li.active a {
1.911 bisitz 6342: background:url('/adm/lonIcons/tabbgleft.gif') left top no-repeat;
6343: color:$font;
1.744 ehlerst 6344: }
1.795 www 6345:
1.870 tempelho 6346: ul.LC_TabContentBigger li b {
1.911 bisitz 6347: background: url('/adm/lonIcons/tabbgright.gif') no-repeat right bottom;
6348: display: block;
6349: float: left;
6350: padding: 0 30px;
1.948.2.3 raeburn 6351: border-bottom: 1px solid $lg_border_color;
6352: }
6353:
6354: ul.LC_TabContentBigger li:hover b {
6355: color:$button_hover;
1.870 tempelho 6356: }
6357:
6358: ul.LC_TabContentBigger li.active b {
1.911 bisitz 6359: background:url('/adm/lonIcons/tabbgright.gif') right top no-repeat;
6360: color:$font;
1.948.2.3 raeburn 6361: border: 0;
6362: cursor:default;
1.741 harmsja 6363: }
1.693 droeschl 6364:
1.862 bisitz 6365: ul.LC_CourseBreadcrumbs {
6366: background: $sidebg;
6367: line-height: 32px;
6368: padding-left: 10px;
6369: margin: 0 0 10px 0;
6370: list-style-position: inside;
6371:
6372: }
6373:
1.911 bisitz 6374: ol#LC_MenuBreadcrumbs,
1.862 bisitz 6375: ol#LC_PathBreadcrumbs {
1.911 bisitz 6376: padding-left: 10px;
6377: margin: 0;
1.933 droeschl 6378: height: 2.5em; /* equal to #LC_breadcrumbs line-height */
1.693 droeschl 6379: }
6380:
1.911 bisitz 6381: ol#LC_MenuBreadcrumbs li,
6382: ol#LC_PathBreadcrumbs li,
1.862 bisitz 6383: ul.LC_CourseBreadcrumbs li {
1.911 bisitz 6384: display: inline;
1.933 droeschl 6385: white-space: normal;
1.693 droeschl 6386: }
6387:
1.823 bisitz 6388: ol#LC_MenuBreadcrumbs li a,
1.862 bisitz 6389: ul.LC_CourseBreadcrumbs li a {
1.911 bisitz 6390: text-decoration: none;
6391: font-size:90%;
1.693 droeschl 6392: }
1.795 www 6393:
1.948.2.7 raeburn 6394: ol#LC_MenuBreadcrumbs h1 {
6395: display: inline;
6396: font-size: 90%;
6397: line-height: 2.5em;
6398: margin: 0;
6399: padding: 0;
6400: }
6401:
1.795 www 6402: ol#LC_PathBreadcrumbs li a {
1.911 bisitz 6403: text-decoration:none;
6404: font-size:100%;
6405: font-weight:bold;
1.693 droeschl 6406: }
1.795 www 6407:
1.840 bisitz 6408: .LC_Box {
1.911 bisitz 6409: border: solid 1px $lg_border_color;
6410: padding: 0 10px 10px 10px;
1.746 neumanie 6411: }
1.795 www 6412:
6413: .LC_AboutMe_Image {
1.911 bisitz 6414: float:left;
6415: margin-right:10px;
1.747 neumanie 6416: }
1.795 www 6417:
6418: .LC_Clear_AboutMe_Image {
1.911 bisitz 6419: clear:left;
1.747 neumanie 6420: }
1.795 www 6421:
1.721 harmsja 6422: dl.LC_ListStyleClean dt {
1.911 bisitz 6423: padding-right: 5px;
6424: display: table-header-group;
1.693 droeschl 6425: }
6426:
1.721 harmsja 6427: dl.LC_ListStyleClean dd {
1.911 bisitz 6428: display: table-row;
1.693 droeschl 6429: }
6430:
1.721 harmsja 6431: .LC_ListStyleClean,
6432: .LC_ListStyleSimple,
6433: .LC_ListStyleNormal,
1.795 www 6434: .LC_ListStyleSpecial {
1.911 bisitz 6435: /* display:block; */
6436: list-style-position: inside;
6437: list-style-type: none;
6438: overflow: hidden;
6439: padding: 0;
1.693 droeschl 6440: }
6441:
1.721 harmsja 6442: .LC_ListStyleSimple li,
6443: .LC_ListStyleSimple dd,
6444: .LC_ListStyleNormal li,
6445: .LC_ListStyleNormal dd,
6446: .LC_ListStyleSpecial li,
1.795 www 6447: .LC_ListStyleSpecial dd {
1.911 bisitz 6448: margin: 0;
6449: padding: 5px 5px 5px 10px;
6450: clear: both;
1.693 droeschl 6451: }
6452:
1.721 harmsja 6453: .LC_ListStyleClean li,
6454: .LC_ListStyleClean dd {
1.911 bisitz 6455: padding-top: 0;
6456: padding-bottom: 0;
1.693 droeschl 6457: }
6458:
1.721 harmsja 6459: .LC_ListStyleSimple dd,
1.795 www 6460: .LC_ListStyleSimple li {
1.911 bisitz 6461: border-bottom: solid 1px $lg_border_color;
1.693 droeschl 6462: }
6463:
1.721 harmsja 6464: .LC_ListStyleSpecial li,
6465: .LC_ListStyleSpecial dd {
1.911 bisitz 6466: list-style-type: none;
6467: background-color: RGB(220, 220, 220);
6468: margin-bottom: 4px;
1.693 droeschl 6469: }
6470:
1.721 harmsja 6471: table.LC_SimpleTable {
1.911 bisitz 6472: margin:5px;
6473: border:solid 1px $lg_border_color;
1.795 www 6474: }
1.693 droeschl 6475:
1.721 harmsja 6476: table.LC_SimpleTable tr {
1.911 bisitz 6477: padding: 0;
6478: border:solid 1px $lg_border_color;
1.693 droeschl 6479: }
1.795 www 6480:
6481: table.LC_SimpleTable thead {
1.911 bisitz 6482: background:rgb(220,220,220);
1.693 droeschl 6483: }
6484:
1.721 harmsja 6485: div.LC_columnSection {
1.911 bisitz 6486: display: block;
6487: clear: both;
6488: overflow: hidden;
6489: margin: 0;
1.693 droeschl 6490: }
6491:
1.721 harmsja 6492: div.LC_columnSection>* {
1.911 bisitz 6493: float: left;
6494: margin: 10px 20px 10px 0;
6495: overflow:hidden;
1.693 droeschl 6496: }
1.721 harmsja 6497:
1.795 www 6498: table em {
1.911 bisitz 6499: font-weight: bold;
6500: font-style: normal;
1.748 schulted 6501: }
1.795 www 6502:
1.779 bisitz 6503: table.LC_tableBrowseRes,
1.795 www 6504: table.LC_tableOfContent {
1.911 bisitz 6505: border:none;
6506: border-spacing: 1px;
6507: padding: 3px;
6508: background-color: #FFFFFF;
6509: font-size: 90%;
1.753 droeschl 6510: }
1.789 droeschl 6511:
1.911 bisitz 6512: table.LC_tableOfContent {
6513: border-collapse: collapse;
1.789 droeschl 6514: }
6515:
1.771 droeschl 6516: table.LC_tableBrowseRes a,
1.768 schulted 6517: table.LC_tableOfContent a {
1.911 bisitz 6518: background-color: transparent;
6519: text-decoration: none;
1.753 droeschl 6520: }
6521:
1.795 www 6522: table.LC_tableOfContent img {
1.911 bisitz 6523: border: none;
6524: height: 1.3em;
6525: vertical-align: text-bottom;
6526: margin-right: 0.3em;
1.753 droeschl 6527: }
1.757 schulted 6528:
1.795 www 6529: a#LC_content_toolbar_firsthomework {
1.911 bisitz 6530: background-image:url(/res/adm/pages/open-first-problem.gif);
1.774 ehlerst 6531: }
6532:
1.795 www 6533: a#LC_content_toolbar_launchnav {
1.911 bisitz 6534: background-image:url(/res/adm/pages/start-navigation.gif);
1.774 ehlerst 6535: }
6536:
1.795 www 6537: a#LC_content_toolbar_closenav {
1.911 bisitz 6538: background-image:url(/res/adm/pages/close-navigation.gif);
1.774 ehlerst 6539: }
6540:
1.795 www 6541: a#LC_content_toolbar_everything {
1.911 bisitz 6542: background-image:url(/res/adm/pages/show-all.gif);
1.774 ehlerst 6543: }
6544:
1.795 www 6545: a#LC_content_toolbar_uncompleted {
1.911 bisitz 6546: background-image:url(/res/adm/pages/show-incomplete-problems.gif);
1.774 ehlerst 6547: }
6548:
1.795 www 6549: #LC_content_toolbar_clearbubbles {
1.911 bisitz 6550: background-image:url(/res/adm/pages/mark-discussionentries-read.gif);
1.774 ehlerst 6551: }
6552:
1.795 www 6553: a#LC_content_toolbar_changefolder {
1.911 bisitz 6554: background : url(/res/adm/pages/close-all-folders.gif) top center ;
1.757 schulted 6555: }
6556:
1.795 www 6557: a#LC_content_toolbar_changefolder_toggled {
1.911 bisitz 6558: background-image:url(/res/adm/pages/open-all-folders.gif);
1.757 schulted 6559: }
6560:
1.795 www 6561: ul#LC_toolbar li a:hover {
1.911 bisitz 6562: background-position: bottom center;
1.757 schulted 6563: }
6564:
1.795 www 6565: ul#LC_toolbar {
1.911 bisitz 6566: padding: 0;
6567: margin: 2px;
6568: list-style:none;
6569: position:relative;
6570: background-color:white;
1.757 schulted 6571: }
6572:
1.795 www 6573: ul#LC_toolbar li {
1.911 bisitz 6574: border:1px solid white;
6575: padding: 0;
6576: margin: 0;
6577: float: left;
6578: display:inline;
6579: vertical-align:middle;
6580: }
1.757 schulted 6581:
1.783 amueller 6582:
1.795 www 6583: a.LC_toolbarItem {
1.911 bisitz 6584: display:block;
6585: padding: 0;
6586: margin: 0;
6587: height: 32px;
6588: width: 32px;
6589: color:white;
6590: border: none;
6591: background-repeat:no-repeat;
6592: background-color:transparent;
1.757 schulted 6593: }
6594:
1.915 droeschl 6595: ul.LC_funclist {
6596: margin: 0;
6597: padding: 0.5em 1em 0.5em 0;
6598: }
6599:
1.933 droeschl 6600: ul.LC_funclist > li:first-child {
6601: font-weight:bold;
6602: margin-left:0.8em;
6603: }
6604:
1.915 droeschl 6605: ul.LC_funclist + ul.LC_funclist {
6606: /*
6607: left border as a seperator if we have more than
6608: one list
6609: */
6610: border-left: 1px solid $sidebg;
6611: /*
6612: this hides the left border behind the border of the
6613: outer box if element is wrapped to the next 'line'
6614: */
6615: margin-left: -1px;
6616: }
6617:
1.843 bisitz 6618: ul.LC_funclist li {
1.915 droeschl 6619: display: inline;
1.782 bisitz 6620: white-space: nowrap;
1.915 droeschl 6621: margin: 0 0 0 25px;
6622: line-height: 150%;
1.782 bisitz 6623: }
6624:
1.930 faziophi 6625: .ui-accordion .LC_advanced_toggle {
6626: float: right;
6627: font-size: 90%;
6628: padding: 0px 4px
6629: }
1.757 schulted 6630:
1.343 albertel 6631: END
6632: }
6633:
1.306 albertel 6634: =pod
6635:
6636: =item * &headtag()
6637:
6638: Returns a uniform footer for LON-CAPA web pages.
6639:
1.307 albertel 6640: Inputs: $title - optional title for the head
6641: $head_extra - optional extra HTML to put inside the <head>
1.315 albertel 6642: $args - optional arguments
1.319 albertel 6643: force_register - if is true call registerurl so the remote is
6644: informed
1.415 albertel 6645: redirect -> array ref of
6646: 1- seconds before redirect occurs
6647: 2- url to redirect to
6648: 3- whether the side effect should occur
1.315 albertel 6649: (side effect of setting
6650: $env{'internal.head.redirect'} to the url
6651: redirected too)
1.352 albertel 6652: domain -> force to color decorate a page for a specific
6653: domain
6654: function -> force usage of a specific rolish color scheme
6655: bgcolor -> override the default page bgcolor
1.460 albertel 6656: no_auto_mt_title
6657: -> prevent &mt()ing the title arg
1.464 albertel 6658:
1.306 albertel 6659: =cut
6660:
6661: sub headtag {
1.313 albertel 6662: my ($title,$head_extra,$args) = @_;
1.306 albertel 6663:
1.363 albertel 6664: my $function = $args->{'function'} || &get_users_function();
6665: my $domain = $args->{'domain'} || &determinedomain();
6666: my $bgcolor = $args->{'bgcolor'} || &designparm($function.'.pgbg',$domain);
1.418 albertel 6667: my $url = join(':',$env{'user.name'},$env{'user.domain'},
1.458 albertel 6668: $Apache::lonnet::perlvar{'lonVersion'},
1.531 albertel 6669: #time(),
1.418 albertel 6670: $env{'environment.color.timestamp'},
1.363 albertel 6671: $function,$domain,$bgcolor);
6672:
1.369 www 6673: $url = '/adm/css/'.&escape($url).'.css';
1.363 albertel 6674:
1.308 albertel 6675: my $result =
6676: '<head>'.
1.461 albertel 6677: &font_settings();
1.319 albertel 6678:
1.461 albertel 6679: if (!$args->{'frameset'}) {
6680: $result .= &Apache::lonhtmlcommon::htmlareaheaders();
6681: }
1.319 albertel 6682: if ($args->{'force_register'}) {
6683: $result .= &Apache::lonmenu::registerurl(1);
6684: }
1.436 albertel 6685: if (!$args->{'no_nav_bar'}
6686: && !$args->{'only_body'}
6687: && !$args->{'frameset'}) {
6688: $result .= &help_menu_js();
6689: }
1.319 albertel 6690:
1.314 albertel 6691: if (ref($args->{'redirect'})) {
1.414 albertel 6692: my ($time,$url,$inhibit_continue) = @{$args->{'redirect'}};
1.315 albertel 6693: $url = &Apache::lonenc::check_encrypt($url);
1.414 albertel 6694: if (!$inhibit_continue) {
6695: $env{'internal.head.redirect'} = $url;
6696: }
1.313 albertel 6697: $result.=<<ADDMETA
6698: <meta http-equiv="pragma" content="no-cache" />
1.344 albertel 6699: <meta http-equiv="Refresh" content="$time; url=$url" />
1.313 albertel 6700: ADDMETA
6701: }
1.306 albertel 6702: if (!defined($title)) {
6703: $title = 'The LearningOnline Network with CAPA';
6704: }
1.460 albertel 6705: if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); }
6706: $result .= '<title> LON-CAPA '.$title.'</title>'
1.414 albertel 6707: .'<link rel="stylesheet" type="text/css" href="'.$url.'" />'
6708: .$head_extra;
1.306 albertel 6709: return $result;
6710: }
6711:
6712: =pod
6713:
1.340 albertel 6714: =item * &font_settings()
6715:
6716: Returns neccessary <meta> to set the proper encoding
6717:
6718: Inputs: none
6719:
6720: =cut
6721:
6722: sub font_settings {
6723: my $headerstring='';
1.647 www 6724: if (!$env{'browser.mathml'} && $env{'browser.unicode'}) {
1.340 albertel 6725: $headerstring.=
6726: '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
6727: }
6728: return $headerstring;
6729: }
6730:
1.341 albertel 6731: =pod
6732:
6733: =item * &xml_begin()
6734:
6735: Returns the needed doctype and <html>
6736:
6737: Inputs: none
6738:
6739: =cut
6740:
6741: sub xml_begin {
6742: my $output='';
6743:
6744: if ($env{'browser.mathml'}) {
6745: $output='<?xml version="1.0"?>'
6746: #.'<?xml-stylesheet type="text/css" href="/adm/MathML/mathml.css"?>'."\n"
6747: # .'<!DOCTYPE html SYSTEM "/adm/MathML/mathml.dtd" '
6748:
6749: # .'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" [<!ENTITY mathns "http://www.w3.org/1998/Math/MathML">] >'
6750: .'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd">'
6751: .'<html xmlns:math="http://www.w3.org/1998/Math/MathML" '
6752: .'xmlns="http://www.w3.org/1999/xhtml">';
6753: } else {
1.849 bisitz 6754: $output='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
6755: .'<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';
1.341 albertel 6756: }
6757: return $output;
6758: }
1.340 albertel 6759:
6760: =pod
6761:
1.306 albertel 6762: =item * &endheadtag()
6763:
6764: Returns a uniform </head> for LON-CAPA web pages.
6765:
6766: Inputs: none
6767:
6768: =cut
6769:
6770: sub endheadtag {
6771: return '</head>';
6772: }
6773:
6774: =pod
6775:
6776: =item * &head()
6777:
6778: Returns a uniform complete <head>..</head> section for LON-CAPA web pages.
6779:
1.648 raeburn 6780: Inputs:
6781:
6782: =over 4
6783:
6784: $title - optional title for the page
6785:
6786: $head_extra - optional extra HTML to put inside the <head>
6787:
6788: =back
1.405 albertel 6789:
1.306 albertel 6790: =cut
6791:
6792: sub head {
1.325 albertel 6793: my ($title,$head_extra,$args) = @_;
6794: return &headtag($title,$head_extra,$args).&endheadtag();
1.306 albertel 6795: }
6796:
6797: =pod
6798:
6799: =item * &start_page()
6800:
6801: Returns a complete <html> .. <body> section for LON-CAPA web pages.
6802:
1.648 raeburn 6803: Inputs:
6804:
6805: =over 4
6806:
6807: $title - optional title for the page
6808:
6809: $head_extra - optional extra HTML to incude inside the <head>
6810:
6811: $args - additional optional args supported are:
6812:
6813: =over 8
6814:
6815: only_body -> is true will set &bodytag() onlybodytag
1.317 albertel 6816: arg on
1.814 bisitz 6817: no_nav_bar -> is true will set &bodytag() no_nav_bar arg on
1.648 raeburn 6818: add_entries -> additional attributes to add to the <body>
6819: domain -> force to color decorate a page for a
1.317 albertel 6820: specific domain
1.648 raeburn 6821: function -> force usage of a specific rolish color
1.317 albertel 6822: scheme
1.648 raeburn 6823: redirect -> see &headtag()
6824: bgcolor -> override the default page bg color
6825: js_ready -> return a string ready for being used in
1.317 albertel 6826: a javascript writeln
1.648 raeburn 6827: html_encode -> return a string ready for being used in
1.320 albertel 6828: a html attribute
1.648 raeburn 6829: force_register -> if is true will turn on the &bodytag()
1.317 albertel 6830: $forcereg arg
1.648 raeburn 6831: frameset -> if true will start with a <frameset>
1.330 albertel 6832: rather than <body>
1.648 raeburn 6833: skip_phases -> hash ref of
1.338 albertel 6834: head -> skip the <html><head> generation
6835: body -> skip all <body> generation
1.648 raeburn 6836: no_inline_link -> if true and in remote mode, don't show the
1.361 albertel 6837: 'Switch To Inline Menu' link
1.648 raeburn 6838: no_auto_mt_title -> prevent &mt()ing the title arg
6839: inherit_jsmath -> when creating popup window in a page,
6840: should it have jsmath forced on by the
6841: current page
1.867 kalberla 6842: bread_crumbs -> Array containing breadcrumbs
1.948.2.12 raeburn 6843: bread_crumbs_component -> if exists show it as headline else show only the breadcrumbs
1.361 albertel 6844:
1.648 raeburn 6845: =back
1.460 albertel 6846:
1.648 raeburn 6847: =back
1.562 albertel 6848:
1.306 albertel 6849: =cut
6850:
6851: sub start_page {
1.309 albertel 6852: my ($title,$head_extra,$args) = @_;
1.318 albertel 6853: #&Apache::lonnet::logthis("start_page ".join(':',caller(0)));
1.313 albertel 6854: my %head_args;
1.352 albertel 6855: foreach my $arg ('redirect','force_register','domain','function',
1.460 albertel 6856: 'bgcolor','frameset','no_nav_bar','only_body',
6857: 'no_auto_mt_title') {
1.319 albertel 6858: if (defined($args->{$arg})) {
1.324 raeburn 6859: $head_args{$arg} = $args->{$arg};
1.319 albertel 6860: }
1.313 albertel 6861: }
1.319 albertel 6862:
1.315 albertel 6863: $env{'internal.start_page'}++;
1.338 albertel 6864: my $result;
6865: if (! exists($args->{'skip_phases'}{'head'}) ) {
6866: $result.=
1.341 albertel 6867: &xml_begin().
1.338 albertel 6868: &headtag($title,$head_extra,\%head_args).&endheadtag();
6869: }
6870:
6871: if (! exists($args->{'skip_phases'}{'body'}) ) {
6872: if ($args->{'frameset'}) {
6873: my $attr_string = &make_attr_string($args->{'force_register'},
6874: $args->{'add_entries'});
6875: $result .= "\n<frameset $attr_string>\n";
1.831 bisitz 6876: } else {
6877: $result .=
6878: &bodytag($title,
6879: $args->{'function'}, $args->{'add_entries'},
6880: $args->{'only_body'}, $args->{'domain'},
6881: $args->{'force_register'}, $args->{'no_nav_bar'},
6882: $args->{'bgcolor'}, $args->{'no_inline_link'},
6883: $args);
6884: }
1.330 albertel 6885: }
1.338 albertel 6886:
1.315 albertel 6887: if ($args->{'js_ready'}) {
1.713 kaisler 6888: $result = &js_ready($result);
1.315 albertel 6889: }
1.320 albertel 6890: if ($args->{'html_encode'}) {
1.713 kaisler 6891: $result = &html_encode($result);
6892: }
6893:
1.813 bisitz 6894: # Preparation for new and consistent functionlist at top of screen
6895: # if ($args->{'functionlist'}) {
6896: # $result .= &build_functionlist();
6897: #}
6898:
6899: # Don't add anything more if only_body wanted
6900: return $result if $args->{'only_body'};
6901:
1.920 raeburn 6902: #Breadcrumbs for Construction Space provided by &bodytag.
6903: if (($env{'environment.remote'} eq 'off') && ($env{'request.state'} eq 'construct')) {
6904: return $result;
6905: }
6906:
1.813 bisitz 6907: #Breadcrumbs
1.758 kaisler 6908: if (exists($args->{'bread_crumbs'}) or exists($args->{'bread_crumbs_component'})) {
6909: &Apache::lonhtmlcommon::clear_breadcrumbs();
6910: #if any br links exists, add them to the breadcrumbs
6911: if (exists($args->{'bread_crumbs'}) and ref($args->{'bread_crumbs'}) eq 'ARRAY') {
6912: foreach my $crumb (@{$args->{'bread_crumbs'}}){
6913: &Apache::lonhtmlcommon::add_breadcrumb($crumb);
6914: }
6915: }
6916:
6917: #if bread_crumbs_component exists show it as headline else show only the breadcrumbs
6918: if(exists($args->{'bread_crumbs_component'})){
6919: $result .= &Apache::lonhtmlcommon::breadcrumbs($args->{'bread_crumbs_component'});
6920: }else{
6921: $result .= &Apache::lonhtmlcommon::breadcrumbs();
6922: }
1.320 albertel 6923: }
1.315 albertel 6924: return $result;
1.306 albertel 6925: }
6926:
1.330 albertel 6927:
1.306 albertel 6928: =pod
6929:
6930: =item * &head()
6931:
6932: Returns a complete </body></html> section for LON-CAPA web pages.
6933:
1.315 albertel 6934: Inputs: $args - additional optional args supported are:
6935: js_ready -> return a string ready for being used in
6936: a javascript writeln
1.320 albertel 6937: html_encode -> return a string ready for being used in
6938: a html attribute
1.330 albertel 6939: frameset -> if true will start with a <frameset>
6940: rather than <body>
1.493 albertel 6941: dicsussion -> if true will get discussion from
6942: lonxml::xmlend
6943: (you can pass the target and parser arguments
6944: through optional 'target' and 'parser' args
6945: to this routine)
1.306 albertel 6946:
6947: =cut
6948:
6949: sub end_page {
1.315 albertel 6950: my ($args) = @_;
6951: $env{'internal.end_page'}++;
1.330 albertel 6952: my $result;
1.335 albertel 6953: if ($args->{'discussion'}) {
6954: my ($target,$parser);
6955: if (ref($args->{'discussion'})) {
6956: ($target,$parser) =($args->{'discussion'}{'target'},
6957: $args->{'discussion'}{'parser'});
6958: }
6959: $result .= &Apache::lonxml::xmlend($target,$parser);
6960: }
6961:
1.330 albertel 6962: if ($args->{'frameset'}) {
6963: $result .= '</frameset>';
6964: } else {
1.635 raeburn 6965: $result .= &endbodytag($args);
1.330 albertel 6966: }
6967: $result .= "\n</html>";
6968:
1.315 albertel 6969: if ($args->{'js_ready'}) {
1.317 albertel 6970: $result = &js_ready($result);
1.315 albertel 6971: }
1.335 albertel 6972:
1.320 albertel 6973: if ($args->{'html_encode'}) {
6974: $result = &html_encode($result);
6975: }
1.335 albertel 6976:
1.315 albertel 6977: return $result;
6978: }
6979:
1.320 albertel 6980: sub html_encode {
6981: my ($result) = @_;
6982:
1.322 albertel 6983: $result = &HTML::Entities::encode($result,'<>&"');
1.320 albertel 6984:
6985: return $result;
6986: }
1.317 albertel 6987: sub js_ready {
6988: my ($result) = @_;
6989:
1.323 albertel 6990: $result =~ s/[\n\r]/ /xmsg;
6991: $result =~ s/\\/\\\\/xmsg;
6992: $result =~ s/'/\\'/xmsg;
1.372 albertel 6993: $result =~ s{</}{<\\/}xmsg;
1.317 albertel 6994:
6995: return $result;
6996: }
6997:
1.315 albertel 6998: sub validate_page {
6999: if ( exists($env{'internal.start_page'})
1.316 albertel 7000: && $env{'internal.start_page'} > 1) {
7001: &Apache::lonnet::logthis('start_page called multiple times '.
1.318 albertel 7002: $env{'internal.start_page'}.' '.
1.316 albertel 7003: $ENV{'request.filename'});
1.315 albertel 7004: }
7005: if ( exists($env{'internal.end_page'})
1.316 albertel 7006: && $env{'internal.end_page'} > 1) {
7007: &Apache::lonnet::logthis('end_page called multiple times '.
1.318 albertel 7008: $env{'internal.end_page'}.' '.
1.316 albertel 7009: $env{'request.filename'});
1.315 albertel 7010: }
7011: if ( exists($env{'internal.start_page'})
7012: && ! exists($env{'internal.end_page'})) {
1.316 albertel 7013: &Apache::lonnet::logthis('start_page called without end_page '.
7014: $env{'request.filename'});
1.315 albertel 7015: }
7016: if ( ! exists($env{'internal.start_page'})
7017: && exists($env{'internal.end_page'})) {
1.316 albertel 7018: &Apache::lonnet::logthis('end_page called without start_page'.
7019: $env{'request.filename'});
1.315 albertel 7020: }
1.306 albertel 7021: }
1.315 albertel 7022:
1.318 albertel 7023: sub simple_error_page {
7024: my ($r,$title,$msg) = @_;
7025: my $page =
7026: &Apache::loncommon::start_page($title).
7027: &mt($msg).
7028: &Apache::loncommon::end_page();
7029: if (ref($r)) {
7030: $r->print($page);
1.327 albertel 7031: return;
1.318 albertel 7032: }
7033: return $page;
7034: }
1.347 albertel 7035:
7036: {
1.610 albertel 7037: my @row_count;
1.948.2.5 raeburn 7038:
7039: sub start_data_table_count {
7040: unshift(@row_count, 0);
7041: return;
7042: }
7043:
7044: sub end_data_table_count {
7045: shift(@row_count);
7046: return;
7047: }
7048:
1.347 albertel 7049: sub start_data_table {
1.422 albertel 7050: my ($add_class) = @_;
7051: my $css_class = (join(' ','LC_data_table',$add_class));
1.948.2.5 raeburn 7052: &start_data_table_count();
1.422 albertel 7053: return '<table class="'.$css_class.'">'."\n";
1.347 albertel 7054: }
7055:
7056: sub end_data_table {
1.948.2.5 raeburn 7057: &end_data_table_count();
1.389 albertel 7058: return '</table>'."\n";;
1.347 albertel 7059: }
7060:
7061: sub start_data_table_row {
1.422 albertel 7062: my ($add_class) = @_;
1.610 albertel 7063: $row_count[0]++;
7064: my $css_class = ($row_count[0] % 2)?'LC_odd_row':'LC_even_row';
1.900 bisitz 7065: $css_class = (join(' ',$css_class,$add_class)) unless ($add_class eq '');
1.422 albertel 7066: return '<tr class="'.$css_class.'">'."\n";;
1.347 albertel 7067: }
1.471 banghart 7068:
7069: sub continue_data_table_row {
7070: my ($add_class) = @_;
1.610 albertel 7071: my $css_class = ($row_count[0] % 2)?'LC_odd_row':'LC_even_row';
1.900 bisitz 7072: $css_class = (join(' ',$css_class,$add_class)) unless ($add_class eq '');;
1.471 banghart 7073: return '<tr class="'.$css_class.'">'."\n";;
7074: }
1.347 albertel 7075:
7076: sub end_data_table_row {
1.389 albertel 7077: return '</tr>'."\n";;
1.347 albertel 7078: }
1.367 www 7079:
1.421 albertel 7080: sub start_data_table_empty_row {
1.707 bisitz 7081: # $row_count[0]++;
1.421 albertel 7082: return '<tr class="LC_empty_row" >'."\n";;
7083: }
7084:
7085: sub end_data_table_empty_row {
7086: return '</tr>'."\n";;
7087: }
7088:
1.367 www 7089: sub start_data_table_header_row {
1.389 albertel 7090: return '<tr class="LC_header_row">'."\n";;
1.367 www 7091: }
7092:
7093: sub end_data_table_header_row {
1.389 albertel 7094: return '</tr>'."\n";;
1.367 www 7095: }
1.890 droeschl 7096:
7097: sub data_table_caption {
7098: my $caption = shift;
7099: return "<caption class=\"LC_caption\">$caption</caption>";
7100: }
1.347 albertel 7101: }
7102:
1.548 albertel 7103: =pod
7104:
7105: =item * &inhibit_menu_check($arg)
7106:
7107: Checks for a inhibitmenu state and generates output to preserve it
7108:
7109: Inputs: $arg - can be any of
7110: - undef - in which case the return value is a string
7111: to add into arguments list of a uri
7112: - 'input' - in which case the return value is a HTML
7113: <form> <input> field of type hidden to
7114: preserve the value
7115: - a url - in which case the return value is the url with
7116: the neccesary cgi args added to preserve the
7117: inhibitmenu state
7118: - a ref to a url - no return value, but the string is
7119: updated to include the neccessary cgi
7120: args to preserve the inhibitmenu state
7121:
7122: =cut
7123:
7124: sub inhibit_menu_check {
7125: my ($arg) = @_;
7126: &get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['inhibitmenu']);
7127: if ($arg eq 'input') {
7128: if ($env{'form.inhibitmenu'}) {
7129: return '<input type="hidden" name="inhibitmenu" value="'.$env{'form.inhibitmenu'}.'" />';
7130: } else {
7131: return
7132: }
7133: }
7134: if ($env{'form.inhibitmenu'}) {
7135: if (ref($arg)) {
7136: $$arg .= '?inhibitmenu='.$env{'form.inhibitmenu'};
7137: } elsif ($arg eq '') {
7138: $arg .= 'inhibitmenu='.$env{'form.inhibitmenu'};
7139: } else {
7140: $arg .= '?inhibitmenu='.$env{'form.inhibitmenu'};
7141: }
7142: }
7143: if (!ref($arg)) {
7144: return $arg;
7145: }
7146: }
7147:
1.251 albertel 7148: ###############################################
1.182 matthew 7149:
7150: =pod
7151:
1.549 albertel 7152: =back
7153:
7154: =head1 User Information Routines
7155:
7156: =over 4
7157:
1.405 albertel 7158: =item * &get_users_function()
1.182 matthew 7159:
7160: Used by &bodytag to determine the current users primary role.
7161: Returns either 'student','coordinator','admin', or 'author'.
7162:
7163: =cut
7164:
7165: ###############################################
7166: sub get_users_function {
1.815 tempelho 7167: my $function = 'norole';
1.818 tempelho 7168: if ($env{'request.role'}=~/^(st)/) {
7169: $function='student';
7170: }
1.907 raeburn 7171: if ($env{'request.role'}=~/^(cc|co|in|ta|ep)/) {
1.182 matthew 7172: $function='coordinator';
7173: }
1.258 albertel 7174: if ($env{'request.role'}=~/^(su|dc|ad|li)/) {
1.182 matthew 7175: $function='admin';
7176: }
1.826 bisitz 7177: if (($env{'request.role'}=~/^(au|ca|aa)/) ||
1.182 matthew 7178: ($ENV{'REQUEST_URI'}=~/^(\/priv|\~)/)) {
7179: $function='author';
7180: }
7181: return $function;
1.54 www 7182: }
1.99 www 7183:
7184: ###############################################
7185:
1.233 raeburn 7186: =pod
7187:
1.821 raeburn 7188: =item * &show_course()
7189:
7190: Used by lonmenu.pm and lonroles.pm to determine whether to use the word
7191: 'Courses' or 'Roles' in inline navigation and on screen displaying user's roles.
7192:
7193: Inputs:
7194: None
7195:
7196: Outputs:
7197: Scalar: 1 if 'Course' to be used, 0 otherwise.
7198:
7199: =cut
7200:
7201: ###############################################
7202: sub show_course {
7203: my $course = !$env{'user.adv'};
7204: if (!$env{'user.adv'}) {
7205: foreach my $env (keys(%env)) {
7206: next if ($env !~ m/^user\.priv\./);
7207: if ($env !~ m/^user\.priv\.(?:st|cm)/) {
7208: $course = 0;
7209: last;
7210: }
7211: }
7212: }
7213: return $course;
7214: }
7215:
7216: ###############################################
7217:
7218: =pod
7219:
1.542 raeburn 7220: =item * &check_user_status()
1.274 raeburn 7221:
7222: Determines current status of supplied role for a
7223: specific user. Roles can be active, previous or future.
7224:
7225: Inputs:
7226: user's domain, user's username, course's domain,
1.375 raeburn 7227: course's number, optional section ID.
1.274 raeburn 7228:
7229: Outputs:
7230: role status: active, previous or future.
7231:
7232: =cut
7233:
7234: sub check_user_status {
1.412 raeburn 7235: my ($udom,$uname,$cdom,$crs,$role,$sec) = @_;
1.948.2.11 raeburn 7236: my $extra = &Apache::lonnet::freeze_escape({'skipcheck' => 1});
7237: my %userinfo = &Apache::lonnet::dump('roles',$udom,$uname,'.',undef,$extra);
1.274 raeburn 7238: my @uroles = keys %userinfo;
7239: my $srchstr;
7240: my $active_chk = 'none';
1.412 raeburn 7241: my $now = time;
1.274 raeburn 7242: if (@uroles > 0) {
1.908 raeburn 7243: if (($role eq 'cc') || ($role eq 'co') || ($sec eq '') || (!defined($sec))) {
1.274 raeburn 7244: $srchstr = '/'.$cdom.'/'.$crs.'_'.$role;
7245: } else {
1.412 raeburn 7246: $srchstr = '/'.$cdom.'/'.$crs.'/'.$sec.'_'.$role;
7247: }
7248: if (grep/^\Q$srchstr\E$/,@uroles) {
1.274 raeburn 7249: my $role_end = 0;
7250: my $role_start = 0;
7251: $active_chk = 'active';
1.412 raeburn 7252: if ($userinfo{$srchstr} =~ m/^\Q$role\E_(\d+)/) {
7253: $role_end = $1;
7254: if ($userinfo{$srchstr} =~ m/^\Q$role\E_\Q$role_end\E_(\d+)$/) {
7255: $role_start = $1;
1.274 raeburn 7256: }
7257: }
7258: if ($role_start > 0) {
1.412 raeburn 7259: if ($now < $role_start) {
1.274 raeburn 7260: $active_chk = 'future';
7261: }
7262: }
7263: if ($role_end > 0) {
1.412 raeburn 7264: if ($now > $role_end) {
1.274 raeburn 7265: $active_chk = 'previous';
7266: }
7267: }
7268: }
7269: }
7270: return $active_chk;
7271: }
7272:
7273: ###############################################
7274:
7275: =pod
7276:
1.405 albertel 7277: =item * &get_sections()
1.233 raeburn 7278:
7279: Determines all the sections for a course including
7280: sections with students and sections containing other roles.
1.419 raeburn 7281: Incoming parameters:
7282:
7283: 1. domain
7284: 2. course number
7285: 3. reference to array containing roles for which sections should
7286: be gathered (optional).
7287: 4. reference to array containing status types for which sections
7288: should be gathered (optional).
7289:
7290: If the third argument is undefined, sections are gathered for any role.
7291: If the fourth argument is undefined, sections are gathered for any status.
7292: Permissible values are 'active' or 'future' or 'previous'.
1.233 raeburn 7293:
1.374 raeburn 7294: Returns section hash (keys are section IDs, values are
7295: number of users in each section), subject to the
1.419 raeburn 7296: optional roles filter, optional status filter
1.233 raeburn 7297:
7298: =cut
7299:
7300: ###############################################
7301: sub get_sections {
1.419 raeburn 7302: my ($cdom,$cnum,$possible_roles,$possible_status) = @_;
1.366 albertel 7303: if (!defined($cdom) || !defined($cnum)) {
7304: my $cid = $env{'request.course.id'};
7305:
7306: return if (!defined($cid));
7307:
7308: $cdom = $env{'course.'.$cid.'.domain'};
7309: $cnum = $env{'course.'.$cid.'.num'};
7310: }
7311:
7312: my %sectioncount;
1.419 raeburn 7313: my $now = time;
1.240 albertel 7314:
1.366 albertel 7315: if (!defined($possible_roles) || (grep(/^st$/,@$possible_roles))) {
1.276 albertel 7316: my ($classlist) = &Apache::loncoursedata::get_classlist($cdom,$cnum);
1.240 albertel 7317: my $sec_index = &Apache::loncoursedata::CL_SECTION();
7318: my $status_index = &Apache::loncoursedata::CL_STATUS();
1.419 raeburn 7319: my $start_index = &Apache::loncoursedata::CL_START();
7320: my $end_index = &Apache::loncoursedata::CL_END();
7321: my $status;
1.366 albertel 7322: while (my ($student,$data) = each(%$classlist)) {
1.419 raeburn 7323: my ($section,$stu_status,$start,$end) = ($data->[$sec_index],
7324: $data->[$status_index],
7325: $data->[$start_index],
7326: $data->[$end_index]);
7327: if ($stu_status eq 'Active') {
7328: $status = 'active';
7329: } elsif ($end < $now) {
7330: $status = 'previous';
7331: } elsif ($start > $now) {
7332: $status = 'future';
7333: }
7334: if ($section ne '-1' && $section !~ /^\s*$/) {
7335: if ((!defined($possible_status)) || (($status ne '') &&
7336: (grep/^\Q$status\E$/,@{$possible_status}))) {
7337: $sectioncount{$section}++;
7338: }
1.240 albertel 7339: }
7340: }
7341: }
7342: my %courseroles = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
7343: foreach my $user (sort(keys(%courseroles))) {
7344: if ($user !~ /^(\w{2})/) { next; }
7345: my ($role) = ($user =~ /^(\w{2})/);
7346: if ($possible_roles && !(grep(/^$role$/,@$possible_roles))) { next; }
1.419 raeburn 7347: my ($section,$status);
1.240 albertel 7348: if ($role eq 'cr' &&
7349: $user =~ m-^$role/[^/]*/[^/]*/[^/]*:[^:]*:[^:]*:(\w+)-) {
7350: $section=$1;
7351: }
7352: if ($user =~ /^$role:[^:]*:[^:]*:(\w+)/) { $section=$1; }
7353: if (!defined($section) || $section eq '-1') { next; }
1.419 raeburn 7354: my ($end,$start) = ($courseroles{$user} =~ /^([^:]*):([^:]*)$/);
7355: if ($end == -1 && $start == -1) {
7356: next; #deleted role
7357: }
7358: if (!defined($possible_status)) {
7359: $sectioncount{$section}++;
7360: } else {
7361: if ((!$end || $end >= $now) && (!$start || $start <= $now)) {
7362: $status = 'active';
7363: } elsif ($end < $now) {
7364: $status = 'future';
7365: } elsif ($start > $now) {
7366: $status = 'previous';
7367: }
7368: if (($status ne '') && (grep/^\Q$status\E$/,@{$possible_status})) {
7369: $sectioncount{$section}++;
7370: }
7371: }
1.233 raeburn 7372: }
1.366 albertel 7373: return %sectioncount;
1.233 raeburn 7374: }
7375:
1.274 raeburn 7376: ###############################################
1.294 raeburn 7377:
7378: =pod
1.405 albertel 7379:
7380: =item * &get_course_users()
7381:
1.275 raeburn 7382: Retrieves usernames:domains for users in the specified course
7383: with specific role(s), and access status.
7384:
7385: Incoming parameters:
1.277 albertel 7386: 1. course domain
7387: 2. course number
7388: 3. access status: users must have - either active,
1.275 raeburn 7389: previous, future, or all.
1.277 albertel 7390: 4. reference to array of permissible roles
1.288 raeburn 7391: 5. reference to array of section restrictions (optional)
7392: 6. reference to results object (hash of hashes).
7393: 7. reference to optional userdata hash
1.609 raeburn 7394: 8. reference to optional statushash
1.630 raeburn 7395: 9. flag if privileged users (except those set to unhide in
7396: course settings) should be excluded
1.609 raeburn 7397: Keys of top level results hash are roles.
1.275 raeburn 7398: Keys of inner hashes are username:domain, with
7399: values set to access type.
1.288 raeburn 7400: Optional userdata hash returns an array with arguments in the
7401: same order as loncoursedata::get_classlist() for student data.
7402:
1.609 raeburn 7403: Optional statushash returns
7404:
1.288 raeburn 7405: Entries for end, start, section and status are blank because
7406: of the possibility of multiple values for non-student roles.
7407:
1.275 raeburn 7408: =cut
1.405 albertel 7409:
1.275 raeburn 7410: ###############################################
1.405 albertel 7411:
1.275 raeburn 7412: sub get_course_users {
1.630 raeburn 7413: my ($cdom,$cnum,$types,$roles,$sections,$users,$userdata,$statushash,$hidepriv) = @_;
1.288 raeburn 7414: my %idx = ();
1.419 raeburn 7415: my %seclists;
1.288 raeburn 7416:
7417: $idx{udom} = &Apache::loncoursedata::CL_SDOM();
7418: $idx{uname} = &Apache::loncoursedata::CL_SNAME();
7419: $idx{end} = &Apache::loncoursedata::CL_END();
7420: $idx{start} = &Apache::loncoursedata::CL_START();
7421: $idx{id} = &Apache::loncoursedata::CL_ID();
7422: $idx{section} = &Apache::loncoursedata::CL_SECTION();
7423: $idx{fullname} = &Apache::loncoursedata::CL_FULLNAME();
7424: $idx{status} = &Apache::loncoursedata::CL_STATUS();
7425:
1.290 albertel 7426: if (grep(/^st$/,@{$roles})) {
1.276 albertel 7427: my ($classlist,$keylist)=&Apache::loncoursedata::get_classlist($cdom,$cnum);
1.278 raeburn 7428: my $now = time;
1.277 albertel 7429: foreach my $student (keys(%{$classlist})) {
1.288 raeburn 7430: my $match = 0;
1.412 raeburn 7431: my $secmatch = 0;
1.419 raeburn 7432: my $section = $$classlist{$student}[$idx{section}];
1.609 raeburn 7433: my $status = $$classlist{$student}[$idx{status}];
1.419 raeburn 7434: if ($section eq '') {
7435: $section = 'none';
7436: }
1.291 albertel 7437: if ((ref($sections) eq 'ARRAY') && (@{$sections} > 0)) {
1.420 albertel 7438: if (grep(/^all$/,@{$sections})) {
1.412 raeburn 7439: $secmatch = 1;
7440: } elsif ($$classlist{$student}[$idx{section}] eq '') {
1.420 albertel 7441: if (grep(/^none$/,@{$sections})) {
1.412 raeburn 7442: $secmatch = 1;
7443: }
7444: } else {
1.419 raeburn 7445: if (grep(/^\Q$section\E$/,@{$sections})) {
1.412 raeburn 7446: $secmatch = 1;
7447: }
1.290 albertel 7448: }
1.412 raeburn 7449: if (!$secmatch) {
7450: next;
7451: }
1.419 raeburn 7452: }
1.275 raeburn 7453: if (defined($$types{'active'})) {
1.288 raeburn 7454: if ($$classlist{$student}[$idx{status}] eq 'Active') {
1.275 raeburn 7455: push(@{$$users{st}{$student}},'active');
1.288 raeburn 7456: $match = 1;
1.275 raeburn 7457: }
7458: }
7459: if (defined($$types{'previous'})) {
1.609 raeburn 7460: if ($$classlist{$student}[$idx{status}] eq 'Expired') {
1.275 raeburn 7461: push(@{$$users{st}{$student}},'previous');
1.288 raeburn 7462: $match = 1;
1.275 raeburn 7463: }
7464: }
7465: if (defined($$types{'future'})) {
1.609 raeburn 7466: if ($$classlist{$student}[$idx{status}] eq 'Future') {
1.275 raeburn 7467: push(@{$$users{st}{$student}},'future');
1.288 raeburn 7468: $match = 1;
1.275 raeburn 7469: }
7470: }
1.609 raeburn 7471: if ($match) {
7472: push(@{$seclists{$student}},$section);
7473: if (ref($userdata) eq 'HASH') {
7474: $$userdata{$student} = $$classlist{$student};
7475: }
7476: if (ref($statushash) eq 'HASH') {
7477: $statushash->{$student}{'st'}{$section} = $status;
7478: }
1.288 raeburn 7479: }
1.275 raeburn 7480: }
7481: }
1.412 raeburn 7482: if ((@{$roles} > 1) || ((@{$roles} == 1) && ($$roles[0] ne "st"))) {
1.439 raeburn 7483: my %coursepersonnel = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
7484: my $now = time;
1.609 raeburn 7485: my %displaystatus = ( previous => 'Expired',
7486: active => 'Active',
7487: future => 'Future',
7488: );
1.630 raeburn 7489: my %nothide;
7490: if ($hidepriv) {
7491: my %coursehash=&Apache::lonnet::coursedescription($cdom.'_'.$cnum);
7492: foreach my $user (split(/\s*\,\s*/,$coursehash{'nothideprivileged'})) {
7493: if ($user !~ /:/) {
7494: $nothide{join(':',split(/[\@]/,$user))}=1;
7495: } else {
7496: $nothide{$user} = 1;
7497: }
7498: }
7499: }
1.439 raeburn 7500: foreach my $person (sort(keys(%coursepersonnel))) {
1.288 raeburn 7501: my $match = 0;
1.412 raeburn 7502: my $secmatch = 0;
1.439 raeburn 7503: my $status;
1.412 raeburn 7504: my ($role,$user,$usec) = ($person =~ /^([^:]*):([^:]+:[^:]+):([^:]*)/);
1.275 raeburn 7505: $user =~ s/:$//;
1.439 raeburn 7506: my ($end,$start) = split(/:/,$coursepersonnel{$person});
7507: if ($end == -1 || $start == -1) {
7508: next;
7509: }
7510: if (($role) && ((grep(/^\Q$role\E$/,@{$roles})) ||
7511: (grep(/^cr$/,@{$roles}) && $role =~ /^cr\//))) {
1.412 raeburn 7512: my ($uname,$udom) = split(/:/,$user);
7513: if ((ref($sections) eq 'ARRAY') && (@{$sections} > 0)) {
1.420 albertel 7514: if (grep(/^all$/,@{$sections})) {
1.412 raeburn 7515: $secmatch = 1;
7516: } elsif ($usec eq '') {
1.420 albertel 7517: if (grep(/^none$/,@{$sections})) {
1.412 raeburn 7518: $secmatch = 1;
7519: }
7520: } else {
7521: if (grep(/^\Q$usec\E$/,@{$sections})) {
7522: $secmatch = 1;
7523: }
7524: }
7525: if (!$secmatch) {
7526: next;
7527: }
1.288 raeburn 7528: }
1.419 raeburn 7529: if ($usec eq '') {
7530: $usec = 'none';
7531: }
1.275 raeburn 7532: if ($uname ne '' && $udom ne '') {
1.630 raeburn 7533: if ($hidepriv) {
7534: if ((&Apache::lonnet::privileged($uname,$udom)) &&
7535: (!$nothide{$uname.':'.$udom})) {
7536: next;
7537: }
7538: }
1.503 raeburn 7539: if ($end > 0 && $end < $now) {
1.439 raeburn 7540: $status = 'previous';
7541: } elsif ($start > $now) {
7542: $status = 'future';
7543: } else {
7544: $status = 'active';
7545: }
1.277 albertel 7546: foreach my $type (keys(%{$types})) {
1.275 raeburn 7547: if ($status eq $type) {
1.420 albertel 7548: if (!grep(/^\Q$type\E$/,@{$$users{$role}{$user}})) {
1.419 raeburn 7549: push(@{$$users{$role}{$user}},$type);
7550: }
1.288 raeburn 7551: $match = 1;
7552: }
7553: }
1.419 raeburn 7554: if (($match) && (ref($userdata) eq 'HASH')) {
7555: if (!exists($$userdata{$uname.':'.$udom})) {
7556: &get_user_info($udom,$uname,\%idx,$userdata);
7557: }
1.420 albertel 7558: if (!grep(/^\Q$usec\E$/,@{$seclists{$uname.':'.$udom}})) {
1.419 raeburn 7559: push(@{$seclists{$uname.':'.$udom}},$usec);
7560: }
1.609 raeburn 7561: if (ref($statushash) eq 'HASH') {
7562: $statushash->{$uname.':'.$udom}{$role}{$usec} = $displaystatus{$status};
7563: }
1.275 raeburn 7564: }
7565: }
7566: }
7567: }
1.290 albertel 7568: if (grep(/^ow$/,@{$roles})) {
1.279 raeburn 7569: if ((defined($cdom)) && (defined($cnum))) {
7570: my %csettings = &Apache::lonnet::get('environment',['internal.courseowner'],$cdom,$cnum);
7571: if ( defined($csettings{'internal.courseowner'}) ) {
7572: my $owner = $csettings{'internal.courseowner'};
1.609 raeburn 7573: next if ($owner eq '');
7574: my ($ownername,$ownerdom);
7575: if ($owner =~ /^([^:]+):([^:]+)$/) {
7576: $ownername = $1;
7577: $ownerdom = $2;
7578: } else {
7579: $ownername = $owner;
7580: $ownerdom = $cdom;
7581: $owner = $ownername.':'.$ownerdom;
1.439 raeburn 7582: }
7583: @{$$users{'ow'}{$owner}} = 'any';
1.290 albertel 7584: if (defined($userdata) &&
1.609 raeburn 7585: !exists($$userdata{$owner})) {
7586: &get_user_info($ownerdom,$ownername,\%idx,$userdata);
7587: if (!grep(/^none$/,@{$seclists{$owner}})) {
7588: push(@{$seclists{$owner}},'none');
7589: }
7590: if (ref($statushash) eq 'HASH') {
7591: $statushash->{$owner}{'ow'}{'none'} = 'Any';
1.419 raeburn 7592: }
1.290 albertel 7593: }
1.279 raeburn 7594: }
7595: }
7596: }
1.419 raeburn 7597: foreach my $user (keys(%seclists)) {
7598: @{$seclists{$user}} = (sort {$a <=> $b} @{$seclists{$user}});
7599: $$userdata{$user}[$idx{section}] = join(',',@{$seclists{$user}});
7600: }
1.275 raeburn 7601: }
7602: return;
7603: }
7604:
1.288 raeburn 7605: sub get_user_info {
7606: my ($udom,$uname,$idx,$userdata) = @_;
1.289 albertel 7607: $$userdata{$uname.':'.$udom}[$$idx{fullname}] =
7608: &plainname($uname,$udom,'lastname');
1.291 albertel 7609: $$userdata{$uname.':'.$udom}[$$idx{uname}] = $uname;
1.297 raeburn 7610: $$userdata{$uname.':'.$udom}[$$idx{udom}] = $udom;
1.609 raeburn 7611: my %idhash = &Apache::lonnet::idrget($udom,($uname));
7612: $$userdata{$uname.':'.$udom}[$$idx{id}] = $idhash{$uname};
1.288 raeburn 7613: return;
7614: }
1.275 raeburn 7615:
1.472 raeburn 7616: ###############################################
7617:
7618: =pod
7619:
7620: =item * &get_user_quota()
7621:
7622: Retrieves quota assigned for storage of portfolio files for a user
7623:
7624: Incoming parameters:
7625: 1. user's username
7626: 2. user's domain
7627:
7628: Returns:
1.536 raeburn 7629: 1. Disk quota (in Mb) assigned to student.
7630: 2. (Optional) Type of setting: custom or default
7631: (individually assigned or default for user's
7632: institutional status).
7633: 3. (Optional) - User's institutional status (e.g., faculty, staff
7634: or student - types as defined in localenroll::inst_usertypes
7635: for user's domain, which determines default quota for user.
7636: 4. (Optional) - Default quota which would apply to the user.
1.472 raeburn 7637:
7638: If a value has been stored in the user's environment,
1.536 raeburn 7639: it will return that, otherwise it returns the maximal default
7640: defined for the user's instituional status(es) in the domain.
1.472 raeburn 7641:
7642: =cut
7643:
7644: ###############################################
7645:
7646:
7647: sub get_user_quota {
7648: my ($uname,$udom) = @_;
1.536 raeburn 7649: my ($quota,$quotatype,$settingstatus,$defquota);
1.472 raeburn 7650: if (!defined($udom)) {
7651: $udom = $env{'user.domain'};
7652: }
7653: if (!defined($uname)) {
7654: $uname = $env{'user.name'};
7655: }
7656: if (($udom eq '' || $uname eq '') ||
7657: ($udom eq 'public') && ($uname eq 'public')) {
7658: $quota = 0;
1.536 raeburn 7659: $quotatype = 'default';
7660: $defquota = 0;
1.472 raeburn 7661: } else {
1.536 raeburn 7662: my $inststatus;
1.472 raeburn 7663: if ($udom eq $env{'user.domain'} && $uname eq $env{'user.name'}) {
7664: $quota = $env{'environment.portfolioquota'};
1.536 raeburn 7665: $inststatus = $env{'environment.inststatus'};
1.472 raeburn 7666: } else {
1.536 raeburn 7667: my %userenv =
7668: &Apache::lonnet::get('environment',['portfolioquota',
7669: 'inststatus'],$udom,$uname);
1.472 raeburn 7670: my ($tmp) = keys(%userenv);
7671: if ($tmp !~ /^(con_lost|error|no_such_host)/i) {
7672: $quota = $userenv{'portfolioquota'};
1.536 raeburn 7673: $inststatus = $userenv{'inststatus'};
1.472 raeburn 7674: } else {
7675: undef(%userenv);
7676: }
7677: }
1.536 raeburn 7678: ($defquota,$settingstatus) = &default_quota($udom,$inststatus);
1.472 raeburn 7679: if ($quota eq '') {
1.536 raeburn 7680: $quota = $defquota;
7681: $quotatype = 'default';
7682: } else {
7683: $quotatype = 'custom';
1.472 raeburn 7684: }
7685: }
1.536 raeburn 7686: if (wantarray) {
7687: return ($quota,$quotatype,$settingstatus,$defquota);
7688: } else {
7689: return $quota;
7690: }
1.472 raeburn 7691: }
7692:
7693: ###############################################
7694:
7695: =pod
7696:
7697: =item * &default_quota()
7698:
1.536 raeburn 7699: Retrieves default quota assigned for storage of user portfolio files,
7700: given an (optional) user's institutional status.
1.472 raeburn 7701:
7702: Incoming parameters:
7703: 1. domain
1.536 raeburn 7704: 2. (Optional) institutional status(es). This is a : separated list of
7705: status types (e.g., faculty, staff, student etc.)
7706: which apply to the user for whom the default is being retrieved.
7707: If the institutional status string in undefined, the domain
7708: default quota will be returned.
1.472 raeburn 7709:
7710: Returns:
7711: 1. Default disk quota (in Mb) for user portfolios in the domain.
1.536 raeburn 7712: 2. (Optional) institutional type which determined the value of the
7713: default quota.
1.472 raeburn 7714:
7715: If a value has been stored in the domain's configuration db,
7716: it will return that, otherwise it returns 20 (for backwards
7717: compatibility with domains which have not set up a configuration
7718: db file; the original statically defined portfolio quota was 20 Mb).
7719:
1.536 raeburn 7720: If the user's status includes multiple types (e.g., staff and student),
7721: the largest default quota which applies to the user determines the
7722: default quota returned.
7723:
1.780 raeburn 7724: =back
7725:
1.472 raeburn 7726: =cut
7727:
7728: ###############################################
7729:
7730:
7731: sub default_quota {
1.536 raeburn 7732: my ($udom,$inststatus) = @_;
7733: my ($defquota,$settingstatus);
7734: my %quotahash = &Apache::lonnet::get_dom('configuration',
1.622 raeburn 7735: ['quotas'],$udom);
7736: if (ref($quotahash{'quotas'}) eq 'HASH') {
1.536 raeburn 7737: if ($inststatus ne '') {
1.765 raeburn 7738: my @statuses = map { &unescape($_); } split(/:/,$inststatus);
1.536 raeburn 7739: foreach my $item (@statuses) {
1.711 raeburn 7740: if (ref($quotahash{'quotas'}{'defaultquota'}) eq 'HASH') {
7741: if ($quotahash{'quotas'}{'defaultquota'}{$item} ne '') {
7742: if ($defquota eq '') {
7743: $defquota = $quotahash{'quotas'}{'defaultquota'}{$item};
7744: $settingstatus = $item;
7745: } elsif ($quotahash{'quotas'}{'defaultquota'}{$item} > $defquota) {
7746: $defquota = $quotahash{'quotas'}{'defaultquota'}{$item};
7747: $settingstatus = $item;
7748: }
7749: }
7750: } else {
7751: if ($quotahash{'quotas'}{$item} ne '') {
7752: if ($defquota eq '') {
7753: $defquota = $quotahash{'quotas'}{$item};
7754: $settingstatus = $item;
7755: } elsif ($quotahash{'quotas'}{$item} > $defquota) {
7756: $defquota = $quotahash{'quotas'}{$item};
7757: $settingstatus = $item;
7758: }
1.536 raeburn 7759: }
7760: }
7761: }
7762: }
7763: if ($defquota eq '') {
1.711 raeburn 7764: if (ref($quotahash{'quotas'}{'defaultquota'}) eq 'HASH') {
7765: $defquota = $quotahash{'quotas'}{'defaultquota'}{'default'};
7766: } else {
7767: $defquota = $quotahash{'quotas'}{'default'};
7768: }
1.536 raeburn 7769: $settingstatus = 'default';
7770: }
7771: } else {
7772: $settingstatus = 'default';
7773: $defquota = 20;
7774: }
7775: if (wantarray) {
7776: return ($defquota,$settingstatus);
1.472 raeburn 7777: } else {
1.536 raeburn 7778: return $defquota;
1.472 raeburn 7779: }
7780: }
7781:
1.384 raeburn 7782: sub get_secgrprole_info {
7783: my ($cdom,$cnum,$needroles,$type) = @_;
7784: my %sections_count = &get_sections($cdom,$cnum);
7785: my @sections = (sort {$a <=> $b} keys(%sections_count));
7786: my %curr_groups = &Apache::longroup::coursegroups($cdom,$cnum);
7787: my @groups = sort(keys(%curr_groups));
7788: my $allroles = [];
7789: my $rolehash;
7790: my $accesshash = {
7791: active => 'Currently has access',
7792: future => 'Will have future access',
7793: previous => 'Previously had access',
7794: };
7795: if ($needroles) {
7796: $rolehash = {'all' => 'all'};
1.385 albertel 7797: my %user_roles = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
7798: if (&Apache::lonnet::error(%user_roles)) {
7799: undef(%user_roles);
7800: }
7801: foreach my $item (keys(%user_roles)) {
1.384 raeburn 7802: my ($role)=split(/\:/,$item,2);
7803: if ($role eq 'cr') { next; }
7804: if ($role =~ /^cr/) {
7805: $$rolehash{$role} = (split('/',$role))[3];
7806: } else {
7807: $$rolehash{$role} = &Apache::lonnet::plaintext($role,$type);
7808: }
7809: }
7810: foreach my $key (sort(keys(%{$rolehash}))) {
7811: push(@{$allroles},$key);
7812: }
7813: push (@{$allroles},'st');
7814: $$rolehash{'st'} = &Apache::lonnet::plaintext('st',$type);
7815: }
7816: return (\@sections,\@groups,$allroles,$rolehash,$accesshash);
7817: }
7818:
1.555 raeburn 7819: sub user_picker {
1.627 raeburn 7820: my ($dom,$srch,$forcenewuser,$caller,$cancreate,$usertype) = @_;
1.555 raeburn 7821: my $currdom = $dom;
7822: my %curr_selected = (
7823: srchin => 'dom',
1.580 raeburn 7824: srchby => 'lastname',
1.555 raeburn 7825: );
7826: my $srchterm;
1.625 raeburn 7827: if ((ref($srch) eq 'HASH') && ($env{'form.origform'} ne 'crtusername')) {
1.555 raeburn 7828: if ($srch->{'srchby'} ne '') {
7829: $curr_selected{'srchby'} = $srch->{'srchby'};
7830: }
7831: if ($srch->{'srchin'} ne '') {
7832: $curr_selected{'srchin'} = $srch->{'srchin'};
7833: }
7834: if ($srch->{'srchtype'} ne '') {
7835: $curr_selected{'srchtype'} = $srch->{'srchtype'};
7836: }
7837: if ($srch->{'srchdomain'} ne '') {
7838: $currdom = $srch->{'srchdomain'};
7839: }
7840: $srchterm = $srch->{'srchterm'};
7841: }
7842: my %lt=&Apache::lonlocal::texthash(
1.573 raeburn 7843: 'usr' => 'Search criteria',
1.563 raeburn 7844: 'doma' => 'Domain/institution to search',
1.558 albertel 7845: 'uname' => 'username',
7846: 'lastname' => 'last name',
1.555 raeburn 7847: 'lastfirst' => 'last name, first name',
1.558 albertel 7848: 'crs' => 'in this course',
1.576 raeburn 7849: 'dom' => 'in selected LON-CAPA domain',
1.558 albertel 7850: 'alc' => 'all LON-CAPA',
1.573 raeburn 7851: 'instd' => 'in institutional directory for selected domain',
1.558 albertel 7852: 'exact' => 'is',
7853: 'contains' => 'contains',
1.569 raeburn 7854: 'begins' => 'begins with',
1.571 raeburn 7855: 'youm' => "You must include some text to search for.",
7856: 'thte' => "The text you are searching for must contain at least two characters when using a 'begins' type search.",
7857: 'thet' => "The text you are searching for must contain at least three characters when using a 'contains' type search.",
7858: 'yomc' => "You must choose a domain when using an institutional directory search.",
7859: 'ymcd' => "You must choose a domain when using a domain search.",
7860: 'whus' => "When using searching by last,first you must include a comma as separator between last name and first name.",
7861: 'whse' => "When searching by last,first you must include at least one character in the first name.",
7862: 'thfo' => "The following need to be corrected before the search can be run:",
1.555 raeburn 7863: );
1.563 raeburn 7864: my $domform = &select_dom_form($currdom,'srchdomain',1,1);
7865: my $srchinsel = ' <select name="srchin">';
1.555 raeburn 7866:
7867: my @srchins = ('crs','dom','alc','instd');
7868:
7869: foreach my $option (@srchins) {
7870: # FIXME 'alc' option unavailable until
7871: # loncreateuser::print_user_query_page()
7872: # has been completed.
7873: next if ($option eq 'alc');
1.880 raeburn 7874: next if (($option eq 'crs') && ($env{'form.form'} eq 'requestcrs'));
1.555 raeburn 7875: next if ($option eq 'crs' && !$env{'request.course.id'});
1.563 raeburn 7876: if ($curr_selected{'srchin'} eq $option) {
7877: $srchinsel .= '
7878: <option value="'.$option.'" selected="selected">'.$lt{$option}.'</option>';
7879: } else {
7880: $srchinsel .= '
7881: <option value="'.$option.'">'.$lt{$option}.'</option>';
7882: }
1.555 raeburn 7883: }
1.563 raeburn 7884: $srchinsel .= "\n </select>\n";
1.555 raeburn 7885:
7886: my $srchbysel = ' <select name="srchby">';
1.580 raeburn 7887: foreach my $option ('lastname','lastfirst','uname') {
1.555 raeburn 7888: if ($curr_selected{'srchby'} eq $option) {
7889: $srchbysel .= '
7890: <option value="'.$option.'" selected="selected">'.$lt{$option}.'</option>';
7891: } else {
7892: $srchbysel .= '
7893: <option value="'.$option.'">'.$lt{$option}.'</option>';
7894: }
7895: }
7896: $srchbysel .= "\n </select>\n";
7897:
7898: my $srchtypesel = ' <select name="srchtype">';
1.580 raeburn 7899: foreach my $option ('begins','contains','exact') {
1.555 raeburn 7900: if ($curr_selected{'srchtype'} eq $option) {
7901: $srchtypesel .= '
7902: <option value="'.$option.'" selected="selected">'.$lt{$option}.'</option>';
7903: } else {
7904: $srchtypesel .= '
7905: <option value="'.$option.'">'.$lt{$option}.'</option>';
7906: }
7907: }
7908: $srchtypesel .= "\n </select>\n";
7909:
1.558 albertel 7910: my ($newuserscript,$new_user_create);
1.556 raeburn 7911:
7912: if ($forcenewuser) {
1.576 raeburn 7913: if (ref($srch) eq 'HASH') {
7914: if ($srch->{'srchby'} eq 'uname' && $srch->{'srchtype'} eq 'exact' && $srch->{'srchin'} eq 'dom' && $srch->{'srchdomain'} eq $env{'request.role.domain'}) {
1.627 raeburn 7915: if ($cancreate) {
7916: $new_user_create = '<p> <input type="submit" name="forcenew" value="'.&HTML::Entities::encode(&mt('Make new user "[_1]"',$srchterm),'<>&"').'" onclick="javascript:setSearch(\'1\','.$caller.');" /> </p>';
7917: } else {
1.799 bisitz 7918: my $helplink = 'javascript:helpMenu('."'display'".')';
1.627 raeburn 7919: my %usertypetext = (
7920: official => 'institutional',
7921: unofficial => 'non-institutional',
7922: );
1.799 bisitz 7923: $new_user_create = '<p class="LC_warning">'
7924: .&mt("You are not authorized to create new $usertypetext{$usertype} users in this domain.")
7925: .' '
7926: .&mt('Please contact the [_1]helpdesk[_2] for assistance.'
7927: ,'<a href="'.$helplink.'">','</a>')
7928: .'</p><br />';
1.627 raeburn 7929: }
1.576 raeburn 7930: }
7931: }
7932:
1.556 raeburn 7933: $newuserscript = <<"ENDSCRIPT";
7934:
1.570 raeburn 7935: function setSearch(createnew,callingForm) {
1.556 raeburn 7936: if (createnew == 1) {
1.570 raeburn 7937: for (var i=0; i<callingForm.srchby.length; i++) {
7938: if (callingForm.srchby.options[i].value == 'uname') {
7939: callingForm.srchby.selectedIndex = i;
1.556 raeburn 7940: }
7941: }
1.570 raeburn 7942: for (var i=0; i<callingForm.srchin.length; i++) {
7943: if ( callingForm.srchin.options[i].value == 'dom') {
7944: callingForm.srchin.selectedIndex = i;
1.556 raeburn 7945: }
7946: }
1.570 raeburn 7947: for (var i=0; i<callingForm.srchtype.length; i++) {
7948: if (callingForm.srchtype.options[i].value == 'exact') {
7949: callingForm.srchtype.selectedIndex = i;
1.556 raeburn 7950: }
7951: }
1.570 raeburn 7952: for (var i=0; i<callingForm.srchdomain.length; i++) {
7953: if (callingForm.srchdomain.options[i].value == '$env{'request.role.domain'}') {
7954: callingForm.srchdomain.selectedIndex = i;
1.556 raeburn 7955: }
7956: }
7957: }
7958: }
7959: ENDSCRIPT
1.558 albertel 7960:
1.556 raeburn 7961: }
7962:
1.555 raeburn 7963: my $output = <<"END_BLOCK";
1.556 raeburn 7964: <script type="text/javascript">
1.824 bisitz 7965: // <![CDATA[
1.570 raeburn 7966: function validateEntry(callingForm) {
1.558 albertel 7967:
1.556 raeburn 7968: var checkok = 1;
1.558 albertel 7969: var srchin;
1.570 raeburn 7970: for (var i=0; i<callingForm.srchin.length; i++) {
7971: if ( callingForm.srchin[i].checked ) {
7972: srchin = callingForm.srchin[i].value;
1.558 albertel 7973: }
7974: }
7975:
1.570 raeburn 7976: var srchtype = callingForm.srchtype.options[callingForm.srchtype.selectedIndex].value;
7977: var srchby = callingForm.srchby.options[callingForm.srchby.selectedIndex].value;
7978: var srchdomain = callingForm.srchdomain.options[callingForm.srchdomain.selectedIndex].value;
7979: var srchterm = callingForm.srchterm.value;
7980: var srchin = callingForm.srchin.options[callingForm.srchin.selectedIndex].value;
1.556 raeburn 7981: var msg = "";
7982:
7983: if (srchterm == "") {
7984: checkok = 0;
1.571 raeburn 7985: msg += "$lt{'youm'}\\n";
1.556 raeburn 7986: }
7987:
1.569 raeburn 7988: if (srchtype== 'begins') {
7989: if (srchterm.length < 2) {
7990: checkok = 0;
1.571 raeburn 7991: msg += "$lt{'thte'}\\n";
1.569 raeburn 7992: }
7993: }
7994:
1.556 raeburn 7995: if (srchtype== 'contains') {
7996: if (srchterm.length < 3) {
7997: checkok = 0;
1.571 raeburn 7998: msg += "$lt{'thet'}\\n";
1.556 raeburn 7999: }
8000: }
8001: if (srchin == 'instd') {
8002: if (srchdomain == '') {
8003: checkok = 0;
1.571 raeburn 8004: msg += "$lt{'yomc'}\\n";
1.556 raeburn 8005: }
8006: }
8007: if (srchin == 'dom') {
8008: if (srchdomain == '') {
8009: checkok = 0;
1.571 raeburn 8010: msg += "$lt{'ymcd'}\\n";
1.556 raeburn 8011: }
8012: }
8013: if (srchby == 'lastfirst') {
8014: if (srchterm.indexOf(",") == -1) {
8015: checkok = 0;
1.571 raeburn 8016: msg += "$lt{'whus'}\\n";
1.556 raeburn 8017: }
8018: if (srchterm.indexOf(",") == srchterm.length -1) {
8019: checkok = 0;
1.571 raeburn 8020: msg += "$lt{'whse'}\\n";
1.556 raeburn 8021: }
8022: }
8023: if (checkok == 0) {
1.571 raeburn 8024: alert("$lt{'thfo'}\\n"+msg);
1.556 raeburn 8025: return;
8026: }
8027: if (checkok == 1) {
1.570 raeburn 8028: callingForm.submit();
1.556 raeburn 8029: }
8030: }
8031:
8032: $newuserscript
8033:
1.824 bisitz 8034: // ]]>
1.556 raeburn 8035: </script>
1.558 albertel 8036:
8037: $new_user_create
8038:
1.555 raeburn 8039: END_BLOCK
1.558 albertel 8040:
1.876 raeburn 8041: $output .= &Apache::lonhtmlcommon::start_pick_box().
8042: &Apache::lonhtmlcommon::row_title($lt{'doma'}).
8043: $domform.
8044: &Apache::lonhtmlcommon::row_closure().
8045: &Apache::lonhtmlcommon::row_title($lt{'usr'}).
8046: $srchbysel.
8047: $srchtypesel.
8048: '<input type="text" size="15" name="srchterm" value="'.$srchterm.'" />'.
8049: $srchinsel.
8050: &Apache::lonhtmlcommon::row_closure(1).
8051: &Apache::lonhtmlcommon::end_pick_box().
8052: '<br />';
1.555 raeburn 8053: return $output;
8054: }
8055:
1.612 raeburn 8056: sub user_rule_check {
1.615 raeburn 8057: my ($usershash,$checks,$alerts,$rulematch,$inst_results,$curr_rules,$got_rules) = @_;
1.612 raeburn 8058: my $response;
8059: if (ref($usershash) eq 'HASH') {
8060: foreach my $user (keys(%{$usershash})) {
8061: my ($uname,$udom) = split(/:/,$user);
8062: next if ($udom eq '' || $uname eq '');
1.615 raeburn 8063: my ($id,$newuser);
1.612 raeburn 8064: if (ref($usershash->{$user}) eq 'HASH') {
1.615 raeburn 8065: $newuser = $usershash->{$user}->{'newuser'};
1.612 raeburn 8066: $id = $usershash->{$user}->{'id'};
8067: }
8068: my $inst_response;
8069: if (ref($checks) eq 'HASH') {
8070: if (defined($checks->{'username'})) {
1.615 raeburn 8071: ($inst_response,%{$inst_results->{$user}}) =
1.612 raeburn 8072: &Apache::lonnet::get_instuser($udom,$uname);
8073: } elsif (defined($checks->{'id'})) {
1.615 raeburn 8074: ($inst_response,%{$inst_results->{$user}}) =
1.612 raeburn 8075: &Apache::lonnet::get_instuser($udom,undef,$id);
8076: }
1.615 raeburn 8077: } else {
8078: ($inst_response,%{$inst_results->{$user}}) =
8079: &Apache::lonnet::get_instuser($udom,$uname);
8080: return;
1.612 raeburn 8081: }
1.615 raeburn 8082: if (!$got_rules->{$udom}) {
1.612 raeburn 8083: my %domconfig = &Apache::lonnet::get_dom('configuration',
8084: ['usercreation'],$udom);
8085: if (ref($domconfig{'usercreation'}) eq 'HASH') {
1.615 raeburn 8086: foreach my $item ('username','id') {
1.612 raeburn 8087: if (ref($domconfig{'usercreation'}{$item.'_rule'}) eq 'ARRAY') {
8088: $$curr_rules{$udom}{$item} =
8089: $domconfig{'usercreation'}{$item.'_rule'};
1.585 raeburn 8090: }
8091: }
8092: }
1.615 raeburn 8093: $got_rules->{$udom} = 1;
1.585 raeburn 8094: }
1.612 raeburn 8095: foreach my $item (keys(%{$checks})) {
8096: if (ref($$curr_rules{$udom}) eq 'HASH') {
8097: if (ref($$curr_rules{$udom}{$item}) eq 'ARRAY') {
8098: if (@{$$curr_rules{$udom}{$item}} > 0) {
8099: my %rule_check = &Apache::lonnet::inst_rulecheck($udom,$uname,$id,$item,$$curr_rules{$udom}{$item});
8100: foreach my $rule (@{$$curr_rules{$udom}{$item}}) {
8101: if ($rule_check{$rule}) {
8102: $$rulematch{$user}{$item} = $rule;
8103: if ($inst_response eq 'ok') {
1.615 raeburn 8104: if (ref($inst_results) eq 'HASH') {
8105: if (ref($inst_results->{$user}) eq 'HASH') {
8106: if (keys(%{$inst_results->{$user}}) == 0) {
8107: $$alerts{$item}{$udom}{$uname} = 1;
8108: }
1.612 raeburn 8109: }
8110: }
1.615 raeburn 8111: }
8112: last;
1.585 raeburn 8113: }
8114: }
8115: }
8116: }
8117: }
8118: }
8119: }
8120: }
1.612 raeburn 8121: return;
8122: }
8123:
8124: sub user_rule_formats {
8125: my ($domain,$domdesc,$curr_rules,$check) = @_;
8126: my %text = (
8127: 'username' => 'Usernames',
8128: 'id' => 'IDs',
8129: );
8130: my $output;
8131: my ($rules,$ruleorder) = &Apache::lonnet::inst_userrules($domain,$check);
8132: if ((ref($rules) eq 'HASH') && (ref($ruleorder) eq 'ARRAY')) {
8133: if (@{$ruleorder} > 0) {
8134: $output = '<br />'.&mt("$text{$check} with the following format(s) may <span class=\"LC_cusr_emph\">only</span> be used for verified users at [_1]:",$domdesc).' <ul>';
8135: foreach my $rule (@{$ruleorder}) {
8136: if (ref($curr_rules) eq 'ARRAY') {
8137: if (grep(/^\Q$rule\E$/,@{$curr_rules})) {
8138: if (ref($rules->{$rule}) eq 'HASH') {
8139: $output .= '<li>'.$rules->{$rule}{'name'}.': '.
8140: $rules->{$rule}{'desc'}.'</li>';
8141: }
8142: }
8143: }
8144: }
8145: $output .= '</ul>';
8146: }
8147: }
8148: return $output;
8149: }
8150:
8151: sub instrule_disallow_msg {
1.615 raeburn 8152: my ($checkitem,$domdesc,$count,$mode) = @_;
1.612 raeburn 8153: my $response;
8154: my %text = (
8155: item => 'username',
8156: items => 'usernames',
8157: match => 'matches',
8158: do => 'does',
8159: action => 'a username',
8160: one => 'one',
8161: );
8162: if ($count > 1) {
8163: $text{'item'} = 'usernames';
8164: $text{'match'} ='match';
8165: $text{'do'} = 'do';
8166: $text{'action'} = 'usernames',
8167: $text{'one'} = 'ones';
8168: }
8169: if ($checkitem eq 'id') {
8170: $text{'items'} = 'IDs';
8171: $text{'item'} = 'ID';
8172: $text{'action'} = 'an ID';
1.615 raeburn 8173: if ($count > 1) {
8174: $text{'item'} = 'IDs';
8175: $text{'action'} = 'IDs';
8176: }
1.612 raeburn 8177: }
1.674 bisitz 8178: $response = &mt("The $text{'item'} you chose $text{'match'} the format of $text{'items'} defined for [_1], but the $text{'item'} $text{'do'} not exist in the institutional directory.",'<span class="LC_cusr_emph">'.$domdesc.'</span>').'<br />';
1.615 raeburn 8179: if ($mode eq 'upload') {
8180: if ($checkitem eq 'username') {
8181: $response .= &mt("You will need to modify your upload file so it will include $text{'action'} with a different format -- $text{'one'} that will not conflict with 'official' institutional $text{'items'}.");
8182: } elsif ($checkitem eq 'id') {
1.674 bisitz 8183: $response .= &mt("Either upload a file which includes $text{'action'} with a different format -- $text{'one'} that will not conflict with 'official' institutional $text{'items'}, or when associating fields with data columns, omit an association for the Student/Employee ID field.");
1.615 raeburn 8184: }
1.669 raeburn 8185: } elsif ($mode eq 'selfcreate') {
8186: if ($checkitem eq 'id') {
8187: $response .= &mt("You must either choose $text{'action'} with a different format -- $text{'one'} that will not conflict with 'official' institutional $text{'items'}, or leave the ID field blank.");
8188: }
1.615 raeburn 8189: } else {
8190: if ($checkitem eq 'username') {
8191: $response .= &mt("You must choose $text{'action'} with a different format -- $text{'one'} that will not conflict with 'official' institutional $text{'items'}.");
8192: } elsif ($checkitem eq 'id') {
8193: $response .= &mt("You must either choose $text{'action'} with a different format -- $text{'one'} that will not conflict with 'official' institutional $text{'items'}, or leave the ID field blank.");
8194: }
1.612 raeburn 8195: }
8196: return $response;
1.585 raeburn 8197: }
8198:
1.624 raeburn 8199: sub personal_data_fieldtitles {
8200: my %fieldtitles = &Apache::lonlocal::texthash (
8201: id => 'Student/Employee ID',
8202: permanentemail => 'E-mail address',
8203: lastname => 'Last Name',
8204: firstname => 'First Name',
8205: middlename => 'Middle Name',
8206: generation => 'Generation',
8207: gen => 'Generation',
1.765 raeburn 8208: inststatus => 'Affiliation',
1.624 raeburn 8209: );
8210: return %fieldtitles;
8211: }
8212:
1.642 raeburn 8213: sub sorted_inst_types {
8214: my ($dom) = @_;
8215: my ($usertypes,$order) = &Apache::lonnet::retrieve_inst_usertypes($dom);
8216: my $othertitle = &mt('All users');
8217: if ($env{'request.course.id'}) {
1.668 raeburn 8218: $othertitle = &mt('Any users');
1.642 raeburn 8219: }
8220: my @types;
8221: if (ref($order) eq 'ARRAY') {
8222: @types = @{$order};
8223: }
8224: if (@types == 0) {
8225: if (ref($usertypes) eq 'HASH') {
8226: @types = sort(keys(%{$usertypes}));
8227: }
8228: }
8229: if (keys(%{$usertypes}) > 0) {
8230: $othertitle = &mt('Other users');
8231: }
8232: return ($othertitle,$usertypes,\@types);
8233: }
8234:
1.645 raeburn 8235: sub get_institutional_codes {
8236: my ($settings,$allcourses,$LC_code) = @_;
8237: # Get complete list of course sections to update
8238: my @currsections = ();
8239: my @currxlists = ();
8240: my $coursecode = $$settings{'internal.coursecode'};
8241:
8242: if ($$settings{'internal.sectionnums'} ne '') {
8243: @currsections = split(/,/,$$settings{'internal.sectionnums'});
8244: }
8245:
8246: if ($$settings{'internal.crosslistings'} ne '') {
8247: @currxlists = split(/,/,$$settings{'internal.crosslistings'});
8248: }
8249:
8250: if (@currxlists > 0) {
8251: foreach (@currxlists) {
8252: if (m/^([^:]+):(\w*)$/) {
8253: unless (grep/^$1$/,@{$allcourses}) {
8254: push @{$allcourses},$1;
8255: $$LC_code{$1} = $2;
8256: }
8257: }
8258: }
8259: }
8260:
8261: if (@currsections > 0) {
8262: foreach (@currsections) {
8263: if (m/^(\w+):(\w*)$/) {
8264: my $sec = $coursecode.$1;
8265: my $lc_sec = $2;
8266: unless (grep/^$sec$/,@{$allcourses}) {
8267: push @{$allcourses},$sec;
8268: $$LC_code{$sec} = $lc_sec;
8269: }
8270: }
8271: }
8272: }
8273: return;
8274: }
8275:
1.948.2.7 raeburn 8276: sub get_standard_codeitems {
8277: return ('Year','Semester','Department','Number','Section');
8278: }
8279:
1.112 bowersj2 8280: =pod
8281:
1.780 raeburn 8282: =head1 Slot Helpers
8283:
8284: =over 4
8285:
8286: =item * sorted_slots()
8287:
8288: Sorts an array of slot names in order of slot start time (earliest first).
8289:
8290: Inputs:
8291:
8292: =over 4
8293:
8294: slotsarr - Reference to array of unsorted slot names.
8295:
8296: slots - Reference to hash of hash, where outer hash keys are slot names.
8297:
1.549 albertel 8298: =back
8299:
1.780 raeburn 8300: Returns:
8301:
8302: =over 4
8303:
8304: sorted - An array of slot names sorted by the start time of the slot.
8305:
8306: =back
8307:
8308: =back
8309:
8310: =cut
8311:
8312:
8313: sub sorted_slots {
8314: my ($slotsarr,$slots) = @_;
8315: my @sorted;
8316: if ((ref($slotsarr) eq 'ARRAY') && (ref($slots) eq 'HASH')) {
8317: @sorted =
8318: sort {
8319: if (ref($slots->{$a}) && ref($slots->{$b})) {
8320: return $slots->{$a}{'starttime'} <=> $slots->{$b}{'starttime'}
8321: }
8322: if (ref($slots->{$a})) { return -1;}
8323: if (ref($slots->{$b})) { return 1;}
8324: return 0;
8325: } @{$slotsarr};
8326: }
8327: return @sorted;
8328: }
8329:
8330:
8331: =pod
8332:
1.549 albertel 8333: =head1 HTTP Helpers
8334:
8335: =over 4
8336:
1.648 raeburn 8337: =item * &get_unprocessed_cgi($query,$possible_names)
1.112 bowersj2 8338:
1.258 albertel 8339: Modify the %env hash to contain unprocessed CGI form parameters held in
1.112 bowersj2 8340: $query. The parameters listed in $possible_names (an array reference),
1.258 albertel 8341: will be set in $env{'form.name'} if they do not already exist.
1.112 bowersj2 8342:
8343: Typically called with $ENV{'QUERY_STRING'} as the first parameter.
8344: $possible_names is an ref to an array of form element names. As an example:
8345: get_unprocessed_cgi($ENV{'QUERY_STRING'},['uname','udom']);
1.258 albertel 8346: will result in $env{'form.uname'} and $env{'form.udom'} being set.
1.112 bowersj2 8347:
8348: =cut
1.1 albertel 8349:
1.6 albertel 8350: sub get_unprocessed_cgi {
1.25 albertel 8351: my ($query,$possible_names)= @_;
1.26 matthew 8352: # $Apache::lonxml::debug=1;
1.356 albertel 8353: foreach my $pair (split(/&/,$query)) {
8354: my ($name, $value) = split(/=/,$pair);
1.369 www 8355: $name = &unescape($name);
1.25 albertel 8356: if (!defined($possible_names) || (grep {$_ eq $name} @$possible_names)) {
8357: $value =~ tr/+/ /;
8358: $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
1.258 albertel 8359: unless (defined($env{'form.'.$name})) { &add_to_env('form.'.$name,$value) };
1.25 albertel 8360: }
1.16 harris41 8361: }
1.6 albertel 8362: }
8363:
1.112 bowersj2 8364: =pod
8365:
1.648 raeburn 8366: =item * &cacheheader()
1.112 bowersj2 8367:
8368: returns cache-controlling header code
8369:
8370: =cut
8371:
1.7 albertel 8372: sub cacheheader {
1.258 albertel 8373: unless ($env{'request.method'} eq 'GET') { return ''; }
1.216 albertel 8374: my $date=strftime("%a, %d %b %Y %H:%M:%S GMT",gmtime);
8375: my $output .='<meta HTTP-EQUIV="Expires" CONTENT="'.$date.'" />
1.7 albertel 8376: <meta HTTP-EQUIV="Cache-control" CONTENT="no-cache" />
8377: <meta HTTP-EQUIV="Pragma" CONTENT="no-cache" />';
1.216 albertel 8378: return $output;
1.7 albertel 8379: }
8380:
1.112 bowersj2 8381: =pod
8382:
1.648 raeburn 8383: =item * &no_cache($r)
1.112 bowersj2 8384:
8385: specifies header code to not have cache
8386:
8387: =cut
8388:
1.9 albertel 8389: sub no_cache {
1.216 albertel 8390: my ($r) = @_;
8391: if ($ENV{'REQUEST_METHOD'} ne 'GET' &&
1.258 albertel 8392: $env{'request.method'} ne 'GET') { return ''; }
1.216 albertel 8393: my $date=strftime("%a, %d %b %Y %H:%M:%S GMT",gmtime(time));
8394: $r->no_cache(1);
8395: $r->header_out("Expires" => $date);
8396: $r->header_out("Pragma" => "no-cache");
1.123 www 8397: }
8398:
8399: sub content_type {
1.181 albertel 8400: my ($r,$type,$charset) = @_;
1.299 foxr 8401: if ($r) {
8402: # Note that printout.pl calls this with undef for $r.
8403: &no_cache($r);
8404: }
1.258 albertel 8405: if ($env{'browser.mathml'} && $type eq 'text/html') { $type='text/xml'; }
1.181 albertel 8406: unless ($charset) {
8407: $charset=&Apache::lonlocal::current_encoding;
8408: }
8409: if ($charset) { $type.='; charset='.$charset; }
8410: if ($r) {
8411: $r->content_type($type);
8412: } else {
8413: print("Content-type: $type\n\n");
8414: }
1.9 albertel 8415: }
1.25 albertel 8416:
1.112 bowersj2 8417: =pod
8418:
1.648 raeburn 8419: =item * &add_to_env($name,$value)
1.112 bowersj2 8420:
1.258 albertel 8421: adds $name to the %env hash with value
1.112 bowersj2 8422: $value, if $name already exists, the entry is converted to an array
8423: reference and $value is added to the array.
8424:
8425: =cut
8426:
1.25 albertel 8427: sub add_to_env {
8428: my ($name,$value)=@_;
1.258 albertel 8429: if (defined($env{$name})) {
8430: if (ref($env{$name})) {
1.25 albertel 8431: #already have multiple values
1.258 albertel 8432: push(@{ $env{$name} },$value);
1.25 albertel 8433: } else {
8434: #first time seeing multiple values, convert hash entry to an arrayref
1.258 albertel 8435: my $first=$env{$name};
8436: undef($env{$name});
8437: push(@{ $env{$name} },$first,$value);
1.25 albertel 8438: }
8439: } else {
1.258 albertel 8440: $env{$name}=$value;
1.25 albertel 8441: }
1.31 albertel 8442: }
1.149 albertel 8443:
8444: =pod
8445:
1.648 raeburn 8446: =item * &get_env_multiple($name)
1.149 albertel 8447:
1.258 albertel 8448: gets $name from the %env hash, it seemlessly handles the cases where multiple
1.149 albertel 8449: values may be defined and end up as an array ref.
8450:
8451: returns an array of values
8452:
8453: =cut
8454:
8455: sub get_env_multiple {
8456: my ($name) = @_;
8457: my @values;
1.258 albertel 8458: if (defined($env{$name})) {
1.149 albertel 8459: # exists is it an array
1.258 albertel 8460: if (ref($env{$name})) {
8461: @values=@{ $env{$name} };
1.149 albertel 8462: } else {
1.258 albertel 8463: $values[0]=$env{$name};
1.149 albertel 8464: }
8465: }
8466: return(@values);
8467: }
8468:
1.660 raeburn 8469: sub ask_for_embedded_content {
8470: my ($actionurl,$state,$allfiles,$codebase,$args)=@_;
1.948.2.12 raeburn 8471: my (%subdependencies,%dependencies,%newfiles);
1.660 raeburn 8472: my $num = 0;
1.948.2.12 raeburn 8473: my $upload_output;
8474: foreach my $embed_file (keys(%{$allfiles})) {
8475: unless ($embed_file =~ m{^\w+://} || $embed_file =~ m{^/}) {
8476: my ($relpath,$fname);
8477: if ($embed_file =~ m{/}) {
8478: my ($path,$fname) = ($embed_file =~ m{^(.+)/([^/]*)$});
8479: $subdependencies{$path}{$fname} = 1;
8480: } else {
8481: $dependencies{$embed_file} = 1;
8482: }
8483: }
8484: }
8485: my ($url,$udom,$uname,$getpropath);
8486: if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) {
8487: my $current_path='/';
8488: if ($env{'form.currentpath'}) {
8489: $current_path = $env{'form.currentpath'};
8490: }
8491: if ($actionurl eq '/adm/coursegrp_portfolio') {
8492: $udom = $env{'course.'.$env{'request.course.id'}.'.domain'};
8493: $uname = $env{'course.'.$env{'request.course.id'}.'.num'};
8494: $url = '/userfiles/groups/'.$env{'form.group'}.'/portfolio';
8495: } else {
8496: $udom = $env{'user.domain'};
8497: $uname = $env{'user.name'};
8498: $url = '/userfiles/portfolio';
8499: }
8500: $url .= $current_path;
8501: $getpropath = 1;
8502: } elsif ($actionurl eq '/adm/upload') {
8503: ($uname,my $rest) = ($args->{'current_path'} =~ m{/priv/($match_username)/?(.*)$});
8504: $url = '/home/'.$uname.'/public_html';
8505: if ($rest ne '') {
8506: $url .= '/'.$rest;
8507: }
8508: }
8509: foreach my $path (keys(%subdependencies)) {
8510: my %currsubfile;
8511: if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) {
8512: my @subdir_list = &Apache::lonnet::dirlist($url.$path,$udom,$uname,$getpropath);
8513: foreach my $line (@subdir_list) {
8514: my ($file_name,$rest) = split(/\&/,$line,2);
8515: $currsubfile{$file_name} = 1;
8516: }
8517: } elsif ($actionurl eq '/adm/upload') {
8518: if (opendir(my $dir,$url.'/'.$path)) {
8519: my @subdir_list = grep(!/^\./,readdir($dir));
8520: map {$currsubfile{$_} = 1;} @subdir_list;
8521: }
8522: }
8523: foreach my $file (keys(%{$subdependencies{$path}})) {
8524: unless ($currsubfile{$file}) {
8525: $newfiles{$path.'/'.$file} = 1;
8526: }
8527: }
8528: }
8529: my (@dir_list,%currfile);
8530: if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) {
8531: my @dir_list = &Apache::lonnet::dirlist($url,$udom,$uname,$getpropath);
8532: foreach my $line (@dir_list) {
8533: my ($file_name,$rest) = split(/\&/,$line,2);
8534: $currfile{$file_name} = 1;
8535: }
8536: } elsif ($actionurl eq '/adm/upload') {
8537: if (opendir(my $dir,$url)) {
8538: @dir_list = grep(!/^\./,readdir($dir));
8539: map {$currfile{$_} = 1;} @dir_list;
8540: }
8541: }
8542: foreach my $file (keys(%dependencies)) {
8543: unless ($currfile{$file}) {
8544: $newfiles{$file} = 1;
8545: }
8546: }
8547: foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%newfiles)) {
1.660 raeburn 8548: $upload_output .= &start_data_table_row().
8549: '<td>'.$embed_file.'</td><td>';
8550: if ($args->{'ignore_remote_references'}
8551: && $embed_file =~ m{^\w+://}) {
8552: $upload_output.='<span class="LC_warning">'.&mt("URL points to other server.").'</span>';
8553: } elsif ($args->{'error_on_invalid_names'}
8554: && $embed_file ne &Apache::lonnet::clean_filename($embed_file,{'keep_path' => 1,})) {
8555:
8556: $upload_output.='<span class="LC_warning">'.&mt("Invalid characters").'</span>';
8557:
8558: } else {
8559: $upload_output .='
1.661 raeburn 8560: <input name="embedded_item_'.$num.'" type="file" value="" />
1.660 raeburn 8561: <input name="embedded_orig_'.$num.'" type="hidden" value="'.&escape($embed_file).'" />';
8562: my $attrib = join(':',@{$$allfiles{$embed_file}});
8563: $upload_output .=
8564: "\n\t\t".
8565: '<input name="embedded_attrib_'.$num.'" type="hidden" value="'.
8566: $attrib.'" />';
8567: if (exists($$codebase{$embed_file})) {
8568: $upload_output .=
8569: "\n\t\t".
8570: '<input name="codebase_'.$num.'" type="hidden" value="'.
8571: &escape($$codebase{$embed_file}).'" />';
8572: }
8573: }
1.948.2.12 raeburn 8574: $upload_output .= '</td>'.&Apache::loncommon::end_data_table_row()."\n";
1.660 raeburn 8575: $num++;
8576: }
1.948.2.12 raeburn 8577: if ($num) {
8578: $upload_output = '<form name="upload_embedded" action="'.$actionurl.'"'.
8579: ' method="post" enctype="multipart/form-data">'."\n".
8580: $state.
8581: '<b>Upload embedded files</b>:<br />'.&start_data_table().
8582: $upload_output.
8583: &Apache::loncommon::end_data_table().'<br />'."\n".
8584: '<input type ="hidden" name="number_embedded_items" value="'.$num.'" />'."\n".
8585: '<input type ="submit" value="'.&mt('Upload Listed Files').'" />'."\n".
8586: &mt('(only files for which a location has been provided will be uploaded)')."\n".
8587: '</form>';
8588: }
1.660 raeburn 8589: return $upload_output;
8590: }
8591:
1.661 raeburn 8592: sub upload_embedded {
8593: my ($context,$dirpath,$uname,$udom,$dir_root,$url_root,$group,$disk_quota,
8594: $current_disk_usage) = @_;
8595: my $output;
8596: for (my $i=0; $i<$env{'form.number_embedded_items'}; $i++) {
8597: next if (!exists($env{'form.embedded_item_'.$i.'.filename'}));
8598: my $orig_uploaded_filename =
8599: $env{'form.embedded_item_'.$i.'.filename'};
8600:
8601: $env{'form.embedded_orig_'.$i} =
8602: &unescape($env{'form.embedded_orig_'.$i});
8603: my ($path,$fname) =
8604: ($env{'form.embedded_orig_'.$i} =~ m{(.*/)([^/]*)});
8605: # no path, whole string is fname
8606: if (!$fname) { $fname = $env{'form.embedded_orig_'.$i} };
8607:
8608: $path = $env{'form.currentpath'}.$path;
8609: $fname = &Apache::lonnet::clean_filename($fname);
8610: # See if there is anything left
8611: next if ($fname eq '');
8612:
8613: # Check if file already exists as a file or directory.
8614: my ($state,$msg);
8615: if ($context eq 'portfolio') {
8616: my $port_path = $dirpath;
8617: if ($group ne '') {
8618: $port_path = "groups/$group/$port_path";
8619: }
8620: ($state,$msg) = &check_for_upload($path,$fname,$group,'embedded_item_'.$i,
8621: $dir_root,$port_path,$disk_quota,
8622: $current_disk_usage,$uname,$udom);
8623: if ($state eq 'will_exceed_quota'
1.948.2.12 raeburn 8624: || $state eq 'file_locked') {
1.661 raeburn 8625: $output .= $msg;
8626: next;
8627: }
8628: } elsif (($context eq 'author') || ($context eq 'testbank')) {
8629: ($state,$msg) = &check_for_existing($path,$fname,'embedded_item_'.$i);
8630: if ($state eq 'exists') {
8631: $output .= $msg;
8632: next;
8633: }
8634: }
8635: # Check if extension is valid
8636: if (($fname =~ /\.(\w+)$/) &&
8637: (&Apache::loncommon::fileembstyle($1) eq 'hdn')) {
8638: $output .= &mt('Invalid file extension ([_1]) - reserved for LONCAPA use - rename the file with a different extension and re-upload. ',$1);
8639: next;
8640: } elsif (($fname =~ /\.(\w+)$/) &&
8641: (!defined(&Apache::loncommon::fileembstyle($1)))) {
8642: $output .= &mt('Unrecognized file extension ([_1]) - rename the file with a proper extension and re-upload.',$1);
8643: next;
8644: } elsif ($fname=~/\.(\d+)\.(\w+)$/) {
8645: $output .= &mt('File name not allowed - rename the file to remove the number immediately before the file extension([_1]) and re-upload.',$2);
8646: next;
8647: }
8648:
8649: $env{'form.embedded_item_'.$i.'.filename'}=$fname;
8650: if ($context eq 'portfolio') {
1.948.2.12 raeburn 8651: my $result;
8652: if ($state eq 'existingfile') {
8653: $result=
8654: &Apache::lonnet::userfileupload('embedded_item_'.$i,'existingfile',
8655: $dirpath.$path,);
1.661 raeburn 8656: } else {
1.948.2.12 raeburn 8657: $result=
8658: &Apache::lonnet::userfileupload('embedded_item_'.$i,'',
8659: $dirpath.$path);
8660: if ($result !~ m|^/uploaded/|) {
8661: $output .= '<span class="LC_error">'
8662: .&mt('An error occurred ([_1]) while trying to upload [_2] for embedded element [_3].'
8663: ,$result,$orig_uploaded_filename,$env{'form.embedded_orig_'.$i})
8664: .'</span><br />';
8665: next;
8666: } else {
8667: $output .= '<p>'.&mt('Uploaded [_1]','<span class="LC_filename">'.
8668: $path.$fname.'</span>').'</p>';
8669: }
1.661 raeburn 8670: }
8671: } else {
8672: # Save the file
8673: my $target = $env{'form.embedded_item_'.$i};
8674: my $fullpath = $dir_root.$dirpath.'/'.$path;
8675: my $dest = $fullpath.$fname;
8676: my $url = $url_root.$dirpath.'/'.$path.$fname;
8677: my @parts=split(/\//,$fullpath);
8678: my $count;
8679: my $filepath = $dir_root;
8680: for ($count=4;$count<=$#parts;$count++) {
8681: $filepath .= "/$parts[$count]";
8682: if ((-e $filepath)!=1) {
8683: mkdir($filepath,0770);
8684: }
8685: }
8686: my $fh;
8687: if (!open($fh,'>'.$dest)) {
8688: &Apache::lonnet::logthis('Failed to create '.$dest);
8689: $output .= '<span class="LC_error">'.
8690: &mt('An error occurred while trying to upload [_1] for embedded element [_2].',$orig_uploaded_filename,$env{'form.embedded_orig_'.$i}).
8691: '</span><br />';
8692: } else {
8693: if (!print $fh $env{'form.embedded_item_'.$i}) {
8694: &Apache::lonnet::logthis('Failed to write to '.$dest);
8695: $output .= '<span class="LC_error">'.
8696: &mt('An error occurred while writing the file [_1] for embedded element [_2].',$orig_uploaded_filename,$env{'form.embedded_orig_'.$i}).
8697: '</span><br />';
8698: } else {
8699: if ($context eq 'testbank') {
8700: $output .= &mt('Embedded file uploaded successfully:').
8701: ' <a href="'.$url.'">'.
8702: $orig_uploaded_filename.'</a><br />';
8703: } else {
1.705 tempelho 8704: $output .= '<span class=\"LC_fontsize_large\">'.
1.661 raeburn 8705: &mt('View embedded file: [_1]','<a href="'.$url.'">'.
1.705 tempelho 8706: $orig_uploaded_filename.'</a>').'</span><br />';
1.661 raeburn 8707: }
8708: }
8709: close($fh);
8710: }
8711: }
8712: }
8713: return $output;
8714: }
8715:
8716: sub check_for_existing {
8717: my ($path,$fname,$element) = @_;
8718: my ($state,$msg);
8719: if (-d $path.'/'.$fname) {
8720: $state = 'exists';
8721: $msg = &mt('Unable to upload [_1]. A directory by that name was found in [_2].','<span class="LC_filename">'.$fname.'</span>',$path);
8722: } elsif (-e $path.'/'.$fname) {
8723: $state = 'exists';
8724: $msg = &mt('Unable to upload [_1]. A file by that name was found in [_2].','<span class="LC_filename">'.$fname.'</span>',$path);
8725: }
8726: if ($state eq 'exists') {
8727: $msg = '<span class="LC_error">'.$msg.'</span><br />';
8728: }
8729: return ($state,$msg);
8730: }
8731:
8732: sub check_for_upload {
8733: my ($path,$fname,$group,$element,$portfolio_root,$port_path,
8734: $disk_quota,$current_disk_usage,$uname,$udom) = @_;
1.948.2.12 raeburn 8735: my $filesize = length($env{'form.'.$element});
8736: if (!$filesize) {
8737: my $msg = '<span class="LC_error">'.
8738: &mt('Unable to upload [_1]. (size = [_2] bytes)',
8739: '<span class="LC_filename">'.$fname.'</span>',
8740: $filesize).'<br />'.
8741: &mt('Either the file you uploaded was empty, or your web browser was unable to read its contents.').'<br />';
8742: '</span>';
8743: return ('zero_bytes',$msg);
8744: }
8745: $filesize = $filesize/1000; #express in k (1024?)
1.661 raeburn 8746: my $getpropath = 1;
8747: my @dir_list = &Apache::lonnet::dirlist($portfolio_root.$path,$udom,$uname,
8748: $getpropath);
8749: my $found_file = 0;
8750: my $locked_file = 0;
8751: foreach my $line (@dir_list) {
1.948.2.12 raeburn 8752: my ($file_name,$rest)=split(/\&/,$line,2);
1.661 raeburn 8753: if ($file_name eq $fname){
8754: $file_name = $path.$file_name;
8755: if ($group ne '') {
8756: $file_name = $group.$file_name;
8757: }
8758: $found_file = 1;
8759: if (&Apache::lonnet::is_locked($file_name,$udom,$uname) eq 'true') {
8760: $locked_file = 1;
1.948.2.12 raeburn 8761: } else {
8762: my @info = split(/\&/,$rest);
8763: my $currsize = $info[6]/1000;
8764: if ($currsize < $filesize) {
8765: my $extra = $filesize - $currsize;
8766: if (($current_disk_usage + $extra) > $disk_quota) {
8767: my $msg = '<span class="LC_error">'.
8768: &mt('Unable to upload [_1]. (size = [_2] kilobytes). Disk quota will be exceeded if existing (smaller) file with same name (size = [_3] kilobytes) is replaced.',
8769: '<span class="LC_filename">'.$fname.'</span>',$filesize,$currsize).'</span>'.
8770: '<br />'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.',
8771: $disk_quota,$current_disk_usage);
8772: return ('will_exceed_quota',$msg);
8773: }
8774: }
1.661 raeburn 8775: }
8776: }
8777: }
8778: if (($current_disk_usage + $filesize) > $disk_quota){
8779: my $msg = '<span class="LC_error">'.
8780: &mt('Unable to upload [_1]. (size = [_2] kilobytes). Disk quota will be exceeded.','<span class="LC_filename">'.$fname.'</span>',$filesize).'</span>'.
8781: '<br />'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.',$disk_quota,$current_disk_usage);
8782: return ('will_exceed_quota',$msg);
8783: } elsif ($found_file) {
8784: if ($locked_file) {
8785: my $msg = '<span class="LC_error">';
8786: $msg .= &mt('Unable to upload [_1]. A locked file by that name was found in [_2].','<span class="LC_filename">'.$fname.'</span>','<span class="LC_filename">'.$port_path.$env{'form.currentpath'}.'</span>');
8787: $msg .= '</span><br />';
8788: $msg .= &mt('You will be able to rename or delete existing [_1] after a grade has been assigned.','<span class="LC_filename">'.$fname.'</span>');
8789: return ('file_locked',$msg);
8790: } else {
8791: my $msg = '<span class="LC_error">';
1.948.2.12 raeburn 8792: $msg .= &mt(' A file by that name: [_1] was found in [_2].','<span class="LC_filename">'.$fname.'</span>',$port_path.$env{'form.currentpath'});
1.661 raeburn 8793: $msg .= '</span>';
1.948.2.12 raeburn 8794: return ('existingfile',$msg);
1.661 raeburn 8795: }
8796: }
8797: }
8798:
1.31 albertel 8799:
1.41 ng 8800: =pod
1.45 matthew 8801:
1.464 albertel 8802: =back
1.41 ng 8803:
1.112 bowersj2 8804: =head1 CSV Upload/Handling functions
1.38 albertel 8805:
1.41 ng 8806: =over 4
8807:
1.648 raeburn 8808: =item * &upfile_store($r)
1.41 ng 8809:
8810: Store uploaded file, $r should be the HTTP Request object,
1.258 albertel 8811: needs $env{'form.upfile'}
1.41 ng 8812: returns $datatoken to be put into hidden field
8813:
8814: =cut
1.31 albertel 8815:
8816: sub upfile_store {
8817: my $r=shift;
1.258 albertel 8818: $env{'form.upfile'}=~s/\r/\n/gs;
8819: $env{'form.upfile'}=~s/\f/\n/gs;
8820: $env{'form.upfile'}=~s/\n+/\n/gs;
8821: $env{'form.upfile'}=~s/\n+$//gs;
1.31 albertel 8822:
1.258 albertel 8823: my $datatoken=$env{'user.name'}.'_'.$env{'user.domain'}.
8824: '_enroll_'.$env{'request.course.id'}.'_'.time.'_'.$$;
1.31 albertel 8825: {
1.158 raeburn 8826: my $datafile = $r->dir_config('lonDaemons').
8827: '/tmp/'.$datatoken.'.tmp';
8828: if ( open(my $fh,">$datafile") ) {
1.258 albertel 8829: print $fh $env{'form.upfile'};
1.158 raeburn 8830: close($fh);
8831: }
1.31 albertel 8832: }
8833: return $datatoken;
8834: }
8835:
1.56 matthew 8836: =pod
8837:
1.648 raeburn 8838: =item * &load_tmp_file($r)
1.41 ng 8839:
8840: Load uploaded file from tmp, $r should be the HTTP Request object,
1.258 albertel 8841: needs $env{'form.datatoken'},
8842: sets $env{'form.upfile'} to the contents of the file
1.41 ng 8843:
8844: =cut
1.31 albertel 8845:
8846: sub load_tmp_file {
8847: my $r=shift;
8848: my @studentdata=();
8849: {
1.158 raeburn 8850: my $studentfile = $r->dir_config('lonDaemons').
1.258 albertel 8851: '/tmp/'.$env{'form.datatoken'}.'.tmp';
1.158 raeburn 8852: if ( open(my $fh,"<$studentfile") ) {
8853: @studentdata=<$fh>;
8854: close($fh);
8855: }
1.31 albertel 8856: }
1.258 albertel 8857: $env{'form.upfile'}=join('',@studentdata);
1.31 albertel 8858: }
8859:
1.56 matthew 8860: =pod
8861:
1.648 raeburn 8862: =item * &upfile_record_sep()
1.41 ng 8863:
8864: Separate uploaded file into records
8865: returns array of records,
1.258 albertel 8866: needs $env{'form.upfile'} and $env{'form.upfiletype'}
1.41 ng 8867:
8868: =cut
1.31 albertel 8869:
8870: sub upfile_record_sep {
1.258 albertel 8871: if ($env{'form.upfiletype'} eq 'xml') {
1.31 albertel 8872: } else {
1.248 albertel 8873: my @records;
1.258 albertel 8874: foreach my $line (split(/\n/,$env{'form.upfile'})) {
1.248 albertel 8875: if ($line=~/^\s*$/) { next; }
8876: push(@records,$line);
8877: }
8878: return @records;
1.31 albertel 8879: }
8880: }
8881:
1.56 matthew 8882: =pod
8883:
1.648 raeburn 8884: =item * &record_sep($record)
1.41 ng 8885:
1.258 albertel 8886: Separate a record into fields $record should be an item from the upfile_record_sep(), needs $env{'form.upfiletype'}
1.41 ng 8887:
8888: =cut
8889:
1.263 www 8890: sub takeleft {
8891: my $index=shift;
8892: return substr('0000'.$index,-4,4);
8893: }
8894:
1.31 albertel 8895: sub record_sep {
8896: my $record=shift;
8897: my %components=();
1.258 albertel 8898: if ($env{'form.upfiletype'} eq 'xml') {
8899: } elsif ($env{'form.upfiletype'} eq 'space') {
1.31 albertel 8900: my $i=0;
1.356 albertel 8901: foreach my $field (split(/\s+/,$record)) {
1.31 albertel 8902: $field=~s/^(\"|\')//;
8903: $field=~s/(\"|\')$//;
1.263 www 8904: $components{&takeleft($i)}=$field;
1.31 albertel 8905: $i++;
8906: }
1.258 albertel 8907: } elsif ($env{'form.upfiletype'} eq 'tab') {
1.31 albertel 8908: my $i=0;
1.356 albertel 8909: foreach my $field (split(/\t/,$record)) {
1.31 albertel 8910: $field=~s/^(\"|\')//;
8911: $field=~s/(\"|\')$//;
1.263 www 8912: $components{&takeleft($i)}=$field;
1.31 albertel 8913: $i++;
8914: }
8915: } else {
1.561 www 8916: my $separator=',';
1.480 banghart 8917: if ($env{'form.upfiletype'} eq 'semisv') {
1.561 www 8918: $separator=';';
1.480 banghart 8919: }
1.31 albertel 8920: my $i=0;
1.561 www 8921: # the character we are looking for to indicate the end of a quote or a record
8922: my $looking_for=$separator;
8923: # do not add the characters to the fields
8924: my $ignore=0;
8925: # we just encountered a separator (or the beginning of the record)
8926: my $just_found_separator=1;
8927: # store the field we are working on here
8928: my $field='';
8929: # work our way through all characters in record
8930: foreach my $character ($record=~/(.)/g) {
8931: if ($character eq $looking_for) {
8932: if ($character ne $separator) {
8933: # Found the end of a quote, again looking for separator
8934: $looking_for=$separator;
8935: $ignore=1;
8936: } else {
8937: # Found a separator, store away what we got
8938: $components{&takeleft($i)}=$field;
8939: $i++;
8940: $just_found_separator=1;
8941: $ignore=0;
8942: $field='';
8943: }
8944: next;
8945: }
8946: # single or double quotation marks after a separator indicate beginning of a quote
8947: # we are now looking for the end of the quote and need to ignore separators
8948: if ((($character eq '"') || ($character eq "'")) && ($just_found_separator)) {
8949: $looking_for=$character;
8950: next;
8951: }
8952: # ignore would be true after we reached the end of a quote
8953: if ($ignore) { next; }
8954: if (($just_found_separator) && ($character=~/\s/)) { next; }
8955: $field.=$character;
8956: $just_found_separator=0;
1.31 albertel 8957: }
1.561 www 8958: # catch the very last entry, since we never encountered the separator
8959: $components{&takeleft($i)}=$field;
1.31 albertel 8960: }
8961: return %components;
8962: }
8963:
1.144 matthew 8964: ######################################################
8965: ######################################################
8966:
1.56 matthew 8967: =pod
8968:
1.648 raeburn 8969: =item * &upfile_select_html()
1.41 ng 8970:
1.144 matthew 8971: Return HTML code to select a file from the users machine and specify
8972: the file type.
1.41 ng 8973:
8974: =cut
8975:
1.144 matthew 8976: ######################################################
8977: ######################################################
1.31 albertel 8978: sub upfile_select_html {
1.144 matthew 8979: my %Types = (
8980: csv => &mt('CSV (comma separated values, spreadsheet)'),
1.480 banghart 8981: semisv => &mt('Semicolon separated values'),
1.144 matthew 8982: space => &mt('Space separated'),
8983: tab => &mt('Tabulator separated'),
8984: # xml => &mt('HTML/XML'),
8985: );
8986: my $Str = '<input type="file" name="upfile" size="50" />'.
1.727 riegler 8987: '<br />'.&mt('Type').': <select name="upfiletype">';
1.144 matthew 8988: foreach my $type (sort(keys(%Types))) {
8989: $Str .= '<option value="'.$type.'" >'.$Types{$type}."</option>\n";
8990: }
8991: $Str .= "</select>\n";
8992: return $Str;
1.31 albertel 8993: }
8994:
1.301 albertel 8995: sub get_samples {
8996: my ($records,$toget) = @_;
8997: my @samples=({});
8998: my $got=0;
8999: foreach my $rec (@$records) {
9000: my %temp = &record_sep($rec);
9001: if (! grep(/\S/, values(%temp))) { next; }
9002: if (%temp) {
9003: $samples[$got]=\%temp;
9004: $got++;
9005: if ($got == $toget) { last; }
9006: }
9007: }
9008: return \@samples;
9009: }
9010:
1.144 matthew 9011: ######################################################
9012: ######################################################
9013:
1.56 matthew 9014: =pod
9015:
1.648 raeburn 9016: =item * &csv_print_samples($r,$records)
1.41 ng 9017:
9018: Prints a table of sample values from each column uploaded $r is an
9019: Apache Request ref, $records is an arrayref from
9020: &Apache::loncommon::upfile_record_sep
9021:
9022: =cut
9023:
1.144 matthew 9024: ######################################################
9025: ######################################################
1.31 albertel 9026: sub csv_print_samples {
9027: my ($r,$records) = @_;
1.662 bisitz 9028: my $samples = &get_samples($records,5);
1.301 albertel 9029:
1.594 raeburn 9030: $r->print(&mt('Samples').'<br />'.&start_data_table().
9031: &start_data_table_header_row());
1.356 albertel 9032: foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) {
1.845 bisitz 9033: $r->print('<th>'.&mt('Column [_1]',($sample+1)).'</th>'); }
1.594 raeburn 9034: $r->print(&end_data_table_header_row());
1.301 albertel 9035: foreach my $hash (@$samples) {
1.594 raeburn 9036: $r->print(&start_data_table_row());
1.356 albertel 9037: foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) {
1.31 albertel 9038: $r->print('<td>');
1.356 albertel 9039: if (defined($$hash{$sample})) { $r->print($$hash{$sample}); }
1.31 albertel 9040: $r->print('</td>');
9041: }
1.594 raeburn 9042: $r->print(&end_data_table_row());
1.31 albertel 9043: }
1.594 raeburn 9044: $r->print(&end_data_table().'<br />'."\n");
1.31 albertel 9045: }
9046:
1.144 matthew 9047: ######################################################
9048: ######################################################
9049:
1.56 matthew 9050: =pod
9051:
1.648 raeburn 9052: =item * &csv_print_select_table($r,$records,$d)
1.41 ng 9053:
9054: Prints a table to create associations between values and table columns.
1.144 matthew 9055:
1.41 ng 9056: $r is an Apache Request ref,
9057: $records is an arrayref from &Apache::loncommon::upfile_record_sep,
1.174 matthew 9058: $d is an array of 2 element arrays (internal name, displayed name,defaultcol)
1.41 ng 9059:
9060: =cut
9061:
1.144 matthew 9062: ######################################################
9063: ######################################################
1.31 albertel 9064: sub csv_print_select_table {
9065: my ($r,$records,$d) = @_;
1.301 albertel 9066: my $i=0;
9067: my $samples = &get_samples($records,1);
1.144 matthew 9068: $r->print(&mt('Associate columns with student attributes.')."\n".
1.594 raeburn 9069: &start_data_table().&start_data_table_header_row().
1.144 matthew 9070: '<th>'.&mt('Attribute').'</th>'.
1.594 raeburn 9071: '<th>'.&mt('Column').'</th>'.
9072: &end_data_table_header_row()."\n");
1.356 albertel 9073: foreach my $array_ref (@$d) {
9074: my ($value,$display,$defaultcol)=@{ $array_ref };
1.729 raeburn 9075: $r->print(&start_data_table_row().'<td>'.$display.'</td>');
1.31 albertel 9076:
1.875 bisitz 9077: $r->print('<td><select name="f'.$i.'"'.
1.32 matthew 9078: ' onchange="javascript:flip(this.form,'.$i.');">');
1.31 albertel 9079: $r->print('<option value="none"></option>');
1.356 albertel 9080: foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) {
9081: $r->print('<option value="'.$sample.'"'.
9082: ($sample eq $defaultcol ? ' selected="selected" ' : '').
1.662 bisitz 9083: '>'.&mt('Column [_1]',($sample+1)).'</option>');
1.31 albertel 9084: }
1.594 raeburn 9085: $r->print('</select></td>'.&end_data_table_row()."\n");
1.31 albertel 9086: $i++;
9087: }
1.594 raeburn 9088: $r->print(&end_data_table());
1.31 albertel 9089: $i--;
9090: return $i;
9091: }
1.56 matthew 9092:
1.144 matthew 9093: ######################################################
9094: ######################################################
9095:
1.56 matthew 9096: =pod
1.31 albertel 9097:
1.648 raeburn 9098: =item * &csv_samples_select_table($r,$records,$d)
1.41 ng 9099:
9100: Prints a table of sample values from the upload and can make associate samples to internal names.
9101:
9102: $r is an Apache Request ref,
9103: $records is an arrayref from &Apache::loncommon::upfile_record_sep,
9104: $d is an array of 2 element arrays (internal name, displayed name)
9105:
9106: =cut
9107:
1.144 matthew 9108: ######################################################
9109: ######################################################
1.31 albertel 9110: sub csv_samples_select_table {
9111: my ($r,$records,$d) = @_;
9112: my $i=0;
1.144 matthew 9113: #
1.662 bisitz 9114: my $max_samples = 5;
9115: my $samples = &get_samples($records,$max_samples);
1.594 raeburn 9116: $r->print(&start_data_table().
9117: &start_data_table_header_row().'<th>'.
9118: &mt('Field').'</th><th>'.&mt('Samples').'</th>'.
9119: &end_data_table_header_row());
1.301 albertel 9120:
9121: foreach my $key (sort(keys(%{ $samples->[0] }))) {
1.594 raeburn 9122: $r->print(&start_data_table_row().'<td><select name="f'.$i.'"'.
1.32 matthew 9123: ' onchange="javascript:flip(this.form,'.$i.');">');
1.301 albertel 9124: foreach my $option (@$d) {
9125: my ($value,$display,$defaultcol)=@{ $option };
1.174 matthew 9126: $r->print('<option value="'.$value.'"'.
1.253 albertel 9127: ($i eq $defaultcol ? ' selected="selected" ':'').'>'.
1.174 matthew 9128: $display.'</option>');
1.31 albertel 9129: }
9130: $r->print('</select></td><td>');
1.662 bisitz 9131: foreach my $line (0..($max_samples-1)) {
1.301 albertel 9132: if (defined($samples->[$line]{$key})) {
9133: $r->print($samples->[$line]{$key}."<br />\n");
9134: }
9135: }
1.594 raeburn 9136: $r->print('</td>'.&end_data_table_row());
1.31 albertel 9137: $i++;
9138: }
1.594 raeburn 9139: $r->print(&end_data_table());
1.31 albertel 9140: $i--;
9141: return($i);
1.115 matthew 9142: }
9143:
1.144 matthew 9144: ######################################################
9145: ######################################################
9146:
1.115 matthew 9147: =pod
9148:
1.648 raeburn 9149: =item * &clean_excel_name($name)
1.115 matthew 9150:
9151: Returns a replacement for $name which does not contain any illegal characters.
9152:
9153: =cut
9154:
1.144 matthew 9155: ######################################################
9156: ######################################################
1.115 matthew 9157: sub clean_excel_name {
9158: my ($name) = @_;
9159: $name =~ s/[:\*\?\/\\]//g;
9160: if (length($name) > 31) {
9161: $name = substr($name,0,31);
9162: }
9163: return $name;
1.25 albertel 9164: }
1.84 albertel 9165:
1.85 albertel 9166: =pod
9167:
1.648 raeburn 9168: =item * &check_if_partid_hidden($id,$symb,$udom,$uname)
1.85 albertel 9169:
9170: Returns either 1 or undef
9171:
9172: 1 if the part is to be hidden, undef if it is to be shown
9173:
9174: Arguments are:
9175:
9176: $id the id of the part to be checked
9177: $symb, optional the symb of the resource to check
9178: $udom, optional the domain of the user to check for
9179: $uname, optional the username of the user to check for
9180:
9181: =cut
1.84 albertel 9182:
9183: sub check_if_partid_hidden {
9184: my ($id,$symb,$udom,$uname) = @_;
1.133 albertel 9185: my $hiddenparts=&Apache::lonnet::EXT('resource.0.hiddenparts',
1.84 albertel 9186: $symb,$udom,$uname);
1.141 albertel 9187: my $truth=1;
9188: #if the string starts with !, then the list is the list to show not hide
9189: if ($hiddenparts=~s/^\s*!//) { $truth=undef; }
1.84 albertel 9190: my @hiddenlist=split(/,/,$hiddenparts);
9191: foreach my $checkid (@hiddenlist) {
1.141 albertel 9192: if ($checkid =~ /^\s*\Q$id\E\s*$/) { return $truth; }
1.84 albertel 9193: }
1.141 albertel 9194: return !$truth;
1.84 albertel 9195: }
1.127 matthew 9196:
1.138 matthew 9197:
9198: ############################################################
9199: ############################################################
9200:
9201: =pod
9202:
1.157 matthew 9203: =back
9204:
1.138 matthew 9205: =head1 cgi-bin script and graphing routines
9206:
1.157 matthew 9207: =over 4
9208:
1.648 raeburn 9209: =item * &get_cgi_id()
1.138 matthew 9210:
9211: Inputs: none
9212:
9213: Returns an id which can be used to pass environment variables
9214: to various cgi-bin scripts. These environment variables will
9215: be removed from the users environment after a given time by
9216: the routine &Apache::lonnet::transfer_profile_to_env.
9217:
9218: =cut
9219:
9220: ############################################################
9221: ############################################################
1.152 albertel 9222: my $uniq=0;
1.136 matthew 9223: sub get_cgi_id {
1.154 albertel 9224: $uniq=($uniq+1)%100000;
1.280 albertel 9225: return (time.'_'.$$.'_'.$uniq);
1.136 matthew 9226: }
9227:
1.127 matthew 9228: ############################################################
9229: ############################################################
9230:
9231: =pod
9232:
1.648 raeburn 9233: =item * &DrawBarGraph()
1.127 matthew 9234:
1.138 matthew 9235: Facilitates the plotting of data in a (stacked) bar graph.
9236: Puts plot definition data into the users environment in order for
9237: graph.png to plot it. Returns an <img> tag for the plot.
9238: The bars on the plot are labeled '1','2',...,'n'.
9239:
9240: Inputs:
9241:
9242: =over 4
9243:
9244: =item $Title: string, the title of the plot
9245:
9246: =item $xlabel: string, text describing the X-axis of the plot
9247:
9248: =item $ylabel: string, text describing the Y-axis of the plot
9249:
9250: =item $Max: scalar, the maximum Y value to use in the plot
9251: If $Max is < any data point, the graph will not be rendered.
9252:
1.140 matthew 9253: =item $colors: array ref holding the colors to be used for the data sets when
1.138 matthew 9254: they are plotted. If undefined, default values will be used.
9255:
1.178 matthew 9256: =item $labels: array ref holding the labels to use on the x-axis for the bars.
9257:
1.138 matthew 9258: =item @Values: An array of array references. Each array reference holds data
9259: to be plotted in a stacked bar chart.
9260:
1.239 matthew 9261: =item If the final element of @Values is a hash reference the key/value
9262: pairs will be added to the graph definition.
9263:
1.138 matthew 9264: =back
9265:
9266: Returns:
9267:
9268: An <img> tag which references graph.png and the appropriate identifying
9269: information for the plot.
9270:
1.127 matthew 9271: =cut
9272:
9273: ############################################################
9274: ############################################################
1.134 matthew 9275: sub DrawBarGraph {
1.178 matthew 9276: my ($Title,$xlabel,$ylabel,$Max,$colors,$labels,@Values)=@_;
1.134 matthew 9277: #
9278: if (! defined($colors)) {
9279: $colors = ['#33ff00',
9280: '#0033cc', '#990000', '#aaaa66', '#663399', '#ff9933',
9281: '#66ccff', '#ff9999', '#cccc33', '#660000', '#33cc66',
9282: ];
9283: }
1.228 matthew 9284: my $extra_settings = {};
9285: if (ref($Values[-1]) eq 'HASH') {
9286: $extra_settings = pop(@Values);
9287: }
1.127 matthew 9288: #
1.136 matthew 9289: my $identifier = &get_cgi_id();
9290: my $id = 'cgi.'.$identifier;
1.129 matthew 9291: if (! @Values || ref($Values[0]) ne 'ARRAY') {
1.127 matthew 9292: return '';
9293: }
1.225 matthew 9294: #
9295: my @Labels;
9296: if (defined($labels)) {
9297: @Labels = @$labels;
9298: } else {
9299: for (my $i=0;$i<@{$Values[0]};$i++) {
9300: push (@Labels,$i+1);
9301: }
9302: }
9303: #
1.129 matthew 9304: my $NumBars = scalar(@{$Values[0]});
1.225 matthew 9305: if ($NumBars < scalar(@Labels)) { $NumBars = scalar(@Labels); }
1.129 matthew 9306: my %ValuesHash;
9307: my $NumSets=1;
9308: foreach my $array (@Values) {
9309: next if (! ref($array));
1.136 matthew 9310: $ValuesHash{$id.'.data.'.$NumSets++} =
1.132 matthew 9311: join(',',@$array);
1.129 matthew 9312: }
1.127 matthew 9313: #
1.136 matthew 9314: my ($height,$width,$xskip,$bar_width) = (200,120,1,15);
1.225 matthew 9315: if ($NumBars < 3) {
9316: $width = 120+$NumBars*32;
1.220 matthew 9317: $xskip = 1;
1.225 matthew 9318: $bar_width = 30;
9319: } elsif ($NumBars < 5) {
9320: $width = 120+$NumBars*20;
9321: $xskip = 1;
9322: $bar_width = 20;
1.220 matthew 9323: } elsif ($NumBars < 10) {
1.136 matthew 9324: $width = 120+$NumBars*15;
9325: $xskip = 1;
9326: $bar_width = 15;
9327: } elsif ($NumBars <= 25) {
9328: $width = 120+$NumBars*11;
9329: $xskip = 5;
9330: $bar_width = 8;
9331: } elsif ($NumBars <= 50) {
9332: $width = 120+$NumBars*8;
9333: $xskip = 5;
9334: $bar_width = 4;
9335: } else {
9336: $width = 120+$NumBars*8;
9337: $xskip = 5;
9338: $bar_width = 4;
9339: }
9340: #
1.137 matthew 9341: $Max = 1 if ($Max < 1);
9342: if ( int($Max) < $Max ) {
9343: $Max++;
9344: $Max = int($Max);
9345: }
1.127 matthew 9346: $Title = '' if (! defined($Title));
9347: $xlabel = '' if (! defined($xlabel));
9348: $ylabel = '' if (! defined($ylabel));
1.369 www 9349: $ValuesHash{$id.'.title'} = &escape($Title);
9350: $ValuesHash{$id.'.xlabel'} = &escape($xlabel);
9351: $ValuesHash{$id.'.ylabel'} = &escape($ylabel);
1.137 matthew 9352: $ValuesHash{$id.'.y_max_value'} = $Max;
1.136 matthew 9353: $ValuesHash{$id.'.NumBars'} = $NumBars;
9354: $ValuesHash{$id.'.NumSets'} = $NumSets;
9355: $ValuesHash{$id.'.PlotType'} = 'bar';
9356: $ValuesHash{$id.'.Colors'} = join(',',@{$colors});
9357: $ValuesHash{$id.'.height'} = $height;
9358: $ValuesHash{$id.'.width'} = $width;
9359: $ValuesHash{$id.'.xskip'} = $xskip;
9360: $ValuesHash{$id.'.bar_width'} = $bar_width;
9361: $ValuesHash{$id.'.labels'} = join(',',@Labels);
1.127 matthew 9362: #
1.228 matthew 9363: # Deal with other parameters
9364: while (my ($key,$value) = each(%$extra_settings)) {
9365: $ValuesHash{$id.'.'.$key} = $value;
9366: }
9367: #
1.646 raeburn 9368: &Apache::lonnet::appenv(\%ValuesHash);
1.137 matthew 9369: return '<img src="/cgi-bin/graph.png?'.$identifier.'" border="1" />';
9370: }
9371:
9372: ############################################################
9373: ############################################################
9374:
9375: =pod
9376:
1.648 raeburn 9377: =item * &DrawXYGraph()
1.137 matthew 9378:
1.138 matthew 9379: Facilitates the plotting of data in an XY graph.
9380: Puts plot definition data into the users environment in order for
9381: graph.png to plot it. Returns an <img> tag for the plot.
9382:
9383: Inputs:
9384:
9385: =over 4
9386:
9387: =item $Title: string, the title of the plot
9388:
9389: =item $xlabel: string, text describing the X-axis of the plot
9390:
9391: =item $ylabel: string, text describing the Y-axis of the plot
9392:
9393: =item $Max: scalar, the maximum Y value to use in the plot
9394: If $Max is < any data point, the graph will not be rendered.
9395:
9396: =item $colors: Array ref containing the hex color codes for the data to be
9397: plotted in. If undefined, default values will be used.
9398:
9399: =item $Xlabels: Array ref containing the labels to be used for the X-axis.
9400:
9401: =item $Ydata: Array ref containing Array refs.
1.185 www 9402: Each of the contained arrays will be plotted as a separate curve.
1.138 matthew 9403:
9404: =item %Values: hash indicating or overriding any default values which are
9405: passed to graph.png.
9406: Possible values are: width, xskip, x_ticks, x_tick_offset, among others.
9407:
9408: =back
9409:
9410: Returns:
9411:
9412: An <img> tag which references graph.png and the appropriate identifying
9413: information for the plot.
9414:
1.137 matthew 9415: =cut
9416:
9417: ############################################################
9418: ############################################################
9419: sub DrawXYGraph {
9420: my ($Title,$xlabel,$ylabel,$Max,$colors,$Xlabels,$Ydata,%Values)=@_;
9421: #
9422: # Create the identifier for the graph
9423: my $identifier = &get_cgi_id();
9424: my $id = 'cgi.'.$identifier;
9425: #
9426: $Title = '' if (! defined($Title));
9427: $xlabel = '' if (! defined($xlabel));
9428: $ylabel = '' if (! defined($ylabel));
9429: my %ValuesHash =
9430: (
1.369 www 9431: $id.'.title' => &escape($Title),
9432: $id.'.xlabel' => &escape($xlabel),
9433: $id.'.ylabel' => &escape($ylabel),
1.137 matthew 9434: $id.'.y_max_value'=> $Max,
9435: $id.'.labels' => join(',',@$Xlabels),
9436: $id.'.PlotType' => 'XY',
9437: );
9438: #
9439: if (defined($colors) && ref($colors) eq 'ARRAY') {
9440: $ValuesHash{$id.'.Colors'} = join(',',@{$colors});
9441: }
9442: #
9443: if (! ref($Ydata) || ref($Ydata) ne 'ARRAY') {
9444: return '';
9445: }
9446: my $NumSets=1;
1.138 matthew 9447: foreach my $array (@{$Ydata}){
1.137 matthew 9448: next if (! ref($array));
9449: $ValuesHash{$id.'.data.'.$NumSets++} = join(',',@$array);
9450: }
1.138 matthew 9451: $ValuesHash{$id.'.NumSets'} = $NumSets-1;
1.137 matthew 9452: #
9453: # Deal with other parameters
9454: while (my ($key,$value) = each(%Values)) {
9455: $ValuesHash{$id.'.'.$key} = $value;
1.127 matthew 9456: }
9457: #
1.646 raeburn 9458: &Apache::lonnet::appenv(\%ValuesHash);
1.136 matthew 9459: return '<img src="/cgi-bin/graph.png?'.$identifier.'" border="1" />';
9460: }
9461:
9462: ############################################################
9463: ############################################################
9464:
9465: =pod
9466:
1.648 raeburn 9467: =item * &DrawXYYGraph()
1.138 matthew 9468:
9469: Facilitates the plotting of data in an XY graph with two Y axes.
9470: Puts plot definition data into the users environment in order for
9471: graph.png to plot it. Returns an <img> tag for the plot.
9472:
9473: Inputs:
9474:
9475: =over 4
9476:
9477: =item $Title: string, the title of the plot
9478:
9479: =item $xlabel: string, text describing the X-axis of the plot
9480:
9481: =item $ylabel: string, text describing the Y-axis of the plot
9482:
9483: =item $colors: Array ref containing the hex color codes for the data to be
9484: plotted in. If undefined, default values will be used.
9485:
9486: =item $Xlabels: Array ref containing the labels to be used for the X-axis.
9487:
9488: =item $Ydata1: The first data set
9489:
9490: =item $Min1: The minimum value of the left Y-axis
9491:
9492: =item $Max1: The maximum value of the left Y-axis
9493:
9494: =item $Ydata2: The second data set
9495:
9496: =item $Min2: The minimum value of the right Y-axis
9497:
9498: =item $Max2: The maximum value of the left Y-axis
9499:
9500: =item %Values: hash indicating or overriding any default values which are
9501: passed to graph.png.
9502: Possible values are: width, xskip, x_ticks, x_tick_offset, among others.
9503:
9504: =back
9505:
9506: Returns:
9507:
9508: An <img> tag which references graph.png and the appropriate identifying
9509: information for the plot.
1.136 matthew 9510:
9511: =cut
9512:
9513: ############################################################
9514: ############################################################
1.137 matthew 9515: sub DrawXYYGraph {
9516: my ($Title,$xlabel,$ylabel,$colors,$Xlabels,$Ydata1,$Min1,$Max1,
9517: $Ydata2,$Min2,$Max2,%Values)=@_;
1.136 matthew 9518: #
9519: # Create the identifier for the graph
9520: my $identifier = &get_cgi_id();
9521: my $id = 'cgi.'.$identifier;
9522: #
9523: $Title = '' if (! defined($Title));
9524: $xlabel = '' if (! defined($xlabel));
9525: $ylabel = '' if (! defined($ylabel));
9526: my %ValuesHash =
9527: (
1.369 www 9528: $id.'.title' => &escape($Title),
9529: $id.'.xlabel' => &escape($xlabel),
9530: $id.'.ylabel' => &escape($ylabel),
1.136 matthew 9531: $id.'.labels' => join(',',@$Xlabels),
9532: $id.'.PlotType' => 'XY',
9533: $id.'.NumSets' => 2,
1.137 matthew 9534: $id.'.two_axes' => 1,
9535: $id.'.y1_max_value' => $Max1,
9536: $id.'.y1_min_value' => $Min1,
9537: $id.'.y2_max_value' => $Max2,
9538: $id.'.y2_min_value' => $Min2,
1.136 matthew 9539: );
9540: #
1.137 matthew 9541: if (defined($colors) && ref($colors) eq 'ARRAY') {
9542: $ValuesHash{$id.'.Colors'} = join(',',@{$colors});
9543: }
9544: #
9545: if (! ref($Ydata1) || ref($Ydata1) ne 'ARRAY' ||
9546: ! ref($Ydata2) || ref($Ydata2) ne 'ARRAY'){
1.136 matthew 9547: return '';
9548: }
9549: my $NumSets=1;
1.137 matthew 9550: foreach my $array ($Ydata1,$Ydata2){
1.136 matthew 9551: next if (! ref($array));
9552: $ValuesHash{$id.'.data.'.$NumSets++} = join(',',@$array);
1.137 matthew 9553: }
9554: #
9555: # Deal with other parameters
9556: while (my ($key,$value) = each(%Values)) {
9557: $ValuesHash{$id.'.'.$key} = $value;
1.136 matthew 9558: }
9559: #
1.646 raeburn 9560: &Apache::lonnet::appenv(\%ValuesHash);
1.130 albertel 9561: return '<img src="/cgi-bin/graph.png?'.$identifier.'" border="1" />';
1.139 matthew 9562: }
9563:
9564: ############################################################
9565: ############################################################
9566:
9567: =pod
9568:
1.157 matthew 9569: =back
9570:
1.139 matthew 9571: =head1 Statistics helper routines?
9572:
9573: Bad place for them but what the hell.
9574:
1.157 matthew 9575: =over 4
9576:
1.648 raeburn 9577: =item * &chartlink()
1.139 matthew 9578:
9579: Returns a link to the chart for a specific student.
9580:
9581: Inputs:
9582:
9583: =over 4
9584:
9585: =item $linktext: The text of the link
9586:
9587: =item $sname: The students username
9588:
9589: =item $sdomain: The students domain
9590:
9591: =back
9592:
1.157 matthew 9593: =back
9594:
1.139 matthew 9595: =cut
9596:
9597: ############################################################
9598: ############################################################
9599: sub chartlink {
9600: my ($linktext, $sname, $sdomain) = @_;
9601: my $link = '<a href="/adm/statistics?reportSelected=student_assessment'.
1.369 www 9602: '&SelectedStudent='.&escape($sname.':'.$sdomain).
1.219 albertel 9603: '&chartoutputmode='.HTML::Entities::encode('html, with all links').
1.139 matthew 9604: '">'.$linktext.'</a>';
1.153 matthew 9605: }
9606:
9607: #######################################################
9608: #######################################################
9609:
9610: =pod
9611:
9612: =head1 Course Environment Routines
1.157 matthew 9613:
9614: =over 4
1.153 matthew 9615:
1.648 raeburn 9616: =item * &restore_course_settings()
1.153 matthew 9617:
1.648 raeburn 9618: =item * &store_course_settings()
1.153 matthew 9619:
9620: Restores/Store indicated form parameters from the course environment.
9621: Will not overwrite existing values of the form parameters.
9622:
9623: Inputs:
9624: a scalar describing the data (e.g. 'chart', 'problem_analysis')
9625:
9626: a hash ref describing the data to be stored. For example:
9627:
9628: %Save_Parameters = ('Status' => 'scalar',
9629: 'chartoutputmode' => 'scalar',
9630: 'chartoutputdata' => 'scalar',
9631: 'Section' => 'array',
1.373 raeburn 9632: 'Group' => 'array',
1.153 matthew 9633: 'StudentData' => 'array',
9634: 'Maps' => 'array');
9635:
9636: Returns: both routines return nothing
9637:
1.631 raeburn 9638: =back
9639:
1.153 matthew 9640: =cut
9641:
9642: #######################################################
9643: #######################################################
9644: sub store_course_settings {
1.496 albertel 9645: return &store_settings($env{'request.course.id'},@_);
9646: }
9647:
9648: sub store_settings {
1.153 matthew 9649: # save to the environment
9650: # appenv the same items, just to be safe
1.300 albertel 9651: my $udom = $env{'user.domain'};
9652: my $uname = $env{'user.name'};
1.496 albertel 9653: my ($context,$prefix,$Settings) = @_;
1.153 matthew 9654: my %SaveHash;
9655: my %AppHash;
9656: while (my ($setting,$type) = each(%$Settings)) {
1.496 albertel 9657: my $basename = join('.','internal',$context,$prefix,$setting);
1.300 albertel 9658: my $envname = 'environment.'.$basename;
1.258 albertel 9659: if (exists($env{'form.'.$setting})) {
1.153 matthew 9660: # Save this value away
9661: if ($type eq 'scalar' &&
1.258 albertel 9662: (! exists($env{$envname}) ||
9663: $env{$envname} ne $env{'form.'.$setting})) {
9664: $SaveHash{$basename} = $env{'form.'.$setting};
9665: $AppHash{$envname} = $env{'form.'.$setting};
1.153 matthew 9666: } elsif ($type eq 'array') {
9667: my $stored_form;
1.258 albertel 9668: if (ref($env{'form.'.$setting})) {
1.153 matthew 9669: $stored_form = join(',',
9670: map {
1.369 www 9671: &escape($_);
1.258 albertel 9672: } sort(@{$env{'form.'.$setting}}));
1.153 matthew 9673: } else {
9674: $stored_form =
1.369 www 9675: &escape($env{'form.'.$setting});
1.153 matthew 9676: }
9677: # Determine if the array contents are the same.
1.258 albertel 9678: if ($stored_form ne $env{$envname}) {
1.153 matthew 9679: $SaveHash{$basename} = $stored_form;
9680: $AppHash{$envname} = $stored_form;
9681: }
9682: }
9683: }
9684: }
9685: my $put_result = &Apache::lonnet::put('environment',\%SaveHash,
1.300 albertel 9686: $udom,$uname);
1.153 matthew 9687: if ($put_result !~ /^(ok|delayed)/) {
9688: &Apache::lonnet::logthis('unable to save form parameters, '.
9689: 'got error:'.$put_result);
9690: }
9691: # Make sure these settings stick around in this session, too
1.646 raeburn 9692: &Apache::lonnet::appenv(\%AppHash);
1.153 matthew 9693: return;
9694: }
9695:
9696: sub restore_course_settings {
1.499 albertel 9697: return &restore_settings($env{'request.course.id'},@_);
1.496 albertel 9698: }
9699:
9700: sub restore_settings {
9701: my ($context,$prefix,$Settings) = @_;
1.153 matthew 9702: while (my ($setting,$type) = each(%$Settings)) {
1.258 albertel 9703: next if (exists($env{'form.'.$setting}));
1.496 albertel 9704: my $envname = 'environment.internal.'.$context.'.'.$prefix.
1.153 matthew 9705: '.'.$setting;
1.258 albertel 9706: if (exists($env{$envname})) {
1.153 matthew 9707: if ($type eq 'scalar') {
1.258 albertel 9708: $env{'form.'.$setting} = $env{$envname};
1.153 matthew 9709: } elsif ($type eq 'array') {
1.258 albertel 9710: $env{'form.'.$setting} = [
1.153 matthew 9711: map {
1.369 www 9712: &unescape($_);
1.258 albertel 9713: } split(',',$env{$envname})
1.153 matthew 9714: ];
9715: }
9716: }
9717: }
1.127 matthew 9718: }
9719:
1.618 raeburn 9720: #######################################################
9721: #######################################################
9722:
9723: =pod
9724:
9725: =head1 Domain E-mail Routines
9726:
9727: =over 4
9728:
1.648 raeburn 9729: =item * &build_recipient_list()
1.618 raeburn 9730:
1.884 raeburn 9731: Build recipient lists for five types of e-mail:
1.766 raeburn 9732: (a) Error Reports, (b) Package Updates, (c) lonstatus warnings/errors
1.884 raeburn 9733: (d) Help requests, (e) Course requests needing approval, generated by
9734: lonerrorhandler.pm, CHECKRPMS, loncron, lonsupportreq.pm and
9735: loncoursequeueadmin.pm respectively.
1.618 raeburn 9736:
9737: Inputs:
1.619 raeburn 9738: defmail (scalar - email address of default recipient),
1.618 raeburn 9739: mailing type (scalar - errormail, packagesmail, or helpdeskmail),
1.619 raeburn 9740: defdom (domain for which to retrieve configuration settings),
9741: origmail (scalar - email address of recipient from loncapa.conf,
9742: i.e., predates configuration by DC via domainprefs.pm
1.618 raeburn 9743:
1.655 raeburn 9744: Returns: comma separated list of addresses to which to send e-mail.
9745:
9746: =back
1.618 raeburn 9747:
9748: =cut
9749:
9750: ############################################################
9751: ############################################################
9752: sub build_recipient_list {
1.619 raeburn 9753: my ($defmail,$mailing,$defdom,$origmail) = @_;
1.618 raeburn 9754: my @recipients;
9755: my $otheremails;
9756: my %domconfig =
9757: &Apache::lonnet::get_dom('configuration',['contacts'],$defdom);
9758: if (ref($domconfig{'contacts'}) eq 'HASH') {
1.766 raeburn 9759: if (exists($domconfig{'contacts'}{$mailing})) {
9760: if (ref($domconfig{'contacts'}{$mailing}) eq 'HASH') {
9761: my @contacts = ('adminemail','supportemail');
9762: foreach my $item (@contacts) {
9763: if ($domconfig{'contacts'}{$mailing}{$item}) {
9764: my $addr = $domconfig{'contacts'}{$item};
9765: if (!grep(/^\Q$addr\E$/,@recipients)) {
9766: push(@recipients,$addr);
9767: }
1.619 raeburn 9768: }
1.766 raeburn 9769: $otheremails = $domconfig{'contacts'}{$mailing}{'others'};
1.618 raeburn 9770: }
9771: }
1.766 raeburn 9772: } elsif ($origmail ne '') {
9773: push(@recipients,$origmail);
1.618 raeburn 9774: }
1.619 raeburn 9775: } elsif ($origmail ne '') {
9776: push(@recipients,$origmail);
1.618 raeburn 9777: }
1.688 raeburn 9778: if (defined($defmail)) {
9779: if ($defmail ne '') {
9780: push(@recipients,$defmail);
9781: }
1.618 raeburn 9782: }
9783: if ($otheremails) {
1.619 raeburn 9784: my @others;
9785: if ($otheremails =~ /,/) {
9786: @others = split(/,/,$otheremails);
1.618 raeburn 9787: } else {
1.619 raeburn 9788: push(@others,$otheremails);
9789: }
9790: foreach my $addr (@others) {
9791: if (!grep(/^\Q$addr\E$/,@recipients)) {
9792: push(@recipients,$addr);
9793: }
1.618 raeburn 9794: }
9795: }
1.619 raeburn 9796: my $recipientlist = join(',',@recipients);
1.618 raeburn 9797: return $recipientlist;
9798: }
9799:
1.127 matthew 9800: ############################################################
9801: ############################################################
1.154 albertel 9802:
1.655 raeburn 9803: =pod
9804:
9805: =head1 Course Catalog Routines
9806:
9807: =over 4
9808:
9809: =item * &gather_categories()
9810:
9811: Converts category definitions - keys of categories hash stored in
9812: coursecategories in configuration.db on the primary library server in a
9813: domain - to an array. Also generates javascript and idx hash used to
9814: generate Domain Coordinator interface for editing Course Categories.
9815:
9816: Inputs:
1.663 raeburn 9817:
1.655 raeburn 9818: categories (reference to hash of category definitions).
1.663 raeburn 9819:
1.655 raeburn 9820: cats (reference to array of arrays/hashes which encapsulates hierarchy of
9821: categories and subcategories).
1.663 raeburn 9822:
1.655 raeburn 9823: idx (reference to hash of counters used in Domain Coordinator interface for
9824: editing Course Categories).
1.663 raeburn 9825:
1.655 raeburn 9826: jsarray (reference to array of categories used to create Javascript arrays for
9827: Domain Coordinator interface for editing Course Categories).
9828:
9829: Returns: nothing
9830:
9831: Side effects: populates cats, idx and jsarray.
9832:
9833: =cut
9834:
9835: sub gather_categories {
9836: my ($categories,$cats,$idx,$jsarray) = @_;
9837: my %counters;
9838: my $num = 0;
9839: foreach my $item (keys(%{$categories})) {
9840: my ($cat,$container,$depth) = map { &unescape($_); } split(/:/,$item);
9841: if ($container eq '' && $depth == 0) {
9842: $cats->[$depth][$categories->{$item}] = $cat;
9843: } else {
9844: $cats->[$depth]{$container}[$categories->{$item}] = $cat;
9845: }
9846: my ($escitem,$tail) = split(/:/,$item,2);
9847: if ($counters{$tail} eq '') {
9848: $counters{$tail} = $num;
9849: $num ++;
9850: }
9851: if (ref($idx) eq 'HASH') {
9852: $idx->{$item} = $counters{$tail};
9853: }
9854: if (ref($jsarray) eq 'ARRAY') {
9855: push(@{$jsarray->[$counters{$tail}]},$item);
9856: }
9857: }
9858: return;
9859: }
9860:
9861: =pod
9862:
9863: =item * &extract_categories()
9864:
9865: Used to generate breadcrumb trails for course categories.
9866:
9867: Inputs:
1.663 raeburn 9868:
1.655 raeburn 9869: categories (reference to hash of category definitions).
1.663 raeburn 9870:
1.655 raeburn 9871: cats (reference to array of arrays/hashes which encapsulates hierarchy of
9872: categories and subcategories).
1.663 raeburn 9873:
1.655 raeburn 9874: trails (reference to array of breacrumb trails for each category).
1.663 raeburn 9875:
1.655 raeburn 9876: allitems (reference to hash - key is category key
9877: (format: escaped(name):escaped(parent category):depth in hierarchy).
1.663 raeburn 9878:
1.655 raeburn 9879: idx (reference to hash of counters used in Domain Coordinator interface for
9880: editing Course Categories).
1.663 raeburn 9881:
1.655 raeburn 9882: jsarray (reference to array of categories used to create Javascript arrays for
9883: Domain Coordinator interface for editing Course Categories).
9884:
1.665 raeburn 9885: subcats (reference to hash of arrays containing all subcategories within each
9886: category, -recursive)
9887:
1.655 raeburn 9888: Returns: nothing
9889:
9890: Side effects: populates trails and allitems hash references.
9891:
9892: =cut
9893:
9894: sub extract_categories {
1.665 raeburn 9895: my ($categories,$cats,$trails,$allitems,$idx,$jsarray,$subcats) = @_;
1.655 raeburn 9896: if (ref($categories) eq 'HASH') {
9897: &gather_categories($categories,$cats,$idx,$jsarray);
9898: if (ref($cats->[0]) eq 'ARRAY') {
9899: for (my $i=0; $i<@{$cats->[0]}; $i++) {
9900: my $name = $cats->[0][$i];
9901: my $item = &escape($name).'::0';
9902: my $trailstr;
9903: if ($name eq 'instcode') {
9904: $trailstr = &mt('Official courses (with institutional codes)');
1.919 raeburn 9905: } elsif ($name eq 'communities') {
9906: $trailstr = &mt('Communities');
1.655 raeburn 9907: } else {
9908: $trailstr = $name;
9909: }
9910: if ($allitems->{$item} eq '') {
9911: push(@{$trails},$trailstr);
9912: $allitems->{$item} = scalar(@{$trails})-1;
9913: }
9914: my @parents = ($name);
9915: if (ref($cats->[1]{$name}) eq 'ARRAY') {
9916: for (my $j=0; $j<@{$cats->[1]{$name}}; $j++) {
9917: my $category = $cats->[1]{$name}[$j];
1.665 raeburn 9918: if (ref($subcats) eq 'HASH') {
9919: push(@{$subcats->{$item}},&escape($category).':'.&escape($name).':1');
9920: }
9921: &recurse_categories($cats,2,$category,$trails,$allitems,\@parents,$subcats);
9922: }
9923: } else {
9924: if (ref($subcats) eq 'HASH') {
9925: $subcats->{$item} = [];
1.655 raeburn 9926: }
9927: }
9928: }
9929: }
9930: }
9931: return;
9932: }
9933:
9934: =pod
9935:
9936: =item *&recurse_categories()
9937:
9938: Recursively used to generate breadcrumb trails for course categories.
9939:
9940: Inputs:
1.663 raeburn 9941:
1.655 raeburn 9942: cats (reference to array of arrays/hashes which encapsulates hierarchy of
9943: categories and subcategories).
1.663 raeburn 9944:
1.655 raeburn 9945: depth (current depth in hierarchy of categories and sub-categories - 0 indexed).
1.663 raeburn 9946:
9947: category (current course category, for which breadcrumb trail is being generated).
9948:
9949: trails (reference to array of breadcrumb trails for each category).
9950:
1.655 raeburn 9951: allitems (reference to hash - key is category key
9952: (format: escaped(name):escaped(parent category):depth in hierarchy).
1.663 raeburn 9953:
1.655 raeburn 9954: parents (array containing containers directories for current category,
9955: back to top level).
9956:
9957: Returns: nothing
9958:
9959: Side effects: populates trails and allitems hash references
9960:
9961: =cut
9962:
9963: sub recurse_categories {
1.665 raeburn 9964: my ($cats,$depth,$category,$trails,$allitems,$parents,$subcats) = @_;
1.655 raeburn 9965: my $shallower = $depth - 1;
9966: if (ref($cats->[$depth]{$category}) eq 'ARRAY') {
9967: for (my $k=0; $k<@{$cats->[$depth]{$category}}; $k++) {
9968: my $name = $cats->[$depth]{$category}[$k];
9969: my $item = &escape($category).':'.&escape($parents->[-1]).':'.$shallower;
9970: my $trailstr = join(' -> ',(@{$parents},$category));
9971: if ($allitems->{$item} eq '') {
9972: push(@{$trails},$trailstr);
9973: $allitems->{$item} = scalar(@{$trails})-1;
9974: }
9975: my $deeper = $depth+1;
9976: push(@{$parents},$category);
1.665 raeburn 9977: if (ref($subcats) eq 'HASH') {
9978: my $subcat = &escape($name).':'.$category.':'.$depth;
9979: for (my $j=@{$parents}; $j>=0; $j--) {
9980: my $higher;
9981: if ($j > 0) {
9982: $higher = &escape($parents->[$j]).':'.
9983: &escape($parents->[$j-1]).':'.$j;
9984: } else {
9985: $higher = &escape($parents->[$j]).'::'.$j;
9986: }
9987: push(@{$subcats->{$higher}},$subcat);
9988: }
9989: }
9990: &recurse_categories($cats,$deeper,$name,$trails,$allitems,$parents,
9991: $subcats);
1.655 raeburn 9992: pop(@{$parents});
9993: }
9994: } else {
9995: my $item = &escape($category).':'.&escape($parents->[-1]).':'.$shallower;
9996: my $trailstr = join(' -> ',(@{$parents},$category));
9997: if ($allitems->{$item} eq '') {
9998: push(@{$trails},$trailstr);
9999: $allitems->{$item} = scalar(@{$trails})-1;
10000: }
10001: }
10002: return;
10003: }
10004:
1.663 raeburn 10005: =pod
10006:
10007: =item *&assign_categories_table()
10008:
10009: Create a datatable for display of hierarchical categories in a domain,
10010: with checkboxes to allow a course to be categorized.
10011:
10012: Inputs:
10013:
10014: cathash - reference to hash of categories defined for the domain (from
10015: configuration.db)
10016:
10017: currcat - scalar with an & separated list of categories assigned to a course.
10018:
1.919 raeburn 10019: type - scalar contains course type (Course or Community).
10020:
1.663 raeburn 10021: Returns: $output (markup to be displayed)
10022:
10023: =cut
10024:
10025: sub assign_categories_table {
1.919 raeburn 10026: my ($cathash,$currcat,$type) = @_;
1.663 raeburn 10027: my $output;
10028: if (ref($cathash) eq 'HASH') {
10029: my (@cats,@trails,%allitems,%idx,@jsarray,@path,$maxdepth);
10030: &extract_categories($cathash,\@cats,\@trails,\%allitems,\%idx,\@jsarray);
10031: $maxdepth = scalar(@cats);
10032: if (@cats > 0) {
10033: my $itemcount = 0;
10034: if (ref($cats[0]) eq 'ARRAY') {
10035: my @currcategories;
10036: if ($currcat ne '') {
10037: @currcategories = split('&',$currcat);
10038: }
1.919 raeburn 10039: my $table;
1.663 raeburn 10040: for (my $i=0; $i<@{$cats[0]}; $i++) {
10041: my $parent = $cats[0][$i];
1.919 raeburn 10042: next if ($parent eq 'instcode');
10043: if ($type eq 'Community') {
10044: next unless ($parent eq 'communities');
10045: } else {
10046: next if ($parent eq 'communities');
10047: }
1.663 raeburn 10048: my $css_class = $itemcount%2?' class="LC_odd_row"':'';
10049: my $item = &escape($parent).'::0';
10050: my $checked = '';
10051: if (@currcategories > 0) {
10052: if (grep(/^\Q$item\E$/,@currcategories)) {
1.772 bisitz 10053: $checked = ' checked="checked"';
1.663 raeburn 10054: }
10055: }
1.919 raeburn 10056: my $parent_title = $parent;
10057: if ($parent eq 'communities') {
10058: $parent_title = &mt('Communities');
10059: }
10060: $table .= '<tr '.$css_class.'><td><span class="LC_nobreak">'.
10061: '<input type="checkbox" name="usecategory" value="'.
10062: $item.'"'.$checked.' />'.$parent_title.'</span>'.
10063: '<input type="hidden" name="catname" value="'.$parent.'" /></td>';
1.663 raeburn 10064: my $depth = 1;
10065: push(@path,$parent);
1.919 raeburn 10066: $table .= &assign_category_rows($itemcount,\@cats,$depth,$parent,\@path,\@currcategories);
1.663 raeburn 10067: pop(@path);
1.919 raeburn 10068: $table .= '</tr><tr><td colspan="'.$maxdepth.'" class="LC_row_separator"></td></tr>';
1.663 raeburn 10069: $itemcount ++;
10070: }
1.919 raeburn 10071: if ($itemcount) {
10072: $output = &Apache::loncommon::start_data_table().
10073: $table.
10074: &Apache::loncommon::end_data_table();
10075: }
1.663 raeburn 10076: }
10077: }
10078: }
10079: return $output;
10080: }
10081:
10082: =pod
10083:
10084: =item *&assign_category_rows()
10085:
10086: Create a datatable row for display of nested categories in a domain,
10087: with checkboxes to allow a course to be categorized,called recursively.
10088:
10089: Inputs:
10090:
10091: itemcount - track row number for alternating colors
10092:
10093: cats - reference to array of arrays/hashes which encapsulates hierarchy of
10094: categories and subcategories.
10095:
10096: depth - current depth in hierarchy of categories and sub-categories - 0 indexed.
10097:
10098: parent - parent of current category item
10099:
10100: path - Array containing all categories back up through the hierarchy from the
10101: current category to the top level.
10102:
10103: currcategories - reference to array of current categories assigned to the course
10104:
10105: Returns: $output (markup to be displayed).
10106:
10107: =cut
10108:
10109: sub assign_category_rows {
10110: my ($itemcount,$cats,$depth,$parent,$path,$currcategories) = @_;
10111: my ($text,$name,$item,$chgstr);
10112: if (ref($cats) eq 'ARRAY') {
10113: my $maxdepth = scalar(@{$cats});
10114: if (ref($cats->[$depth]) eq 'HASH') {
10115: if (ref($cats->[$depth]{$parent}) eq 'ARRAY') {
10116: my $numchildren = @{$cats->[$depth]{$parent}};
10117: my $css_class = $itemcount%2?' class="LC_odd_row"':'';
10118: $text .= '<td><table class="LC_datatable">';
10119: for (my $j=0; $j<$numchildren; $j++) {
10120: $name = $cats->[$depth]{$parent}[$j];
10121: $item = &escape($name).':'.&escape($parent).':'.$depth;
10122: my $deeper = $depth+1;
10123: my $checked = '';
10124: if (ref($currcategories) eq 'ARRAY') {
10125: if (@{$currcategories} > 0) {
10126: if (grep(/^\Q$item\E$/,@{$currcategories})) {
1.772 bisitz 10127: $checked = ' checked="checked"';
1.663 raeburn 10128: }
10129: }
10130: }
1.664 raeburn 10131: $text .= '<tr><td><span class="LC_nobreak"><label>'.
10132: '<input type="checkbox" name="usecategory" value="'.
1.675 raeburn 10133: $item.'"'.$checked.' />'.$name.'</label></span>'.
10134: '<input type="hidden" name="catname" value="'.$name.'" />'.
10135: '</td><td>';
1.663 raeburn 10136: if (ref($path) eq 'ARRAY') {
10137: push(@{$path},$name);
10138: $text .= &assign_category_rows($itemcount,$cats,$deeper,$name,$path,$currcategories);
10139: pop(@{$path});
10140: }
10141: $text .= '</td></tr>';
10142: }
10143: $text .= '</table></td>';
10144: }
10145: }
10146: }
10147: return $text;
10148: }
10149:
1.655 raeburn 10150: ############################################################
10151: ############################################################
10152:
10153:
1.443 albertel 10154: sub commit_customrole {
1.664 raeburn 10155: my ($udom,$uname,$url,$three,$four,$five,$start,$end,$context) = @_;
1.630 raeburn 10156: my $output = &mt('Assigning custom role').' "'.$five.'" by '.$four.':'.$three.' in '.$url.
1.443 albertel 10157: ($start?', '.&mt('starting').' '.localtime($start):'').
10158: ($end?', ending '.localtime($end):'').': <b>'.
10159: &Apache::lonnet::assigncustomrole(
1.664 raeburn 10160: $udom,$uname,$url,$three,$four,$five,$end,$start,undef,undef,$context).
1.443 albertel 10161: '</b><br />';
10162: return $output;
10163: }
10164:
10165: sub commit_standardrole {
1.541 raeburn 10166: my ($udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context) = @_;
10167: my ($output,$logmsg,$linefeed);
10168: if ($context eq 'auto') {
10169: $linefeed = "\n";
10170: } else {
10171: $linefeed = "<br />\n";
10172: }
1.443 albertel 10173: if ($three eq 'st') {
1.541 raeburn 10174: my $result = &commit_studentrole(\$logmsg,$udom,$uname,$url,$three,$start,$end,
10175: $one,$two,$sec,$context);
10176: if (($result =~ /^error/) || ($result eq 'not_in_class') ||
1.626 raeburn 10177: ($result eq 'unknown_course') || ($result eq 'refused')) {
10178: $output = $logmsg.' '.&mt('Error: ').$result."\n";
1.443 albertel 10179: } else {
1.541 raeburn 10180: $output = $logmsg.$linefeed.&mt('Assigning').' '.$three.' in '.$url.
1.443 albertel 10181: ($start?', '.&mt('starting').' '.localtime($start):'').
1.541 raeburn 10182: ($end?', '.&mt('ending').' '.localtime($end):'').': ';
10183: if ($context eq 'auto') {
10184: $output .= $result.$linefeed.&mt('Add to classlist').': ok';
10185: } else {
10186: $output .= '<b>'.$result.'</b>'.$linefeed.
10187: &mt('Add to classlist').': <b>ok</b>';
10188: }
10189: $output .= $linefeed;
1.443 albertel 10190: }
10191: } else {
10192: $output = &mt('Assigning').' '.$three.' in '.$url.
10193: ($start?', '.&mt('starting').' '.localtime($start):'').
1.541 raeburn 10194: ($end?', '.&mt('ending').' '.localtime($end):'').': ';
1.652 raeburn 10195: my $result = &Apache::lonnet::assignrole($udom,$uname,$url,$three,$end,$start,'','',$context);
1.541 raeburn 10196: if ($context eq 'auto') {
10197: $output .= $result.$linefeed;
10198: } else {
10199: $output .= '<b>'.$result.'</b>'.$linefeed;
10200: }
1.443 albertel 10201: }
10202: return $output;
10203: }
10204:
10205: sub commit_studentrole {
1.541 raeburn 10206: my ($logmsg,$udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context) = @_;
1.626 raeburn 10207: my ($result,$linefeed,$oldsecurl,$newsecurl);
1.541 raeburn 10208: if ($context eq 'auto') {
10209: $linefeed = "\n";
10210: } else {
10211: $linefeed = '<br />'."\n";
10212: }
1.443 albertel 10213: if (defined($one) && defined($two)) {
10214: my $cid=$one.'_'.$two;
10215: my $oldsec=&Apache::lonnet::getsection($udom,$uname,$cid);
10216: my $secchange = 0;
10217: my $expire_role_result;
10218: my $modify_section_result;
1.628 raeburn 10219: if ($oldsec ne '-1') {
10220: if ($oldsec ne $sec) {
1.443 albertel 10221: $secchange = 1;
1.628 raeburn 10222: my $now = time;
1.443 albertel 10223: my $uurl='/'.$cid;
10224: $uurl=~s/\_/\//g;
10225: if ($oldsec) {
10226: $uurl.='/'.$oldsec;
10227: }
1.626 raeburn 10228: $oldsecurl = $uurl;
1.628 raeburn 10229: $expire_role_result =
1.652 raeburn 10230: &Apache::lonnet::assignrole($udom,$uname,$uurl,'st',$now,'','',$context);
1.628 raeburn 10231: if ($env{'request.course.sec'} ne '') {
10232: if ($expire_role_result eq 'refused') {
10233: my @roles = ('st');
10234: my @statuses = ('previous');
10235: my @roledoms = ($one);
10236: my $withsec = 1;
10237: my %roleshash =
10238: &Apache::lonnet::get_my_roles($uname,$udom,'userroles',
10239: \@statuses,\@roles,\@roledoms,$withsec);
10240: if (defined ($roleshash{$two.':'.$one.':st:'.$oldsec})) {
10241: my ($oldstart,$oldend) =
10242: split(':',$roleshash{$two.':'.$one.':st:'.$oldsec});
10243: if ($oldend > 0 && $oldend <= $now) {
10244: $expire_role_result = 'ok';
10245: }
10246: }
10247: }
10248: }
1.443 albertel 10249: $result = $expire_role_result;
10250: }
10251: }
10252: if (($expire_role_result eq 'ok') || ($secchange == 0)) {
1.652 raeburn 10253: $modify_section_result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,'','',$cid,'',$context);
1.443 albertel 10254: if ($modify_section_result =~ /^ok/) {
10255: if ($secchange == 1) {
1.628 raeburn 10256: if ($sec eq '') {
10257: $$logmsg .= &mt('Section for [_1] switched from (possibly expired) old section: [_2] to student role without a section.',$uname,$oldsec).$linefeed;
10258: } else {
10259: $$logmsg .= &mt('Section for [_1] switched from (possibly expired) old section: [_2] to new section: [_3].',$uname,$oldsec,$sec).$linefeed;
10260: }
1.443 albertel 10261: } elsif ($oldsec eq '-1') {
1.628 raeburn 10262: if ($sec eq '') {
10263: $$logmsg .= &mt('New student role without a section for [_1] in course [_2].',$uname,$cid).$linefeed;
10264: } else {
10265: $$logmsg .= &mt('New student role for [_1] in section [_2] in course [_3].',$uname,$sec,$cid).$linefeed;
10266: }
1.443 albertel 10267: } else {
1.628 raeburn 10268: if ($sec eq '') {
10269: $$logmsg .= &mt('Student [_1] assigned to course [_2] without a section.',$uname,$cid).$linefeed;
10270: } else {
10271: $$logmsg .= &mt('Student [_1] assigned to section [_2] in course [_3].',$uname,$sec,$cid).$linefeed;
10272: }
1.443 albertel 10273: }
10274: } else {
1.628 raeburn 10275: if ($secchange) {
10276: $$logmsg .= &mt('Error when attempting section change for [_1] from old section "[_2]" to new section: "[_3]" in course [_4] -error:',$uname,$oldsec,$sec,$cid).' '.$modify_section_result.$linefeed;
10277: } else {
10278: $$logmsg .= &mt('Error when attempting to modify role for [_1] for section: "[_2]" in course [_3] -error:',$uname,$sec,$cid).' '.$modify_section_result.$linefeed;
10279: }
1.443 albertel 10280: }
10281: $result = $modify_section_result;
10282: } elsif ($secchange == 1) {
1.628 raeburn 10283: if ($oldsec eq '') {
10284: $$logmsg .= &mt('Error when attempting to expire existing role without a section for [_1] in course [_3] -error: ',$uname,$cid).' '.$expire_role_result.$linefeed;
10285: } else {
10286: $$logmsg .= &mt('Error when attempting to expire existing role for [_1] in section [_2] in course [_3] -error: ',$uname,$oldsec,$cid).' '.$expire_role_result.$linefeed;
10287: }
1.626 raeburn 10288: if ($expire_role_result eq 'refused') {
10289: my $newsecurl = '/'.$cid;
10290: $newsecurl =~ s/\_/\//g;
10291: if ($sec ne '') {
10292: $newsecurl.='/'.$sec;
10293: }
10294: if (&Apache::lonnet::allowed('cst',$newsecurl) && !(&Apache::lonnet::allowed('cst',$oldsecurl))) {
10295: if ($sec eq '') {
10296: $$logmsg .= &mt('Although your current role has privileges to add students to section "[_1]", you do not have privileges to modify existing enrollments unaffiliated with any section.',$sec).$linefeed;
10297: } else {
10298: $$logmsg .= &mt('Although your current role has privileges to add students to section "[_1]", you do not have privileges to modify existing enrollments in other sections.',$sec).$linefeed;
10299: }
10300: }
10301: }
1.443 albertel 10302: }
10303: } else {
1.626 raeburn 10304: $$logmsg .= &mt('Incomplete course id defined.').$linefeed.&mt('Addition of user [_1] from domain [_2] to course [_3], section [_4] not completed.',$uname,$udom,$one.'_'.$two,$sec).$linefeed;
1.443 albertel 10305: $result = "error: incomplete course id\n";
10306: }
10307: return $result;
10308: }
10309:
10310: ############################################################
10311: ############################################################
10312:
1.566 albertel 10313: sub check_clone {
1.578 raeburn 10314: my ($args,$linefeed) = @_;
1.566 albertel 10315: my $cloneid='/'.$args->{'clonedomain'}.'/'.$args->{'clonecourse'};
10316: my ($clonecrsudom,$clonecrsunum)= &LONCAPA::split_courseid($cloneid);
10317: my $clonehome=&Apache::lonnet::homeserver($clonecrsunum,$clonecrsudom);
10318: my $clonemsg;
10319: my $can_clone = 0;
1.944 raeburn 10320: my $lctype = lc($args->{'crstype'});
1.908 raeburn 10321: if ($lctype ne 'community') {
10322: $lctype = 'course';
10323: }
1.566 albertel 10324: if ($clonehome eq 'no_host') {
1.944 raeburn 10325: if ($args->{'crstype'} eq 'Community') {
1.908 raeburn 10326: $clonemsg = &mt('No new community created.').$linefeed.&mt('A new community could not be cloned from the specified original - [_1] - because it is a non-existent community.',$args->{'clonecourse'}.':'.$args->{'clonedomain'});
10327: } else {
10328: $clonemsg = &mt('No new course created.').$linefeed.&mt('A new course could not be cloned from the specified original - [_1] - because it is a non-existent course.',$args->{'clonecourse'}.':'.$args->{'clonedomain'});
10329: }
1.566 albertel 10330: } else {
10331: my %clonedesc = &Apache::lonnet::coursedescription($cloneid,{'one_time' => 1});
1.944 raeburn 10332: if ($args->{'crstype'} eq 'Community') {
1.908 raeburn 10333: if ($clonedesc{'type'} ne 'Community') {
10334: $clonemsg = &mt('No new community created.').$linefeed.&mt('A new community could not be cloned from the specified original - [_1] - because it is a course not a community.',$args->{'clonecourse'}.':'.$args->{'clonedomain'});
10335: return ($can_clone, $clonemsg, $cloneid, $clonehome);
10336: }
10337: }
1.882 raeburn 10338: if (($env{'request.role.domain'} eq $args->{'clonedomain'}) &&
10339: (&Apache::lonnet::allowed('ccc',$env{'request.role.domain'}))) {
1.566 albertel 10340: $can_clone = 1;
10341: } else {
10342: my %clonehash = &Apache::lonnet::get('environment',['cloners'],
10343: $args->{'clonedomain'},$args->{'clonecourse'});
10344: my @cloners = split(/,/,$clonehash{'cloners'});
1.578 raeburn 10345: if (grep(/^\*$/,@cloners)) {
10346: $can_clone = 1;
10347: } elsif (grep(/^\*\:\Q$args->{'ccdomain'}\E$/,@cloners)) {
10348: $can_clone = 1;
10349: } else {
1.908 raeburn 10350: my $ccrole = 'cc';
1.944 raeburn 10351: if ($args->{'crstype'} eq 'Community') {
1.908 raeburn 10352: $ccrole = 'co';
10353: }
1.578 raeburn 10354: my %roleshash =
10355: &Apache::lonnet::get_my_roles($args->{'ccuname'},
10356: $args->{'ccdomain'},
1.908 raeburn 10357: 'userroles',['active'],[$ccrole],
1.578 raeburn 10358: [$args->{'clonedomain'}]);
1.908 raeburn 10359: if (($roleshash{$args->{'clonecourse'}.':'.$args->{'clonedomain'}.':'.$ccrole}) || (grep(/^\Q$args->{'ccuname'}\E:\Q$args->{'ccdomain'}\E$/,@cloners))) {
1.942 raeburn 10360: $can_clone = 1;
10361: } elsif (&Apache::lonnet::is_course_owner($args->{'clonedomain'},$args->{'clonecourse'},$args->{'ccuname'},$args->{'ccdomain'})) {
10362: $can_clone = 1;
10363: } else {
1.944 raeburn 10364: if ($args->{'crstype'} eq 'Community') {
1.908 raeburn 10365: $clonemsg = &mt('No new community created.').$linefeed.&mt('The new community could not be cloned from the existing community because the new community owner ([_1]) does not have cloning rights in the existing community ([_2]).',$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'});
10366: } else {
10367: $clonemsg = &mt('No new course created.').$linefeed.&mt('The new course could not be cloned from the existing course because the new course owner ([_1]) does not have cloning rights in the existing course ([_2]).',$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'});
10368: }
1.578 raeburn 10369: }
1.566 albertel 10370: }
1.578 raeburn 10371: }
1.566 albertel 10372: }
10373: return ($can_clone, $clonemsg, $cloneid, $clonehome);
10374: }
10375:
1.444 albertel 10376: sub construct_course {
1.885 raeburn 10377: my ($args,$logmsg,$courseid,$crsudom,$crsunum,$udom,$uname,$context,$cnum,$category) = @_;
1.444 albertel 10378: my $outcome;
1.541 raeburn 10379: my $linefeed = '<br />'."\n";
10380: if ($context eq 'auto') {
10381: $linefeed = "\n";
10382: }
1.566 albertel 10383:
10384: #
10385: # Are we cloning?
10386: #
10387: my ($can_clone, $clonemsg, $cloneid, $clonehome);
10388: if (($args->{'clonecourse'}) && ($args->{'clonedomain'})) {
1.578 raeburn 10389: ($can_clone, $clonemsg, $cloneid, $clonehome) = &check_clone($args,$linefeed);
1.566 albertel 10390: if ($context ne 'auto') {
1.578 raeburn 10391: if ($clonemsg ne '') {
10392: $clonemsg = '<span class="LC_error">'.$clonemsg.'</span>';
10393: }
1.566 albertel 10394: }
10395: $outcome .= $clonemsg.$linefeed;
10396:
10397: if (!$can_clone) {
10398: return (0,$outcome);
10399: }
10400: }
10401:
1.444 albertel 10402: #
10403: # Open course
10404: #
10405: my $crstype = lc($args->{'crstype'});
10406: my %cenv=();
10407: $$courseid=&Apache::lonnet::createcourse($args->{'course_domain'},
10408: $args->{'cdescr'},
10409: $args->{'curl'},
10410: $args->{'course_home'},
10411: $args->{'nonstandard'},
10412: $args->{'crscode'},
10413: $args->{'ccuname'}.':'.
10414: $args->{'ccdomain'},
1.882 raeburn 10415: $args->{'crstype'},
1.885 raeburn 10416: $cnum,$context,$category);
1.444 albertel 10417:
10418: # Note: The testing routines depend on this being output; see
10419: # Utils::Course. This needs to at least be output as a comment
10420: # if anyone ever decides to not show this, and Utils::Course::new
10421: # will need to be suitably modified.
1.541 raeburn 10422: $outcome .= &mt('New LON-CAPA [_1] ID: [_2]',$crstype,$$courseid).$linefeed;
1.943 raeburn 10423: if ($$courseid =~ /^error:/) {
10424: return (0,$outcome);
10425: }
10426:
1.444 albertel 10427: #
10428: # Check if created correctly
10429: #
1.479 albertel 10430: ($$crsudom,$$crsunum)= &LONCAPA::split_courseid($$courseid);
1.444 albertel 10431: my $crsuhome=&Apache::lonnet::homeserver($$crsunum,$$crsudom);
1.943 raeburn 10432: if ($crsuhome eq 'no_host') {
10433: $outcome .= &mt('Course creation failed, unrecognized course home server.').$linefeed;
10434: return (0,$outcome);
10435: }
1.541 raeburn 10436: $outcome .= &mt('Created on').': '.$crsuhome.$linefeed;
1.566 albertel 10437:
1.444 albertel 10438: #
1.566 albertel 10439: # Do the cloning
10440: #
10441: if ($can_clone && $cloneid) {
10442: $clonemsg = &mt('Cloning [_1] from [_2]',$crstype,$clonehome);
10443: if ($context ne 'auto') {
10444: $clonemsg = '<span class="LC_success">'.$clonemsg.'</span>';
10445: }
10446: $outcome .= $clonemsg.$linefeed;
10447: my %oldcenv=&Apache::lonnet::dump('environment',$$crsudom,$$crsunum);
1.444 albertel 10448: # Copy all files
1.637 www 10449: &Apache::lonclonecourse::copycoursefiles($cloneid,$$courseid,$args->{'datemode'},$args->{'dateshift'});
1.444 albertel 10450: # Restore URL
1.566 albertel 10451: $cenv{'url'}=$oldcenv{'url'};
1.444 albertel 10452: # Restore title
1.566 albertel 10453: $cenv{'description'}=$oldcenv{'description'};
1.948.2.2 raeburn 10454: # Restore creation date, creator and creation context.
10455: $cenv{'internal.created'}=$oldcenv{'internal.created'};
10456: $cenv{'internal.creator'}=$oldcenv{'internal.creator'};
10457: $cenv{'internal.creationcontext'}=$oldcenv{'internal.creationcontext'};
1.444 albertel 10458: # Mark as cloned
1.566 albertel 10459: $cenv{'clonedfrom'}=$cloneid;
1.638 www 10460: # Need to clone grading mode
10461: my %newenv=&Apache::lonnet::get('environment',['grading'],$$crsudom,$$crsunum);
10462: $cenv{'grading'}=$newenv{'grading'};
10463: # Do not clone these environment entries
10464: &Apache::lonnet::del('environment',
10465: ['default_enrollment_start_date',
10466: 'default_enrollment_end_date',
10467: 'question.email',
10468: 'policy.email',
10469: 'comment.email',
10470: 'pch.users.denied',
1.725 raeburn 10471: 'plc.users.denied',
10472: 'hidefromcat',
10473: 'categories'],
1.638 www 10474: $$crsudom,$$crsunum);
1.444 albertel 10475: }
1.566 albertel 10476:
1.444 albertel 10477: #
10478: # Set environment (will override cloned, if existing)
10479: #
10480: my @sections = ();
10481: my @xlists = ();
10482: if ($args->{'crstype'}) {
10483: $cenv{'type'}=$args->{'crstype'};
10484: }
10485: if ($args->{'crsid'}) {
10486: $cenv{'courseid'}=$args->{'crsid'};
10487: }
10488: if ($args->{'crscode'}) {
10489: $cenv{'internal.coursecode'}=$args->{'crscode'};
10490: }
10491: if ($args->{'crsquota'} ne '') {
10492: $cenv{'internal.coursequota'}=$args->{'crsquota'};
10493: } else {
10494: $cenv{'internal.coursequota'}=$args->{'crsquota'} = 20;
10495: }
10496: if ($args->{'ccuname'}) {
10497: $cenv{'internal.courseowner'} = $args->{'ccuname'}.
10498: ':'.$args->{'ccdomain'};
10499: } else {
10500: $cenv{'internal.courseowner'} = $args->{'curruser'};
10501: }
10502: my @badclasses = (); # Used to accumulate sections/crosslistings that did not pass classlist access check for course owner.
10503: if ($args->{'crssections'}) {
10504: $cenv{'internal.sectionnums'} = '';
10505: if ($args->{'crssections'} =~ m/,/) {
10506: @sections = split/,/,$args->{'crssections'};
10507: } else {
10508: $sections[0] = $args->{'crssections'};
10509: }
10510: if (@sections > 0) {
10511: foreach my $item (@sections) {
10512: my ($sec,$gp) = split/:/,$item;
10513: my $class = $args->{'crscode'}.$sec;
10514: my $addcheck = &Apache::lonnet::auto_new_course($$crsunum,$$crsudom,$class,$cenv{'internal.courseowner'});
10515: $cenv{'internal.sectionnums'} .= $item.',';
10516: unless ($addcheck eq 'ok') {
10517: push @badclasses, $class;
10518: }
10519: }
10520: $cenv{'internal.sectionnums'} =~ s/,$//;
10521: }
10522: }
10523: # do not hide course coordinator from staff listing,
10524: # even if privileged
10525: $cenv{'nothideprivileged'}=$args->{'ccuname'}.':'.$args->{'ccdomain'};
10526: # add crosslistings
10527: if ($args->{'crsxlist'}) {
10528: $cenv{'internal.crosslistings'}='';
10529: if ($args->{'crsxlist'} =~ m/,/) {
10530: @xlists = split/,/,$args->{'crsxlist'};
10531: } else {
10532: $xlists[0] = $args->{'crsxlist'};
10533: }
10534: if (@xlists > 0) {
10535: foreach my $item (@xlists) {
10536: my ($xl,$gp) = split/:/,$item;
10537: my $addcheck = &Apache::lonnet::auto_new_course($$crsunum,$$crsudom,$xl,$cenv{'internal.courseowner'});
10538: $cenv{'internal.crosslistings'} .= $item.',';
10539: unless ($addcheck eq 'ok') {
10540: push @badclasses, $xl;
10541: }
10542: }
10543: $cenv{'internal.crosslistings'} =~ s/,$//;
10544: }
10545: }
10546: if ($args->{'autoadds'}) {
10547: $cenv{'internal.autoadds'}=$args->{'autoadds'};
10548: }
10549: if ($args->{'autodrops'}) {
10550: $cenv{'internal.autodrops'}=$args->{'autodrops'};
10551: }
10552: # check for notification of enrollment changes
10553: my @notified = ();
10554: if ($args->{'notify_owner'}) {
10555: if ($args->{'ccuname'} ne '') {
10556: push(@notified,$args->{'ccuname'}.':'.$args->{'ccdomain'});
10557: }
10558: }
10559: if ($args->{'notify_dc'}) {
10560: if ($uname ne '') {
1.630 raeburn 10561: push(@notified,$uname.':'.$udom);
1.444 albertel 10562: }
10563: }
10564: if (@notified > 0) {
10565: my $notifylist;
10566: if (@notified > 1) {
10567: $notifylist = join(',',@notified);
10568: } else {
10569: $notifylist = $notified[0];
10570: }
10571: $cenv{'internal.notifylist'} = $notifylist;
10572: }
10573: if (@badclasses > 0) {
10574: my %lt=&Apache::lonlocal::texthash(
10575: 'tclb' => 'The courses listed below were included as sections or crosslistings affiliated with your new LON-CAPA course. However, if automated course roster updates are enabled for this class, these particular sections/crosslistings will not contribute towards enrollment, because the user identified as the course owner for this LON-CAPA course',
10576: 'dnhr' => 'does not have rights to access enrollment in these classes',
10577: 'adby' => 'as determined by the policies of your institution on access to official classlists'
10578: );
1.541 raeburn 10579: my $badclass_msg = $cenv{'internal.courseowner'}.') - '.$lt{'dnhr'}.
10580: ' ('.$lt{'adby'}.')';
10581: if ($context eq 'auto') {
10582: $outcome .= $badclass_msg.$linefeed;
1.566 albertel 10583: $outcome .= '<div class="LC_warning">'.$badclass_msg.$linefeed.'<ul>'."\n";
1.541 raeburn 10584: foreach my $item (@badclasses) {
10585: if ($context eq 'auto') {
10586: $outcome .= " - $item\n";
10587: } else {
10588: $outcome .= "<li>$item</li>\n";
10589: }
10590: }
10591: if ($context eq 'auto') {
10592: $outcome .= $linefeed;
10593: } else {
1.566 albertel 10594: $outcome .= "</ul><br /><br /></div>\n";
1.541 raeburn 10595: }
10596: }
1.444 albertel 10597: }
10598: if ($args->{'no_end_date'}) {
10599: $args->{'endaccess'} = 0;
10600: }
10601: $cenv{'internal.autostart'}=$args->{'enrollstart'};
10602: $cenv{'internal.autoend'}=$args->{'enrollend'};
10603: $cenv{'default_enrollment_start_date'}=$args->{'startaccess'};
10604: $cenv{'default_enrollment_end_date'}=$args->{'endaccess'};
10605: if ($args->{'showphotos'}) {
10606: $cenv{'internal.showphotos'}=$args->{'showphotos'};
10607: }
10608: $cenv{'internal.authtype'} = $args->{'authtype'};
10609: $cenv{'internal.autharg'} = $args->{'autharg'};
10610: if ( ($cenv{'internal.authtype'} =~ /^krb/) && ($cenv{'internal.autoadds'} == 1)) {
10611: if (! defined($cenv{'internal.autharg'}) || $cenv{'internal.autharg'} eq '') {
1.541 raeburn 10612: my $krb_msg = &mt('As you did not include the default Kerberos domain to be used for authentication in this class, the institutional data used by the automated enrollment process must include the Kerberos domain for each new student');
10613: if ($context eq 'auto') {
10614: $outcome .= $krb_msg;
10615: } else {
1.566 albertel 10616: $outcome .= '<span class="LC_error">'.$krb_msg.'</span>';
1.541 raeburn 10617: }
10618: $outcome .= $linefeed;
1.444 albertel 10619: }
10620: }
10621: if (($args->{'ccdomain'}) && ($args->{'ccuname'})) {
10622: if ($args->{'setpolicy'}) {
10623: $cenv{'policy.email'}=$args->{'ccuname'}.':'.$args->{'ccdomain'};
10624: }
10625: if ($args->{'setcontent'}) {
10626: $cenv{'question.email'}=$args->{'ccuname'}.':'.$args->{'ccdomain'};
10627: }
10628: }
10629: if ($args->{'reshome'}) {
10630: $cenv{'reshome'}=$args->{'reshome'}.'/';
10631: $cenv{'reshome'}=~s/\/+$/\//;
10632: }
10633: #
10634: # course has keyed access
10635: #
10636: if ($args->{'setkeys'}) {
10637: $cenv{'keyaccess'}='yes';
10638: }
10639: # if specified, key authority is not course, but user
10640: # only active if keyaccess is yes
10641: if ($args->{'keyauth'}) {
1.487 albertel 10642: my ($user,$domain) = split(':',$args->{'keyauth'});
10643: $user = &LONCAPA::clean_username($user);
10644: $domain = &LONCAPA::clean_username($domain);
1.488 foxr 10645: if ($user ne '' && $domain ne '') {
1.487 albertel 10646: $cenv{'keyauth'}=$user.':'.$domain;
1.444 albertel 10647: }
10648: }
10649:
10650: if ($args->{'disresdis'}) {
10651: $cenv{'pch.roles.denied'}='st';
10652: }
10653: if ($args->{'disablechat'}) {
10654: $cenv{'plc.roles.denied'}='st';
10655: }
10656:
10657: # Record we've not yet viewed the Course Initialization Helper for this
10658: # course
10659: $cenv{'course.helper.not.run'} = 1;
10660: #
10661: # Use new Randomseed
10662: #
10663: $cenv{'rndseed'}=&Apache::lonnet::latest_rnd_algorithm_id();;
10664: $cenv{'receiptalg'}=&Apache::lonnet::latest_receipt_algorithm_id();;
10665: #
10666: # The encryption code and receipt prefix for this course
10667: #
10668: $cenv{'internal.encseed'}=$Apache::lonnet::perlvar{'lonReceipt'}.$$.time.int(rand(9999));
10669: $cenv{'internal.encpref'}=100+int(9*rand(99));
10670: #
10671: # By default, use standard grading
10672: if (!defined($cenv{'grading'})) { $cenv{'grading'} = 'standard'; }
10673:
1.541 raeburn 10674: $outcome .= $linefeed.&mt('Setting environment').': '.
10675: &Apache::lonnet::put('environment',\%cenv,$$crsudom,$$crsunum).$linefeed;
1.444 albertel 10676: #
10677: # Open all assignments
10678: #
10679: if ($args->{'openall'}) {
10680: my $storeunder=$$crsudom.'_'.$$crsunum.'.0.opendate';
10681: my %storecontent = ($storeunder => time,
10682: $storeunder.'.type' => 'date_start');
10683:
10684: $outcome .= &mt('Opening all assignments').': '.&Apache::lonnet::cput
1.541 raeburn 10685: ('resourcedata',\%storecontent,$$crsudom,$$crsunum).$linefeed;
1.444 albertel 10686: }
10687: #
10688: # Set first page
10689: #
10690: unless (($args->{'nonstandard'}) || ($args->{'firstres'} eq 'blank')
10691: || ($cloneid)) {
1.445 albertel 10692: use LONCAPA::map;
1.444 albertel 10693: $outcome .= &mt('Setting first resource').': ';
1.445 albertel 10694:
10695: my $map = '/uploaded/'.$$crsudom.'/'.$$crsunum.'/default.sequence';
10696: my ($errtext,$fatal)=&LONCAPA::map::mapread($map);
10697:
1.444 albertel 10698: $outcome .= ($fatal?$errtext:'read ok').' - ';
10699: my $title; my $url;
10700: if ($args->{'firstres'} eq 'syl') {
1.690 bisitz 10701: $title=&mt('Syllabus');
1.444 albertel 10702: $url='/public/'.$$crsudom.'/'.$$crsunum.'/syllabus';
10703: } else {
1.948.2.5 raeburn 10704: $title=&mt('Table of Contents');
1.444 albertel 10705: $url='/adm/navmaps';
10706: }
1.445 albertel 10707:
10708: $LONCAPA::map::resources[1]=$title.':'.$url.':false:start:res';
10709: (my $outtext,$errtext) = &LONCAPA::map::storemap($map,1);
10710:
10711: if ($errtext) { $fatal=2; }
1.541 raeburn 10712: $outcome .= ($fatal?$errtext:'write ok').$linefeed;
1.444 albertel 10713: }
1.566 albertel 10714:
10715: return (1,$outcome);
1.444 albertel 10716: }
10717:
10718: ############################################################
10719: ############################################################
10720:
1.378 raeburn 10721: sub course_type {
10722: my ($cid) = @_;
10723: if (!defined($cid)) {
10724: $cid = $env{'request.course.id'};
10725: }
1.404 albertel 10726: if (defined($env{'course.'.$cid.'.type'})) {
10727: return $env{'course.'.$cid.'.type'};
1.378 raeburn 10728: } else {
10729: return 'Course';
1.377 raeburn 10730: }
10731: }
1.156 albertel 10732:
1.406 raeburn 10733: sub group_term {
10734: my $crstype = &course_type();
10735: my %names = (
10736: 'Course' => 'group',
1.865 raeburn 10737: 'Community' => 'group',
1.406 raeburn 10738: );
10739: return $names{$crstype};
10740: }
10741:
1.902 raeburn 10742: sub course_types {
10743: my @types = ('official','unofficial','community');
10744: my %typename = (
10745: official => 'Official course',
10746: unofficial => 'Unofficial course',
10747: community => 'Community',
10748: );
10749: return (\@types,\%typename);
10750: }
10751:
1.156 albertel 10752: sub icon {
10753: my ($file)=@_;
1.505 albertel 10754: my $curfext = lc((split(/\./,$file))[-1]);
1.168 albertel 10755: my $iconname=$Apache::lonnet::perlvar{'lonIconsURL'}.'/unknown.gif';
1.156 albertel 10756: my $embstyle = &Apache::loncommon::fileembstyle($curfext);
1.168 albertel 10757: if (!(!defined($embstyle) || $embstyle eq 'unk' || $embstyle eq 'hdn')) {
10758: if (-e $Apache::lonnet::perlvar{'lonDocRoot'}.'/'.
10759: $Apache::lonnet::perlvar{'lonIconsURL'}.'/'.
10760: $curfext.".gif") {
10761: $iconname=$Apache::lonnet::perlvar{'lonIconsURL'}.'/'.
10762: $curfext.".gif";
10763: }
10764: }
1.249 albertel 10765: return &lonhttpdurl($iconname);
1.154 albertel 10766: }
1.84 albertel 10767:
1.575 albertel 10768: sub lonhttpdurl {
1.692 www 10769: #
10770: # Had been used for "small fry" static images on separate port 8080.
10771: # Modify here if lightweight http functionality desired again.
10772: # Currently eliminated due to increasing firewall issues.
10773: #
1.575 albertel 10774: my ($url)=@_;
1.692 www 10775: return $url;
1.215 albertel 10776: }
10777:
1.213 albertel 10778: sub connection_aborted {
10779: my ($r)=@_;
10780: $r->print(" ");$r->rflush();
10781: my $c = $r->connection;
10782: return $c->aborted();
10783: }
10784:
1.221 foxr 10785: # Escapes strings that may have embedded 's that will be put into
1.222 foxr 10786: # strings as 'strings'.
10787: sub escape_single {
1.221 foxr 10788: my ($input) = @_;
1.223 albertel 10789: $input =~ s/\\/\\\\/g; # Escape the \'s..(must be first)>
1.221 foxr 10790: $input =~ s/\'/\\\'/g; # Esacpe the 's....
10791: return $input;
10792: }
1.223 albertel 10793:
1.222 foxr 10794: # Same as escape_single, but escape's "'s This
10795: # can be used for "strings"
10796: sub escape_double {
10797: my ($input) = @_;
10798: $input =~ s/\\/\\\\/g; # Escape the /'s..(must be first)>
10799: $input =~ s/\"/\\\"/g; # Esacpe the "s....
10800: return $input;
10801: }
1.223 albertel 10802:
1.222 foxr 10803: # Escapes the last element of a full URL.
10804: sub escape_url {
10805: my ($url) = @_;
1.238 raeburn 10806: my @urlslices = split(/\//, $url,-1);
1.369 www 10807: my $lastitem = &escape(pop(@urlslices));
1.223 albertel 10808: return join('/',@urlslices).'/'.$lastitem;
1.222 foxr 10809: }
1.462 albertel 10810:
1.820 raeburn 10811: sub compare_arrays {
10812: my ($arrayref1,$arrayref2) = @_;
10813: my (@difference,%count);
10814: @difference = ();
10815: %count = ();
10816: if ((ref($arrayref1) eq 'ARRAY') && (ref($arrayref2) eq 'ARRAY')) {
10817: foreach my $element (@{$arrayref1}, @{$arrayref2}) { $count{$element}++; }
10818: foreach my $element (keys(%count)) {
10819: if ($count{$element} == 1) {
10820: push(@difference,$element);
10821: }
10822: }
10823: }
10824: return @difference;
10825: }
10826:
1.817 bisitz 10827: # -------------------------------------------------------- Initialize user login
1.462 albertel 10828: sub init_user_environment {
1.463 albertel 10829: my ($r, $username, $domain, $authhost, $form, $args) = @_;
1.462 albertel 10830: my $lonids=$Apache::lonnet::perlvar{'lonIDsDir'};
10831:
10832: my $public=($username eq 'public' && $domain eq 'public');
10833:
10834: # See if old ID present, if so, remove
10835:
10836: my ($filename,$cookie,$userroles);
10837: my $now=time;
10838:
10839: if ($public) {
10840: my $max_public=100;
10841: my $oldest;
10842: my $oldest_time=0;
10843: for(my $next=1;$next<=$max_public;$next++) {
10844: if (-e $lonids."/publicuser_$next.id") {
10845: my $mtime=(stat($lonids."/publicuser_$next.id"))[9];
10846: if ($mtime<$oldest_time || !$oldest_time) {
10847: $oldest_time=$mtime;
10848: $oldest=$next;
10849: }
10850: } else {
10851: $cookie="publicuser_$next";
10852: last;
10853: }
10854: }
10855: if (!$cookie) { $cookie="publicuser_$oldest"; }
10856: } else {
1.463 albertel 10857: # if this isn't a robot, kill any existing non-robot sessions
10858: if (!$args->{'robot'}) {
10859: opendir(DIR,$lonids);
10860: while ($filename=readdir(DIR)) {
10861: if ($filename=~/^$username\_\d+\_$domain\_$authhost\.id$/) {
10862: unlink($lonids.'/'.$filename);
10863: }
1.462 albertel 10864: }
1.463 albertel 10865: closedir(DIR);
1.462 albertel 10866: }
10867: # Give them a new cookie
1.463 albertel 10868: my $id = ($args->{'robot'} ? 'robot'.$args->{'robot'}
1.684 www 10869: : $now.$$.int(rand(10000)));
1.463 albertel 10870: $cookie="$username\_$id\_$domain\_$authhost";
1.462 albertel 10871:
10872: # Initialize roles
10873:
10874: $userroles=&Apache::lonnet::rolesinit($domain,$username,$authhost);
10875: }
10876: # ------------------------------------ Check browser type and MathML capability
10877:
10878: my ($httpbrowser,$clientbrowser,$clientversion,$clientmathml,
10879: $clientunicode,$clientos) = &decode_user_agent($r);
10880:
10881: # ------------------------------------------------------------- Get environment
10882:
10883: my %userenv = &Apache::lonnet::dump('environment',$domain,$username);
10884: my ($tmp) = keys(%userenv);
10885: if ($tmp !~ /^(con_lost|error|no_such_host)/i) {
10886: # default remote control to off
10887: if ($userenv{'remote'} ne 'on') { $userenv{'remote'} = 'off'; }
10888: } else {
10889: undef(%userenv);
10890: }
10891: if (($userenv{'interface'}) && (!$form->{'interface'})) {
10892: $form->{'interface'}=$userenv{'interface'};
10893: }
10894: $env{'environment.remote'}=$userenv{'remote'};
10895: if ($userenv{'texengine'} eq 'ttm') { $clientmathml=1; }
10896:
10897: # --------------- Do not trust query string to be put directly into environment
1.817 bisitz 10898: foreach my $option ('interface','localpath','localres') {
10899: $form->{$option}=~s/[\n\r\=]//gs;
1.462 albertel 10900: }
10901: # --------------------------------------------------------- Write first profile
10902:
10903: {
10904: my %initial_env =
10905: ("user.name" => $username,
10906: "user.domain" => $domain,
10907: "user.home" => $authhost,
10908: "browser.type" => $clientbrowser,
10909: "browser.version" => $clientversion,
10910: "browser.mathml" => $clientmathml,
10911: "browser.unicode" => $clientunicode,
10912: "browser.os" => $clientos,
10913: "server.domain" => $Apache::lonnet::perlvar{'lonDefDomain'},
10914: "request.course.fn" => '',
10915: "request.course.uri" => '',
10916: "request.course.sec" => '',
10917: "request.role" => 'cm',
10918: "request.role.adv" => $env{'user.adv'},
10919: "request.host" => $ENV{'REMOTE_ADDR'},);
10920:
10921: if ($form->{'localpath'}) {
10922: $initial_env{"browser.localpath"} = $form->{'localpath'};
10923: $initial_env{"browser.localres"} = $form->{'localres'};
10924: }
10925:
10926: if ($public) {
10927: $initial_env{"environment.remote"} = "off";
10928: }
10929: if ($form->{'interface'}) {
10930: $form->{'interface'}=~s/\W//gs;
10931: $initial_env{"browser.interface"} = $form->{'interface'};
10932: $env{'browser.interface'}=$form->{'interface'};
10933: }
1.948.2.11 raeburn 10934: my %is_adv = ( is_adv => $env{'user.adv'} );
1.948.2.10 raeburn 10935: my %domdef = &Apache::lonnet::get_domain_defaults($domain);
1.462 albertel 10936:
1.724 raeburn 10937: foreach my $tool ('aboutme','blog','portfolio') {
10938: $userenv{'availabletools.'.$tool} =
1.948.2.10 raeburn 10939: &Apache::lonnet::usertools_access($username,$domain,$tool,'reload',
10940: undef,\%userenv,\%domdef,\%is_adv);
1.724 raeburn 10941: }
10942:
1.864 raeburn 10943: foreach my $crstype ('official','unofficial','community') {
1.765 raeburn 10944: $userenv{'canrequest.'.$crstype} =
10945: &Apache::lonnet::usertools_access($username,$domain,$crstype,
1.948.2.10 raeburn 10946: 'reload','requestcourses',
10947: \%userenv,\%domdef,\%is_adv);
1.765 raeburn 10948: }
10949:
1.462 albertel 10950: $env{'user.environment'} = "$lonids/$cookie.id";
10951:
10952: if (tie(my %disk_env,'GDBM_File',"$lonids/$cookie.id",
10953: &GDBM_WRCREAT(),0640)) {
10954: &_add_to_env(\%disk_env,\%initial_env);
10955: &_add_to_env(\%disk_env,\%userenv,'environment.');
10956: &_add_to_env(\%disk_env,$userroles);
1.463 albertel 10957: if (ref($args->{'extra_env'})) {
10958: &_add_to_env(\%disk_env,$args->{'extra_env'});
10959: }
1.462 albertel 10960: untie(%disk_env);
10961: } else {
1.705 tempelho 10962: &Apache::lonnet::logthis("<span style=\"color:blue;\">WARNING: ".
10963: 'Could not create environment storage in lonauth: '.$!.'</span>');
1.462 albertel 10964: return 'error: '.$!;
10965: }
10966: }
10967: $env{'request.role'}='cm';
10968: $env{'request.role.adv'}=$env{'user.adv'};
10969: $env{'browser.type'}=$clientbrowser;
10970:
10971: return $cookie;
10972:
10973: }
10974:
10975: sub _add_to_env {
10976: my ($idf,$env_data,$prefix) = @_;
1.676 raeburn 10977: if (ref($env_data) eq 'HASH') {
10978: while (my ($key,$value) = each(%$env_data)) {
10979: $idf->{$prefix.$key} = $value;
10980: $env{$prefix.$key} = $value;
10981: }
1.462 albertel 10982: }
10983: }
10984:
1.685 tempelho 10985: # --- Get the symbolic name of a problem and the url
10986: sub get_symb {
10987: my ($request,$silent) = @_;
1.726 raeburn 10988: (my $url=$env{'form.url'}) =~ s-^https?\://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;
1.685 tempelho 10989: my $symb=($env{'form.symb'} ne '' ? $env{'form.symb'} : (&Apache::lonnet::symbread($url)));
10990: if ($symb eq '') {
10991: if (!$silent) {
10992: $request->print("Unable to handle ambiguous references:$url:.");
10993: return ();
10994: }
10995: }
10996: &Apache::lonenc::check_decrypt(\$symb);
10997: return ($symb);
10998: }
10999:
11000: # --------------------------------------------------------------Get annotation
11001:
11002: sub get_annotation {
11003: my ($symb,$enc) = @_;
11004:
11005: my $key = $symb;
11006: if (!$enc) {
11007: $key =
11008: &Apache::lonnet::clutter((&Apache::lonnet::decode_symb($symb))[2]);
11009: }
11010: my %annotation=&Apache::lonnet::get('nohist_annotations',[$key]);
11011: return $annotation{$key};
11012: }
11013:
11014: sub clean_symb {
1.731 raeburn 11015: my ($symb,$delete_enc) = @_;
1.685 tempelho 11016:
11017: &Apache::lonenc::check_decrypt(\$symb);
11018: my $enc = $env{'request.enc'};
1.731 raeburn 11019: if ($delete_enc) {
1.730 raeburn 11020: delete($env{'request.enc'});
11021: }
1.685 tempelho 11022:
11023: return ($symb,$enc);
11024: }
1.462 albertel 11025:
1.948.2.16! raeburn 11026: sub build_release_hashes {
! 11027: my ($checkparms,$checkresponsetypes,$checkcrstypes,$anonsurvey,$randomizetry) = @_;
! 11028: return unless((ref($checkparms) eq 'HASH') && (ref($checkresponsetypes) eq 'HASH') &&
! 11029: (ref($checkcrstypes) eq 'HASH') && (ref($anonsurvey) eq 'HASH') &&
! 11030: (ref($randomizetry) eq 'HASH'));
! 11031: foreach my $key (keys(%Apache::lonnet::needsrelease)) {
! 11032: my ($item,$name,$value) = split(/:/,$key);
! 11033: if ($item eq 'parameter') {
! 11034: if (ref($checkparms->{$name}) eq 'ARRAY') {
! 11035: unless(grep(/^\Q$name\E$/,@{$checkparms->{$name}})) {
! 11036: push(@{$checkparms->{$name}},$value);
! 11037: }
! 11038: } else {
! 11039: push(@{$checkparms->{$name}},$value);
! 11040: }
! 11041: } elsif ($item eq 'resourcetag') {
! 11042: if ($name eq 'responsetype') {
! 11043: $checkresponsetypes->{$value} = $Apache::lonnet::needsrelease{$key}
! 11044: }
! 11045: } elsif ($item eq 'course') {
! 11046: if ($name eq 'crstype') {
! 11047: $checkcrstypes->{$value} = $Apache::lonnet::needsrelease{$key};
! 11048: }
! 11049: }
! 11050: }
! 11051: ($anonsurvey->{major},$anonsurvey->{minor}) = split(/\./,$Apache::lonnet::needsrelease{'parameter:type:anonsurvey'});
! 11052: ($randomizetry->{major},$randomizetry->{minor}) = split(/\./,$Apache::lonnet::needsrelease{'parameter:type:randomizetry'});
! 11053: return;
! 11054: }
! 11055:
1.41 ng 11056: =pod
11057:
11058: =back
11059:
1.112 bowersj2 11060: =cut
1.41 ng 11061:
1.112 bowersj2 11062: 1;
11063: __END__;
1.41 ng 11064:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>