Annotation of loncom/interface/loncommon.pm, revision 1.882
1.10 albertel 1: # The LearningOnline Network with CAPA
1.1 albertel 2: # a pile of common routines
1.10 albertel 3: #
1.882 ! raeburn 4: # $Id: loncommon.pm,v 1.881 2009/08/06 20:40:59 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.468 raeburn 485: my ($domainfilter,$sec_element,$formname)=@_;
1.865 raeburn 486: my $crs_or_grp_alert = &mt('Please select the type of LON-CAPA entity - Course or Community - for which you wish to add/modify a user role');
1.876 raeburn 487: my $id_functions = &javascript_index_functions();
488: my $output = '
1.776 bisitz 489: <script type="text/javascript" language="JavaScript">
1.824 bisitz 490: // <![CDATA[
1.468 raeburn 491: var stdeditbrowser;'."\n";
1.876 raeburn 492:
493: $output .= <<"ENDSTDBRW";
1.377 raeburn 494: function opencrsbrowser(formname,uname,udom,desc,extra_element,multflag,crstype) {
1.91 www 495: var url = '/adm/pickcourse?';
1.876 raeburn 496: var domainfilter = getDomainFromSelectbox(formname,udom);
1.128 albertel 497: if (domainfilter != null) {
498: if (domainfilter != '') {
499: url += 'domainfilter='+domainfilter+'&';
500: }
501: }
1.91 www 502: url += 'form=' + formname + '&cnumelement='+uname+
1.187 albertel 503: '&cdomelement='+udom+
504: '&cnameelement='+desc;
1.468 raeburn 505: if (extra_element !=null && extra_element != '') {
1.594 raeburn 506: if (formname == 'rolechoice' || formname == 'studentform') {
1.468 raeburn 507: url += '&roleelement='+extra_element;
508: if (domainfilter == null || domainfilter == '') {
509: url += '&domainfilter='+extra_element;
510: }
1.234 raeburn 511: }
1.468 raeburn 512: else {
513: if (formname == 'portform') {
514: url += '&setroles='+extra_element;
1.800 raeburn 515: } else {
516: if (formname == 'rules') {
517: url += '&fixeddom='+extra_element;
518: }
1.468 raeburn 519: }
520: }
1.230 raeburn 521: }
1.872 raeburn 522: if (formname == 'ccrs') {
523: var ownername = document.forms[formid].ccuname.value;
524: var ownerdom = document.forms[formid].ccdomain.options[document.forms[formid].ccdomain.selectedIndex].value;
525: url += '&cloner='+ownername+':'+ownerdom;
526: }
1.293 raeburn 527: if (multflag !=null && multflag != '') {
528: url += '&multiple='+multflag;
529: }
1.865 raeburn 530: if (crstype == 'Course/Community') {
1.377 raeburn 531: if (formname == 'cu') {
532: crstype = document.cu.crstype.options[document.cu.crstype.selectedIndex].value;
533: if (crstype == "") {
534: alert("$crs_or_grp_alert");
535: return;
536: }
537: }
538: }
539: if (crstype !=null && crstype != '') {
540: url += '&type='+crstype;
541: }
1.102 www 542: var title = 'Course_Browser';
1.91 www 543: var options = 'scrollbars=1,resizable=1,menubar=0';
544: options += ',width=700,height=600';
545: stdeditbrowser = open(url,title,options,'1');
546: stdeditbrowser.focus();
547: }
1.876 raeburn 548: $id_functions
549: ENDSTDBRW
550: if ($sec_element ne '') {
551: $output .= &setsec_javascript($sec_element,$formname);
552: }
553: $output .= '
554: // ]]>
555: </script>';
556: return $output;
557: }
558:
559: sub javascript_index_functions {
560: return <<"ENDJS";
561:
562: function getFormIdByName(formname) {
563: for (var i=0;i<document.forms.length;i++) {
564: if (document.forms[i].name == formname) {
565: return i;
566: }
567: }
568: return -1;
569: }
570:
571: function getIndexByName(formid,item) {
572: for (var i=0;i<document.forms[formid].elements.length;i++) {
573: if (document.forms[formid].elements[i].name == item) {
574: return i;
575: }
576: }
577: return -1;
578: }
1.468 raeburn 579:
1.876 raeburn 580: function getDomainFromSelectbox(formname,udom) {
581: var userdom;
582: var formid = getFormIdByName(formname);
583: if (formid > -1) {
584: var domid = getIndexByName(formid,udom);
585: if (domid > -1) {
586: if (document.forms[formid].elements[domid].type == 'select-one') {
587: userdom=document.forms[formid].elements[domid].options[document.forms[formid].elements[domid].selectedIndex].value;
588: }
589: if (document.forms[formid].elements[domid].type == 'hidden') {
590: userdom=document.forms[formid].elements[domid].value;
1.468 raeburn 591: }
592: }
593: }
1.876 raeburn 594: return userdom;
595: }
596:
597: ENDJS
1.468 raeburn 598:
1.876 raeburn 599: }
600:
601: sub userbrowser_javascript {
602: my $id_functions = &javascript_index_functions();
603: return <<"ENDUSERBRW";
604:
1.881 raeburn 605: function openuserbrowser(formname,uname,udom,ulast,ufirst,uemail,hideudom,crsdom) {
1.876 raeburn 606: var url = '/adm/pickuser?';
607: var userdom = getDomainFromSelectbox(formname,udom);
608: if (userdom != null) {
609: if (userdom != '') {
610: url += 'srchdom='+userdom+'&';
611: }
612: }
613: url += 'form=' + formname + '&unameelement='+uname+
614: '&udomelement='+udom+
615: '&ulastelement='+ulast+
616: '&ufirstelement='+ufirst+
617: '&uemailelement='+uemail+
1.881 raeburn 618: '&hideudomelement='+hideudom+
619: '&coursedom='+crsdom;
1.876 raeburn 620: var title = 'User_Browser';
621: var options = 'scrollbars=1,resizable=1,menubar=0';
622: options += ',width=700,height=600';
623: var stdeditbrowser = open(url,title,options,'1');
624: stdeditbrowser.focus();
625: }
626:
627: function fix_domain (formname,udom,origdom) {
628: var formid = getFormIdByName(formname);
629: if (formid > -1) {
630: var domid = getIndexByName(formid,udom);
631: var hidedomid = getIndexByName(formid,origdom);
632: if (hidedomid > -1) {
633: var fixeddom = document.forms[formid].elements[hidedomid].value;
634: if (domid > -1) {
635: var slct = document.forms[formid].elements[domid];
636: if (slct.type == 'select-one') {
637: var i;
638: for (i=0;i<slct.length;i++) {
639: if (slct.options[i].value==fixeddom) { slct.selectedIndex=i; }
640: }
641: }
642: if (slct.type == 'hidden') {
643: slct.value = fixeddom;
644: }
1.468 raeburn 645: }
646: }
647: }
1.876 raeburn 648: return;
649: }
650:
651: $id_functions
652: ENDUSERBRW
1.468 raeburn 653: }
654:
655: sub setsec_javascript {
656: my ($sec_element,$formname) = @_;
657: my $setsections = qq|
658: function setSect(sectionlist) {
1.629 raeburn 659: var sectionsArray = new Array();
660: if ((sectionlist != '') && (typeof sectionlist != "undefined")) {
661: sectionsArray = sectionlist.split(",");
662: }
1.468 raeburn 663: var numSections = sectionsArray.length;
664: document.$formname.$sec_element.length = 0;
665: if (numSections == 0) {
666: document.$formname.$sec_element.multiple=false;
667: document.$formname.$sec_element.size=1;
668: document.$formname.$sec_element.options[0] = new Option('No existing sections','',false,false)
669: } else {
670: if (numSections == 1) {
671: document.$formname.$sec_element.multiple=false;
672: document.$formname.$sec_element.size=1;
673: document.$formname.$sec_element.options[0] = new Option('Select','',true,true);
674: document.$formname.$sec_element.options[1] = new Option('No section','',false,false)
675: document.$formname.$sec_element.options[2] = new Option(sectionsArray[0],sectionsArray[0],false,false);
676: } else {
677: for (var i=0; i<numSections; i++) {
678: document.$formname.$sec_element.options[i] = new Option(sectionsArray[i],sectionsArray[i],false,false)
679: }
680: document.$formname.$sec_element.multiple=true
681: if (numSections < 3) {
682: document.$formname.$sec_element.size=numSections;
683: } else {
684: document.$formname.$sec_element.size=3;
685: }
686: document.$formname.$sec_element.options[0].selected = false
687: }
688: }
1.91 www 689: }
1.468 raeburn 690: |;
691: return $setsections;
692: }
693:
1.91 www 694:
695: sub selectcourse_link {
1.377 raeburn 696: my ($form,$unameele,$udomele,$desc,$extra_element,$multflag,$selecttype)=@_;
1.871 raeburn 697: my $linktext = &mt('Select Course');
698: if ($selecttype eq 'Community') {
699: $linktext = &mt('Select Community');
700: }
1.787 bisitz 701: return '<span class="LC_nobreak">'
702: ."<a href='"
703: .'javascript:opencrsbrowser("'.$form.'","'.$unameele
704: .'","'.$udomele.'","'.$desc.'","'.$extra_element
705: .'","'.$multflag.'","'.$selecttype.'");'
1.871 raeburn 706: ."'>".$linktext.'</a>'
1.787 bisitz 707: .'</span>';
1.74 www 708: }
1.42 matthew 709:
1.653 raeburn 710: sub selectauthor_link {
711: my ($form,$udom)=@_;
712: return '<a href="javascript:openauthorbrowser('."'$form','$udom'".');">'.
713: &mt('Select Author').'</a>';
714: }
715:
1.876 raeburn 716: sub selectuser_link {
1.881 raeburn 717: my ($form,$unameelem,$domelem,$lastelem,$firstelem,$emailelem,$hdomelem,
718: $coursedom,$linktext) = @_;
1.876 raeburn 719: return '<a href="javascript:openuserbrowser('."'$form','$unameelem','$domelem',".
1.881 raeburn 720: "'$lastelem','$firstelem','$emailelem','$hdomelem','$coursedom'".
721: ');">'.$linktext.'</a>';
1.876 raeburn 722: }
723:
1.273 raeburn 724: sub check_uncheck_jscript {
725: my $jscript = <<"ENDSCRT";
726: function checkAll(field) {
727: if (field.length > 0) {
728: for (i = 0; i < field.length; i++) {
729: field[i].checked = true ;
730: }
731: } else {
732: field.checked = true
733: }
734: }
735:
736: function uncheckAll(field) {
737: if (field.length > 0) {
738: for (i = 0; i < field.length; i++) {
739: field[i].checked = false ;
1.543 albertel 740: }
741: } else {
1.273 raeburn 742: field.checked = false ;
743: }
744: }
745: ENDSCRT
746: return $jscript;
747: }
748:
1.656 www 749: sub select_timezone {
1.659 raeburn 750: my ($name,$selected,$onchange,$includeempty)=@_;
751: my $output='<select name="'.$name.'" '.$onchange.'>'."\n";
752: if ($includeempty) {
753: $output .= '<option value=""';
754: if (($selected eq '') || ($selected eq 'local')) {
755: $output .= ' selected="selected" ';
756: }
757: $output .= '> </option>';
758: }
1.657 raeburn 759: my @timezones = DateTime::TimeZone->all_names;
760: foreach my $tzone (@timezones) {
761: $output.= '<option value="'.$tzone.'"';
762: if ($tzone eq $selected) {
763: $output.=' selected="selected"';
764: }
765: $output.=">$tzone</option>\n";
1.656 www 766: }
767: $output.="</select>";
768: return $output;
769: }
1.273 raeburn 770:
1.687 raeburn 771: sub select_datelocale {
772: my ($name,$selected,$onchange,$includeempty)=@_;
773: my $output='<select name="'.$name.'" '.$onchange.'>'."\n";
774: if ($includeempty) {
775: $output .= '<option value=""';
776: if ($selected eq '') {
777: $output .= ' selected="selected" ';
778: }
779: $output .= '> </option>';
780: }
781: my (@possibles,%locale_names);
782: my @locales = DateTime::Locale::Catalog::Locales;
783: foreach my $locale (@locales) {
784: if (ref($locale) eq 'HASH') {
785: my $id = $locale->{'id'};
786: if ($id ne '') {
787: my $en_terr = $locale->{'en_territory'};
788: my $native_terr = $locale->{'native_territory'};
1.695 raeburn 789: my @languages = &Apache::lonlocal::preferred_languages();
1.687 raeburn 790: if (grep(/^en$/,@languages) || !@languages) {
791: if ($en_terr ne '') {
792: $locale_names{$id} = '('.$en_terr.')';
793: } elsif ($native_terr ne '') {
794: $locale_names{$id} = $native_terr;
795: }
796: } else {
797: if ($native_terr ne '') {
798: $locale_names{$id} = $native_terr.' ';
799: } elsif ($en_terr ne '') {
800: $locale_names{$id} = '('.$en_terr.')';
801: }
802: }
803: push (@possibles,$id);
804: }
805: }
806: }
807: foreach my $item (sort(@possibles)) {
808: $output.= '<option value="'.$item.'"';
809: if ($item eq $selected) {
810: $output.=' selected="selected"';
811: }
812: $output.=">$item";
813: if ($locale_names{$item} ne '') {
814: $output.=" $locale_names{$item}</option>\n";
815: }
816: $output.="</option>\n";
817: }
818: $output.="</select>";
819: return $output;
820: }
821:
1.792 raeburn 822: sub select_language {
823: my ($name,$selected,$includeempty) = @_;
824: my %langchoices;
825: if ($includeempty) {
826: %langchoices = ('' => 'No language preference');
827: }
828: foreach my $id (&languageids()) {
829: my $code = &supportedlanguagecode($id);
830: if ($code) {
831: $langchoices{$code} = &plainlanguagedescription($id);
832: }
833: }
834: return &select_form($selected,$name,%langchoices);
835: }
836:
1.42 matthew 837: =pod
1.36 matthew 838:
1.648 raeburn 839: =item * &linked_select_forms(...)
1.36 matthew 840:
841: linked_select_forms returns a string containing a <script></script> block
842: and html for two <select> menus. The select menus will be linked in that
843: changing the value of the first menu will result in new values being placed
844: in the second menu. The values in the select menu will appear in alphabetical
1.609 raeburn 845: order unless a defined order is provided.
1.36 matthew 846:
847: linked_select_forms takes the following ordered inputs:
848:
849: =over 4
850:
1.112 bowersj2 851: =item * $formname, the name of the <form> tag
1.36 matthew 852:
1.112 bowersj2 853: =item * $middletext, the text which appears between the <select> tags
1.36 matthew 854:
1.112 bowersj2 855: =item * $firstdefault, the default value for the first menu
1.36 matthew 856:
1.112 bowersj2 857: =item * $firstselectname, the name of the first <select> tag
1.36 matthew 858:
1.112 bowersj2 859: =item * $secondselectname, the name of the second <select> tag
1.36 matthew 860:
1.112 bowersj2 861: =item * $hashref, a reference to a hash containing the data for the menus.
1.36 matthew 862:
1.609 raeburn 863: =item * $menuorder, the order of values in the first menu
864:
1.41 ng 865: =back
866:
1.36 matthew 867: Below is an example of such a hash. Only the 'text', 'default', and
868: 'select2' keys must appear as stated. keys(%menu) are the possible
869: values for the first select menu. The text that coincides with the
1.41 ng 870: first menu value is given in $menu{$choice1}->{'text'}. The values
1.36 matthew 871: and text for the second menu are given in the hash pointed to by
872: $menu{$choice1}->{'select2'}.
873:
1.112 bowersj2 874: my %menu = ( A1 => { text =>"Choice A1" ,
875: default => "B3",
876: select2 => {
877: B1 => "Choice B1",
878: B2 => "Choice B2",
879: B3 => "Choice B3",
880: B4 => "Choice B4"
1.609 raeburn 881: },
882: order => ['B4','B3','B1','B2'],
1.112 bowersj2 883: },
884: A2 => { text =>"Choice A2" ,
885: default => "C2",
886: select2 => {
887: C1 => "Choice C1",
888: C2 => "Choice C2",
889: C3 => "Choice C3"
1.609 raeburn 890: },
891: order => ['C2','C1','C3'],
1.112 bowersj2 892: },
893: A3 => { text =>"Choice A3" ,
894: default => "D6",
895: select2 => {
896: D1 => "Choice D1",
897: D2 => "Choice D2",
898: D3 => "Choice D3",
899: D4 => "Choice D4",
900: D5 => "Choice D5",
901: D6 => "Choice D6",
902: D7 => "Choice D7"
1.609 raeburn 903: },
904: order => ['D4','D3','D2','D1','D7','D6','D5'],
1.112 bowersj2 905: }
906: );
1.36 matthew 907:
908: =cut
909:
910: sub linked_select_forms {
911: my ($formname,
912: $middletext,
913: $firstdefault,
914: $firstselectname,
915: $secondselectname,
1.609 raeburn 916: $hashref,
917: $menuorder,
1.36 matthew 918: ) = @_;
919: my $second = "document.$formname.$secondselectname";
920: my $first = "document.$formname.$firstselectname";
921: # output the javascript to do the changing
922: my $result = '';
1.776 bisitz 923: $result.='<script type="text/javascript" language="JavaScript">'."\n";
1.824 bisitz 924: $result.="// <![CDATA[\n";
1.36 matthew 925: $result.="var select2data = new Object();\n";
926: $" = '","';
927: my $debug = '';
928: foreach my $s1 (sort(keys(%$hashref))) {
929: $result.="select2data.d_$s1 = new Object();\n";
930: $result.="select2data.d_$s1.def = new String('".
931: $hashref->{$s1}->{'default'}."');\n";
1.609 raeburn 932: $result.="select2data.d_$s1.values = new Array(";
1.36 matthew 933: my @s2values = sort(keys( %{ $hashref->{$s1}->{'select2'} } ));
1.609 raeburn 934: if (ref($hashref->{$s1}->{'order'}) eq 'ARRAY') {
935: @s2values = @{$hashref->{$s1}->{'order'}};
936: }
1.36 matthew 937: $result.="\"@s2values\");\n";
938: $result.="select2data.d_$s1.texts = new Array(";
939: my @s2texts;
940: foreach my $value (@s2values) {
941: push @s2texts, $hashref->{$s1}->{'select2'}->{$value};
942: }
943: $result.="\"@s2texts\");\n";
944: }
945: $"=' ';
946: $result.= <<"END";
947:
948: function select1_changed() {
949: // Determine new choice
950: var newvalue = "d_" + $first.value;
951: // update select2
952: var values = select2data[newvalue].values;
953: var texts = select2data[newvalue].texts;
954: var select2def = select2data[newvalue].def;
955: var i;
956: // out with the old
957: for (i = 0; i < $second.options.length; i++) {
958: $second.options[i] = null;
959: }
960: // in with the nuclear
961: for (i=0;i<values.length; i++) {
962: $second.options[i] = new Option(values[i]);
1.143 matthew 963: $second.options[i].value = values[i];
1.36 matthew 964: $second.options[i].text = texts[i];
965: if (values[i] == select2def) {
966: $second.options[i].selected = true;
967: }
968: }
969: }
1.824 bisitz 970: // ]]>
1.36 matthew 971: </script>
972: END
973: # output the initial values for the selection lists
974: $result .= "<select size=\"1\" name=\"$firstselectname\" onchange=\"select1_changed()\">\n";
1.609 raeburn 975: my @order = sort(keys(%{$hashref}));
976: if (ref($menuorder) eq 'ARRAY') {
977: @order = @{$menuorder};
978: }
979: foreach my $value (@order) {
1.36 matthew 980: $result.=" <option value=\"$value\" ";
1.253 albertel 981: $result.=" selected=\"selected\" " if ($value eq $firstdefault);
1.119 www 982: $result.=">".&mt($hashref->{$value}->{'text'})."</option>\n";
1.36 matthew 983: }
984: $result .= "</select>\n";
985: my %select2 = %{$hashref->{$firstdefault}->{'select2'}};
986: $result .= $middletext;
987: $result .= "<select size=\"1\" name=\"$secondselectname\">\n";
988: my $seconddefault = $hashref->{$firstdefault}->{'default'};
1.609 raeburn 989:
990: my @secondorder = sort(keys(%select2));
991: if (ref($hashref->{$firstdefault}->{'order'}) eq 'ARRAY') {
992: @secondorder = @{$hashref->{$firstdefault}->{'order'}};
993: }
994: foreach my $value (@secondorder) {
1.36 matthew 995: $result.=" <option value=\"$value\" ";
1.253 albertel 996: $result.=" selected=\"selected\" " if ($value eq $seconddefault);
1.119 www 997: $result.=">".&mt($select2{$value})."</option>\n";
1.36 matthew 998: }
999: $result .= "</select>\n";
1000: # return $debug;
1001: return $result;
1002: } # end of sub linked_select_forms {
1003:
1.45 matthew 1004: =pod
1.44 bowersj2 1005:
1.648 raeburn 1006: =item * &help_open_topic($topic,$text,$stayOnPage,$width,$height)
1.44 bowersj2 1007:
1.112 bowersj2 1008: Returns a string corresponding to an HTML link to the given help
1009: $topic, where $topic corresponds to the name of a .tex file in
1010: /home/httpd/html/adm/help/tex, with underscores replaced by
1011: spaces.
1012:
1013: $text will optionally be linked to the same topic, allowing you to
1014: link text in addition to the graphic. If you do not want to link
1015: text, but wish to specify one of the later parameters, pass an
1016: empty string.
1017:
1018: $stayOnPage is a value that will be interpreted as a boolean. If true,
1019: the link will not open a new window. If false, the link will open
1020: a new window using Javascript. (Default is false.)
1021:
1022: $width and $height are optional numerical parameters that will
1023: override the width and height of the popped up window, which may
1024: be useful for certain help topics with big pictures included.
1.44 bowersj2 1025:
1026: =cut
1027:
1028: sub help_open_topic {
1.48 bowersj2 1029: my ($topic, $text, $stayOnPage, $width, $height) = @_;
1030: $text = "" if (not defined $text);
1.44 bowersj2 1031: $stayOnPage = 0 if (not defined $stayOnPage);
1032: $width = 350 if (not defined $width);
1033: $height = 400 if (not defined $height);
1034: my $filename = $topic;
1035: $filename =~ s/ /_/g;
1036:
1.48 bowersj2 1037: my $template = "";
1038: my $link;
1.572 banghart 1039:
1.159 www 1040: $topic=~s/\W/\_/g;
1.44 bowersj2 1041:
1.572 banghart 1042: if (!$stayOnPage) {
1.72 bowersj2 1043: $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 1044: } else {
1.48 bowersj2 1045: $link = "/adm/help/${filename}.hlp";
1046: }
1047:
1048: # Add the text
1.755 neumanie 1049: if ($text ne "") {
1.763 bisitz 1050: $template.='<span class="LC_help_open_topic">'
1051: .'<a target="_top" href="'.$link.'">'
1052: .$text.'</a>';
1.48 bowersj2 1053: }
1054:
1.763 bisitz 1055: # (Always) Add the graphic
1.179 matthew 1056: my $title = &mt('Online Help');
1.667 raeburn 1057: my $helpicon=&lonhttpdurl("/adm/help/help.png");
1.763 bisitz 1058: $template.=' <a target="_top" href="'.$link.'" title="'.$title.'">'
1059: .'<img src="'.$helpicon.'" border="0"'
1060: .' alt="'.&mt('Help: [_1]',$topic).'"'
1.783 amueller 1061: .' title="'.$title.'"'
1.763 bisitz 1062: .' /></a>';
1063: if ($text ne "") {
1064: $template.='</span>';
1065: }
1.44 bowersj2 1066: return $template;
1067:
1.106 bowersj2 1068: }
1069:
1070: # This is a quicky function for Latex cheatsheet editing, since it
1071: # appears in at least four places
1072: sub helpLatexCheatsheet {
1.732 raeburn 1073: my ($topic,$text,$not_author) = @_;
1074: my $out;
1.106 bowersj2 1075: my $addOther = '';
1.732 raeburn 1076: if ($topic) {
1.763 bisitz 1077: $addOther = '<span>'.&Apache::loncommon::help_open_topic($topic,&mt($text),
1078: undef, undef, 600).
1079: '</span> ';
1080: }
1081: $out = '<span>' # Start cheatsheet
1082: .$addOther
1083: .'<span>'
1084: .&Apache::loncommon::help_open_topic('Greek_Symbols',&mt('Greek Symbols'),
1085: undef,undef,600)
1086: .'</span> <span>'
1087: .&Apache::loncommon::help_open_topic('Other_Symbols',&mt('Other Symbols'),
1088: undef,undef,600)
1089: .'</span>';
1.732 raeburn 1090: unless ($not_author) {
1.763 bisitz 1091: $out .= ' <span>'
1092: .&Apache::loncommon::help_open_topic('Authoring_Output_Tags',&mt('Output Tags'),
1093: undef,undef,600)
1094: .'</span>';
1.732 raeburn 1095: }
1.763 bisitz 1096: $out .= '</span>'; # End cheatsheet
1.732 raeburn 1097: return $out;
1.172 www 1098: }
1099:
1.430 albertel 1100: sub general_help {
1101: my $helptopic='Student_Intro';
1102: if ($env{'request.role'}=~/^(ca|au)/) {
1103: $helptopic='Authoring_Intro';
1104: } elsif ($env{'request.role'}=~/^cc/) {
1105: $helptopic='Course_Coordination_Intro';
1.672 raeburn 1106: } elsif ($env{'request.role'}=~/^dc/) {
1107: $helptopic='Domain_Coordination_Intro';
1.430 albertel 1108: }
1109: return $helptopic;
1110: }
1111:
1112: sub update_help_link {
1113: my ($topic,$component_help,$faq,$bug,$stayOnPage) = @_;
1114: my $origurl = $ENV{'REQUEST_URI'};
1115: $origurl=~s|^/~|/priv/|;
1116: my $timestamp = time;
1117: foreach my $datum (\$topic,\$component_help,\$faq,\$bug,\$origurl) {
1118: $$datum = &escape($$datum);
1119: }
1120:
1121: my $banner_link = "/adm/helpmenu?page=banner&topic=$topic&component_help=$component_help&faq=$faq&bug=$bug&origurl=$origurl&stamp=$timestamp&stayonpage=$stayOnPage";
1122: my $output .= <<"ENDOUTPUT";
1123: <script type="text/javascript">
1.824 bisitz 1124: // <![CDATA[
1.430 albertel 1125: banner_link = '$banner_link';
1.824 bisitz 1126: // ]]>
1.430 albertel 1127: </script>
1128: ENDOUTPUT
1129: return $output;
1130: }
1131:
1132: # now just updates the help link and generates a blue icon
1.193 raeburn 1133: sub help_open_menu {
1.430 albertel 1134: my ($topic,$component_help,$faq,$bug,$stayOnPage,$width,$height,$text)
1.552 banghart 1135: = @_;
1.430 albertel 1136: $stayOnPage = 0 if (not defined $stayOnPage);
1.572 banghart 1137: # only use pop-up help (stayOnPage == 0)
1.552 banghart 1138: # if environment.remote is on (using remote control UI)
1.798 tempelho 1139: if ($env{'environment.remote'} eq 'off' ) {
1.552 banghart 1140: $stayOnPage=1;
1.430 albertel 1141: }
1142: my $output;
1143: if ($component_help) {
1144: if (!$text) {
1145: $output=&help_open_topic($component_help,undef,$stayOnPage,
1146: $width,$height);
1147: } else {
1148: my $help_text;
1149: $help_text=&unescape($topic);
1150: $output='<table><tr><td>'.
1151: &help_open_topic($component_help,$help_text,$stayOnPage,
1152: $width,$height).'</td></tr></table>';
1153: }
1154: }
1155: my $banner_link = &update_help_link($topic,$component_help,$faq,$bug,$stayOnPage);
1156: return $output.$banner_link;
1157: }
1158:
1159: sub top_nav_help {
1160: my ($text) = @_;
1.436 albertel 1161: $text = &mt($text);
1.572 banghart 1162: my $stay_on_page =
1.798 tempelho 1163: ($env{'environment.remote'} eq 'off' );
1.572 banghart 1164: my $link = ($stay_on_page) ? "javascript:helpMenu('display')"
1.436 albertel 1165: : "javascript:helpMenu('open')";
1.572 banghart 1166: my $banner_link = &update_help_link(undef,undef,undef,undef,$stay_on_page);
1.436 albertel 1167:
1.201 raeburn 1168: my $title = &mt('Get help');
1.436 albertel 1169:
1170: return <<"END";
1171: $banner_link
1172: <a href="$link" title="$title">$text</a>
1173: END
1174: }
1175:
1176: sub help_menu_js {
1177: my ($text) = @_;
1178:
1179: my $stayOnPage =
1.798 tempelho 1180: ($env{'environment.remote'} eq 'off' );
1.436 albertel 1181:
1182: my $width = 620;
1183: my $height = 600;
1.430 albertel 1184: my $helptopic=&general_help();
1185: my $details_link = '/adm/help/'.$helptopic.'.hlp';
1.261 albertel 1186: my $nothing=&Apache::lonhtmlcommon::javascript_nothing();
1.331 albertel 1187: my $start_page =
1188: &Apache::loncommon::start_page('Help Menu', undef,
1189: {'frameset' => 1,
1190: 'js_ready' => 1,
1191: 'add_entries' => {
1192: 'border' => '0',
1.579 raeburn 1193: 'rows' => "110,*",},});
1.331 albertel 1194: my $end_page =
1195: &Apache::loncommon::end_page({'frameset' => 1,
1196: 'js_ready' => 1,});
1197:
1.436 albertel 1198: my $template .= <<"ENDTEMPLATE";
1199: <script type="text/javascript">
1.877 bisitz 1200: // <![CDATA[
1.253 albertel 1201: // <!-- BEGIN LON-CAPA Internal
1.430 albertel 1202: var banner_link = '';
1.243 raeburn 1203: function helpMenu(target) {
1204: var caller = this;
1205: if (target == 'open') {
1206: var newWindow = null;
1207: try {
1.262 albertel 1208: newWindow = window.open($nothing,"helpmenu","HEIGHT=$height,WIDTH=$width,resizable=yes,scrollbars=yes" )
1.243 raeburn 1209: }
1210: catch(error) {
1211: writeHelp(caller);
1212: return;
1213: }
1214: if (newWindow) {
1215: caller = newWindow;
1216: }
1.193 raeburn 1217: }
1.243 raeburn 1218: writeHelp(caller);
1219: return;
1220: }
1221: function writeHelp(caller) {
1.430 albertel 1222: caller.document.writeln('$start_page<frame name="bannerframe" src="'+banner_link+'" /><frame name="bodyframe" src="$details_link" /> $end_page')
1.243 raeburn 1223: caller.document.close()
1224: caller.focus()
1.193 raeburn 1225: }
1.877 bisitz 1226: // END LON-CAPA Internal -->
1.253 albertel 1227: // ]]>
1.436 albertel 1228: </script>
1.193 raeburn 1229: ENDTEMPLATE
1230: return $template;
1231: }
1232:
1.172 www 1233: sub help_open_bug {
1234: my ($topic, $text, $stayOnPage, $width, $height) = @_;
1.258 albertel 1235: unless ($env{'user.adv'}) { return ''; }
1.172 www 1236: unless ($Apache::lonnet::perlvar{'BugzillaHost'}) { return ''; }
1237: $text = "" if (not defined $text);
1238: $stayOnPage = 0 if (not defined $stayOnPage);
1.798 tempelho 1239: if ($env{'environment.remote'} eq 'off' ) {
1.172 www 1240: $stayOnPage=1;
1241: }
1.184 albertel 1242: $width = 600 if (not defined $width);
1243: $height = 600 if (not defined $height);
1.172 www 1244:
1245: $topic=~s/\W+/\+/g;
1246: my $link='';
1247: my $template='';
1.379 albertel 1248: my $url=$Apache::lonnet::perlvar{'BugzillaHost'}.'enter_bug.cgi?product=LON-CAPA&bug_file_loc='.
1249: &escape($ENV{'REQUEST_URI'}).'&component='.$topic;
1.172 www 1250: if (!$stayOnPage)
1251: {
1252: $link = "javascript:void(open('$url', 'Bugzilla', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))";
1253: }
1254: else
1255: {
1256: $link = $url;
1257: }
1258: # Add the text
1259: if ($text ne "")
1260: {
1261: $template .=
1262: "<table bgcolor='#AA3333' cellspacing='1' cellpadding='1' border='0'><tr>".
1.705 tempelho 1263: "<td bgcolor='#FF5555'><a target=\"_top\" href=\"$link\"><span style=\"color:#FFFFFF;font-size:10pt;\">$text</span></a>";
1.172 www 1264: }
1265:
1266: # Add the graphic
1.179 matthew 1267: my $title = &mt('Report a Bug');
1.215 albertel 1268: my $bugicon=&lonhttpdurl("/adm/lonMisc/smallBug.gif");
1.172 www 1269: $template .= <<"ENDTEMPLATE";
1.436 albertel 1270: <a target="_top" href="$link" title="$title"><img src="$bugicon" border="0" alt="(Bug: $topic)" /></a>
1.172 www 1271: ENDTEMPLATE
1272: if ($text ne '') { $template.='</td></tr></table>' };
1273: return $template;
1274:
1275: }
1276:
1277: sub help_open_faq {
1278: my ($topic, $text, $stayOnPage, $width, $height) = @_;
1.258 albertel 1279: unless ($env{'user.adv'}) { return ''; }
1.172 www 1280: unless ($Apache::lonnet::perlvar{'FAQHost'}) { return ''; }
1281: $text = "" if (not defined $text);
1282: $stayOnPage = 0 if (not defined $stayOnPage);
1.798 tempelho 1283: if ($env{'environment.remote'} eq 'off' ) {
1.172 www 1284: $stayOnPage=1;
1285: }
1286: $width = 350 if (not defined $width);
1287: $height = 400 if (not defined $height);
1288:
1289: $topic=~s/\W+/\+/g;
1290: my $link='';
1291: my $template='';
1292: my $url=$Apache::lonnet::perlvar{'FAQHost'}.'/fom/cache/'.$topic.'.html';
1293: if (!$stayOnPage)
1294: {
1295: $link = "javascript:void(open('$url', 'FAQ-O-Matic', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))";
1296: }
1297: else
1298: {
1299: $link = $url;
1300: }
1301:
1302: # Add the text
1303: if ($text ne "")
1304: {
1305: $template .=
1.173 www 1306: "<table bgcolor='#337733' cellspacing='1' cellpadding='1' border='0'><tr>".
1.705 tempelho 1307: "<td bgcolor='#448844'><a target=\"_top\" href=\"$link\"><span style=\"color:#FFFFFF; font-size:10pt;\">$text</span></a>";
1.172 www 1308: }
1309:
1310: # Add the graphic
1.179 matthew 1311: my $title = &mt('View the FAQ');
1.215 albertel 1312: my $faqicon=&lonhttpdurl("/adm/lonMisc/smallFAQ.gif");
1.172 www 1313: $template .= <<"ENDTEMPLATE";
1.436 albertel 1314: <a target="_top" href="$link" title="$title"><img src="$faqicon" border="0" alt="(FAQ: $topic)" /></a>
1.172 www 1315: ENDTEMPLATE
1316: if ($text ne '') { $template.='</td></tr></table>' };
1317: return $template;
1318:
1.44 bowersj2 1319: }
1.37 matthew 1320:
1.180 matthew 1321: ###############################################################
1322: ###############################################################
1323:
1.45 matthew 1324: =pod
1325:
1.648 raeburn 1326: =item * &change_content_javascript():
1.256 matthew 1327:
1328: This and the next function allow you to create small sections of an
1329: otherwise static HTML page that you can update on the fly with
1330: Javascript, even in Netscape 4.
1331:
1332: The Javascript fragment returned by this function (no E<lt>scriptE<gt> tag)
1333: must be written to the HTML page once. It will prove the Javascript
1334: function "change(name, content)". Calling the change function with the
1335: name of the section
1336: you want to update, matching the name passed to C<changable_area>, and
1337: the new content you want to put in there, will put the content into
1338: that area.
1339:
1340: B<Note>: Netscape 4 only reserves enough space for the changable area
1341: to contain room for the original contents. You need to "make space"
1342: for whatever changes you wish to make, and be B<sure> to check your
1343: code in Netscape 4. This feature in Netscape 4 is B<not> powerful;
1344: it's adequate for updating a one-line status display, but little more.
1345: This script will set the space to 100% width, so you only need to
1346: worry about height in Netscape 4.
1347:
1348: Modern browsers are much less limiting, and if you can commit to the
1349: user not using Netscape 4, this feature may be used freely with
1350: pretty much any HTML.
1351:
1352: =cut
1353:
1354: sub change_content_javascript {
1355: # If we're on Netscape 4, we need to use Layer-based code
1.258 albertel 1356: if ($env{'browser.type'} eq 'netscape' &&
1357: $env{'browser.version'} =~ /^4\./) {
1.256 matthew 1358: return (<<NETSCAPE4);
1359: function change(name, content) {
1360: doc = document.layers[name+"___escape"].layers[0].document;
1361: doc.open();
1362: doc.write(content);
1363: doc.close();
1364: }
1365: NETSCAPE4
1366: } else {
1367: # Otherwise, we need to use semi-standards-compliant code
1368: # (technically, "innerHTML" isn't standard but the equivalent
1369: # is really scary, and every useful browser supports it
1370: return (<<DOMBASED);
1371: function change(name, content) {
1372: element = document.getElementById(name);
1373: element.innerHTML = content;
1374: }
1375: DOMBASED
1376: }
1377: }
1378:
1379: =pod
1380:
1.648 raeburn 1381: =item * &changable_area($name,$origContent):
1.256 matthew 1382:
1383: This provides a "changable area" that can be modified on the fly via
1384: the Javascript code provided in C<change_content_javascript>. $name is
1385: the name you will use to reference the area later; do not repeat the
1386: same name on a given HTML page more then once. $origContent is what
1387: the area will originally contain, which can be left blank.
1388:
1389: =cut
1390:
1391: sub changable_area {
1392: my ($name, $origContent) = @_;
1393:
1.258 albertel 1394: if ($env{'browser.type'} eq 'netscape' &&
1395: $env{'browser.version'} =~ /^4\./) {
1.256 matthew 1396: # If this is netscape 4, we need to use the Layer tag
1397: return "<ilayer width='100%' id='${name}___escape' overflow='none'><layer width='100%' id='$name' overflow='none'>$origContent</layer></ilayer>";
1398: } else {
1399: return "<span id='$name'>$origContent</span>";
1400: }
1401: }
1402:
1403: =pod
1404:
1.648 raeburn 1405: =item * &viewport_geometry_js
1.590 raeburn 1406:
1407: Provides javascript object (Geometry) which can provide information about the viewport geometry for the client browser.
1408:
1409: =cut
1410:
1411:
1412: sub viewport_geometry_js {
1413: return <<"GEOMETRY";
1414: var Geometry = {};
1415: function init_geometry() {
1416: if (Geometry.init) { return };
1417: Geometry.init=1;
1418: if (window.innerHeight) {
1419: Geometry.getViewportHeight = function() { return window.innerHeight; };
1420: Geometry.getViewportWidth = function() { return window.innerWidth; };
1421: Geometry.getHorizontalScroll = function() { return window.pageXOffset; };
1422: Geometry.getVerticalScroll = function() { return window.pageYOffset; };
1423: }
1424: else if (document.documentElement && document.documentElement.clientHeight) {
1425: Geometry.getViewportHeight =
1426: function() { return document.documentElement.clientHeight; };
1427: Geometry.getViewportWidth =
1428: function() { return document.documentElement.clientWidth; };
1429:
1430: Geometry.getHorizontalScroll =
1431: function() { return document.documentElement.scrollLeft; };
1432: Geometry.getVerticalScroll =
1433: function() { return document.documentElement.scrollTop; };
1434: }
1435: else if (document.body.clientHeight) {
1436: Geometry.getViewportHeight =
1437: function() { return document.body.clientHeight; };
1438: Geometry.getViewportWidth =
1439: function() { return document.body.clientWidth; };
1440: Geometry.getHorizontalScroll =
1441: function() { return document.body.scrollLeft; };
1442: Geometry.getVerticalScroll =
1443: function() { return document.body.scrollTop; };
1444: }
1445: }
1446:
1447: GEOMETRY
1448: }
1449:
1450: =pod
1451:
1.648 raeburn 1452: =item * &viewport_size_js()
1.590 raeburn 1453:
1454: 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.
1455:
1456: =cut
1457:
1458: sub viewport_size_js {
1459: my $geometry = &viewport_geometry_js();
1460: return <<"DIMS";
1461:
1462: $geometry
1463:
1464: function getViewportDims(width,height) {
1465: init_geometry();
1466: width.value = Geometry.getViewportWidth();
1467: height.value = Geometry.getViewportHeight();
1468: return;
1469: }
1470:
1471: DIMS
1472: }
1473:
1474: =pod
1475:
1.648 raeburn 1476: =item * &resize_textarea_js()
1.565 albertel 1477:
1478: emits the needed javascript to resize a textarea to be as big as possible
1479:
1480: creates a function resize_textrea that takes two IDs first should be
1481: the id of the element to resize, second should be the id of a div that
1482: surrounds everything that comes after the textarea, this routine needs
1483: to be attached to the <body> for the onload and onresize events.
1484:
1.648 raeburn 1485: =back
1.565 albertel 1486:
1487: =cut
1488:
1489: sub resize_textarea_js {
1.590 raeburn 1490: my $geometry = &viewport_geometry_js();
1.565 albertel 1491: return <<"RESIZE";
1492: <script type="text/javascript">
1.824 bisitz 1493: // <![CDATA[
1.590 raeburn 1494: $geometry
1.565 albertel 1495:
1.588 albertel 1496: function getX(element) {
1497: var x = 0;
1498: while (element) {
1499: x += element.offsetLeft;
1500: element = element.offsetParent;
1501: }
1502: return x;
1503: }
1504: function getY(element) {
1505: var y = 0;
1506: while (element) {
1507: y += element.offsetTop;
1508: element = element.offsetParent;
1509: }
1510: return y;
1511: }
1512:
1513:
1.565 albertel 1514: function resize_textarea(textarea_id,bottom_id) {
1515: init_geometry();
1516: var textarea = document.getElementById(textarea_id);
1517: //alert(textarea);
1518:
1.588 albertel 1519: var textarea_top = getY(textarea);
1.565 albertel 1520: var textarea_height = textarea.offsetHeight;
1521: var bottom = document.getElementById(bottom_id);
1.588 albertel 1522: var bottom_top = getY(bottom);
1.565 albertel 1523: var bottom_height = bottom.offsetHeight;
1524: var window_height = Geometry.getViewportHeight();
1.588 albertel 1525: var fudge = 23;
1.565 albertel 1526: var new_height = window_height-fudge-textarea_top-bottom_height;
1527: if (new_height < 300) {
1528: new_height = 300;
1529: }
1530: textarea.style.height=new_height+'px';
1531: }
1.824 bisitz 1532: // ]]>
1.565 albertel 1533: </script>
1534: RESIZE
1535:
1536: }
1537:
1538: =pod
1539:
1.256 matthew 1540: =head1 Excel and CSV file utility routines
1541:
1542: =over 4
1543:
1544: =cut
1545:
1546: ###############################################################
1547: ###############################################################
1548:
1549: =pod
1550:
1.648 raeburn 1551: =item * &csv_translate($text)
1.37 matthew 1552:
1.185 www 1553: Translate $text to allow it to be output as a 'comma separated values'
1.37 matthew 1554: format.
1555:
1556: =cut
1557:
1.180 matthew 1558: ###############################################################
1559: ###############################################################
1.37 matthew 1560: sub csv_translate {
1561: my $text = shift;
1562: $text =~ s/\"/\"\"/g;
1.209 albertel 1563: $text =~ s/\n/ /g;
1.37 matthew 1564: return $text;
1565: }
1.180 matthew 1566:
1567: ###############################################################
1568: ###############################################################
1569:
1570: =pod
1571:
1.648 raeburn 1572: =item * &define_excel_formats()
1.180 matthew 1573:
1574: Define some commonly used Excel cell formats.
1575:
1576: Currently supported formats:
1577:
1578: =over 4
1579:
1580: =item header
1581:
1582: =item bold
1583:
1584: =item h1
1585:
1586: =item h2
1587:
1588: =item h3
1589:
1.256 matthew 1590: =item h4
1591:
1592: =item i
1593:
1.180 matthew 1594: =item date
1595:
1596: =back
1597:
1598: Inputs: $workbook
1599:
1600: Returns: $format, a hash reference.
1601:
1602: =cut
1603:
1604: ###############################################################
1605: ###############################################################
1606: sub define_excel_formats {
1607: my ($workbook) = @_;
1608: my $format;
1609: $format->{'header'} = $workbook->add_format(bold => 1,
1610: bottom => 1,
1611: align => 'center');
1612: $format->{'bold'} = $workbook->add_format(bold=>1);
1613: $format->{'h1'} = $workbook->add_format(bold=>1, size=>18);
1614: $format->{'h2'} = $workbook->add_format(bold=>1, size=>16);
1615: $format->{'h3'} = $workbook->add_format(bold=>1, size=>14);
1.255 matthew 1616: $format->{'h4'} = $workbook->add_format(bold=>1, size=>12);
1.246 matthew 1617: $format->{'i'} = $workbook->add_format(italic=>1);
1.180 matthew 1618: $format->{'date'} = $workbook->add_format(num_format=>
1.207 matthew 1619: 'mm/dd/yyyy hh:mm:ss');
1.180 matthew 1620: return $format;
1621: }
1622:
1623: ###############################################################
1624: ###############################################################
1.113 bowersj2 1625:
1626: =pod
1627:
1.648 raeburn 1628: =item * &create_workbook()
1.255 matthew 1629:
1630: Create an Excel worksheet. If it fails, output message on the
1631: request object and return undefs.
1632:
1633: Inputs: Apache request object
1634:
1635: Returns (undef) on failure,
1636: Excel worksheet object, scalar with filename, and formats
1637: from &Apache::loncommon::define_excel_formats on success
1638:
1639: =cut
1640:
1641: ###############################################################
1642: ###############################################################
1643: sub create_workbook {
1644: my ($r) = @_;
1645: #
1646: # Create the excel spreadsheet
1647: my $filename = '/prtspool/'.
1.258 albertel 1648: $env{'user.name'}.'_'.$env{'user.domain'}.'_'.
1.255 matthew 1649: time.'_'.rand(1000000000).'.xls';
1650: my $workbook = Spreadsheet::WriteExcel->new('/home/httpd'.$filename);
1651: if (! defined($workbook)) {
1652: $r->log_error("Error creating excel spreadsheet $filename: $!");
1653: $r->print('<p>'.&mt("Unable to create new Excel file. ".
1654: "This error has been logged. ".
1655: "Please alert your LON-CAPA administrator").
1656: '</p>');
1657: return (undef);
1658: }
1659: #
1660: $workbook->set_tempdir('/home/httpd/perl/tmp');
1661: #
1662: my $format = &Apache::loncommon::define_excel_formats($workbook);
1663: return ($workbook,$filename,$format);
1664: }
1665:
1666: ###############################################################
1667: ###############################################################
1668:
1669: =pod
1670:
1.648 raeburn 1671: =item * &create_text_file()
1.113 bowersj2 1672:
1.542 raeburn 1673: Create a file to write to and eventually make available to the user.
1.256 matthew 1674: If file creation fails, outputs an error message on the request object and
1675: return undefs.
1.113 bowersj2 1676:
1.256 matthew 1677: Inputs: Apache request object, and file suffix
1.113 bowersj2 1678:
1.256 matthew 1679: Returns (undef) on failure,
1680: Filehandle and filename on success.
1.113 bowersj2 1681:
1682: =cut
1683:
1.256 matthew 1684: ###############################################################
1685: ###############################################################
1686: sub create_text_file {
1687: my ($r,$suffix) = @_;
1688: if (! defined($suffix)) { $suffix = 'txt'; };
1689: my $fh;
1690: my $filename = '/prtspool/'.
1.258 albertel 1691: $env{'user.name'}.'_'.$env{'user.domain'}.'_'.
1.256 matthew 1692: time.'_'.rand(1000000000).'.'.$suffix;
1693: $fh = Apache::File->new('>/home/httpd'.$filename);
1694: if (! defined($fh)) {
1695: $r->log_error("Couldn't open $filename for output $!");
1.683 bisitz 1696: $r->print(&mt('Problems occurred in creating the output file. '
1697: .'This error has been logged. '
1698: .'Please alert your LON-CAPA administrator.'));
1.113 bowersj2 1699: }
1.256 matthew 1700: return ($fh,$filename)
1.113 bowersj2 1701: }
1702:
1703:
1.256 matthew 1704: =pod
1.113 bowersj2 1705:
1706: =back
1707:
1708: =cut
1.37 matthew 1709:
1710: ###############################################################
1.33 matthew 1711: ## Home server <option> list generating code ##
1712: ###############################################################
1.35 matthew 1713:
1.169 www 1714: # ------------------------------------------
1715:
1716: sub domain_select {
1717: my ($name,$value,$multiple)=@_;
1718: my %domains=map {
1.514 albertel 1719: $_ => $_.' '. &Apache::lonnet::domain($_,'description')
1.512 albertel 1720: } &Apache::lonnet::all_domains();
1.169 www 1721: if ($multiple) {
1722: $domains{''}=&mt('Any domain');
1.550 albertel 1723: $domains{'select_form_order'} = [sort {lc($a) cmp lc($b) } (keys(%domains))];
1.287 albertel 1724: return &multiple_select_form($name,$value,4,\%domains);
1.169 www 1725: } else {
1.550 albertel 1726: $domains{'select_form_order'} = [sort {lc($a) cmp lc($b) } (keys(%domains))];
1.169 www 1727: return &select_form($name,$value,%domains);
1728: }
1729: }
1730:
1.282 albertel 1731: #-------------------------------------------
1732:
1733: =pod
1734:
1.519 raeburn 1735: =head1 Routines for form select boxes
1736:
1737: =over 4
1738:
1.648 raeburn 1739: =item * &multiple_select_form($name,$value,$size,$hash,$order)
1.282 albertel 1740:
1741: Returns a string containing a <select> element int multiple mode
1742:
1743:
1744: Args:
1745: $name - name of the <select> element
1.506 raeburn 1746: $value - scalar or array ref of values that should already be selected
1.282 albertel 1747: $size - number of rows long the select element is
1.283 albertel 1748: $hash - the elements should be 'option' => 'shown text'
1.282 albertel 1749: (shown text should already have been &mt())
1.506 raeburn 1750: $order - (optional) array ref of the order to show the elements in
1.283 albertel 1751:
1.282 albertel 1752: =cut
1753:
1754: #-------------------------------------------
1.169 www 1755: sub multiple_select_form {
1.284 albertel 1756: my ($name,$value,$size,$hash,$order)=@_;
1.169 www 1757: my %selected = map { $_ => 1 } ref($value)?@{$value}:($value);
1758: my $output='';
1.191 matthew 1759: if (! defined($size)) {
1760: $size = 4;
1.283 albertel 1761: if (scalar(keys(%$hash))<4) {
1762: $size = scalar(keys(%$hash));
1.191 matthew 1763: }
1764: }
1.734 bisitz 1765: $output.="\n".'<select name="'.$name.'" size="'.$size.'" multiple="multiple">';
1.501 banghart 1766: my @order;
1.506 raeburn 1767: if (ref($order) eq 'ARRAY') {
1768: @order = @{$order};
1769: } else {
1770: @order = sort(keys(%$hash));
1.501 banghart 1771: }
1772: if (exists($$hash{'select_form_order'})) {
1773: @order = @{$$hash{'select_form_order'}};
1774: }
1775:
1.284 albertel 1776: foreach my $key (@order) {
1.356 albertel 1777: $output.='<option value="'.&HTML::Entities::encode($key,'"<>&').'" ';
1.284 albertel 1778: $output.='selected="selected" ' if ($selected{$key});
1779: $output.='>'.$hash->{$key}."</option>\n";
1.169 www 1780: }
1781: $output.="</select>\n";
1782: return $output;
1783: }
1784:
1.88 www 1785: #-------------------------------------------
1786:
1787: =pod
1788:
1.648 raeburn 1789: =item * &select_form($defdom,$name,%hash)
1.88 www 1790:
1791: Returns a string containing a <select name='$name' size='1'> form to
1792: allow a user to select options from a hash option_name => displayed text.
1793: See lonrights.pm for an example invocation and use.
1794:
1795: =cut
1796:
1797: #-------------------------------------------
1798: sub select_form {
1799: my ($def,$name,%hash) = @_;
1800: my $selectform = "<select name=\"$name\" size=\"1\">\n";
1.128 albertel 1801: my @keys;
1802: if (exists($hash{'select_form_order'})) {
1803: @keys=@{$hash{'select_form_order'}};
1804: } else {
1805: @keys=sort(keys(%hash));
1806: }
1.356 albertel 1807: foreach my $key (@keys) {
1808: $selectform.=
1809: '<option value="'.&HTML::Entities::encode($key,'"<>&').'" '.
1810: ($key eq $def ? 'selected="selected" ' : '').
1811: ">".&mt($hash{$key})."</option>\n";
1.88 www 1812: }
1813: $selectform.="</select>";
1814: return $selectform;
1815: }
1816:
1.475 www 1817: # For display filters
1818:
1819: sub display_filter {
1820: if (!$env{'form.show'}) { $env{'form.show'}=10; }
1.477 www 1821: if (!$env{'form.displayfilter'}) { $env{'form.displayfilter'}='currentfolder'; }
1.714 bisitz 1822: return '<span class="LC_nobreak"><label>'.&mt('Records [_1]',
1.475 www 1823: &Apache::lonmeta::selectbox('show',$env{'form.show'},undef,
1824: (&mt('all'),10,20,50,100,1000,10000))).
1.714 bisitz 1825: '</label></span> <span class="LC_nobreak">'.
1.475 www 1826: &mt('Filter [_1]',
1.477 www 1827: &select_form($env{'form.displayfilter'},
1828: 'displayfilter',
1829: ('currentfolder' => 'Current folder/page',
1830: 'containing' => 'Containing phrase',
1831: 'none' => 'None'))).
1.714 bisitz 1832: '<input type="text" name="containingphrase" size="30" value="'.&HTML::Entities::encode($env{'form.containingphrase'}).'" /></span>';
1.475 www 1833: }
1834:
1.167 www 1835: sub gradeleveldescription {
1836: my $gradelevel=shift;
1837: my %gradelevels=(0 => 'Not specified',
1838: 1 => 'Grade 1',
1839: 2 => 'Grade 2',
1840: 3 => 'Grade 3',
1841: 4 => 'Grade 4',
1842: 5 => 'Grade 5',
1843: 6 => 'Grade 6',
1844: 7 => 'Grade 7',
1845: 8 => 'Grade 8',
1846: 9 => 'Grade 9',
1847: 10 => 'Grade 10',
1848: 11 => 'Grade 11',
1849: 12 => 'Grade 12',
1850: 13 => 'Grade 13',
1851: 14 => '100 Level',
1852: 15 => '200 Level',
1853: 16 => '300 Level',
1854: 17 => '400 Level',
1855: 18 => 'Graduate Level');
1856: return &mt($gradelevels{$gradelevel});
1857: }
1858:
1.163 www 1859: sub select_level_form {
1860: my ($deflevel,$name)=@_;
1861: unless ($deflevel) { $deflevel=0; }
1.167 www 1862: my $selectform = "<select name=\"$name\" size=\"1\">\n";
1863: for (my $i=0; $i<=18; $i++) {
1864: $selectform.="<option value=\"$i\" ".
1.253 albertel 1865: ($i==$deflevel ? 'selected="selected" ' : '').
1.167 www 1866: ">".&gradeleveldescription($i)."</option>\n";
1867: }
1868: $selectform.="</select>";
1869: return $selectform;
1.163 www 1870: }
1.167 www 1871:
1.35 matthew 1872: #-------------------------------------------
1873:
1.45 matthew 1874: =pod
1875:
1.873 raeburn 1876: =item * &select_dom_form($defdom,$name,$includeempty,$showdomdesc,$onchange)
1.35 matthew 1877:
1878: Returns a string containing a <select name='$name' size='1'> form to
1879: allow a user to select the domain to preform an operation in.
1880: See loncreateuser.pm for an example invocation and use.
1881:
1.90 www 1882: If the $includeempty flag is set, it also includes an empty choice ("no domain
1883: selected");
1884:
1.743 raeburn 1885: If the $showdomdesc flag is set, the domain name is followed by the domain description.
1886:
1.872 raeburn 1887: The optional $onchange argumnet specifies what should occur if the domain selector is changed, e.g., 'this.form.submit()' if the form is to be automatically submitted.
1.563 raeburn 1888:
1.35 matthew 1889: =cut
1890:
1891: #-------------------------------------------
1.34 matthew 1892: sub select_dom_form {
1.872 raeburn 1893: my ($defdom,$name,$includeempty,$showdomdesc,$onchange) = @_;
1894: if ($onchange) {
1.874 raeburn 1895: $onchange = ' onchange="'.$onchange.'"';
1.743 raeburn 1896: }
1.550 albertel 1897: my @domains = sort {lc($a) cmp lc($b)} (&Apache::lonnet::all_domains());
1.90 www 1898: if ($includeempty) { @domains=('',@domains); }
1.743 raeburn 1899: my $selectdomain = "<select name=\"$name\" size=\"1\"$onchange>\n";
1.356 albertel 1900: foreach my $dom (@domains) {
1901: $selectdomain.="<option value=\"$dom\" ".
1.563 raeburn 1902: ($dom eq $defdom ? 'selected="selected" ' : '').'>'.$dom;
1903: if ($showdomdesc) {
1904: if ($dom ne '') {
1905: my $domdesc = &Apache::lonnet::domain($dom,'description');
1906: if ($domdesc ne '') {
1907: $selectdomain .= ' ('.$domdesc.')';
1908: }
1909: }
1910: }
1911: $selectdomain .= "</option>\n";
1.34 matthew 1912: }
1913: $selectdomain.="</select>";
1914: return $selectdomain;
1915: }
1916:
1.35 matthew 1917: #-------------------------------------------
1918:
1.45 matthew 1919: =pod
1920:
1.648 raeburn 1921: =item * &home_server_form_item($domain,$name,$defaultflag)
1.35 matthew 1922:
1.586 raeburn 1923: input: 4 arguments (two required, two optional) -
1924: $domain - domain of new user
1925: $name - name of form element
1926: $default - Value of 'default' causes a default item to be first
1927: option, and selected by default.
1928: $hide - Value of 'hide' causes hiding of the name of the server,
1929: if 1 server found, or default, if 0 found.
1.594 raeburn 1930: output: returns 2 items:
1.586 raeburn 1931: (a) form element which contains either:
1932: (i) <select name="$name">
1933: <option value="$hostid1">$hostid $servers{$hostid}</option>
1934: <option value="$hostid2">$hostid $servers{$hostid}</option>
1935: </select>
1936: form item if there are multiple library servers in $domain, or
1937: (ii) an <input type="hidden" name="$name" value="$hostid" /> form item
1938: if there is only one library server in $domain.
1939:
1940: (b) number of library servers found.
1941:
1942: See loncreateuser.pm for example of use.
1.35 matthew 1943:
1944: =cut
1945:
1946: #-------------------------------------------
1.586 raeburn 1947: sub home_server_form_item {
1948: my ($domain,$name,$default,$hide) = @_;
1.513 albertel 1949: my %servers = &Apache::lonnet::get_servers($domain,'library');
1.586 raeburn 1950: my $result;
1951: my $numlib = keys(%servers);
1952: if ($numlib > 1) {
1953: $result .= '<select name="'.$name.'" />'."\n";
1954: if ($default) {
1.804 bisitz 1955: $result .= '<option value="default" selected="selected">'.&mt('default').
1.586 raeburn 1956: '</option>'."\n";
1957: }
1958: foreach my $hostid (sort(keys(%servers))) {
1959: $result.= '<option value="'.$hostid.'">'.
1960: $hostid.' '.$servers{$hostid}."</option>\n";
1961: }
1962: $result .= '</select>'."\n";
1963: } elsif ($numlib == 1) {
1964: my $hostid;
1965: foreach my $item (keys(%servers)) {
1966: $hostid = $item;
1967: }
1968: $result .= '<input type="hidden" name="'.$name.'" value="'.
1969: $hostid.'" />';
1970: if (!$hide) {
1971: $result .= $hostid.' '.$servers{$hostid};
1972: }
1973: $result .= "\n";
1974: } elsif ($default) {
1975: $result .= '<input type="hidden" name="'.$name.
1976: '" value="default" />';
1977: if (!$hide) {
1978: $result .= &mt('default');
1979: }
1980: $result .= "\n";
1.33 matthew 1981: }
1.586 raeburn 1982: return ($result,$numlib);
1.33 matthew 1983: }
1.112 bowersj2 1984:
1985: =pod
1986:
1.534 albertel 1987: =back
1988:
1.112 bowersj2 1989: =cut
1.87 matthew 1990:
1991: ###############################################################
1.112 bowersj2 1992: ## Decoding User Agent ##
1.87 matthew 1993: ###############################################################
1994:
1995: =pod
1996:
1.112 bowersj2 1997: =head1 Decoding the User Agent
1998:
1999: =over 4
2000:
2001: =item * &decode_user_agent()
1.87 matthew 2002:
2003: Inputs: $r
2004:
2005: Outputs:
2006:
2007: =over 4
2008:
1.112 bowersj2 2009: =item * $httpbrowser
1.87 matthew 2010:
1.112 bowersj2 2011: =item * $clientbrowser
1.87 matthew 2012:
1.112 bowersj2 2013: =item * $clientversion
1.87 matthew 2014:
1.112 bowersj2 2015: =item * $clientmathml
1.87 matthew 2016:
1.112 bowersj2 2017: =item * $clientunicode
1.87 matthew 2018:
1.112 bowersj2 2019: =item * $clientos
1.87 matthew 2020:
2021: =back
2022:
1.157 matthew 2023: =back
2024:
1.87 matthew 2025: =cut
2026:
2027: ###############################################################
2028: ###############################################################
2029: sub decode_user_agent {
1.247 albertel 2030: my ($r)=@_;
1.87 matthew 2031: my @browsertype=split(/\&/,$Apache::lonnet::perlvar{"lonBrowsDet"});
2032: my %mathcap=split(/\&/,$$Apache::lonnet::perlvar{"lonMathML"});
2033: my $httpbrowser=$ENV{"HTTP_USER_AGENT"};
1.247 albertel 2034: if (!$httpbrowser && $r) { $httpbrowser=$r->header_in('User-Agent'); }
1.87 matthew 2035: my $clientbrowser='unknown';
2036: my $clientversion='0';
2037: my $clientmathml='';
2038: my $clientunicode='0';
2039: for (my $i=0;$i<=$#browsertype;$i++) {
2040: my ($bname,$match,$notmatch,$vreg,$minv,$univ)=split(/\:/,$browsertype[$i]);
2041: if (($httpbrowser=~/$match/i) && ($httpbrowser!~/$notmatch/i)) {
2042: $clientbrowser=$bname;
2043: $httpbrowser=~/$vreg/i;
2044: $clientversion=$1;
2045: $clientmathml=($clientversion>=$minv);
2046: $clientunicode=($clientversion>=$univ);
2047: }
2048: }
2049: my $clientos='unknown';
2050: if (($httpbrowser=~/linux/i) ||
2051: ($httpbrowser=~/unix/i) ||
2052: ($httpbrowser=~/ux/i) ||
2053: ($httpbrowser=~/solaris/i)) { $clientos='unix'; }
2054: if (($httpbrowser=~/vax/i) ||
2055: ($httpbrowser=~/vms/i)) { $clientos='vms'; }
2056: if ($httpbrowser=~/next/i) { $clientos='next'; }
2057: if (($httpbrowser=~/mac/i) ||
2058: ($httpbrowser=~/powerpc/i)) { $clientos='mac'; }
2059: if ($httpbrowser=~/win/i) { $clientos='win'; }
2060: if ($httpbrowser=~/embed/i) { $clientos='pda'; }
2061: return ($httpbrowser,$clientbrowser,$clientversion,$clientmathml,
2062: $clientunicode,$clientos,);
2063: }
2064:
1.32 matthew 2065: ###############################################################
2066: ## Authentication changing form generation subroutines ##
2067: ###############################################################
2068: ##
2069: ## All of the authform_xxxxxxx subroutines take their inputs in a
2070: ## hash, and have reasonable default values.
2071: ##
2072: ## formname = the name given in the <form> tag.
1.35 matthew 2073: #-------------------------------------------
2074:
1.45 matthew 2075: =pod
2076:
1.112 bowersj2 2077: =head1 Authentication Routines
2078:
2079: =over 4
2080:
1.648 raeburn 2081: =item * &authform_xxxxxx()
1.35 matthew 2082:
2083: The authform_xxxxxx subroutines provide javascript and html forms which
2084: handle some of the conveniences required for authentication forms.
2085: This is not an optimal method, but it works.
2086:
2087: =over 4
2088:
1.112 bowersj2 2089: =item * authform_header
1.35 matthew 2090:
1.112 bowersj2 2091: =item * authform_authorwarning
1.35 matthew 2092:
1.112 bowersj2 2093: =item * authform_nochange
1.35 matthew 2094:
1.112 bowersj2 2095: =item * authform_kerberos
1.35 matthew 2096:
1.112 bowersj2 2097: =item * authform_internal
1.35 matthew 2098:
1.112 bowersj2 2099: =item * authform_filesystem
1.35 matthew 2100:
2101: =back
2102:
1.648 raeburn 2103: See loncreateuser.pm for invocation and use examples.
1.157 matthew 2104:
1.35 matthew 2105: =cut
2106:
2107: #-------------------------------------------
1.32 matthew 2108: sub authform_header{
2109: my %in = (
2110: formname => 'cu',
1.80 albertel 2111: kerb_def_dom => '',
1.32 matthew 2112: @_,
2113: );
2114: $in{'formname'} = 'document.' . $in{'formname'};
2115: my $result='';
1.80 albertel 2116:
2117: #---------------------------------------------- Code for upper case translation
2118: my $Javascript_toUpperCase;
2119: unless ($in{kerb_def_dom}) {
2120: $Javascript_toUpperCase =<<"END";
2121: switch (choice) {
2122: case 'krb': currentform.elements[choicearg].value =
2123: currentform.elements[choicearg].value.toUpperCase();
2124: break;
2125: default:
2126: }
2127: END
2128: } else {
2129: $Javascript_toUpperCase = "";
2130: }
2131:
1.165 raeburn 2132: my $radioval = "'nochange'";
1.591 raeburn 2133: if (defined($in{'curr_authtype'})) {
2134: if ($in{'curr_authtype'} ne '') {
2135: $radioval = "'".$in{'curr_authtype'}."arg'";
2136: }
1.174 matthew 2137: }
1.165 raeburn 2138: my $argfield = 'null';
1.591 raeburn 2139: if (defined($in{'mode'})) {
1.165 raeburn 2140: if ($in{'mode'} eq 'modifycourse') {
1.591 raeburn 2141: if (defined($in{'curr_autharg'})) {
2142: if ($in{'curr_autharg'} ne '') {
1.165 raeburn 2143: $argfield = "'$in{'curr_autharg'}'";
2144: }
2145: }
2146: }
2147: }
2148:
1.32 matthew 2149: $result.=<<"END";
2150: var current = new Object();
1.165 raeburn 2151: current.radiovalue = $radioval;
2152: current.argfield = $argfield;
1.32 matthew 2153:
2154: function changed_radio(choice,currentform) {
2155: var choicearg = choice + 'arg';
2156: // If a radio button in changed, we need to change the argfield
2157: if (current.radiovalue != choice) {
2158: current.radiovalue = choice;
2159: if (current.argfield != null) {
2160: currentform.elements[current.argfield].value = '';
2161: }
2162: if (choice == 'nochange') {
2163: current.argfield = null;
2164: } else {
2165: current.argfield = choicearg;
2166: switch(choice) {
2167: case 'krb':
2168: currentform.elements[current.argfield].value =
2169: "$in{'kerb_def_dom'}";
2170: break;
2171: default:
2172: break;
2173: }
2174: }
2175: }
2176: return;
2177: }
1.22 www 2178:
1.32 matthew 2179: function changed_text(choice,currentform) {
2180: var choicearg = choice + 'arg';
2181: if (currentform.elements[choicearg].value !='') {
1.80 albertel 2182: $Javascript_toUpperCase
1.32 matthew 2183: // clear old field
2184: if ((current.argfield != choicearg) && (current.argfield != null)) {
2185: currentform.elements[current.argfield].value = '';
2186: }
2187: current.argfield = choicearg;
2188: }
2189: set_auth_radio_buttons(choice,currentform);
2190: return;
1.20 www 2191: }
1.32 matthew 2192:
2193: function set_auth_radio_buttons(newvalue,currentform) {
2194: var i=0;
2195: while (i < currentform.login.length) {
2196: if (currentform.login[i].value == newvalue) { break; }
2197: i++;
2198: }
2199: if (i == currentform.login.length) {
2200: return;
2201: }
2202: current.radiovalue = newvalue;
2203: currentform.login[i].checked = true;
2204: return;
2205: }
2206: END
2207: return $result;
2208: }
2209:
2210: sub authform_authorwarning{
2211: my $result='';
1.144 matthew 2212: $result='<i>'.
2213: &mt('As a general rule, only authors or co-authors should be '.
2214: 'filesystem authenticated '.
2215: '(which allows access to the server filesystem).')."</i>\n";
1.32 matthew 2216: return $result;
2217: }
2218:
2219: sub authform_nochange{
2220: my %in = (
2221: formname => 'document.cu',
2222: kerb_def_dom => 'MSU.EDU',
2223: @_,
2224: );
1.586 raeburn 2225: my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
2226: my $result;
2227: if (keys(%can_assign) == 0) {
2228: $result = &mt('Under you current role you are not permitted to change login settings for this user');
2229: } else {
2230: $result = '<label>'.&mt('[_1] Do not change login data',
2231: '<input type="radio" name="login" value="nochange" '.
2232: 'checked="checked" onclick="'.
1.281 albertel 2233: "javascript:changed_radio('nochange',$in{'formname'});".'" />').
2234: '</label>';
1.586 raeburn 2235: }
1.32 matthew 2236: return $result;
2237: }
2238:
1.591 raeburn 2239: sub authform_kerberos {
1.32 matthew 2240: my %in = (
2241: formname => 'document.cu',
2242: kerb_def_dom => 'MSU.EDU',
1.80 albertel 2243: kerb_def_auth => 'krb4',
1.32 matthew 2244: @_,
2245: );
1.586 raeburn 2246: my ($check4,$check5,$krbcheck,$krbarg,$krbver,$result,$authtype,
2247: $autharg,$jscall);
2248: my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
1.80 albertel 2249: if ($in{'kerb_def_auth'} eq 'krb5') {
1.772 bisitz 2250: $check5 = ' checked="checked"';
1.80 albertel 2251: } else {
1.772 bisitz 2252: $check4 = ' checked="checked"';
1.80 albertel 2253: }
1.165 raeburn 2254: $krbarg = $in{'kerb_def_dom'};
1.591 raeburn 2255: if (defined($in{'curr_authtype'})) {
2256: if ($in{'curr_authtype'} eq 'krb') {
1.772 bisitz 2257: $krbcheck = ' checked="checked"';
1.623 raeburn 2258: if (defined($in{'mode'})) {
2259: if ($in{'mode'} eq 'modifyuser') {
2260: $krbcheck = '';
2261: }
2262: }
1.591 raeburn 2263: if (defined($in{'curr_kerb_ver'})) {
2264: if ($in{'curr_krb_ver'} eq '5') {
1.772 bisitz 2265: $check5 = ' checked="checked"';
1.591 raeburn 2266: $check4 = '';
2267: } else {
1.772 bisitz 2268: $check4 = ' checked="checked"';
1.591 raeburn 2269: $check5 = '';
2270: }
1.586 raeburn 2271: }
1.591 raeburn 2272: if (defined($in{'curr_autharg'})) {
1.165 raeburn 2273: $krbarg = $in{'curr_autharg'};
2274: }
1.586 raeburn 2275: if (!$can_assign{'krb4'} && !$can_assign{'krb5'}) {
1.591 raeburn 2276: if (defined($in{'curr_autharg'})) {
1.586 raeburn 2277: $result =
2278: &mt('Currently Kerberos authenticated with domain [_1] Version [_2].',
2279: $in{'curr_autharg'},$krbver);
2280: } else {
2281: $result =
2282: &mt('Currently Kerberos authenticated, Version [_1].',$krbver);
2283: }
2284: return $result;
2285: }
2286: }
2287: } else {
2288: if ($authnum == 1) {
1.784 bisitz 2289: $authtype = '<input type="hidden" name="login" value="krb" />';
1.165 raeburn 2290: }
2291: }
1.586 raeburn 2292: if (!$can_assign{'krb4'} && !$can_assign{'krb5'}) {
2293: return;
1.587 raeburn 2294: } elsif ($authtype eq '') {
1.591 raeburn 2295: if (defined($in{'mode'})) {
1.587 raeburn 2296: if ($in{'mode'} eq 'modifycourse') {
2297: if ($authnum == 1) {
1.784 bisitz 2298: $authtype = '<input type="hidden" name="login" value="krb" />';
1.587 raeburn 2299: }
2300: }
2301: }
1.586 raeburn 2302: }
2303: $jscall = "javascript:changed_radio('krb',$in{'formname'});";
2304: if ($authtype eq '') {
2305: $authtype = '<input type="radio" name="login" value="krb" '.
2306: 'onclick="'.$jscall.'" onchange="'.$jscall.'"'.
2307: $krbcheck.' />';
2308: }
2309: if (($can_assign{'krb4'} && $can_assign{'krb5'}) ||
2310: ($can_assign{'krb4'} && !$can_assign{'krb5'} &&
2311: $in{'curr_authtype'} eq 'krb5') ||
2312: (!$can_assign{'krb4'} && $can_assign{'krb5'} &&
2313: $in{'curr_authtype'} eq 'krb4')) {
2314: $result .= &mt
1.144 matthew 2315: ('[_1] Kerberos authenticated with domain [_2] '.
1.281 albertel 2316: '[_3] Version 4 [_4] Version 5 [_5]',
1.586 raeburn 2317: '<label>'.$authtype,
1.281 albertel 2318: '</label><input type="text" size="10" name="krbarg" '.
1.165 raeburn 2319: 'value="'.$krbarg.'" '.
1.144 matthew 2320: 'onchange="'.$jscall.'" />',
1.281 albertel 2321: '<label><input type="radio" name="krbver" value="4" '.$check4.' />',
2322: '</label><label><input type="radio" name="krbver" value="5" '.$check5.' />',
2323: '</label>');
1.586 raeburn 2324: } elsif ($can_assign{'krb4'}) {
2325: $result .= &mt
2326: ('[_1] Kerberos authenticated with domain [_2] '.
2327: '[_3] Version 4 [_4]',
2328: '<label>'.$authtype,
2329: '</label><input type="text" size="10" name="krbarg" '.
2330: 'value="'.$krbarg.'" '.
2331: 'onchange="'.$jscall.'" />',
2332: '<label><input type="hidden" name="krbver" value="4" />',
2333: '</label>');
2334: } elsif ($can_assign{'krb5'}) {
2335: $result .= &mt
2336: ('[_1] Kerberos authenticated with domain [_2] '.
2337: '[_3] Version 5 [_4]',
2338: '<label>'.$authtype,
2339: '</label><input type="text" size="10" name="krbarg" '.
2340: 'value="'.$krbarg.'" '.
2341: 'onchange="'.$jscall.'" />',
2342: '<label><input type="hidden" name="krbver" value="5" />',
2343: '</label>');
2344: }
1.32 matthew 2345: return $result;
2346: }
2347:
2348: sub authform_internal{
1.586 raeburn 2349: my %in = (
1.32 matthew 2350: formname => 'document.cu',
2351: kerb_def_dom => 'MSU.EDU',
2352: @_,
2353: );
1.586 raeburn 2354: my ($intcheck,$intarg,$result,$authtype,$autharg,$jscall);
2355: my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
1.591 raeburn 2356: if (defined($in{'curr_authtype'})) {
2357: if ($in{'curr_authtype'} eq 'int') {
1.586 raeburn 2358: if ($can_assign{'int'}) {
1.772 bisitz 2359: $intcheck = 'checked="checked" ';
1.623 raeburn 2360: if (defined($in{'mode'})) {
2361: if ($in{'mode'} eq 'modifyuser') {
2362: $intcheck = '';
2363: }
2364: }
1.591 raeburn 2365: if (defined($in{'curr_autharg'})) {
1.586 raeburn 2366: $intarg = $in{'curr_autharg'};
2367: }
2368: } else {
2369: $result = &mt('Currently internally authenticated.');
2370: return $result;
1.165 raeburn 2371: }
2372: }
1.586 raeburn 2373: } else {
2374: if ($authnum == 1) {
1.784 bisitz 2375: $authtype = '<input type="hidden" name="login" value="int" />';
1.586 raeburn 2376: }
2377: }
2378: if (!$can_assign{'int'}) {
2379: return;
1.587 raeburn 2380: } elsif ($authtype eq '') {
1.591 raeburn 2381: if (defined($in{'mode'})) {
1.587 raeburn 2382: if ($in{'mode'} eq 'modifycourse') {
2383: if ($authnum == 1) {
1.784 bisitz 2384: $authtype = '<input type="hidden" name="login" value="int" />';
1.587 raeburn 2385: }
2386: }
2387: }
1.165 raeburn 2388: }
1.586 raeburn 2389: $jscall = "javascript:changed_radio('int',$in{'formname'});";
2390: if ($authtype eq '') {
2391: $authtype = '<input type="radio" name="login" value="int" '.$intcheck.
2392: ' onchange="'.$jscall.'" onclick="'.$jscall.'" />';
2393: }
1.605 bisitz 2394: $autharg = '<input type="password" size="10" name="intarg" value="'.
1.586 raeburn 2395: $intarg.'" onchange="'.$jscall.'" />';
2396: $result = &mt
1.144 matthew 2397: ('[_1] Internally authenticated (with initial password [_2])',
1.586 raeburn 2398: '<label>'.$authtype,'</label>'.$autharg);
1.824 bisitz 2399: $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 2400: return $result;
2401: }
2402:
2403: sub authform_local{
2404: my %in = (
2405: formname => 'document.cu',
2406: kerb_def_dom => 'MSU.EDU',
2407: @_,
2408: );
1.586 raeburn 2409: my ($loccheck,$locarg,$result,$authtype,$autharg,$jscall);
2410: my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
1.591 raeburn 2411: if (defined($in{'curr_authtype'})) {
2412: if ($in{'curr_authtype'} eq 'loc') {
1.586 raeburn 2413: if ($can_assign{'loc'}) {
1.772 bisitz 2414: $loccheck = 'checked="checked" ';
1.623 raeburn 2415: if (defined($in{'mode'})) {
2416: if ($in{'mode'} eq 'modifyuser') {
2417: $loccheck = '';
2418: }
2419: }
1.591 raeburn 2420: if (defined($in{'curr_autharg'})) {
1.586 raeburn 2421: $locarg = $in{'curr_autharg'};
2422: }
2423: } else {
2424: $result = &mt('Currently using local (institutional) authentication.');
2425: return $result;
1.165 raeburn 2426: }
2427: }
1.586 raeburn 2428: } else {
2429: if ($authnum == 1) {
1.784 bisitz 2430: $authtype = '<input type="hidden" name="login" value="loc" />';
1.586 raeburn 2431: }
2432: }
2433: if (!$can_assign{'loc'}) {
2434: return;
1.587 raeburn 2435: } elsif ($authtype eq '') {
1.591 raeburn 2436: if (defined($in{'mode'})) {
1.587 raeburn 2437: if ($in{'mode'} eq 'modifycourse') {
2438: if ($authnum == 1) {
1.784 bisitz 2439: $authtype = '<input type="hidden" name="login" value="loc" />';
1.587 raeburn 2440: }
2441: }
2442: }
1.165 raeburn 2443: }
1.586 raeburn 2444: $jscall = "javascript:changed_radio('loc',$in{'formname'});";
2445: if ($authtype eq '') {
2446: $authtype = '<input type="radio" name="login" value="loc" '.
2447: $loccheck.' onchange="'.$jscall.'" onclick="'.
2448: $jscall.'" />';
2449: }
2450: $autharg = '<input type="text" size="10" name="locarg" value="'.
2451: $locarg.'" onchange="'.$jscall.'" />';
2452: $result = &mt('[_1] Local Authentication with argument [_2]',
2453: '<label>'.$authtype,'</label>'.$autharg);
1.32 matthew 2454: return $result;
2455: }
2456:
2457: sub authform_filesystem{
2458: my %in = (
2459: formname => 'document.cu',
2460: kerb_def_dom => 'MSU.EDU',
2461: @_,
2462: );
1.586 raeburn 2463: my ($fsyscheck,$result,$authtype,$autharg,$jscall);
2464: my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
1.591 raeburn 2465: if (defined($in{'curr_authtype'})) {
2466: if ($in{'curr_authtype'} eq 'fsys') {
1.586 raeburn 2467: if ($can_assign{'fsys'}) {
1.772 bisitz 2468: $fsyscheck = 'checked="checked" ';
1.623 raeburn 2469: if (defined($in{'mode'})) {
2470: if ($in{'mode'} eq 'modifyuser') {
2471: $fsyscheck = '';
2472: }
2473: }
1.586 raeburn 2474: } else {
2475: $result = &mt('Currently Filesystem Authenticated.');
2476: return $result;
2477: }
2478: }
2479: } else {
2480: if ($authnum == 1) {
1.784 bisitz 2481: $authtype = '<input type="hidden" name="login" value="fsys" />';
1.586 raeburn 2482: }
2483: }
2484: if (!$can_assign{'fsys'}) {
2485: return;
1.587 raeburn 2486: } elsif ($authtype eq '') {
1.591 raeburn 2487: if (defined($in{'mode'})) {
1.587 raeburn 2488: if ($in{'mode'} eq 'modifycourse') {
2489: if ($authnum == 1) {
1.784 bisitz 2490: $authtype = '<input type="hidden" name="login" value="fsys" />';
1.587 raeburn 2491: }
2492: }
2493: }
1.586 raeburn 2494: }
2495: $jscall = "javascript:changed_radio('fsys',$in{'formname'});";
2496: if ($authtype eq '') {
2497: $authtype = '<input type="radio" name="login" value="fsys" '.
2498: $fsyscheck.' onchange="'.$jscall.'" onclick="'.
2499: $jscall.'" />';
2500: }
2501: $autharg = '<input type="text" size="10" name="fsysarg" value=""'.
2502: ' onchange="'.$jscall.'" />';
2503: $result = &mt
1.144 matthew 2504: ('[_1] Filesystem Authenticated (with initial password [_2])',
1.281 albertel 2505: '<label><input type="radio" name="login" value="fsys" '.
1.586 raeburn 2506: $fsyscheck.'onchange="'.$jscall.'" onclick="'.$jscall.'" />',
1.605 bisitz 2507: '</label><input type="password" size="10" name="fsysarg" value="" '.
1.144 matthew 2508: 'onchange="'.$jscall.'" />');
1.32 matthew 2509: return $result;
2510: }
2511:
1.586 raeburn 2512: sub get_assignable_auth {
2513: my ($dom) = @_;
2514: if ($dom eq '') {
2515: $dom = $env{'request.role.domain'};
2516: }
2517: my %can_assign = (
2518: krb4 => 1,
2519: krb5 => 1,
2520: int => 1,
2521: loc => 1,
2522: );
2523: my %domconfig = &Apache::lonnet::get_dom('configuration',['usercreation'],$dom);
2524: if (ref($domconfig{'usercreation'}) eq 'HASH') {
2525: if (ref($domconfig{'usercreation'}{'authtypes'}) eq 'HASH') {
2526: my $authhash = $domconfig{'usercreation'}{'authtypes'};
2527: my $context;
2528: if ($env{'request.role'} =~ /^au/) {
2529: $context = 'author';
2530: } elsif ($env{'request.role'} =~ /^dc/) {
2531: $context = 'domain';
2532: } elsif ($env{'request.course.id'}) {
2533: $context = 'course';
2534: }
2535: if ($context) {
2536: if (ref($authhash->{$context}) eq 'HASH') {
2537: %can_assign = %{$authhash->{$context}};
2538: }
2539: }
2540: }
2541: }
2542: my $authnum = 0;
2543: foreach my $key (keys(%can_assign)) {
2544: if ($can_assign{$key}) {
2545: $authnum ++;
2546: }
2547: }
2548: if ($can_assign{'krb4'} && $can_assign{'krb5'}) {
2549: $authnum --;
2550: }
2551: return ($authnum,%can_assign);
2552: }
2553:
1.80 albertel 2554: ###############################################################
2555: ## Get Kerberos Defaults for Domain ##
2556: ###############################################################
2557: ##
2558: ## Returns default kerberos version and an associated argument
2559: ## as listed in file domain.tab. If not listed, provides
2560: ## appropriate default domain and kerberos version.
2561: ##
2562: #-------------------------------------------
2563:
2564: =pod
2565:
1.648 raeburn 2566: =item * &get_kerberos_defaults()
1.80 albertel 2567:
2568: get_kerberos_defaults($target_domain) returns the default kerberos
1.641 raeburn 2569: version and domain. If not found, it defaults to version 4 and the
2570: domain of the server.
1.80 albertel 2571:
1.648 raeburn 2572: =over 4
2573:
1.80 albertel 2574: ($def_version, $def_krb_domain) = &get_kerberos_defaults($target_domain);
2575:
1.648 raeburn 2576: =back
2577:
2578: =back
2579:
1.80 albertel 2580: =cut
2581:
2582: #-------------------------------------------
2583: sub get_kerberos_defaults {
2584: my $domain=shift;
1.641 raeburn 2585: my ($krbdef,$krbdefdom);
2586: my %domdefaults = &Apache::lonnet::get_domain_defaults($domain);
2587: if (($domdefaults{'auth_def'} =~/^krb(4|5)$/) && ($domdefaults{'auth_arg_def'} ne '')) {
2588: $krbdef = $domdefaults{'auth_def'};
2589: $krbdefdom = $domdefaults{'auth_arg_def'};
2590: } else {
1.80 albertel 2591: $ENV{'SERVER_NAME'}=~/(\w+\.\w+)$/;
2592: my $krbdefdom=$1;
2593: $krbdefdom=~tr/a-z/A-Z/;
2594: $krbdef = "krb4";
2595: }
2596: return ($krbdef,$krbdefdom);
2597: }
1.112 bowersj2 2598:
1.32 matthew 2599:
1.46 matthew 2600: ###############################################################
2601: ## Thesaurus Functions ##
2602: ###############################################################
1.20 www 2603:
1.46 matthew 2604: =pod
1.20 www 2605:
1.112 bowersj2 2606: =head1 Thesaurus Functions
2607:
2608: =over 4
2609:
1.648 raeburn 2610: =item * &initialize_keywords()
1.46 matthew 2611:
2612: Initializes the package variable %Keywords if it is empty. Uses the
2613: package variable $thesaurus_db_file.
2614:
2615: =cut
2616:
2617: ###################################################
2618:
2619: sub initialize_keywords {
2620: return 1 if (scalar keys(%Keywords));
2621: # If we are here, %Keywords is empty, so fill it up
2622: # Make sure the file we need exists...
2623: if (! -e $thesaurus_db_file) {
2624: &Apache::lonnet::logthis("Attempt to access $thesaurus_db_file".
2625: " failed because it does not exist");
2626: return 0;
2627: }
2628: # Set up the hash as a database
2629: my %thesaurus_db;
2630: if (! tie(%thesaurus_db,'GDBM_File',
1.53 albertel 2631: $thesaurus_db_file,&GDBM_READER(),0640)){
1.46 matthew 2632: &Apache::lonnet::logthis("Could not tie \%thesaurus_db to ".
2633: $thesaurus_db_file);
2634: return 0;
2635: }
2636: # Get the average number of appearances of a word.
2637: my $avecount = $thesaurus_db{'average.count'};
2638: # Put keywords (those that appear > average) into %Keywords
2639: while (my ($word,$data)=each (%thesaurus_db)) {
2640: my ($count,undef) = split /:/,$data;
2641: $Keywords{$word}++ if ($count > $avecount);
2642: }
2643: untie %thesaurus_db;
2644: # Remove special values from %Keywords.
1.356 albertel 2645: foreach my $value ('total.count','average.count') {
2646: delete($Keywords{$value}) if (exists($Keywords{$value}));
1.586 raeburn 2647: }
1.46 matthew 2648: return 1;
2649: }
2650:
2651: ###################################################
2652:
2653: =pod
2654:
1.648 raeburn 2655: =item * &keyword($word)
1.46 matthew 2656:
2657: Returns true if $word is a keyword. A keyword is a word that appears more
2658: than the average number of times in the thesaurus database. Calls
2659: &initialize_keywords
2660:
2661: =cut
2662:
2663: ###################################################
1.20 www 2664:
2665: sub keyword {
1.46 matthew 2666: return if (!&initialize_keywords());
2667: my $word=lc(shift());
2668: $word=~s/\W//g;
2669: return exists($Keywords{$word});
1.20 www 2670: }
1.46 matthew 2671:
2672: ###############################################################
2673:
2674: =pod
1.20 www 2675:
1.648 raeburn 2676: =item * &get_related_words()
1.46 matthew 2677:
1.160 matthew 2678: Look up a word in the thesaurus. Takes a scalar argument and returns
1.46 matthew 2679: an array of words. If the keyword is not in the thesaurus, an empty array
2680: will be returned. The order of the words returned is determined by the
2681: database which holds them.
2682:
2683: Uses global $thesaurus_db_file.
2684:
2685: =cut
2686:
2687: ###############################################################
2688: sub get_related_words {
2689: my $keyword = shift;
2690: my %thesaurus_db;
2691: if (! -e $thesaurus_db_file) {
2692: &Apache::lonnet::logthis("Attempt to access $thesaurus_db_file ".
2693: "failed because the file does not exist");
2694: return ();
2695: }
2696: if (! tie(%thesaurus_db,'GDBM_File',
1.53 albertel 2697: $thesaurus_db_file,&GDBM_READER(),0640)){
1.46 matthew 2698: return ();
2699: }
2700: my @Words=();
1.429 www 2701: my $count=0;
1.46 matthew 2702: if (exists($thesaurus_db{$keyword})) {
1.356 albertel 2703: # The first element is the number of times
2704: # the word appears. We do not need it now.
1.429 www 2705: my (undef,@RelatedWords) = (split(/:/,$thesaurus_db{$keyword}));
2706: my (undef,$mostfrequentcount)=split(/\,/,$RelatedWords[0]);
2707: my $threshold=$mostfrequentcount/10;
2708: foreach my $possibleword (@RelatedWords) {
2709: my ($word,$wordcount)=split(/\,/,$possibleword);
2710: if ($wordcount>$threshold) {
2711: push(@Words,$word);
2712: $count++;
2713: if ($count>10) { last; }
2714: }
1.20 www 2715: }
2716: }
1.46 matthew 2717: untie %thesaurus_db;
2718: return @Words;
1.14 harris41 2719: }
1.46 matthew 2720:
1.112 bowersj2 2721: =pod
2722:
2723: =back
2724:
2725: =cut
1.61 www 2726:
2727: # -------------------------------------------------------------- Plaintext name
1.81 albertel 2728: =pod
2729:
1.112 bowersj2 2730: =head1 User Name Functions
2731:
2732: =over 4
2733:
1.648 raeburn 2734: =item * &plainname($uname,$udom,$first)
1.81 albertel 2735:
1.112 bowersj2 2736: Takes a users logon name and returns it as a string in
1.226 albertel 2737: "first middle last generation" form
2738: if $first is set to 'lastname' then it returns it as
2739: 'lastname generation, firstname middlename' if their is a lastname
1.81 albertel 2740:
2741: =cut
1.61 www 2742:
1.295 www 2743:
1.81 albertel 2744: ###############################################################
1.61 www 2745: sub plainname {
1.226 albertel 2746: my ($uname,$udom,$first)=@_;
1.537 albertel 2747: return if (!defined($uname) || !defined($udom));
1.295 www 2748: my %names=&getnames($uname,$udom);
1.226 albertel 2749: my $name=&Apache::lonnet::format_name($names{'firstname'},
2750: $names{'middlename'},
2751: $names{'lastname'},
2752: $names{'generation'},$first);
2753: $name=~s/^\s+//;
1.62 www 2754: $name=~s/\s+$//;
2755: $name=~s/\s+/ /g;
1.353 albertel 2756: if ($name !~ /\S/) { $name=$uname.':'.$udom; }
1.62 www 2757: return $name;
1.61 www 2758: }
1.66 www 2759:
2760: # -------------------------------------------------------------------- Nickname
1.81 albertel 2761: =pod
2762:
1.648 raeburn 2763: =item * &nickname($uname,$udom)
1.81 albertel 2764:
2765: Gets a users name and returns it as a string as
2766:
2767: ""nickname""
1.66 www 2768:
1.81 albertel 2769: if the user has a nickname or
2770:
2771: "first middle last generation"
2772:
2773: if the user does not
2774:
2775: =cut
1.66 www 2776:
2777: sub nickname {
2778: my ($uname,$udom)=@_;
1.537 albertel 2779: return if (!defined($uname) || !defined($udom));
1.295 www 2780: my %names=&getnames($uname,$udom);
1.68 albertel 2781: my $name=$names{'nickname'};
1.66 www 2782: if ($name) {
2783: $name='"'.$name.'"';
2784: } else {
2785: $name=$names{'firstname'}.' '.$names{'middlename'}.' '.
2786: $names{'lastname'}.' '.$names{'generation'};
2787: $name=~s/\s+$//;
2788: $name=~s/\s+/ /g;
2789: }
2790: return $name;
2791: }
2792:
1.295 www 2793: sub getnames {
2794: my ($uname,$udom)=@_;
1.537 albertel 2795: return if (!defined($uname) || !defined($udom));
1.433 albertel 2796: if ($udom eq 'public' && $uname eq 'public') {
2797: return ('lastname' => &mt('Public'));
2798: }
1.295 www 2799: my $id=$uname.':'.$udom;
2800: my ($names,$cached)=&Apache::lonnet::is_cached_new('namescache',$id);
2801: if ($cached) {
2802: return %{$names};
2803: } else {
2804: my %loadnames=&Apache::lonnet::get('environment',
2805: ['firstname','middlename','lastname','generation','nickname'],
2806: $udom,$uname);
2807: &Apache::lonnet::do_cache_new('namescache',$id,\%loadnames);
2808: return %loadnames;
2809: }
2810: }
1.61 www 2811:
1.542 raeburn 2812: # -------------------------------------------------------------------- getemails
1.648 raeburn 2813:
1.542 raeburn 2814: =pod
2815:
1.648 raeburn 2816: =item * &getemails($uname,$udom)
1.542 raeburn 2817:
2818: Gets a user's email information and returns it as a hash with keys:
2819: notification, critnotification, permanentemail
2820:
2821: For notification and critnotification, values are comma-separated lists
1.648 raeburn 2822: of e-mail addresses; for permanentemail, value is a single e-mail address.
1.542 raeburn 2823:
1.648 raeburn 2824:
1.542 raeburn 2825: =cut
2826:
1.648 raeburn 2827:
1.466 albertel 2828: sub getemails {
2829: my ($uname,$udom)=@_;
2830: if ($udom eq 'public' && $uname eq 'public') {
2831: return;
2832: }
1.467 www 2833: if (!$udom) { $udom=$env{'user.domain'}; }
2834: if (!$uname) { $uname=$env{'user.name'}; }
1.466 albertel 2835: my $id=$uname.':'.$udom;
2836: my ($names,$cached)=&Apache::lonnet::is_cached_new('emailscache',$id);
2837: if ($cached) {
2838: return %{$names};
2839: } else {
2840: my %loadnames=&Apache::lonnet::get('environment',
2841: ['notification','critnotification',
2842: 'permanentemail'],
2843: $udom,$uname);
2844: &Apache::lonnet::do_cache_new('emailscache',$id,\%loadnames);
2845: return %loadnames;
2846: }
2847: }
2848:
1.551 albertel 2849: sub flush_email_cache {
2850: my ($uname,$udom)=@_;
2851: if (!$udom) { $udom =$env{'user.domain'}; }
2852: if (!$uname) { $uname=$env{'user.name'}; }
2853: return if ($udom eq 'public' && $uname eq 'public');
2854: my $id=$uname.':'.$udom;
2855: &Apache::lonnet::devalidate_cache_new('emailscache',$id);
2856: }
2857:
1.728 raeburn 2858: # -------------------------------------------------------------------- getlangs
2859:
2860: =pod
2861:
2862: =item * &getlangs($uname,$udom)
2863:
2864: Gets a user's language preference and returns it as a hash with key:
2865: language.
2866:
2867: =cut
2868:
2869:
2870: sub getlangs {
2871: my ($uname,$udom) = @_;
2872: if (!$udom) { $udom =$env{'user.domain'}; }
2873: if (!$uname) { $uname=$env{'user.name'}; }
2874: my $id=$uname.':'.$udom;
2875: my ($langs,$cached)=&Apache::lonnet::is_cached_new('userlangs',$id);
2876: if ($cached) {
2877: return %{$langs};
2878: } else {
2879: my %loadlangs=&Apache::lonnet::get('environment',['languages'],
2880: $udom,$uname);
2881: &Apache::lonnet::do_cache_new('userlangs',$id,\%loadlangs);
2882: return %loadlangs;
2883: }
2884: }
2885:
2886: sub flush_langs_cache {
2887: my ($uname,$udom)=@_;
2888: if (!$udom) { $udom =$env{'user.domain'}; }
2889: if (!$uname) { $uname=$env{'user.name'}; }
2890: return if ($udom eq 'public' && $uname eq 'public');
2891: my $id=$uname.':'.$udom;
2892: &Apache::lonnet::devalidate_cache_new('userlangs',$id);
2893: }
2894:
1.61 www 2895: # ------------------------------------------------------------------ Screenname
1.81 albertel 2896:
2897: =pod
2898:
1.648 raeburn 2899: =item * &screenname($uname,$udom)
1.81 albertel 2900:
2901: Gets a users screenname and returns it as a string
2902:
2903: =cut
1.61 www 2904:
2905: sub screenname {
2906: my ($uname,$udom)=@_;
1.258 albertel 2907: if ($uname eq $env{'user.name'} &&
2908: $udom eq $env{'user.domain'}) {return $env{'environment.screenname'};}
1.212 albertel 2909: my %names=&Apache::lonnet::get('environment',['screenname'],$udom,$uname);
1.68 albertel 2910: return $names{'screenname'};
1.62 www 2911: }
2912:
1.212 albertel 2913:
1.802 bisitz 2914: # ------------------------------------------------------------- Confirm Wrapper
2915: =pod
2916:
2917: =item confirmwrapper
2918:
2919: Wrap messages about completion of operation in box
2920:
2921: =cut
2922:
2923: sub confirmwrapper {
2924: my ($message)=@_;
2925: if ($message) {
2926: return "\n".'<div class="LC_confirm_box">'."\n"
2927: .$message."\n"
2928: .'</div>'."\n";
2929: } else {
2930: return $message;
2931: }
2932: }
2933:
1.62 www 2934: # ------------------------------------------------------------- Message Wrapper
2935:
2936: sub messagewrapper {
1.369 www 2937: my ($link,$username,$domain,$subject,$text)=@_;
1.62 www 2938: return
1.441 albertel 2939: '<a href="/adm/email?compose=individual&'.
2940: 'recname='.$username.'&recdom='.$domain.
2941: '&subject='.&escape($subject).'&text='.&escape($text).'" '.
1.200 matthew 2942: 'title="'.&mt('Send message').'">'.$link.'</a>';
1.74 www 2943: }
1.802 bisitz 2944:
1.74 www 2945: # --------------------------------------------------------------- Notes Wrapper
2946:
2947: sub noteswrapper {
2948: my ($link,$un,$do)=@_;
2949: return
2950: "<a href='/adm/email?recordftf=retrieve&recname=$un&recdom=$do'>$link</a>";
1.62 www 2951: }
1.802 bisitz 2952:
1.62 www 2953: # ------------------------------------------------------------- Aboutme Wrapper
2954:
2955: sub aboutmewrapper {
1.166 www 2956: my ($link,$username,$domain,$target)=@_;
1.447 raeburn 2957: if (!defined($username) && !defined($domain)) {
2958: return;
2959: }
1.205 www 2960: return '<a href="/adm/'.$domain.'/'.$username.'/aboutme"'.
1.756 weissno 2961: ($target?' target="$target"':'').' title="'.&mt("View this user's personal information page").'">'.$link.'</a>';
1.62 www 2962: }
2963:
2964: # ------------------------------------------------------------ Syllabus Wrapper
2965:
2966: sub syllabuswrapper {
1.707 bisitz 2967: my ($linktext,$coursedir,$domain)=@_;
1.208 matthew 2968: return qq{<a href="/public/$domain/$coursedir/syllabus">$linktext</a>};
1.61 www 2969: }
1.14 harris41 2970:
1.802 bisitz 2971: # -----------------------------------------------------------------------------
2972:
1.208 matthew 2973: sub track_student_link {
1.268 albertel 2974: my ($linktext,$sname,$sdom,$target,$start) = @_;
2975: my $link ="/adm/trackstudent?";
1.208 matthew 2976: my $title = 'View recent activity';
2977: if (defined($sname) && $sname !~ /^\s*$/ &&
2978: defined($sdom) && $sdom !~ /^\s*$/) {
1.268 albertel 2979: $link .= "selected_student=$sname:$sdom";
1.208 matthew 2980: $title .= ' of this student';
1.268 albertel 2981: }
1.208 matthew 2982: if (defined($target) && $target !~ /^\s*$/) {
2983: $target = qq{target="$target"};
2984: } else {
2985: $target = '';
2986: }
1.268 albertel 2987: if ($start) { $link.='&start='.$start; }
1.554 albertel 2988: $title = &mt($title);
2989: $linktext = &mt($linktext);
1.448 albertel 2990: return qq{<a href="$link" title="$title" $target>$linktext</a>}.
2991: &help_open_topic('View_recent_activity');
1.208 matthew 2992: }
2993:
1.781 raeburn 2994: sub slot_reservations_link {
2995: my ($linktext,$sname,$sdom,$target) = @_;
2996: my $link ="/adm/slotrequest?command=showresv&origin=aboutme";
2997: my $title = 'View slot reservation history';
2998: if (defined($sname) && $sname !~ /^\s*$/ &&
2999: defined($sdom) && $sdom !~ /^\s*$/) {
3000: $link .= "&uname=$sname&udom=$sdom";
3001: $title .= ' of this student';
3002: }
3003: if (defined($target) && $target !~ /^\s*$/) {
3004: $target = qq{target="$target"};
3005: } else {
3006: $target = '';
3007: }
3008: $title = &mt($title);
3009: $linktext = &mt($linktext);
3010: return qq{<a href="$link" title="$title" $target>$linktext</a>};
3011: # FIXME uncomment when help item created: &help_open_topic('Slot_Reservation_History');
3012:
3013: }
3014:
1.508 www 3015: # ===================================================== Display a student photo
3016:
3017:
1.509 albertel 3018: sub student_image_tag {
1.508 www 3019: my ($domain,$user)=@_;
3020: my $imgsrc=&Apache::lonnet::studentphoto($domain,$user,'jpg');
3021: if (($imgsrc) && ($imgsrc ne '/adm/lonKaputt/lonlogo_broken.gif')) {
3022: return '<img src="'.$imgsrc.'" align="right" />';
3023: } else {
3024: return '';
3025: }
3026: }
3027:
1.112 bowersj2 3028: =pod
3029:
3030: =back
3031:
3032: =head1 Access .tab File Data
3033:
3034: =over 4
3035:
1.648 raeburn 3036: =item * &languageids()
1.112 bowersj2 3037:
3038: returns list of all language ids
3039:
3040: =cut
3041:
1.14 harris41 3042: sub languageids {
1.16 harris41 3043: return sort(keys(%language));
1.14 harris41 3044: }
3045:
1.112 bowersj2 3046: =pod
3047:
1.648 raeburn 3048: =item * &languagedescription()
1.112 bowersj2 3049:
3050: returns description of a specified language id
3051:
3052: =cut
3053:
1.14 harris41 3054: sub languagedescription {
1.125 www 3055: my $code=shift;
3056: return ($supported_language{$code}?'* ':'').
3057: $language{$code}.
1.126 www 3058: ($supported_language{$code}?' ('.&mt('interface available').')':'');
1.145 www 3059: }
3060:
3061: sub plainlanguagedescription {
3062: my $code=shift;
3063: return $language{$code};
3064: }
3065:
3066: sub supportedlanguagecode {
3067: my $code=shift;
3068: return $supported_language{$code};
1.97 www 3069: }
3070:
1.112 bowersj2 3071: =pod
3072:
1.648 raeburn 3073: =item * ©rightids()
1.112 bowersj2 3074:
3075: returns list of all copyrights
3076:
3077: =cut
3078:
3079: sub copyrightids {
3080: return sort(keys(%cprtag));
3081: }
3082:
3083: =pod
3084:
1.648 raeburn 3085: =item * ©rightdescription()
1.112 bowersj2 3086:
3087: returns description of a specified copyright id
3088:
3089: =cut
3090:
3091: sub copyrightdescription {
1.166 www 3092: return &mt($cprtag{shift(@_)});
1.112 bowersj2 3093: }
1.197 matthew 3094:
3095: =pod
3096:
1.648 raeburn 3097: =item * &source_copyrightids()
1.192 taceyjo1 3098:
3099: returns list of all source copyrights
3100:
3101: =cut
3102:
3103: sub source_copyrightids {
3104: return sort(keys(%scprtag));
3105: }
3106:
3107: =pod
3108:
1.648 raeburn 3109: =item * &source_copyrightdescription()
1.192 taceyjo1 3110:
3111: returns description of a specified source copyright id
3112:
3113: =cut
3114:
3115: sub source_copyrightdescription {
3116: return &mt($scprtag{shift(@_)});
3117: }
1.112 bowersj2 3118:
3119: =pod
3120:
1.648 raeburn 3121: =item * &filecategories()
1.112 bowersj2 3122:
3123: returns list of all file categories
3124:
3125: =cut
3126:
3127: sub filecategories {
3128: return sort(keys(%category_extensions));
3129: }
3130:
3131: =pod
3132:
1.648 raeburn 3133: =item * &filecategorytypes()
1.112 bowersj2 3134:
3135: returns list of file types belonging to a given file
3136: category
3137:
3138: =cut
3139:
3140: sub filecategorytypes {
1.356 albertel 3141: my ($cat) = @_;
3142: return @{$category_extensions{lc($cat)}};
1.112 bowersj2 3143: }
3144:
3145: =pod
3146:
1.648 raeburn 3147: =item * &fileembstyle()
1.112 bowersj2 3148:
3149: returns embedding style for a specified file type
3150:
3151: =cut
3152:
3153: sub fileembstyle {
3154: return $fe{lc(shift(@_))};
1.169 www 3155: }
3156:
1.351 www 3157: sub filemimetype {
3158: return $fm{lc(shift(@_))};
3159: }
3160:
1.169 www 3161:
3162: sub filecategoryselect {
3163: my ($name,$value)=@_;
1.189 matthew 3164: return &select_form($value,$name,
1.169 www 3165: '' => &mt('Any category'),
3166: map { $_,$_ } sort(keys(%category_extensions)));
1.112 bowersj2 3167: }
3168:
3169: =pod
3170:
1.648 raeburn 3171: =item * &filedescription()
1.112 bowersj2 3172:
3173: returns description for a specified file type
3174:
3175: =cut
3176:
3177: sub filedescription {
1.188 matthew 3178: my $file_description = $fd{lc(shift())};
3179: $file_description =~ s:([\[\]]):~$1:g;
3180: return &mt($file_description);
1.112 bowersj2 3181: }
3182:
3183: =pod
3184:
1.648 raeburn 3185: =item * &filedescriptionex()
1.112 bowersj2 3186:
3187: returns description for a specified file type with
3188: extra formatting
3189:
3190: =cut
3191:
3192: sub filedescriptionex {
3193: my $ex=shift;
1.188 matthew 3194: my $file_description = $fd{lc($ex)};
3195: $file_description =~ s:([\[\]]):~$1:g;
3196: return '.'.$ex.' '.&mt($file_description);
1.112 bowersj2 3197: }
3198:
3199: # End of .tab access
3200: =pod
3201:
3202: =back
3203:
3204: =cut
3205:
3206: # ------------------------------------------------------------------ File Types
3207: sub fileextensions {
3208: return sort(keys(%fe));
3209: }
3210:
1.97 www 3211: # ----------------------------------------------------------- Display Languages
3212: # returns a hash with all desired display languages
3213: #
3214:
3215: sub display_languages {
3216: my %languages=();
1.695 raeburn 3217: foreach my $lang (&Apache::lonlocal::preferred_languages()) {
1.356 albertel 3218: $languages{$lang}=1;
1.97 www 3219: }
3220: &get_unprocessed_cgi($ENV{'QUERY_STRING'},['displaylanguage']);
1.258 albertel 3221: if ($env{'form.displaylanguage'}) {
1.356 albertel 3222: foreach my $lang (split(/\s*(\,|\;|\:)\s*/,$env{'form.displaylanguage'})) {
3223: $languages{$lang}=1;
1.97 www 3224: }
3225: }
3226: return %languages;
1.14 harris41 3227: }
3228:
1.582 albertel 3229: sub languages {
3230: my ($possible_langs) = @_;
1.695 raeburn 3231: my @preferred_langs = &Apache::lonlocal::preferred_languages();
1.582 albertel 3232: if (!ref($possible_langs)) {
3233: if( wantarray ) {
3234: return @preferred_langs;
3235: } else {
3236: return $preferred_langs[0];
3237: }
3238: }
3239: my %possibilities = map { $_ => 1 } (@$possible_langs);
3240: my @preferred_possibilities;
3241: foreach my $preferred_lang (@preferred_langs) {
3242: if (exists($possibilities{$preferred_lang})) {
3243: push(@preferred_possibilities, $preferred_lang);
3244: }
3245: }
3246: if( wantarray ) {
3247: return @preferred_possibilities;
3248: }
3249: return $preferred_possibilities[0];
3250: }
3251:
1.742 raeburn 3252: sub user_lang {
3253: my ($touname,$toudom,$fromcid) = @_;
3254: my @userlangs;
3255: if (($fromcid ne '') && ($env{'course.'.$fromcid.'.languages'} ne '')) {
3256: @userlangs=(@userlangs,split(/\s*(\,|\;|\:)\s*/,
3257: $env{'course.'.$fromcid.'.languages'}));
3258: } else {
3259: my %langhash = &getlangs($touname,$toudom);
3260: if ($langhash{'languages'} ne '') {
3261: @userlangs = split(/\s*(\,|\;|\:)\s*/,$langhash{'languages'});
3262: } else {
3263: my %domdefs = &Apache::lonnet::get_domain_defaults($toudom);
3264: if ($domdefs{'lang_def'} ne '') {
3265: @userlangs = ($domdefs{'lang_def'});
3266: }
3267: }
3268: }
3269: my @languages=&Apache::lonlocal::get_genlanguages(@userlangs);
3270: my $user_lh = Apache::localize->get_handle(@languages);
3271: return $user_lh;
3272: }
3273:
3274:
1.112 bowersj2 3275: ###############################################################
3276: ## Student Answer Attempts ##
3277: ###############################################################
3278:
3279: =pod
3280:
3281: =head1 Alternate Problem Views
3282:
3283: =over 4
3284:
1.648 raeburn 3285: =item * &get_previous_attempt($symb, $username, $domain, $course,
1.112 bowersj2 3286: $getattempt, $regexp, $gradesub)
3287:
3288: Return string with previous attempt on problem. Arguments:
3289:
3290: =over 4
3291:
3292: =item * $symb: Problem, including path
3293:
3294: =item * $username: username of the desired student
3295:
3296: =item * $domain: domain of the desired student
1.14 harris41 3297:
1.112 bowersj2 3298: =item * $course: Course ID
1.14 harris41 3299:
1.112 bowersj2 3300: =item * $getattempt: Leave blank for all attempts, otherwise put
3301: something
1.14 harris41 3302:
1.112 bowersj2 3303: =item * $regexp: if string matches this regexp, the string will be
3304: sent to $gradesub
1.14 harris41 3305:
1.112 bowersj2 3306: =item * $gradesub: routine that processes the string if it matches $regexp
1.14 harris41 3307:
1.112 bowersj2 3308: =back
1.14 harris41 3309:
1.112 bowersj2 3310: The output string is a table containing all desired attempts, if any.
1.16 harris41 3311:
1.112 bowersj2 3312: =cut
1.1 albertel 3313:
3314: sub get_previous_attempt {
1.43 ng 3315: my ($symb,$username,$domain,$course,$getattempt,$regexp,$gradesub)=@_;
1.1 albertel 3316: my $prevattempts='';
1.43 ng 3317: no strict 'refs';
1.1 albertel 3318: if ($symb) {
1.3 albertel 3319: my (%returnhash)=
3320: &Apache::lonnet::restore($symb,$course,$domain,$username);
1.1 albertel 3321: if ($returnhash{'version'}) {
3322: my %lasthash=();
3323: my $version;
3324: for ($version=1;$version<=$returnhash{'version'};$version++) {
1.356 albertel 3325: foreach my $key (sort(split(/\:/,$returnhash{$version.':keys'}))) {
3326: $lasthash{$key}=$returnhash{$version.':'.$key};
1.19 harris41 3327: }
1.1 albertel 3328: }
1.596 albertel 3329: $prevattempts=&start_data_table().&start_data_table_header_row();
3330: $prevattempts.='<th>'.&mt('History').'</th>';
1.356 albertel 3331: foreach my $key (sort(keys(%lasthash))) {
3332: my ($ign,@parts) = split(/\./,$key);
1.41 ng 3333: if ($#parts > 0) {
1.31 albertel 3334: my $data=$parts[-1];
3335: pop(@parts);
1.596 albertel 3336: $prevattempts.='<th>'.&mt('Part ').join('.',@parts).'<br />'.$data.' </th>';
1.31 albertel 3337: } else {
1.41 ng 3338: if ($#parts == 0) {
3339: $prevattempts.='<th>'.$parts[0].'</th>';
3340: } else {
3341: $prevattempts.='<th>'.$ign.'</th>';
3342: }
1.31 albertel 3343: }
1.16 harris41 3344: }
1.596 albertel 3345: $prevattempts.=&end_data_table_header_row();
1.40 ng 3346: if ($getattempt eq '') {
3347: for ($version=1;$version<=$returnhash{'version'};$version++) {
1.596 albertel 3348: $prevattempts.=&start_data_table_row().
3349: '<td>'.&mt('Transaction [_1]',$version).'</td>';
1.356 albertel 3350: foreach my $key (sort(keys(%lasthash))) {
1.581 albertel 3351: my $value = &format_previous_attempt_value($key,
3352: $returnhash{$version.':'.$key});
3353: $prevattempts.='<td>'.$value.' </td>';
1.40 ng 3354: }
1.596 albertel 3355: $prevattempts.=&end_data_table_row();
1.40 ng 3356: }
1.1 albertel 3357: }
1.596 albertel 3358: $prevattempts.=&start_data_table_row().'<td>'.&mt('Current').'</td>';
1.356 albertel 3359: foreach my $key (sort(keys(%lasthash))) {
1.581 albertel 3360: my $value = &format_previous_attempt_value($key,$lasthash{$key});
1.356 albertel 3361: if ($key =~/$regexp$/ && (defined &$gradesub)) {$value = &$gradesub($value)}
1.40 ng 3362: $prevattempts.='<td>'.$value.' </td>';
1.16 harris41 3363: }
1.596 albertel 3364: $prevattempts.= &end_data_table_row().&end_data_table();
1.1 albertel 3365: } else {
1.596 albertel 3366: $prevattempts=
3367: &start_data_table().&start_data_table_row().
3368: '<td>'.&mt('Nothing submitted - no attempts.').'</td>'.
3369: &end_data_table_row().&end_data_table();
1.1 albertel 3370: }
3371: } else {
1.596 albertel 3372: $prevattempts=
3373: &start_data_table().&start_data_table_row().
3374: '<td>'.&mt('No data.').'</td>'.
3375: &end_data_table_row().&end_data_table();
1.1 albertel 3376: }
1.10 albertel 3377: }
3378:
1.581 albertel 3379: sub format_previous_attempt_value {
3380: my ($key,$value) = @_;
3381: if ($key =~ /timestamp/) {
3382: $value = &Apache::lonlocal::locallocaltime($value);
3383: } elsif (ref($value) eq 'ARRAY') {
3384: $value = '('.join(', ', @{ $value }).')';
3385: } else {
3386: $value = &unescape($value);
3387: }
3388: return $value;
3389: }
3390:
3391:
1.107 albertel 3392: sub relative_to_absolute {
3393: my ($url,$output)=@_;
3394: my $parser=HTML::TokeParser->new(\$output);
3395: my $token;
3396: my $thisdir=$url;
3397: my @rlinks=();
3398: while ($token=$parser->get_token) {
3399: if ($token->[0] eq 'S') {
3400: if ($token->[1] eq 'a') {
3401: if ($token->[2]->{'href'}) {
3402: $rlinks[$#rlinks+1]=$token->[2]->{'href'};
3403: }
3404: } elsif ($token->[1] eq 'img' || $token->[1] eq 'embed' ) {
3405: $rlinks[$#rlinks+1]=$token->[2]->{'src'};
3406: } elsif ($token->[1] eq 'base') {
3407: $thisdir=$token->[2]->{'href'};
3408: }
3409: }
3410: }
3411: $thisdir=~s-/[^/]*$--;
1.356 albertel 3412: foreach my $link (@rlinks) {
1.726 raeburn 3413: unless (($link=~/^https?\:\/\//i) ||
1.356 albertel 3414: ($link=~/^\//) ||
3415: ($link=~/^javascript:/i) ||
3416: ($link=~/^mailto:/i) ||
3417: ($link=~/^\#/)) {
3418: my $newlocation=&Apache::lonnet::hreflocation($thisdir,$link);
3419: $output=~s/(\"|\'|\=\s*)\Q$link\E(\"|\'|\s|\>)/$1$newlocation$2/;
1.107 albertel 3420: }
3421: }
3422: # -------------------------------------------------- Deal with Applet codebases
3423: $output=~s/(\<applet[^\>]+)(codebase\=[^\S\>]+)*([^\>]*)\>/$1.($2?$2:' codebase="'.$thisdir.'"').$3.'>'/gei;
3424: return $output;
3425: }
3426:
1.112 bowersj2 3427: =pod
3428:
1.648 raeburn 3429: =item * &get_student_view()
1.112 bowersj2 3430:
3431: show a snapshot of what student was looking at
3432:
3433: =cut
3434:
1.10 albertel 3435: sub get_student_view {
1.186 albertel 3436: my ($symb,$username,$domain,$courseid,$target,$moreenv) = @_;
1.114 www 3437: my ($map,$id,$feedurl) = &Apache::lonnet::decode_symb($symb);
1.186 albertel 3438: my (%form);
1.10 albertel 3439: my @elements=('symb','courseid','domain','username');
3440: foreach my $element (@elements) {
1.186 albertel 3441: $form{'grade_'.$element}=eval '$'.$element #'
1.10 albertel 3442: }
1.186 albertel 3443: if (defined($moreenv)) {
3444: %form=(%form,%{$moreenv});
3445: }
1.236 albertel 3446: if (defined($target)) { $form{'grade_target'} = $target; }
1.107 albertel 3447: $feedurl=&Apache::lonnet::clutter($feedurl);
1.650 www 3448: my ($userview,$response)=&Apache::lonnet::ssi_body($feedurl,%form);
1.11 albertel 3449: $userview=~s/\<body[^\>]*\>//gi;
3450: $userview=~s/\<\/body\>//gi;
3451: $userview=~s/\<html\>//gi;
3452: $userview=~s/\<\/html\>//gi;
3453: $userview=~s/\<head\>//gi;
3454: $userview=~s/\<\/head\>//gi;
3455: $userview=~s/action\s*\=/would_be_action\=/gi;
1.107 albertel 3456: $userview=&relative_to_absolute($feedurl,$userview);
1.650 www 3457: if (wantarray) {
3458: return ($userview,$response);
3459: } else {
3460: return $userview;
3461: }
3462: }
3463:
3464: sub get_student_view_with_retries {
3465: my ($symb,$retries,$username,$domain,$courseid,$target,$moreenv) = @_;
3466:
3467: my $ok = 0; # True if we got a good response.
3468: my $content;
3469: my $response;
3470:
3471: # Try to get the student_view done. within the retries count:
3472:
3473: do {
3474: ($content, $response) = &get_student_view($symb,$username,$domain,$courseid,$target,$moreenv);
3475: $ok = $response->is_success;
3476: if (!$ok) {
3477: &Apache::lonnet::logthis("Failed get_student_view_with_retries on $symb: ".$response->is_success.', '.$response->code.', '.$response->message);
3478: }
3479: $retries--;
3480: } while (!$ok && ($retries > 0));
3481:
3482: if (!$ok) {
3483: $content = ''; # On error return an empty content.
3484: }
1.651 www 3485: if (wantarray) {
3486: return ($content, $response);
3487: } else {
3488: return $content;
3489: }
1.11 albertel 3490: }
3491:
1.112 bowersj2 3492: =pod
3493:
1.648 raeburn 3494: =item * &get_student_answers()
1.112 bowersj2 3495:
3496: show a snapshot of how student was answering problem
3497:
3498: =cut
3499:
1.11 albertel 3500: sub get_student_answers {
1.100 sakharuk 3501: my ($symb,$username,$domain,$courseid,%form) = @_;
1.114 www 3502: my ($map,$id,$feedurl) = &Apache::lonnet::decode_symb($symb);
1.186 albertel 3503: my (%moreenv);
1.11 albertel 3504: my @elements=('symb','courseid','domain','username');
3505: foreach my $element (@elements) {
1.186 albertel 3506: $moreenv{'grade_'.$element}=eval '$'.$element #'
1.10 albertel 3507: }
1.186 albertel 3508: $moreenv{'grade_target'}='answer';
3509: %moreenv=(%form,%moreenv);
1.497 raeburn 3510: $feedurl = &Apache::lonnet::clutter($feedurl);
3511: my $userview=&Apache::lonnet::ssi($feedurl,%moreenv);
1.10 albertel 3512: return $userview;
1.1 albertel 3513: }
1.116 albertel 3514:
3515: =pod
3516:
3517: =item * &submlink()
3518:
1.242 albertel 3519: Inputs: $text $uname $udom $symb $target
1.116 albertel 3520:
3521: Returns: A link to grades.pm such as to see the SUBM view of a student
3522:
3523: =cut
3524:
3525: ###############################################
3526: sub submlink {
1.242 albertel 3527: my ($text,$uname,$udom,$symb,$target)=@_;
1.116 albertel 3528: if (!($uname && $udom)) {
3529: (my $cursymb, my $courseid,$udom,$uname)=
1.463 albertel 3530: &Apache::lonnet::whichuser($symb);
1.116 albertel 3531: if (!$symb) { $symb=$cursymb; }
3532: }
1.254 matthew 3533: if (!$symb) { $symb=&Apache::lonnet::symbread(); }
1.369 www 3534: $symb=&escape($symb);
1.242 albertel 3535: if ($target) { $target="target=\"$target\""; }
3536: return '<a href="/adm/grades?&command=submission&'.
3537: 'symb='.$symb.'&student='.$uname.
3538: '&userdom='.$udom.'" '.$target.'>'.$text.'</a>';
3539: }
3540: ##############################################
3541:
3542: =pod
3543:
3544: =item * &pgrdlink()
3545:
3546: Inputs: $text $uname $udom $symb $target
3547:
3548: Returns: A link to grades.pm such as to see the PGRD view of a student
3549:
3550: =cut
3551:
3552: ###############################################
3553: sub pgrdlink {
3554: my $link=&submlink(@_);
3555: $link=~s/(&command=submission)/$1&showgrading=yes/;
3556: return $link;
3557: }
3558: ##############################################
3559:
3560: =pod
3561:
3562: =item * &pprmlink()
3563:
3564: Inputs: $text $uname $udom $symb $target
3565:
3566: Returns: A link to parmset.pm such as to see the PPRM view of a
1.283 albertel 3567: student and a specific resource
1.242 albertel 3568:
3569: =cut
3570:
3571: ###############################################
3572: sub pprmlink {
3573: my ($text,$uname,$udom,$symb,$target)=@_;
3574: if (!($uname && $udom)) {
3575: (my $cursymb, my $courseid,$udom,$uname)=
1.463 albertel 3576: &Apache::lonnet::whichuser($symb);
1.242 albertel 3577: if (!$symb) { $symb=$cursymb; }
3578: }
1.254 matthew 3579: if (!$symb) { $symb=&Apache::lonnet::symbread(); }
1.369 www 3580: $symb=&escape($symb);
1.242 albertel 3581: if ($target) { $target="target=\"$target\""; }
1.595 albertel 3582: return '<a href="/adm/parmset?command=set&'.
3583: 'symb='.$symb.'&uname='.$uname.
3584: '&udom='.$udom.'" '.$target.'>'.$text.'</a>';
1.116 albertel 3585: }
3586: ##############################################
1.37 matthew 3587:
1.112 bowersj2 3588: =pod
3589:
3590: =back
3591:
3592: =cut
3593:
1.37 matthew 3594: ###############################################
1.51 www 3595:
3596:
3597: sub timehash {
1.687 raeburn 3598: my ($thistime) = @_;
3599: my $timezone = &Apache::lonlocal::gettimezone();
3600: my $dt = DateTime->from_epoch(epoch => $thistime)
3601: ->set_time_zone($timezone);
3602: my $wday = $dt->day_of_week();
3603: if ($wday == 7) { $wday = 0; }
3604: return ( 'second' => $dt->second(),
3605: 'minute' => $dt->minute(),
3606: 'hour' => $dt->hour(),
3607: 'day' => $dt->day_of_month(),
3608: 'month' => $dt->month(),
3609: 'year' => $dt->year(),
3610: 'weekday' => $wday,
3611: 'dayyear' => $dt->day_of_year(),
3612: 'dlsav' => $dt->is_dst() );
1.51 www 3613: }
3614:
1.370 www 3615: sub utc_string {
3616: my ($date)=@_;
1.371 www 3617: return strftime("%Y%m%dT%H%M%SZ",gmtime($date));
1.370 www 3618: }
3619:
1.51 www 3620: sub maketime {
3621: my %th=@_;
1.687 raeburn 3622: my ($epoch_time,$timezone,$dt);
3623: $timezone = &Apache::lonlocal::gettimezone();
3624: eval {
3625: $dt = DateTime->new( year => $th{'year'},
3626: month => $th{'month'},
3627: day => $th{'day'},
3628: hour => $th{'hour'},
3629: minute => $th{'minute'},
3630: second => $th{'second'},
3631: time_zone => $timezone,
3632: );
3633: };
3634: if (!$@) {
3635: $epoch_time = $dt->epoch;
3636: if ($epoch_time) {
3637: return $epoch_time;
3638: }
3639: }
1.51 www 3640: return POSIX::mktime(
3641: ($th{'seconds'},$th{'minutes'},$th{'hours'},
1.210 www 3642: $th{'day'},$th{'month'}-1,$th{'year'}-1900,0,0,-1));
1.70 www 3643: }
3644:
3645: #########################################
1.51 www 3646:
3647: sub findallcourses {
1.482 raeburn 3648: my ($roles,$uname,$udom) = @_;
1.355 albertel 3649: my %roles;
3650: if (ref($roles)) { %roles = map { $_ => 1 } @{$roles}; }
1.348 albertel 3651: my %courses;
1.51 www 3652: my $now=time;
1.482 raeburn 3653: if (!defined($uname)) {
3654: $uname = $env{'user.name'};
3655: }
3656: if (!defined($udom)) {
3657: $udom = $env{'user.domain'};
3658: }
3659: if (($uname ne $env{'user.name'}) || ($udom ne $env{'user.domain'})) {
3660: my %roleshash = &Apache::lonnet::dump('roles',$udom,$uname);
3661: if (!%roles) {
3662: %roles = (
3663: cc => 1,
3664: in => 1,
3665: ep => 1,
3666: ta => 1,
3667: cr => 1,
3668: st => 1,
3669: );
3670: }
3671: foreach my $entry (keys(%roleshash)) {
3672: my ($trole,$tend,$tstart) = split(/_/,$roleshash{$entry});
3673: if ($trole =~ /^cr/) {
3674: next if (!exists($roles{$trole}) && !exists($roles{'cr'}));
3675: } else {
3676: next if (!exists($roles{$trole}));
3677: }
3678: if ($tend) {
3679: next if ($tend < $now);
3680: }
3681: if ($tstart) {
3682: next if ($tstart > $now);
3683: }
3684: my ($cdom,$cnum,$sec,$cnumpart,$secpart,$role,$realsec);
3685: (undef,$cdom,$cnumpart,$secpart) = split(/\//,$entry);
3686: if ($secpart eq '') {
3687: ($cnum,$role) = split(/_/,$cnumpart);
3688: $sec = 'none';
3689: $realsec = '';
3690: } else {
3691: $cnum = $cnumpart;
3692: ($sec,$role) = split(/_/,$secpart);
3693: $realsec = $sec;
1.490 raeburn 3694: }
1.482 raeburn 3695: $courses{$cdom.'_'.$cnum}{$sec} = $trole.'/'.$cdom.'/'.$cnum.'/'.$realsec;
3696: }
3697: } else {
3698: foreach my $key (keys(%env)) {
1.483 albertel 3699: if ( $key=~m{^user\.role\.(\w+)\./($match_domain)/($match_courseid)/?(\w*)$} ||
3700: $key=~m{^user\.role\.(cr/$match_domain/$match_username/\w+)\./($match_domain)/($match_courseid)/?(\w*)$}) {
1.482 raeburn 3701: my ($role,$cdom,$cnum,$sec) = ($1,$2,$3,$4);
3702: next if ($role eq 'ca' || $role eq 'aa');
3703: next if (%roles && !exists($roles{$role}));
3704: my ($starttime,$endtime)=split(/\./,$env{$key});
3705: my $active=1;
3706: if ($starttime) {
3707: if ($now<$starttime) { $active=0; }
3708: }
3709: if ($endtime) {
3710: if ($now>$endtime) { $active=0; }
3711: }
3712: if ($active) {
3713: if ($sec eq '') {
3714: $sec = 'none';
3715: }
3716: $courses{$cdom.'_'.$cnum}{$sec} =
3717: $role.'/'.$cdom.'/'.$cnum.'/'.$sec;
1.474 raeburn 3718: }
3719: }
1.51 www 3720: }
3721: }
1.474 raeburn 3722: return %courses;
1.51 www 3723: }
1.37 matthew 3724:
1.54 www 3725: ###############################################
1.474 raeburn 3726:
3727: sub blockcheck {
1.482 raeburn 3728: my ($setters,$activity,$uname,$udom) = @_;
1.490 raeburn 3729:
3730: if (!defined($udom)) {
3731: $udom = $env{'user.domain'};
3732: }
3733: if (!defined($uname)) {
3734: $uname = $env{'user.name'};
3735: }
3736:
3737: # If uname and udom are for a course, check for blocks in the course.
3738:
3739: if (&Apache::lonnet::is_course($udom,$uname)) {
3740: my %records = &Apache::lonnet::dump('comm_block',$udom,$uname);
1.502 raeburn 3741: my ($startblock,$endblock)=&get_blocks($setters,$activity,$udom,$uname);
1.490 raeburn 3742: return ($startblock,$endblock);
3743: }
1.474 raeburn 3744:
1.502 raeburn 3745: my $startblock = 0;
3746: my $endblock = 0;
1.482 raeburn 3747: my %live_courses = &findallcourses(undef,$uname,$udom);
1.474 raeburn 3748:
1.490 raeburn 3749: # If uname is for a user, and activity is course-specific, i.e.,
3750: # boards, chat or groups, check for blocking in current course only.
1.474 raeburn 3751:
1.490 raeburn 3752: if (($activity eq 'boards' || $activity eq 'chat' ||
3753: $activity eq 'groups') && ($env{'request.course.id'})) {
3754: foreach my $key (keys(%live_courses)) {
3755: if ($key ne $env{'request.course.id'}) {
3756: delete($live_courses{$key});
3757: }
3758: }
3759: }
3760:
3761: my $otheruser = 0;
3762: my %own_courses;
3763: if ((($uname ne $env{'user.name'})) || ($udom ne $env{'user.domain'})) {
3764: # Resource belongs to user other than current user.
3765: $otheruser = 1;
3766: # Gather courses for current user
3767: %own_courses =
3768: &findallcourses(undef,$env{'user.name'},$env{'user.domain'});
3769: }
3770:
3771: # Gather active course roles - course coordinator, instructor,
3772: # exam proctor, ta, student, or custom role.
1.474 raeburn 3773:
3774: foreach my $course (keys(%live_courses)) {
1.482 raeburn 3775: my ($cdom,$cnum);
3776: if ((defined($env{'course.'.$course.'.domain'})) && (defined($env{'course.'.$course.'.num'}))) {
3777: $cdom = $env{'course.'.$course.'.domain'};
3778: $cnum = $env{'course.'.$course.'.num'};
3779: } else {
1.490 raeburn 3780: ($cdom,$cnum) = split(/_/,$course);
1.482 raeburn 3781: }
3782: my $no_ownblock = 0;
3783: my $no_userblock = 0;
1.533 raeburn 3784: if ($otheruser && $activity ne 'com') {
1.490 raeburn 3785: # Check if current user has 'evb' priv for this
3786: if (defined($own_courses{$course})) {
3787: foreach my $sec (keys(%{$own_courses{$course}})) {
3788: my $checkrole = 'cm./'.$cdom.'/'.$cnum;
3789: if ($sec ne 'none') {
3790: $checkrole .= '/'.$sec;
3791: }
3792: if (&Apache::lonnet::allowed('evb',undef,undef,$checkrole)) {
3793: $no_ownblock = 1;
3794: last;
3795: }
3796: }
3797: }
3798: # if they have 'evb' priv and are currently not playing student
3799: next if (($no_ownblock) &&
3800: ($env{'request.role'} !~ m{^st\./$cdom/$cnum}));
3801: }
1.474 raeburn 3802: foreach my $sec (keys(%{$live_courses{$course}})) {
1.482 raeburn 3803: my $checkrole = 'cm./'.$cdom.'/'.$cnum;
1.474 raeburn 3804: if ($sec ne 'none') {
1.482 raeburn 3805: $checkrole .= '/'.$sec;
1.474 raeburn 3806: }
1.490 raeburn 3807: if ($otheruser) {
3808: # Resource belongs to user other than current user.
3809: # Assemble privs for that user, and check for 'evb' priv.
1.482 raeburn 3810: my ($trole,$tdom,$tnum,$tsec);
3811: my $entry = $live_courses{$course}{$sec};
3812: if ($entry =~ /^cr/) {
3813: ($trole,$tdom,$tnum,$tsec) =
3814: ($entry =~ m|^(cr/$match_domain/$match_username/\w+)\./($match_domain)/($match_username)/?(\w*)$|);
3815: } else {
3816: ($trole,$tdom,$tnum,$tsec) = split(/\//,$entry);
3817: }
3818: my ($spec,$area,$trest,%allroles,%userroles);
3819: $area = '/'.$tdom.'/'.$tnum;
3820: $trest = $tnum;
3821: if ($tsec ne '') {
3822: $area .= '/'.$tsec;
3823: $trest .= '/'.$tsec;
3824: }
3825: $spec = $trole.'.'.$area;
3826: if ($trole =~ /^cr/) {
3827: &Apache::lonnet::custom_roleprivs(\%allroles,$trole,
3828: $tdom,$spec,$trest,$area);
3829: } else {
3830: &Apache::lonnet::standard_roleprivs(\%allroles,$trole,
3831: $tdom,$spec,$trest,$area);
3832: }
3833: my ($author,$adv) = &Apache::lonnet::set_userprivs(\%userroles,\%allroles);
1.486 raeburn 3834: if ($userroles{'user.priv.'.$checkrole} =~ /evb\&([^\:]*)/) {
3835: if ($1) {
3836: $no_userblock = 1;
3837: last;
3838: }
3839: }
1.490 raeburn 3840: } else {
3841: # Resource belongs to current user
3842: # Check for 'evb' priv via lonnet::allowed().
1.482 raeburn 3843: if (&Apache::lonnet::allowed('evb',undef,undef,$checkrole)) {
3844: $no_ownblock = 1;
3845: last;
3846: }
1.474 raeburn 3847: }
3848: }
3849: # if they have the evb priv and are currently not playing student
1.482 raeburn 3850: next if (($no_ownblock) &&
1.491 albertel 3851: ($env{'request.role'} !~ m{^st\./\Q$cdom\E/\Q$cnum\E}));
1.482 raeburn 3852: next if ($no_userblock);
1.474 raeburn 3853:
1.866 kalberla 3854: # Retrieve blocking times and identity of locker for course
1.490 raeburn 3855: # of specified user, unless user has 'evb' privilege.
1.502 raeburn 3856:
3857: my ($start,$end)=&get_blocks($setters,$activity,$cdom,$cnum);
3858: if (($start != 0) &&
3859: (($startblock == 0) || ($startblock > $start))) {
3860: $startblock = $start;
3861: }
3862: if (($end != 0) &&
3863: (($endblock == 0) || ($endblock < $end))) {
3864: $endblock = $end;
3865: }
1.490 raeburn 3866: }
3867: return ($startblock,$endblock);
3868: }
3869:
3870: sub get_blocks {
3871: my ($setters,$activity,$cdom,$cnum) = @_;
3872: my $startblock = 0;
3873: my $endblock = 0;
3874: my $course = $cdom.'_'.$cnum;
3875: $setters->{$course} = {};
3876: $setters->{$course}{'staff'} = [];
3877: $setters->{$course}{'times'} = [];
3878: my %records = &Apache::lonnet::dump('comm_block',$cdom,$cnum);
3879: foreach my $record (keys(%records)) {
3880: my ($start,$end) = ($record =~ m/^(\d+)____(\d+)$/);
3881: if ($start <= time && $end >= time) {
3882: my ($staff_name,$staff_dom,$title,$blocks) =
3883: &parse_block_record($records{$record});
3884: if ($blocks->{$activity} eq 'on') {
3885: push(@{$$setters{$course}{'staff'}},[$staff_name,$staff_dom]);
3886: push(@{$$setters{$course}{'times'}}, [$start,$end]);
1.491 albertel 3887: if ( ($startblock == 0) || ($startblock > $start) ) {
3888: $startblock = $start;
1.490 raeburn 3889: }
1.491 albertel 3890: if ( ($endblock == 0) || ($endblock < $end) ) {
3891: $endblock = $end;
1.474 raeburn 3892: }
3893: }
3894: }
3895: }
3896: return ($startblock,$endblock);
3897: }
3898:
3899: sub parse_block_record {
3900: my ($record) = @_;
3901: my ($setuname,$setudom,$title,$blocks);
3902: if (ref($record) eq 'HASH') {
3903: ($setuname,$setudom) = split(/:/,$record->{'setter'});
3904: $title = &unescape($record->{'event'});
3905: $blocks = $record->{'blocks'};
3906: } else {
3907: my @data = split(/:/,$record,3);
3908: if (scalar(@data) eq 2) {
3909: $title = $data[1];
3910: ($setuname,$setudom) = split(/@/,$data[0]);
3911: } else {
3912: ($setuname,$setudom,$title) = @data;
3913: }
3914: $blocks = { 'com' => 'on' };
3915: }
3916: return ($setuname,$setudom,$title,$blocks);
3917: }
3918:
1.854 kalberla 3919: sub blocking_status {
1.867 kalberla 3920: my $blocked;
1.854 kalberla 3921: my ($activity,$uname,$udom) = @_;
1.867 kalberla 3922: my %setters;
3923: my ($startblock,$endblock)=&blockcheck(\%setters,$activity,$uname,$udom);
3924: if ($startblock && $endblock) {
3925: $blocked = 1;
3926: }
1.854 kalberla 3927: if(!wantarray) {
3928: return $blocked;
3929: }
3930: my $output;
3931: my $querystring;
3932: $querystring = "?activity=$activity";
3933:
3934: $output .= <<"END_MYBLOCK";
3935: <script type="text/javascript">
3936: // <![CDATA[
3937: function openWindow(url, wdwName, w, h, toolbar,scrollbar) {
3938: var options = "width=" + w + ",height=" + h + ",";
3939: options += "resizable=yes,scrollbars="+scrollbar+",status=no,";
3940: options += "menubar=no,toolbar="+toolbar+",location=no,directories=no";
3941: var newWin = window.open(url, wdwName, options);
3942: newWin.focus();
3943: }
3944:
3945: // ]]>
3946: </script>
3947: END_MYBLOCK
3948: my $popupUrl = "/adm/blockingstatus/$querystring";
1.867 kalberla 3949: $output .= <<"END_BLOCK";
3950: <div class='LC_comblock'>
1.869 kalberla 3951: <a onclick='openWindow("$popupUrl","Blocking Table",600,300,"no","no");return false;' href='/adm/blockingstatus/$querystring'
3952: title='Communication Blocked'>
3953: <img class='LC_noBorder LC_middle' title='Communication Blocked' src='/res/adm/pages/comblock.png' alt='Communication Blocked'/></a>
3954: <a onclick='openWindow("$popupUrl","Blocking Table",600,300,"no","no");return false;' href='/adm/blockingstatus/$querystring'
3955: title='Communication Blocked'>Communication Blocked</a>
1.867 kalberla 3956: </div>
3957:
3958: END_BLOCK
1.474 raeburn 3959:
1.854 kalberla 3960: return ($blocked, $output);
3961: }
1.490 raeburn 3962:
1.60 matthew 3963: ###############################################
3964:
1.682 raeburn 3965: sub check_ip_acc {
3966: my ($acc)=@_;
3967: &Apache::lonxml::debug("acc is $acc");
3968: if (!defined($acc) || $acc =~ /^\s*$/ || $acc =~/^\s*no\s*$/i) {
3969: return 1;
3970: }
3971: my $allowed=0;
3972: my $ip=$env{'request.host'} || $ENV{'REMOTE_ADDR'};
3973:
3974: my $name;
3975: foreach my $pattern (split(',',$acc)) {
3976: $pattern =~ s/^\s*//;
3977: $pattern =~ s/\s*$//;
3978: if ($pattern =~ /\*$/) {
3979: #35.8.*
3980: $pattern=~s/\*//;
3981: if ($ip =~ /^\Q$pattern\E/) { $allowed=1; }
3982: } elsif ($pattern =~ /(\d+\.\d+\.\d+)\.\[(\d+)-(\d+)\]$/) {
3983: #35.8.3.[34-56]
3984: my $low=$2;
3985: my $high=$3;
3986: $pattern=$1;
3987: if ($ip =~ /^\Q$pattern\E/) {
3988: my $last=(split(/\./,$ip))[3];
3989: if ($last <=$high && $last >=$low) { $allowed=1; }
3990: }
3991: } elsif ($pattern =~ /^\*/) {
3992: #*.msu.edu
3993: $pattern=~s/\*//;
3994: if (!defined($name)) {
3995: use Socket;
3996: my $netaddr=inet_aton($ip);
3997: ($name)=gethostbyaddr($netaddr,AF_INET);
3998: }
3999: if ($name =~ /\Q$pattern\E$/i) { $allowed=1; }
4000: } elsif ($pattern =~ /\d+\.\d+\.\d+\.\d+/) {
4001: #127.0.0.1
4002: if ($ip =~ /^\Q$pattern\E/) { $allowed=1; }
4003: } else {
4004: #some.name.com
4005: if (!defined($name)) {
4006: use Socket;
4007: my $netaddr=inet_aton($ip);
4008: ($name)=gethostbyaddr($netaddr,AF_INET);
4009: }
4010: if ($name =~ /\Q$pattern\E$/i) { $allowed=1; }
4011: }
4012: if ($allowed) { last; }
4013: }
4014: return $allowed;
4015: }
4016:
4017: ###############################################
4018:
1.60 matthew 4019: =pod
4020:
1.112 bowersj2 4021: =head1 Domain Template Functions
4022:
4023: =over 4
4024:
4025: =item * &determinedomain()
1.60 matthew 4026:
4027: Inputs: $domain (usually will be undef)
4028:
1.63 www 4029: Returns: Determines which domain should be used for designs
1.60 matthew 4030:
4031: =cut
1.54 www 4032:
1.60 matthew 4033: ###############################################
1.63 www 4034: sub determinedomain {
4035: my $domain=shift;
1.531 albertel 4036: if (! $domain) {
1.60 matthew 4037: # Determine domain if we have not been given one
4038: $domain = $Apache::lonnet::perlvar{'lonDefDomain'};
1.258 albertel 4039: if ($env{'user.domain'}) { $domain=$env{'user.domain'}; }
4040: if ($env{'request.role.domain'}) {
4041: $domain=$env{'request.role.domain'};
1.60 matthew 4042: }
4043: }
1.63 www 4044: return $domain;
4045: }
4046: ###############################################
1.517 raeburn 4047:
1.518 albertel 4048: sub devalidate_domconfig_cache {
4049: my ($udom)=@_;
4050: &Apache::lonnet::devalidate_cache_new('domainconfig',$udom);
4051: }
4052:
4053: # ---------------------- Get domain configuration for a domain
4054: sub get_domainconf {
4055: my ($udom) = @_;
4056: my $cachetime=1800;
4057: my ($result,$cached)=&Apache::lonnet::is_cached_new('domainconfig',$udom);
4058: if (defined($cached)) { return %{$result}; }
4059:
4060: my %domconfig = &Apache::lonnet::get_dom('configuration',
4061: ['login','rolecolors'],$udom);
1.632 raeburn 4062: my (%designhash,%legacy);
1.518 albertel 4063: if (keys(%domconfig) > 0) {
4064: if (ref($domconfig{'login'}) eq 'HASH') {
1.632 raeburn 4065: if (keys(%{$domconfig{'login'}})) {
4066: foreach my $key (keys(%{$domconfig{'login'}})) {
1.699 raeburn 4067: if (ref($domconfig{'login'}{$key}) eq 'HASH') {
4068: foreach my $img (keys(%{$domconfig{'login'}{$key}})) {
4069: $designhash{$udom.'.login.'.$key.'_'.$img} =
4070: $domconfig{'login'}{$key}{$img};
4071: }
4072: } else {
4073: $designhash{$udom.'.login.'.$key}=$domconfig{'login'}{$key};
4074: }
1.632 raeburn 4075: }
4076: } else {
4077: $legacy{'login'} = 1;
1.518 albertel 4078: }
1.632 raeburn 4079: } else {
4080: $legacy{'login'} = 1;
1.518 albertel 4081: }
4082: if (ref($domconfig{'rolecolors'}) eq 'HASH') {
1.632 raeburn 4083: if (keys(%{$domconfig{'rolecolors'}})) {
4084: foreach my $role (keys(%{$domconfig{'rolecolors'}})) {
4085: if (ref($domconfig{'rolecolors'}{$role}) eq 'HASH') {
4086: foreach my $item (keys(%{$domconfig{'rolecolors'}{$role}})) {
4087: $designhash{$udom.'.'.$role.'.'.$item}=$domconfig{'rolecolors'}{$role}{$item};
4088: }
1.518 albertel 4089: }
4090: }
1.632 raeburn 4091: } else {
4092: $legacy{'rolecolors'} = 1;
1.518 albertel 4093: }
1.632 raeburn 4094: } else {
4095: $legacy{'rolecolors'} = 1;
1.518 albertel 4096: }
1.632 raeburn 4097: if (keys(%legacy) > 0) {
4098: my %legacyhash = &get_legacy_domconf($udom);
4099: foreach my $item (keys(%legacyhash)) {
4100: if ($item =~ /^\Q$udom\E\.login/) {
4101: if ($legacy{'login'}) {
4102: $designhash{$item} = $legacyhash{$item};
4103: }
4104: } else {
4105: if ($legacy{'rolecolors'}) {
4106: $designhash{$item} = $legacyhash{$item};
4107: }
1.518 albertel 4108: }
4109: }
4110: }
1.632 raeburn 4111: } else {
4112: %designhash = &get_legacy_domconf($udom);
1.518 albertel 4113: }
4114: &Apache::lonnet::do_cache_new('domainconfig',$udom,\%designhash,
4115: $cachetime);
4116: return %designhash;
4117: }
4118:
1.632 raeburn 4119: sub get_legacy_domconf {
4120: my ($udom) = @_;
4121: my %legacyhash;
4122: my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors';
4123: my $designfile = $designdir.'/'.$udom.'.tab';
4124: if (-e $designfile) {
4125: if ( open (my $fh,"<$designfile") ) {
4126: while (my $line = <$fh>) {
4127: next if ($line =~ /^\#/);
4128: chomp($line);
4129: my ($key,$val)=(split(/\=/,$line));
4130: if ($val) { $legacyhash{$udom.'.'.$key}=$val; }
4131: }
4132: close($fh);
4133: }
4134: }
4135: if (-e '/home/httpd/html/adm/lonDomLogos/'.$udom.'.gif') {
4136: $legacyhash{$udom.'.login.domlogo'} = "/adm/lonDomLogos/$udom.gif";
4137: }
4138: return %legacyhash;
4139: }
4140:
1.63 www 4141: =pod
4142:
1.112 bowersj2 4143: =item * &domainlogo()
1.63 www 4144:
4145: Inputs: $domain (usually will be undef)
4146:
4147: Returns: A link to a domain logo, if the domain logo exists.
4148: If the domain logo does not exist, a description of the domain.
4149:
4150: =cut
1.112 bowersj2 4151:
1.63 www 4152: ###############################################
4153: sub domainlogo {
1.517 raeburn 4154: my $domain = &determinedomain(shift);
1.518 albertel 4155: my %designhash = &get_domainconf($domain);
1.517 raeburn 4156: # See if there is a logo
4157: if ($designhash{$domain.'.login.domlogo'} ne '') {
1.519 raeburn 4158: my $imgsrc = $designhash{$domain.'.login.domlogo'};
1.538 albertel 4159: if ($imgsrc =~ m{^/(adm|res)/}) {
4160: if ($imgsrc =~ m{^/res/}) {
4161: my $local_name = &Apache::lonnet::filelocation('',$imgsrc);
4162: &Apache::lonnet::repcopy($local_name);
4163: }
4164: $imgsrc = &lonhttpdurl($imgsrc);
1.519 raeburn 4165: }
4166: return '<img src="'.$imgsrc.'" alt="'.$domain.'" />';
1.514 albertel 4167: } elsif (defined(&Apache::lonnet::domain($domain,'description'))) {
4168: return &Apache::lonnet::domain($domain,'description');
1.59 www 4169: } else {
1.60 matthew 4170: return '';
1.59 www 4171: }
4172: }
1.63 www 4173: ##############################################
4174:
4175: =pod
4176:
1.112 bowersj2 4177: =item * &designparm()
1.63 www 4178:
4179: Inputs: $which parameter; $domain (usually will be undef)
4180:
4181: Returns: value of designparamter $which
4182:
4183: =cut
1.112 bowersj2 4184:
1.397 albertel 4185:
1.400 albertel 4186: ##############################################
1.397 albertel 4187: sub designparm {
4188: my ($which,$domain)=@_;
4189: if (exists($env{'environment.color.'.$which})) {
1.817 bisitz 4190: return $env{'environment.color.'.$which};
1.96 www 4191: }
1.63 www 4192: $domain=&determinedomain($domain);
1.518 albertel 4193: my %domdesign = &get_domainconf($domain);
1.520 raeburn 4194: my $output;
1.517 raeburn 4195: if ($domdesign{$domain.'.'.$which} ne '') {
1.817 bisitz 4196: $output = $domdesign{$domain.'.'.$which};
1.63 www 4197: } else {
1.520 raeburn 4198: $output = $defaultdesign{$which};
4199: }
4200: if (($which =~ /^(student|coordinator|author|admin)\.img$/) ||
1.635 raeburn 4201: ($which =~ /login\.(img|logo|domlogo|login)/)) {
1.538 albertel 4202: if ($output =~ m{^/(adm|res)/}) {
1.817 bisitz 4203: if ($output =~ m{^/res/}) {
4204: my $local_name = &Apache::lonnet::filelocation('',$output);
4205: &Apache::lonnet::repcopy($local_name);
4206: }
1.520 raeburn 4207: $output = &lonhttpdurl($output);
4208: }
1.63 www 4209: }
1.520 raeburn 4210: return $output;
1.63 www 4211: }
1.59 www 4212:
1.822 bisitz 4213: ##############################################
4214: =pod
4215:
1.832 bisitz 4216: =item * &authorspace()
4217:
4218: Inputs: ./.
4219:
4220: Returns: Path to the Construction Space of the current user's
4221: accessed author space
4222: The author space will be that of the current user
4223: when accessing the own author space
4224: and that of the co-author/assistent co-author
4225: when accessing the co-author's/assistent co-author's
4226: space
4227:
4228: =cut
4229:
4230: sub authorspace {
4231: my $caname = '';
4232: if ($env{'request.role'} =~ /^ca|^aa/) {
4233: (undef,$caname) =
4234: ($env{'request.role'}=~/($match_domain)\/($match_username)$/);
4235: } else {
4236: $caname = $env{'user.name'};
4237: }
4238: return '/priv/'.$caname.'/';
4239: }
4240:
4241: ##############################################
4242: =pod
4243:
1.822 bisitz 4244: =item * &head_subbox()
4245:
4246: Inputs: $content (contains HTML code with page functions, etc.)
4247:
4248: Returns: HTML div with $content
4249: To be included in page header
4250:
4251: =cut
4252:
4253: sub head_subbox {
4254: my ($content)=@_;
4255: my $output =
1.844 bisitz 4256: '<div id="LC_head_subbox">'
1.822 bisitz 4257: .$content
4258: .'</div>'
4259: }
4260:
4261: ##############################################
4262: =pod
4263:
4264: =item * &CSTR_pageheader()
4265:
4266: Inputs: ./.
4267:
4268: Returns: HTML div with CSTR path and recent box
4269: To be included on Construction Space pages
4270:
4271: =cut
4272:
4273: sub CSTR_pageheader {
4274: # this is for resources; directories have customtitle, and crumbs
4275: # and select recent are created in lonpubdir.pm
4276: my ($uname,$thisdisfn)=
4277: ($env{'request.filename'} =~ m|^/home/([^/]+)/public_html/(.*)|);
4278: my $formaction='/priv/'.$uname.'/'.$thisdisfn;
4279: $formaction=~s/\/+/\//g;
4280:
4281: my $parentpath = '';
4282: my $lastitem = '';
4283: if ($thisdisfn =~ m-(.+/)([^/]*)$-) {
4284: $parentpath = $1;
4285: $lastitem = $2;
4286: } else {
4287: $lastitem = $thisdisfn;
4288: }
4289: return
4290: '<div>'
4291: .&Apache::loncommon::help_open_menu('','',3,'Authoring') #FIXME: Broken? Where is it?
4292: .'<b>'.&mt('Construction Space:').'</b> '
4293: .'<form name="dirs" method="post" action="'.$formaction
4294: .'" target="_top"><tt><b>' #FIXME lonpubdir: target="_parent"
4295: .&Apache::lonhtmlcommon::crumbs($uname.'/'.$parentpath,'_top','/priv','','+1',1)."$lastitem</b></tt><br />"
4296: #FIXME lonpubdir: &Apache::lonhtmlcommon::crumbs($uname.$thisdisfn.'/','_top','/priv','','+1',1)."</b></tt><br />"
4297: .&Apache::lonhtmlcommon::select_recent('construct','recent','this.form.action=this.form.recent.value;this.form.submit()')
4298: .'</form>'
4299: .&Apache::lonmenu::constspaceform()
4300: .'</div>';
4301: }
4302:
1.60 matthew 4303: ###############################################
4304: ###############################################
4305:
4306: =pod
4307:
1.112 bowersj2 4308: =back
4309:
1.549 albertel 4310: =head1 HTML Helpers
1.112 bowersj2 4311:
4312: =over 4
4313:
4314: =item * &bodytag()
1.60 matthew 4315:
4316: Returns a uniform header for LON-CAPA web pages.
4317:
4318: Inputs:
4319:
1.112 bowersj2 4320: =over 4
4321:
4322: =item * $title, A title to be displayed on the page.
4323:
4324: =item * $function, the current role (can be undef).
4325:
4326: =item * $addentries, extra parameters for the <body> tag.
4327:
4328: =item * $bodyonly, if defined, only return the <body> tag.
4329:
4330: =item * $domain, if defined, force a given domain.
4331:
4332: =item * $forcereg, if page should register as content page (relevant for
1.86 www 4333: text interface only)
1.60 matthew 4334:
1.814 bisitz 4335: =item * $no_nav_bar, if true, keep the 'what is this' info but remove the
4336: navigational links
1.317 albertel 4337:
1.338 albertel 4338: =item * $bgcolor, used to override the bgcolor on a webpage to a specific value
4339:
1.361 albertel 4340: =item * $no_inline_link, if true and in remote mode, don't show the
4341: 'Switch To Inline Menu' link
4342:
1.460 albertel 4343: =item * $args, optional argument valid values are
4344: no_auto_mt_title -> prevents &mt()ing the title arg
1.562 albertel 4345: inherit_jsmath -> when creating popup window in a page,
4346: should it have jsmath forced on by the
4347: current page
1.460 albertel 4348:
1.112 bowersj2 4349: =back
4350:
1.60 matthew 4351: Returns: A uniform header for LON-CAPA web pages.
4352: If $bodyonly is nonzero, a string containing a <body> tag will be returned.
4353: If $bodyonly is undef or zero, an html string containing a <body> tag and
4354: other decorations will be returned.
4355:
4356: =cut
4357:
1.54 www 4358: sub bodytag {
1.831 bisitz 4359: my ($title,$function,$addentries,$bodyonly,$domain,$forcereg,
1.816 bisitz 4360: $no_nav_bar,$bgcolor,$no_inline_link,$args)=@_;
1.339 albertel 4361:
1.460 albertel 4362: if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); }
1.339 albertel 4363:
1.183 matthew 4364: $function = &get_users_function() if (!$function);
1.339 albertel 4365: my $img = &designparm($function.'.img',$domain);
4366: my $font = &designparm($function.'.font',$domain);
4367: my $pgbg = $bgcolor || &designparm($function.'.pgbg',$domain);
4368:
1.803 bisitz 4369: my %design = ( 'style' => 'margin-top: 0',
1.535 albertel 4370: 'bgcolor' => $pgbg,
1.339 albertel 4371: 'text' => $font,
4372: 'alink' => &designparm($function.'.alink',$domain),
4373: 'vlink' => &designparm($function.'.vlink',$domain),
4374: 'link' => &designparm($function.'.link',$domain),);
1.438 albertel 4375: @design{keys(%$addentries)} = @$addentries{keys(%$addentries)};
1.339 albertel 4376:
1.63 www 4377: # role and realm
1.378 raeburn 4378: my ($role,$realm) = split(/\./,$env{'request.role'},2);
4379: if ($role eq 'ca') {
1.479 albertel 4380: my ($rdom,$rname) = ($realm =~ m{^/($match_domain)/($match_username)$});
1.500 albertel 4381: $realm = &plainname($rname,$rdom);
1.378 raeburn 4382: }
1.55 www 4383: # realm
1.258 albertel 4384: if ($env{'request.course.id'}) {
1.378 raeburn 4385: if ($env{'request.role'} !~ /^cr/) {
4386: $role = &Apache::lonnet::plaintext($role,&course_type());
4387: }
1.359 albertel 4388: $realm = $env{'course.'.$env{'request.course.id'}.'.description'};
1.378 raeburn 4389: } else {
4390: $role = &Apache::lonnet::plaintext($role);
1.54 www 4391: }
1.433 albertel 4392:
1.359 albertel 4393: if (!$realm) { $realm=' '; }
1.55 www 4394: # Set messages
1.60 matthew 4395: my $messages=&domainlogo($domain);
1.330 albertel 4396:
1.438 albertel 4397: my $extra_body_attr = &make_attr_string($forcereg,\%design);
1.329 albertel 4398:
1.101 www 4399: # construct main body tag
1.359 albertel 4400: my $bodytag = "<body $extra_body_attr>".
1.562 albertel 4401: &Apache::lontexconvert::init_math_support($args->{'inherit_jsmath'});
1.252 albertel 4402:
1.530 albertel 4403: if ($bodyonly) {
1.60 matthew 4404: return $bodytag;
1.798 tempelho 4405: }
1.359 albertel 4406:
1.410 albertel 4407: my $name = &plainname($env{'user.name'},$env{'user.domain'});
1.433 albertel 4408: if ($env{'user.name'} eq 'public' && $env{'user.domain'} eq 'public') {
4409: undef($role);
1.434 albertel 4410: } else {
4411: $name = &aboutmewrapper($name,$env{'user.name'},$env{'user.domain'});
1.433 albertel 4412: }
1.359 albertel 4413:
1.762 bisitz 4414: my $titleinfo = '<h1>'.$title.'</h1>';
1.359 albertel 4415: #
4416: # Extra info if you are the DC
4417: my $dc_info = '';
4418: if ($env{'user.adv'} && exists($env{'user.role.dc./'.
4419: $env{'course.'.$env{'request.course.id'}.
4420: '.domain'}.'/'})) {
4421: my $cid = $env{'request.course.id'};
4422: $dc_info.= $cid.' '.$env{'course.'.$cid.'.internal.coursecode'};
1.380 www 4423: $dc_info =~ s/\s+$//;
1.359 albertel 4424: $dc_info = '('.$dc_info.')';
4425: }
4426:
1.853 droeschl 4427: $role = "($role)" if $role;
4428: &get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['inhibitmenu']);
4429:
1.837 bisitz 4430: if ($env{'environment.remote'} eq 'off') {
1.359 albertel 4431: # No Remote
1.258 albertel 4432: if ($env{'request.state'} eq 'construct') {
1.359 albertel 4433: $forcereg=1;
4434: }
4435:
1.836 bisitz 4436: # if ($env{'request.state'} eq 'construct') {
4437: # $titleinfo = &CSTR_pageheader(); #FIXME: Will be removed once all scripts have their own calls
4438: # }
1.359 albertel 4439:
1.816 bisitz 4440: my $titletable = '<table id="LC_title_bar">'
1.836 bisitz 4441: ."<tr><td> $titleinfo $dc_info</td>"
1.816 bisitz 4442: .'</tr></table>';
4443:
1.814 bisitz 4444: if ($no_nav_bar) {
1.359 albertel 4445: $bodytag .= $titletable;
4446: } else {
1.852 droeschl 4447: $bodytag .= qq|<div id="LC_nav_bar">$name $role<br />
4448: <em>$realm</em> $dc_info</div>| unless $env{'form.inhibitmenu'};
4449:
1.359 albertel 4450: if ($env{'request.state'} eq 'construct') {
1.863 droeschl 4451: $bodytag .= &Apache::lonmenu::menubuttons($forcereg,$titletable);
1.272 raeburn 4452: } else {
1.863 droeschl 4453: $bodytag .= &Apache::lonmenu::menubuttons($forcereg).$titletable;
1.272 raeburn 4454: }
1.235 raeburn 4455: }
4456: return $bodytag;
1.94 www 4457: }
1.95 www 4458:
1.93 www 4459: #
1.95 www 4460: # Top frame rendering, Remote is up
1.93 www 4461: #
1.359 albertel 4462:
1.517 raeburn 4463: my $imgsrc = $img;
4464: if ($img =~ /^\/adm/) {
1.575 albertel 4465: $imgsrc = &lonhttpdurl($img);
1.517 raeburn 4466: }
4467: my $upperleft='<img src="'.$imgsrc.'" alt="'.$function.'" />';
1.359 albertel 4468:
1.305 www 4469: # Explicit link to get inline menu
1.361 albertel 4470: my $menu= ($no_inline_link?''
1.853 droeschl 4471: :'<a href="/adm/remote?action=collapse">'.&mt('Switch to Inline Menu Mode').'</a>');
4472: $bodytag .= qq|<div id="LC_nav_bar">$name $role
4473: <em>$realm</em> $dc_info </div>
4474: <ol class="LC_smallMenu LC_right">
4475: <li>$menu</li>
4476: </ol>| unless $env{'form.inhibitmenu'};
1.245 matthew 4477: #
1.94 www 4478: return(<<ENDBODY);
1.60 matthew 4479: $bodytag
1.359 albertel 4480: <table id="LC_title_bar" class="LC_with_remote">
1.791 tempelho 4481: <tr><td>$upperleft</td>
4482: <td>$messages </td>
1.54 www 4483: </tr>
1.359 albertel 4484: <tr><td>$titleinfo $dc_info $menu</td>
1.368 albertel 4485: </tr>
1.356 albertel 4486: </table>
1.54 www 4487: ENDBODY
1.182 matthew 4488: }
4489:
1.330 albertel 4490: sub make_attr_string {
4491: my ($register,$attr_ref) = @_;
4492:
4493: if ($attr_ref && !ref($attr_ref)) {
4494: die("addentries Must be a hash ref ".
4495: join(':',caller(1))." ".
4496: join(':',caller(0))." ");
4497: }
4498:
4499: if ($register) {
1.339 albertel 4500: my ($on_load,$on_unload);
4501: foreach my $key (keys(%{$attr_ref})) {
4502: if (lc($key) eq 'onload') {
4503: $on_load.=$attr_ref->{$key}.';';
4504: delete($attr_ref->{$key});
4505:
4506: } elsif (lc($key) eq 'onunload') {
4507: $on_unload.=$attr_ref->{$key}.';';
4508: delete($attr_ref->{$key});
4509: }
4510: }
4511: $attr_ref->{'onload'} =
4512: &Apache::lonmenu::loadevents(). $on_load;
4513: $attr_ref->{'onunload'}=
4514: &Apache::lonmenu::unloadevents().$on_unload;
4515: }
4516:
4517: # Accessibility font enhance
4518: if ($env{'browser.fontenhance'} eq 'on') {
4519: my $style;
4520: foreach my $key (keys(%{$attr_ref})) {
4521: if (lc($key) eq 'style') {
4522: $style.=$attr_ref->{$key}.';';
4523: delete($attr_ref->{$key});
4524: }
4525: }
4526: $attr_ref->{'style'}=$style.'; font-size: x-large;';
1.330 albertel 4527: }
1.339 albertel 4528:
1.330 albertel 4529: my $attr_string;
4530: foreach my $attr (keys(%$attr_ref)) {
4531: $attr_string .= " $attr=\"".$attr_ref->{$attr}.'" ';
4532: }
4533: return $attr_string;
4534: }
4535:
4536:
1.182 matthew 4537: ###############################################
1.251 albertel 4538: ###############################################
4539:
4540: =pod
4541:
4542: =item * &endbodytag()
4543:
4544: Returns a uniform footer for LON-CAPA web pages.
4545:
1.635 raeburn 4546: Inputs: 1 - optional reference to an args hash
4547: If in the hash, key for noredirectlink has a value which evaluates to true,
4548: a 'Continue' link is not displayed if the page contains an
4549: internal redirect in the <head></head> section,
4550: i.e., $env{'internal.head.redirect'} exists
1.251 albertel 4551:
4552: =cut
4553:
4554: sub endbodytag {
1.635 raeburn 4555: my ($args) = @_;
1.251 albertel 4556: my $endbodytag='</body>';
1.269 albertel 4557: $endbodytag=&Apache::lontexconvert::jsMath_process()."\n".$endbodytag;
1.315 albertel 4558: if ( exists( $env{'internal.head.redirect'} ) ) {
1.635 raeburn 4559: if (!(ref($args) eq 'HASH' && $args->{'noredirectlink'})) {
4560: $endbodytag=
4561: "<br /><a href=\"$env{'internal.head.redirect'}\">".
4562: &mt('Continue').'</a>'.
4563: $endbodytag;
4564: }
1.315 albertel 4565: }
1.251 albertel 4566: return $endbodytag;
4567: }
4568:
1.352 albertel 4569: =pod
4570:
4571: =item * &standard_css()
4572:
4573: Returns a style sheet
4574:
4575: Inputs: (all optional)
4576: domain -> force to color decorate a page for a specific
4577: domain
4578: function -> force usage of a specific rolish color scheme
4579: bgcolor -> override the default page bgcolor
4580:
4581: =cut
4582:
1.343 albertel 4583: sub standard_css {
1.345 albertel 4584: my ($function,$domain,$bgcolor) = @_;
1.352 albertel 4585: $function = &get_users_function() if (!$function);
4586: my $img = &designparm($function.'.img', $domain);
4587: my $tabbg = &designparm($function.'.tabbg', $domain);
4588: my $font = &designparm($function.'.font', $domain);
1.801 tempelho 4589: my $fontmenu = &designparm($function.'.fontmenu', $domain);
1.791 tempelho 4590: #second colour for later usage
1.345 albertel 4591: my $sidebg = &designparm($function.'.sidebg',$domain);
1.382 albertel 4592: my $pgbg_or_bgcolor =
4593: $bgcolor ||
1.352 albertel 4594: &designparm($function.'.pgbg', $domain);
1.382 albertel 4595: my $pgbg = &designparm($function.'.pgbg', $domain);
1.352 albertel 4596: my $alink = &designparm($function.'.alink', $domain);
4597: my $vlink = &designparm($function.'.vlink', $domain);
4598: my $link = &designparm($function.'.link', $domain);
4599:
1.704 muellerd 4600: my $loginbg = &designparm('login.sidebg',$domain);
1.712 muellerd 4601: my $bgcol = &designparm('login.bgcol',$domain);
4602: my $textcol = &designparm('login.textcol',$domain);
1.704 muellerd 4603:
1.602 albertel 4604: my $sans = 'Verdana,Arial,Helvetica,sans-serif';
1.395 albertel 4605: my $mono = 'monospace';
1.850 bisitz 4606: my $data_table_head = $sidebg;
4607: my $data_table_light = '#FAFAFA';
4608: my $data_table_dark = '#F0F0F0';
1.470 banghart 4609: my $data_table_darker = '#CCCCCC';
1.349 albertel 4610: my $data_table_highlight = '#FFFF00';
1.352 albertel 4611: my $mail_new = '#FFBB77';
4612: my $mail_new_hover = '#DD9955';
4613: my $mail_read = '#BBBB77';
4614: my $mail_read_hover = '#999944';
4615: my $mail_replied = '#AAAA88';
4616: my $mail_replied_hover = '#888855';
4617: my $mail_other = '#99BBBB';
4618: my $mail_other_hover = '#669999';
1.391 albertel 4619: my $table_header = '#DDDDDD';
1.489 raeburn 4620: my $feedback_link_bg = '#BBBBBB';
1.701 harmsja 4621: my $lg_border_color = '#C8C8C8';
1.392 albertel 4622:
1.608 albertel 4623: my $border = ($env{'browser.type'} eq 'explorer' ||
1.803 bisitz 4624: $env{'browser.type'} eq 'safari' ) ? '0 2px 0 2px'
4625: : '0 3px 0 4px';
1.448 albertel 4626:
1.523 albertel 4627:
1.343 albertel 4628: return <<END;
1.795 www 4629: body {
4630: font-family: $sans;
4631: line-height:130%;
4632: font-size:0.83em;
4633: color:$font;
4634: }
4635:
4636: a:link, a:visited {
4637: font-size:100%;
4638: }
4639:
4640: a:focus {
4641: color: red;
4642: background: yellow
4643: }
1.698 harmsja 4644:
1.846 bisitz 4645: hr {
4646: clear: both;
4647: color: $tabbg;
4648: background-color: $tabbg;
4649: height: 3px;
4650: border: none;
4651: }
4652:
1.795 www 4653: form, .inline {
4654: display: inline;
4655: }
1.721 harmsja 4656:
1.795 www 4657: .LC_right {
4658: text-align:right;
4659: }
4660:
4661: .LC_middle {
4662: vertical-align:middle;
4663: }
1.721 harmsja 4664:
4665: /* just for tests */
1.754 droeschl 4666: .LC_400Box {width:400px; }
1.721 harmsja 4667: /* end */
4668:
1.778 bisitz 4669: .LC_filename {
4670: font-family: $mono;
4671: white-space:pre;
4672: }
4673:
4674: .LC_fileicon {
4675: border: none;
4676: height: 1.3em;
4677: vertical-align: text-bottom;
4678: margin-right: 0.3em;
4679: text-decoration:none;
4680: }
4681:
1.350 albertel 4682: .LC_error {
4683: color: red;
4684: font-size: larger;
4685: }
1.795 www 4686:
1.457 albertel 4687: .LC_warning,
4688: .LC_diff_removed {
1.733 bisitz 4689: color: red;
1.394 albertel 4690: }
1.532 albertel 4691:
4692: .LC_info,
1.457 albertel 4693: .LC_success,
4694: .LC_diff_added {
1.350 albertel 4695: color: green;
4696: }
1.795 www 4697:
1.802 bisitz 4698: div.LC_confirm_box {
4699: background-color: #FAFAFA;
4700: border: 1px solid $lg_border_color;
4701: margin-right: 0;
4702: padding: 5px;
4703: }
4704:
4705: div.LC_confirm_box .LC_error img,
4706: div.LC_confirm_box .LC_success img {
4707: vertical-align: middle;
4708: }
4709:
1.440 albertel 4710: .LC_icon {
1.771 droeschl 4711: border: none;
1.790 droeschl 4712: vertical-align: middle;
1.771 droeschl 4713: }
4714:
1.543 albertel 4715: .LC_docs_spacer {
4716: width: 25px;
4717: height: 1px;
1.771 droeschl 4718: border: none;
1.543 albertel 4719: }
1.346 albertel 4720:
1.532 albertel 4721: .LC_internal_info {
1.735 bisitz 4722: color: #999999;
1.532 albertel 4723: }
4724:
1.794 www 4725: .LC_discussion {
4726: background: $tabbg;
4727: border: 1px solid black;
4728: margin: 2px;
4729: }
4730:
4731: .LC_disc_action_links_bar {
4732: background: $tabbg;
1.803 bisitz 4733: border: none;
1.795 www 4734: margin: 4px;
1.794 www 4735: }
4736:
4737: .LC_disc_action_left {
4738: text-align: left;
4739: }
4740:
4741: .LC_disc_action_right {
4742: text-align: right;
4743: }
4744:
4745: .LC_disc_new_item {
4746: background: white;
4747: border: 2px solid red;
4748: margin: 2px;
4749: }
4750:
4751: .LC_disc_old_item {
4752: background: white;
4753: border: 1px solid black;
4754: margin: 2px;
4755: }
4756:
1.458 albertel 4757: table.LC_pastsubmission {
4758: border: 1px solid black;
4759: margin: 2px;
4760: }
4761:
1.795 www 4762: table#LC_top_nav,
4763: table#LC_menubuttons,
4764: table#LC_nav_location {
1.345 albertel 4765: width: 100%;
4766: background: $pgbg;
1.392 albertel 4767: border: 2px;
1.402 albertel 4768: border-collapse: separate;
1.803 bisitz 4769: padding: 0;
1.345 albertel 4770: }
1.392 albertel 4771:
1.801 tempelho 4772: table#LC_title_bar a {
4773: color: $fontmenu;
4774: }
1.836 bisitz 4775:
1.807 droeschl 4776: table#LC_title_bar {
1.819 tempelho 4777: clear: both;
1.836 bisitz 4778: display: none;
1.807 droeschl 4779: }
4780:
1.795 www 4781: table#LC_title_bar,
4782: table.LC_breadcrumbs,
1.393 albertel 4783: table#LC_title_bar.LC_with_remote {
1.359 albertel 4784: width: 100%;
1.392 albertel 4785: border-color: $pgbg;
4786: border-style: solid;
4787: border-width: $border;
1.379 albertel 4788: background: $pgbg;
1.801 tempelho 4789: color: $fontmenu;
1.392 albertel 4790: border-collapse: collapse;
1.803 bisitz 4791: padding: 0;
1.819 tempelho 4792: margin: 0;
1.359 albertel 4793: }
1.795 www 4794:
1.359 albertel 4795: table#LC_title_bar td {
4796: background: $tabbg;
4797: }
1.795 www 4798:
1.706 harmsja 4799: table#LC_menubuttons img{
1.803 bisitz 4800: border: none;
1.346 albertel 4801: }
1.795 www 4802:
1.345 albertel 4803: table#LC_top_nav td {
4804: background: $tabbg;
1.803 bisitz 4805: border: none;
1.407 albertel 4806: font-size: small;
1.706 harmsja 4807: vertical-align:top;
4808: padding:2px 5px 2px 5px;
1.345 albertel 4809: }
1.795 www 4810:
4811: table#LC_top_nav td a,
4812: div#LC_top_nav a {
1.345 albertel 4813: color: $font;
4814: }
1.795 www 4815:
1.364 albertel 4816: table#LC_top_nav td.LC_top_nav_logo {
4817: background: $tabbg;
1.432 albertel 4818: text-align: left;
1.408 albertel 4819: white-space: nowrap;
1.432 albertel 4820: width: 31px;
1.408 albertel 4821: }
1.795 www 4822:
1.408 albertel 4823: table#LC_top_nav td.LC_top_nav_logo img {
1.803 bisitz 4824: border: none;
1.408 albertel 4825: vertical-align: bottom;
1.364 albertel 4826: }
1.795 www 4827:
1.777 tempelho 4828: table#LC_top_nav td.LC_top_nav_exit,
1.779 bisitz 4829: table#LC_top_nav td.LC_top_nav_help {
1.777 tempelho 4830: width: 2.0em;
4831: }
1.795 www 4832:
1.442 albertel 4833: table#LC_top_nav td.LC_top_nav_login {
4834: width: 4.0em;
4835: text-align: center;
4836: }
1.795 www 4837:
1.842 droeschl 4838: .LC_breadcrumbs_component {
4839: float: right;
4840: margin: 0 1em;
1.357 albertel 4841: }
1.842 droeschl 4842: .LC_breadcrumbs_component img {
4843: vertical-align: middle;
1.777 tempelho 4844: }
1.795 www 4845:
1.383 albertel 4846: td.LC_table_cell_checkbox {
4847: text-align: center;
4848: }
1.795 www 4849:
1.779 bisitz 4850: table#LC_mainmenu td.LC_mainmenu_column {
4851: vertical-align: top;
1.777 tempelho 4852: }
1.522 albertel 4853:
1.795 www 4854: .LC_fontsize_small {
1.705 tempelho 4855: font-size: 70%;
4856: }
4857:
1.844 bisitz 4858: #LC_breadcrumbs {
1.819 tempelho 4859: clear:both;
4860: background: $sidebg;
1.822 bisitz 4861: border-bottom: 1px solid $lg_border_color;
1.819 tempelho 4862: line-height: 32px;
1.822 bisitz 4863: margin: 0;
1.819 tempelho 4864: padding: 0;
4865: }
1.862 bisitz 4866:
1.839 droeschl 4867: /* Preliminary fix to hide breadcrumbs inside remote control window */
1.844 bisitz 4868: #LC_remote #LC_breadcrumbs {
1.839 droeschl 4869: display:none;
4870: }
1.819 tempelho 4871:
1.844 bisitz 4872: #LC_head_subbox {
1.822 bisitz 4873: clear:both;
4874: background: #F8F8F8; /* $sidebg; */
4875: border-bottom: 1px solid $lg_border_color;
4876: margin: 0 0 10px 0;
4877: padding: 5px;
4878: }
4879:
1.795 www 4880: .LC_fontsize_medium {
1.705 tempelho 4881: font-size: 85%;
4882: }
4883:
1.795 www 4884: .LC_fontsize_large {
1.705 tempelho 4885: font-size: 120%;
4886: }
4887:
1.346 albertel 4888: .LC_menubuttons_inline_text {
4889: color: $font;
1.698 harmsja 4890: font-size: 90%;
1.701 harmsja 4891: padding-left:3px;
1.346 albertel 4892: }
4893:
1.526 www 4894: .LC_menubuttons_link {
4895: text-decoration: none;
4896: }
1.795 www 4897:
1.522 albertel 4898: .LC_menubuttons_category {
1.521 www 4899: color: $font;
1.526 www 4900: background: $pgbg;
1.521 www 4901: font-size: larger;
4902: font-weight: bold;
4903: }
4904:
1.346 albertel 4905: td.LC_menubuttons_text {
1.779 bisitz 4906: color: $font;
1.346 albertel 4907: }
1.706 harmsja 4908:
1.346 albertel 4909: .LC_current_location {
4910: background: $tabbg;
4911: }
1.795 www 4912:
1.346 albertel 4913: .LC_new_mail {
1.634 www 4914: background: $tabbg;
1.346 albertel 4915: font-weight: bold;
4916: }
1.347 albertel 4917:
1.795 www 4918: table.LC_data_table,
4919: table.LC_mail_list {
1.347 albertel 4920: border: 1px solid #000000;
1.402 albertel 4921: border-collapse: separate;
1.426 albertel 4922: border-spacing: 1px;
1.610 albertel 4923: background: $pgbg;
1.347 albertel 4924: }
1.795 www 4925:
1.422 albertel 4926: .LC_data_table_dense {
4927: font-size: small;
4928: }
1.795 www 4929:
1.507 raeburn 4930: table.LC_nested_outer {
4931: border: 1px solid #000000;
1.589 raeburn 4932: border-collapse: collapse;
1.803 bisitz 4933: border-spacing: 0;
1.507 raeburn 4934: width: 100%;
4935: }
1.795 www 4936:
1.879 raeburn 4937: table.LC_innerpickbox,
1.507 raeburn 4938: table.LC_nested {
1.803 bisitz 4939: border: none;
1.589 raeburn 4940: border-collapse: collapse;
1.803 bisitz 4941: border-spacing: 0;
1.507 raeburn 4942: width: 100%;
4943: }
1.795 www 4944:
4945: table.LC_data_table tr th,
4946: table.LC_calendar tr th,
4947: table.LC_mail_list tr th,
1.879 raeburn 4948: table.LC_prior_tries tr th,
4949: table.LC_innerpickbox tr th {
1.349 albertel 4950: font-weight: bold;
4951: background-color: $data_table_head;
1.801 tempelho 4952: color:$fontmenu;
1.701 harmsja 4953: font-size:90%;
1.347 albertel 4954: }
1.795 www 4955:
1.879 raeburn 4956: table.LC_innerpickbox tr th,
4957: table.LC_innerpickbox tr td {
4958: vertical-align: top;
4959: }
4960:
1.711 raeburn 4961: table.LC_data_table tr.LC_info_row > td {
1.735 bisitz 4962: background-color: #CCCCCC;
1.711 raeburn 4963: font-weight: bold;
4964: text-align: left;
4965: }
1.795 www 4966:
1.779 bisitz 4967: table.LC_data_table tr.LC_odd_row > td,
1.809 bisitz 4968: table.LC_pick_box tr > td.LC_odd_row {
1.349 albertel 4969: background-color: $data_table_light;
1.425 albertel 4970: padding: 2px;
1.347 albertel 4971: }
1.795 www 4972:
1.610 albertel 4973: table.LC_data_table tr.LC_even_row > td,
1.809 bisitz 4974: table.LC_pick_box tr > td.LC_even_row {
1.349 albertel 4975: background-color: $data_table_dark;
1.709 bisitz 4976: padding: 2px;
1.347 albertel 4977: }
1.795 www 4978:
1.425 albertel 4979: table.LC_data_table tr.LC_data_table_highlight td {
4980: background-color: $data_table_darker;
4981: }
1.795 www 4982:
1.639 raeburn 4983: table.LC_data_table tr td.LC_leftcol_header {
4984: background-color: $data_table_head;
4985: font-weight: bold;
4986: }
1.795 www 4987:
1.451 albertel 4988: table.LC_data_table tr.LC_empty_row td,
1.507 raeburn 4989: table.LC_nested tr.LC_empty_row td {
1.347 albertel 4990: background-color: #FFFFFF;
1.421 albertel 4991: font-weight: bold;
4992: font-style: italic;
4993: text-align: center;
4994: padding: 8px;
1.347 albertel 4995: }
1.795 www 4996:
1.507 raeburn 4997: table.LC_nested tr.LC_empty_row td {
1.465 albertel 4998: padding: 4ex
4999: }
1.795 www 5000:
1.507 raeburn 5001: table.LC_nested_outer tr th {
5002: font-weight: bold;
1.801 tempelho 5003: color:$fontmenu;
1.507 raeburn 5004: background-color: $data_table_head;
1.701 harmsja 5005: font-size: small;
1.507 raeburn 5006: border-bottom: 1px solid #000000;
5007: }
1.795 www 5008:
1.507 raeburn 5009: table.LC_nested_outer tr td.LC_subheader {
5010: background-color: $data_table_head;
5011: font-weight: bold;
5012: font-size: small;
5013: border-bottom: 1px solid #000000;
5014: text-align: right;
1.451 albertel 5015: }
1.795 www 5016:
1.507 raeburn 5017: table.LC_nested tr.LC_info_row td {
1.735 bisitz 5018: background-color: #CCCCCC;
1.451 albertel 5019: font-weight: bold;
5020: font-size: small;
1.507 raeburn 5021: text-align: center;
5022: }
1.795 www 5023:
1.589 raeburn 5024: table.LC_nested tr.LC_info_row td.LC_left_item,
5025: table.LC_nested_outer tr th.LC_left_item {
1.507 raeburn 5026: text-align: left;
1.451 albertel 5027: }
1.795 www 5028:
1.507 raeburn 5029: table.LC_nested td {
1.735 bisitz 5030: background-color: #FFFFFF;
1.451 albertel 5031: font-size: small;
1.507 raeburn 5032: }
1.795 www 5033:
1.507 raeburn 5034: table.LC_nested_outer tr th.LC_right_item,
5035: table.LC_nested tr.LC_info_row td.LC_right_item,
5036: table.LC_nested tr.LC_odd_row td.LC_right_item,
5037: table.LC_nested tr td.LC_right_item {
1.451 albertel 5038: text-align: right;
5039: }
5040:
1.507 raeburn 5041: table.LC_nested tr.LC_odd_row td {
1.735 bisitz 5042: background-color: #EEEEEE;
1.451 albertel 5043: }
5044:
1.473 raeburn 5045: table.LC_createuser {
5046: }
5047:
5048: table.LC_createuser tr.LC_section_row td {
1.701 harmsja 5049: font-size: small;
1.473 raeburn 5050: }
5051:
5052: table.LC_createuser tr.LC_info_row td {
1.735 bisitz 5053: background-color: #CCCCCC;
1.473 raeburn 5054: font-weight: bold;
5055: text-align: center;
5056: }
5057:
1.349 albertel 5058: table.LC_calendar {
5059: border: 1px solid #000000;
5060: border-collapse: collapse;
5061: }
1.795 www 5062:
1.349 albertel 5063: table.LC_calendar_pickdate {
5064: font-size: xx-small;
5065: }
1.795 www 5066:
1.349 albertel 5067: table.LC_calendar tr td {
5068: border: 1px solid #000000;
5069: vertical-align: top;
5070: }
1.795 www 5071:
1.349 albertel 5072: table.LC_calendar tr td.LC_calendar_day_empty {
5073: background-color: $data_table_dark;
5074: }
1.795 www 5075:
1.779 bisitz 5076: table.LC_calendar tr td.LC_calendar_day_current {
5077: background-color: $data_table_highlight;
1.777 tempelho 5078: }
1.795 www 5079:
1.349 albertel 5080: table.LC_mail_list tr.LC_mail_new {
5081: background-color: $mail_new;
5082: }
1.795 www 5083:
1.349 albertel 5084: table.LC_mail_list tr.LC_mail_new:hover {
5085: background-color: $mail_new_hover;
5086: }
1.795 www 5087:
5088: table.LC_mail_list tr.LC_mail_even {
1.777 tempelho 5089: }
1.795 www 5090:
5091: table.LC_mail_list tr.LC_mail_odd {
1.777 tempelho 5092: }
1.795 www 5093:
1.349 albertel 5094: table.LC_mail_list tr.LC_mail_read {
5095: background-color: $mail_read;
5096: }
1.795 www 5097:
1.349 albertel 5098: table.LC_mail_list tr.LC_mail_read:hover {
5099: background-color: $mail_read_hover;
5100: }
1.795 www 5101:
1.349 albertel 5102: table.LC_mail_list tr.LC_mail_replied {
5103: background-color: $mail_replied;
5104: }
1.795 www 5105:
1.349 albertel 5106: table.LC_mail_list tr.LC_mail_replied:hover {
5107: background-color: $mail_replied_hover;
5108: }
1.795 www 5109:
1.349 albertel 5110: table.LC_mail_list tr.LC_mail_other {
5111: background-color: $mail_other;
5112: }
1.795 www 5113:
1.349 albertel 5114: table.LC_mail_list tr.LC_mail_other:hover {
5115: background-color: $mail_other_hover;
5116: }
1.494 raeburn 5117:
1.777 tempelho 5118: table.LC_data_table tr > td.LC_browser_file,
5119: table.LC_data_table tr > td.LC_browser_file_published {
1.389 albertel 5120: background: #CCFF88;
5121: }
1.795 www 5122:
1.777 tempelho 5123: table.LC_data_table tr > td.LC_browser_file_locked,
5124: table.LC_data_table tr > td.LC_browser_file_unpublished {
1.389 albertel 5125: background: #FFAA99;
1.387 albertel 5126: }
1.795 www 5127:
1.777 tempelho 5128: table.LC_data_table tr > td.LC_browser_file_obsolete {
1.779 bisitz 5129: background: #AAAAAA;
5130: }
1.795 www 5131:
1.777 tempelho 5132: table.LC_data_table tr > td.LC_browser_file_modified,
1.779 bisitz 5133: table.LC_data_table tr > td.LC_browser_file_metamodified {
5134: background: #FFFF77;
1.777 tempelho 5135: }
1.795 www 5136:
1.696 bisitz 5137: table.LC_data_table tr.LC_browser_folder > td {
1.389 albertel 5138: background: #CCCCFF;
1.387 albertel 5139: }
1.696 bisitz 5140:
1.707 bisitz 5141: table.LC_data_table tr > td.LC_roles_is {
5142: /* background: #77FF77; */
5143: }
1.795 www 5144:
1.707 bisitz 5145: table.LC_data_table tr > td.LC_roles_future {
5146: background: #FFFF77;
5147: }
1.795 www 5148:
1.707 bisitz 5149: table.LC_data_table tr > td.LC_roles_will {
5150: background: #FFAA77;
5151: }
1.795 www 5152:
1.707 bisitz 5153: table.LC_data_table tr > td.LC_roles_expired {
5154: background: #FF7777;
5155: }
1.795 www 5156:
1.707 bisitz 5157: table.LC_data_table tr > td.LC_roles_will_not {
5158: background: #AAFF77;
5159: }
1.795 www 5160:
1.707 bisitz 5161: table.LC_data_table tr > td.LC_roles_selected {
5162: background: #11CC55;
5163: }
5164:
1.388 albertel 5165: span.LC_current_location {
1.701 harmsja 5166: font-size:larger;
1.388 albertel 5167: background: $pgbg;
5168: }
1.387 albertel 5169:
1.395 albertel 5170: span.LC_parm_menu_item {
5171: font-size: larger;
5172: }
1.795 www 5173:
1.395 albertel 5174: span.LC_parm_scope_all {
5175: color: red;
5176: }
1.795 www 5177:
1.395 albertel 5178: span.LC_parm_scope_folder {
5179: color: green;
5180: }
1.795 www 5181:
1.395 albertel 5182: span.LC_parm_scope_resource {
5183: color: orange;
5184: }
1.795 www 5185:
1.395 albertel 5186: span.LC_parm_part {
5187: color: blue;
5188: }
1.795 www 5189:
1.395 albertel 5190: span.LC_parm_folder, span.LC_parm_symb {
5191: font-size: x-small;
5192: font-family: $mono;
5193: color: #AAAAAA;
5194: }
5195:
1.795 www 5196: td.LC_parm_overview_level_menu,
5197: td.LC_parm_overview_map_menu,
5198: td.LC_parm_overview_parm_selectors,
5199: td.LC_parm_overview_restrictions {
1.396 albertel 5200: border: 1px solid black;
5201: border-collapse: collapse;
5202: }
1.795 www 5203:
1.396 albertel 5204: table.LC_parm_overview_restrictions td {
5205: border-width: 1px 4px 1px 4px;
5206: border-style: solid;
5207: border-color: $pgbg;
5208: text-align: center;
5209: }
1.795 www 5210:
1.396 albertel 5211: table.LC_parm_overview_restrictions th {
5212: background: $tabbg;
5213: border-width: 1px 4px 1px 4px;
5214: border-style: solid;
5215: border-color: $pgbg;
5216: }
1.795 www 5217:
1.398 albertel 5218: table#LC_helpmenu {
1.803 bisitz 5219: border: none;
1.398 albertel 5220: height: 55px;
1.803 bisitz 5221: border-spacing: 0;
1.398 albertel 5222: }
5223:
5224: table#LC_helpmenu fieldset legend {
5225: font-size: larger;
5226: }
1.795 www 5227:
1.397 albertel 5228: table#LC_helpmenu_links {
5229: width: 100%;
5230: border: 1px solid black;
5231: background: $pgbg;
1.803 bisitz 5232: padding: 0;
1.397 albertel 5233: border-spacing: 1px;
5234: }
1.795 www 5235:
1.397 albertel 5236: table#LC_helpmenu_links tr td {
5237: padding: 1px;
5238: background: $tabbg;
1.399 albertel 5239: text-align: center;
5240: font-weight: bold;
1.397 albertel 5241: }
1.396 albertel 5242:
1.795 www 5243: table#LC_helpmenu_links a:link,
5244: table#LC_helpmenu_links a:visited,
1.397 albertel 5245: table#LC_helpmenu_links a:active {
5246: text-decoration: none;
5247: color: $font;
5248: }
1.795 www 5249:
1.397 albertel 5250: table#LC_helpmenu_links a:hover {
5251: text-decoration: underline;
5252: color: $vlink;
5253: }
1.396 albertel 5254:
1.417 albertel 5255: .LC_chrt_popup_exists {
5256: border: 1px solid #339933;
5257: margin: -1px;
5258: }
1.795 www 5259:
1.417 albertel 5260: .LC_chrt_popup_up {
5261: border: 1px solid yellow;
5262: margin: -1px;
5263: }
1.795 www 5264:
1.417 albertel 5265: .LC_chrt_popup {
5266: border: 1px solid #8888FF;
5267: background: #CCCCFF;
5268: }
1.795 www 5269:
1.421 albertel 5270: table.LC_pick_box {
5271: border-collapse: separate;
5272: background: white;
5273: border: 1px solid black;
5274: border-spacing: 1px;
5275: }
1.795 www 5276:
1.421 albertel 5277: table.LC_pick_box td.LC_pick_box_title {
1.850 bisitz 5278: background: $sidebg;
1.421 albertel 5279: font-weight: bold;
5280: text-align: right;
1.740 bisitz 5281: vertical-align: top;
1.421 albertel 5282: width: 184px;
5283: padding: 8px;
5284: }
1.795 www 5285:
1.579 raeburn 5286: table.LC_pick_box td.LC_pick_box_value {
5287: text-align: left;
5288: padding: 8px;
5289: }
1.795 www 5290:
1.579 raeburn 5291: table.LC_pick_box td.LC_pick_box_select {
5292: text-align: left;
5293: padding: 8px;
5294: }
1.795 www 5295:
1.424 albertel 5296: table.LC_pick_box td.LC_pick_box_separator {
1.803 bisitz 5297: padding: 0;
1.421 albertel 5298: height: 1px;
5299: background: black;
5300: }
1.795 www 5301:
1.421 albertel 5302: table.LC_pick_box td.LC_pick_box_submit {
5303: text-align: right;
5304: }
1.795 www 5305:
1.579 raeburn 5306: table.LC_pick_box td.LC_evenrow_value {
5307: text-align: left;
5308: padding: 8px;
5309: background-color: $data_table_light;
5310: }
1.795 www 5311:
1.579 raeburn 5312: table.LC_pick_box td.LC_oddrow_value {
5313: text-align: left;
5314: padding: 8px;
5315: background-color: $data_table_light;
5316: }
1.795 www 5317:
1.579 raeburn 5318: table.LC_helpform_receipt {
5319: width: 620px;
5320: border-collapse: separate;
5321: background: white;
5322: border: 1px solid black;
5323: border-spacing: 1px;
5324: }
1.795 www 5325:
1.579 raeburn 5326: table.LC_helpform_receipt td.LC_pick_box_title {
5327: background: $tabbg;
5328: font-weight: bold;
5329: text-align: right;
5330: width: 184px;
5331: padding: 8px;
5332: }
1.795 www 5333:
1.579 raeburn 5334: table.LC_helpform_receipt td.LC_evenrow_value {
5335: text-align: left;
5336: padding: 8px;
5337: background-color: $data_table_light;
5338: }
1.795 www 5339:
1.579 raeburn 5340: table.LC_helpform_receipt td.LC_oddrow_value {
5341: text-align: left;
5342: padding: 8px;
5343: background-color: $data_table_light;
5344: }
1.795 www 5345:
1.579 raeburn 5346: table.LC_helpform_receipt td.LC_pick_box_separator {
1.803 bisitz 5347: padding: 0;
1.579 raeburn 5348: height: 1px;
5349: background: black;
5350: }
1.795 www 5351:
1.579 raeburn 5352: span.LC_helpform_receipt_cat {
5353: font-weight: bold;
5354: }
1.795 www 5355:
1.424 albertel 5356: table.LC_group_priv_box {
5357: background: white;
5358: border: 1px solid black;
5359: border-spacing: 1px;
5360: }
1.795 www 5361:
1.424 albertel 5362: table.LC_group_priv_box td.LC_pick_box_title {
5363: background: $tabbg;
5364: font-weight: bold;
5365: text-align: right;
5366: width: 184px;
5367: }
1.795 www 5368:
1.424 albertel 5369: table.LC_group_priv_box td.LC_groups_fixed {
5370: background: $data_table_light;
5371: text-align: center;
5372: }
1.795 www 5373:
1.424 albertel 5374: table.LC_group_priv_box td.LC_groups_optional {
5375: background: $data_table_dark;
5376: text-align: center;
5377: }
1.795 www 5378:
1.424 albertel 5379: table.LC_group_priv_box td.LC_groups_functionality {
5380: background: $data_table_darker;
5381: text-align: center;
5382: font-weight: bold;
5383: }
1.795 www 5384:
1.424 albertel 5385: table.LC_group_priv td {
5386: text-align: left;
1.803 bisitz 5387: padding: 0;
1.424 albertel 5388: }
5389:
1.421 albertel 5390: table.LC_notify_front_page {
5391: background: white;
5392: border: 1px solid black;
5393: padding: 8px;
5394: }
1.795 www 5395:
1.421 albertel 5396: table.LC_notify_front_page td {
5397: padding: 8px;
5398: }
1.795 www 5399:
1.424 albertel 5400: .LC_navbuttons {
5401: margin: 2ex 0ex 2ex 0ex;
5402: }
1.795 www 5403:
1.423 albertel 5404: .LC_topic_bar {
5405: font-weight: bold;
5406: width: 100%;
5407: background: $tabbg;
5408: vertical-align: middle;
5409: margin: 2ex 0ex 2ex 0ex;
1.805 bisitz 5410: padding: 3px;
1.423 albertel 5411: }
1.795 www 5412:
1.423 albertel 5413: .LC_topic_bar span {
5414: vertical-align: middle;
5415: }
1.795 www 5416:
1.423 albertel 5417: .LC_topic_bar img {
5418: vertical-align: bottom;
5419: }
1.795 www 5420:
1.423 albertel 5421: table.LC_course_group_status {
5422: margin: 20px;
5423: }
1.795 www 5424:
1.423 albertel 5425: table.LC_status_selector td {
5426: vertical-align: top;
5427: text-align: center;
1.424 albertel 5428: padding: 4px;
5429: }
1.795 www 5430:
1.599 albertel 5431: div.LC_feedback_link {
1.616 albertel 5432: clear: both;
1.829 kalberla 5433: background: $sidebg;
1.779 bisitz 5434: width: 100%;
1.829 kalberla 5435: padding-bottom: 10px;
5436: border: 1px $tabbg solid;
1.833 kalberla 5437: height: 22px;
5438: line-height: 22px;
5439: padding-top: 5px;
5440: }
5441:
5442: div.LC_feedback_link img {
5443: height: 22px;
1.867 kalberla 5444: vertical-align:middle;
1.829 kalberla 5445: }
5446:
5447: div.LC_feedback_link a{
5448: text-decoration: none;
1.489 raeburn 5449: }
1.795 www 5450:
1.867 kalberla 5451: div.LC_comblock {
5452: display:inline;
5453: color:$font;
5454: font-size:90%;
5455: }
5456:
5457: div.LC_feedback_link div.LC_comblock {
5458: padding-left:5px;
5459: }
5460:
5461: div.LC_feedback_link div.LC_comblock a {
5462: color:$font;
5463: }
5464:
1.489 raeburn 5465: span.LC_feedback_link {
1.858 bisitz 5466: /* background: $feedback_link_bg; */
1.599 albertel 5467: font-size: larger;
5468: }
1.795 www 5469:
1.599 albertel 5470: span.LC_message_link {
1.858 bisitz 5471: /* background: $feedback_link_bg; */
1.599 albertel 5472: font-size: larger;
5473: position: absolute;
5474: right: 1em;
1.489 raeburn 5475: }
1.421 albertel 5476:
1.515 albertel 5477: table.LC_prior_tries {
1.524 albertel 5478: border: 1px solid #000000;
5479: border-collapse: separate;
5480: border-spacing: 1px;
1.515 albertel 5481: }
1.523 albertel 5482:
1.515 albertel 5483: table.LC_prior_tries td {
1.524 albertel 5484: padding: 2px;
1.515 albertel 5485: }
1.523 albertel 5486:
5487: .LC_answer_correct {
1.795 www 5488: background: lightgreen;
5489: color: darkgreen;
5490: padding: 6px;
1.523 albertel 5491: }
1.795 www 5492:
1.523 albertel 5493: .LC_answer_charged_try {
1.797 www 5494: background: #FFAAAA;
1.795 www 5495: color: darkred;
5496: padding: 6px;
1.523 albertel 5497: }
1.795 www 5498:
1.779 bisitz 5499: .LC_answer_not_charged_try,
1.523 albertel 5500: .LC_answer_no_grade,
5501: .LC_answer_late {
1.795 www 5502: background: lightyellow;
1.523 albertel 5503: color: black;
1.795 www 5504: padding: 6px;
1.523 albertel 5505: }
1.795 www 5506:
1.523 albertel 5507: .LC_answer_previous {
1.795 www 5508: background: lightblue;
5509: color: darkblue;
5510: padding: 6px;
1.523 albertel 5511: }
1.795 www 5512:
1.779 bisitz 5513: .LC_answer_no_message {
1.777 tempelho 5514: background: #FFFFFF;
5515: color: black;
1.795 www 5516: padding: 6px;
1.779 bisitz 5517: }
1.795 www 5518:
1.779 bisitz 5519: .LC_answer_unknown {
5520: background: orange;
5521: color: black;
1.795 www 5522: padding: 6px;
1.777 tempelho 5523: }
1.795 www 5524:
1.529 albertel 5525: span.LC_prior_numerical,
5526: span.LC_prior_string,
5527: span.LC_prior_custom,
5528: span.LC_prior_reaction,
5529: span.LC_prior_math {
1.523 albertel 5530: font-family: monospace;
5531: white-space: pre;
5532: }
5533:
1.525 albertel 5534: span.LC_prior_string {
5535: font-family: monospace;
5536: white-space: pre;
5537: }
5538:
1.523 albertel 5539: table.LC_prior_option {
5540: width: 100%;
5541: border-collapse: collapse;
5542: }
1.795 www 5543:
5544: table.LC_prior_rank,
5545: table.LC_prior_match {
1.528 albertel 5546: border-collapse: collapse;
5547: }
1.795 www 5548:
1.528 albertel 5549: table.LC_prior_option tr td,
5550: table.LC_prior_rank tr td,
5551: table.LC_prior_match tr td {
1.524 albertel 5552: border: 1px solid #000000;
1.515 albertel 5553: }
5554:
1.855 bisitz 5555: .LC_nobreak {
1.544 albertel 5556: white-space: nowrap;
1.519 raeburn 5557: }
5558:
1.576 raeburn 5559: span.LC_cusr_emph {
5560: font-style: italic;
5561: }
5562:
1.633 raeburn 5563: span.LC_cusr_subheading {
5564: font-weight: normal;
5565: font-size: 85%;
5566: }
5567:
1.545 albertel 5568: table.LC_docs_documents {
5569: background: #BBBBBB;
1.803 bisitz 5570: border-width: 0;
1.545 albertel 5571: border-collapse: collapse;
5572: }
1.795 www 5573:
1.777 tempelho 5574: table.LC_docs_documents td.LC_docs_document {
1.779 bisitz 5575: border: 2px solid black;
5576: padding: 4px;
1.777 tempelho 5577: }
1.795 www 5578:
1.861 bisitz 5579: div.LC_docs_entry_move {
1.859 bisitz 5580: border: 1px solid #BBBBBB;
1.545 albertel 5581: background: #DDDDDD;
1.861 bisitz 5582: width: 22px;
1.859 bisitz 5583: padding: 1px;
5584: margin: 0;
1.545 albertel 5585: }
5586:
1.861 bisitz 5587: table.LC_data_table tr > td.LC_docs_entry_commands,
5588: table.LC_data_table tr > td.LC_docs_entry_parameter {
1.545 albertel 5589: background: #DDDDDD;
5590: font-size: x-small;
5591: }
1.795 www 5592:
1.861 bisitz 5593: .LC_docs_entry_parameter {
5594: white-space: nowrap;
5595: }
5596:
1.544 albertel 5597: .LC_docs_copy {
1.545 albertel 5598: color: #000099;
1.544 albertel 5599: }
1.795 www 5600:
1.544 albertel 5601: .LC_docs_cut {
1.545 albertel 5602: color: #550044;
1.544 albertel 5603: }
1.795 www 5604:
1.544 albertel 5605: .LC_docs_rename {
1.545 albertel 5606: color: #009900;
1.544 albertel 5607: }
1.795 www 5608:
1.544 albertel 5609: .LC_docs_remove {
1.545 albertel 5610: color: #990000;
5611: }
5612:
1.547 albertel 5613: .LC_docs_reinit_warn,
5614: .LC_docs_ext_edit {
5615: font-size: x-small;
5616: }
5617:
1.545 albertel 5618: table.LC_docs_adddocs td,
5619: table.LC_docs_adddocs th {
5620: border: 1px solid #BBBBBB;
5621: padding: 4px;
5622: background: #DDDDDD;
1.543 albertel 5623: }
5624:
1.584 albertel 5625: table.LC_sty_begin {
5626: background: #BBFFBB;
5627: }
1.795 www 5628:
1.584 albertel 5629: table.LC_sty_end {
5630: background: #FFBBBB;
5631: }
5632:
1.589 raeburn 5633: table.LC_double_column {
1.803 bisitz 5634: border-width: 0;
1.589 raeburn 5635: border-collapse: collapse;
5636: width: 100%;
5637: padding: 2px;
5638: }
5639:
5640: table.LC_double_column tr td.LC_left_col {
1.590 raeburn 5641: top: 2px;
1.589 raeburn 5642: left: 2px;
5643: width: 47%;
5644: vertical-align: top;
5645: }
5646:
5647: table.LC_double_column tr td.LC_right_col {
5648: top: 2px;
1.779 bisitz 5649: right: 2px;
1.589 raeburn 5650: width: 47%;
5651: vertical-align: top;
5652: }
5653:
1.591 raeburn 5654: div.LC_left_float {
5655: float: left;
5656: padding-right: 5%;
1.597 albertel 5657: padding-bottom: 4px;
1.591 raeburn 5658: }
5659:
5660: div.LC_clear_float_header {
1.597 albertel 5661: padding-bottom: 2px;
1.591 raeburn 5662: }
5663:
5664: div.LC_clear_float_footer {
1.597 albertel 5665: padding-top: 10px;
1.591 raeburn 5666: clear: both;
5667: }
5668:
1.597 albertel 5669: div.LC_grade_show_user {
5670: margin-top: 20px;
5671: border: 1px solid black;
5672: }
1.795 www 5673:
1.597 albertel 5674: div.LC_grade_user_name {
5675: background: #DDDDEE;
5676: border-bottom: 1px solid black;
1.705 tempelho 5677: font-weight: bold;
5678: font-size: large;
1.597 albertel 5679: }
1.795 www 5680:
1.597 albertel 5681: div.LC_grade_show_user_odd_row div.LC_grade_user_name {
5682: background: #DDEEDD;
5683: }
5684:
5685: div.LC_grade_show_problem,
5686: div.LC_grade_submissions,
5687: div.LC_grade_message_center,
5688: div.LC_grade_info_links,
5689: div.LC_grade_assign {
5690: margin: 5px;
5691: width: 99%;
5692: background: #FFFFFF;
5693: }
1.795 www 5694:
1.597 albertel 5695: div.LC_grade_show_problem_header,
5696: div.LC_grade_submissions_header,
5697: div.LC_grade_message_center_header,
5698: div.LC_grade_assign_header {
1.705 tempelho 5699: font-weight: bold;
5700: font-size: large;
1.597 albertel 5701: }
1.795 www 5702:
1.597 albertel 5703: div.LC_grade_show_problem_problem,
5704: div.LC_grade_submissions_body,
5705: div.LC_grade_message_center_body,
5706: div.LC_grade_assign_body {
5707: border: 1px solid black;
5708: width: 99%;
5709: background: #FFFFFF;
5710: }
1.795 www 5711:
1.598 albertel 5712: span.LC_grade_check_note {
1.705 tempelho 5713: font-weight: normal;
5714: font-size: medium;
1.598 albertel 5715: display: inline;
5716: position: absolute;
5717: right: 1em;
5718: }
1.597 albertel 5719:
1.613 albertel 5720: table.LC_scantron_action {
5721: width: 100%;
5722: }
1.795 www 5723:
1.613 albertel 5724: table.LC_scantron_action tr th {
1.698 harmsja 5725: font-weight:bold;
5726: font-style:normal;
1.613 albertel 5727: }
1.795 www 5728:
1.779 bisitz 5729: .LC_edit_problem_header,
1.614 albertel 5730: div.LC_edit_problem_footer {
1.705 tempelho 5731: font-weight: normal;
5732: font-size: medium;
1.602 albertel 5733: margin: 2px;
1.600 albertel 5734: }
1.795 www 5735:
1.600 albertel 5736: div.LC_edit_problem_header,
1.602 albertel 5737: div.LC_edit_problem_header div,
1.614 albertel 5738: div.LC_edit_problem_footer,
5739: div.LC_edit_problem_footer div,
1.602 albertel 5740: div.LC_edit_problem_editxml_header,
5741: div.LC_edit_problem_editxml_header div {
1.600 albertel 5742: margin-top: 5px;
5743: }
1.795 www 5744:
1.600 albertel 5745: div.LC_edit_problem_header_title {
1.705 tempelho 5746: font-weight: bold;
5747: font-size: larger;
1.602 albertel 5748: background: $tabbg;
5749: padding: 3px;
5750: }
1.795 www 5751:
1.602 albertel 5752: table.LC_edit_problem_header_title {
1.705 tempelho 5753: font-size: larger;
5754: font-weight: bold;
1.602 albertel 5755: width: 100%;
5756: border-color: $pgbg;
5757: border-style: solid;
5758: border-width: $border;
1.600 albertel 5759: background: $tabbg;
1.602 albertel 5760: border-collapse: collapse;
1.803 bisitz 5761: padding: 0;
1.602 albertel 5762: }
5763:
5764: div.LC_edit_problem_discards {
5765: float: left;
5766: padding-bottom: 5px;
5767: }
1.795 www 5768:
1.602 albertel 5769: div.LC_edit_problem_saves {
5770: float: right;
5771: padding-bottom: 5px;
1.600 albertel 5772: }
1.795 www 5773:
1.679 riegler 5774: img.stift{
1.803 bisitz 5775: border-width: 0;
5776: vertical-align: middle;
1.677 riegler 5777: }
1.680 riegler 5778:
1.681 riegler 5779: table#LC_mainmenu{
5780: margin-top:10px;
5781: width:80%;
5782: }
5783:
1.680 riegler 5784: table#LC_mainmenu td.LC_mainmenu_col_fieldset{
5785: vertical-align: top;
5786: width: 45%;
5787: }
1.795 www 5788:
1.779 bisitz 5789: .LC_mainmenu_fieldset_category {
5790: color: $font;
5791: background: $pgbg;
5792: font-size: small;
5793: font-weight: bold;
1.777 tempelho 5794: }
1.795 www 5795:
1.716 raeburn 5796: div.LC_createcourse {
5797: margin: 10px 10px 10px 10px;
5798: }
5799:
1.693 droeschl 5800: /* ---- Remove when done ----
5801: # The following styles is part of the redesign of LON-CAPA and are
5802: # subject to change during this project.
5803: # Don't rely on their current functionality as they might be
5804: # changed or removed.
5805: # --------------------------*/
5806:
1.698 harmsja 5807: a:hover,
1.721 harmsja 5808: ol.LC_smallMenu a:hover,
5809: ol#LC_MenuBreadcrumbs a:hover,
5810: ol#LC_PathBreadcrumbs a:hover,
5811: ul#LC_TabMainMenuContent a:hover,
5812: .LC_FormSectionClearButton input:hover
1.795 www 5813: ul.LC_TabContent li:hover a {
1.698 harmsja 5814: color:#BF2317;
5815: text-decoration:none;
1.693 droeschl 5816: }
5817:
1.779 bisitz 5818: h1 {
1.813 bisitz 5819: padding: 0;
1.693 droeschl 5820: line-height:130%;
5821: }
1.698 harmsja 5822:
1.795 www 5823: h2,h3,h4,h5,h6 {
1.803 bisitz 5824: margin: 5px 0 5px 0;
5825: padding: 0;
1.721 harmsja 5826: line-height:130%;
1.693 droeschl 5827: }
1.795 www 5828:
5829: .LC_hcell {
1.698 harmsja 5830: padding:3px 15px 3px 15px;
1.803 bisitz 5831: margin: 0;
1.703 harmsja 5832: background-color:$tabbg;
1.801 tempelho 5833: color:$fontmenu;
1.779 bisitz 5834: border-bottom:solid 1px $lg_border_color;
1.693 droeschl 5835: }
1.795 www 5836:
1.840 bisitz 5837: .LC_Box > .LC_hcell {
1.847 tempelho 5838: margin: 0 -10px 10px -10px;
1.835 bisitz 5839: }
5840:
1.721 harmsja 5841: .LC_noBorder {
1.803 bisitz 5842: border: 0;
1.698 harmsja 5843: }
1.693 droeschl 5844:
1.761 tempelho 5845: .LC_Right {
5846: float: right;
1.803 bisitz 5847: margin: 0;
5848: padding: 0;
1.761 tempelho 5849: }
5850:
1.721 harmsja 5851: .LC_FormSectionClearButton input {
1.779 bisitz 5852: background-color:transparent;
1.803 bisitz 5853: border: none;
1.698 harmsja 5854: cursor:pointer;
5855: text-decoration:underline;
1.693 droeschl 5856: }
1.763 bisitz 5857:
5858: .LC_help_open_topic {
5859: color: #FFFFFF;
5860: background-color: #EEEEFF;
5861: margin: 1px;
5862: padding: 4px;
5863: border: 1px solid #000033;
5864: white-space: nowrap;
1.783 amueller 5865: /* vertical-align: middle; */
1.759 neumanie 5866: }
1.693 droeschl 5867:
1.698 harmsja 5868: dl,ul,div,fieldset {
1.803 bisitz 5869: margin: 10px 10px 10px 0;
1.806 bisitz 5870: /* overflow: hidden; */
1.693 droeschl 5871: }
1.795 www 5872:
1.838 bisitz 5873: fieldset > legend {
5874: font-weight: bold;
5875: padding: 0 5px 0 5px;
5876: }
5877:
1.813 bisitz 5878: #LC_nav_bar {
1.807 droeschl 5879: float: left;
1.852 droeschl 5880: margin: 0.2em 0 0 0;
1.807 droeschl 5881: }
5882:
1.813 bisitz 5883: #LC_nav_bar em{
1.807 droeschl 5884: font-weight: bold;
5885: font-style: normal;
5886: }
5887:
5888: ol.LC_smallMenu {
5889: float: right;
1.852 droeschl 5890: margin: 0.2em 0 0 0;
1.807 droeschl 5891: }
5892:
1.852 droeschl 5893: ol#LC_PathBreadcrumbs {
1.803 bisitz 5894: margin: 0;
1.693 droeschl 5895: }
5896:
1.721 harmsja 5897: ol.LC_smallMenu li {
1.693 droeschl 5898: display: inline;
1.803 bisitz 5899: padding: 5px 5px 0 10px;
1.693 droeschl 5900: vertical-align: top;
5901: }
5902:
1.721 harmsja 5903: ol.LC_smallMenu li img {
1.693 droeschl 5904: vertical-align: bottom;
5905: }
5906:
1.721 harmsja 5907: ol.LC_smallMenu a {
1.693 droeschl 5908: font-size: 90%;
5909: color: RGB(80, 80, 80);
5910: text-decoration: none;
5911: }
1.795 www 5912:
1.808 droeschl 5913: ul#LC_TabMainMenuContent {
1.807 droeschl 5914: clear: both;
1.808 droeschl 5915: color: $fontmenu;
5916: background: $tabbg;
5917: list-style: none;
5918: padding: 0;
5919: margin: 0;
5920: width: 100%;
5921: }
5922:
5923: ul#LC_TabMainMenuContent li {
5924: font-weight: bold;
5925: line-height: 1.8em;
5926: padding: 0 0.8em;
5927: border-right: 1px solid black;
5928: display: inline;
5929: vertical-align: middle;
1.807 droeschl 5930: }
5931:
1.847 tempelho 5932: ul.LC_TabContent {
1.721 harmsja 5933: display:block;
1.847 tempelho 5934: background: $sidebg;
1.858 bisitz 5935: border-bottom: solid 1px $lg_border_color;
1.721 harmsja 5936: list-style:none;
1.870 tempelho 5937: margin: 0 -10px;
1.803 bisitz 5938: padding: 0;
1.693 droeschl 5939: }
5940:
1.795 www 5941: ul.LC_TabContent li,
5942: ul.LC_TabContentBigger li {
1.741 harmsja 5943: float:left;
5944: }
1.795 www 5945:
1.808 droeschl 5946: ul#LC_TabMainMenuContent li a {
5947: color: $fontmenu;
1.693 droeschl 5948: text-decoration: none;
5949: }
1.795 www 5950:
1.721 harmsja 5951: ul.LC_TabContent {
1.847 tempelho 5952: min-height:1.5em;
1.721 harmsja 5953: }
1.795 www 5954:
5955: ul.LC_TabContent li {
1.741 harmsja 5956: vertical-align:middle;
1.803 bisitz 5957: padding: 0 10px 0 10px;
1.745 ehlerst 5958: background-color:$tabbg;
5959: border-bottom:solid 1px $lg_border_color;
1.721 harmsja 5960: }
1.795 www 5961:
1.847 tempelho 5962: ul.LC_TabContent .right {
5963: float:right;
5964: }
5965:
1.795 www 5966: ul.LC_TabContent li a, ul.LC_TabContent li {
1.721 harmsja 5967: color:rgb(47,47,47);
5968: text-decoration:none;
5969: font-size:95%;
5970: font-weight:bold;
1.761 tempelho 5971: padding-right: 16px;
1.721 harmsja 5972: }
1.795 www 5973:
5974: ul.LC_TabContent li:hover, ul.LC_TabContent li.active {
1.761 tempelho 5975: background:#FFFFFF url(/adm/lonIcons/open.gif) no-repeat scroll right center;
1.841 tempelho 5976: border-bottom:solid 2px #FFFFFF;
1.761 tempelho 5977: padding-right: 16px;
1.744 ehlerst 5978: }
1.795 www 5979:
1.870 tempelho 5980: #maincoursedoc {
5981: clear:both;
5982: }
5983:
5984: ul.LC_TabContentBigger {
5985: display:block;
5986: list-style:none;
5987: padding: 0;
5988: }
5989:
1.795 www 5990: ul.LC_TabContentBigger li {
1.870 tempelho 5991: vertical-align:bottom;
5992: height: 30px;
5993: font-size:110%;
5994: font-weight:bold;
5995: color: #737373;
1.841 tempelho 5996: }
5997:
1.870 tempelho 5998:
5999: ul.LC_TabContentBigger li a {
6000: background:url('/adm/lonIcons/tabbgleft.gif') left bottom no-repeat;
6001: height: 30px;
6002: line-height: 30px;
6003: text-align: center;
6004: display: block;
6005: text-decoration: none;
1.741 harmsja 6006: }
1.795 www 6007:
1.870 tempelho 6008: ul.LC_TabContentBigger li:hover a,
6009: ul.LC_TabContentBigger li.active a {
6010: background:url('/adm/lonIcons/tabbgleft.gif') left top no-repeat;
1.857 tempelho 6011: color:$font;
1.870 tempelho 6012: text-decoration: underline;
1.744 ehlerst 6013: }
1.795 www 6014:
1.870 tempelho 6015:
6016: ul.LC_TabContentBigger li b {
6017: background: url('/adm/lonIcons/tabbgright.gif') no-repeat right bottom;
6018: display: block;
6019: float: left;
6020: padding: 0 30px;
6021: }
6022:
6023: ul.LC_TabContentBigger li:hover b,
6024: ul.LC_TabContentBigger li.active b {
6025: background:url('/adm/lonIcons/tabbgright.gif') right top no-repeat;
6026: color:$font;
6027: border-bottom: 1px solid #FFFFFF;
1.741 harmsja 6028: }
1.693 droeschl 6029:
1.870 tempelho 6030:
1.862 bisitz 6031: ul.LC_CourseBreadcrumbs {
6032: background: $sidebg;
6033: line-height: 32px;
6034: padding-left: 10px;
6035: margin: 0 0 10px 0;
6036: list-style-position: inside;
6037:
6038: }
6039:
1.795 www 6040: ol#LC_MenuBreadcrumbs,
1.862 bisitz 6041: ol#LC_PathBreadcrumbs {
1.693 droeschl 6042: padding-left: 10px;
1.819 tempelho 6043: margin: 0;
1.693 droeschl 6044: list-style-position: inside;
6045: }
6046:
1.795 www 6047: ol#LC_MenuBreadcrumbs li,
6048: ol#LC_PathBreadcrumbs li,
1.862 bisitz 6049: ul.LC_CourseBreadcrumbs li {
1.842 droeschl 6050: display: inline;
6051: white-space: nowrap;
1.693 droeschl 6052: }
6053:
1.823 bisitz 6054: ol#LC_MenuBreadcrumbs li a,
1.862 bisitz 6055: ul.LC_CourseBreadcrumbs li a {
1.693 droeschl 6056: text-decoration: none;
6057: font-size:90%;
6058: }
1.795 www 6059:
6060: ol#LC_PathBreadcrumbs li a {
1.698 harmsja 6061: text-decoration:none;
6062: font-size:100%;
6063: font-weight:bold;
1.693 droeschl 6064: }
1.795 www 6065:
1.840 bisitz 6066: .LC_Box {
1.835 bisitz 6067: border: solid 1px $lg_border_color;
6068: padding: 0 10px 10px 10px;
1.746 neumanie 6069: }
1.795 www 6070:
6071: .LC_AboutMe_Image {
1.747 neumanie 6072: float:left;
6073: margin-right:10px;
6074: }
1.795 www 6075:
6076: .LC_Clear_AboutMe_Image {
1.747 neumanie 6077: clear:left;
6078: }
1.795 www 6079:
1.721 harmsja 6080: dl.LC_ListStyleClean dt {
1.693 droeschl 6081: padding-right: 5px;
6082: display: table-header-group;
6083: }
6084:
1.721 harmsja 6085: dl.LC_ListStyleClean dd {
1.693 droeschl 6086: display: table-row;
6087: }
6088:
1.721 harmsja 6089: .LC_ListStyleClean,
6090: .LC_ListStyleSimple,
6091: .LC_ListStyleNormal,
1.777 tempelho 6092: .LC_ListStyle_Border,
1.795 www 6093: .LC_ListStyleSpecial {
1.693 droeschl 6094: /*display:block; */
6095: list-style-position: inside;
6096: list-style-type: none;
6097: overflow: hidden;
1.803 bisitz 6098: padding: 0;
1.693 droeschl 6099: }
6100:
1.721 harmsja 6101: .LC_ListStyleSimple li,
6102: .LC_ListStyleSimple dd,
6103: .LC_ListStyleNormal li,
6104: .LC_ListStyleNormal dd,
6105: .LC_ListStyleSpecial li,
1.795 www 6106: .LC_ListStyleSpecial dd {
1.803 bisitz 6107: margin: 0;
1.693 droeschl 6108: padding: 5px 5px 5px 10px;
6109: clear: both;
6110: }
6111:
1.721 harmsja 6112: .LC_ListStyleClean li,
6113: .LC_ListStyleClean dd {
1.803 bisitz 6114: padding-top: 0;
6115: padding-bottom: 0;
1.693 droeschl 6116: }
6117:
1.721 harmsja 6118: .LC_ListStyleSimple dd,
1.795 www 6119: .LC_ListStyleSimple li {
1.698 harmsja 6120: border-bottom: solid 1px $lg_border_color;
1.693 droeschl 6121: }
6122:
1.721 harmsja 6123: .LC_ListStyleSpecial li,
6124: .LC_ListStyleSpecial dd {
1.693 droeschl 6125: list-style-type: none;
6126: background-color: RGB(220, 220, 220);
6127: margin-bottom: 4px;
6128: }
6129:
1.721 harmsja 6130: table.LC_SimpleTable {
1.698 harmsja 6131: margin:5px;
6132: border:solid 1px $lg_border_color;
1.795 www 6133: }
1.693 droeschl 6134:
1.721 harmsja 6135: table.LC_SimpleTable tr {
1.803 bisitz 6136: padding: 0;
1.698 harmsja 6137: border:solid 1px $lg_border_color;
1.693 droeschl 6138: }
1.795 www 6139:
6140: table.LC_SimpleTable thead {
1.698 harmsja 6141: background:rgb(220,220,220);
1.693 droeschl 6142: }
6143:
1.721 harmsja 6144: div.LC_columnSection {
1.693 droeschl 6145: display: block;
6146: clear: both;
6147: overflow: hidden;
1.803 bisitz 6148: margin: 0;
1.693 droeschl 6149: }
6150:
1.721 harmsja 6151: div.LC_columnSection>* {
1.693 droeschl 6152: float: left;
1.803 bisitz 6153: margin: 10px 20px 10px 0;
1.747 neumanie 6154: overflow:hidden;
1.693 droeschl 6155: }
1.721 harmsja 6156:
1.694 tempelho 6157: .LC_loginpage_container {
6158: text-align:left;
6159: margin : 0 auto;
1.785 tempelho 6160: width:90%;
1.694 tempelho 6161: padding: 10px;
6162: height: auto;
1.712 muellerd 6163: background-color:#FFFFFF;
1.694 tempelho 6164: border:1px solid #CCCCCC;
6165: }
6166:
6167:
6168: .LC_loginpage_loginContainer {
6169: float:left;
1.712 muellerd 6170: width: 182px;
1.785 tempelho 6171: padding: 2px;
1.712 muellerd 6172: border:1px solid #CCCCCC;
6173: background-color:$loginbg;
1.694 tempelho 6174: }
6175:
1.795 www 6176: .LC_loginpage_loginContainer h2 {
1.803 bisitz 6177: margin-top: 0;
1.712 muellerd 6178: display:block;
6179: background:$bgcol;
6180: color:$textcol;
6181: padding-left:5px;
6182: }
1.785 tempelho 6183:
1.694 tempelho 6184: .LC_loginpage_loginInfo {
6185: float:left;
1.785 tempelho 6186: width:182px;
1.694 tempelho 6187: border:1px solid #CCCCCC;
1.785 tempelho 6188: padding:2px;
1.712 muellerd 6189: }
6190:
1.694 tempelho 6191: .LC_loginpage_space {
1.754 droeschl 6192: clear: both;
6193: margin-bottom: 20px;
1.694 tempelho 6194: border-bottom: 1px solid #CCCCCC;
6195: }
6196:
1.785 tempelho 6197: .LC_loginpage_floatLeft {
6198: float: left;
6199: width: 200px;
6200: margin: 0;
6201: }
6202:
1.795 www 6203: table em {
1.754 droeschl 6204: font-weight: bold;
6205: font-style: normal;
1.748 schulted 6206: }
1.795 www 6207:
1.779 bisitz 6208: table.LC_tableBrowseRes,
1.795 www 6209: table.LC_tableOfContent {
1.769 schulted 6210: border:none;
1.858 bisitz 6211: border-spacing: 1px;
1.754 droeschl 6212: padding: 3px;
6213: background-color: #FFFFFF;
6214: font-size: 90%;
1.753 droeschl 6215: }
1.789 droeschl 6216:
6217: table.LC_tableOfContent{
6218: border-collapse: collapse;
6219: }
6220:
1.771 droeschl 6221: table.LC_tableBrowseRes a,
1.768 schulted 6222: table.LC_tableOfContent a {
1.771 droeschl 6223: background-color: transparent;
1.753 droeschl 6224: text-decoration: none;
6225: }
6226:
1.771 droeschl 6227: table.LC_tableBrowseRes tr.LC_trOdd,
1.768 schulted 6228: table.LC_tableOfContent tr.LC_trOdd{
1.754 droeschl 6229: background-color: #EEEEEE;
1.753 droeschl 6230: }
6231:
1.795 www 6232: table.LC_tableOfContent img {
1.753 droeschl 6233: border: none;
6234: height: 1.3em;
6235: vertical-align: text-bottom;
6236: margin-right: 0.3em;
6237: }
1.757 schulted 6238:
1.795 www 6239: a#LC_content_toolbar_firsthomework {
1.774 ehlerst 6240: background-image:url(/res/adm/pages/open-first-problem.gif);
6241: }
6242:
1.795 www 6243: a#LC_content_toolbar_launchnav {
1.774 ehlerst 6244: background-image:url(/res/adm/pages/start-navigation.gif);
6245: }
6246:
1.795 www 6247: a#LC_content_toolbar_closenav {
1.774 ehlerst 6248: background-image:url(/res/adm/pages/close-navigation.gif);
6249: }
6250:
1.795 www 6251: a#LC_content_toolbar_everything {
1.774 ehlerst 6252: background-image:url(/res/adm/pages/show-all.gif);
6253: }
6254:
1.795 www 6255: a#LC_content_toolbar_uncompleted {
1.774 ehlerst 6256: background-image:url(/res/adm/pages/show-incomplete-problems.gif);
6257: }
6258:
1.795 www 6259: #LC_content_toolbar_clearbubbles {
1.774 ehlerst 6260: background-image:url(/res/adm/pages/mark-discussionentries-read.gif);
6261: }
6262:
1.795 www 6263: a#LC_content_toolbar_changefolder {
1.757 schulted 6264: background : url(/res/adm/pages/close-all-folders.gif) top center ;
6265: }
6266:
1.795 www 6267: a#LC_content_toolbar_changefolder_toggled {
1.757 schulted 6268: background-image:url(/res/adm/pages/open-all-folders.gif);
6269: }
6270:
1.795 www 6271: ul#LC_toolbar li a:hover {
1.757 schulted 6272: background-position: bottom center;
6273: }
6274:
1.795 www 6275: ul#LC_toolbar {
1.803 bisitz 6276: padding: 0;
1.757 schulted 6277: margin: 2px;
6278: list-style:none;
6279: position:relative;
6280: background-color:white;
6281: }
6282:
1.795 www 6283: ul#LC_toolbar li {
1.757 schulted 6284: border:1px solid white;
1.803 bisitz 6285: padding: 0;
1.757 schulted 6286: margin: 0;
1.795 www 6287: float: left;
1.767 droeschl 6288: display:inline;
1.757 schulted 6289: vertical-align:middle;
1.795 www 6290: }
1.757 schulted 6291:
1.783 amueller 6292:
1.795 www 6293: a.LC_toolbarItem {
1.767 droeschl 6294: display:block;
1.803 bisitz 6295: padding: 0;
6296: margin: 0;
1.757 schulted 6297: height: 32px;
6298: width: 32px;
1.779 bisitz 6299: color:white;
1.803 bisitz 6300: border: none;
1.757 schulted 6301: background-repeat:no-repeat;
6302: background-color:transparent;
6303: }
6304:
1.843 bisitz 6305: ul.LC_funclist li {
1.782 bisitz 6306: float: left;
6307: white-space: nowrap;
6308: height: 35px; /* at least as high as heighest list item */
1.803 bisitz 6309: margin: 0 15px 15px 10px;
1.782 bisitz 6310: }
6311:
1.757 schulted 6312:
1.343 albertel 6313: END
6314: }
6315:
1.306 albertel 6316: =pod
6317:
6318: =item * &headtag()
6319:
6320: Returns a uniform footer for LON-CAPA web pages.
6321:
1.307 albertel 6322: Inputs: $title - optional title for the head
6323: $head_extra - optional extra HTML to put inside the <head>
1.315 albertel 6324: $args - optional arguments
1.319 albertel 6325: force_register - if is true call registerurl so the remote is
6326: informed
1.415 albertel 6327: redirect -> array ref of
6328: 1- seconds before redirect occurs
6329: 2- url to redirect to
6330: 3- whether the side effect should occur
1.315 albertel 6331: (side effect of setting
6332: $env{'internal.head.redirect'} to the url
6333: redirected too)
1.352 albertel 6334: domain -> force to color decorate a page for a specific
6335: domain
6336: function -> force usage of a specific rolish color scheme
6337: bgcolor -> override the default page bgcolor
1.460 albertel 6338: no_auto_mt_title
6339: -> prevent &mt()ing the title arg
1.464 albertel 6340:
1.306 albertel 6341: =cut
6342:
6343: sub headtag {
1.313 albertel 6344: my ($title,$head_extra,$args) = @_;
1.306 albertel 6345:
1.363 albertel 6346: my $function = $args->{'function'} || &get_users_function();
6347: my $domain = $args->{'domain'} || &determinedomain();
6348: my $bgcolor = $args->{'bgcolor'} || &designparm($function.'.pgbg',$domain);
1.418 albertel 6349: my $url = join(':',$env{'user.name'},$env{'user.domain'},
1.458 albertel 6350: $Apache::lonnet::perlvar{'lonVersion'},
1.531 albertel 6351: #time(),
1.418 albertel 6352: $env{'environment.color.timestamp'},
1.363 albertel 6353: $function,$domain,$bgcolor);
6354:
1.369 www 6355: $url = '/adm/css/'.&escape($url).'.css';
1.363 albertel 6356:
1.308 albertel 6357: my $result =
6358: '<head>'.
1.461 albertel 6359: &font_settings();
1.319 albertel 6360:
1.461 albertel 6361: if (!$args->{'frameset'}) {
6362: $result .= &Apache::lonhtmlcommon::htmlareaheaders();
6363: }
1.319 albertel 6364: if ($args->{'force_register'}) {
6365: $result .= &Apache::lonmenu::registerurl(1);
6366: }
1.436 albertel 6367: if (!$args->{'no_nav_bar'}
6368: && !$args->{'only_body'}
6369: && !$args->{'frameset'}) {
6370: $result .= &help_menu_js();
6371: }
1.319 albertel 6372:
1.314 albertel 6373: if (ref($args->{'redirect'})) {
1.414 albertel 6374: my ($time,$url,$inhibit_continue) = @{$args->{'redirect'}};
1.315 albertel 6375: $url = &Apache::lonenc::check_encrypt($url);
1.414 albertel 6376: if (!$inhibit_continue) {
6377: $env{'internal.head.redirect'} = $url;
6378: }
1.313 albertel 6379: $result.=<<ADDMETA
6380: <meta http-equiv="pragma" content="no-cache" />
1.344 albertel 6381: <meta http-equiv="Refresh" content="$time; url=$url" />
1.313 albertel 6382: ADDMETA
6383: }
1.306 albertel 6384: if (!defined($title)) {
6385: $title = 'The LearningOnline Network with CAPA';
6386: }
1.460 albertel 6387: if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); }
6388: $result .= '<title> LON-CAPA '.$title.'</title>'
1.414 albertel 6389: .'<link rel="stylesheet" type="text/css" href="'.$url.'" />'
6390: .$head_extra;
1.306 albertel 6391: return $result;
6392: }
6393:
6394: =pod
6395:
1.340 albertel 6396: =item * &font_settings()
6397:
6398: Returns neccessary <meta> to set the proper encoding
6399:
6400: Inputs: none
6401:
6402: =cut
6403:
6404: sub font_settings {
6405: my $headerstring='';
1.647 www 6406: if (!$env{'browser.mathml'} && $env{'browser.unicode'}) {
1.340 albertel 6407: $headerstring.=
6408: '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
6409: }
6410: return $headerstring;
6411: }
6412:
1.341 albertel 6413: =pod
6414:
6415: =item * &xml_begin()
6416:
6417: Returns the needed doctype and <html>
6418:
6419: Inputs: none
6420:
6421: =cut
6422:
6423: sub xml_begin {
6424: my $output='';
6425:
1.592 albertel 6426: if ($env{'internal.start_page'}==1) {
6427: &Apache::lonhtmlcommon::init_htmlareafields();
6428: }
1.342 albertel 6429:
1.341 albertel 6430: if ($env{'browser.mathml'}) {
6431: $output='<?xml version="1.0"?>'
6432: #.'<?xml-stylesheet type="text/css" href="/adm/MathML/mathml.css"?>'."\n"
6433: # .'<!DOCTYPE html SYSTEM "/adm/MathML/mathml.dtd" '
6434:
6435: # .'<!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">] >'
6436: .'<!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">'
6437: .'<html xmlns:math="http://www.w3.org/1998/Math/MathML" '
6438: .'xmlns="http://www.w3.org/1999/xhtml">';
6439: } else {
1.849 bisitz 6440: $output='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
6441: .'<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';
1.341 albertel 6442: }
6443: return $output;
6444: }
1.340 albertel 6445:
6446: =pod
6447:
1.306 albertel 6448: =item * &endheadtag()
6449:
6450: Returns a uniform </head> for LON-CAPA web pages.
6451:
6452: Inputs: none
6453:
6454: =cut
6455:
6456: sub endheadtag {
6457: return '</head>';
6458: }
6459:
6460: =pod
6461:
6462: =item * &head()
6463:
6464: Returns a uniform complete <head>..</head> section for LON-CAPA web pages.
6465:
1.648 raeburn 6466: Inputs:
6467:
6468: =over 4
6469:
6470: $title - optional title for the page
6471:
6472: $head_extra - optional extra HTML to put inside the <head>
6473:
6474: =back
1.405 albertel 6475:
1.306 albertel 6476: =cut
6477:
6478: sub head {
1.325 albertel 6479: my ($title,$head_extra,$args) = @_;
6480: return &headtag($title,$head_extra,$args).&endheadtag();
1.306 albertel 6481: }
6482:
6483: =pod
6484:
6485: =item * &start_page()
6486:
6487: Returns a complete <html> .. <body> section for LON-CAPA web pages.
6488:
1.648 raeburn 6489: Inputs:
6490:
6491: =over 4
6492:
6493: $title - optional title for the page
6494:
6495: $head_extra - optional extra HTML to incude inside the <head>
6496:
6497: $args - additional optional args supported are:
6498:
6499: =over 8
6500:
6501: only_body -> is true will set &bodytag() onlybodytag
1.317 albertel 6502: arg on
1.814 bisitz 6503: no_nav_bar -> is true will set &bodytag() no_nav_bar arg on
1.648 raeburn 6504: add_entries -> additional attributes to add to the <body>
6505: domain -> force to color decorate a page for a
1.317 albertel 6506: specific domain
1.648 raeburn 6507: function -> force usage of a specific rolish color
1.317 albertel 6508: scheme
1.648 raeburn 6509: redirect -> see &headtag()
6510: bgcolor -> override the default page bg color
6511: js_ready -> return a string ready for being used in
1.317 albertel 6512: a javascript writeln
1.648 raeburn 6513: html_encode -> return a string ready for being used in
1.320 albertel 6514: a html attribute
1.648 raeburn 6515: force_register -> if is true will turn on the &bodytag()
1.317 albertel 6516: $forcereg arg
1.648 raeburn 6517: frameset -> if true will start with a <frameset>
1.330 albertel 6518: rather than <body>
1.648 raeburn 6519: skip_phases -> hash ref of
1.338 albertel 6520: head -> skip the <html><head> generation
6521: body -> skip all <body> generation
1.648 raeburn 6522: no_inline_link -> if true and in remote mode, don't show the
1.361 albertel 6523: 'Switch To Inline Menu' link
1.648 raeburn 6524: no_auto_mt_title -> prevent &mt()ing the title arg
6525: inherit_jsmath -> when creating popup window in a page,
6526: should it have jsmath forced on by the
6527: current page
1.867 kalberla 6528: bread_crumbs -> Array containing breadcrumbs
6529: bread_crumbs_components -> if exists show it as headline else show only the breadcrumbs
1.361 albertel 6530:
1.648 raeburn 6531: =back
1.460 albertel 6532:
1.648 raeburn 6533: =back
1.562 albertel 6534:
1.306 albertel 6535: =cut
6536:
6537: sub start_page {
1.309 albertel 6538: my ($title,$head_extra,$args) = @_;
1.318 albertel 6539: #&Apache::lonnet::logthis("start_page ".join(':',caller(0)));
1.313 albertel 6540: my %head_args;
1.352 albertel 6541: foreach my $arg ('redirect','force_register','domain','function',
1.460 albertel 6542: 'bgcolor','frameset','no_nav_bar','only_body',
6543: 'no_auto_mt_title') {
1.319 albertel 6544: if (defined($args->{$arg})) {
1.324 raeburn 6545: $head_args{$arg} = $args->{$arg};
1.319 albertel 6546: }
1.313 albertel 6547: }
1.319 albertel 6548:
1.315 albertel 6549: $env{'internal.start_page'}++;
1.338 albertel 6550: my $result;
6551: if (! exists($args->{'skip_phases'}{'head'}) ) {
6552: $result.=
1.341 albertel 6553: &xml_begin().
1.338 albertel 6554: &headtag($title,$head_extra,\%head_args).&endheadtag();
6555: }
6556:
6557: if (! exists($args->{'skip_phases'}{'body'}) ) {
6558: if ($args->{'frameset'}) {
6559: my $attr_string = &make_attr_string($args->{'force_register'},
6560: $args->{'add_entries'});
6561: $result .= "\n<frameset $attr_string>\n";
1.831 bisitz 6562: } else {
6563: $result .=
6564: &bodytag($title,
6565: $args->{'function'}, $args->{'add_entries'},
6566: $args->{'only_body'}, $args->{'domain'},
6567: $args->{'force_register'}, $args->{'no_nav_bar'},
6568: $args->{'bgcolor'}, $args->{'no_inline_link'},
6569: $args);
6570: }
1.330 albertel 6571: }
1.338 albertel 6572:
1.315 albertel 6573: if ($args->{'js_ready'}) {
1.713 kaisler 6574: $result = &js_ready($result);
1.315 albertel 6575: }
1.320 albertel 6576: if ($args->{'html_encode'}) {
1.713 kaisler 6577: $result = &html_encode($result);
6578: }
6579:
1.813 bisitz 6580: # Preparation for new and consistent functionlist at top of screen
6581: # if ($args->{'functionlist'}) {
6582: # $result .= &build_functionlist();
6583: #}
6584:
6585: # Don't add anything more if only_body wanted
6586: return $result if $args->{'only_body'};
6587:
6588: #Breadcrumbs
1.758 kaisler 6589: if (exists($args->{'bread_crumbs'}) or exists($args->{'bread_crumbs_component'})) {
6590: &Apache::lonhtmlcommon::clear_breadcrumbs();
6591: #if any br links exists, add them to the breadcrumbs
6592: if (exists($args->{'bread_crumbs'}) and ref($args->{'bread_crumbs'}) eq 'ARRAY') {
6593: foreach my $crumb (@{$args->{'bread_crumbs'}}){
6594: &Apache::lonhtmlcommon::add_breadcrumb($crumb);
6595: }
6596: }
6597:
6598: #if bread_crumbs_component exists show it as headline else show only the breadcrumbs
6599: if(exists($args->{'bread_crumbs_component'})){
6600: $result .= &Apache::lonhtmlcommon::breadcrumbs($args->{'bread_crumbs_component'});
6601: }else{
6602: $result .= &Apache::lonhtmlcommon::breadcrumbs();
6603: }
1.320 albertel 6604: }
1.315 albertel 6605: return $result;
1.306 albertel 6606: }
6607:
1.330 albertel 6608:
1.306 albertel 6609: =pod
6610:
6611: =item * &head()
6612:
6613: Returns a complete </body></html> section for LON-CAPA web pages.
6614:
1.315 albertel 6615: Inputs: $args - additional optional args supported are:
6616: js_ready -> return a string ready for being used in
6617: a javascript writeln
1.320 albertel 6618: html_encode -> return a string ready for being used in
6619: a html attribute
1.330 albertel 6620: frameset -> if true will start with a <frameset>
6621: rather than <body>
1.493 albertel 6622: dicsussion -> if true will get discussion from
6623: lonxml::xmlend
6624: (you can pass the target and parser arguments
6625: through optional 'target' and 'parser' args
6626: to this routine)
1.306 albertel 6627:
6628: =cut
6629:
6630: sub end_page {
1.315 albertel 6631: my ($args) = @_;
6632: $env{'internal.end_page'}++;
1.330 albertel 6633: my $result;
1.335 albertel 6634: if ($args->{'discussion'}) {
6635: my ($target,$parser);
6636: if (ref($args->{'discussion'})) {
6637: ($target,$parser) =($args->{'discussion'}{'target'},
6638: $args->{'discussion'}{'parser'});
6639: }
6640: $result .= &Apache::lonxml::xmlend($target,$parser);
6641: }
6642:
1.330 albertel 6643: if ($args->{'frameset'}) {
6644: $result .= '</frameset>';
6645: } else {
1.635 raeburn 6646: $result .= &endbodytag($args);
1.330 albertel 6647: }
6648: $result .= "\n</html>";
6649:
1.315 albertel 6650: if ($args->{'js_ready'}) {
1.317 albertel 6651: $result = &js_ready($result);
1.315 albertel 6652: }
1.335 albertel 6653:
1.320 albertel 6654: if ($args->{'html_encode'}) {
6655: $result = &html_encode($result);
6656: }
1.335 albertel 6657:
1.315 albertel 6658: return $result;
6659: }
6660:
1.320 albertel 6661: sub html_encode {
6662: my ($result) = @_;
6663:
1.322 albertel 6664: $result = &HTML::Entities::encode($result,'<>&"');
1.320 albertel 6665:
6666: return $result;
6667: }
1.317 albertel 6668: sub js_ready {
6669: my ($result) = @_;
6670:
1.323 albertel 6671: $result =~ s/[\n\r]/ /xmsg;
6672: $result =~ s/\\/\\\\/xmsg;
6673: $result =~ s/'/\\'/xmsg;
1.372 albertel 6674: $result =~ s{</}{<\\/}xmsg;
1.317 albertel 6675:
6676: return $result;
6677: }
6678:
1.315 albertel 6679: sub validate_page {
6680: if ( exists($env{'internal.start_page'})
1.316 albertel 6681: && $env{'internal.start_page'} > 1) {
6682: &Apache::lonnet::logthis('start_page called multiple times '.
1.318 albertel 6683: $env{'internal.start_page'}.' '.
1.316 albertel 6684: $ENV{'request.filename'});
1.315 albertel 6685: }
6686: if ( exists($env{'internal.end_page'})
1.316 albertel 6687: && $env{'internal.end_page'} > 1) {
6688: &Apache::lonnet::logthis('end_page called multiple times '.
1.318 albertel 6689: $env{'internal.end_page'}.' '.
1.316 albertel 6690: $env{'request.filename'});
1.315 albertel 6691: }
6692: if ( exists($env{'internal.start_page'})
6693: && ! exists($env{'internal.end_page'})) {
1.316 albertel 6694: &Apache::lonnet::logthis('start_page called without end_page '.
6695: $env{'request.filename'});
1.315 albertel 6696: }
6697: if ( ! exists($env{'internal.start_page'})
6698: && exists($env{'internal.end_page'})) {
1.316 albertel 6699: &Apache::lonnet::logthis('end_page called without start_page'.
6700: $env{'request.filename'});
1.315 albertel 6701: }
1.306 albertel 6702: }
1.315 albertel 6703:
1.318 albertel 6704: sub simple_error_page {
6705: my ($r,$title,$msg) = @_;
6706: my $page =
6707: &Apache::loncommon::start_page($title).
6708: &mt($msg).
6709: &Apache::loncommon::end_page();
6710: if (ref($r)) {
6711: $r->print($page);
1.327 albertel 6712: return;
1.318 albertel 6713: }
6714: return $page;
6715: }
1.347 albertel 6716:
6717: {
1.610 albertel 6718: my @row_count;
1.347 albertel 6719: sub start_data_table {
1.422 albertel 6720: my ($add_class) = @_;
6721: my $css_class = (join(' ','LC_data_table',$add_class));
1.610 albertel 6722: unshift(@row_count,0);
1.422 albertel 6723: return '<table class="'.$css_class.'">'."\n";
1.347 albertel 6724: }
6725:
6726: sub end_data_table {
1.610 albertel 6727: shift(@row_count);
1.389 albertel 6728: return '</table>'."\n";;
1.347 albertel 6729: }
6730:
6731: sub start_data_table_row {
1.422 albertel 6732: my ($add_class) = @_;
1.610 albertel 6733: $row_count[0]++;
6734: my $css_class = ($row_count[0] % 2)?'LC_odd_row':'LC_even_row';
1.428 albertel 6735: $css_class = (join(' ',$css_class,$add_class));
1.422 albertel 6736: return '<tr class="'.$css_class.'">'."\n";;
1.347 albertel 6737: }
1.471 banghart 6738:
6739: sub continue_data_table_row {
6740: my ($add_class) = @_;
1.610 albertel 6741: my $css_class = ($row_count[0] % 2)?'LC_odd_row':'LC_even_row';
1.471 banghart 6742: $css_class = (join(' ',$css_class,$add_class));
6743: return '<tr class="'.$css_class.'">'."\n";;
6744: }
1.347 albertel 6745:
6746: sub end_data_table_row {
1.389 albertel 6747: return '</tr>'."\n";;
1.347 albertel 6748: }
1.367 www 6749:
1.421 albertel 6750: sub start_data_table_empty_row {
1.707 bisitz 6751: # $row_count[0]++;
1.421 albertel 6752: return '<tr class="LC_empty_row" >'."\n";;
6753: }
6754:
6755: sub end_data_table_empty_row {
6756: return '</tr>'."\n";;
6757: }
6758:
1.367 www 6759: sub start_data_table_header_row {
1.389 albertel 6760: return '<tr class="LC_header_row">'."\n";;
1.367 www 6761: }
6762:
6763: sub end_data_table_header_row {
1.389 albertel 6764: return '</tr>'."\n";;
1.367 www 6765: }
1.347 albertel 6766: }
6767:
1.548 albertel 6768: =pod
6769:
6770: =item * &inhibit_menu_check($arg)
6771:
6772: Checks for a inhibitmenu state and generates output to preserve it
6773:
6774: Inputs: $arg - can be any of
6775: - undef - in which case the return value is a string
6776: to add into arguments list of a uri
6777: - 'input' - in which case the return value is a HTML
6778: <form> <input> field of type hidden to
6779: preserve the value
6780: - a url - in which case the return value is the url with
6781: the neccesary cgi args added to preserve the
6782: inhibitmenu state
6783: - a ref to a url - no return value, but the string is
6784: updated to include the neccessary cgi
6785: args to preserve the inhibitmenu state
6786:
6787: =cut
6788:
6789: sub inhibit_menu_check {
6790: my ($arg) = @_;
6791: &get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['inhibitmenu']);
6792: if ($arg eq 'input') {
6793: if ($env{'form.inhibitmenu'}) {
6794: return '<input type="hidden" name="inhibitmenu" value="'.$env{'form.inhibitmenu'}.'" />';
6795: } else {
6796: return
6797: }
6798: }
6799: if ($env{'form.inhibitmenu'}) {
6800: if (ref($arg)) {
6801: $$arg .= '?inhibitmenu='.$env{'form.inhibitmenu'};
6802: } elsif ($arg eq '') {
6803: $arg .= 'inhibitmenu='.$env{'form.inhibitmenu'};
6804: } else {
6805: $arg .= '?inhibitmenu='.$env{'form.inhibitmenu'};
6806: }
6807: }
6808: if (!ref($arg)) {
6809: return $arg;
6810: }
6811: }
6812:
1.251 albertel 6813: ###############################################
1.182 matthew 6814:
6815: =pod
6816:
1.549 albertel 6817: =back
6818:
6819: =head1 User Information Routines
6820:
6821: =over 4
6822:
1.405 albertel 6823: =item * &get_users_function()
1.182 matthew 6824:
6825: Used by &bodytag to determine the current users primary role.
6826: Returns either 'student','coordinator','admin', or 'author'.
6827:
6828: =cut
6829:
6830: ###############################################
6831: sub get_users_function {
1.815 tempelho 6832: my $function = 'norole';
1.818 tempelho 6833: if ($env{'request.role'}=~/^(st)/) {
6834: $function='student';
6835: }
1.258 albertel 6836: if ($env{'request.role'}=~/^(cc|in|ta|ep)/) {
1.182 matthew 6837: $function='coordinator';
6838: }
1.258 albertel 6839: if ($env{'request.role'}=~/^(su|dc|ad|li)/) {
1.182 matthew 6840: $function='admin';
6841: }
1.826 bisitz 6842: if (($env{'request.role'}=~/^(au|ca|aa)/) ||
1.182 matthew 6843: ($ENV{'REQUEST_URI'}=~/^(\/priv|\~)/)) {
6844: $function='author';
6845: }
6846: return $function;
1.54 www 6847: }
1.99 www 6848:
6849: ###############################################
6850:
1.233 raeburn 6851: =pod
6852:
1.821 raeburn 6853: =item * &show_course()
6854:
6855: Used by lonmenu.pm and lonroles.pm to determine whether to use the word
6856: 'Courses' or 'Roles' in inline navigation and on screen displaying user's roles.
6857:
6858: Inputs:
6859: None
6860:
6861: Outputs:
6862: Scalar: 1 if 'Course' to be used, 0 otherwise.
6863:
6864: =cut
6865:
6866: ###############################################
6867: sub show_course {
6868: my $course = !$env{'user.adv'};
6869: if (!$env{'user.adv'}) {
6870: foreach my $env (keys(%env)) {
6871: next if ($env !~ m/^user\.priv\./);
6872: if ($env !~ m/^user\.priv\.(?:st|cm)/) {
6873: $course = 0;
6874: last;
6875: }
6876: }
6877: }
6878: return $course;
6879: }
6880:
6881: ###############################################
6882:
6883: =pod
6884:
1.542 raeburn 6885: =item * &check_user_status()
1.274 raeburn 6886:
6887: Determines current status of supplied role for a
6888: specific user. Roles can be active, previous or future.
6889:
6890: Inputs:
6891: user's domain, user's username, course's domain,
1.375 raeburn 6892: course's number, optional section ID.
1.274 raeburn 6893:
6894: Outputs:
6895: role status: active, previous or future.
6896:
6897: =cut
6898:
6899: sub check_user_status {
1.412 raeburn 6900: my ($udom,$uname,$cdom,$crs,$role,$sec) = @_;
1.274 raeburn 6901: my %userinfo = &Apache::lonnet::dump('roles',$udom,$uname);
6902: my @uroles = keys %userinfo;
6903: my $srchstr;
6904: my $active_chk = 'none';
1.412 raeburn 6905: my $now = time;
1.274 raeburn 6906: if (@uroles > 0) {
1.412 raeburn 6907: if (($role eq 'cc') || ($sec eq '') || (!defined($sec))) {
1.274 raeburn 6908: $srchstr = '/'.$cdom.'/'.$crs.'_'.$role;
6909: } else {
1.412 raeburn 6910: $srchstr = '/'.$cdom.'/'.$crs.'/'.$sec.'_'.$role;
6911: }
6912: if (grep/^\Q$srchstr\E$/,@uroles) {
1.274 raeburn 6913: my $role_end = 0;
6914: my $role_start = 0;
6915: $active_chk = 'active';
1.412 raeburn 6916: if ($userinfo{$srchstr} =~ m/^\Q$role\E_(\d+)/) {
6917: $role_end = $1;
6918: if ($userinfo{$srchstr} =~ m/^\Q$role\E_\Q$role_end\E_(\d+)$/) {
6919: $role_start = $1;
1.274 raeburn 6920: }
6921: }
6922: if ($role_start > 0) {
1.412 raeburn 6923: if ($now < $role_start) {
1.274 raeburn 6924: $active_chk = 'future';
6925: }
6926: }
6927: if ($role_end > 0) {
1.412 raeburn 6928: if ($now > $role_end) {
1.274 raeburn 6929: $active_chk = 'previous';
6930: }
6931: }
6932: }
6933: }
6934: return $active_chk;
6935: }
6936:
6937: ###############################################
6938:
6939: =pod
6940:
1.405 albertel 6941: =item * &get_sections()
1.233 raeburn 6942:
6943: Determines all the sections for a course including
6944: sections with students and sections containing other roles.
1.419 raeburn 6945: Incoming parameters:
6946:
6947: 1. domain
6948: 2. course number
6949: 3. reference to array containing roles for which sections should
6950: be gathered (optional).
6951: 4. reference to array containing status types for which sections
6952: should be gathered (optional).
6953:
6954: If the third argument is undefined, sections are gathered for any role.
6955: If the fourth argument is undefined, sections are gathered for any status.
6956: Permissible values are 'active' or 'future' or 'previous'.
1.233 raeburn 6957:
1.374 raeburn 6958: Returns section hash (keys are section IDs, values are
6959: number of users in each section), subject to the
1.419 raeburn 6960: optional roles filter, optional status filter
1.233 raeburn 6961:
6962: =cut
6963:
6964: ###############################################
6965: sub get_sections {
1.419 raeburn 6966: my ($cdom,$cnum,$possible_roles,$possible_status) = @_;
1.366 albertel 6967: if (!defined($cdom) || !defined($cnum)) {
6968: my $cid = $env{'request.course.id'};
6969:
6970: return if (!defined($cid));
6971:
6972: $cdom = $env{'course.'.$cid.'.domain'};
6973: $cnum = $env{'course.'.$cid.'.num'};
6974: }
6975:
6976: my %sectioncount;
1.419 raeburn 6977: my $now = time;
1.240 albertel 6978:
1.366 albertel 6979: if (!defined($possible_roles) || (grep(/^st$/,@$possible_roles))) {
1.276 albertel 6980: my ($classlist) = &Apache::loncoursedata::get_classlist($cdom,$cnum);
1.240 albertel 6981: my $sec_index = &Apache::loncoursedata::CL_SECTION();
6982: my $status_index = &Apache::loncoursedata::CL_STATUS();
1.419 raeburn 6983: my $start_index = &Apache::loncoursedata::CL_START();
6984: my $end_index = &Apache::loncoursedata::CL_END();
6985: my $status;
1.366 albertel 6986: while (my ($student,$data) = each(%$classlist)) {
1.419 raeburn 6987: my ($section,$stu_status,$start,$end) = ($data->[$sec_index],
6988: $data->[$status_index],
6989: $data->[$start_index],
6990: $data->[$end_index]);
6991: if ($stu_status eq 'Active') {
6992: $status = 'active';
6993: } elsif ($end < $now) {
6994: $status = 'previous';
6995: } elsif ($start > $now) {
6996: $status = 'future';
6997: }
6998: if ($section ne '-1' && $section !~ /^\s*$/) {
6999: if ((!defined($possible_status)) || (($status ne '') &&
7000: (grep/^\Q$status\E$/,@{$possible_status}))) {
7001: $sectioncount{$section}++;
7002: }
1.240 albertel 7003: }
7004: }
7005: }
7006: my %courseroles = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
7007: foreach my $user (sort(keys(%courseroles))) {
7008: if ($user !~ /^(\w{2})/) { next; }
7009: my ($role) = ($user =~ /^(\w{2})/);
7010: if ($possible_roles && !(grep(/^$role$/,@$possible_roles))) { next; }
1.419 raeburn 7011: my ($section,$status);
1.240 albertel 7012: if ($role eq 'cr' &&
7013: $user =~ m-^$role/[^/]*/[^/]*/[^/]*:[^:]*:[^:]*:(\w+)-) {
7014: $section=$1;
7015: }
7016: if ($user =~ /^$role:[^:]*:[^:]*:(\w+)/) { $section=$1; }
7017: if (!defined($section) || $section eq '-1') { next; }
1.419 raeburn 7018: my ($end,$start) = ($courseroles{$user} =~ /^([^:]*):([^:]*)$/);
7019: if ($end == -1 && $start == -1) {
7020: next; #deleted role
7021: }
7022: if (!defined($possible_status)) {
7023: $sectioncount{$section}++;
7024: } else {
7025: if ((!$end || $end >= $now) && (!$start || $start <= $now)) {
7026: $status = 'active';
7027: } elsif ($end < $now) {
7028: $status = 'future';
7029: } elsif ($start > $now) {
7030: $status = 'previous';
7031: }
7032: if (($status ne '') && (grep/^\Q$status\E$/,@{$possible_status})) {
7033: $sectioncount{$section}++;
7034: }
7035: }
1.233 raeburn 7036: }
1.366 albertel 7037: return %sectioncount;
1.233 raeburn 7038: }
7039:
1.274 raeburn 7040: ###############################################
1.294 raeburn 7041:
7042: =pod
1.405 albertel 7043:
7044: =item * &get_course_users()
7045:
1.275 raeburn 7046: Retrieves usernames:domains for users in the specified course
7047: with specific role(s), and access status.
7048:
7049: Incoming parameters:
1.277 albertel 7050: 1. course domain
7051: 2. course number
7052: 3. access status: users must have - either active,
1.275 raeburn 7053: previous, future, or all.
1.277 albertel 7054: 4. reference to array of permissible roles
1.288 raeburn 7055: 5. reference to array of section restrictions (optional)
7056: 6. reference to results object (hash of hashes).
7057: 7. reference to optional userdata hash
1.609 raeburn 7058: 8. reference to optional statushash
1.630 raeburn 7059: 9. flag if privileged users (except those set to unhide in
7060: course settings) should be excluded
1.609 raeburn 7061: Keys of top level results hash are roles.
1.275 raeburn 7062: Keys of inner hashes are username:domain, with
7063: values set to access type.
1.288 raeburn 7064: Optional userdata hash returns an array with arguments in the
7065: same order as loncoursedata::get_classlist() for student data.
7066:
1.609 raeburn 7067: Optional statushash returns
7068:
1.288 raeburn 7069: Entries for end, start, section and status are blank because
7070: of the possibility of multiple values for non-student roles.
7071:
1.275 raeburn 7072: =cut
1.405 albertel 7073:
1.275 raeburn 7074: ###############################################
1.405 albertel 7075:
1.275 raeburn 7076: sub get_course_users {
1.630 raeburn 7077: my ($cdom,$cnum,$types,$roles,$sections,$users,$userdata,$statushash,$hidepriv) = @_;
1.288 raeburn 7078: my %idx = ();
1.419 raeburn 7079: my %seclists;
1.288 raeburn 7080:
7081: $idx{udom} = &Apache::loncoursedata::CL_SDOM();
7082: $idx{uname} = &Apache::loncoursedata::CL_SNAME();
7083: $idx{end} = &Apache::loncoursedata::CL_END();
7084: $idx{start} = &Apache::loncoursedata::CL_START();
7085: $idx{id} = &Apache::loncoursedata::CL_ID();
7086: $idx{section} = &Apache::loncoursedata::CL_SECTION();
7087: $idx{fullname} = &Apache::loncoursedata::CL_FULLNAME();
7088: $idx{status} = &Apache::loncoursedata::CL_STATUS();
7089:
1.290 albertel 7090: if (grep(/^st$/,@{$roles})) {
1.276 albertel 7091: my ($classlist,$keylist)=&Apache::loncoursedata::get_classlist($cdom,$cnum);
1.278 raeburn 7092: my $now = time;
1.277 albertel 7093: foreach my $student (keys(%{$classlist})) {
1.288 raeburn 7094: my $match = 0;
1.412 raeburn 7095: my $secmatch = 0;
1.419 raeburn 7096: my $section = $$classlist{$student}[$idx{section}];
1.609 raeburn 7097: my $status = $$classlist{$student}[$idx{status}];
1.419 raeburn 7098: if ($section eq '') {
7099: $section = 'none';
7100: }
1.291 albertel 7101: if ((ref($sections) eq 'ARRAY') && (@{$sections} > 0)) {
1.420 albertel 7102: if (grep(/^all$/,@{$sections})) {
1.412 raeburn 7103: $secmatch = 1;
7104: } elsif ($$classlist{$student}[$idx{section}] eq '') {
1.420 albertel 7105: if (grep(/^none$/,@{$sections})) {
1.412 raeburn 7106: $secmatch = 1;
7107: }
7108: } else {
1.419 raeburn 7109: if (grep(/^\Q$section\E$/,@{$sections})) {
1.412 raeburn 7110: $secmatch = 1;
7111: }
1.290 albertel 7112: }
1.412 raeburn 7113: if (!$secmatch) {
7114: next;
7115: }
1.419 raeburn 7116: }
1.275 raeburn 7117: if (defined($$types{'active'})) {
1.288 raeburn 7118: if ($$classlist{$student}[$idx{status}] eq 'Active') {
1.275 raeburn 7119: push(@{$$users{st}{$student}},'active');
1.288 raeburn 7120: $match = 1;
1.275 raeburn 7121: }
7122: }
7123: if (defined($$types{'previous'})) {
1.609 raeburn 7124: if ($$classlist{$student}[$idx{status}] eq 'Expired') {
1.275 raeburn 7125: push(@{$$users{st}{$student}},'previous');
1.288 raeburn 7126: $match = 1;
1.275 raeburn 7127: }
7128: }
7129: if (defined($$types{'future'})) {
1.609 raeburn 7130: if ($$classlist{$student}[$idx{status}] eq 'Future') {
1.275 raeburn 7131: push(@{$$users{st}{$student}},'future');
1.288 raeburn 7132: $match = 1;
1.275 raeburn 7133: }
7134: }
1.609 raeburn 7135: if ($match) {
7136: push(@{$seclists{$student}},$section);
7137: if (ref($userdata) eq 'HASH') {
7138: $$userdata{$student} = $$classlist{$student};
7139: }
7140: if (ref($statushash) eq 'HASH') {
7141: $statushash->{$student}{'st'}{$section} = $status;
7142: }
1.288 raeburn 7143: }
1.275 raeburn 7144: }
7145: }
1.412 raeburn 7146: if ((@{$roles} > 1) || ((@{$roles} == 1) && ($$roles[0] ne "st"))) {
1.439 raeburn 7147: my %coursepersonnel = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
7148: my $now = time;
1.609 raeburn 7149: my %displaystatus = ( previous => 'Expired',
7150: active => 'Active',
7151: future => 'Future',
7152: );
1.630 raeburn 7153: my %nothide;
7154: if ($hidepriv) {
7155: my %coursehash=&Apache::lonnet::coursedescription($cdom.'_'.$cnum);
7156: foreach my $user (split(/\s*\,\s*/,$coursehash{'nothideprivileged'})) {
7157: if ($user !~ /:/) {
7158: $nothide{join(':',split(/[\@]/,$user))}=1;
7159: } else {
7160: $nothide{$user} = 1;
7161: }
7162: }
7163: }
1.439 raeburn 7164: foreach my $person (sort(keys(%coursepersonnel))) {
1.288 raeburn 7165: my $match = 0;
1.412 raeburn 7166: my $secmatch = 0;
1.439 raeburn 7167: my $status;
1.412 raeburn 7168: my ($role,$user,$usec) = ($person =~ /^([^:]*):([^:]+:[^:]+):([^:]*)/);
1.275 raeburn 7169: $user =~ s/:$//;
1.439 raeburn 7170: my ($end,$start) = split(/:/,$coursepersonnel{$person});
7171: if ($end == -1 || $start == -1) {
7172: next;
7173: }
7174: if (($role) && ((grep(/^\Q$role\E$/,@{$roles})) ||
7175: (grep(/^cr$/,@{$roles}) && $role =~ /^cr\//))) {
1.412 raeburn 7176: my ($uname,$udom) = split(/:/,$user);
7177: if ((ref($sections) eq 'ARRAY') && (@{$sections} > 0)) {
1.420 albertel 7178: if (grep(/^all$/,@{$sections})) {
1.412 raeburn 7179: $secmatch = 1;
7180: } elsif ($usec eq '') {
1.420 albertel 7181: if (grep(/^none$/,@{$sections})) {
1.412 raeburn 7182: $secmatch = 1;
7183: }
7184: } else {
7185: if (grep(/^\Q$usec\E$/,@{$sections})) {
7186: $secmatch = 1;
7187: }
7188: }
7189: if (!$secmatch) {
7190: next;
7191: }
1.288 raeburn 7192: }
1.419 raeburn 7193: if ($usec eq '') {
7194: $usec = 'none';
7195: }
1.275 raeburn 7196: if ($uname ne '' && $udom ne '') {
1.630 raeburn 7197: if ($hidepriv) {
7198: if ((&Apache::lonnet::privileged($uname,$udom)) &&
7199: (!$nothide{$uname.':'.$udom})) {
7200: next;
7201: }
7202: }
1.503 raeburn 7203: if ($end > 0 && $end < $now) {
1.439 raeburn 7204: $status = 'previous';
7205: } elsif ($start > $now) {
7206: $status = 'future';
7207: } else {
7208: $status = 'active';
7209: }
1.277 albertel 7210: foreach my $type (keys(%{$types})) {
1.275 raeburn 7211: if ($status eq $type) {
1.420 albertel 7212: if (!grep(/^\Q$type\E$/,@{$$users{$role}{$user}})) {
1.419 raeburn 7213: push(@{$$users{$role}{$user}},$type);
7214: }
1.288 raeburn 7215: $match = 1;
7216: }
7217: }
1.419 raeburn 7218: if (($match) && (ref($userdata) eq 'HASH')) {
7219: if (!exists($$userdata{$uname.':'.$udom})) {
7220: &get_user_info($udom,$uname,\%idx,$userdata);
7221: }
1.420 albertel 7222: if (!grep(/^\Q$usec\E$/,@{$seclists{$uname.':'.$udom}})) {
1.419 raeburn 7223: push(@{$seclists{$uname.':'.$udom}},$usec);
7224: }
1.609 raeburn 7225: if (ref($statushash) eq 'HASH') {
7226: $statushash->{$uname.':'.$udom}{$role}{$usec} = $displaystatus{$status};
7227: }
1.275 raeburn 7228: }
7229: }
7230: }
7231: }
1.290 albertel 7232: if (grep(/^ow$/,@{$roles})) {
1.279 raeburn 7233: if ((defined($cdom)) && (defined($cnum))) {
7234: my %csettings = &Apache::lonnet::get('environment',['internal.courseowner'],$cdom,$cnum);
7235: if ( defined($csettings{'internal.courseowner'}) ) {
7236: my $owner = $csettings{'internal.courseowner'};
1.609 raeburn 7237: next if ($owner eq '');
7238: my ($ownername,$ownerdom);
7239: if ($owner =~ /^([^:]+):([^:]+)$/) {
7240: $ownername = $1;
7241: $ownerdom = $2;
7242: } else {
7243: $ownername = $owner;
7244: $ownerdom = $cdom;
7245: $owner = $ownername.':'.$ownerdom;
1.439 raeburn 7246: }
7247: @{$$users{'ow'}{$owner}} = 'any';
1.290 albertel 7248: if (defined($userdata) &&
1.609 raeburn 7249: !exists($$userdata{$owner})) {
7250: &get_user_info($ownerdom,$ownername,\%idx,$userdata);
7251: if (!grep(/^none$/,@{$seclists{$owner}})) {
7252: push(@{$seclists{$owner}},'none');
7253: }
7254: if (ref($statushash) eq 'HASH') {
7255: $statushash->{$owner}{'ow'}{'none'} = 'Any';
1.419 raeburn 7256: }
1.290 albertel 7257: }
1.279 raeburn 7258: }
7259: }
7260: }
1.419 raeburn 7261: foreach my $user (keys(%seclists)) {
7262: @{$seclists{$user}} = (sort {$a <=> $b} @{$seclists{$user}});
7263: $$userdata{$user}[$idx{section}] = join(',',@{$seclists{$user}});
7264: }
1.275 raeburn 7265: }
7266: return;
7267: }
7268:
1.288 raeburn 7269: sub get_user_info {
7270: my ($udom,$uname,$idx,$userdata) = @_;
1.289 albertel 7271: $$userdata{$uname.':'.$udom}[$$idx{fullname}] =
7272: &plainname($uname,$udom,'lastname');
1.291 albertel 7273: $$userdata{$uname.':'.$udom}[$$idx{uname}] = $uname;
1.297 raeburn 7274: $$userdata{$uname.':'.$udom}[$$idx{udom}] = $udom;
1.609 raeburn 7275: my %idhash = &Apache::lonnet::idrget($udom,($uname));
7276: $$userdata{$uname.':'.$udom}[$$idx{id}] = $idhash{$uname};
1.288 raeburn 7277: return;
7278: }
1.275 raeburn 7279:
1.472 raeburn 7280: ###############################################
7281:
7282: =pod
7283:
7284: =item * &get_user_quota()
7285:
7286: Retrieves quota assigned for storage of portfolio files for a user
7287:
7288: Incoming parameters:
7289: 1. user's username
7290: 2. user's domain
7291:
7292: Returns:
1.536 raeburn 7293: 1. Disk quota (in Mb) assigned to student.
7294: 2. (Optional) Type of setting: custom or default
7295: (individually assigned or default for user's
7296: institutional status).
7297: 3. (Optional) - User's institutional status (e.g., faculty, staff
7298: or student - types as defined in localenroll::inst_usertypes
7299: for user's domain, which determines default quota for user.
7300: 4. (Optional) - Default quota which would apply to the user.
1.472 raeburn 7301:
7302: If a value has been stored in the user's environment,
1.536 raeburn 7303: it will return that, otherwise it returns the maximal default
7304: defined for the user's instituional status(es) in the domain.
1.472 raeburn 7305:
7306: =cut
7307:
7308: ###############################################
7309:
7310:
7311: sub get_user_quota {
7312: my ($uname,$udom) = @_;
1.536 raeburn 7313: my ($quota,$quotatype,$settingstatus,$defquota);
1.472 raeburn 7314: if (!defined($udom)) {
7315: $udom = $env{'user.domain'};
7316: }
7317: if (!defined($uname)) {
7318: $uname = $env{'user.name'};
7319: }
7320: if (($udom eq '' || $uname eq '') ||
7321: ($udom eq 'public') && ($uname eq 'public')) {
7322: $quota = 0;
1.536 raeburn 7323: $quotatype = 'default';
7324: $defquota = 0;
1.472 raeburn 7325: } else {
1.536 raeburn 7326: my $inststatus;
1.472 raeburn 7327: if ($udom eq $env{'user.domain'} && $uname eq $env{'user.name'}) {
7328: $quota = $env{'environment.portfolioquota'};
1.536 raeburn 7329: $inststatus = $env{'environment.inststatus'};
1.472 raeburn 7330: } else {
1.536 raeburn 7331: my %userenv =
7332: &Apache::lonnet::get('environment',['portfolioquota',
7333: 'inststatus'],$udom,$uname);
1.472 raeburn 7334: my ($tmp) = keys(%userenv);
7335: if ($tmp !~ /^(con_lost|error|no_such_host)/i) {
7336: $quota = $userenv{'portfolioquota'};
1.536 raeburn 7337: $inststatus = $userenv{'inststatus'};
1.472 raeburn 7338: } else {
7339: undef(%userenv);
7340: }
7341: }
1.536 raeburn 7342: ($defquota,$settingstatus) = &default_quota($udom,$inststatus);
1.472 raeburn 7343: if ($quota eq '') {
1.536 raeburn 7344: $quota = $defquota;
7345: $quotatype = 'default';
7346: } else {
7347: $quotatype = 'custom';
1.472 raeburn 7348: }
7349: }
1.536 raeburn 7350: if (wantarray) {
7351: return ($quota,$quotatype,$settingstatus,$defquota);
7352: } else {
7353: return $quota;
7354: }
1.472 raeburn 7355: }
7356:
7357: ###############################################
7358:
7359: =pod
7360:
7361: =item * &default_quota()
7362:
1.536 raeburn 7363: Retrieves default quota assigned for storage of user portfolio files,
7364: given an (optional) user's institutional status.
1.472 raeburn 7365:
7366: Incoming parameters:
7367: 1. domain
1.536 raeburn 7368: 2. (Optional) institutional status(es). This is a : separated list of
7369: status types (e.g., faculty, staff, student etc.)
7370: which apply to the user for whom the default is being retrieved.
7371: If the institutional status string in undefined, the domain
7372: default quota will be returned.
1.472 raeburn 7373:
7374: Returns:
7375: 1. Default disk quota (in Mb) for user portfolios in the domain.
1.536 raeburn 7376: 2. (Optional) institutional type which determined the value of the
7377: default quota.
1.472 raeburn 7378:
7379: If a value has been stored in the domain's configuration db,
7380: it will return that, otherwise it returns 20 (for backwards
7381: compatibility with domains which have not set up a configuration
7382: db file; the original statically defined portfolio quota was 20 Mb).
7383:
1.536 raeburn 7384: If the user's status includes multiple types (e.g., staff and student),
7385: the largest default quota which applies to the user determines the
7386: default quota returned.
7387:
1.780 raeburn 7388: =back
7389:
1.472 raeburn 7390: =cut
7391:
7392: ###############################################
7393:
7394:
7395: sub default_quota {
1.536 raeburn 7396: my ($udom,$inststatus) = @_;
7397: my ($defquota,$settingstatus);
7398: my %quotahash = &Apache::lonnet::get_dom('configuration',
1.622 raeburn 7399: ['quotas'],$udom);
7400: if (ref($quotahash{'quotas'}) eq 'HASH') {
1.536 raeburn 7401: if ($inststatus ne '') {
1.765 raeburn 7402: my @statuses = map { &unescape($_); } split(/:/,$inststatus);
1.536 raeburn 7403: foreach my $item (@statuses) {
1.711 raeburn 7404: if (ref($quotahash{'quotas'}{'defaultquota'}) eq 'HASH') {
7405: if ($quotahash{'quotas'}{'defaultquota'}{$item} ne '') {
7406: if ($defquota eq '') {
7407: $defquota = $quotahash{'quotas'}{'defaultquota'}{$item};
7408: $settingstatus = $item;
7409: } elsif ($quotahash{'quotas'}{'defaultquota'}{$item} > $defquota) {
7410: $defquota = $quotahash{'quotas'}{'defaultquota'}{$item};
7411: $settingstatus = $item;
7412: }
7413: }
7414: } else {
7415: if ($quotahash{'quotas'}{$item} ne '') {
7416: if ($defquota eq '') {
7417: $defquota = $quotahash{'quotas'}{$item};
7418: $settingstatus = $item;
7419: } elsif ($quotahash{'quotas'}{$item} > $defquota) {
7420: $defquota = $quotahash{'quotas'}{$item};
7421: $settingstatus = $item;
7422: }
1.536 raeburn 7423: }
7424: }
7425: }
7426: }
7427: if ($defquota eq '') {
1.711 raeburn 7428: if (ref($quotahash{'quotas'}{'defaultquota'}) eq 'HASH') {
7429: $defquota = $quotahash{'quotas'}{'defaultquota'}{'default'};
7430: } else {
7431: $defquota = $quotahash{'quotas'}{'default'};
7432: }
1.536 raeburn 7433: $settingstatus = 'default';
7434: }
7435: } else {
7436: $settingstatus = 'default';
7437: $defquota = 20;
7438: }
7439: if (wantarray) {
7440: return ($defquota,$settingstatus);
1.472 raeburn 7441: } else {
1.536 raeburn 7442: return $defquota;
1.472 raeburn 7443: }
7444: }
7445:
1.384 raeburn 7446: sub get_secgrprole_info {
7447: my ($cdom,$cnum,$needroles,$type) = @_;
7448: my %sections_count = &get_sections($cdom,$cnum);
7449: my @sections = (sort {$a <=> $b} keys(%sections_count));
7450: my %curr_groups = &Apache::longroup::coursegroups($cdom,$cnum);
7451: my @groups = sort(keys(%curr_groups));
7452: my $allroles = [];
7453: my $rolehash;
7454: my $accesshash = {
7455: active => 'Currently has access',
7456: future => 'Will have future access',
7457: previous => 'Previously had access',
7458: };
7459: if ($needroles) {
7460: $rolehash = {'all' => 'all'};
1.385 albertel 7461: my %user_roles = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
7462: if (&Apache::lonnet::error(%user_roles)) {
7463: undef(%user_roles);
7464: }
7465: foreach my $item (keys(%user_roles)) {
1.384 raeburn 7466: my ($role)=split(/\:/,$item,2);
7467: if ($role eq 'cr') { next; }
7468: if ($role =~ /^cr/) {
7469: $$rolehash{$role} = (split('/',$role))[3];
7470: } else {
7471: $$rolehash{$role} = &Apache::lonnet::plaintext($role,$type);
7472: }
7473: }
7474: foreach my $key (sort(keys(%{$rolehash}))) {
7475: push(@{$allroles},$key);
7476: }
7477: push (@{$allroles},'st');
7478: $$rolehash{'st'} = &Apache::lonnet::plaintext('st',$type);
7479: }
7480: return (\@sections,\@groups,$allroles,$rolehash,$accesshash);
7481: }
7482:
1.555 raeburn 7483: sub user_picker {
1.627 raeburn 7484: my ($dom,$srch,$forcenewuser,$caller,$cancreate,$usertype) = @_;
1.555 raeburn 7485: my $currdom = $dom;
7486: my %curr_selected = (
7487: srchin => 'dom',
1.580 raeburn 7488: srchby => 'lastname',
1.555 raeburn 7489: );
7490: my $srchterm;
1.625 raeburn 7491: if ((ref($srch) eq 'HASH') && ($env{'form.origform'} ne 'crtusername')) {
1.555 raeburn 7492: if ($srch->{'srchby'} ne '') {
7493: $curr_selected{'srchby'} = $srch->{'srchby'};
7494: }
7495: if ($srch->{'srchin'} ne '') {
7496: $curr_selected{'srchin'} = $srch->{'srchin'};
7497: }
7498: if ($srch->{'srchtype'} ne '') {
7499: $curr_selected{'srchtype'} = $srch->{'srchtype'};
7500: }
7501: if ($srch->{'srchdomain'} ne '') {
7502: $currdom = $srch->{'srchdomain'};
7503: }
7504: $srchterm = $srch->{'srchterm'};
7505: }
7506: my %lt=&Apache::lonlocal::texthash(
1.573 raeburn 7507: 'usr' => 'Search criteria',
1.563 raeburn 7508: 'doma' => 'Domain/institution to search',
1.558 albertel 7509: 'uname' => 'username',
7510: 'lastname' => 'last name',
1.555 raeburn 7511: 'lastfirst' => 'last name, first name',
1.558 albertel 7512: 'crs' => 'in this course',
1.576 raeburn 7513: 'dom' => 'in selected LON-CAPA domain',
1.558 albertel 7514: 'alc' => 'all LON-CAPA',
1.573 raeburn 7515: 'instd' => 'in institutional directory for selected domain',
1.558 albertel 7516: 'exact' => 'is',
7517: 'contains' => 'contains',
1.569 raeburn 7518: 'begins' => 'begins with',
1.571 raeburn 7519: 'youm' => "You must include some text to search for.",
7520: 'thte' => "The text you are searching for must contain at least two characters when using a 'begins' type search.",
7521: 'thet' => "The text you are searching for must contain at least three characters when using a 'contains' type search.",
7522: 'yomc' => "You must choose a domain when using an institutional directory search.",
7523: 'ymcd' => "You must choose a domain when using a domain search.",
7524: 'whus' => "When using searching by last,first you must include a comma as separator between last name and first name.",
7525: 'whse' => "When searching by last,first you must include at least one character in the first name.",
7526: 'thfo' => "The following need to be corrected before the search can be run:",
1.555 raeburn 7527: );
1.563 raeburn 7528: my $domform = &select_dom_form($currdom,'srchdomain',1,1);
7529: my $srchinsel = ' <select name="srchin">';
1.555 raeburn 7530:
7531: my @srchins = ('crs','dom','alc','instd');
7532:
7533: foreach my $option (@srchins) {
7534: # FIXME 'alc' option unavailable until
7535: # loncreateuser::print_user_query_page()
7536: # has been completed.
7537: next if ($option eq 'alc');
1.880 raeburn 7538: next if (($option eq 'crs') && ($env{'form.form'} eq 'requestcrs'));
1.555 raeburn 7539: next if ($option eq 'crs' && !$env{'request.course.id'});
1.563 raeburn 7540: if ($curr_selected{'srchin'} eq $option) {
7541: $srchinsel .= '
7542: <option value="'.$option.'" selected="selected">'.$lt{$option}.'</option>';
7543: } else {
7544: $srchinsel .= '
7545: <option value="'.$option.'">'.$lt{$option}.'</option>';
7546: }
1.555 raeburn 7547: }
1.563 raeburn 7548: $srchinsel .= "\n </select>\n";
1.555 raeburn 7549:
7550: my $srchbysel = ' <select name="srchby">';
1.580 raeburn 7551: foreach my $option ('lastname','lastfirst','uname') {
1.555 raeburn 7552: if ($curr_selected{'srchby'} eq $option) {
7553: $srchbysel .= '
7554: <option value="'.$option.'" selected="selected">'.$lt{$option}.'</option>';
7555: } else {
7556: $srchbysel .= '
7557: <option value="'.$option.'">'.$lt{$option}.'</option>';
7558: }
7559: }
7560: $srchbysel .= "\n </select>\n";
7561:
7562: my $srchtypesel = ' <select name="srchtype">';
1.580 raeburn 7563: foreach my $option ('begins','contains','exact') {
1.555 raeburn 7564: if ($curr_selected{'srchtype'} eq $option) {
7565: $srchtypesel .= '
7566: <option value="'.$option.'" selected="selected">'.$lt{$option}.'</option>';
7567: } else {
7568: $srchtypesel .= '
7569: <option value="'.$option.'">'.$lt{$option}.'</option>';
7570: }
7571: }
7572: $srchtypesel .= "\n </select>\n";
7573:
1.558 albertel 7574: my ($newuserscript,$new_user_create);
1.556 raeburn 7575:
7576: if ($forcenewuser) {
1.576 raeburn 7577: if (ref($srch) eq 'HASH') {
7578: if ($srch->{'srchby'} eq 'uname' && $srch->{'srchtype'} eq 'exact' && $srch->{'srchin'} eq 'dom' && $srch->{'srchdomain'} eq $env{'request.role.domain'}) {
1.627 raeburn 7579: if ($cancreate) {
7580: $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>';
7581: } else {
1.799 bisitz 7582: my $helplink = 'javascript:helpMenu('."'display'".')';
1.627 raeburn 7583: my %usertypetext = (
7584: official => 'institutional',
7585: unofficial => 'non-institutional',
7586: );
1.799 bisitz 7587: $new_user_create = '<p class="LC_warning">'
7588: .&mt("You are not authorized to create new $usertypetext{$usertype} users in this domain.")
7589: .' '
7590: .&mt('Please contact the [_1]helpdesk[_2] for assistance.'
7591: ,'<a href="'.$helplink.'">','</a>')
7592: .'</p><br />';
1.627 raeburn 7593: }
1.576 raeburn 7594: }
7595: }
7596:
1.556 raeburn 7597: $newuserscript = <<"ENDSCRIPT";
7598:
1.570 raeburn 7599: function setSearch(createnew,callingForm) {
1.556 raeburn 7600: if (createnew == 1) {
1.570 raeburn 7601: for (var i=0; i<callingForm.srchby.length; i++) {
7602: if (callingForm.srchby.options[i].value == 'uname') {
7603: callingForm.srchby.selectedIndex = i;
1.556 raeburn 7604: }
7605: }
1.570 raeburn 7606: for (var i=0; i<callingForm.srchin.length; i++) {
7607: if ( callingForm.srchin.options[i].value == 'dom') {
7608: callingForm.srchin.selectedIndex = i;
1.556 raeburn 7609: }
7610: }
1.570 raeburn 7611: for (var i=0; i<callingForm.srchtype.length; i++) {
7612: if (callingForm.srchtype.options[i].value == 'exact') {
7613: callingForm.srchtype.selectedIndex = i;
1.556 raeburn 7614: }
7615: }
1.570 raeburn 7616: for (var i=0; i<callingForm.srchdomain.length; i++) {
7617: if (callingForm.srchdomain.options[i].value == '$env{'request.role.domain'}') {
7618: callingForm.srchdomain.selectedIndex = i;
1.556 raeburn 7619: }
7620: }
7621: }
7622: }
7623: ENDSCRIPT
1.558 albertel 7624:
1.556 raeburn 7625: }
7626:
1.555 raeburn 7627: my $output = <<"END_BLOCK";
1.556 raeburn 7628: <script type="text/javascript">
1.824 bisitz 7629: // <![CDATA[
1.570 raeburn 7630: function validateEntry(callingForm) {
1.558 albertel 7631:
1.556 raeburn 7632: var checkok = 1;
1.558 albertel 7633: var srchin;
1.570 raeburn 7634: for (var i=0; i<callingForm.srchin.length; i++) {
7635: if ( callingForm.srchin[i].checked ) {
7636: srchin = callingForm.srchin[i].value;
1.558 albertel 7637: }
7638: }
7639:
1.570 raeburn 7640: var srchtype = callingForm.srchtype.options[callingForm.srchtype.selectedIndex].value;
7641: var srchby = callingForm.srchby.options[callingForm.srchby.selectedIndex].value;
7642: var srchdomain = callingForm.srchdomain.options[callingForm.srchdomain.selectedIndex].value;
7643: var srchterm = callingForm.srchterm.value;
7644: var srchin = callingForm.srchin.options[callingForm.srchin.selectedIndex].value;
1.556 raeburn 7645: var msg = "";
7646:
7647: if (srchterm == "") {
7648: checkok = 0;
1.571 raeburn 7649: msg += "$lt{'youm'}\\n";
1.556 raeburn 7650: }
7651:
1.569 raeburn 7652: if (srchtype== 'begins') {
7653: if (srchterm.length < 2) {
7654: checkok = 0;
1.571 raeburn 7655: msg += "$lt{'thte'}\\n";
1.569 raeburn 7656: }
7657: }
7658:
1.556 raeburn 7659: if (srchtype== 'contains') {
7660: if (srchterm.length < 3) {
7661: checkok = 0;
1.571 raeburn 7662: msg += "$lt{'thet'}\\n";
1.556 raeburn 7663: }
7664: }
7665: if (srchin == 'instd') {
7666: if (srchdomain == '') {
7667: checkok = 0;
1.571 raeburn 7668: msg += "$lt{'yomc'}\\n";
1.556 raeburn 7669: }
7670: }
7671: if (srchin == 'dom') {
7672: if (srchdomain == '') {
7673: checkok = 0;
1.571 raeburn 7674: msg += "$lt{'ymcd'}\\n";
1.556 raeburn 7675: }
7676: }
7677: if (srchby == 'lastfirst') {
7678: if (srchterm.indexOf(",") == -1) {
7679: checkok = 0;
1.571 raeburn 7680: msg += "$lt{'whus'}\\n";
1.556 raeburn 7681: }
7682: if (srchterm.indexOf(",") == srchterm.length -1) {
7683: checkok = 0;
1.571 raeburn 7684: msg += "$lt{'whse'}\\n";
1.556 raeburn 7685: }
7686: }
7687: if (checkok == 0) {
1.571 raeburn 7688: alert("$lt{'thfo'}\\n"+msg);
1.556 raeburn 7689: return;
7690: }
7691: if (checkok == 1) {
1.570 raeburn 7692: callingForm.submit();
1.556 raeburn 7693: }
7694: }
7695:
7696: $newuserscript
7697:
1.824 bisitz 7698: // ]]>
1.556 raeburn 7699: </script>
1.558 albertel 7700:
7701: $new_user_create
7702:
1.555 raeburn 7703: END_BLOCK
1.558 albertel 7704:
1.876 raeburn 7705: $output .= &Apache::lonhtmlcommon::start_pick_box().
7706: &Apache::lonhtmlcommon::row_title($lt{'doma'}).
7707: $domform.
7708: &Apache::lonhtmlcommon::row_closure().
7709: &Apache::lonhtmlcommon::row_title($lt{'usr'}).
7710: $srchbysel.
7711: $srchtypesel.
7712: '<input type="text" size="15" name="srchterm" value="'.$srchterm.'" />'.
7713: $srchinsel.
7714: &Apache::lonhtmlcommon::row_closure(1).
7715: &Apache::lonhtmlcommon::end_pick_box().
7716: '<br />';
1.555 raeburn 7717: return $output;
7718: }
7719:
1.612 raeburn 7720: sub user_rule_check {
1.615 raeburn 7721: my ($usershash,$checks,$alerts,$rulematch,$inst_results,$curr_rules,$got_rules) = @_;
1.612 raeburn 7722: my $response;
7723: if (ref($usershash) eq 'HASH') {
7724: foreach my $user (keys(%{$usershash})) {
7725: my ($uname,$udom) = split(/:/,$user);
7726: next if ($udom eq '' || $uname eq '');
1.615 raeburn 7727: my ($id,$newuser);
1.612 raeburn 7728: if (ref($usershash->{$user}) eq 'HASH') {
1.615 raeburn 7729: $newuser = $usershash->{$user}->{'newuser'};
1.612 raeburn 7730: $id = $usershash->{$user}->{'id'};
7731: }
7732: my $inst_response;
7733: if (ref($checks) eq 'HASH') {
7734: if (defined($checks->{'username'})) {
1.615 raeburn 7735: ($inst_response,%{$inst_results->{$user}}) =
1.612 raeburn 7736: &Apache::lonnet::get_instuser($udom,$uname);
7737: } elsif (defined($checks->{'id'})) {
1.615 raeburn 7738: ($inst_response,%{$inst_results->{$user}}) =
1.612 raeburn 7739: &Apache::lonnet::get_instuser($udom,undef,$id);
7740: }
1.615 raeburn 7741: } else {
7742: ($inst_response,%{$inst_results->{$user}}) =
7743: &Apache::lonnet::get_instuser($udom,$uname);
7744: return;
1.612 raeburn 7745: }
1.615 raeburn 7746: if (!$got_rules->{$udom}) {
1.612 raeburn 7747: my %domconfig = &Apache::lonnet::get_dom('configuration',
7748: ['usercreation'],$udom);
7749: if (ref($domconfig{'usercreation'}) eq 'HASH') {
1.615 raeburn 7750: foreach my $item ('username','id') {
1.612 raeburn 7751: if (ref($domconfig{'usercreation'}{$item.'_rule'}) eq 'ARRAY') {
7752: $$curr_rules{$udom}{$item} =
7753: $domconfig{'usercreation'}{$item.'_rule'};
1.585 raeburn 7754: }
7755: }
7756: }
1.615 raeburn 7757: $got_rules->{$udom} = 1;
1.585 raeburn 7758: }
1.612 raeburn 7759: foreach my $item (keys(%{$checks})) {
7760: if (ref($$curr_rules{$udom}) eq 'HASH') {
7761: if (ref($$curr_rules{$udom}{$item}) eq 'ARRAY') {
7762: if (@{$$curr_rules{$udom}{$item}} > 0) {
7763: my %rule_check = &Apache::lonnet::inst_rulecheck($udom,$uname,$id,$item,$$curr_rules{$udom}{$item});
7764: foreach my $rule (@{$$curr_rules{$udom}{$item}}) {
7765: if ($rule_check{$rule}) {
7766: $$rulematch{$user}{$item} = $rule;
7767: if ($inst_response eq 'ok') {
1.615 raeburn 7768: if (ref($inst_results) eq 'HASH') {
7769: if (ref($inst_results->{$user}) eq 'HASH') {
7770: if (keys(%{$inst_results->{$user}}) == 0) {
7771: $$alerts{$item}{$udom}{$uname} = 1;
7772: }
1.612 raeburn 7773: }
7774: }
1.615 raeburn 7775: }
7776: last;
1.585 raeburn 7777: }
7778: }
7779: }
7780: }
7781: }
7782: }
7783: }
7784: }
1.612 raeburn 7785: return;
7786: }
7787:
7788: sub user_rule_formats {
7789: my ($domain,$domdesc,$curr_rules,$check) = @_;
7790: my %text = (
7791: 'username' => 'Usernames',
7792: 'id' => 'IDs',
7793: );
7794: my $output;
7795: my ($rules,$ruleorder) = &Apache::lonnet::inst_userrules($domain,$check);
7796: if ((ref($rules) eq 'HASH') && (ref($ruleorder) eq 'ARRAY')) {
7797: if (@{$ruleorder} > 0) {
7798: $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>';
7799: foreach my $rule (@{$ruleorder}) {
7800: if (ref($curr_rules) eq 'ARRAY') {
7801: if (grep(/^\Q$rule\E$/,@{$curr_rules})) {
7802: if (ref($rules->{$rule}) eq 'HASH') {
7803: $output .= '<li>'.$rules->{$rule}{'name'}.': '.
7804: $rules->{$rule}{'desc'}.'</li>';
7805: }
7806: }
7807: }
7808: }
7809: $output .= '</ul>';
7810: }
7811: }
7812: return $output;
7813: }
7814:
7815: sub instrule_disallow_msg {
1.615 raeburn 7816: my ($checkitem,$domdesc,$count,$mode) = @_;
1.612 raeburn 7817: my $response;
7818: my %text = (
7819: item => 'username',
7820: items => 'usernames',
7821: match => 'matches',
7822: do => 'does',
7823: action => 'a username',
7824: one => 'one',
7825: );
7826: if ($count > 1) {
7827: $text{'item'} = 'usernames';
7828: $text{'match'} ='match';
7829: $text{'do'} = 'do';
7830: $text{'action'} = 'usernames',
7831: $text{'one'} = 'ones';
7832: }
7833: if ($checkitem eq 'id') {
7834: $text{'items'} = 'IDs';
7835: $text{'item'} = 'ID';
7836: $text{'action'} = 'an ID';
1.615 raeburn 7837: if ($count > 1) {
7838: $text{'item'} = 'IDs';
7839: $text{'action'} = 'IDs';
7840: }
1.612 raeburn 7841: }
1.674 bisitz 7842: $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 7843: if ($mode eq 'upload') {
7844: if ($checkitem eq 'username') {
7845: $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'}.");
7846: } elsif ($checkitem eq 'id') {
1.674 bisitz 7847: $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 7848: }
1.669 raeburn 7849: } elsif ($mode eq 'selfcreate') {
7850: if ($checkitem eq 'id') {
7851: $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.");
7852: }
1.615 raeburn 7853: } else {
7854: if ($checkitem eq 'username') {
7855: $response .= &mt("You must choose $text{'action'} with a different format -- $text{'one'} that will not conflict with 'official' institutional $text{'items'}.");
7856: } elsif ($checkitem eq 'id') {
7857: $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.");
7858: }
1.612 raeburn 7859: }
7860: return $response;
1.585 raeburn 7861: }
7862:
1.624 raeburn 7863: sub personal_data_fieldtitles {
7864: my %fieldtitles = &Apache::lonlocal::texthash (
7865: id => 'Student/Employee ID',
7866: permanentemail => 'E-mail address',
7867: lastname => 'Last Name',
7868: firstname => 'First Name',
7869: middlename => 'Middle Name',
7870: generation => 'Generation',
7871: gen => 'Generation',
1.765 raeburn 7872: inststatus => 'Affiliation',
1.624 raeburn 7873: );
7874: return %fieldtitles;
7875: }
7876:
1.642 raeburn 7877: sub sorted_inst_types {
7878: my ($dom) = @_;
7879: my ($usertypes,$order) = &Apache::lonnet::retrieve_inst_usertypes($dom);
7880: my $othertitle = &mt('All users');
7881: if ($env{'request.course.id'}) {
1.668 raeburn 7882: $othertitle = &mt('Any users');
1.642 raeburn 7883: }
7884: my @types;
7885: if (ref($order) eq 'ARRAY') {
7886: @types = @{$order};
7887: }
7888: if (@types == 0) {
7889: if (ref($usertypes) eq 'HASH') {
7890: @types = sort(keys(%{$usertypes}));
7891: }
7892: }
7893: if (keys(%{$usertypes}) > 0) {
7894: $othertitle = &mt('Other users');
7895: }
7896: return ($othertitle,$usertypes,\@types);
7897: }
7898:
1.645 raeburn 7899: sub get_institutional_codes {
7900: my ($settings,$allcourses,$LC_code) = @_;
7901: # Get complete list of course sections to update
7902: my @currsections = ();
7903: my @currxlists = ();
7904: my $coursecode = $$settings{'internal.coursecode'};
7905:
7906: if ($$settings{'internal.sectionnums'} ne '') {
7907: @currsections = split(/,/,$$settings{'internal.sectionnums'});
7908: }
7909:
7910: if ($$settings{'internal.crosslistings'} ne '') {
7911: @currxlists = split(/,/,$$settings{'internal.crosslistings'});
7912: }
7913:
7914: if (@currxlists > 0) {
7915: foreach (@currxlists) {
7916: if (m/^([^:]+):(\w*)$/) {
7917: unless (grep/^$1$/,@{$allcourses}) {
7918: push @{$allcourses},$1;
7919: $$LC_code{$1} = $2;
7920: }
7921: }
7922: }
7923: }
7924:
7925: if (@currsections > 0) {
7926: foreach (@currsections) {
7927: if (m/^(\w+):(\w*)$/) {
7928: my $sec = $coursecode.$1;
7929: my $lc_sec = $2;
7930: unless (grep/^$sec$/,@{$allcourses}) {
7931: push @{$allcourses},$sec;
7932: $$LC_code{$sec} = $lc_sec;
7933: }
7934: }
7935: }
7936: }
7937: return;
7938: }
7939:
1.112 bowersj2 7940: =pod
7941:
1.780 raeburn 7942: =head1 Slot Helpers
7943:
7944: =over 4
7945:
7946: =item * sorted_slots()
7947:
7948: Sorts an array of slot names in order of slot start time (earliest first).
7949:
7950: Inputs:
7951:
7952: =over 4
7953:
7954: slotsarr - Reference to array of unsorted slot names.
7955:
7956: slots - Reference to hash of hash, where outer hash keys are slot names.
7957:
1.549 albertel 7958: =back
7959:
1.780 raeburn 7960: Returns:
7961:
7962: =over 4
7963:
7964: sorted - An array of slot names sorted by the start time of the slot.
7965:
7966: =back
7967:
7968: =back
7969:
7970: =cut
7971:
7972:
7973: sub sorted_slots {
7974: my ($slotsarr,$slots) = @_;
7975: my @sorted;
7976: if ((ref($slotsarr) eq 'ARRAY') && (ref($slots) eq 'HASH')) {
7977: @sorted =
7978: sort {
7979: if (ref($slots->{$a}) && ref($slots->{$b})) {
7980: return $slots->{$a}{'starttime'} <=> $slots->{$b}{'starttime'}
7981: }
7982: if (ref($slots->{$a})) { return -1;}
7983: if (ref($slots->{$b})) { return 1;}
7984: return 0;
7985: } @{$slotsarr};
7986: }
7987: return @sorted;
7988: }
7989:
7990:
7991: =pod
7992:
1.549 albertel 7993: =head1 HTTP Helpers
7994:
7995: =over 4
7996:
1.648 raeburn 7997: =item * &get_unprocessed_cgi($query,$possible_names)
1.112 bowersj2 7998:
1.258 albertel 7999: Modify the %env hash to contain unprocessed CGI form parameters held in
1.112 bowersj2 8000: $query. The parameters listed in $possible_names (an array reference),
1.258 albertel 8001: will be set in $env{'form.name'} if they do not already exist.
1.112 bowersj2 8002:
8003: Typically called with $ENV{'QUERY_STRING'} as the first parameter.
8004: $possible_names is an ref to an array of form element names. As an example:
8005: get_unprocessed_cgi($ENV{'QUERY_STRING'},['uname','udom']);
1.258 albertel 8006: will result in $env{'form.uname'} and $env{'form.udom'} being set.
1.112 bowersj2 8007:
8008: =cut
1.1 albertel 8009:
1.6 albertel 8010: sub get_unprocessed_cgi {
1.25 albertel 8011: my ($query,$possible_names)= @_;
1.26 matthew 8012: # $Apache::lonxml::debug=1;
1.356 albertel 8013: foreach my $pair (split(/&/,$query)) {
8014: my ($name, $value) = split(/=/,$pair);
1.369 www 8015: $name = &unescape($name);
1.25 albertel 8016: if (!defined($possible_names) || (grep {$_ eq $name} @$possible_names)) {
8017: $value =~ tr/+/ /;
8018: $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
1.258 albertel 8019: unless (defined($env{'form.'.$name})) { &add_to_env('form.'.$name,$value) };
1.25 albertel 8020: }
1.16 harris41 8021: }
1.6 albertel 8022: }
8023:
1.112 bowersj2 8024: =pod
8025:
1.648 raeburn 8026: =item * &cacheheader()
1.112 bowersj2 8027:
8028: returns cache-controlling header code
8029:
8030: =cut
8031:
1.7 albertel 8032: sub cacheheader {
1.258 albertel 8033: unless ($env{'request.method'} eq 'GET') { return ''; }
1.216 albertel 8034: my $date=strftime("%a, %d %b %Y %H:%M:%S GMT",gmtime);
8035: my $output .='<meta HTTP-EQUIV="Expires" CONTENT="'.$date.'" />
1.7 albertel 8036: <meta HTTP-EQUIV="Cache-control" CONTENT="no-cache" />
8037: <meta HTTP-EQUIV="Pragma" CONTENT="no-cache" />';
1.216 albertel 8038: return $output;
1.7 albertel 8039: }
8040:
1.112 bowersj2 8041: =pod
8042:
1.648 raeburn 8043: =item * &no_cache($r)
1.112 bowersj2 8044:
8045: specifies header code to not have cache
8046:
8047: =cut
8048:
1.9 albertel 8049: sub no_cache {
1.216 albertel 8050: my ($r) = @_;
8051: if ($ENV{'REQUEST_METHOD'} ne 'GET' &&
1.258 albertel 8052: $env{'request.method'} ne 'GET') { return ''; }
1.216 albertel 8053: my $date=strftime("%a, %d %b %Y %H:%M:%S GMT",gmtime(time));
8054: $r->no_cache(1);
8055: $r->header_out("Expires" => $date);
8056: $r->header_out("Pragma" => "no-cache");
1.123 www 8057: }
8058:
8059: sub content_type {
1.181 albertel 8060: my ($r,$type,$charset) = @_;
1.299 foxr 8061: if ($r) {
8062: # Note that printout.pl calls this with undef for $r.
8063: &no_cache($r);
8064: }
1.258 albertel 8065: if ($env{'browser.mathml'} && $type eq 'text/html') { $type='text/xml'; }
1.181 albertel 8066: unless ($charset) {
8067: $charset=&Apache::lonlocal::current_encoding;
8068: }
8069: if ($charset) { $type.='; charset='.$charset; }
8070: if ($r) {
8071: $r->content_type($type);
8072: } else {
8073: print("Content-type: $type\n\n");
8074: }
1.9 albertel 8075: }
1.25 albertel 8076:
1.112 bowersj2 8077: =pod
8078:
1.648 raeburn 8079: =item * &add_to_env($name,$value)
1.112 bowersj2 8080:
1.258 albertel 8081: adds $name to the %env hash with value
1.112 bowersj2 8082: $value, if $name already exists, the entry is converted to an array
8083: reference and $value is added to the array.
8084:
8085: =cut
8086:
1.25 albertel 8087: sub add_to_env {
8088: my ($name,$value)=@_;
1.258 albertel 8089: if (defined($env{$name})) {
8090: if (ref($env{$name})) {
1.25 albertel 8091: #already have multiple values
1.258 albertel 8092: push(@{ $env{$name} },$value);
1.25 albertel 8093: } else {
8094: #first time seeing multiple values, convert hash entry to an arrayref
1.258 albertel 8095: my $first=$env{$name};
8096: undef($env{$name});
8097: push(@{ $env{$name} },$first,$value);
1.25 albertel 8098: }
8099: } else {
1.258 albertel 8100: $env{$name}=$value;
1.25 albertel 8101: }
1.31 albertel 8102: }
1.149 albertel 8103:
8104: =pod
8105:
1.648 raeburn 8106: =item * &get_env_multiple($name)
1.149 albertel 8107:
1.258 albertel 8108: gets $name from the %env hash, it seemlessly handles the cases where multiple
1.149 albertel 8109: values may be defined and end up as an array ref.
8110:
8111: returns an array of values
8112:
8113: =cut
8114:
8115: sub get_env_multiple {
8116: my ($name) = @_;
8117: my @values;
1.258 albertel 8118: if (defined($env{$name})) {
1.149 albertel 8119: # exists is it an array
1.258 albertel 8120: if (ref($env{$name})) {
8121: @values=@{ $env{$name} };
1.149 albertel 8122: } else {
1.258 albertel 8123: $values[0]=$env{$name};
1.149 albertel 8124: }
8125: }
8126: return(@values);
8127: }
8128:
1.660 raeburn 8129: sub ask_for_embedded_content {
8130: my ($actionurl,$state,$allfiles,$codebase,$args)=@_;
8131: my $upload_output = '
8132: <form name="upload_embedded" action="'.$actionurl.'"
8133: method="post" enctype="multipart/form-data">';
8134: $upload_output .= $state;
1.661 raeburn 8135: $upload_output .= '<b>Upload embedded files</b>:<br />'.&start_data_table();
1.660 raeburn 8136:
8137: my $num = 0;
8138: foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%{$allfiles})) {
8139: $upload_output .= &start_data_table_row().
8140: '<td>'.$embed_file.'</td><td>';
8141: if ($args->{'ignore_remote_references'}
8142: && $embed_file =~ m{^\w+://}) {
8143: $upload_output.='<span class="LC_warning">'.&mt("URL points to other server.").'</span>';
8144: } elsif ($args->{'error_on_invalid_names'}
8145: && $embed_file ne &Apache::lonnet::clean_filename($embed_file,{'keep_path' => 1,})) {
8146:
8147: $upload_output.='<span class="LC_warning">'.&mt("Invalid characters").'</span>';
8148:
8149: } else {
8150: $upload_output .='
1.661 raeburn 8151: <input name="embedded_item_'.$num.'" type="file" value="" />
1.660 raeburn 8152: <input name="embedded_orig_'.$num.'" type="hidden" value="'.&escape($embed_file).'" />';
8153: my $attrib = join(':',@{$$allfiles{$embed_file}});
8154: $upload_output .=
8155: "\n\t\t".
8156: '<input name="embedded_attrib_'.$num.'" type="hidden" value="'.
8157: $attrib.'" />';
8158: if (exists($$codebase{$embed_file})) {
8159: $upload_output .=
8160: "\n\t\t".
8161: '<input name="codebase_'.$num.'" type="hidden" value="'.
8162: &escape($$codebase{$embed_file}).'" />';
8163: }
8164: }
8165: $upload_output .= '</td>'.&Apache::loncommon::end_data_table_row();
8166: $num++;
8167: }
8168: $upload_output .= &Apache::loncommon::end_data_table().'<br />
8169: <input type ="hidden" name="number_embedded_items" value="'.$num.'" />
8170: <input type ="submit" value="'.&mt('Upload Listed Files').'" />
8171: '.&mt('(only files for which a location has been provided will be uploaded)').'
8172: </form>';
8173: return $upload_output;
8174: }
8175:
1.661 raeburn 8176: sub upload_embedded {
8177: my ($context,$dirpath,$uname,$udom,$dir_root,$url_root,$group,$disk_quota,
8178: $current_disk_usage) = @_;
8179: my $output;
8180: for (my $i=0; $i<$env{'form.number_embedded_items'}; $i++) {
8181: next if (!exists($env{'form.embedded_item_'.$i.'.filename'}));
8182: my $orig_uploaded_filename =
8183: $env{'form.embedded_item_'.$i.'.filename'};
8184:
8185: $env{'form.embedded_orig_'.$i} =
8186: &unescape($env{'form.embedded_orig_'.$i});
8187: my ($path,$fname) =
8188: ($env{'form.embedded_orig_'.$i} =~ m{(.*/)([^/]*)});
8189: # no path, whole string is fname
8190: if (!$fname) { $fname = $env{'form.embedded_orig_'.$i} };
8191:
8192: $path = $env{'form.currentpath'}.$path;
8193: $fname = &Apache::lonnet::clean_filename($fname);
8194: # See if there is anything left
8195: next if ($fname eq '');
8196:
8197: # Check if file already exists as a file or directory.
8198: my ($state,$msg);
8199: if ($context eq 'portfolio') {
8200: my $port_path = $dirpath;
8201: if ($group ne '') {
8202: $port_path = "groups/$group/$port_path";
8203: }
8204: ($state,$msg) = &check_for_upload($path,$fname,$group,'embedded_item_'.$i,
8205: $dir_root,$port_path,$disk_quota,
8206: $current_disk_usage,$uname,$udom);
8207: if ($state eq 'will_exceed_quota'
8208: || $state eq 'file_locked'
8209: || $state eq 'file_exists' ) {
8210: $output .= $msg;
8211: next;
8212: }
8213: } elsif (($context eq 'author') || ($context eq 'testbank')) {
8214: ($state,$msg) = &check_for_existing($path,$fname,'embedded_item_'.$i);
8215: if ($state eq 'exists') {
8216: $output .= $msg;
8217: next;
8218: }
8219: }
8220: # Check if extension is valid
8221: if (($fname =~ /\.(\w+)$/) &&
8222: (&Apache::loncommon::fileembstyle($1) eq 'hdn')) {
8223: $output .= &mt('Invalid file extension ([_1]) - reserved for LONCAPA use - rename the file with a different extension and re-upload. ',$1);
8224: next;
8225: } elsif (($fname =~ /\.(\w+)$/) &&
8226: (!defined(&Apache::loncommon::fileembstyle($1)))) {
8227: $output .= &mt('Unrecognized file extension ([_1]) - rename the file with a proper extension and re-upload.',$1);
8228: next;
8229: } elsif ($fname=~/\.(\d+)\.(\w+)$/) {
8230: $output .= &mt('File name not allowed - rename the file to remove the number immediately before the file extension([_1]) and re-upload.',$2);
8231: next;
8232: }
8233:
8234: $env{'form.embedded_item_'.$i.'.filename'}=$fname;
8235: if ($context eq 'portfolio') {
8236: my $result=
8237: &Apache::lonnet::userfileupload('embedded_item_'.$i,'',
8238: $dirpath.$path);
8239: if ($result !~ m|^/uploaded/|) {
8240: $output .= '<span class="LC_error">'
8241: .&mt('An error occurred ([_1]) while trying to upload [_2] for embedded element [_3].'
8242: ,$result,$orig_uploaded_filename,$env{'form.embedded_orig_'.$i})
8243: .'</span><br />';
8244: next;
8245: } else {
8246: $output .= '<p>'.&mt('Uploaded [_1]','<span class="LC_filename">'.
8247: $path.$fname.'</span>').'</p>';
8248: }
8249: } else {
8250: # Save the file
8251: my $target = $env{'form.embedded_item_'.$i};
8252: my $fullpath = $dir_root.$dirpath.'/'.$path;
8253: my $dest = $fullpath.$fname;
8254: my $url = $url_root.$dirpath.'/'.$path.$fname;
8255: my @parts=split(/\//,$fullpath);
8256: my $count;
8257: my $filepath = $dir_root;
8258: for ($count=4;$count<=$#parts;$count++) {
8259: $filepath .= "/$parts[$count]";
8260: if ((-e $filepath)!=1) {
8261: mkdir($filepath,0770);
8262: }
8263: }
8264: my $fh;
8265: if (!open($fh,'>'.$dest)) {
8266: &Apache::lonnet::logthis('Failed to create '.$dest);
8267: $output .= '<span class="LC_error">'.
8268: &mt('An error occurred while trying to upload [_1] for embedded element [_2].',$orig_uploaded_filename,$env{'form.embedded_orig_'.$i}).
8269: '</span><br />';
8270: } else {
8271: if (!print $fh $env{'form.embedded_item_'.$i}) {
8272: &Apache::lonnet::logthis('Failed to write to '.$dest);
8273: $output .= '<span class="LC_error">'.
8274: &mt('An error occurred while writing the file [_1] for embedded element [_2].',$orig_uploaded_filename,$env{'form.embedded_orig_'.$i}).
8275: '</span><br />';
8276: } else {
8277: if ($context eq 'testbank') {
8278: $output .= &mt('Embedded file uploaded successfully:').
8279: ' <a href="'.$url.'">'.
8280: $orig_uploaded_filename.'</a><br />';
8281: } else {
1.705 tempelho 8282: $output .= '<span class=\"LC_fontsize_large\">'.
1.661 raeburn 8283: &mt('View embedded file: [_1]','<a href="'.$url.'">'.
1.705 tempelho 8284: $orig_uploaded_filename.'</a>').'</span><br />';
1.661 raeburn 8285: }
8286: }
8287: close($fh);
8288: }
8289: }
8290: }
8291: return $output;
8292: }
8293:
8294: sub check_for_existing {
8295: my ($path,$fname,$element) = @_;
8296: my ($state,$msg);
8297: if (-d $path.'/'.$fname) {
8298: $state = 'exists';
8299: $msg = &mt('Unable to upload [_1]. A directory by that name was found in [_2].','<span class="LC_filename">'.$fname.'</span>',$path);
8300: } elsif (-e $path.'/'.$fname) {
8301: $state = 'exists';
8302: $msg = &mt('Unable to upload [_1]. A file by that name was found in [_2].','<span class="LC_filename">'.$fname.'</span>',$path);
8303: }
8304: if ($state eq 'exists') {
8305: $msg = '<span class="LC_error">'.$msg.'</span><br />';
8306: }
8307: return ($state,$msg);
8308: }
8309:
8310: sub check_for_upload {
8311: my ($path,$fname,$group,$element,$portfolio_root,$port_path,
8312: $disk_quota,$current_disk_usage,$uname,$udom) = @_;
8313: my $filesize = (length($env{'form.'.$element})) / 1000; #express in k (1024?)
8314: my $getpropath = 1;
8315: my @dir_list = &Apache::lonnet::dirlist($portfolio_root.$path,$udom,$uname,
8316: $getpropath);
8317: my $found_file = 0;
8318: my $locked_file = 0;
8319: foreach my $line (@dir_list) {
8320: my ($file_name)=split(/\&/,$line,2);
8321: if ($file_name eq $fname){
8322: $file_name = $path.$file_name;
8323: if ($group ne '') {
8324: $file_name = $group.$file_name;
8325: }
8326: $found_file = 1;
8327: if (&Apache::lonnet::is_locked($file_name,$udom,$uname) eq 'true') {
8328: $locked_file = 1;
8329: }
8330: }
8331: }
8332: if (($current_disk_usage + $filesize) > $disk_quota){
8333: my $msg = '<span class="LC_error">'.
8334: &mt('Unable to upload [_1]. (size = [_2] kilobytes). Disk quota will be exceeded.','<span class="LC_filename">'.$fname.'</span>',$filesize).'</span>'.
8335: '<br />'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.',$disk_quota,$current_disk_usage);
8336: return ('will_exceed_quota',$msg);
8337: } elsif ($found_file) {
8338: if ($locked_file) {
8339: my $msg = '<span class="LC_error">';
8340: $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>');
8341: $msg .= '</span><br />';
8342: $msg .= &mt('You will be able to rename or delete existing [_1] after a grade has been assigned.','<span class="LC_filename">'.$fname.'</span>');
8343: return ('file_locked',$msg);
8344: } else {
8345: my $msg = '<span class="LC_error">';
8346: $msg .= &mt('Unable to upload [_1]. A file by that name was found in [_2].','<span class="LC_filename">'.$fname.'</span>',$port_path.$env{'form.currentpath'});
8347: $msg .= '</span>';
8348: $msg .= '<br />';
8349: $msg .= &mt('To upload, rename or delete existing [_1] in [_2].','<span class="LC_filename">'.$fname.'</span>', $port_path.$env{'form.currentpath'});
8350: return ('file_exists',$msg);
8351: }
8352: }
8353: }
8354:
1.31 albertel 8355:
1.41 ng 8356: =pod
1.45 matthew 8357:
1.464 albertel 8358: =back
1.41 ng 8359:
1.112 bowersj2 8360: =head1 CSV Upload/Handling functions
1.38 albertel 8361:
1.41 ng 8362: =over 4
8363:
1.648 raeburn 8364: =item * &upfile_store($r)
1.41 ng 8365:
8366: Store uploaded file, $r should be the HTTP Request object,
1.258 albertel 8367: needs $env{'form.upfile'}
1.41 ng 8368: returns $datatoken to be put into hidden field
8369:
8370: =cut
1.31 albertel 8371:
8372: sub upfile_store {
8373: my $r=shift;
1.258 albertel 8374: $env{'form.upfile'}=~s/\r/\n/gs;
8375: $env{'form.upfile'}=~s/\f/\n/gs;
8376: $env{'form.upfile'}=~s/\n+/\n/gs;
8377: $env{'form.upfile'}=~s/\n+$//gs;
1.31 albertel 8378:
1.258 albertel 8379: my $datatoken=$env{'user.name'}.'_'.$env{'user.domain'}.
8380: '_enroll_'.$env{'request.course.id'}.'_'.time.'_'.$$;
1.31 albertel 8381: {
1.158 raeburn 8382: my $datafile = $r->dir_config('lonDaemons').
8383: '/tmp/'.$datatoken.'.tmp';
8384: if ( open(my $fh,">$datafile") ) {
1.258 albertel 8385: print $fh $env{'form.upfile'};
1.158 raeburn 8386: close($fh);
8387: }
1.31 albertel 8388: }
8389: return $datatoken;
8390: }
8391:
1.56 matthew 8392: =pod
8393:
1.648 raeburn 8394: =item * &load_tmp_file($r)
1.41 ng 8395:
8396: Load uploaded file from tmp, $r should be the HTTP Request object,
1.258 albertel 8397: needs $env{'form.datatoken'},
8398: sets $env{'form.upfile'} to the contents of the file
1.41 ng 8399:
8400: =cut
1.31 albertel 8401:
8402: sub load_tmp_file {
8403: my $r=shift;
8404: my @studentdata=();
8405: {
1.158 raeburn 8406: my $studentfile = $r->dir_config('lonDaemons').
1.258 albertel 8407: '/tmp/'.$env{'form.datatoken'}.'.tmp';
1.158 raeburn 8408: if ( open(my $fh,"<$studentfile") ) {
8409: @studentdata=<$fh>;
8410: close($fh);
8411: }
1.31 albertel 8412: }
1.258 albertel 8413: $env{'form.upfile'}=join('',@studentdata);
1.31 albertel 8414: }
8415:
1.56 matthew 8416: =pod
8417:
1.648 raeburn 8418: =item * &upfile_record_sep()
1.41 ng 8419:
8420: Separate uploaded file into records
8421: returns array of records,
1.258 albertel 8422: needs $env{'form.upfile'} and $env{'form.upfiletype'}
1.41 ng 8423:
8424: =cut
1.31 albertel 8425:
8426: sub upfile_record_sep {
1.258 albertel 8427: if ($env{'form.upfiletype'} eq 'xml') {
1.31 albertel 8428: } else {
1.248 albertel 8429: my @records;
1.258 albertel 8430: foreach my $line (split(/\n/,$env{'form.upfile'})) {
1.248 albertel 8431: if ($line=~/^\s*$/) { next; }
8432: push(@records,$line);
8433: }
8434: return @records;
1.31 albertel 8435: }
8436: }
8437:
1.56 matthew 8438: =pod
8439:
1.648 raeburn 8440: =item * &record_sep($record)
1.41 ng 8441:
1.258 albertel 8442: Separate a record into fields $record should be an item from the upfile_record_sep(), needs $env{'form.upfiletype'}
1.41 ng 8443:
8444: =cut
8445:
1.263 www 8446: sub takeleft {
8447: my $index=shift;
8448: return substr('0000'.$index,-4,4);
8449: }
8450:
1.31 albertel 8451: sub record_sep {
8452: my $record=shift;
8453: my %components=();
1.258 albertel 8454: if ($env{'form.upfiletype'} eq 'xml') {
8455: } elsif ($env{'form.upfiletype'} eq 'space') {
1.31 albertel 8456: my $i=0;
1.356 albertel 8457: foreach my $field (split(/\s+/,$record)) {
1.31 albertel 8458: $field=~s/^(\"|\')//;
8459: $field=~s/(\"|\')$//;
1.263 www 8460: $components{&takeleft($i)}=$field;
1.31 albertel 8461: $i++;
8462: }
1.258 albertel 8463: } elsif ($env{'form.upfiletype'} eq 'tab') {
1.31 albertel 8464: my $i=0;
1.356 albertel 8465: foreach my $field (split(/\t/,$record)) {
1.31 albertel 8466: $field=~s/^(\"|\')//;
8467: $field=~s/(\"|\')$//;
1.263 www 8468: $components{&takeleft($i)}=$field;
1.31 albertel 8469: $i++;
8470: }
8471: } else {
1.561 www 8472: my $separator=',';
1.480 banghart 8473: if ($env{'form.upfiletype'} eq 'semisv') {
1.561 www 8474: $separator=';';
1.480 banghart 8475: }
1.31 albertel 8476: my $i=0;
1.561 www 8477: # the character we are looking for to indicate the end of a quote or a record
8478: my $looking_for=$separator;
8479: # do not add the characters to the fields
8480: my $ignore=0;
8481: # we just encountered a separator (or the beginning of the record)
8482: my $just_found_separator=1;
8483: # store the field we are working on here
8484: my $field='';
8485: # work our way through all characters in record
8486: foreach my $character ($record=~/(.)/g) {
8487: if ($character eq $looking_for) {
8488: if ($character ne $separator) {
8489: # Found the end of a quote, again looking for separator
8490: $looking_for=$separator;
8491: $ignore=1;
8492: } else {
8493: # Found a separator, store away what we got
8494: $components{&takeleft($i)}=$field;
8495: $i++;
8496: $just_found_separator=1;
8497: $ignore=0;
8498: $field='';
8499: }
8500: next;
8501: }
8502: # single or double quotation marks after a separator indicate beginning of a quote
8503: # we are now looking for the end of the quote and need to ignore separators
8504: if ((($character eq '"') || ($character eq "'")) && ($just_found_separator)) {
8505: $looking_for=$character;
8506: next;
8507: }
8508: # ignore would be true after we reached the end of a quote
8509: if ($ignore) { next; }
8510: if (($just_found_separator) && ($character=~/\s/)) { next; }
8511: $field.=$character;
8512: $just_found_separator=0;
1.31 albertel 8513: }
1.561 www 8514: # catch the very last entry, since we never encountered the separator
8515: $components{&takeleft($i)}=$field;
1.31 albertel 8516: }
8517: return %components;
8518: }
8519:
1.144 matthew 8520: ######################################################
8521: ######################################################
8522:
1.56 matthew 8523: =pod
8524:
1.648 raeburn 8525: =item * &upfile_select_html()
1.41 ng 8526:
1.144 matthew 8527: Return HTML code to select a file from the users machine and specify
8528: the file type.
1.41 ng 8529:
8530: =cut
8531:
1.144 matthew 8532: ######################################################
8533: ######################################################
1.31 albertel 8534: sub upfile_select_html {
1.144 matthew 8535: my %Types = (
8536: csv => &mt('CSV (comma separated values, spreadsheet)'),
1.480 banghart 8537: semisv => &mt('Semicolon separated values'),
1.144 matthew 8538: space => &mt('Space separated'),
8539: tab => &mt('Tabulator separated'),
8540: # xml => &mt('HTML/XML'),
8541: );
8542: my $Str = '<input type="file" name="upfile" size="50" />'.
1.727 riegler 8543: '<br />'.&mt('Type').': <select name="upfiletype">';
1.144 matthew 8544: foreach my $type (sort(keys(%Types))) {
8545: $Str .= '<option value="'.$type.'" >'.$Types{$type}."</option>\n";
8546: }
8547: $Str .= "</select>\n";
8548: return $Str;
1.31 albertel 8549: }
8550:
1.301 albertel 8551: sub get_samples {
8552: my ($records,$toget) = @_;
8553: my @samples=({});
8554: my $got=0;
8555: foreach my $rec (@$records) {
8556: my %temp = &record_sep($rec);
8557: if (! grep(/\S/, values(%temp))) { next; }
8558: if (%temp) {
8559: $samples[$got]=\%temp;
8560: $got++;
8561: if ($got == $toget) { last; }
8562: }
8563: }
8564: return \@samples;
8565: }
8566:
1.144 matthew 8567: ######################################################
8568: ######################################################
8569:
1.56 matthew 8570: =pod
8571:
1.648 raeburn 8572: =item * &csv_print_samples($r,$records)
1.41 ng 8573:
8574: Prints a table of sample values from each column uploaded $r is an
8575: Apache Request ref, $records is an arrayref from
8576: &Apache::loncommon::upfile_record_sep
8577:
8578: =cut
8579:
1.144 matthew 8580: ######################################################
8581: ######################################################
1.31 albertel 8582: sub csv_print_samples {
8583: my ($r,$records) = @_;
1.662 bisitz 8584: my $samples = &get_samples($records,5);
1.301 albertel 8585:
1.594 raeburn 8586: $r->print(&mt('Samples').'<br />'.&start_data_table().
8587: &start_data_table_header_row());
1.356 albertel 8588: foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) {
1.845 bisitz 8589: $r->print('<th>'.&mt('Column [_1]',($sample+1)).'</th>'); }
1.594 raeburn 8590: $r->print(&end_data_table_header_row());
1.301 albertel 8591: foreach my $hash (@$samples) {
1.594 raeburn 8592: $r->print(&start_data_table_row());
1.356 albertel 8593: foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) {
1.31 albertel 8594: $r->print('<td>');
1.356 albertel 8595: if (defined($$hash{$sample})) { $r->print($$hash{$sample}); }
1.31 albertel 8596: $r->print('</td>');
8597: }
1.594 raeburn 8598: $r->print(&end_data_table_row());
1.31 albertel 8599: }
1.594 raeburn 8600: $r->print(&end_data_table().'<br />'."\n");
1.31 albertel 8601: }
8602:
1.144 matthew 8603: ######################################################
8604: ######################################################
8605:
1.56 matthew 8606: =pod
8607:
1.648 raeburn 8608: =item * &csv_print_select_table($r,$records,$d)
1.41 ng 8609:
8610: Prints a table to create associations between values and table columns.
1.144 matthew 8611:
1.41 ng 8612: $r is an Apache Request ref,
8613: $records is an arrayref from &Apache::loncommon::upfile_record_sep,
1.174 matthew 8614: $d is an array of 2 element arrays (internal name, displayed name,defaultcol)
1.41 ng 8615:
8616: =cut
8617:
1.144 matthew 8618: ######################################################
8619: ######################################################
1.31 albertel 8620: sub csv_print_select_table {
8621: my ($r,$records,$d) = @_;
1.301 albertel 8622: my $i=0;
8623: my $samples = &get_samples($records,1);
1.144 matthew 8624: $r->print(&mt('Associate columns with student attributes.')."\n".
1.594 raeburn 8625: &start_data_table().&start_data_table_header_row().
1.144 matthew 8626: '<th>'.&mt('Attribute').'</th>'.
1.594 raeburn 8627: '<th>'.&mt('Column').'</th>'.
8628: &end_data_table_header_row()."\n");
1.356 albertel 8629: foreach my $array_ref (@$d) {
8630: my ($value,$display,$defaultcol)=@{ $array_ref };
1.729 raeburn 8631: $r->print(&start_data_table_row().'<td>'.$display.'</td>');
1.31 albertel 8632:
1.875 bisitz 8633: $r->print('<td><select name="f'.$i.'"'.
1.32 matthew 8634: ' onchange="javascript:flip(this.form,'.$i.');">');
1.31 albertel 8635: $r->print('<option value="none"></option>');
1.356 albertel 8636: foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) {
8637: $r->print('<option value="'.$sample.'"'.
8638: ($sample eq $defaultcol ? ' selected="selected" ' : '').
1.662 bisitz 8639: '>'.&mt('Column [_1]',($sample+1)).'</option>');
1.31 albertel 8640: }
1.594 raeburn 8641: $r->print('</select></td>'.&end_data_table_row()."\n");
1.31 albertel 8642: $i++;
8643: }
1.594 raeburn 8644: $r->print(&end_data_table());
1.31 albertel 8645: $i--;
8646: return $i;
8647: }
1.56 matthew 8648:
1.144 matthew 8649: ######################################################
8650: ######################################################
8651:
1.56 matthew 8652: =pod
1.31 albertel 8653:
1.648 raeburn 8654: =item * &csv_samples_select_table($r,$records,$d)
1.41 ng 8655:
8656: Prints a table of sample values from the upload and can make associate samples to internal names.
8657:
8658: $r is an Apache Request ref,
8659: $records is an arrayref from &Apache::loncommon::upfile_record_sep,
8660: $d is an array of 2 element arrays (internal name, displayed name)
8661:
8662: =cut
8663:
1.144 matthew 8664: ######################################################
8665: ######################################################
1.31 albertel 8666: sub csv_samples_select_table {
8667: my ($r,$records,$d) = @_;
8668: my $i=0;
1.144 matthew 8669: #
1.662 bisitz 8670: my $max_samples = 5;
8671: my $samples = &get_samples($records,$max_samples);
1.594 raeburn 8672: $r->print(&start_data_table().
8673: &start_data_table_header_row().'<th>'.
8674: &mt('Field').'</th><th>'.&mt('Samples').'</th>'.
8675: &end_data_table_header_row());
1.301 albertel 8676:
8677: foreach my $key (sort(keys(%{ $samples->[0] }))) {
1.594 raeburn 8678: $r->print(&start_data_table_row().'<td><select name="f'.$i.'"'.
1.32 matthew 8679: ' onchange="javascript:flip(this.form,'.$i.');">');
1.301 albertel 8680: foreach my $option (@$d) {
8681: my ($value,$display,$defaultcol)=@{ $option };
1.174 matthew 8682: $r->print('<option value="'.$value.'"'.
1.253 albertel 8683: ($i eq $defaultcol ? ' selected="selected" ':'').'>'.
1.174 matthew 8684: $display.'</option>');
1.31 albertel 8685: }
8686: $r->print('</select></td><td>');
1.662 bisitz 8687: foreach my $line (0..($max_samples-1)) {
1.301 albertel 8688: if (defined($samples->[$line]{$key})) {
8689: $r->print($samples->[$line]{$key}."<br />\n");
8690: }
8691: }
1.594 raeburn 8692: $r->print('</td>'.&end_data_table_row());
1.31 albertel 8693: $i++;
8694: }
1.594 raeburn 8695: $r->print(&end_data_table());
1.31 albertel 8696: $i--;
8697: return($i);
1.115 matthew 8698: }
8699:
1.144 matthew 8700: ######################################################
8701: ######################################################
8702:
1.115 matthew 8703: =pod
8704:
1.648 raeburn 8705: =item * &clean_excel_name($name)
1.115 matthew 8706:
8707: Returns a replacement for $name which does not contain any illegal characters.
8708:
8709: =cut
8710:
1.144 matthew 8711: ######################################################
8712: ######################################################
1.115 matthew 8713: sub clean_excel_name {
8714: my ($name) = @_;
8715: $name =~ s/[:\*\?\/\\]//g;
8716: if (length($name) > 31) {
8717: $name = substr($name,0,31);
8718: }
8719: return $name;
1.25 albertel 8720: }
1.84 albertel 8721:
1.85 albertel 8722: =pod
8723:
1.648 raeburn 8724: =item * &check_if_partid_hidden($id,$symb,$udom,$uname)
1.85 albertel 8725:
8726: Returns either 1 or undef
8727:
8728: 1 if the part is to be hidden, undef if it is to be shown
8729:
8730: Arguments are:
8731:
8732: $id the id of the part to be checked
8733: $symb, optional the symb of the resource to check
8734: $udom, optional the domain of the user to check for
8735: $uname, optional the username of the user to check for
8736:
8737: =cut
1.84 albertel 8738:
8739: sub check_if_partid_hidden {
8740: my ($id,$symb,$udom,$uname) = @_;
1.133 albertel 8741: my $hiddenparts=&Apache::lonnet::EXT('resource.0.hiddenparts',
1.84 albertel 8742: $symb,$udom,$uname);
1.141 albertel 8743: my $truth=1;
8744: #if the string starts with !, then the list is the list to show not hide
8745: if ($hiddenparts=~s/^\s*!//) { $truth=undef; }
1.84 albertel 8746: my @hiddenlist=split(/,/,$hiddenparts);
8747: foreach my $checkid (@hiddenlist) {
1.141 albertel 8748: if ($checkid =~ /^\s*\Q$id\E\s*$/) { return $truth; }
1.84 albertel 8749: }
1.141 albertel 8750: return !$truth;
1.84 albertel 8751: }
1.127 matthew 8752:
1.138 matthew 8753:
8754: ############################################################
8755: ############################################################
8756:
8757: =pod
8758:
1.157 matthew 8759: =back
8760:
1.138 matthew 8761: =head1 cgi-bin script and graphing routines
8762:
1.157 matthew 8763: =over 4
8764:
1.648 raeburn 8765: =item * &get_cgi_id()
1.138 matthew 8766:
8767: Inputs: none
8768:
8769: Returns an id which can be used to pass environment variables
8770: to various cgi-bin scripts. These environment variables will
8771: be removed from the users environment after a given time by
8772: the routine &Apache::lonnet::transfer_profile_to_env.
8773:
8774: =cut
8775:
8776: ############################################################
8777: ############################################################
1.152 albertel 8778: my $uniq=0;
1.136 matthew 8779: sub get_cgi_id {
1.154 albertel 8780: $uniq=($uniq+1)%100000;
1.280 albertel 8781: return (time.'_'.$$.'_'.$uniq);
1.136 matthew 8782: }
8783:
1.127 matthew 8784: ############################################################
8785: ############################################################
8786:
8787: =pod
8788:
1.648 raeburn 8789: =item * &DrawBarGraph()
1.127 matthew 8790:
1.138 matthew 8791: Facilitates the plotting of data in a (stacked) bar graph.
8792: Puts plot definition data into the users environment in order for
8793: graph.png to plot it. Returns an <img> tag for the plot.
8794: The bars on the plot are labeled '1','2',...,'n'.
8795:
8796: Inputs:
8797:
8798: =over 4
8799:
8800: =item $Title: string, the title of the plot
8801:
8802: =item $xlabel: string, text describing the X-axis of the plot
8803:
8804: =item $ylabel: string, text describing the Y-axis of the plot
8805:
8806: =item $Max: scalar, the maximum Y value to use in the plot
8807: If $Max is < any data point, the graph will not be rendered.
8808:
1.140 matthew 8809: =item $colors: array ref holding the colors to be used for the data sets when
1.138 matthew 8810: they are plotted. If undefined, default values will be used.
8811:
1.178 matthew 8812: =item $labels: array ref holding the labels to use on the x-axis for the bars.
8813:
1.138 matthew 8814: =item @Values: An array of array references. Each array reference holds data
8815: to be plotted in a stacked bar chart.
8816:
1.239 matthew 8817: =item If the final element of @Values is a hash reference the key/value
8818: pairs will be added to the graph definition.
8819:
1.138 matthew 8820: =back
8821:
8822: Returns:
8823:
8824: An <img> tag which references graph.png and the appropriate identifying
8825: information for the plot.
8826:
1.127 matthew 8827: =cut
8828:
8829: ############################################################
8830: ############################################################
1.134 matthew 8831: sub DrawBarGraph {
1.178 matthew 8832: my ($Title,$xlabel,$ylabel,$Max,$colors,$labels,@Values)=@_;
1.134 matthew 8833: #
8834: if (! defined($colors)) {
8835: $colors = ['#33ff00',
8836: '#0033cc', '#990000', '#aaaa66', '#663399', '#ff9933',
8837: '#66ccff', '#ff9999', '#cccc33', '#660000', '#33cc66',
8838: ];
8839: }
1.228 matthew 8840: my $extra_settings = {};
8841: if (ref($Values[-1]) eq 'HASH') {
8842: $extra_settings = pop(@Values);
8843: }
1.127 matthew 8844: #
1.136 matthew 8845: my $identifier = &get_cgi_id();
8846: my $id = 'cgi.'.$identifier;
1.129 matthew 8847: if (! @Values || ref($Values[0]) ne 'ARRAY') {
1.127 matthew 8848: return '';
8849: }
1.225 matthew 8850: #
8851: my @Labels;
8852: if (defined($labels)) {
8853: @Labels = @$labels;
8854: } else {
8855: for (my $i=0;$i<@{$Values[0]};$i++) {
8856: push (@Labels,$i+1);
8857: }
8858: }
8859: #
1.129 matthew 8860: my $NumBars = scalar(@{$Values[0]});
1.225 matthew 8861: if ($NumBars < scalar(@Labels)) { $NumBars = scalar(@Labels); }
1.129 matthew 8862: my %ValuesHash;
8863: my $NumSets=1;
8864: foreach my $array (@Values) {
8865: next if (! ref($array));
1.136 matthew 8866: $ValuesHash{$id.'.data.'.$NumSets++} =
1.132 matthew 8867: join(',',@$array);
1.129 matthew 8868: }
1.127 matthew 8869: #
1.136 matthew 8870: my ($height,$width,$xskip,$bar_width) = (200,120,1,15);
1.225 matthew 8871: if ($NumBars < 3) {
8872: $width = 120+$NumBars*32;
1.220 matthew 8873: $xskip = 1;
1.225 matthew 8874: $bar_width = 30;
8875: } elsif ($NumBars < 5) {
8876: $width = 120+$NumBars*20;
8877: $xskip = 1;
8878: $bar_width = 20;
1.220 matthew 8879: } elsif ($NumBars < 10) {
1.136 matthew 8880: $width = 120+$NumBars*15;
8881: $xskip = 1;
8882: $bar_width = 15;
8883: } elsif ($NumBars <= 25) {
8884: $width = 120+$NumBars*11;
8885: $xskip = 5;
8886: $bar_width = 8;
8887: } elsif ($NumBars <= 50) {
8888: $width = 120+$NumBars*8;
8889: $xskip = 5;
8890: $bar_width = 4;
8891: } else {
8892: $width = 120+$NumBars*8;
8893: $xskip = 5;
8894: $bar_width = 4;
8895: }
8896: #
1.137 matthew 8897: $Max = 1 if ($Max < 1);
8898: if ( int($Max) < $Max ) {
8899: $Max++;
8900: $Max = int($Max);
8901: }
1.127 matthew 8902: $Title = '' if (! defined($Title));
8903: $xlabel = '' if (! defined($xlabel));
8904: $ylabel = '' if (! defined($ylabel));
1.369 www 8905: $ValuesHash{$id.'.title'} = &escape($Title);
8906: $ValuesHash{$id.'.xlabel'} = &escape($xlabel);
8907: $ValuesHash{$id.'.ylabel'} = &escape($ylabel);
1.137 matthew 8908: $ValuesHash{$id.'.y_max_value'} = $Max;
1.136 matthew 8909: $ValuesHash{$id.'.NumBars'} = $NumBars;
8910: $ValuesHash{$id.'.NumSets'} = $NumSets;
8911: $ValuesHash{$id.'.PlotType'} = 'bar';
8912: $ValuesHash{$id.'.Colors'} = join(',',@{$colors});
8913: $ValuesHash{$id.'.height'} = $height;
8914: $ValuesHash{$id.'.width'} = $width;
8915: $ValuesHash{$id.'.xskip'} = $xskip;
8916: $ValuesHash{$id.'.bar_width'} = $bar_width;
8917: $ValuesHash{$id.'.labels'} = join(',',@Labels);
1.127 matthew 8918: #
1.228 matthew 8919: # Deal with other parameters
8920: while (my ($key,$value) = each(%$extra_settings)) {
8921: $ValuesHash{$id.'.'.$key} = $value;
8922: }
8923: #
1.646 raeburn 8924: &Apache::lonnet::appenv(\%ValuesHash);
1.137 matthew 8925: return '<img src="/cgi-bin/graph.png?'.$identifier.'" border="1" />';
8926: }
8927:
8928: ############################################################
8929: ############################################################
8930:
8931: =pod
8932:
1.648 raeburn 8933: =item * &DrawXYGraph()
1.137 matthew 8934:
1.138 matthew 8935: Facilitates the plotting of data in an XY graph.
8936: Puts plot definition data into the users environment in order for
8937: graph.png to plot it. Returns an <img> tag for the plot.
8938:
8939: Inputs:
8940:
8941: =over 4
8942:
8943: =item $Title: string, the title of the plot
8944:
8945: =item $xlabel: string, text describing the X-axis of the plot
8946:
8947: =item $ylabel: string, text describing the Y-axis of the plot
8948:
8949: =item $Max: scalar, the maximum Y value to use in the plot
8950: If $Max is < any data point, the graph will not be rendered.
8951:
8952: =item $colors: Array ref containing the hex color codes for the data to be
8953: plotted in. If undefined, default values will be used.
8954:
8955: =item $Xlabels: Array ref containing the labels to be used for the X-axis.
8956:
8957: =item $Ydata: Array ref containing Array refs.
1.185 www 8958: Each of the contained arrays will be plotted as a separate curve.
1.138 matthew 8959:
8960: =item %Values: hash indicating or overriding any default values which are
8961: passed to graph.png.
8962: Possible values are: width, xskip, x_ticks, x_tick_offset, among others.
8963:
8964: =back
8965:
8966: Returns:
8967:
8968: An <img> tag which references graph.png and the appropriate identifying
8969: information for the plot.
8970:
1.137 matthew 8971: =cut
8972:
8973: ############################################################
8974: ############################################################
8975: sub DrawXYGraph {
8976: my ($Title,$xlabel,$ylabel,$Max,$colors,$Xlabels,$Ydata,%Values)=@_;
8977: #
8978: # Create the identifier for the graph
8979: my $identifier = &get_cgi_id();
8980: my $id = 'cgi.'.$identifier;
8981: #
8982: $Title = '' if (! defined($Title));
8983: $xlabel = '' if (! defined($xlabel));
8984: $ylabel = '' if (! defined($ylabel));
8985: my %ValuesHash =
8986: (
1.369 www 8987: $id.'.title' => &escape($Title),
8988: $id.'.xlabel' => &escape($xlabel),
8989: $id.'.ylabel' => &escape($ylabel),
1.137 matthew 8990: $id.'.y_max_value'=> $Max,
8991: $id.'.labels' => join(',',@$Xlabels),
8992: $id.'.PlotType' => 'XY',
8993: );
8994: #
8995: if (defined($colors) && ref($colors) eq 'ARRAY') {
8996: $ValuesHash{$id.'.Colors'} = join(',',@{$colors});
8997: }
8998: #
8999: if (! ref($Ydata) || ref($Ydata) ne 'ARRAY') {
9000: return '';
9001: }
9002: my $NumSets=1;
1.138 matthew 9003: foreach my $array (@{$Ydata}){
1.137 matthew 9004: next if (! ref($array));
9005: $ValuesHash{$id.'.data.'.$NumSets++} = join(',',@$array);
9006: }
1.138 matthew 9007: $ValuesHash{$id.'.NumSets'} = $NumSets-1;
1.137 matthew 9008: #
9009: # Deal with other parameters
9010: while (my ($key,$value) = each(%Values)) {
9011: $ValuesHash{$id.'.'.$key} = $value;
1.127 matthew 9012: }
9013: #
1.646 raeburn 9014: &Apache::lonnet::appenv(\%ValuesHash);
1.136 matthew 9015: return '<img src="/cgi-bin/graph.png?'.$identifier.'" border="1" />';
9016: }
9017:
9018: ############################################################
9019: ############################################################
9020:
9021: =pod
9022:
1.648 raeburn 9023: =item * &DrawXYYGraph()
1.138 matthew 9024:
9025: Facilitates the plotting of data in an XY graph with two Y axes.
9026: Puts plot definition data into the users environment in order for
9027: graph.png to plot it. Returns an <img> tag for the plot.
9028:
9029: Inputs:
9030:
9031: =over 4
9032:
9033: =item $Title: string, the title of the plot
9034:
9035: =item $xlabel: string, text describing the X-axis of the plot
9036:
9037: =item $ylabel: string, text describing the Y-axis of the plot
9038:
9039: =item $colors: Array ref containing the hex color codes for the data to be
9040: plotted in. If undefined, default values will be used.
9041:
9042: =item $Xlabels: Array ref containing the labels to be used for the X-axis.
9043:
9044: =item $Ydata1: The first data set
9045:
9046: =item $Min1: The minimum value of the left Y-axis
9047:
9048: =item $Max1: The maximum value of the left Y-axis
9049:
9050: =item $Ydata2: The second data set
9051:
9052: =item $Min2: The minimum value of the right Y-axis
9053:
9054: =item $Max2: The maximum value of the left Y-axis
9055:
9056: =item %Values: hash indicating or overriding any default values which are
9057: passed to graph.png.
9058: Possible values are: width, xskip, x_ticks, x_tick_offset, among others.
9059:
9060: =back
9061:
9062: Returns:
9063:
9064: An <img> tag which references graph.png and the appropriate identifying
9065: information for the plot.
1.136 matthew 9066:
9067: =cut
9068:
9069: ############################################################
9070: ############################################################
1.137 matthew 9071: sub DrawXYYGraph {
9072: my ($Title,$xlabel,$ylabel,$colors,$Xlabels,$Ydata1,$Min1,$Max1,
9073: $Ydata2,$Min2,$Max2,%Values)=@_;
1.136 matthew 9074: #
9075: # Create the identifier for the graph
9076: my $identifier = &get_cgi_id();
9077: my $id = 'cgi.'.$identifier;
9078: #
9079: $Title = '' if (! defined($Title));
9080: $xlabel = '' if (! defined($xlabel));
9081: $ylabel = '' if (! defined($ylabel));
9082: my %ValuesHash =
9083: (
1.369 www 9084: $id.'.title' => &escape($Title),
9085: $id.'.xlabel' => &escape($xlabel),
9086: $id.'.ylabel' => &escape($ylabel),
1.136 matthew 9087: $id.'.labels' => join(',',@$Xlabels),
9088: $id.'.PlotType' => 'XY',
9089: $id.'.NumSets' => 2,
1.137 matthew 9090: $id.'.two_axes' => 1,
9091: $id.'.y1_max_value' => $Max1,
9092: $id.'.y1_min_value' => $Min1,
9093: $id.'.y2_max_value' => $Max2,
9094: $id.'.y2_min_value' => $Min2,
1.136 matthew 9095: );
9096: #
1.137 matthew 9097: if (defined($colors) && ref($colors) eq 'ARRAY') {
9098: $ValuesHash{$id.'.Colors'} = join(',',@{$colors});
9099: }
9100: #
9101: if (! ref($Ydata1) || ref($Ydata1) ne 'ARRAY' ||
9102: ! ref($Ydata2) || ref($Ydata2) ne 'ARRAY'){
1.136 matthew 9103: return '';
9104: }
9105: my $NumSets=1;
1.137 matthew 9106: foreach my $array ($Ydata1,$Ydata2){
1.136 matthew 9107: next if (! ref($array));
9108: $ValuesHash{$id.'.data.'.$NumSets++} = join(',',@$array);
1.137 matthew 9109: }
9110: #
9111: # Deal with other parameters
9112: while (my ($key,$value) = each(%Values)) {
9113: $ValuesHash{$id.'.'.$key} = $value;
1.136 matthew 9114: }
9115: #
1.646 raeburn 9116: &Apache::lonnet::appenv(\%ValuesHash);
1.130 albertel 9117: return '<img src="/cgi-bin/graph.png?'.$identifier.'" border="1" />';
1.139 matthew 9118: }
9119:
9120: ############################################################
9121: ############################################################
9122:
9123: =pod
9124:
1.157 matthew 9125: =back
9126:
1.139 matthew 9127: =head1 Statistics helper routines?
9128:
9129: Bad place for them but what the hell.
9130:
1.157 matthew 9131: =over 4
9132:
1.648 raeburn 9133: =item * &chartlink()
1.139 matthew 9134:
9135: Returns a link to the chart for a specific student.
9136:
9137: Inputs:
9138:
9139: =over 4
9140:
9141: =item $linktext: The text of the link
9142:
9143: =item $sname: The students username
9144:
9145: =item $sdomain: The students domain
9146:
9147: =back
9148:
1.157 matthew 9149: =back
9150:
1.139 matthew 9151: =cut
9152:
9153: ############################################################
9154: ############################################################
9155: sub chartlink {
9156: my ($linktext, $sname, $sdomain) = @_;
9157: my $link = '<a href="/adm/statistics?reportSelected=student_assessment'.
1.369 www 9158: '&SelectedStudent='.&escape($sname.':'.$sdomain).
1.219 albertel 9159: '&chartoutputmode='.HTML::Entities::encode('html, with all links').
1.139 matthew 9160: '">'.$linktext.'</a>';
1.153 matthew 9161: }
9162:
9163: #######################################################
9164: #######################################################
9165:
9166: =pod
9167:
9168: =head1 Course Environment Routines
1.157 matthew 9169:
9170: =over 4
1.153 matthew 9171:
1.648 raeburn 9172: =item * &restore_course_settings()
1.153 matthew 9173:
1.648 raeburn 9174: =item * &store_course_settings()
1.153 matthew 9175:
9176: Restores/Store indicated form parameters from the course environment.
9177: Will not overwrite existing values of the form parameters.
9178:
9179: Inputs:
9180: a scalar describing the data (e.g. 'chart', 'problem_analysis')
9181:
9182: a hash ref describing the data to be stored. For example:
9183:
9184: %Save_Parameters = ('Status' => 'scalar',
9185: 'chartoutputmode' => 'scalar',
9186: 'chartoutputdata' => 'scalar',
9187: 'Section' => 'array',
1.373 raeburn 9188: 'Group' => 'array',
1.153 matthew 9189: 'StudentData' => 'array',
9190: 'Maps' => 'array');
9191:
9192: Returns: both routines return nothing
9193:
1.631 raeburn 9194: =back
9195:
1.153 matthew 9196: =cut
9197:
9198: #######################################################
9199: #######################################################
9200: sub store_course_settings {
1.496 albertel 9201: return &store_settings($env{'request.course.id'},@_);
9202: }
9203:
9204: sub store_settings {
1.153 matthew 9205: # save to the environment
9206: # appenv the same items, just to be safe
1.300 albertel 9207: my $udom = $env{'user.domain'};
9208: my $uname = $env{'user.name'};
1.496 albertel 9209: my ($context,$prefix,$Settings) = @_;
1.153 matthew 9210: my %SaveHash;
9211: my %AppHash;
9212: while (my ($setting,$type) = each(%$Settings)) {
1.496 albertel 9213: my $basename = join('.','internal',$context,$prefix,$setting);
1.300 albertel 9214: my $envname = 'environment.'.$basename;
1.258 albertel 9215: if (exists($env{'form.'.$setting})) {
1.153 matthew 9216: # Save this value away
9217: if ($type eq 'scalar' &&
1.258 albertel 9218: (! exists($env{$envname}) ||
9219: $env{$envname} ne $env{'form.'.$setting})) {
9220: $SaveHash{$basename} = $env{'form.'.$setting};
9221: $AppHash{$envname} = $env{'form.'.$setting};
1.153 matthew 9222: } elsif ($type eq 'array') {
9223: my $stored_form;
1.258 albertel 9224: if (ref($env{'form.'.$setting})) {
1.153 matthew 9225: $stored_form = join(',',
9226: map {
1.369 www 9227: &escape($_);
1.258 albertel 9228: } sort(@{$env{'form.'.$setting}}));
1.153 matthew 9229: } else {
9230: $stored_form =
1.369 www 9231: &escape($env{'form.'.$setting});
1.153 matthew 9232: }
9233: # Determine if the array contents are the same.
1.258 albertel 9234: if ($stored_form ne $env{$envname}) {
1.153 matthew 9235: $SaveHash{$basename} = $stored_form;
9236: $AppHash{$envname} = $stored_form;
9237: }
9238: }
9239: }
9240: }
9241: my $put_result = &Apache::lonnet::put('environment',\%SaveHash,
1.300 albertel 9242: $udom,$uname);
1.153 matthew 9243: if ($put_result !~ /^(ok|delayed)/) {
9244: &Apache::lonnet::logthis('unable to save form parameters, '.
9245: 'got error:'.$put_result);
9246: }
9247: # Make sure these settings stick around in this session, too
1.646 raeburn 9248: &Apache::lonnet::appenv(\%AppHash);
1.153 matthew 9249: return;
9250: }
9251:
9252: sub restore_course_settings {
1.499 albertel 9253: return &restore_settings($env{'request.course.id'},@_);
1.496 albertel 9254: }
9255:
9256: sub restore_settings {
9257: my ($context,$prefix,$Settings) = @_;
1.153 matthew 9258: while (my ($setting,$type) = each(%$Settings)) {
1.258 albertel 9259: next if (exists($env{'form.'.$setting}));
1.496 albertel 9260: my $envname = 'environment.internal.'.$context.'.'.$prefix.
1.153 matthew 9261: '.'.$setting;
1.258 albertel 9262: if (exists($env{$envname})) {
1.153 matthew 9263: if ($type eq 'scalar') {
1.258 albertel 9264: $env{'form.'.$setting} = $env{$envname};
1.153 matthew 9265: } elsif ($type eq 'array') {
1.258 albertel 9266: $env{'form.'.$setting} = [
1.153 matthew 9267: map {
1.369 www 9268: &unescape($_);
1.258 albertel 9269: } split(',',$env{$envname})
1.153 matthew 9270: ];
9271: }
9272: }
9273: }
1.127 matthew 9274: }
9275:
1.618 raeburn 9276: #######################################################
9277: #######################################################
9278:
9279: =pod
9280:
9281: =head1 Domain E-mail Routines
9282:
9283: =over 4
9284:
1.648 raeburn 9285: =item * &build_recipient_list()
1.618 raeburn 9286:
1.766 raeburn 9287: Build recipient lists for four types of e-mail:
9288: (a) Error Reports, (b) Package Updates, (c) lonstatus warnings/errors
9289: (d) Help requests, generated by
9290: lonerrorhandler.pm, CHECKRPMS, loncron, and lonsupportreq.pm respectively.
1.618 raeburn 9291:
9292: Inputs:
1.619 raeburn 9293: defmail (scalar - email address of default recipient),
1.618 raeburn 9294: mailing type (scalar - errormail, packagesmail, or helpdeskmail),
1.619 raeburn 9295: defdom (domain for which to retrieve configuration settings),
9296: origmail (scalar - email address of recipient from loncapa.conf,
9297: i.e., predates configuration by DC via domainprefs.pm
1.618 raeburn 9298:
1.655 raeburn 9299: Returns: comma separated list of addresses to which to send e-mail.
9300:
9301: =back
1.618 raeburn 9302:
9303: =cut
9304:
9305: ############################################################
9306: ############################################################
9307: sub build_recipient_list {
1.619 raeburn 9308: my ($defmail,$mailing,$defdom,$origmail) = @_;
1.618 raeburn 9309: my @recipients;
9310: my $otheremails;
9311: my %domconfig =
9312: &Apache::lonnet::get_dom('configuration',['contacts'],$defdom);
9313: if (ref($domconfig{'contacts'}) eq 'HASH') {
1.766 raeburn 9314: if (exists($domconfig{'contacts'}{$mailing})) {
9315: if (ref($domconfig{'contacts'}{$mailing}) eq 'HASH') {
9316: my @contacts = ('adminemail','supportemail');
9317: foreach my $item (@contacts) {
9318: if ($domconfig{'contacts'}{$mailing}{$item}) {
9319: my $addr = $domconfig{'contacts'}{$item};
9320: if (!grep(/^\Q$addr\E$/,@recipients)) {
9321: push(@recipients,$addr);
9322: }
1.619 raeburn 9323: }
1.766 raeburn 9324: $otheremails = $domconfig{'contacts'}{$mailing}{'others'};
1.618 raeburn 9325: }
9326: }
1.766 raeburn 9327: } elsif ($origmail ne '') {
9328: push(@recipients,$origmail);
1.618 raeburn 9329: }
1.619 raeburn 9330: } elsif ($origmail ne '') {
9331: push(@recipients,$origmail);
1.618 raeburn 9332: }
1.688 raeburn 9333: if (defined($defmail)) {
9334: if ($defmail ne '') {
9335: push(@recipients,$defmail);
9336: }
1.618 raeburn 9337: }
9338: if ($otheremails) {
1.619 raeburn 9339: my @others;
9340: if ($otheremails =~ /,/) {
9341: @others = split(/,/,$otheremails);
1.618 raeburn 9342: } else {
1.619 raeburn 9343: push(@others,$otheremails);
9344: }
9345: foreach my $addr (@others) {
9346: if (!grep(/^\Q$addr\E$/,@recipients)) {
9347: push(@recipients,$addr);
9348: }
1.618 raeburn 9349: }
9350: }
1.619 raeburn 9351: my $recipientlist = join(',',@recipients);
1.618 raeburn 9352: return $recipientlist;
9353: }
9354:
1.127 matthew 9355: ############################################################
9356: ############################################################
1.154 albertel 9357:
1.655 raeburn 9358: =pod
9359:
9360: =head1 Course Catalog Routines
9361:
9362: =over 4
9363:
9364: =item * &gather_categories()
9365:
9366: Converts category definitions - keys of categories hash stored in
9367: coursecategories in configuration.db on the primary library server in a
9368: domain - to an array. Also generates javascript and idx hash used to
9369: generate Domain Coordinator interface for editing Course Categories.
9370:
9371: Inputs:
1.663 raeburn 9372:
1.655 raeburn 9373: categories (reference to hash of category definitions).
1.663 raeburn 9374:
1.655 raeburn 9375: cats (reference to array of arrays/hashes which encapsulates hierarchy of
9376: categories and subcategories).
1.663 raeburn 9377:
1.655 raeburn 9378: idx (reference to hash of counters used in Domain Coordinator interface for
9379: editing Course Categories).
1.663 raeburn 9380:
1.655 raeburn 9381: jsarray (reference to array of categories used to create Javascript arrays for
9382: Domain Coordinator interface for editing Course Categories).
9383:
9384: Returns: nothing
9385:
9386: Side effects: populates cats, idx and jsarray.
9387:
9388: =cut
9389:
9390: sub gather_categories {
9391: my ($categories,$cats,$idx,$jsarray) = @_;
9392: my %counters;
9393: my $num = 0;
9394: foreach my $item (keys(%{$categories})) {
9395: my ($cat,$container,$depth) = map { &unescape($_); } split(/:/,$item);
9396: if ($container eq '' && $depth == 0) {
9397: $cats->[$depth][$categories->{$item}] = $cat;
9398: } else {
9399: $cats->[$depth]{$container}[$categories->{$item}] = $cat;
9400: }
9401: my ($escitem,$tail) = split(/:/,$item,2);
9402: if ($counters{$tail} eq '') {
9403: $counters{$tail} = $num;
9404: $num ++;
9405: }
9406: if (ref($idx) eq 'HASH') {
9407: $idx->{$item} = $counters{$tail};
9408: }
9409: if (ref($jsarray) eq 'ARRAY') {
9410: push(@{$jsarray->[$counters{$tail}]},$item);
9411: }
9412: }
9413: return;
9414: }
9415:
9416: =pod
9417:
9418: =item * &extract_categories()
9419:
9420: Used to generate breadcrumb trails for course categories.
9421:
9422: Inputs:
1.663 raeburn 9423:
1.655 raeburn 9424: categories (reference to hash of category definitions).
1.663 raeburn 9425:
1.655 raeburn 9426: cats (reference to array of arrays/hashes which encapsulates hierarchy of
9427: categories and subcategories).
1.663 raeburn 9428:
1.655 raeburn 9429: trails (reference to array of breacrumb trails for each category).
1.663 raeburn 9430:
1.655 raeburn 9431: allitems (reference to hash - key is category key
9432: (format: escaped(name):escaped(parent category):depth in hierarchy).
1.663 raeburn 9433:
1.655 raeburn 9434: idx (reference to hash of counters used in Domain Coordinator interface for
9435: editing Course Categories).
1.663 raeburn 9436:
1.655 raeburn 9437: jsarray (reference to array of categories used to create Javascript arrays for
9438: Domain Coordinator interface for editing Course Categories).
9439:
1.665 raeburn 9440: subcats (reference to hash of arrays containing all subcategories within each
9441: category, -recursive)
9442:
1.655 raeburn 9443: Returns: nothing
9444:
9445: Side effects: populates trails and allitems hash references.
9446:
9447: =cut
9448:
9449: sub extract_categories {
1.665 raeburn 9450: my ($categories,$cats,$trails,$allitems,$idx,$jsarray,$subcats) = @_;
1.655 raeburn 9451: if (ref($categories) eq 'HASH') {
9452: &gather_categories($categories,$cats,$idx,$jsarray);
9453: if (ref($cats->[0]) eq 'ARRAY') {
9454: for (my $i=0; $i<@{$cats->[0]}; $i++) {
9455: my $name = $cats->[0][$i];
9456: my $item = &escape($name).'::0';
9457: my $trailstr;
9458: if ($name eq 'instcode') {
9459: $trailstr = &mt('Official courses (with institutional codes)');
9460: } else {
9461: $trailstr = $name;
9462: }
9463: if ($allitems->{$item} eq '') {
9464: push(@{$trails},$trailstr);
9465: $allitems->{$item} = scalar(@{$trails})-1;
9466: }
9467: my @parents = ($name);
9468: if (ref($cats->[1]{$name}) eq 'ARRAY') {
9469: for (my $j=0; $j<@{$cats->[1]{$name}}; $j++) {
9470: my $category = $cats->[1]{$name}[$j];
1.665 raeburn 9471: if (ref($subcats) eq 'HASH') {
9472: push(@{$subcats->{$item}},&escape($category).':'.&escape($name).':1');
9473: }
9474: &recurse_categories($cats,2,$category,$trails,$allitems,\@parents,$subcats);
9475: }
9476: } else {
9477: if (ref($subcats) eq 'HASH') {
9478: $subcats->{$item} = [];
1.655 raeburn 9479: }
9480: }
9481: }
9482: }
9483: }
9484: return;
9485: }
9486:
9487: =pod
9488:
9489: =item *&recurse_categories()
9490:
9491: Recursively used to generate breadcrumb trails for course categories.
9492:
9493: Inputs:
1.663 raeburn 9494:
1.655 raeburn 9495: cats (reference to array of arrays/hashes which encapsulates hierarchy of
9496: categories and subcategories).
1.663 raeburn 9497:
1.655 raeburn 9498: depth (current depth in hierarchy of categories and sub-categories - 0 indexed).
1.663 raeburn 9499:
9500: category (current course category, for which breadcrumb trail is being generated).
9501:
9502: trails (reference to array of breadcrumb trails for each category).
9503:
1.655 raeburn 9504: allitems (reference to hash - key is category key
9505: (format: escaped(name):escaped(parent category):depth in hierarchy).
1.663 raeburn 9506:
1.655 raeburn 9507: parents (array containing containers directories for current category,
9508: back to top level).
9509:
9510: Returns: nothing
9511:
9512: Side effects: populates trails and allitems hash references
9513:
9514: =cut
9515:
9516: sub recurse_categories {
1.665 raeburn 9517: my ($cats,$depth,$category,$trails,$allitems,$parents,$subcats) = @_;
1.655 raeburn 9518: my $shallower = $depth - 1;
9519: if (ref($cats->[$depth]{$category}) eq 'ARRAY') {
9520: for (my $k=0; $k<@{$cats->[$depth]{$category}}; $k++) {
9521: my $name = $cats->[$depth]{$category}[$k];
9522: my $item = &escape($category).':'.&escape($parents->[-1]).':'.$shallower;
9523: my $trailstr = join(' -> ',(@{$parents},$category));
9524: if ($allitems->{$item} eq '') {
9525: push(@{$trails},$trailstr);
9526: $allitems->{$item} = scalar(@{$trails})-1;
9527: }
9528: my $deeper = $depth+1;
9529: push(@{$parents},$category);
1.665 raeburn 9530: if (ref($subcats) eq 'HASH') {
9531: my $subcat = &escape($name).':'.$category.':'.$depth;
9532: for (my $j=@{$parents}; $j>=0; $j--) {
9533: my $higher;
9534: if ($j > 0) {
9535: $higher = &escape($parents->[$j]).':'.
9536: &escape($parents->[$j-1]).':'.$j;
9537: } else {
9538: $higher = &escape($parents->[$j]).'::'.$j;
9539: }
9540: push(@{$subcats->{$higher}},$subcat);
9541: }
9542: }
9543: &recurse_categories($cats,$deeper,$name,$trails,$allitems,$parents,
9544: $subcats);
1.655 raeburn 9545: pop(@{$parents});
9546: }
9547: } else {
9548: my $item = &escape($category).':'.&escape($parents->[-1]).':'.$shallower;
9549: my $trailstr = join(' -> ',(@{$parents},$category));
9550: if ($allitems->{$item} eq '') {
9551: push(@{$trails},$trailstr);
9552: $allitems->{$item} = scalar(@{$trails})-1;
9553: }
9554: }
9555: return;
9556: }
9557:
1.663 raeburn 9558: =pod
9559:
9560: =item *&assign_categories_table()
9561:
9562: Create a datatable for display of hierarchical categories in a domain,
9563: with checkboxes to allow a course to be categorized.
9564:
9565: Inputs:
9566:
9567: cathash - reference to hash of categories defined for the domain (from
9568: configuration.db)
9569:
9570: currcat - scalar with an & separated list of categories assigned to a course.
9571:
9572: Returns: $output (markup to be displayed)
9573:
9574: =cut
9575:
9576: sub assign_categories_table {
9577: my ($cathash,$currcat) = @_;
9578: my $output;
9579: if (ref($cathash) eq 'HASH') {
9580: my (@cats,@trails,%allitems,%idx,@jsarray,@path,$maxdepth);
9581: &extract_categories($cathash,\@cats,\@trails,\%allitems,\%idx,\@jsarray);
9582: $maxdepth = scalar(@cats);
9583: if (@cats > 0) {
9584: my $itemcount = 0;
9585: if (ref($cats[0]) eq 'ARRAY') {
9586: $output = &Apache::loncommon::start_data_table();
9587: my @currcategories;
9588: if ($currcat ne '') {
9589: @currcategories = split('&',$currcat);
9590: }
9591: for (my $i=0; $i<@{$cats[0]}; $i++) {
9592: my $parent = $cats[0][$i];
9593: my $css_class = $itemcount%2?' class="LC_odd_row"':'';
9594: next if ($parent eq 'instcode');
9595: my $item = &escape($parent).'::0';
9596: my $checked = '';
9597: if (@currcategories > 0) {
9598: if (grep(/^\Q$item\E$/,@currcategories)) {
1.772 bisitz 9599: $checked = ' checked="checked"';
1.663 raeburn 9600: }
9601: }
1.675 raeburn 9602: $output .= '<tr '.$css_class.'><td><span class="LC_nobreak">'.
9603: '<input type="checkbox" name="usecategory" value="'.
9604: $item.'"'.$checked.' />'.$parent.'</span>'.
9605: '<input type="hidden" name="catname" value="'.$parent.'" /></td>';
1.663 raeburn 9606: my $depth = 1;
9607: push(@path,$parent);
9608: $output .= &assign_category_rows($itemcount,\@cats,$depth,$parent,\@path,\@currcategories);
9609: pop(@path);
9610: $output .= '</tr><tr><td colspan="'.$maxdepth.'" class="LC_row_separator"></td></tr>';
9611: $itemcount ++;
9612: }
9613: $output .= &Apache::loncommon::end_data_table();
9614: }
9615: }
9616: }
9617: return $output;
9618: }
9619:
9620: =pod
9621:
9622: =item *&assign_category_rows()
9623:
9624: Create a datatable row for display of nested categories in a domain,
9625: with checkboxes to allow a course to be categorized,called recursively.
9626:
9627: Inputs:
9628:
9629: itemcount - track row number for alternating colors
9630:
9631: cats - reference to array of arrays/hashes which encapsulates hierarchy of
9632: categories and subcategories.
9633:
9634: depth - current depth in hierarchy of categories and sub-categories - 0 indexed.
9635:
9636: parent - parent of current category item
9637:
9638: path - Array containing all categories back up through the hierarchy from the
9639: current category to the top level.
9640:
9641: currcategories - reference to array of current categories assigned to the course
9642:
9643: Returns: $output (markup to be displayed).
9644:
9645: =cut
9646:
9647: sub assign_category_rows {
9648: my ($itemcount,$cats,$depth,$parent,$path,$currcategories) = @_;
9649: my ($text,$name,$item,$chgstr);
9650: if (ref($cats) eq 'ARRAY') {
9651: my $maxdepth = scalar(@{$cats});
9652: if (ref($cats->[$depth]) eq 'HASH') {
9653: if (ref($cats->[$depth]{$parent}) eq 'ARRAY') {
9654: my $numchildren = @{$cats->[$depth]{$parent}};
9655: my $css_class = $itemcount%2?' class="LC_odd_row"':'';
9656: $text .= '<td><table class="LC_datatable">';
9657: for (my $j=0; $j<$numchildren; $j++) {
9658: $name = $cats->[$depth]{$parent}[$j];
9659: $item = &escape($name).':'.&escape($parent).':'.$depth;
9660: my $deeper = $depth+1;
9661: my $checked = '';
9662: if (ref($currcategories) eq 'ARRAY') {
9663: if (@{$currcategories} > 0) {
9664: if (grep(/^\Q$item\E$/,@{$currcategories})) {
1.772 bisitz 9665: $checked = ' checked="checked"';
1.663 raeburn 9666: }
9667: }
9668: }
1.664 raeburn 9669: $text .= '<tr><td><span class="LC_nobreak"><label>'.
9670: '<input type="checkbox" name="usecategory" value="'.
1.675 raeburn 9671: $item.'"'.$checked.' />'.$name.'</label></span>'.
9672: '<input type="hidden" name="catname" value="'.$name.'" />'.
9673: '</td><td>';
1.663 raeburn 9674: if (ref($path) eq 'ARRAY') {
9675: push(@{$path},$name);
9676: $text .= &assign_category_rows($itemcount,$cats,$deeper,$name,$path,$currcategories);
9677: pop(@{$path});
9678: }
9679: $text .= '</td></tr>';
9680: }
9681: $text .= '</table></td>';
9682: }
9683: }
9684: }
9685: return $text;
9686: }
9687:
1.655 raeburn 9688: ############################################################
9689: ############################################################
9690:
9691:
1.443 albertel 9692: sub commit_customrole {
1.664 raeburn 9693: my ($udom,$uname,$url,$three,$four,$five,$start,$end,$context) = @_;
1.630 raeburn 9694: my $output = &mt('Assigning custom role').' "'.$five.'" by '.$four.':'.$three.' in '.$url.
1.443 albertel 9695: ($start?', '.&mt('starting').' '.localtime($start):'').
9696: ($end?', ending '.localtime($end):'').': <b>'.
9697: &Apache::lonnet::assigncustomrole(
1.664 raeburn 9698: $udom,$uname,$url,$three,$four,$five,$end,$start,undef,undef,$context).
1.443 albertel 9699: '</b><br />';
9700: return $output;
9701: }
9702:
9703: sub commit_standardrole {
1.541 raeburn 9704: my ($udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context) = @_;
9705: my ($output,$logmsg,$linefeed);
9706: if ($context eq 'auto') {
9707: $linefeed = "\n";
9708: } else {
9709: $linefeed = "<br />\n";
9710: }
1.443 albertel 9711: if ($three eq 'st') {
1.541 raeburn 9712: my $result = &commit_studentrole(\$logmsg,$udom,$uname,$url,$three,$start,$end,
9713: $one,$two,$sec,$context);
9714: if (($result =~ /^error/) || ($result eq 'not_in_class') ||
1.626 raeburn 9715: ($result eq 'unknown_course') || ($result eq 'refused')) {
9716: $output = $logmsg.' '.&mt('Error: ').$result."\n";
1.443 albertel 9717: } else {
1.541 raeburn 9718: $output = $logmsg.$linefeed.&mt('Assigning').' '.$three.' in '.$url.
1.443 albertel 9719: ($start?', '.&mt('starting').' '.localtime($start):'').
1.541 raeburn 9720: ($end?', '.&mt('ending').' '.localtime($end):'').': ';
9721: if ($context eq 'auto') {
9722: $output .= $result.$linefeed.&mt('Add to classlist').': ok';
9723: } else {
9724: $output .= '<b>'.$result.'</b>'.$linefeed.
9725: &mt('Add to classlist').': <b>ok</b>';
9726: }
9727: $output .= $linefeed;
1.443 albertel 9728: }
9729: } else {
9730: $output = &mt('Assigning').' '.$three.' in '.$url.
9731: ($start?', '.&mt('starting').' '.localtime($start):'').
1.541 raeburn 9732: ($end?', '.&mt('ending').' '.localtime($end):'').': ';
1.652 raeburn 9733: my $result = &Apache::lonnet::assignrole($udom,$uname,$url,$three,$end,$start,'','',$context);
1.541 raeburn 9734: if ($context eq 'auto') {
9735: $output .= $result.$linefeed;
9736: } else {
9737: $output .= '<b>'.$result.'</b>'.$linefeed;
9738: }
1.443 albertel 9739: }
9740: return $output;
9741: }
9742:
9743: sub commit_studentrole {
1.541 raeburn 9744: my ($logmsg,$udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context) = @_;
1.626 raeburn 9745: my ($result,$linefeed,$oldsecurl,$newsecurl);
1.541 raeburn 9746: if ($context eq 'auto') {
9747: $linefeed = "\n";
9748: } else {
9749: $linefeed = '<br />'."\n";
9750: }
1.443 albertel 9751: if (defined($one) && defined($two)) {
9752: my $cid=$one.'_'.$two;
9753: my $oldsec=&Apache::lonnet::getsection($udom,$uname,$cid);
9754: my $secchange = 0;
9755: my $expire_role_result;
9756: my $modify_section_result;
1.628 raeburn 9757: if ($oldsec ne '-1') {
9758: if ($oldsec ne $sec) {
1.443 albertel 9759: $secchange = 1;
1.628 raeburn 9760: my $now = time;
1.443 albertel 9761: my $uurl='/'.$cid;
9762: $uurl=~s/\_/\//g;
9763: if ($oldsec) {
9764: $uurl.='/'.$oldsec;
9765: }
1.626 raeburn 9766: $oldsecurl = $uurl;
1.628 raeburn 9767: $expire_role_result =
1.652 raeburn 9768: &Apache::lonnet::assignrole($udom,$uname,$uurl,'st',$now,'','',$context);
1.628 raeburn 9769: if ($env{'request.course.sec'} ne '') {
9770: if ($expire_role_result eq 'refused') {
9771: my @roles = ('st');
9772: my @statuses = ('previous');
9773: my @roledoms = ($one);
9774: my $withsec = 1;
9775: my %roleshash =
9776: &Apache::lonnet::get_my_roles($uname,$udom,'userroles',
9777: \@statuses,\@roles,\@roledoms,$withsec);
9778: if (defined ($roleshash{$two.':'.$one.':st:'.$oldsec})) {
9779: my ($oldstart,$oldend) =
9780: split(':',$roleshash{$two.':'.$one.':st:'.$oldsec});
9781: if ($oldend > 0 && $oldend <= $now) {
9782: $expire_role_result = 'ok';
9783: }
9784: }
9785: }
9786: }
1.443 albertel 9787: $result = $expire_role_result;
9788: }
9789: }
9790: if (($expire_role_result eq 'ok') || ($secchange == 0)) {
1.652 raeburn 9791: $modify_section_result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,'','',$cid,'',$context);
1.443 albertel 9792: if ($modify_section_result =~ /^ok/) {
9793: if ($secchange == 1) {
1.628 raeburn 9794: if ($sec eq '') {
9795: $$logmsg .= &mt('Section for [_1] switched from (possibly expired) old section: [_2] to student role without a section.',$uname,$oldsec).$linefeed;
9796: } else {
9797: $$logmsg .= &mt('Section for [_1] switched from (possibly expired) old section: [_2] to new section: [_3].',$uname,$oldsec,$sec).$linefeed;
9798: }
1.443 albertel 9799: } elsif ($oldsec eq '-1') {
1.628 raeburn 9800: if ($sec eq '') {
9801: $$logmsg .= &mt('New student role without a section for [_1] in course [_2].',$uname,$cid).$linefeed;
9802: } else {
9803: $$logmsg .= &mt('New student role for [_1] in section [_2] in course [_3].',$uname,$sec,$cid).$linefeed;
9804: }
1.443 albertel 9805: } else {
1.628 raeburn 9806: if ($sec eq '') {
9807: $$logmsg .= &mt('Student [_1] assigned to course [_2] without a section.',$uname,$cid).$linefeed;
9808: } else {
9809: $$logmsg .= &mt('Student [_1] assigned to section [_2] in course [_3].',$uname,$sec,$cid).$linefeed;
9810: }
1.443 albertel 9811: }
9812: } else {
1.628 raeburn 9813: if ($secchange) {
9814: $$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;
9815: } else {
9816: $$logmsg .= &mt('Error when attempting to modify role for [_1] for section: "[_2]" in course [_3] -error:',$uname,$sec,$cid).' '.$modify_section_result.$linefeed;
9817: }
1.443 albertel 9818: }
9819: $result = $modify_section_result;
9820: } elsif ($secchange == 1) {
1.628 raeburn 9821: if ($oldsec eq '') {
9822: $$logmsg .= &mt('Error when attempting to expire existing role without a section for [_1] in course [_3] -error: ',$uname,$cid).' '.$expire_role_result.$linefeed;
9823: } else {
9824: $$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;
9825: }
1.626 raeburn 9826: if ($expire_role_result eq 'refused') {
9827: my $newsecurl = '/'.$cid;
9828: $newsecurl =~ s/\_/\//g;
9829: if ($sec ne '') {
9830: $newsecurl.='/'.$sec;
9831: }
9832: if (&Apache::lonnet::allowed('cst',$newsecurl) && !(&Apache::lonnet::allowed('cst',$oldsecurl))) {
9833: if ($sec eq '') {
9834: $$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;
9835: } else {
9836: $$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;
9837: }
9838: }
9839: }
1.443 albertel 9840: }
9841: } else {
1.626 raeburn 9842: $$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 9843: $result = "error: incomplete course id\n";
9844: }
9845: return $result;
9846: }
9847:
9848: ############################################################
9849: ############################################################
9850:
1.566 albertel 9851: sub check_clone {
1.578 raeburn 9852: my ($args,$linefeed) = @_;
1.566 albertel 9853: my $cloneid='/'.$args->{'clonedomain'}.'/'.$args->{'clonecourse'};
9854: my ($clonecrsudom,$clonecrsunum)= &LONCAPA::split_courseid($cloneid);
9855: my $clonehome=&Apache::lonnet::homeserver($clonecrsunum,$clonecrsudom);
9856: my $clonemsg;
9857: my $can_clone = 0;
9858:
9859: if ($clonehome eq 'no_host') {
1.578 raeburn 9860: $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'});
1.566 albertel 9861: } else {
9862: my %clonedesc = &Apache::lonnet::coursedescription($cloneid,{'one_time' => 1});
1.882 ! raeburn 9863: if (($env{'request.role.domain'} eq $args->{'clonedomain'}) &&
! 9864: (&Apache::lonnet::allowed('ccc',$env{'request.role.domain'}))) {
1.566 albertel 9865: $can_clone = 1;
9866: } else {
9867: my %clonehash = &Apache::lonnet::get('environment',['cloners'],
9868: $args->{'clonedomain'},$args->{'clonecourse'});
9869: my @cloners = split(/,/,$clonehash{'cloners'});
1.578 raeburn 9870: if (grep(/^\*$/,@cloners)) {
9871: $can_clone = 1;
9872: } elsif (grep(/^\*\:\Q$args->{'ccdomain'}\E$/,@cloners)) {
9873: $can_clone = 1;
9874: } else {
9875: my %roleshash =
9876: &Apache::lonnet::get_my_roles($args->{'ccuname'},
9877: $args->{'ccdomain'},
9878: 'userroles',['active'],['cc'],
9879: [$args->{'clonedomain'}]);
9880: if (($roleshash{$args->{'clonecourse'}.':'.$args->{'clonedomain'}.':cc'}) || (grep(/^\Q$args->{'ccuname'}\E:\Q$args->{'ccdomain'}\E$/,@cloners))) {
9881: $can_clone = 1;
9882: } else {
9883: $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'});
9884: }
1.566 albertel 9885: }
1.578 raeburn 9886: }
1.566 albertel 9887: }
9888: return ($can_clone, $clonemsg, $cloneid, $clonehome);
9889: }
9890:
1.444 albertel 9891: sub construct_course {
1.882 ! raeburn 9892: my ($args,$logmsg,$courseid,$crsudom,$crsunum,$udom,$uname,$context,$cnum) = @_;
1.444 albertel 9893: my $outcome;
1.541 raeburn 9894: my $linefeed = '<br />'."\n";
9895: if ($context eq 'auto') {
9896: $linefeed = "\n";
9897: }
1.566 albertel 9898:
9899: #
9900: # Are we cloning?
9901: #
9902: my ($can_clone, $clonemsg, $cloneid, $clonehome);
9903: if (($args->{'clonecourse'}) && ($args->{'clonedomain'})) {
1.578 raeburn 9904: ($can_clone, $clonemsg, $cloneid, $clonehome) = &check_clone($args,$linefeed);
1.566 albertel 9905: if ($context ne 'auto') {
1.578 raeburn 9906: if ($clonemsg ne '') {
9907: $clonemsg = '<span class="LC_error">'.$clonemsg.'</span>';
9908: }
1.566 albertel 9909: }
9910: $outcome .= $clonemsg.$linefeed;
9911:
9912: if (!$can_clone) {
9913: return (0,$outcome);
9914: }
9915: }
9916:
1.444 albertel 9917: #
9918: # Open course
9919: #
9920: my $crstype = lc($args->{'crstype'});
9921: my %cenv=();
9922: $$courseid=&Apache::lonnet::createcourse($args->{'course_domain'},
9923: $args->{'cdescr'},
9924: $args->{'curl'},
9925: $args->{'course_home'},
9926: $args->{'nonstandard'},
9927: $args->{'crscode'},
9928: $args->{'ccuname'}.':'.
9929: $args->{'ccdomain'},
1.882 ! raeburn 9930: $args->{'crstype'},
! 9931: $cnum);
1.444 albertel 9932:
9933: # Note: The testing routines depend on this being output; see
9934: # Utils::Course. This needs to at least be output as a comment
9935: # if anyone ever decides to not show this, and Utils::Course::new
9936: # will need to be suitably modified.
1.541 raeburn 9937: $outcome .= &mt('New LON-CAPA [_1] ID: [_2]',$crstype,$$courseid).$linefeed;
1.444 albertel 9938: #
9939: # Check if created correctly
9940: #
1.479 albertel 9941: ($$crsudom,$$crsunum)= &LONCAPA::split_courseid($$courseid);
1.444 albertel 9942: my $crsuhome=&Apache::lonnet::homeserver($$crsunum,$$crsudom);
1.541 raeburn 9943: $outcome .= &mt('Created on').': '.$crsuhome.$linefeed;
1.566 albertel 9944:
1.444 albertel 9945: #
1.566 albertel 9946: # Do the cloning
9947: #
9948: if ($can_clone && $cloneid) {
9949: $clonemsg = &mt('Cloning [_1] from [_2]',$crstype,$clonehome);
9950: if ($context ne 'auto') {
9951: $clonemsg = '<span class="LC_success">'.$clonemsg.'</span>';
9952: }
9953: $outcome .= $clonemsg.$linefeed;
9954: my %oldcenv=&Apache::lonnet::dump('environment',$$crsudom,$$crsunum);
1.444 albertel 9955: # Copy all files
1.637 www 9956: &Apache::lonclonecourse::copycoursefiles($cloneid,$$courseid,$args->{'datemode'},$args->{'dateshift'});
1.444 albertel 9957: # Restore URL
1.566 albertel 9958: $cenv{'url'}=$oldcenv{'url'};
1.444 albertel 9959: # Restore title
1.566 albertel 9960: $cenv{'description'}=$oldcenv{'description'};
1.444 albertel 9961: # Mark as cloned
1.566 albertel 9962: $cenv{'clonedfrom'}=$cloneid;
1.638 www 9963: # Need to clone grading mode
9964: my %newenv=&Apache::lonnet::get('environment',['grading'],$$crsudom,$$crsunum);
9965: $cenv{'grading'}=$newenv{'grading'};
9966: # Do not clone these environment entries
9967: &Apache::lonnet::del('environment',
9968: ['default_enrollment_start_date',
9969: 'default_enrollment_end_date',
9970: 'question.email',
9971: 'policy.email',
9972: 'comment.email',
9973: 'pch.users.denied',
1.725 raeburn 9974: 'plc.users.denied',
9975: 'hidefromcat',
9976: 'categories'],
1.638 www 9977: $$crsudom,$$crsunum);
1.444 albertel 9978: }
1.566 albertel 9979:
1.444 albertel 9980: #
9981: # Set environment (will override cloned, if existing)
9982: #
9983: my @sections = ();
9984: my @xlists = ();
9985: if ($args->{'crstype'}) {
9986: $cenv{'type'}=$args->{'crstype'};
9987: }
9988: if ($args->{'crsid'}) {
9989: $cenv{'courseid'}=$args->{'crsid'};
9990: }
9991: if ($args->{'crscode'}) {
9992: $cenv{'internal.coursecode'}=$args->{'crscode'};
9993: }
9994: if ($args->{'crsquota'} ne '') {
9995: $cenv{'internal.coursequota'}=$args->{'crsquota'};
9996: } else {
9997: $cenv{'internal.coursequota'}=$args->{'crsquota'} = 20;
9998: }
9999: if ($args->{'ccuname'}) {
10000: $cenv{'internal.courseowner'} = $args->{'ccuname'}.
10001: ':'.$args->{'ccdomain'};
10002: } else {
10003: $cenv{'internal.courseowner'} = $args->{'curruser'};
10004: }
10005: my @badclasses = (); # Used to accumulate sections/crosslistings that did not pass classlist access check for course owner.
10006: if ($args->{'crssections'}) {
10007: $cenv{'internal.sectionnums'} = '';
10008: if ($args->{'crssections'} =~ m/,/) {
10009: @sections = split/,/,$args->{'crssections'};
10010: } else {
10011: $sections[0] = $args->{'crssections'};
10012: }
10013: if (@sections > 0) {
10014: foreach my $item (@sections) {
10015: my ($sec,$gp) = split/:/,$item;
10016: my $class = $args->{'crscode'}.$sec;
10017: my $addcheck = &Apache::lonnet::auto_new_course($$crsunum,$$crsudom,$class,$cenv{'internal.courseowner'});
10018: $cenv{'internal.sectionnums'} .= $item.',';
10019: unless ($addcheck eq 'ok') {
10020: push @badclasses, $class;
10021: }
10022: }
10023: $cenv{'internal.sectionnums'} =~ s/,$//;
10024: }
10025: }
10026: # do not hide course coordinator from staff listing,
10027: # even if privileged
10028: $cenv{'nothideprivileged'}=$args->{'ccuname'}.':'.$args->{'ccdomain'};
10029: # add crosslistings
10030: if ($args->{'crsxlist'}) {
10031: $cenv{'internal.crosslistings'}='';
10032: if ($args->{'crsxlist'} =~ m/,/) {
10033: @xlists = split/,/,$args->{'crsxlist'};
10034: } else {
10035: $xlists[0] = $args->{'crsxlist'};
10036: }
10037: if (@xlists > 0) {
10038: foreach my $item (@xlists) {
10039: my ($xl,$gp) = split/:/,$item;
10040: my $addcheck = &Apache::lonnet::auto_new_course($$crsunum,$$crsudom,$xl,$cenv{'internal.courseowner'});
10041: $cenv{'internal.crosslistings'} .= $item.',';
10042: unless ($addcheck eq 'ok') {
10043: push @badclasses, $xl;
10044: }
10045: }
10046: $cenv{'internal.crosslistings'} =~ s/,$//;
10047: }
10048: }
10049: if ($args->{'autoadds'}) {
10050: $cenv{'internal.autoadds'}=$args->{'autoadds'};
10051: }
10052: if ($args->{'autodrops'}) {
10053: $cenv{'internal.autodrops'}=$args->{'autodrops'};
10054: }
10055: # check for notification of enrollment changes
10056: my @notified = ();
10057: if ($args->{'notify_owner'}) {
10058: if ($args->{'ccuname'} ne '') {
10059: push(@notified,$args->{'ccuname'}.':'.$args->{'ccdomain'});
10060: }
10061: }
10062: if ($args->{'notify_dc'}) {
10063: if ($uname ne '') {
1.630 raeburn 10064: push(@notified,$uname.':'.$udom);
1.444 albertel 10065: }
10066: }
10067: if (@notified > 0) {
10068: my $notifylist;
10069: if (@notified > 1) {
10070: $notifylist = join(',',@notified);
10071: } else {
10072: $notifylist = $notified[0];
10073: }
10074: $cenv{'internal.notifylist'} = $notifylist;
10075: }
10076: if (@badclasses > 0) {
10077: my %lt=&Apache::lonlocal::texthash(
10078: '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',
10079: 'dnhr' => 'does not have rights to access enrollment in these classes',
10080: 'adby' => 'as determined by the policies of your institution on access to official classlists'
10081: );
1.541 raeburn 10082: my $badclass_msg = $cenv{'internal.courseowner'}.') - '.$lt{'dnhr'}.
10083: ' ('.$lt{'adby'}.')';
10084: if ($context eq 'auto') {
10085: $outcome .= $badclass_msg.$linefeed;
1.566 albertel 10086: $outcome .= '<div class="LC_warning">'.$badclass_msg.$linefeed.'<ul>'."\n";
1.541 raeburn 10087: foreach my $item (@badclasses) {
10088: if ($context eq 'auto') {
10089: $outcome .= " - $item\n";
10090: } else {
10091: $outcome .= "<li>$item</li>\n";
10092: }
10093: }
10094: if ($context eq 'auto') {
10095: $outcome .= $linefeed;
10096: } else {
1.566 albertel 10097: $outcome .= "</ul><br /><br /></div>\n";
1.541 raeburn 10098: }
10099: }
1.444 albertel 10100: }
10101: if ($args->{'no_end_date'}) {
10102: $args->{'endaccess'} = 0;
10103: }
10104: $cenv{'internal.autostart'}=$args->{'enrollstart'};
10105: $cenv{'internal.autoend'}=$args->{'enrollend'};
10106: $cenv{'default_enrollment_start_date'}=$args->{'startaccess'};
10107: $cenv{'default_enrollment_end_date'}=$args->{'endaccess'};
10108: if ($args->{'showphotos'}) {
10109: $cenv{'internal.showphotos'}=$args->{'showphotos'};
10110: }
10111: $cenv{'internal.authtype'} = $args->{'authtype'};
10112: $cenv{'internal.autharg'} = $args->{'autharg'};
10113: if ( ($cenv{'internal.authtype'} =~ /^krb/) && ($cenv{'internal.autoadds'} == 1)) {
10114: if (! defined($cenv{'internal.autharg'}) || $cenv{'internal.autharg'} eq '') {
1.541 raeburn 10115: 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');
10116: if ($context eq 'auto') {
10117: $outcome .= $krb_msg;
10118: } else {
1.566 albertel 10119: $outcome .= '<span class="LC_error">'.$krb_msg.'</span>';
1.541 raeburn 10120: }
10121: $outcome .= $linefeed;
1.444 albertel 10122: }
10123: }
10124: if (($args->{'ccdomain'}) && ($args->{'ccuname'})) {
10125: if ($args->{'setpolicy'}) {
10126: $cenv{'policy.email'}=$args->{'ccuname'}.':'.$args->{'ccdomain'};
10127: }
10128: if ($args->{'setcontent'}) {
10129: $cenv{'question.email'}=$args->{'ccuname'}.':'.$args->{'ccdomain'};
10130: }
10131: }
10132: if ($args->{'reshome'}) {
10133: $cenv{'reshome'}=$args->{'reshome'}.'/';
10134: $cenv{'reshome'}=~s/\/+$/\//;
10135: }
10136: #
10137: # course has keyed access
10138: #
10139: if ($args->{'setkeys'}) {
10140: $cenv{'keyaccess'}='yes';
10141: }
10142: # if specified, key authority is not course, but user
10143: # only active if keyaccess is yes
10144: if ($args->{'keyauth'}) {
1.487 albertel 10145: my ($user,$domain) = split(':',$args->{'keyauth'});
10146: $user = &LONCAPA::clean_username($user);
10147: $domain = &LONCAPA::clean_username($domain);
1.488 foxr 10148: if ($user ne '' && $domain ne '') {
1.487 albertel 10149: $cenv{'keyauth'}=$user.':'.$domain;
1.444 albertel 10150: }
10151: }
10152:
10153: if ($args->{'disresdis'}) {
10154: $cenv{'pch.roles.denied'}='st';
10155: }
10156: if ($args->{'disablechat'}) {
10157: $cenv{'plc.roles.denied'}='st';
10158: }
10159:
10160: # Record we've not yet viewed the Course Initialization Helper for this
10161: # course
10162: $cenv{'course.helper.not.run'} = 1;
10163: #
10164: # Use new Randomseed
10165: #
10166: $cenv{'rndseed'}=&Apache::lonnet::latest_rnd_algorithm_id();;
10167: $cenv{'receiptalg'}=&Apache::lonnet::latest_receipt_algorithm_id();;
10168: #
10169: # The encryption code and receipt prefix for this course
10170: #
10171: $cenv{'internal.encseed'}=$Apache::lonnet::perlvar{'lonReceipt'}.$$.time.int(rand(9999));
10172: $cenv{'internal.encpref'}=100+int(9*rand(99));
10173: #
10174: # By default, use standard grading
10175: if (!defined($cenv{'grading'})) { $cenv{'grading'} = 'standard'; }
10176:
1.541 raeburn 10177: $outcome .= $linefeed.&mt('Setting environment').': '.
10178: &Apache::lonnet::put('environment',\%cenv,$$crsudom,$$crsunum).$linefeed;
1.444 albertel 10179: #
10180: # Open all assignments
10181: #
10182: if ($args->{'openall'}) {
10183: my $storeunder=$$crsudom.'_'.$$crsunum.'.0.opendate';
10184: my %storecontent = ($storeunder => time,
10185: $storeunder.'.type' => 'date_start');
10186:
10187: $outcome .= &mt('Opening all assignments').': '.&Apache::lonnet::cput
1.541 raeburn 10188: ('resourcedata',\%storecontent,$$crsudom,$$crsunum).$linefeed;
1.444 albertel 10189: }
10190: #
10191: # Set first page
10192: #
10193: unless (($args->{'nonstandard'}) || ($args->{'firstres'} eq 'blank')
10194: || ($cloneid)) {
1.445 albertel 10195: use LONCAPA::map;
1.444 albertel 10196: $outcome .= &mt('Setting first resource').': ';
1.445 albertel 10197:
10198: my $map = '/uploaded/'.$$crsudom.'/'.$$crsunum.'/default.sequence';
10199: my ($errtext,$fatal)=&LONCAPA::map::mapread($map);
10200:
1.444 albertel 10201: $outcome .= ($fatal?$errtext:'read ok').' - ';
10202: my $title; my $url;
10203: if ($args->{'firstres'} eq 'syl') {
1.690 bisitz 10204: $title=&mt('Syllabus');
1.444 albertel 10205: $url='/public/'.$$crsudom.'/'.$$crsunum.'/syllabus';
10206: } else {
1.690 bisitz 10207: $title=&mt('Navigate Contents');
1.444 albertel 10208: $url='/adm/navmaps';
10209: }
1.445 albertel 10210:
10211: $LONCAPA::map::resources[1]=$title.':'.$url.':false:start:res';
10212: (my $outtext,$errtext) = &LONCAPA::map::storemap($map,1);
10213:
10214: if ($errtext) { $fatal=2; }
1.541 raeburn 10215: $outcome .= ($fatal?$errtext:'write ok').$linefeed;
1.444 albertel 10216: }
1.566 albertel 10217:
10218: return (1,$outcome);
1.444 albertel 10219: }
10220:
10221: ############################################################
10222: ############################################################
10223:
1.378 raeburn 10224: sub course_type {
10225: my ($cid) = @_;
10226: if (!defined($cid)) {
10227: $cid = $env{'request.course.id'};
10228: }
1.404 albertel 10229: if (defined($env{'course.'.$cid.'.type'})) {
10230: return $env{'course.'.$cid.'.type'};
1.378 raeburn 10231: } else {
10232: return 'Course';
1.377 raeburn 10233: }
10234: }
1.156 albertel 10235:
1.406 raeburn 10236: sub group_term {
10237: my $crstype = &course_type();
10238: my %names = (
10239: 'Course' => 'group',
1.865 raeburn 10240: 'Community' => 'group',
1.406 raeburn 10241: );
10242: return $names{$crstype};
10243: }
10244:
1.156 albertel 10245: sub icon {
10246: my ($file)=@_;
1.505 albertel 10247: my $curfext = lc((split(/\./,$file))[-1]);
1.168 albertel 10248: my $iconname=$Apache::lonnet::perlvar{'lonIconsURL'}.'/unknown.gif';
1.156 albertel 10249: my $embstyle = &Apache::loncommon::fileembstyle($curfext);
1.168 albertel 10250: if (!(!defined($embstyle) || $embstyle eq 'unk' || $embstyle eq 'hdn')) {
10251: if (-e $Apache::lonnet::perlvar{'lonDocRoot'}.'/'.
10252: $Apache::lonnet::perlvar{'lonIconsURL'}.'/'.
10253: $curfext.".gif") {
10254: $iconname=$Apache::lonnet::perlvar{'lonIconsURL'}.'/'.
10255: $curfext.".gif";
10256: }
10257: }
1.249 albertel 10258: return &lonhttpdurl($iconname);
1.154 albertel 10259: }
1.84 albertel 10260:
1.575 albertel 10261: sub lonhttpdurl {
1.692 www 10262: #
10263: # Had been used for "small fry" static images on separate port 8080.
10264: # Modify here if lightweight http functionality desired again.
10265: # Currently eliminated due to increasing firewall issues.
10266: #
1.575 albertel 10267: my ($url)=@_;
1.692 www 10268: return $url;
1.215 albertel 10269: }
10270:
1.213 albertel 10271: sub connection_aborted {
10272: my ($r)=@_;
10273: $r->print(" ");$r->rflush();
10274: my $c = $r->connection;
10275: return $c->aborted();
10276: }
10277:
1.221 foxr 10278: # Escapes strings that may have embedded 's that will be put into
1.222 foxr 10279: # strings as 'strings'.
10280: sub escape_single {
1.221 foxr 10281: my ($input) = @_;
1.223 albertel 10282: $input =~ s/\\/\\\\/g; # Escape the \'s..(must be first)>
1.221 foxr 10283: $input =~ s/\'/\\\'/g; # Esacpe the 's....
10284: return $input;
10285: }
1.223 albertel 10286:
1.222 foxr 10287: # Same as escape_single, but escape's "'s This
10288: # can be used for "strings"
10289: sub escape_double {
10290: my ($input) = @_;
10291: $input =~ s/\\/\\\\/g; # Escape the /'s..(must be first)>
10292: $input =~ s/\"/\\\"/g; # Esacpe the "s....
10293: return $input;
10294: }
1.223 albertel 10295:
1.222 foxr 10296: # Escapes the last element of a full URL.
10297: sub escape_url {
10298: my ($url) = @_;
1.238 raeburn 10299: my @urlslices = split(/\//, $url,-1);
1.369 www 10300: my $lastitem = &escape(pop(@urlslices));
1.223 albertel 10301: return join('/',@urlslices).'/'.$lastitem;
1.222 foxr 10302: }
1.462 albertel 10303:
1.820 raeburn 10304: sub compare_arrays {
10305: my ($arrayref1,$arrayref2) = @_;
10306: my (@difference,%count);
10307: @difference = ();
10308: %count = ();
10309: if ((ref($arrayref1) eq 'ARRAY') && (ref($arrayref2) eq 'ARRAY')) {
10310: foreach my $element (@{$arrayref1}, @{$arrayref2}) { $count{$element}++; }
10311: foreach my $element (keys(%count)) {
10312: if ($count{$element} == 1) {
10313: push(@difference,$element);
10314: }
10315: }
10316: }
10317: return @difference;
10318: }
10319:
1.817 bisitz 10320: # -------------------------------------------------------- Initialize user login
1.462 albertel 10321: sub init_user_environment {
1.463 albertel 10322: my ($r, $username, $domain, $authhost, $form, $args) = @_;
1.462 albertel 10323: my $lonids=$Apache::lonnet::perlvar{'lonIDsDir'};
10324:
10325: my $public=($username eq 'public' && $domain eq 'public');
10326:
10327: # See if old ID present, if so, remove
10328:
10329: my ($filename,$cookie,$userroles);
10330: my $now=time;
10331:
10332: if ($public) {
10333: my $max_public=100;
10334: my $oldest;
10335: my $oldest_time=0;
10336: for(my $next=1;$next<=$max_public;$next++) {
10337: if (-e $lonids."/publicuser_$next.id") {
10338: my $mtime=(stat($lonids."/publicuser_$next.id"))[9];
10339: if ($mtime<$oldest_time || !$oldest_time) {
10340: $oldest_time=$mtime;
10341: $oldest=$next;
10342: }
10343: } else {
10344: $cookie="publicuser_$next";
10345: last;
10346: }
10347: }
10348: if (!$cookie) { $cookie="publicuser_$oldest"; }
10349: } else {
1.463 albertel 10350: # if this isn't a robot, kill any existing non-robot sessions
10351: if (!$args->{'robot'}) {
10352: opendir(DIR,$lonids);
10353: while ($filename=readdir(DIR)) {
10354: if ($filename=~/^$username\_\d+\_$domain\_$authhost\.id$/) {
10355: unlink($lonids.'/'.$filename);
10356: }
1.462 albertel 10357: }
1.463 albertel 10358: closedir(DIR);
1.462 albertel 10359: }
10360: # Give them a new cookie
1.463 albertel 10361: my $id = ($args->{'robot'} ? 'robot'.$args->{'robot'}
1.684 www 10362: : $now.$$.int(rand(10000)));
1.463 albertel 10363: $cookie="$username\_$id\_$domain\_$authhost";
1.462 albertel 10364:
10365: # Initialize roles
10366:
10367: $userroles=&Apache::lonnet::rolesinit($domain,$username,$authhost);
10368: }
10369: # ------------------------------------ Check browser type and MathML capability
10370:
10371: my ($httpbrowser,$clientbrowser,$clientversion,$clientmathml,
10372: $clientunicode,$clientos) = &decode_user_agent($r);
10373:
10374: # ------------------------------------------------------------- Get environment
10375:
10376: my %userenv = &Apache::lonnet::dump('environment',$domain,$username);
10377: my ($tmp) = keys(%userenv);
10378: if ($tmp !~ /^(con_lost|error|no_such_host)/i) {
10379: # default remote control to off
10380: if ($userenv{'remote'} ne 'on') { $userenv{'remote'} = 'off'; }
10381: } else {
10382: undef(%userenv);
10383: }
10384: if (($userenv{'interface'}) && (!$form->{'interface'})) {
10385: $form->{'interface'}=$userenv{'interface'};
10386: }
10387: $env{'environment.remote'}=$userenv{'remote'};
10388: if ($userenv{'texengine'} eq 'ttm') { $clientmathml=1; }
10389:
10390: # --------------- Do not trust query string to be put directly into environment
1.817 bisitz 10391: foreach my $option ('interface','localpath','localres') {
10392: $form->{$option}=~s/[\n\r\=]//gs;
1.462 albertel 10393: }
10394: # --------------------------------------------------------- Write first profile
10395:
10396: {
10397: my %initial_env =
10398: ("user.name" => $username,
10399: "user.domain" => $domain,
10400: "user.home" => $authhost,
10401: "browser.type" => $clientbrowser,
10402: "browser.version" => $clientversion,
10403: "browser.mathml" => $clientmathml,
10404: "browser.unicode" => $clientunicode,
10405: "browser.os" => $clientos,
10406: "server.domain" => $Apache::lonnet::perlvar{'lonDefDomain'},
10407: "request.course.fn" => '',
10408: "request.course.uri" => '',
10409: "request.course.sec" => '',
10410: "request.role" => 'cm',
10411: "request.role.adv" => $env{'user.adv'},
10412: "request.host" => $ENV{'REMOTE_ADDR'},);
10413:
10414: if ($form->{'localpath'}) {
10415: $initial_env{"browser.localpath"} = $form->{'localpath'};
10416: $initial_env{"browser.localres"} = $form->{'localres'};
10417: }
10418:
10419: if ($public) {
10420: $initial_env{"environment.remote"} = "off";
10421: }
10422: if ($form->{'interface'}) {
10423: $form->{'interface'}=~s/\W//gs;
10424: $initial_env{"browser.interface"} = $form->{'interface'};
10425: $env{'browser.interface'}=$form->{'interface'};
10426: }
10427:
1.724 raeburn 10428: foreach my $tool ('aboutme','blog','portfolio') {
10429: $userenv{'availabletools.'.$tool} =
10430: &Apache::lonnet::usertools_access($username,$domain,$tool,'reload');
10431: }
10432:
1.864 raeburn 10433: foreach my $crstype ('official','unofficial','community') {
1.765 raeburn 10434: $userenv{'canrequest.'.$crstype} =
10435: &Apache::lonnet::usertools_access($username,$domain,$crstype,
10436: 'reload','requestcourses');
10437: }
10438:
1.462 albertel 10439: $env{'user.environment'} = "$lonids/$cookie.id";
10440:
10441: if (tie(my %disk_env,'GDBM_File',"$lonids/$cookie.id",
10442: &GDBM_WRCREAT(),0640)) {
10443: &_add_to_env(\%disk_env,\%initial_env);
10444: &_add_to_env(\%disk_env,\%userenv,'environment.');
10445: &_add_to_env(\%disk_env,$userroles);
1.463 albertel 10446: if (ref($args->{'extra_env'})) {
10447: &_add_to_env(\%disk_env,$args->{'extra_env'});
10448: }
1.462 albertel 10449: untie(%disk_env);
10450: } else {
1.705 tempelho 10451: &Apache::lonnet::logthis("<span style=\"color:blue;\">WARNING: ".
10452: 'Could not create environment storage in lonauth: '.$!.'</span>');
1.462 albertel 10453: return 'error: '.$!;
10454: }
10455: }
10456: $env{'request.role'}='cm';
10457: $env{'request.role.adv'}=$env{'user.adv'};
10458: $env{'browser.type'}=$clientbrowser;
10459:
10460: return $cookie;
10461:
10462: }
10463:
10464: sub _add_to_env {
10465: my ($idf,$env_data,$prefix) = @_;
1.676 raeburn 10466: if (ref($env_data) eq 'HASH') {
10467: while (my ($key,$value) = each(%$env_data)) {
10468: $idf->{$prefix.$key} = $value;
10469: $env{$prefix.$key} = $value;
10470: }
1.462 albertel 10471: }
10472: }
10473:
1.685 tempelho 10474: # --- Get the symbolic name of a problem and the url
10475: sub get_symb {
10476: my ($request,$silent) = @_;
1.726 raeburn 10477: (my $url=$env{'form.url'}) =~ s-^https?\://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;
1.685 tempelho 10478: my $symb=($env{'form.symb'} ne '' ? $env{'form.symb'} : (&Apache::lonnet::symbread($url)));
10479: if ($symb eq '') {
10480: if (!$silent) {
10481: $request->print("Unable to handle ambiguous references:$url:.");
10482: return ();
10483: }
10484: }
10485: &Apache::lonenc::check_decrypt(\$symb);
10486: return ($symb);
10487: }
10488:
10489: # --------------------------------------------------------------Get annotation
10490:
10491: sub get_annotation {
10492: my ($symb,$enc) = @_;
10493:
10494: my $key = $symb;
10495: if (!$enc) {
10496: $key =
10497: &Apache::lonnet::clutter((&Apache::lonnet::decode_symb($symb))[2]);
10498: }
10499: my %annotation=&Apache::lonnet::get('nohist_annotations',[$key]);
10500: return $annotation{$key};
10501: }
10502:
10503: sub clean_symb {
1.731 raeburn 10504: my ($symb,$delete_enc) = @_;
1.685 tempelho 10505:
10506: &Apache::lonenc::check_decrypt(\$symb);
10507: my $enc = $env{'request.enc'};
1.731 raeburn 10508: if ($delete_enc) {
1.730 raeburn 10509: delete($env{'request.enc'});
10510: }
1.685 tempelho 10511:
10512: return ($symb,$enc);
10513: }
1.462 albertel 10514:
1.41 ng 10515: =pod
10516:
10517: =back
10518:
1.112 bowersj2 10519: =cut
1.41 ng 10520:
1.112 bowersj2 10521: 1;
10522: __END__;
1.41 ng 10523:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>