Annotation of loncom/interface/loncommon.pm, revision 1.888
1.10 albertel 1: # The LearningOnline Network with CAPA
1.1 albertel 2: # a pile of common routines
1.10 albertel 3: #
1.888 ! raeburn 4: # $Id: loncommon.pm,v 1.887 2009/08/28 22:47:07 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.886 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.888 ! raeburn 605: function openuserbrowser(formname,uname,udom,ulast,ufirst,uemail,hideudom,crsdom,caller) {
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.888 ! raeburn 620: if ((caller != null) && (caller != undefined)) {
! 621: url += '&caller='+caller;
! 622: }
1.876 raeburn 623: var title = 'User_Browser';
624: var options = 'scrollbars=1,resizable=1,menubar=0';
625: options += ',width=700,height=600';
626: var stdeditbrowser = open(url,title,options,'1');
627: stdeditbrowser.focus();
628: }
629:
1.888 ! raeburn 630: function fix_domain (formname,udom,origdom,uname) {
1.876 raeburn 631: var formid = getFormIdByName(formname);
632: if (formid > -1) {
1.888 ! raeburn 633: var unameid = getIndexByName(formid,uname);
1.876 raeburn 634: var domid = getIndexByName(formid,udom);
635: var hidedomid = getIndexByName(formid,origdom);
636: if (hidedomid > -1) {
637: var fixeddom = document.forms[formid].elements[hidedomid].value;
1.888 ! raeburn 638: var unameval = document.forms[formid].elements[unameid].value;
! 639: if ((fixeddom != '') && (fixeddom != undefined) && (fixeddom != null) && (unameval != '') && (unameval != undefined) && (unameval != null)) {
! 640: if (domid > -1) {
! 641: var slct = document.forms[formid].elements[domid];
! 642: if (slct.type == 'select-one') {
! 643: var i;
! 644: for (i=0;i<slct.length;i++) {
! 645: if (slct.options[i].value==fixeddom) { slct.selectedIndex=i; }
! 646: }
! 647: }
! 648: if (slct.type == 'hidden') {
! 649: slct.value = fixeddom;
1.876 raeburn 650: }
651: }
1.468 raeburn 652: }
653: }
654: }
1.876 raeburn 655: return;
656: }
657:
1.888 ! raeburn 658: function userCheck (formname) {
! 659:
! 660: }
! 661:
1.876 raeburn 662: $id_functions
663: ENDUSERBRW
1.468 raeburn 664: }
665:
666: sub setsec_javascript {
667: my ($sec_element,$formname) = @_;
668: my $setsections = qq|
669: function setSect(sectionlist) {
1.629 raeburn 670: var sectionsArray = new Array();
671: if ((sectionlist != '') && (typeof sectionlist != "undefined")) {
672: sectionsArray = sectionlist.split(",");
673: }
1.468 raeburn 674: var numSections = sectionsArray.length;
675: document.$formname.$sec_element.length = 0;
676: if (numSections == 0) {
677: document.$formname.$sec_element.multiple=false;
678: document.$formname.$sec_element.size=1;
679: document.$formname.$sec_element.options[0] = new Option('No existing sections','',false,false)
680: } else {
681: if (numSections == 1) {
682: document.$formname.$sec_element.multiple=false;
683: document.$formname.$sec_element.size=1;
684: document.$formname.$sec_element.options[0] = new Option('Select','',true,true);
685: document.$formname.$sec_element.options[1] = new Option('No section','',false,false)
686: document.$formname.$sec_element.options[2] = new Option(sectionsArray[0],sectionsArray[0],false,false);
687: } else {
688: for (var i=0; i<numSections; i++) {
689: document.$formname.$sec_element.options[i] = new Option(sectionsArray[i],sectionsArray[i],false,false)
690: }
691: document.$formname.$sec_element.multiple=true
692: if (numSections < 3) {
693: document.$formname.$sec_element.size=numSections;
694: } else {
695: document.$formname.$sec_element.size=3;
696: }
697: document.$formname.$sec_element.options[0].selected = false
698: }
699: }
1.91 www 700: }
1.468 raeburn 701: |;
702: return $setsections;
703: }
704:
1.91 www 705:
706: sub selectcourse_link {
1.377 raeburn 707: my ($form,$unameele,$udomele,$desc,$extra_element,$multflag,$selecttype)=@_;
1.871 raeburn 708: my $linktext = &mt('Select Course');
709: if ($selecttype eq 'Community') {
710: $linktext = &mt('Select Community');
711: }
1.787 bisitz 712: return '<span class="LC_nobreak">'
713: ."<a href='"
714: .'javascript:opencrsbrowser("'.$form.'","'.$unameele
715: .'","'.$udomele.'","'.$desc.'","'.$extra_element
716: .'","'.$multflag.'","'.$selecttype.'");'
1.871 raeburn 717: ."'>".$linktext.'</a>'
1.787 bisitz 718: .'</span>';
1.74 www 719: }
1.42 matthew 720:
1.653 raeburn 721: sub selectauthor_link {
722: my ($form,$udom)=@_;
723: return '<a href="javascript:openauthorbrowser('."'$form','$udom'".');">'.
724: &mt('Select Author').'</a>';
725: }
726:
1.876 raeburn 727: sub selectuser_link {
1.881 raeburn 728: my ($form,$unameelem,$domelem,$lastelem,$firstelem,$emailelem,$hdomelem,
1.888 ! raeburn 729: $coursedom,$linktext,$caller) = @_;
1.876 raeburn 730: return '<a href="javascript:openuserbrowser('."'$form','$unameelem','$domelem',".
1.888 ! raeburn 731: "'$lastelem','$firstelem','$emailelem','$hdomelem','$coursedom','$caller'".
1.881 raeburn 732: ');">'.$linktext.'</a>';
1.876 raeburn 733: }
734:
1.273 raeburn 735: sub check_uncheck_jscript {
736: my $jscript = <<"ENDSCRT";
737: function checkAll(field) {
738: if (field.length > 0) {
739: for (i = 0; i < field.length; i++) {
740: field[i].checked = true ;
741: }
742: } else {
743: field.checked = true
744: }
745: }
746:
747: function uncheckAll(field) {
748: if (field.length > 0) {
749: for (i = 0; i < field.length; i++) {
750: field[i].checked = false ;
1.543 albertel 751: }
752: } else {
1.273 raeburn 753: field.checked = false ;
754: }
755: }
756: ENDSCRT
757: return $jscript;
758: }
759:
1.656 www 760: sub select_timezone {
1.659 raeburn 761: my ($name,$selected,$onchange,$includeempty)=@_;
762: my $output='<select name="'.$name.'" '.$onchange.'>'."\n";
763: if ($includeempty) {
764: $output .= '<option value=""';
765: if (($selected eq '') || ($selected eq 'local')) {
766: $output .= ' selected="selected" ';
767: }
768: $output .= '> </option>';
769: }
1.657 raeburn 770: my @timezones = DateTime::TimeZone->all_names;
771: foreach my $tzone (@timezones) {
772: $output.= '<option value="'.$tzone.'"';
773: if ($tzone eq $selected) {
774: $output.=' selected="selected"';
775: }
776: $output.=">$tzone</option>\n";
1.656 www 777: }
778: $output.="</select>";
779: return $output;
780: }
1.273 raeburn 781:
1.687 raeburn 782: sub select_datelocale {
783: my ($name,$selected,$onchange,$includeempty)=@_;
784: my $output='<select name="'.$name.'" '.$onchange.'>'."\n";
785: if ($includeempty) {
786: $output .= '<option value=""';
787: if ($selected eq '') {
788: $output .= ' selected="selected" ';
789: }
790: $output .= '> </option>';
791: }
792: my (@possibles,%locale_names);
793: my @locales = DateTime::Locale::Catalog::Locales;
794: foreach my $locale (@locales) {
795: if (ref($locale) eq 'HASH') {
796: my $id = $locale->{'id'};
797: if ($id ne '') {
798: my $en_terr = $locale->{'en_territory'};
799: my $native_terr = $locale->{'native_territory'};
1.695 raeburn 800: my @languages = &Apache::lonlocal::preferred_languages();
1.687 raeburn 801: if (grep(/^en$/,@languages) || !@languages) {
802: if ($en_terr ne '') {
803: $locale_names{$id} = '('.$en_terr.')';
804: } elsif ($native_terr ne '') {
805: $locale_names{$id} = $native_terr;
806: }
807: } else {
808: if ($native_terr ne '') {
809: $locale_names{$id} = $native_terr.' ';
810: } elsif ($en_terr ne '') {
811: $locale_names{$id} = '('.$en_terr.')';
812: }
813: }
814: push (@possibles,$id);
815: }
816: }
817: }
818: foreach my $item (sort(@possibles)) {
819: $output.= '<option value="'.$item.'"';
820: if ($item eq $selected) {
821: $output.=' selected="selected"';
822: }
823: $output.=">$item";
824: if ($locale_names{$item} ne '') {
825: $output.=" $locale_names{$item}</option>\n";
826: }
827: $output.="</option>\n";
828: }
829: $output.="</select>";
830: return $output;
831: }
832:
1.792 raeburn 833: sub select_language {
834: my ($name,$selected,$includeempty) = @_;
835: my %langchoices;
836: if ($includeempty) {
837: %langchoices = ('' => 'No language preference');
838: }
839: foreach my $id (&languageids()) {
840: my $code = &supportedlanguagecode($id);
841: if ($code) {
842: $langchoices{$code} = &plainlanguagedescription($id);
843: }
844: }
845: return &select_form($selected,$name,%langchoices);
846: }
847:
1.42 matthew 848: =pod
1.36 matthew 849:
1.648 raeburn 850: =item * &linked_select_forms(...)
1.36 matthew 851:
852: linked_select_forms returns a string containing a <script></script> block
853: and html for two <select> menus. The select menus will be linked in that
854: changing the value of the first menu will result in new values being placed
855: in the second menu. The values in the select menu will appear in alphabetical
1.609 raeburn 856: order unless a defined order is provided.
1.36 matthew 857:
858: linked_select_forms takes the following ordered inputs:
859:
860: =over 4
861:
1.112 bowersj2 862: =item * $formname, the name of the <form> tag
1.36 matthew 863:
1.112 bowersj2 864: =item * $middletext, the text which appears between the <select> tags
1.36 matthew 865:
1.112 bowersj2 866: =item * $firstdefault, the default value for the first menu
1.36 matthew 867:
1.112 bowersj2 868: =item * $firstselectname, the name of the first <select> tag
1.36 matthew 869:
1.112 bowersj2 870: =item * $secondselectname, the name of the second <select> tag
1.36 matthew 871:
1.112 bowersj2 872: =item * $hashref, a reference to a hash containing the data for the menus.
1.36 matthew 873:
1.609 raeburn 874: =item * $menuorder, the order of values in the first menu
875:
1.41 ng 876: =back
877:
1.36 matthew 878: Below is an example of such a hash. Only the 'text', 'default', and
879: 'select2' keys must appear as stated. keys(%menu) are the possible
880: values for the first select menu. The text that coincides with the
1.41 ng 881: first menu value is given in $menu{$choice1}->{'text'}. The values
1.36 matthew 882: and text for the second menu are given in the hash pointed to by
883: $menu{$choice1}->{'select2'}.
884:
1.112 bowersj2 885: my %menu = ( A1 => { text =>"Choice A1" ,
886: default => "B3",
887: select2 => {
888: B1 => "Choice B1",
889: B2 => "Choice B2",
890: B3 => "Choice B3",
891: B4 => "Choice B4"
1.609 raeburn 892: },
893: order => ['B4','B3','B1','B2'],
1.112 bowersj2 894: },
895: A2 => { text =>"Choice A2" ,
896: default => "C2",
897: select2 => {
898: C1 => "Choice C1",
899: C2 => "Choice C2",
900: C3 => "Choice C3"
1.609 raeburn 901: },
902: order => ['C2','C1','C3'],
1.112 bowersj2 903: },
904: A3 => { text =>"Choice A3" ,
905: default => "D6",
906: select2 => {
907: D1 => "Choice D1",
908: D2 => "Choice D2",
909: D3 => "Choice D3",
910: D4 => "Choice D4",
911: D5 => "Choice D5",
912: D6 => "Choice D6",
913: D7 => "Choice D7"
1.609 raeburn 914: },
915: order => ['D4','D3','D2','D1','D7','D6','D5'],
1.112 bowersj2 916: }
917: );
1.36 matthew 918:
919: =cut
920:
921: sub linked_select_forms {
922: my ($formname,
923: $middletext,
924: $firstdefault,
925: $firstselectname,
926: $secondselectname,
1.609 raeburn 927: $hashref,
928: $menuorder,
1.36 matthew 929: ) = @_;
930: my $second = "document.$formname.$secondselectname";
931: my $first = "document.$formname.$firstselectname";
932: # output the javascript to do the changing
933: my $result = '';
1.776 bisitz 934: $result.='<script type="text/javascript" language="JavaScript">'."\n";
1.824 bisitz 935: $result.="// <![CDATA[\n";
1.36 matthew 936: $result.="var select2data = new Object();\n";
937: $" = '","';
938: my $debug = '';
939: foreach my $s1 (sort(keys(%$hashref))) {
940: $result.="select2data.d_$s1 = new Object();\n";
941: $result.="select2data.d_$s1.def = new String('".
942: $hashref->{$s1}->{'default'}."');\n";
1.609 raeburn 943: $result.="select2data.d_$s1.values = new Array(";
1.36 matthew 944: my @s2values = sort(keys( %{ $hashref->{$s1}->{'select2'} } ));
1.609 raeburn 945: if (ref($hashref->{$s1}->{'order'}) eq 'ARRAY') {
946: @s2values = @{$hashref->{$s1}->{'order'}};
947: }
1.36 matthew 948: $result.="\"@s2values\");\n";
949: $result.="select2data.d_$s1.texts = new Array(";
950: my @s2texts;
951: foreach my $value (@s2values) {
952: push @s2texts, $hashref->{$s1}->{'select2'}->{$value};
953: }
954: $result.="\"@s2texts\");\n";
955: }
956: $"=' ';
957: $result.= <<"END";
958:
959: function select1_changed() {
960: // Determine new choice
961: var newvalue = "d_" + $first.value;
962: // update select2
963: var values = select2data[newvalue].values;
964: var texts = select2data[newvalue].texts;
965: var select2def = select2data[newvalue].def;
966: var i;
967: // out with the old
968: for (i = 0; i < $second.options.length; i++) {
969: $second.options[i] = null;
970: }
971: // in with the nuclear
972: for (i=0;i<values.length; i++) {
973: $second.options[i] = new Option(values[i]);
1.143 matthew 974: $second.options[i].value = values[i];
1.36 matthew 975: $second.options[i].text = texts[i];
976: if (values[i] == select2def) {
977: $second.options[i].selected = true;
978: }
979: }
980: }
1.824 bisitz 981: // ]]>
1.36 matthew 982: </script>
983: END
984: # output the initial values for the selection lists
985: $result .= "<select size=\"1\" name=\"$firstselectname\" onchange=\"select1_changed()\">\n";
1.609 raeburn 986: my @order = sort(keys(%{$hashref}));
987: if (ref($menuorder) eq 'ARRAY') {
988: @order = @{$menuorder};
989: }
990: foreach my $value (@order) {
1.36 matthew 991: $result.=" <option value=\"$value\" ";
1.253 albertel 992: $result.=" selected=\"selected\" " if ($value eq $firstdefault);
1.119 www 993: $result.=">".&mt($hashref->{$value}->{'text'})."</option>\n";
1.36 matthew 994: }
995: $result .= "</select>\n";
996: my %select2 = %{$hashref->{$firstdefault}->{'select2'}};
997: $result .= $middletext;
998: $result .= "<select size=\"1\" name=\"$secondselectname\">\n";
999: my $seconddefault = $hashref->{$firstdefault}->{'default'};
1.609 raeburn 1000:
1001: my @secondorder = sort(keys(%select2));
1002: if (ref($hashref->{$firstdefault}->{'order'}) eq 'ARRAY') {
1003: @secondorder = @{$hashref->{$firstdefault}->{'order'}};
1004: }
1005: foreach my $value (@secondorder) {
1.36 matthew 1006: $result.=" <option value=\"$value\" ";
1.253 albertel 1007: $result.=" selected=\"selected\" " if ($value eq $seconddefault);
1.119 www 1008: $result.=">".&mt($select2{$value})."</option>\n";
1.36 matthew 1009: }
1010: $result .= "</select>\n";
1011: # return $debug;
1012: return $result;
1013: } # end of sub linked_select_forms {
1014:
1.45 matthew 1015: =pod
1.44 bowersj2 1016:
1.648 raeburn 1017: =item * &help_open_topic($topic,$text,$stayOnPage,$width,$height)
1.44 bowersj2 1018:
1.112 bowersj2 1019: Returns a string corresponding to an HTML link to the given help
1020: $topic, where $topic corresponds to the name of a .tex file in
1021: /home/httpd/html/adm/help/tex, with underscores replaced by
1022: spaces.
1023:
1024: $text will optionally be linked to the same topic, allowing you to
1025: link text in addition to the graphic. If you do not want to link
1026: text, but wish to specify one of the later parameters, pass an
1027: empty string.
1028:
1029: $stayOnPage is a value that will be interpreted as a boolean. If true,
1030: the link will not open a new window. If false, the link will open
1031: a new window using Javascript. (Default is false.)
1032:
1033: $width and $height are optional numerical parameters that will
1034: override the width and height of the popped up window, which may
1035: be useful for certain help topics with big pictures included.
1.44 bowersj2 1036:
1037: =cut
1038:
1039: sub help_open_topic {
1.48 bowersj2 1040: my ($topic, $text, $stayOnPage, $width, $height) = @_;
1041: $text = "" if (not defined $text);
1.44 bowersj2 1042: $stayOnPage = 0 if (not defined $stayOnPage);
1043: $width = 350 if (not defined $width);
1044: $height = 400 if (not defined $height);
1045: my $filename = $topic;
1046: $filename =~ s/ /_/g;
1047:
1.48 bowersj2 1048: my $template = "";
1049: my $link;
1.572 banghart 1050:
1.159 www 1051: $topic=~s/\W/\_/g;
1.44 bowersj2 1052:
1.572 banghart 1053: if (!$stayOnPage) {
1.72 bowersj2 1054: $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 1055: } else {
1.48 bowersj2 1056: $link = "/adm/help/${filename}.hlp";
1057: }
1058:
1059: # Add the text
1.755 neumanie 1060: if ($text ne "") {
1.763 bisitz 1061: $template.='<span class="LC_help_open_topic">'
1062: .'<a target="_top" href="'.$link.'">'
1063: .$text.'</a>';
1.48 bowersj2 1064: }
1065:
1.763 bisitz 1066: # (Always) Add the graphic
1.179 matthew 1067: my $title = &mt('Online Help');
1.667 raeburn 1068: my $helpicon=&lonhttpdurl("/adm/help/help.png");
1.763 bisitz 1069: $template.=' <a target="_top" href="'.$link.'" title="'.$title.'">'
1070: .'<img src="'.$helpicon.'" border="0"'
1071: .' alt="'.&mt('Help: [_1]',$topic).'"'
1.783 amueller 1072: .' title="'.$title.'"'
1.763 bisitz 1073: .' /></a>';
1074: if ($text ne "") {
1075: $template.='</span>';
1076: }
1.44 bowersj2 1077: return $template;
1078:
1.106 bowersj2 1079: }
1080:
1081: # This is a quicky function for Latex cheatsheet editing, since it
1082: # appears in at least four places
1083: sub helpLatexCheatsheet {
1.732 raeburn 1084: my ($topic,$text,$not_author) = @_;
1085: my $out;
1.106 bowersj2 1086: my $addOther = '';
1.732 raeburn 1087: if ($topic) {
1.763 bisitz 1088: $addOther = '<span>'.&Apache::loncommon::help_open_topic($topic,&mt($text),
1089: undef, undef, 600).
1090: '</span> ';
1091: }
1092: $out = '<span>' # Start cheatsheet
1093: .$addOther
1094: .'<span>'
1095: .&Apache::loncommon::help_open_topic('Greek_Symbols',&mt('Greek Symbols'),
1096: undef,undef,600)
1097: .'</span> <span>'
1098: .&Apache::loncommon::help_open_topic('Other_Symbols',&mt('Other Symbols'),
1099: undef,undef,600)
1100: .'</span>';
1.732 raeburn 1101: unless ($not_author) {
1.763 bisitz 1102: $out .= ' <span>'
1103: .&Apache::loncommon::help_open_topic('Authoring_Output_Tags',&mt('Output Tags'),
1104: undef,undef,600)
1105: .'</span>';
1.732 raeburn 1106: }
1.763 bisitz 1107: $out .= '</span>'; # End cheatsheet
1.732 raeburn 1108: return $out;
1.172 www 1109: }
1110:
1.430 albertel 1111: sub general_help {
1112: my $helptopic='Student_Intro';
1113: if ($env{'request.role'}=~/^(ca|au)/) {
1114: $helptopic='Authoring_Intro';
1115: } elsif ($env{'request.role'}=~/^cc/) {
1116: $helptopic='Course_Coordination_Intro';
1.672 raeburn 1117: } elsif ($env{'request.role'}=~/^dc/) {
1118: $helptopic='Domain_Coordination_Intro';
1.430 albertel 1119: }
1120: return $helptopic;
1121: }
1122:
1123: sub update_help_link {
1124: my ($topic,$component_help,$faq,$bug,$stayOnPage) = @_;
1125: my $origurl = $ENV{'REQUEST_URI'};
1126: $origurl=~s|^/~|/priv/|;
1127: my $timestamp = time;
1128: foreach my $datum (\$topic,\$component_help,\$faq,\$bug,\$origurl) {
1129: $$datum = &escape($$datum);
1130: }
1131:
1132: my $banner_link = "/adm/helpmenu?page=banner&topic=$topic&component_help=$component_help&faq=$faq&bug=$bug&origurl=$origurl&stamp=$timestamp&stayonpage=$stayOnPage";
1133: my $output .= <<"ENDOUTPUT";
1134: <script type="text/javascript">
1.824 bisitz 1135: // <![CDATA[
1.430 albertel 1136: banner_link = '$banner_link';
1.824 bisitz 1137: // ]]>
1.430 albertel 1138: </script>
1139: ENDOUTPUT
1140: return $output;
1141: }
1142:
1143: # now just updates the help link and generates a blue icon
1.193 raeburn 1144: sub help_open_menu {
1.430 albertel 1145: my ($topic,$component_help,$faq,$bug,$stayOnPage,$width,$height,$text)
1.552 banghart 1146: = @_;
1.430 albertel 1147: $stayOnPage = 0 if (not defined $stayOnPage);
1.572 banghart 1148: # only use pop-up help (stayOnPage == 0)
1.552 banghart 1149: # if environment.remote is on (using remote control UI)
1.798 tempelho 1150: if ($env{'environment.remote'} eq 'off' ) {
1.552 banghart 1151: $stayOnPage=1;
1.430 albertel 1152: }
1153: my $output;
1154: if ($component_help) {
1155: if (!$text) {
1156: $output=&help_open_topic($component_help,undef,$stayOnPage,
1157: $width,$height);
1158: } else {
1159: my $help_text;
1160: $help_text=&unescape($topic);
1161: $output='<table><tr><td>'.
1162: &help_open_topic($component_help,$help_text,$stayOnPage,
1163: $width,$height).'</td></tr></table>';
1164: }
1165: }
1166: my $banner_link = &update_help_link($topic,$component_help,$faq,$bug,$stayOnPage);
1167: return $output.$banner_link;
1168: }
1169:
1170: sub top_nav_help {
1171: my ($text) = @_;
1.436 albertel 1172: $text = &mt($text);
1.572 banghart 1173: my $stay_on_page =
1.798 tempelho 1174: ($env{'environment.remote'} eq 'off' );
1.572 banghart 1175: my $link = ($stay_on_page) ? "javascript:helpMenu('display')"
1.436 albertel 1176: : "javascript:helpMenu('open')";
1.572 banghart 1177: my $banner_link = &update_help_link(undef,undef,undef,undef,$stay_on_page);
1.436 albertel 1178:
1.201 raeburn 1179: my $title = &mt('Get help');
1.436 albertel 1180:
1181: return <<"END";
1182: $banner_link
1183: <a href="$link" title="$title">$text</a>
1184: END
1185: }
1186:
1187: sub help_menu_js {
1188: my ($text) = @_;
1189:
1190: my $stayOnPage =
1.798 tempelho 1191: ($env{'environment.remote'} eq 'off' );
1.436 albertel 1192:
1193: my $width = 620;
1194: my $height = 600;
1.430 albertel 1195: my $helptopic=&general_help();
1196: my $details_link = '/adm/help/'.$helptopic.'.hlp';
1.261 albertel 1197: my $nothing=&Apache::lonhtmlcommon::javascript_nothing();
1.331 albertel 1198: my $start_page =
1199: &Apache::loncommon::start_page('Help Menu', undef,
1200: {'frameset' => 1,
1201: 'js_ready' => 1,
1202: 'add_entries' => {
1203: 'border' => '0',
1.579 raeburn 1204: 'rows' => "110,*",},});
1.331 albertel 1205: my $end_page =
1206: &Apache::loncommon::end_page({'frameset' => 1,
1207: 'js_ready' => 1,});
1208:
1.436 albertel 1209: my $template .= <<"ENDTEMPLATE";
1210: <script type="text/javascript">
1.877 bisitz 1211: // <![CDATA[
1.253 albertel 1212: // <!-- BEGIN LON-CAPA Internal
1.430 albertel 1213: var banner_link = '';
1.243 raeburn 1214: function helpMenu(target) {
1215: var caller = this;
1216: if (target == 'open') {
1217: var newWindow = null;
1218: try {
1.262 albertel 1219: newWindow = window.open($nothing,"helpmenu","HEIGHT=$height,WIDTH=$width,resizable=yes,scrollbars=yes" )
1.243 raeburn 1220: }
1221: catch(error) {
1222: writeHelp(caller);
1223: return;
1224: }
1225: if (newWindow) {
1226: caller = newWindow;
1227: }
1.193 raeburn 1228: }
1.243 raeburn 1229: writeHelp(caller);
1230: return;
1231: }
1232: function writeHelp(caller) {
1.430 albertel 1233: caller.document.writeln('$start_page<frame name="bannerframe" src="'+banner_link+'" /><frame name="bodyframe" src="$details_link" /> $end_page')
1.243 raeburn 1234: caller.document.close()
1235: caller.focus()
1.193 raeburn 1236: }
1.877 bisitz 1237: // END LON-CAPA Internal -->
1.253 albertel 1238: // ]]>
1.436 albertel 1239: </script>
1.193 raeburn 1240: ENDTEMPLATE
1241: return $template;
1242: }
1243:
1.172 www 1244: sub help_open_bug {
1245: my ($topic, $text, $stayOnPage, $width, $height) = @_;
1.258 albertel 1246: unless ($env{'user.adv'}) { return ''; }
1.172 www 1247: unless ($Apache::lonnet::perlvar{'BugzillaHost'}) { return ''; }
1248: $text = "" if (not defined $text);
1249: $stayOnPage = 0 if (not defined $stayOnPage);
1.798 tempelho 1250: if ($env{'environment.remote'} eq 'off' ) {
1.172 www 1251: $stayOnPage=1;
1252: }
1.184 albertel 1253: $width = 600 if (not defined $width);
1254: $height = 600 if (not defined $height);
1.172 www 1255:
1256: $topic=~s/\W+/\+/g;
1257: my $link='';
1258: my $template='';
1.379 albertel 1259: my $url=$Apache::lonnet::perlvar{'BugzillaHost'}.'enter_bug.cgi?product=LON-CAPA&bug_file_loc='.
1260: &escape($ENV{'REQUEST_URI'}).'&component='.$topic;
1.172 www 1261: if (!$stayOnPage)
1262: {
1263: $link = "javascript:void(open('$url', 'Bugzilla', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))";
1264: }
1265: else
1266: {
1267: $link = $url;
1268: }
1269: # Add the text
1270: if ($text ne "")
1271: {
1272: $template .=
1273: "<table bgcolor='#AA3333' cellspacing='1' cellpadding='1' border='0'><tr>".
1.705 tempelho 1274: "<td bgcolor='#FF5555'><a target=\"_top\" href=\"$link\"><span style=\"color:#FFFFFF;font-size:10pt;\">$text</span></a>";
1.172 www 1275: }
1276:
1277: # Add the graphic
1.179 matthew 1278: my $title = &mt('Report a Bug');
1.215 albertel 1279: my $bugicon=&lonhttpdurl("/adm/lonMisc/smallBug.gif");
1.172 www 1280: $template .= <<"ENDTEMPLATE";
1.436 albertel 1281: <a target="_top" href="$link" title="$title"><img src="$bugicon" border="0" alt="(Bug: $topic)" /></a>
1.172 www 1282: ENDTEMPLATE
1283: if ($text ne '') { $template.='</td></tr></table>' };
1284: return $template;
1285:
1286: }
1287:
1288: sub help_open_faq {
1289: my ($topic, $text, $stayOnPage, $width, $height) = @_;
1.258 albertel 1290: unless ($env{'user.adv'}) { return ''; }
1.172 www 1291: unless ($Apache::lonnet::perlvar{'FAQHost'}) { return ''; }
1292: $text = "" if (not defined $text);
1293: $stayOnPage = 0 if (not defined $stayOnPage);
1.798 tempelho 1294: if ($env{'environment.remote'} eq 'off' ) {
1.172 www 1295: $stayOnPage=1;
1296: }
1297: $width = 350 if (not defined $width);
1298: $height = 400 if (not defined $height);
1299:
1300: $topic=~s/\W+/\+/g;
1301: my $link='';
1302: my $template='';
1303: my $url=$Apache::lonnet::perlvar{'FAQHost'}.'/fom/cache/'.$topic.'.html';
1304: if (!$stayOnPage)
1305: {
1306: $link = "javascript:void(open('$url', 'FAQ-O-Matic', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))";
1307: }
1308: else
1309: {
1310: $link = $url;
1311: }
1312:
1313: # Add the text
1314: if ($text ne "")
1315: {
1316: $template .=
1.173 www 1317: "<table bgcolor='#337733' cellspacing='1' cellpadding='1' border='0'><tr>".
1.705 tempelho 1318: "<td bgcolor='#448844'><a target=\"_top\" href=\"$link\"><span style=\"color:#FFFFFF; font-size:10pt;\">$text</span></a>";
1.172 www 1319: }
1320:
1321: # Add the graphic
1.179 matthew 1322: my $title = &mt('View the FAQ');
1.215 albertel 1323: my $faqicon=&lonhttpdurl("/adm/lonMisc/smallFAQ.gif");
1.172 www 1324: $template .= <<"ENDTEMPLATE";
1.436 albertel 1325: <a target="_top" href="$link" title="$title"><img src="$faqicon" border="0" alt="(FAQ: $topic)" /></a>
1.172 www 1326: ENDTEMPLATE
1327: if ($text ne '') { $template.='</td></tr></table>' };
1328: return $template;
1329:
1.44 bowersj2 1330: }
1.37 matthew 1331:
1.180 matthew 1332: ###############################################################
1333: ###############################################################
1334:
1.45 matthew 1335: =pod
1336:
1.648 raeburn 1337: =item * &change_content_javascript():
1.256 matthew 1338:
1339: This and the next function allow you to create small sections of an
1340: otherwise static HTML page that you can update on the fly with
1341: Javascript, even in Netscape 4.
1342:
1343: The Javascript fragment returned by this function (no E<lt>scriptE<gt> tag)
1344: must be written to the HTML page once. It will prove the Javascript
1345: function "change(name, content)". Calling the change function with the
1346: name of the section
1347: you want to update, matching the name passed to C<changable_area>, and
1348: the new content you want to put in there, will put the content into
1349: that area.
1350:
1351: B<Note>: Netscape 4 only reserves enough space for the changable area
1352: to contain room for the original contents. You need to "make space"
1353: for whatever changes you wish to make, and be B<sure> to check your
1354: code in Netscape 4. This feature in Netscape 4 is B<not> powerful;
1355: it's adequate for updating a one-line status display, but little more.
1356: This script will set the space to 100% width, so you only need to
1357: worry about height in Netscape 4.
1358:
1359: Modern browsers are much less limiting, and if you can commit to the
1360: user not using Netscape 4, this feature may be used freely with
1361: pretty much any HTML.
1362:
1363: =cut
1364:
1365: sub change_content_javascript {
1366: # If we're on Netscape 4, we need to use Layer-based code
1.258 albertel 1367: if ($env{'browser.type'} eq 'netscape' &&
1368: $env{'browser.version'} =~ /^4\./) {
1.256 matthew 1369: return (<<NETSCAPE4);
1370: function change(name, content) {
1371: doc = document.layers[name+"___escape"].layers[0].document;
1372: doc.open();
1373: doc.write(content);
1374: doc.close();
1375: }
1376: NETSCAPE4
1377: } else {
1378: # Otherwise, we need to use semi-standards-compliant code
1379: # (technically, "innerHTML" isn't standard but the equivalent
1380: # is really scary, and every useful browser supports it
1381: return (<<DOMBASED);
1382: function change(name, content) {
1383: element = document.getElementById(name);
1384: element.innerHTML = content;
1385: }
1386: DOMBASED
1387: }
1388: }
1389:
1390: =pod
1391:
1.648 raeburn 1392: =item * &changable_area($name,$origContent):
1.256 matthew 1393:
1394: This provides a "changable area" that can be modified on the fly via
1395: the Javascript code provided in C<change_content_javascript>. $name is
1396: the name you will use to reference the area later; do not repeat the
1397: same name on a given HTML page more then once. $origContent is what
1398: the area will originally contain, which can be left blank.
1399:
1400: =cut
1401:
1402: sub changable_area {
1403: my ($name, $origContent) = @_;
1404:
1.258 albertel 1405: if ($env{'browser.type'} eq 'netscape' &&
1406: $env{'browser.version'} =~ /^4\./) {
1.256 matthew 1407: # If this is netscape 4, we need to use the Layer tag
1408: return "<ilayer width='100%' id='${name}___escape' overflow='none'><layer width='100%' id='$name' overflow='none'>$origContent</layer></ilayer>";
1409: } else {
1410: return "<span id='$name'>$origContent</span>";
1411: }
1412: }
1413:
1414: =pod
1415:
1.648 raeburn 1416: =item * &viewport_geometry_js
1.590 raeburn 1417:
1418: Provides javascript object (Geometry) which can provide information about the viewport geometry for the client browser.
1419:
1420: =cut
1421:
1422:
1423: sub viewport_geometry_js {
1424: return <<"GEOMETRY";
1425: var Geometry = {};
1426: function init_geometry() {
1427: if (Geometry.init) { return };
1428: Geometry.init=1;
1429: if (window.innerHeight) {
1430: Geometry.getViewportHeight = function() { return window.innerHeight; };
1431: Geometry.getViewportWidth = function() { return window.innerWidth; };
1432: Geometry.getHorizontalScroll = function() { return window.pageXOffset; };
1433: Geometry.getVerticalScroll = function() { return window.pageYOffset; };
1434: }
1435: else if (document.documentElement && document.documentElement.clientHeight) {
1436: Geometry.getViewportHeight =
1437: function() { return document.documentElement.clientHeight; };
1438: Geometry.getViewportWidth =
1439: function() { return document.documentElement.clientWidth; };
1440:
1441: Geometry.getHorizontalScroll =
1442: function() { return document.documentElement.scrollLeft; };
1443: Geometry.getVerticalScroll =
1444: function() { return document.documentElement.scrollTop; };
1445: }
1446: else if (document.body.clientHeight) {
1447: Geometry.getViewportHeight =
1448: function() { return document.body.clientHeight; };
1449: Geometry.getViewportWidth =
1450: function() { return document.body.clientWidth; };
1451: Geometry.getHorizontalScroll =
1452: function() { return document.body.scrollLeft; };
1453: Geometry.getVerticalScroll =
1454: function() { return document.body.scrollTop; };
1455: }
1456: }
1457:
1458: GEOMETRY
1459: }
1460:
1461: =pod
1462:
1.648 raeburn 1463: =item * &viewport_size_js()
1.590 raeburn 1464:
1465: 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.
1466:
1467: =cut
1468:
1469: sub viewport_size_js {
1470: my $geometry = &viewport_geometry_js();
1471: return <<"DIMS";
1472:
1473: $geometry
1474:
1475: function getViewportDims(width,height) {
1476: init_geometry();
1477: width.value = Geometry.getViewportWidth();
1478: height.value = Geometry.getViewportHeight();
1479: return;
1480: }
1481:
1482: DIMS
1483: }
1484:
1485: =pod
1486:
1.648 raeburn 1487: =item * &resize_textarea_js()
1.565 albertel 1488:
1489: emits the needed javascript to resize a textarea to be as big as possible
1490:
1491: creates a function resize_textrea that takes two IDs first should be
1492: the id of the element to resize, second should be the id of a div that
1493: surrounds everything that comes after the textarea, this routine needs
1494: to be attached to the <body> for the onload and onresize events.
1495:
1.648 raeburn 1496: =back
1.565 albertel 1497:
1498: =cut
1499:
1500: sub resize_textarea_js {
1.590 raeburn 1501: my $geometry = &viewport_geometry_js();
1.565 albertel 1502: return <<"RESIZE";
1503: <script type="text/javascript">
1.824 bisitz 1504: // <![CDATA[
1.590 raeburn 1505: $geometry
1.565 albertel 1506:
1.588 albertel 1507: function getX(element) {
1508: var x = 0;
1509: while (element) {
1510: x += element.offsetLeft;
1511: element = element.offsetParent;
1512: }
1513: return x;
1514: }
1515: function getY(element) {
1516: var y = 0;
1517: while (element) {
1518: y += element.offsetTop;
1519: element = element.offsetParent;
1520: }
1521: return y;
1522: }
1523:
1524:
1.565 albertel 1525: function resize_textarea(textarea_id,bottom_id) {
1526: init_geometry();
1527: var textarea = document.getElementById(textarea_id);
1528: //alert(textarea);
1529:
1.588 albertel 1530: var textarea_top = getY(textarea);
1.565 albertel 1531: var textarea_height = textarea.offsetHeight;
1532: var bottom = document.getElementById(bottom_id);
1.588 albertel 1533: var bottom_top = getY(bottom);
1.565 albertel 1534: var bottom_height = bottom.offsetHeight;
1535: var window_height = Geometry.getViewportHeight();
1.588 albertel 1536: var fudge = 23;
1.565 albertel 1537: var new_height = window_height-fudge-textarea_top-bottom_height;
1538: if (new_height < 300) {
1539: new_height = 300;
1540: }
1541: textarea.style.height=new_height+'px';
1542: }
1.824 bisitz 1543: // ]]>
1.565 albertel 1544: </script>
1545: RESIZE
1546:
1547: }
1548:
1549: =pod
1550:
1.256 matthew 1551: =head1 Excel and CSV file utility routines
1552:
1553: =over 4
1554:
1555: =cut
1556:
1557: ###############################################################
1558: ###############################################################
1559:
1560: =pod
1561:
1.648 raeburn 1562: =item * &csv_translate($text)
1.37 matthew 1563:
1.185 www 1564: Translate $text to allow it to be output as a 'comma separated values'
1.37 matthew 1565: format.
1566:
1567: =cut
1568:
1.180 matthew 1569: ###############################################################
1570: ###############################################################
1.37 matthew 1571: sub csv_translate {
1572: my $text = shift;
1573: $text =~ s/\"/\"\"/g;
1.209 albertel 1574: $text =~ s/\n/ /g;
1.37 matthew 1575: return $text;
1576: }
1.180 matthew 1577:
1578: ###############################################################
1579: ###############################################################
1580:
1581: =pod
1582:
1.648 raeburn 1583: =item * &define_excel_formats()
1.180 matthew 1584:
1585: Define some commonly used Excel cell formats.
1586:
1587: Currently supported formats:
1588:
1589: =over 4
1590:
1591: =item header
1592:
1593: =item bold
1594:
1595: =item h1
1596:
1597: =item h2
1598:
1599: =item h3
1600:
1.256 matthew 1601: =item h4
1602:
1603: =item i
1604:
1.180 matthew 1605: =item date
1606:
1607: =back
1608:
1609: Inputs: $workbook
1610:
1611: Returns: $format, a hash reference.
1612:
1613: =cut
1614:
1615: ###############################################################
1616: ###############################################################
1617: sub define_excel_formats {
1618: my ($workbook) = @_;
1619: my $format;
1620: $format->{'header'} = $workbook->add_format(bold => 1,
1621: bottom => 1,
1622: align => 'center');
1623: $format->{'bold'} = $workbook->add_format(bold=>1);
1624: $format->{'h1'} = $workbook->add_format(bold=>1, size=>18);
1625: $format->{'h2'} = $workbook->add_format(bold=>1, size=>16);
1626: $format->{'h3'} = $workbook->add_format(bold=>1, size=>14);
1.255 matthew 1627: $format->{'h4'} = $workbook->add_format(bold=>1, size=>12);
1.246 matthew 1628: $format->{'i'} = $workbook->add_format(italic=>1);
1.180 matthew 1629: $format->{'date'} = $workbook->add_format(num_format=>
1.207 matthew 1630: 'mm/dd/yyyy hh:mm:ss');
1.180 matthew 1631: return $format;
1632: }
1633:
1634: ###############################################################
1635: ###############################################################
1.113 bowersj2 1636:
1637: =pod
1638:
1.648 raeburn 1639: =item * &create_workbook()
1.255 matthew 1640:
1641: Create an Excel worksheet. If it fails, output message on the
1642: request object and return undefs.
1643:
1644: Inputs: Apache request object
1645:
1646: Returns (undef) on failure,
1647: Excel worksheet object, scalar with filename, and formats
1648: from &Apache::loncommon::define_excel_formats on success
1649:
1650: =cut
1651:
1652: ###############################################################
1653: ###############################################################
1654: sub create_workbook {
1655: my ($r) = @_;
1656: #
1657: # Create the excel spreadsheet
1658: my $filename = '/prtspool/'.
1.258 albertel 1659: $env{'user.name'}.'_'.$env{'user.domain'}.'_'.
1.255 matthew 1660: time.'_'.rand(1000000000).'.xls';
1661: my $workbook = Spreadsheet::WriteExcel->new('/home/httpd'.$filename);
1662: if (! defined($workbook)) {
1663: $r->log_error("Error creating excel spreadsheet $filename: $!");
1664: $r->print('<p>'.&mt("Unable to create new Excel file. ".
1665: "This error has been logged. ".
1666: "Please alert your LON-CAPA administrator").
1667: '</p>');
1668: return (undef);
1669: }
1670: #
1671: $workbook->set_tempdir('/home/httpd/perl/tmp');
1672: #
1673: my $format = &Apache::loncommon::define_excel_formats($workbook);
1674: return ($workbook,$filename,$format);
1675: }
1676:
1677: ###############################################################
1678: ###############################################################
1679:
1680: =pod
1681:
1.648 raeburn 1682: =item * &create_text_file()
1.113 bowersj2 1683:
1.542 raeburn 1684: Create a file to write to and eventually make available to the user.
1.256 matthew 1685: If file creation fails, outputs an error message on the request object and
1686: return undefs.
1.113 bowersj2 1687:
1.256 matthew 1688: Inputs: Apache request object, and file suffix
1.113 bowersj2 1689:
1.256 matthew 1690: Returns (undef) on failure,
1691: Filehandle and filename on success.
1.113 bowersj2 1692:
1693: =cut
1694:
1.256 matthew 1695: ###############################################################
1696: ###############################################################
1697: sub create_text_file {
1698: my ($r,$suffix) = @_;
1699: if (! defined($suffix)) { $suffix = 'txt'; };
1700: my $fh;
1701: my $filename = '/prtspool/'.
1.258 albertel 1702: $env{'user.name'}.'_'.$env{'user.domain'}.'_'.
1.256 matthew 1703: time.'_'.rand(1000000000).'.'.$suffix;
1704: $fh = Apache::File->new('>/home/httpd'.$filename);
1705: if (! defined($fh)) {
1706: $r->log_error("Couldn't open $filename for output $!");
1.683 bisitz 1707: $r->print(&mt('Problems occurred in creating the output file. '
1708: .'This error has been logged. '
1709: .'Please alert your LON-CAPA administrator.'));
1.113 bowersj2 1710: }
1.256 matthew 1711: return ($fh,$filename)
1.113 bowersj2 1712: }
1713:
1714:
1.256 matthew 1715: =pod
1.113 bowersj2 1716:
1717: =back
1718:
1719: =cut
1.37 matthew 1720:
1721: ###############################################################
1.33 matthew 1722: ## Home server <option> list generating code ##
1723: ###############################################################
1.35 matthew 1724:
1.169 www 1725: # ------------------------------------------
1726:
1727: sub domain_select {
1728: my ($name,$value,$multiple)=@_;
1729: my %domains=map {
1.514 albertel 1730: $_ => $_.' '. &Apache::lonnet::domain($_,'description')
1.512 albertel 1731: } &Apache::lonnet::all_domains();
1.169 www 1732: if ($multiple) {
1733: $domains{''}=&mt('Any domain');
1.550 albertel 1734: $domains{'select_form_order'} = [sort {lc($a) cmp lc($b) } (keys(%domains))];
1.287 albertel 1735: return &multiple_select_form($name,$value,4,\%domains);
1.169 www 1736: } else {
1.550 albertel 1737: $domains{'select_form_order'} = [sort {lc($a) cmp lc($b) } (keys(%domains))];
1.169 www 1738: return &select_form($name,$value,%domains);
1739: }
1740: }
1741:
1.282 albertel 1742: #-------------------------------------------
1743:
1744: =pod
1745:
1.519 raeburn 1746: =head1 Routines for form select boxes
1747:
1748: =over 4
1749:
1.648 raeburn 1750: =item * &multiple_select_form($name,$value,$size,$hash,$order)
1.282 albertel 1751:
1752: Returns a string containing a <select> element int multiple mode
1753:
1754:
1755: Args:
1756: $name - name of the <select> element
1.506 raeburn 1757: $value - scalar or array ref of values that should already be selected
1.282 albertel 1758: $size - number of rows long the select element is
1.283 albertel 1759: $hash - the elements should be 'option' => 'shown text'
1.282 albertel 1760: (shown text should already have been &mt())
1.506 raeburn 1761: $order - (optional) array ref of the order to show the elements in
1.283 albertel 1762:
1.282 albertel 1763: =cut
1764:
1765: #-------------------------------------------
1.169 www 1766: sub multiple_select_form {
1.284 albertel 1767: my ($name,$value,$size,$hash,$order)=@_;
1.169 www 1768: my %selected = map { $_ => 1 } ref($value)?@{$value}:($value);
1769: my $output='';
1.191 matthew 1770: if (! defined($size)) {
1771: $size = 4;
1.283 albertel 1772: if (scalar(keys(%$hash))<4) {
1773: $size = scalar(keys(%$hash));
1.191 matthew 1774: }
1775: }
1.734 bisitz 1776: $output.="\n".'<select name="'.$name.'" size="'.$size.'" multiple="multiple">';
1.501 banghart 1777: my @order;
1.506 raeburn 1778: if (ref($order) eq 'ARRAY') {
1779: @order = @{$order};
1780: } else {
1781: @order = sort(keys(%$hash));
1.501 banghart 1782: }
1783: if (exists($$hash{'select_form_order'})) {
1784: @order = @{$$hash{'select_form_order'}};
1785: }
1786:
1.284 albertel 1787: foreach my $key (@order) {
1.356 albertel 1788: $output.='<option value="'.&HTML::Entities::encode($key,'"<>&').'" ';
1.284 albertel 1789: $output.='selected="selected" ' if ($selected{$key});
1790: $output.='>'.$hash->{$key}."</option>\n";
1.169 www 1791: }
1792: $output.="</select>\n";
1793: return $output;
1794: }
1795:
1.88 www 1796: #-------------------------------------------
1797:
1798: =pod
1799:
1.648 raeburn 1800: =item * &select_form($defdom,$name,%hash)
1.88 www 1801:
1802: Returns a string containing a <select name='$name' size='1'> form to
1803: allow a user to select options from a hash option_name => displayed text.
1804: See lonrights.pm for an example invocation and use.
1805:
1806: =cut
1807:
1808: #-------------------------------------------
1809: sub select_form {
1810: my ($def,$name,%hash) = @_;
1811: my $selectform = "<select name=\"$name\" size=\"1\">\n";
1.128 albertel 1812: my @keys;
1813: if (exists($hash{'select_form_order'})) {
1814: @keys=@{$hash{'select_form_order'}};
1815: } else {
1816: @keys=sort(keys(%hash));
1817: }
1.356 albertel 1818: foreach my $key (@keys) {
1819: $selectform.=
1820: '<option value="'.&HTML::Entities::encode($key,'"<>&').'" '.
1821: ($key eq $def ? 'selected="selected" ' : '').
1822: ">".&mt($hash{$key})."</option>\n";
1.88 www 1823: }
1824: $selectform.="</select>";
1825: return $selectform;
1826: }
1827:
1.475 www 1828: # For display filters
1829:
1830: sub display_filter {
1831: if (!$env{'form.show'}) { $env{'form.show'}=10; }
1.477 www 1832: if (!$env{'form.displayfilter'}) { $env{'form.displayfilter'}='currentfolder'; }
1.714 bisitz 1833: return '<span class="LC_nobreak"><label>'.&mt('Records [_1]',
1.475 www 1834: &Apache::lonmeta::selectbox('show',$env{'form.show'},undef,
1835: (&mt('all'),10,20,50,100,1000,10000))).
1.714 bisitz 1836: '</label></span> <span class="LC_nobreak">'.
1.475 www 1837: &mt('Filter [_1]',
1.477 www 1838: &select_form($env{'form.displayfilter'},
1839: 'displayfilter',
1840: ('currentfolder' => 'Current folder/page',
1841: 'containing' => 'Containing phrase',
1842: 'none' => 'None'))).
1.714 bisitz 1843: '<input type="text" name="containingphrase" size="30" value="'.&HTML::Entities::encode($env{'form.containingphrase'}).'" /></span>';
1.475 www 1844: }
1845:
1.167 www 1846: sub gradeleveldescription {
1847: my $gradelevel=shift;
1848: my %gradelevels=(0 => 'Not specified',
1849: 1 => 'Grade 1',
1850: 2 => 'Grade 2',
1851: 3 => 'Grade 3',
1852: 4 => 'Grade 4',
1853: 5 => 'Grade 5',
1854: 6 => 'Grade 6',
1855: 7 => 'Grade 7',
1856: 8 => 'Grade 8',
1857: 9 => 'Grade 9',
1858: 10 => 'Grade 10',
1859: 11 => 'Grade 11',
1860: 12 => 'Grade 12',
1861: 13 => 'Grade 13',
1862: 14 => '100 Level',
1863: 15 => '200 Level',
1864: 16 => '300 Level',
1865: 17 => '400 Level',
1866: 18 => 'Graduate Level');
1867: return &mt($gradelevels{$gradelevel});
1868: }
1869:
1.163 www 1870: sub select_level_form {
1871: my ($deflevel,$name)=@_;
1872: unless ($deflevel) { $deflevel=0; }
1.167 www 1873: my $selectform = "<select name=\"$name\" size=\"1\">\n";
1874: for (my $i=0; $i<=18; $i++) {
1875: $selectform.="<option value=\"$i\" ".
1.253 albertel 1876: ($i==$deflevel ? 'selected="selected" ' : '').
1.167 www 1877: ">".&gradeleveldescription($i)."</option>\n";
1878: }
1879: $selectform.="</select>";
1880: return $selectform;
1.163 www 1881: }
1.167 www 1882:
1.35 matthew 1883: #-------------------------------------------
1884:
1.45 matthew 1885: =pod
1886:
1.873 raeburn 1887: =item * &select_dom_form($defdom,$name,$includeempty,$showdomdesc,$onchange)
1.35 matthew 1888:
1889: Returns a string containing a <select name='$name' size='1'> form to
1890: allow a user to select the domain to preform an operation in.
1891: See loncreateuser.pm for an example invocation and use.
1892:
1.90 www 1893: If the $includeempty flag is set, it also includes an empty choice ("no domain
1894: selected");
1895:
1.743 raeburn 1896: If the $showdomdesc flag is set, the domain name is followed by the domain description.
1897:
1.872 raeburn 1898: 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 1899:
1.35 matthew 1900: =cut
1901:
1902: #-------------------------------------------
1.34 matthew 1903: sub select_dom_form {
1.872 raeburn 1904: my ($defdom,$name,$includeempty,$showdomdesc,$onchange) = @_;
1905: if ($onchange) {
1.874 raeburn 1906: $onchange = ' onchange="'.$onchange.'"';
1.743 raeburn 1907: }
1.550 albertel 1908: my @domains = sort {lc($a) cmp lc($b)} (&Apache::lonnet::all_domains());
1.90 www 1909: if ($includeempty) { @domains=('',@domains); }
1.743 raeburn 1910: my $selectdomain = "<select name=\"$name\" size=\"1\"$onchange>\n";
1.356 albertel 1911: foreach my $dom (@domains) {
1912: $selectdomain.="<option value=\"$dom\" ".
1.563 raeburn 1913: ($dom eq $defdom ? 'selected="selected" ' : '').'>'.$dom;
1914: if ($showdomdesc) {
1915: if ($dom ne '') {
1916: my $domdesc = &Apache::lonnet::domain($dom,'description');
1917: if ($domdesc ne '') {
1918: $selectdomain .= ' ('.$domdesc.')';
1919: }
1920: }
1921: }
1922: $selectdomain .= "</option>\n";
1.34 matthew 1923: }
1924: $selectdomain.="</select>";
1925: return $selectdomain;
1926: }
1927:
1.35 matthew 1928: #-------------------------------------------
1929:
1.45 matthew 1930: =pod
1931:
1.648 raeburn 1932: =item * &home_server_form_item($domain,$name,$defaultflag)
1.35 matthew 1933:
1.586 raeburn 1934: input: 4 arguments (two required, two optional) -
1935: $domain - domain of new user
1936: $name - name of form element
1937: $default - Value of 'default' causes a default item to be first
1938: option, and selected by default.
1939: $hide - Value of 'hide' causes hiding of the name of the server,
1940: if 1 server found, or default, if 0 found.
1.594 raeburn 1941: output: returns 2 items:
1.586 raeburn 1942: (a) form element which contains either:
1943: (i) <select name="$name">
1944: <option value="$hostid1">$hostid $servers{$hostid}</option>
1945: <option value="$hostid2">$hostid $servers{$hostid}</option>
1946: </select>
1947: form item if there are multiple library servers in $domain, or
1948: (ii) an <input type="hidden" name="$name" value="$hostid" /> form item
1949: if there is only one library server in $domain.
1950:
1951: (b) number of library servers found.
1952:
1953: See loncreateuser.pm for example of use.
1.35 matthew 1954:
1955: =cut
1956:
1957: #-------------------------------------------
1.586 raeburn 1958: sub home_server_form_item {
1959: my ($domain,$name,$default,$hide) = @_;
1.513 albertel 1960: my %servers = &Apache::lonnet::get_servers($domain,'library');
1.586 raeburn 1961: my $result;
1962: my $numlib = keys(%servers);
1963: if ($numlib > 1) {
1964: $result .= '<select name="'.$name.'" />'."\n";
1965: if ($default) {
1.804 bisitz 1966: $result .= '<option value="default" selected="selected">'.&mt('default').
1.586 raeburn 1967: '</option>'."\n";
1968: }
1969: foreach my $hostid (sort(keys(%servers))) {
1970: $result.= '<option value="'.$hostid.'">'.
1971: $hostid.' '.$servers{$hostid}."</option>\n";
1972: }
1973: $result .= '</select>'."\n";
1974: } elsif ($numlib == 1) {
1975: my $hostid;
1976: foreach my $item (keys(%servers)) {
1977: $hostid = $item;
1978: }
1979: $result .= '<input type="hidden" name="'.$name.'" value="'.
1980: $hostid.'" />';
1981: if (!$hide) {
1982: $result .= $hostid.' '.$servers{$hostid};
1983: }
1984: $result .= "\n";
1985: } elsif ($default) {
1986: $result .= '<input type="hidden" name="'.$name.
1987: '" value="default" />';
1988: if (!$hide) {
1989: $result .= &mt('default');
1990: }
1991: $result .= "\n";
1.33 matthew 1992: }
1.586 raeburn 1993: return ($result,$numlib);
1.33 matthew 1994: }
1.112 bowersj2 1995:
1996: =pod
1997:
1.534 albertel 1998: =back
1999:
1.112 bowersj2 2000: =cut
1.87 matthew 2001:
2002: ###############################################################
1.112 bowersj2 2003: ## Decoding User Agent ##
1.87 matthew 2004: ###############################################################
2005:
2006: =pod
2007:
1.112 bowersj2 2008: =head1 Decoding the User Agent
2009:
2010: =over 4
2011:
2012: =item * &decode_user_agent()
1.87 matthew 2013:
2014: Inputs: $r
2015:
2016: Outputs:
2017:
2018: =over 4
2019:
1.112 bowersj2 2020: =item * $httpbrowser
1.87 matthew 2021:
1.112 bowersj2 2022: =item * $clientbrowser
1.87 matthew 2023:
1.112 bowersj2 2024: =item * $clientversion
1.87 matthew 2025:
1.112 bowersj2 2026: =item * $clientmathml
1.87 matthew 2027:
1.112 bowersj2 2028: =item * $clientunicode
1.87 matthew 2029:
1.112 bowersj2 2030: =item * $clientos
1.87 matthew 2031:
2032: =back
2033:
1.157 matthew 2034: =back
2035:
1.87 matthew 2036: =cut
2037:
2038: ###############################################################
2039: ###############################################################
2040: sub decode_user_agent {
1.247 albertel 2041: my ($r)=@_;
1.87 matthew 2042: my @browsertype=split(/\&/,$Apache::lonnet::perlvar{"lonBrowsDet"});
2043: my %mathcap=split(/\&/,$$Apache::lonnet::perlvar{"lonMathML"});
2044: my $httpbrowser=$ENV{"HTTP_USER_AGENT"};
1.247 albertel 2045: if (!$httpbrowser && $r) { $httpbrowser=$r->header_in('User-Agent'); }
1.87 matthew 2046: my $clientbrowser='unknown';
2047: my $clientversion='0';
2048: my $clientmathml='';
2049: my $clientunicode='0';
2050: for (my $i=0;$i<=$#browsertype;$i++) {
2051: my ($bname,$match,$notmatch,$vreg,$minv,$univ)=split(/\:/,$browsertype[$i]);
2052: if (($httpbrowser=~/$match/i) && ($httpbrowser!~/$notmatch/i)) {
2053: $clientbrowser=$bname;
2054: $httpbrowser=~/$vreg/i;
2055: $clientversion=$1;
2056: $clientmathml=($clientversion>=$minv);
2057: $clientunicode=($clientversion>=$univ);
2058: }
2059: }
2060: my $clientos='unknown';
2061: if (($httpbrowser=~/linux/i) ||
2062: ($httpbrowser=~/unix/i) ||
2063: ($httpbrowser=~/ux/i) ||
2064: ($httpbrowser=~/solaris/i)) { $clientos='unix'; }
2065: if (($httpbrowser=~/vax/i) ||
2066: ($httpbrowser=~/vms/i)) { $clientos='vms'; }
2067: if ($httpbrowser=~/next/i) { $clientos='next'; }
2068: if (($httpbrowser=~/mac/i) ||
2069: ($httpbrowser=~/powerpc/i)) { $clientos='mac'; }
2070: if ($httpbrowser=~/win/i) { $clientos='win'; }
2071: if ($httpbrowser=~/embed/i) { $clientos='pda'; }
2072: return ($httpbrowser,$clientbrowser,$clientversion,$clientmathml,
2073: $clientunicode,$clientos,);
2074: }
2075:
1.32 matthew 2076: ###############################################################
2077: ## Authentication changing form generation subroutines ##
2078: ###############################################################
2079: ##
2080: ## All of the authform_xxxxxxx subroutines take their inputs in a
2081: ## hash, and have reasonable default values.
2082: ##
2083: ## formname = the name given in the <form> tag.
1.35 matthew 2084: #-------------------------------------------
2085:
1.45 matthew 2086: =pod
2087:
1.112 bowersj2 2088: =head1 Authentication Routines
2089:
2090: =over 4
2091:
1.648 raeburn 2092: =item * &authform_xxxxxx()
1.35 matthew 2093:
2094: The authform_xxxxxx subroutines provide javascript and html forms which
2095: handle some of the conveniences required for authentication forms.
2096: This is not an optimal method, but it works.
2097:
2098: =over 4
2099:
1.112 bowersj2 2100: =item * authform_header
1.35 matthew 2101:
1.112 bowersj2 2102: =item * authform_authorwarning
1.35 matthew 2103:
1.112 bowersj2 2104: =item * authform_nochange
1.35 matthew 2105:
1.112 bowersj2 2106: =item * authform_kerberos
1.35 matthew 2107:
1.112 bowersj2 2108: =item * authform_internal
1.35 matthew 2109:
1.112 bowersj2 2110: =item * authform_filesystem
1.35 matthew 2111:
2112: =back
2113:
1.648 raeburn 2114: See loncreateuser.pm for invocation and use examples.
1.157 matthew 2115:
1.35 matthew 2116: =cut
2117:
2118: #-------------------------------------------
1.32 matthew 2119: sub authform_header{
2120: my %in = (
2121: formname => 'cu',
1.80 albertel 2122: kerb_def_dom => '',
1.32 matthew 2123: @_,
2124: );
2125: $in{'formname'} = 'document.' . $in{'formname'};
2126: my $result='';
1.80 albertel 2127:
2128: #---------------------------------------------- Code for upper case translation
2129: my $Javascript_toUpperCase;
2130: unless ($in{kerb_def_dom}) {
2131: $Javascript_toUpperCase =<<"END";
2132: switch (choice) {
2133: case 'krb': currentform.elements[choicearg].value =
2134: currentform.elements[choicearg].value.toUpperCase();
2135: break;
2136: default:
2137: }
2138: END
2139: } else {
2140: $Javascript_toUpperCase = "";
2141: }
2142:
1.165 raeburn 2143: my $radioval = "'nochange'";
1.591 raeburn 2144: if (defined($in{'curr_authtype'})) {
2145: if ($in{'curr_authtype'} ne '') {
2146: $radioval = "'".$in{'curr_authtype'}."arg'";
2147: }
1.174 matthew 2148: }
1.165 raeburn 2149: my $argfield = 'null';
1.591 raeburn 2150: if (defined($in{'mode'})) {
1.165 raeburn 2151: if ($in{'mode'} eq 'modifycourse') {
1.591 raeburn 2152: if (defined($in{'curr_autharg'})) {
2153: if ($in{'curr_autharg'} ne '') {
1.165 raeburn 2154: $argfield = "'$in{'curr_autharg'}'";
2155: }
2156: }
2157: }
2158: }
2159:
1.32 matthew 2160: $result.=<<"END";
2161: var current = new Object();
1.165 raeburn 2162: current.radiovalue = $radioval;
2163: current.argfield = $argfield;
1.32 matthew 2164:
2165: function changed_radio(choice,currentform) {
2166: var choicearg = choice + 'arg';
2167: // If a radio button in changed, we need to change the argfield
2168: if (current.radiovalue != choice) {
2169: current.radiovalue = choice;
2170: if (current.argfield != null) {
2171: currentform.elements[current.argfield].value = '';
2172: }
2173: if (choice == 'nochange') {
2174: current.argfield = null;
2175: } else {
2176: current.argfield = choicearg;
2177: switch(choice) {
2178: case 'krb':
2179: currentform.elements[current.argfield].value =
2180: "$in{'kerb_def_dom'}";
2181: break;
2182: default:
2183: break;
2184: }
2185: }
2186: }
2187: return;
2188: }
1.22 www 2189:
1.32 matthew 2190: function changed_text(choice,currentform) {
2191: var choicearg = choice + 'arg';
2192: if (currentform.elements[choicearg].value !='') {
1.80 albertel 2193: $Javascript_toUpperCase
1.32 matthew 2194: // clear old field
2195: if ((current.argfield != choicearg) && (current.argfield != null)) {
2196: currentform.elements[current.argfield].value = '';
2197: }
2198: current.argfield = choicearg;
2199: }
2200: set_auth_radio_buttons(choice,currentform);
2201: return;
1.20 www 2202: }
1.32 matthew 2203:
2204: function set_auth_radio_buttons(newvalue,currentform) {
2205: var i=0;
2206: while (i < currentform.login.length) {
2207: if (currentform.login[i].value == newvalue) { break; }
2208: i++;
2209: }
2210: if (i == currentform.login.length) {
2211: return;
2212: }
2213: current.radiovalue = newvalue;
2214: currentform.login[i].checked = true;
2215: return;
2216: }
2217: END
2218: return $result;
2219: }
2220:
2221: sub authform_authorwarning{
2222: my $result='';
1.144 matthew 2223: $result='<i>'.
2224: &mt('As a general rule, only authors or co-authors should be '.
2225: 'filesystem authenticated '.
2226: '(which allows access to the server filesystem).')."</i>\n";
1.32 matthew 2227: return $result;
2228: }
2229:
2230: sub authform_nochange{
2231: my %in = (
2232: formname => 'document.cu',
2233: kerb_def_dom => 'MSU.EDU',
2234: @_,
2235: );
1.586 raeburn 2236: my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
2237: my $result;
2238: if (keys(%can_assign) == 0) {
2239: $result = &mt('Under you current role you are not permitted to change login settings for this user');
2240: } else {
2241: $result = '<label>'.&mt('[_1] Do not change login data',
2242: '<input type="radio" name="login" value="nochange" '.
2243: 'checked="checked" onclick="'.
1.281 albertel 2244: "javascript:changed_radio('nochange',$in{'formname'});".'" />').
2245: '</label>';
1.586 raeburn 2246: }
1.32 matthew 2247: return $result;
2248: }
2249:
1.591 raeburn 2250: sub authform_kerberos {
1.32 matthew 2251: my %in = (
2252: formname => 'document.cu',
2253: kerb_def_dom => 'MSU.EDU',
1.80 albertel 2254: kerb_def_auth => 'krb4',
1.32 matthew 2255: @_,
2256: );
1.586 raeburn 2257: my ($check4,$check5,$krbcheck,$krbarg,$krbver,$result,$authtype,
2258: $autharg,$jscall);
2259: my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
1.80 albertel 2260: if ($in{'kerb_def_auth'} eq 'krb5') {
1.772 bisitz 2261: $check5 = ' checked="checked"';
1.80 albertel 2262: } else {
1.772 bisitz 2263: $check4 = ' checked="checked"';
1.80 albertel 2264: }
1.165 raeburn 2265: $krbarg = $in{'kerb_def_dom'};
1.591 raeburn 2266: if (defined($in{'curr_authtype'})) {
2267: if ($in{'curr_authtype'} eq 'krb') {
1.772 bisitz 2268: $krbcheck = ' checked="checked"';
1.623 raeburn 2269: if (defined($in{'mode'})) {
2270: if ($in{'mode'} eq 'modifyuser') {
2271: $krbcheck = '';
2272: }
2273: }
1.591 raeburn 2274: if (defined($in{'curr_kerb_ver'})) {
2275: if ($in{'curr_krb_ver'} eq '5') {
1.772 bisitz 2276: $check5 = ' checked="checked"';
1.591 raeburn 2277: $check4 = '';
2278: } else {
1.772 bisitz 2279: $check4 = ' checked="checked"';
1.591 raeburn 2280: $check5 = '';
2281: }
1.586 raeburn 2282: }
1.591 raeburn 2283: if (defined($in{'curr_autharg'})) {
1.165 raeburn 2284: $krbarg = $in{'curr_autharg'};
2285: }
1.586 raeburn 2286: if (!$can_assign{'krb4'} && !$can_assign{'krb5'}) {
1.591 raeburn 2287: if (defined($in{'curr_autharg'})) {
1.586 raeburn 2288: $result =
2289: &mt('Currently Kerberos authenticated with domain [_1] Version [_2].',
2290: $in{'curr_autharg'},$krbver);
2291: } else {
2292: $result =
2293: &mt('Currently Kerberos authenticated, Version [_1].',$krbver);
2294: }
2295: return $result;
2296: }
2297: }
2298: } else {
2299: if ($authnum == 1) {
1.784 bisitz 2300: $authtype = '<input type="hidden" name="login" value="krb" />';
1.165 raeburn 2301: }
2302: }
1.586 raeburn 2303: if (!$can_assign{'krb4'} && !$can_assign{'krb5'}) {
2304: return;
1.587 raeburn 2305: } elsif ($authtype eq '') {
1.591 raeburn 2306: if (defined($in{'mode'})) {
1.587 raeburn 2307: if ($in{'mode'} eq 'modifycourse') {
2308: if ($authnum == 1) {
1.784 bisitz 2309: $authtype = '<input type="hidden" name="login" value="krb" />';
1.587 raeburn 2310: }
2311: }
2312: }
1.586 raeburn 2313: }
2314: $jscall = "javascript:changed_radio('krb',$in{'formname'});";
2315: if ($authtype eq '') {
2316: $authtype = '<input type="radio" name="login" value="krb" '.
2317: 'onclick="'.$jscall.'" onchange="'.$jscall.'"'.
2318: $krbcheck.' />';
2319: }
2320: if (($can_assign{'krb4'} && $can_assign{'krb5'}) ||
2321: ($can_assign{'krb4'} && !$can_assign{'krb5'} &&
2322: $in{'curr_authtype'} eq 'krb5') ||
2323: (!$can_assign{'krb4'} && $can_assign{'krb5'} &&
2324: $in{'curr_authtype'} eq 'krb4')) {
2325: $result .= &mt
1.144 matthew 2326: ('[_1] Kerberos authenticated with domain [_2] '.
1.281 albertel 2327: '[_3] Version 4 [_4] Version 5 [_5]',
1.586 raeburn 2328: '<label>'.$authtype,
1.281 albertel 2329: '</label><input type="text" size="10" name="krbarg" '.
1.165 raeburn 2330: 'value="'.$krbarg.'" '.
1.144 matthew 2331: 'onchange="'.$jscall.'" />',
1.281 albertel 2332: '<label><input type="radio" name="krbver" value="4" '.$check4.' />',
2333: '</label><label><input type="radio" name="krbver" value="5" '.$check5.' />',
2334: '</label>');
1.586 raeburn 2335: } elsif ($can_assign{'krb4'}) {
2336: $result .= &mt
2337: ('[_1] Kerberos authenticated with domain [_2] '.
2338: '[_3] Version 4 [_4]',
2339: '<label>'.$authtype,
2340: '</label><input type="text" size="10" name="krbarg" '.
2341: 'value="'.$krbarg.'" '.
2342: 'onchange="'.$jscall.'" />',
2343: '<label><input type="hidden" name="krbver" value="4" />',
2344: '</label>');
2345: } elsif ($can_assign{'krb5'}) {
2346: $result .= &mt
2347: ('[_1] Kerberos authenticated with domain [_2] '.
2348: '[_3] Version 5 [_4]',
2349: '<label>'.$authtype,
2350: '</label><input type="text" size="10" name="krbarg" '.
2351: 'value="'.$krbarg.'" '.
2352: 'onchange="'.$jscall.'" />',
2353: '<label><input type="hidden" name="krbver" value="5" />',
2354: '</label>');
2355: }
1.32 matthew 2356: return $result;
2357: }
2358:
2359: sub authform_internal{
1.586 raeburn 2360: my %in = (
1.32 matthew 2361: formname => 'document.cu',
2362: kerb_def_dom => 'MSU.EDU',
2363: @_,
2364: );
1.586 raeburn 2365: my ($intcheck,$intarg,$result,$authtype,$autharg,$jscall);
2366: my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
1.591 raeburn 2367: if (defined($in{'curr_authtype'})) {
2368: if ($in{'curr_authtype'} eq 'int') {
1.586 raeburn 2369: if ($can_assign{'int'}) {
1.772 bisitz 2370: $intcheck = 'checked="checked" ';
1.623 raeburn 2371: if (defined($in{'mode'})) {
2372: if ($in{'mode'} eq 'modifyuser') {
2373: $intcheck = '';
2374: }
2375: }
1.591 raeburn 2376: if (defined($in{'curr_autharg'})) {
1.586 raeburn 2377: $intarg = $in{'curr_autharg'};
2378: }
2379: } else {
2380: $result = &mt('Currently internally authenticated.');
2381: return $result;
1.165 raeburn 2382: }
2383: }
1.586 raeburn 2384: } else {
2385: if ($authnum == 1) {
1.784 bisitz 2386: $authtype = '<input type="hidden" name="login" value="int" />';
1.586 raeburn 2387: }
2388: }
2389: if (!$can_assign{'int'}) {
2390: return;
1.587 raeburn 2391: } elsif ($authtype eq '') {
1.591 raeburn 2392: if (defined($in{'mode'})) {
1.587 raeburn 2393: if ($in{'mode'} eq 'modifycourse') {
2394: if ($authnum == 1) {
1.784 bisitz 2395: $authtype = '<input type="hidden" name="login" value="int" />';
1.587 raeburn 2396: }
2397: }
2398: }
1.165 raeburn 2399: }
1.586 raeburn 2400: $jscall = "javascript:changed_radio('int',$in{'formname'});";
2401: if ($authtype eq '') {
2402: $authtype = '<input type="radio" name="login" value="int" '.$intcheck.
2403: ' onchange="'.$jscall.'" onclick="'.$jscall.'" />';
2404: }
1.605 bisitz 2405: $autharg = '<input type="password" size="10" name="intarg" value="'.
1.586 raeburn 2406: $intarg.'" onchange="'.$jscall.'" />';
2407: $result = &mt
1.144 matthew 2408: ('[_1] Internally authenticated (with initial password [_2])',
1.586 raeburn 2409: '<label>'.$authtype,'</label>'.$autharg);
1.824 bisitz 2410: $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 2411: return $result;
2412: }
2413:
2414: sub authform_local{
2415: my %in = (
2416: formname => 'document.cu',
2417: kerb_def_dom => 'MSU.EDU',
2418: @_,
2419: );
1.586 raeburn 2420: my ($loccheck,$locarg,$result,$authtype,$autharg,$jscall);
2421: my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
1.591 raeburn 2422: if (defined($in{'curr_authtype'})) {
2423: if ($in{'curr_authtype'} eq 'loc') {
1.586 raeburn 2424: if ($can_assign{'loc'}) {
1.772 bisitz 2425: $loccheck = 'checked="checked" ';
1.623 raeburn 2426: if (defined($in{'mode'})) {
2427: if ($in{'mode'} eq 'modifyuser') {
2428: $loccheck = '';
2429: }
2430: }
1.591 raeburn 2431: if (defined($in{'curr_autharg'})) {
1.586 raeburn 2432: $locarg = $in{'curr_autharg'};
2433: }
2434: } else {
2435: $result = &mt('Currently using local (institutional) authentication.');
2436: return $result;
1.165 raeburn 2437: }
2438: }
1.586 raeburn 2439: } else {
2440: if ($authnum == 1) {
1.784 bisitz 2441: $authtype = '<input type="hidden" name="login" value="loc" />';
1.586 raeburn 2442: }
2443: }
2444: if (!$can_assign{'loc'}) {
2445: return;
1.587 raeburn 2446: } elsif ($authtype eq '') {
1.591 raeburn 2447: if (defined($in{'mode'})) {
1.587 raeburn 2448: if ($in{'mode'} eq 'modifycourse') {
2449: if ($authnum == 1) {
1.784 bisitz 2450: $authtype = '<input type="hidden" name="login" value="loc" />';
1.587 raeburn 2451: }
2452: }
2453: }
1.165 raeburn 2454: }
1.586 raeburn 2455: $jscall = "javascript:changed_radio('loc',$in{'formname'});";
2456: if ($authtype eq '') {
2457: $authtype = '<input type="radio" name="login" value="loc" '.
2458: $loccheck.' onchange="'.$jscall.'" onclick="'.
2459: $jscall.'" />';
2460: }
2461: $autharg = '<input type="text" size="10" name="locarg" value="'.
2462: $locarg.'" onchange="'.$jscall.'" />';
2463: $result = &mt('[_1] Local Authentication with argument [_2]',
2464: '<label>'.$authtype,'</label>'.$autharg);
1.32 matthew 2465: return $result;
2466: }
2467:
2468: sub authform_filesystem{
2469: my %in = (
2470: formname => 'document.cu',
2471: kerb_def_dom => 'MSU.EDU',
2472: @_,
2473: );
1.586 raeburn 2474: my ($fsyscheck,$result,$authtype,$autharg,$jscall);
2475: my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
1.591 raeburn 2476: if (defined($in{'curr_authtype'})) {
2477: if ($in{'curr_authtype'} eq 'fsys') {
1.586 raeburn 2478: if ($can_assign{'fsys'}) {
1.772 bisitz 2479: $fsyscheck = 'checked="checked" ';
1.623 raeburn 2480: if (defined($in{'mode'})) {
2481: if ($in{'mode'} eq 'modifyuser') {
2482: $fsyscheck = '';
2483: }
2484: }
1.586 raeburn 2485: } else {
2486: $result = &mt('Currently Filesystem Authenticated.');
2487: return $result;
2488: }
2489: }
2490: } else {
2491: if ($authnum == 1) {
1.784 bisitz 2492: $authtype = '<input type="hidden" name="login" value="fsys" />';
1.586 raeburn 2493: }
2494: }
2495: if (!$can_assign{'fsys'}) {
2496: return;
1.587 raeburn 2497: } elsif ($authtype eq '') {
1.591 raeburn 2498: if (defined($in{'mode'})) {
1.587 raeburn 2499: if ($in{'mode'} eq 'modifycourse') {
2500: if ($authnum == 1) {
1.784 bisitz 2501: $authtype = '<input type="hidden" name="login" value="fsys" />';
1.587 raeburn 2502: }
2503: }
2504: }
1.586 raeburn 2505: }
2506: $jscall = "javascript:changed_radio('fsys',$in{'formname'});";
2507: if ($authtype eq '') {
2508: $authtype = '<input type="radio" name="login" value="fsys" '.
2509: $fsyscheck.' onchange="'.$jscall.'" onclick="'.
2510: $jscall.'" />';
2511: }
2512: $autharg = '<input type="text" size="10" name="fsysarg" value=""'.
2513: ' onchange="'.$jscall.'" />';
2514: $result = &mt
1.144 matthew 2515: ('[_1] Filesystem Authenticated (with initial password [_2])',
1.281 albertel 2516: '<label><input type="radio" name="login" value="fsys" '.
1.586 raeburn 2517: $fsyscheck.'onchange="'.$jscall.'" onclick="'.$jscall.'" />',
1.605 bisitz 2518: '</label><input type="password" size="10" name="fsysarg" value="" '.
1.144 matthew 2519: 'onchange="'.$jscall.'" />');
1.32 matthew 2520: return $result;
2521: }
2522:
1.586 raeburn 2523: sub get_assignable_auth {
2524: my ($dom) = @_;
2525: if ($dom eq '') {
2526: $dom = $env{'request.role.domain'};
2527: }
2528: my %can_assign = (
2529: krb4 => 1,
2530: krb5 => 1,
2531: int => 1,
2532: loc => 1,
2533: );
2534: my %domconfig = &Apache::lonnet::get_dom('configuration',['usercreation'],$dom);
2535: if (ref($domconfig{'usercreation'}) eq 'HASH') {
2536: if (ref($domconfig{'usercreation'}{'authtypes'}) eq 'HASH') {
2537: my $authhash = $domconfig{'usercreation'}{'authtypes'};
2538: my $context;
2539: if ($env{'request.role'} =~ /^au/) {
2540: $context = 'author';
2541: } elsif ($env{'request.role'} =~ /^dc/) {
2542: $context = 'domain';
2543: } elsif ($env{'request.course.id'}) {
2544: $context = 'course';
2545: }
2546: if ($context) {
2547: if (ref($authhash->{$context}) eq 'HASH') {
2548: %can_assign = %{$authhash->{$context}};
2549: }
2550: }
2551: }
2552: }
2553: my $authnum = 0;
2554: foreach my $key (keys(%can_assign)) {
2555: if ($can_assign{$key}) {
2556: $authnum ++;
2557: }
2558: }
2559: if ($can_assign{'krb4'} && $can_assign{'krb5'}) {
2560: $authnum --;
2561: }
2562: return ($authnum,%can_assign);
2563: }
2564:
1.80 albertel 2565: ###############################################################
2566: ## Get Kerberos Defaults for Domain ##
2567: ###############################################################
2568: ##
2569: ## Returns default kerberos version and an associated argument
2570: ## as listed in file domain.tab. If not listed, provides
2571: ## appropriate default domain and kerberos version.
2572: ##
2573: #-------------------------------------------
2574:
2575: =pod
2576:
1.648 raeburn 2577: =item * &get_kerberos_defaults()
1.80 albertel 2578:
2579: get_kerberos_defaults($target_domain) returns the default kerberos
1.641 raeburn 2580: version and domain. If not found, it defaults to version 4 and the
2581: domain of the server.
1.80 albertel 2582:
1.648 raeburn 2583: =over 4
2584:
1.80 albertel 2585: ($def_version, $def_krb_domain) = &get_kerberos_defaults($target_domain);
2586:
1.648 raeburn 2587: =back
2588:
2589: =back
2590:
1.80 albertel 2591: =cut
2592:
2593: #-------------------------------------------
2594: sub get_kerberos_defaults {
2595: my $domain=shift;
1.641 raeburn 2596: my ($krbdef,$krbdefdom);
2597: my %domdefaults = &Apache::lonnet::get_domain_defaults($domain);
2598: if (($domdefaults{'auth_def'} =~/^krb(4|5)$/) && ($domdefaults{'auth_arg_def'} ne '')) {
2599: $krbdef = $domdefaults{'auth_def'};
2600: $krbdefdom = $domdefaults{'auth_arg_def'};
2601: } else {
1.80 albertel 2602: $ENV{'SERVER_NAME'}=~/(\w+\.\w+)$/;
2603: my $krbdefdom=$1;
2604: $krbdefdom=~tr/a-z/A-Z/;
2605: $krbdef = "krb4";
2606: }
2607: return ($krbdef,$krbdefdom);
2608: }
1.112 bowersj2 2609:
1.32 matthew 2610:
1.46 matthew 2611: ###############################################################
2612: ## Thesaurus Functions ##
2613: ###############################################################
1.20 www 2614:
1.46 matthew 2615: =pod
1.20 www 2616:
1.112 bowersj2 2617: =head1 Thesaurus Functions
2618:
2619: =over 4
2620:
1.648 raeburn 2621: =item * &initialize_keywords()
1.46 matthew 2622:
2623: Initializes the package variable %Keywords if it is empty. Uses the
2624: package variable $thesaurus_db_file.
2625:
2626: =cut
2627:
2628: ###################################################
2629:
2630: sub initialize_keywords {
2631: return 1 if (scalar keys(%Keywords));
2632: # If we are here, %Keywords is empty, so fill it up
2633: # Make sure the file we need exists...
2634: if (! -e $thesaurus_db_file) {
2635: &Apache::lonnet::logthis("Attempt to access $thesaurus_db_file".
2636: " failed because it does not exist");
2637: return 0;
2638: }
2639: # Set up the hash as a database
2640: my %thesaurus_db;
2641: if (! tie(%thesaurus_db,'GDBM_File',
1.53 albertel 2642: $thesaurus_db_file,&GDBM_READER(),0640)){
1.46 matthew 2643: &Apache::lonnet::logthis("Could not tie \%thesaurus_db to ".
2644: $thesaurus_db_file);
2645: return 0;
2646: }
2647: # Get the average number of appearances of a word.
2648: my $avecount = $thesaurus_db{'average.count'};
2649: # Put keywords (those that appear > average) into %Keywords
2650: while (my ($word,$data)=each (%thesaurus_db)) {
2651: my ($count,undef) = split /:/,$data;
2652: $Keywords{$word}++ if ($count > $avecount);
2653: }
2654: untie %thesaurus_db;
2655: # Remove special values from %Keywords.
1.356 albertel 2656: foreach my $value ('total.count','average.count') {
2657: delete($Keywords{$value}) if (exists($Keywords{$value}));
1.586 raeburn 2658: }
1.46 matthew 2659: return 1;
2660: }
2661:
2662: ###################################################
2663:
2664: =pod
2665:
1.648 raeburn 2666: =item * &keyword($word)
1.46 matthew 2667:
2668: Returns true if $word is a keyword. A keyword is a word that appears more
2669: than the average number of times in the thesaurus database. Calls
2670: &initialize_keywords
2671:
2672: =cut
2673:
2674: ###################################################
1.20 www 2675:
2676: sub keyword {
1.46 matthew 2677: return if (!&initialize_keywords());
2678: my $word=lc(shift());
2679: $word=~s/\W//g;
2680: return exists($Keywords{$word});
1.20 www 2681: }
1.46 matthew 2682:
2683: ###############################################################
2684:
2685: =pod
1.20 www 2686:
1.648 raeburn 2687: =item * &get_related_words()
1.46 matthew 2688:
1.160 matthew 2689: Look up a word in the thesaurus. Takes a scalar argument and returns
1.46 matthew 2690: an array of words. If the keyword is not in the thesaurus, an empty array
2691: will be returned. The order of the words returned is determined by the
2692: database which holds them.
2693:
2694: Uses global $thesaurus_db_file.
2695:
2696: =cut
2697:
2698: ###############################################################
2699: sub get_related_words {
2700: my $keyword = shift;
2701: my %thesaurus_db;
2702: if (! -e $thesaurus_db_file) {
2703: &Apache::lonnet::logthis("Attempt to access $thesaurus_db_file ".
2704: "failed because the file does not exist");
2705: return ();
2706: }
2707: if (! tie(%thesaurus_db,'GDBM_File',
1.53 albertel 2708: $thesaurus_db_file,&GDBM_READER(),0640)){
1.46 matthew 2709: return ();
2710: }
2711: my @Words=();
1.429 www 2712: my $count=0;
1.46 matthew 2713: if (exists($thesaurus_db{$keyword})) {
1.356 albertel 2714: # The first element is the number of times
2715: # the word appears. We do not need it now.
1.429 www 2716: my (undef,@RelatedWords) = (split(/:/,$thesaurus_db{$keyword}));
2717: my (undef,$mostfrequentcount)=split(/\,/,$RelatedWords[0]);
2718: my $threshold=$mostfrequentcount/10;
2719: foreach my $possibleword (@RelatedWords) {
2720: my ($word,$wordcount)=split(/\,/,$possibleword);
2721: if ($wordcount>$threshold) {
2722: push(@Words,$word);
2723: $count++;
2724: if ($count>10) { last; }
2725: }
1.20 www 2726: }
2727: }
1.46 matthew 2728: untie %thesaurus_db;
2729: return @Words;
1.14 harris41 2730: }
1.46 matthew 2731:
1.112 bowersj2 2732: =pod
2733:
2734: =back
2735:
2736: =cut
1.61 www 2737:
2738: # -------------------------------------------------------------- Plaintext name
1.81 albertel 2739: =pod
2740:
1.112 bowersj2 2741: =head1 User Name Functions
2742:
2743: =over 4
2744:
1.648 raeburn 2745: =item * &plainname($uname,$udom,$first)
1.81 albertel 2746:
1.112 bowersj2 2747: Takes a users logon name and returns it as a string in
1.226 albertel 2748: "first middle last generation" form
2749: if $first is set to 'lastname' then it returns it as
2750: 'lastname generation, firstname middlename' if their is a lastname
1.81 albertel 2751:
2752: =cut
1.61 www 2753:
1.295 www 2754:
1.81 albertel 2755: ###############################################################
1.61 www 2756: sub plainname {
1.226 albertel 2757: my ($uname,$udom,$first)=@_;
1.537 albertel 2758: return if (!defined($uname) || !defined($udom));
1.295 www 2759: my %names=&getnames($uname,$udom);
1.226 albertel 2760: my $name=&Apache::lonnet::format_name($names{'firstname'},
2761: $names{'middlename'},
2762: $names{'lastname'},
2763: $names{'generation'},$first);
2764: $name=~s/^\s+//;
1.62 www 2765: $name=~s/\s+$//;
2766: $name=~s/\s+/ /g;
1.353 albertel 2767: if ($name !~ /\S/) { $name=$uname.':'.$udom; }
1.62 www 2768: return $name;
1.61 www 2769: }
1.66 www 2770:
2771: # -------------------------------------------------------------------- Nickname
1.81 albertel 2772: =pod
2773:
1.648 raeburn 2774: =item * &nickname($uname,$udom)
1.81 albertel 2775:
2776: Gets a users name and returns it as a string as
2777:
2778: ""nickname""
1.66 www 2779:
1.81 albertel 2780: if the user has a nickname or
2781:
2782: "first middle last generation"
2783:
2784: if the user does not
2785:
2786: =cut
1.66 www 2787:
2788: sub nickname {
2789: my ($uname,$udom)=@_;
1.537 albertel 2790: return if (!defined($uname) || !defined($udom));
1.295 www 2791: my %names=&getnames($uname,$udom);
1.68 albertel 2792: my $name=$names{'nickname'};
1.66 www 2793: if ($name) {
2794: $name='"'.$name.'"';
2795: } else {
2796: $name=$names{'firstname'}.' '.$names{'middlename'}.' '.
2797: $names{'lastname'}.' '.$names{'generation'};
2798: $name=~s/\s+$//;
2799: $name=~s/\s+/ /g;
2800: }
2801: return $name;
2802: }
2803:
1.295 www 2804: sub getnames {
2805: my ($uname,$udom)=@_;
1.537 albertel 2806: return if (!defined($uname) || !defined($udom));
1.433 albertel 2807: if ($udom eq 'public' && $uname eq 'public') {
2808: return ('lastname' => &mt('Public'));
2809: }
1.295 www 2810: my $id=$uname.':'.$udom;
2811: my ($names,$cached)=&Apache::lonnet::is_cached_new('namescache',$id);
2812: if ($cached) {
2813: return %{$names};
2814: } else {
2815: my %loadnames=&Apache::lonnet::get('environment',
2816: ['firstname','middlename','lastname','generation','nickname'],
2817: $udom,$uname);
2818: &Apache::lonnet::do_cache_new('namescache',$id,\%loadnames);
2819: return %loadnames;
2820: }
2821: }
1.61 www 2822:
1.542 raeburn 2823: # -------------------------------------------------------------------- getemails
1.648 raeburn 2824:
1.542 raeburn 2825: =pod
2826:
1.648 raeburn 2827: =item * &getemails($uname,$udom)
1.542 raeburn 2828:
2829: Gets a user's email information and returns it as a hash with keys:
2830: notification, critnotification, permanentemail
2831:
2832: For notification and critnotification, values are comma-separated lists
1.648 raeburn 2833: of e-mail addresses; for permanentemail, value is a single e-mail address.
1.542 raeburn 2834:
1.648 raeburn 2835:
1.542 raeburn 2836: =cut
2837:
1.648 raeburn 2838:
1.466 albertel 2839: sub getemails {
2840: my ($uname,$udom)=@_;
2841: if ($udom eq 'public' && $uname eq 'public') {
2842: return;
2843: }
1.467 www 2844: if (!$udom) { $udom=$env{'user.domain'}; }
2845: if (!$uname) { $uname=$env{'user.name'}; }
1.466 albertel 2846: my $id=$uname.':'.$udom;
2847: my ($names,$cached)=&Apache::lonnet::is_cached_new('emailscache',$id);
2848: if ($cached) {
2849: return %{$names};
2850: } else {
2851: my %loadnames=&Apache::lonnet::get('environment',
2852: ['notification','critnotification',
2853: 'permanentemail'],
2854: $udom,$uname);
2855: &Apache::lonnet::do_cache_new('emailscache',$id,\%loadnames);
2856: return %loadnames;
2857: }
2858: }
2859:
1.551 albertel 2860: sub flush_email_cache {
2861: my ($uname,$udom)=@_;
2862: if (!$udom) { $udom =$env{'user.domain'}; }
2863: if (!$uname) { $uname=$env{'user.name'}; }
2864: return if ($udom eq 'public' && $uname eq 'public');
2865: my $id=$uname.':'.$udom;
2866: &Apache::lonnet::devalidate_cache_new('emailscache',$id);
2867: }
2868:
1.728 raeburn 2869: # -------------------------------------------------------------------- getlangs
2870:
2871: =pod
2872:
2873: =item * &getlangs($uname,$udom)
2874:
2875: Gets a user's language preference and returns it as a hash with key:
2876: language.
2877:
2878: =cut
2879:
2880:
2881: sub getlangs {
2882: my ($uname,$udom) = @_;
2883: if (!$udom) { $udom =$env{'user.domain'}; }
2884: if (!$uname) { $uname=$env{'user.name'}; }
2885: my $id=$uname.':'.$udom;
2886: my ($langs,$cached)=&Apache::lonnet::is_cached_new('userlangs',$id);
2887: if ($cached) {
2888: return %{$langs};
2889: } else {
2890: my %loadlangs=&Apache::lonnet::get('environment',['languages'],
2891: $udom,$uname);
2892: &Apache::lonnet::do_cache_new('userlangs',$id,\%loadlangs);
2893: return %loadlangs;
2894: }
2895: }
2896:
2897: sub flush_langs_cache {
2898: my ($uname,$udom)=@_;
2899: if (!$udom) { $udom =$env{'user.domain'}; }
2900: if (!$uname) { $uname=$env{'user.name'}; }
2901: return if ($udom eq 'public' && $uname eq 'public');
2902: my $id=$uname.':'.$udom;
2903: &Apache::lonnet::devalidate_cache_new('userlangs',$id);
2904: }
2905:
1.61 www 2906: # ------------------------------------------------------------------ Screenname
1.81 albertel 2907:
2908: =pod
2909:
1.648 raeburn 2910: =item * &screenname($uname,$udom)
1.81 albertel 2911:
2912: Gets a users screenname and returns it as a string
2913:
2914: =cut
1.61 www 2915:
2916: sub screenname {
2917: my ($uname,$udom)=@_;
1.258 albertel 2918: if ($uname eq $env{'user.name'} &&
2919: $udom eq $env{'user.domain'}) {return $env{'environment.screenname'};}
1.212 albertel 2920: my %names=&Apache::lonnet::get('environment',['screenname'],$udom,$uname);
1.68 albertel 2921: return $names{'screenname'};
1.62 www 2922: }
2923:
1.212 albertel 2924:
1.802 bisitz 2925: # ------------------------------------------------------------- Confirm Wrapper
2926: =pod
2927:
2928: =item confirmwrapper
2929:
2930: Wrap messages about completion of operation in box
2931:
2932: =cut
2933:
2934: sub confirmwrapper {
2935: my ($message)=@_;
2936: if ($message) {
2937: return "\n".'<div class="LC_confirm_box">'."\n"
2938: .$message."\n"
2939: .'</div>'."\n";
2940: } else {
2941: return $message;
2942: }
2943: }
2944:
1.62 www 2945: # ------------------------------------------------------------- Message Wrapper
2946:
2947: sub messagewrapper {
1.369 www 2948: my ($link,$username,$domain,$subject,$text)=@_;
1.62 www 2949: return
1.441 albertel 2950: '<a href="/adm/email?compose=individual&'.
2951: 'recname='.$username.'&recdom='.$domain.
2952: '&subject='.&escape($subject).'&text='.&escape($text).'" '.
1.200 matthew 2953: 'title="'.&mt('Send message').'">'.$link.'</a>';
1.74 www 2954: }
1.802 bisitz 2955:
1.74 www 2956: # --------------------------------------------------------------- Notes Wrapper
2957:
2958: sub noteswrapper {
2959: my ($link,$un,$do)=@_;
2960: return
2961: "<a href='/adm/email?recordftf=retrieve&recname=$un&recdom=$do'>$link</a>";
1.62 www 2962: }
1.802 bisitz 2963:
1.62 www 2964: # ------------------------------------------------------------- Aboutme Wrapper
2965:
2966: sub aboutmewrapper {
1.166 www 2967: my ($link,$username,$domain,$target)=@_;
1.447 raeburn 2968: if (!defined($username) && !defined($domain)) {
2969: return;
2970: }
1.205 www 2971: return '<a href="/adm/'.$domain.'/'.$username.'/aboutme"'.
1.756 weissno 2972: ($target?' target="$target"':'').' title="'.&mt("View this user's personal information page").'">'.$link.'</a>';
1.62 www 2973: }
2974:
2975: # ------------------------------------------------------------ Syllabus Wrapper
2976:
2977: sub syllabuswrapper {
1.707 bisitz 2978: my ($linktext,$coursedir,$domain)=@_;
1.208 matthew 2979: return qq{<a href="/public/$domain/$coursedir/syllabus">$linktext</a>};
1.61 www 2980: }
1.14 harris41 2981:
1.802 bisitz 2982: # -----------------------------------------------------------------------------
2983:
1.208 matthew 2984: sub track_student_link {
1.887 raeburn 2985: my ($linktext,$sname,$sdom,$target,$start,$only_body) = @_;
1.268 albertel 2986: my $link ="/adm/trackstudent?";
1.208 matthew 2987: my $title = 'View recent activity';
2988: if (defined($sname) && $sname !~ /^\s*$/ &&
2989: defined($sdom) && $sdom !~ /^\s*$/) {
1.268 albertel 2990: $link .= "selected_student=$sname:$sdom";
1.208 matthew 2991: $title .= ' of this student';
1.268 albertel 2992: }
1.208 matthew 2993: if (defined($target) && $target !~ /^\s*$/) {
2994: $target = qq{target="$target"};
2995: } else {
2996: $target = '';
2997: }
1.268 albertel 2998: if ($start) { $link.='&start='.$start; }
1.887 raeburn 2999: if ($only_body) { $link .= '&only_body=1'; }
1.554 albertel 3000: $title = &mt($title);
3001: $linktext = &mt($linktext);
1.448 albertel 3002: return qq{<a href="$link" title="$title" $target>$linktext</a>}.
3003: &help_open_topic('View_recent_activity');
1.208 matthew 3004: }
3005:
1.781 raeburn 3006: sub slot_reservations_link {
3007: my ($linktext,$sname,$sdom,$target) = @_;
3008: my $link ="/adm/slotrequest?command=showresv&origin=aboutme";
3009: my $title = 'View slot reservation history';
3010: if (defined($sname) && $sname !~ /^\s*$/ &&
3011: defined($sdom) && $sdom !~ /^\s*$/) {
3012: $link .= "&uname=$sname&udom=$sdom";
3013: $title .= ' of this student';
3014: }
3015: if (defined($target) && $target !~ /^\s*$/) {
3016: $target = qq{target="$target"};
3017: } else {
3018: $target = '';
3019: }
3020: $title = &mt($title);
3021: $linktext = &mt($linktext);
3022: return qq{<a href="$link" title="$title" $target>$linktext</a>};
3023: # FIXME uncomment when help item created: &help_open_topic('Slot_Reservation_History');
3024:
3025: }
3026:
1.508 www 3027: # ===================================================== Display a student photo
3028:
3029:
1.509 albertel 3030: sub student_image_tag {
1.508 www 3031: my ($domain,$user)=@_;
3032: my $imgsrc=&Apache::lonnet::studentphoto($domain,$user,'jpg');
3033: if (($imgsrc) && ($imgsrc ne '/adm/lonKaputt/lonlogo_broken.gif')) {
3034: return '<img src="'.$imgsrc.'" align="right" />';
3035: } else {
3036: return '';
3037: }
3038: }
3039:
1.112 bowersj2 3040: =pod
3041:
3042: =back
3043:
3044: =head1 Access .tab File Data
3045:
3046: =over 4
3047:
1.648 raeburn 3048: =item * &languageids()
1.112 bowersj2 3049:
3050: returns list of all language ids
3051:
3052: =cut
3053:
1.14 harris41 3054: sub languageids {
1.16 harris41 3055: return sort(keys(%language));
1.14 harris41 3056: }
3057:
1.112 bowersj2 3058: =pod
3059:
1.648 raeburn 3060: =item * &languagedescription()
1.112 bowersj2 3061:
3062: returns description of a specified language id
3063:
3064: =cut
3065:
1.14 harris41 3066: sub languagedescription {
1.125 www 3067: my $code=shift;
3068: return ($supported_language{$code}?'* ':'').
3069: $language{$code}.
1.126 www 3070: ($supported_language{$code}?' ('.&mt('interface available').')':'');
1.145 www 3071: }
3072:
3073: sub plainlanguagedescription {
3074: my $code=shift;
3075: return $language{$code};
3076: }
3077:
3078: sub supportedlanguagecode {
3079: my $code=shift;
3080: return $supported_language{$code};
1.97 www 3081: }
3082:
1.112 bowersj2 3083: =pod
3084:
1.648 raeburn 3085: =item * ©rightids()
1.112 bowersj2 3086:
3087: returns list of all copyrights
3088:
3089: =cut
3090:
3091: sub copyrightids {
3092: return sort(keys(%cprtag));
3093: }
3094:
3095: =pod
3096:
1.648 raeburn 3097: =item * ©rightdescription()
1.112 bowersj2 3098:
3099: returns description of a specified copyright id
3100:
3101: =cut
3102:
3103: sub copyrightdescription {
1.166 www 3104: return &mt($cprtag{shift(@_)});
1.112 bowersj2 3105: }
1.197 matthew 3106:
3107: =pod
3108:
1.648 raeburn 3109: =item * &source_copyrightids()
1.192 taceyjo1 3110:
3111: returns list of all source copyrights
3112:
3113: =cut
3114:
3115: sub source_copyrightids {
3116: return sort(keys(%scprtag));
3117: }
3118:
3119: =pod
3120:
1.648 raeburn 3121: =item * &source_copyrightdescription()
1.192 taceyjo1 3122:
3123: returns description of a specified source copyright id
3124:
3125: =cut
3126:
3127: sub source_copyrightdescription {
3128: return &mt($scprtag{shift(@_)});
3129: }
1.112 bowersj2 3130:
3131: =pod
3132:
1.648 raeburn 3133: =item * &filecategories()
1.112 bowersj2 3134:
3135: returns list of all file categories
3136:
3137: =cut
3138:
3139: sub filecategories {
3140: return sort(keys(%category_extensions));
3141: }
3142:
3143: =pod
3144:
1.648 raeburn 3145: =item * &filecategorytypes()
1.112 bowersj2 3146:
3147: returns list of file types belonging to a given file
3148: category
3149:
3150: =cut
3151:
3152: sub filecategorytypes {
1.356 albertel 3153: my ($cat) = @_;
3154: return @{$category_extensions{lc($cat)}};
1.112 bowersj2 3155: }
3156:
3157: =pod
3158:
1.648 raeburn 3159: =item * &fileembstyle()
1.112 bowersj2 3160:
3161: returns embedding style for a specified file type
3162:
3163: =cut
3164:
3165: sub fileembstyle {
3166: return $fe{lc(shift(@_))};
1.169 www 3167: }
3168:
1.351 www 3169: sub filemimetype {
3170: return $fm{lc(shift(@_))};
3171: }
3172:
1.169 www 3173:
3174: sub filecategoryselect {
3175: my ($name,$value)=@_;
1.189 matthew 3176: return &select_form($value,$name,
1.169 www 3177: '' => &mt('Any category'),
3178: map { $_,$_ } sort(keys(%category_extensions)));
1.112 bowersj2 3179: }
3180:
3181: =pod
3182:
1.648 raeburn 3183: =item * &filedescription()
1.112 bowersj2 3184:
3185: returns description for a specified file type
3186:
3187: =cut
3188:
3189: sub filedescription {
1.188 matthew 3190: my $file_description = $fd{lc(shift())};
3191: $file_description =~ s:([\[\]]):~$1:g;
3192: return &mt($file_description);
1.112 bowersj2 3193: }
3194:
3195: =pod
3196:
1.648 raeburn 3197: =item * &filedescriptionex()
1.112 bowersj2 3198:
3199: returns description for a specified file type with
3200: extra formatting
3201:
3202: =cut
3203:
3204: sub filedescriptionex {
3205: my $ex=shift;
1.188 matthew 3206: my $file_description = $fd{lc($ex)};
3207: $file_description =~ s:([\[\]]):~$1:g;
3208: return '.'.$ex.' '.&mt($file_description);
1.112 bowersj2 3209: }
3210:
3211: # End of .tab access
3212: =pod
3213:
3214: =back
3215:
3216: =cut
3217:
3218: # ------------------------------------------------------------------ File Types
3219: sub fileextensions {
3220: return sort(keys(%fe));
3221: }
3222:
1.97 www 3223: # ----------------------------------------------------------- Display Languages
3224: # returns a hash with all desired display languages
3225: #
3226:
3227: sub display_languages {
3228: my %languages=();
1.695 raeburn 3229: foreach my $lang (&Apache::lonlocal::preferred_languages()) {
1.356 albertel 3230: $languages{$lang}=1;
1.97 www 3231: }
3232: &get_unprocessed_cgi($ENV{'QUERY_STRING'},['displaylanguage']);
1.258 albertel 3233: if ($env{'form.displaylanguage'}) {
1.356 albertel 3234: foreach my $lang (split(/\s*(\,|\;|\:)\s*/,$env{'form.displaylanguage'})) {
3235: $languages{$lang}=1;
1.97 www 3236: }
3237: }
3238: return %languages;
1.14 harris41 3239: }
3240:
1.582 albertel 3241: sub languages {
3242: my ($possible_langs) = @_;
1.695 raeburn 3243: my @preferred_langs = &Apache::lonlocal::preferred_languages();
1.582 albertel 3244: if (!ref($possible_langs)) {
3245: if( wantarray ) {
3246: return @preferred_langs;
3247: } else {
3248: return $preferred_langs[0];
3249: }
3250: }
3251: my %possibilities = map { $_ => 1 } (@$possible_langs);
3252: my @preferred_possibilities;
3253: foreach my $preferred_lang (@preferred_langs) {
3254: if (exists($possibilities{$preferred_lang})) {
3255: push(@preferred_possibilities, $preferred_lang);
3256: }
3257: }
3258: if( wantarray ) {
3259: return @preferred_possibilities;
3260: }
3261: return $preferred_possibilities[0];
3262: }
3263:
1.742 raeburn 3264: sub user_lang {
3265: my ($touname,$toudom,$fromcid) = @_;
3266: my @userlangs;
3267: if (($fromcid ne '') && ($env{'course.'.$fromcid.'.languages'} ne '')) {
3268: @userlangs=(@userlangs,split(/\s*(\,|\;|\:)\s*/,
3269: $env{'course.'.$fromcid.'.languages'}));
3270: } else {
3271: my %langhash = &getlangs($touname,$toudom);
3272: if ($langhash{'languages'} ne '') {
3273: @userlangs = split(/\s*(\,|\;|\:)\s*/,$langhash{'languages'});
3274: } else {
3275: my %domdefs = &Apache::lonnet::get_domain_defaults($toudom);
3276: if ($domdefs{'lang_def'} ne '') {
3277: @userlangs = ($domdefs{'lang_def'});
3278: }
3279: }
3280: }
3281: my @languages=&Apache::lonlocal::get_genlanguages(@userlangs);
3282: my $user_lh = Apache::localize->get_handle(@languages);
3283: return $user_lh;
3284: }
3285:
3286:
1.112 bowersj2 3287: ###############################################################
3288: ## Student Answer Attempts ##
3289: ###############################################################
3290:
3291: =pod
3292:
3293: =head1 Alternate Problem Views
3294:
3295: =over 4
3296:
1.648 raeburn 3297: =item * &get_previous_attempt($symb, $username, $domain, $course,
1.112 bowersj2 3298: $getattempt, $regexp, $gradesub)
3299:
3300: Return string with previous attempt on problem. Arguments:
3301:
3302: =over 4
3303:
3304: =item * $symb: Problem, including path
3305:
3306: =item * $username: username of the desired student
3307:
3308: =item * $domain: domain of the desired student
1.14 harris41 3309:
1.112 bowersj2 3310: =item * $course: Course ID
1.14 harris41 3311:
1.112 bowersj2 3312: =item * $getattempt: Leave blank for all attempts, otherwise put
3313: something
1.14 harris41 3314:
1.112 bowersj2 3315: =item * $regexp: if string matches this regexp, the string will be
3316: sent to $gradesub
1.14 harris41 3317:
1.112 bowersj2 3318: =item * $gradesub: routine that processes the string if it matches $regexp
1.14 harris41 3319:
1.112 bowersj2 3320: =back
1.14 harris41 3321:
1.112 bowersj2 3322: The output string is a table containing all desired attempts, if any.
1.16 harris41 3323:
1.112 bowersj2 3324: =cut
1.1 albertel 3325:
3326: sub get_previous_attempt {
1.43 ng 3327: my ($symb,$username,$domain,$course,$getattempt,$regexp,$gradesub)=@_;
1.1 albertel 3328: my $prevattempts='';
1.43 ng 3329: no strict 'refs';
1.1 albertel 3330: if ($symb) {
1.3 albertel 3331: my (%returnhash)=
3332: &Apache::lonnet::restore($symb,$course,$domain,$username);
1.1 albertel 3333: if ($returnhash{'version'}) {
3334: my %lasthash=();
3335: my $version;
3336: for ($version=1;$version<=$returnhash{'version'};$version++) {
1.356 albertel 3337: foreach my $key (sort(split(/\:/,$returnhash{$version.':keys'}))) {
3338: $lasthash{$key}=$returnhash{$version.':'.$key};
1.19 harris41 3339: }
1.1 albertel 3340: }
1.596 albertel 3341: $prevattempts=&start_data_table().&start_data_table_header_row();
3342: $prevattempts.='<th>'.&mt('History').'</th>';
1.356 albertel 3343: foreach my $key (sort(keys(%lasthash))) {
3344: my ($ign,@parts) = split(/\./,$key);
1.41 ng 3345: if ($#parts > 0) {
1.31 albertel 3346: my $data=$parts[-1];
3347: pop(@parts);
1.596 albertel 3348: $prevattempts.='<th>'.&mt('Part ').join('.',@parts).'<br />'.$data.' </th>';
1.31 albertel 3349: } else {
1.41 ng 3350: if ($#parts == 0) {
3351: $prevattempts.='<th>'.$parts[0].'</th>';
3352: } else {
3353: $prevattempts.='<th>'.$ign.'</th>';
3354: }
1.31 albertel 3355: }
1.16 harris41 3356: }
1.596 albertel 3357: $prevattempts.=&end_data_table_header_row();
1.40 ng 3358: if ($getattempt eq '') {
3359: for ($version=1;$version<=$returnhash{'version'};$version++) {
1.596 albertel 3360: $prevattempts.=&start_data_table_row().
3361: '<td>'.&mt('Transaction [_1]',$version).'</td>';
1.356 albertel 3362: foreach my $key (sort(keys(%lasthash))) {
1.581 albertel 3363: my $value = &format_previous_attempt_value($key,
3364: $returnhash{$version.':'.$key});
3365: $prevattempts.='<td>'.$value.' </td>';
1.40 ng 3366: }
1.596 albertel 3367: $prevattempts.=&end_data_table_row();
1.40 ng 3368: }
1.1 albertel 3369: }
1.596 albertel 3370: $prevattempts.=&start_data_table_row().'<td>'.&mt('Current').'</td>';
1.356 albertel 3371: foreach my $key (sort(keys(%lasthash))) {
1.581 albertel 3372: my $value = &format_previous_attempt_value($key,$lasthash{$key});
1.356 albertel 3373: if ($key =~/$regexp$/ && (defined &$gradesub)) {$value = &$gradesub($value)}
1.40 ng 3374: $prevattempts.='<td>'.$value.' </td>';
1.16 harris41 3375: }
1.596 albertel 3376: $prevattempts.= &end_data_table_row().&end_data_table();
1.1 albertel 3377: } else {
1.596 albertel 3378: $prevattempts=
3379: &start_data_table().&start_data_table_row().
3380: '<td>'.&mt('Nothing submitted - no attempts.').'</td>'.
3381: &end_data_table_row().&end_data_table();
1.1 albertel 3382: }
3383: } else {
1.596 albertel 3384: $prevattempts=
3385: &start_data_table().&start_data_table_row().
3386: '<td>'.&mt('No data.').'</td>'.
3387: &end_data_table_row().&end_data_table();
1.1 albertel 3388: }
1.10 albertel 3389: }
3390:
1.581 albertel 3391: sub format_previous_attempt_value {
3392: my ($key,$value) = @_;
3393: if ($key =~ /timestamp/) {
3394: $value = &Apache::lonlocal::locallocaltime($value);
3395: } elsif (ref($value) eq 'ARRAY') {
3396: $value = '('.join(', ', @{ $value }).')';
3397: } else {
3398: $value = &unescape($value);
3399: }
3400: return $value;
3401: }
3402:
3403:
1.107 albertel 3404: sub relative_to_absolute {
3405: my ($url,$output)=@_;
3406: my $parser=HTML::TokeParser->new(\$output);
3407: my $token;
3408: my $thisdir=$url;
3409: my @rlinks=();
3410: while ($token=$parser->get_token) {
3411: if ($token->[0] eq 'S') {
3412: if ($token->[1] eq 'a') {
3413: if ($token->[2]->{'href'}) {
3414: $rlinks[$#rlinks+1]=$token->[2]->{'href'};
3415: }
3416: } elsif ($token->[1] eq 'img' || $token->[1] eq 'embed' ) {
3417: $rlinks[$#rlinks+1]=$token->[2]->{'src'};
3418: } elsif ($token->[1] eq 'base') {
3419: $thisdir=$token->[2]->{'href'};
3420: }
3421: }
3422: }
3423: $thisdir=~s-/[^/]*$--;
1.356 albertel 3424: foreach my $link (@rlinks) {
1.726 raeburn 3425: unless (($link=~/^https?\:\/\//i) ||
1.356 albertel 3426: ($link=~/^\//) ||
3427: ($link=~/^javascript:/i) ||
3428: ($link=~/^mailto:/i) ||
3429: ($link=~/^\#/)) {
3430: my $newlocation=&Apache::lonnet::hreflocation($thisdir,$link);
3431: $output=~s/(\"|\'|\=\s*)\Q$link\E(\"|\'|\s|\>)/$1$newlocation$2/;
1.107 albertel 3432: }
3433: }
3434: # -------------------------------------------------- Deal with Applet codebases
3435: $output=~s/(\<applet[^\>]+)(codebase\=[^\S\>]+)*([^\>]*)\>/$1.($2?$2:' codebase="'.$thisdir.'"').$3.'>'/gei;
3436: return $output;
3437: }
3438:
1.112 bowersj2 3439: =pod
3440:
1.648 raeburn 3441: =item * &get_student_view()
1.112 bowersj2 3442:
3443: show a snapshot of what student was looking at
3444:
3445: =cut
3446:
1.10 albertel 3447: sub get_student_view {
1.186 albertel 3448: my ($symb,$username,$domain,$courseid,$target,$moreenv) = @_;
1.114 www 3449: my ($map,$id,$feedurl) = &Apache::lonnet::decode_symb($symb);
1.186 albertel 3450: my (%form);
1.10 albertel 3451: my @elements=('symb','courseid','domain','username');
3452: foreach my $element (@elements) {
1.186 albertel 3453: $form{'grade_'.$element}=eval '$'.$element #'
1.10 albertel 3454: }
1.186 albertel 3455: if (defined($moreenv)) {
3456: %form=(%form,%{$moreenv});
3457: }
1.236 albertel 3458: if (defined($target)) { $form{'grade_target'} = $target; }
1.107 albertel 3459: $feedurl=&Apache::lonnet::clutter($feedurl);
1.650 www 3460: my ($userview,$response)=&Apache::lonnet::ssi_body($feedurl,%form);
1.11 albertel 3461: $userview=~s/\<body[^\>]*\>//gi;
3462: $userview=~s/\<\/body\>//gi;
3463: $userview=~s/\<html\>//gi;
3464: $userview=~s/\<\/html\>//gi;
3465: $userview=~s/\<head\>//gi;
3466: $userview=~s/\<\/head\>//gi;
3467: $userview=~s/action\s*\=/would_be_action\=/gi;
1.107 albertel 3468: $userview=&relative_to_absolute($feedurl,$userview);
1.650 www 3469: if (wantarray) {
3470: return ($userview,$response);
3471: } else {
3472: return $userview;
3473: }
3474: }
3475:
3476: sub get_student_view_with_retries {
3477: my ($symb,$retries,$username,$domain,$courseid,$target,$moreenv) = @_;
3478:
3479: my $ok = 0; # True if we got a good response.
3480: my $content;
3481: my $response;
3482:
3483: # Try to get the student_view done. within the retries count:
3484:
3485: do {
3486: ($content, $response) = &get_student_view($symb,$username,$domain,$courseid,$target,$moreenv);
3487: $ok = $response->is_success;
3488: if (!$ok) {
3489: &Apache::lonnet::logthis("Failed get_student_view_with_retries on $symb: ".$response->is_success.', '.$response->code.', '.$response->message);
3490: }
3491: $retries--;
3492: } while (!$ok && ($retries > 0));
3493:
3494: if (!$ok) {
3495: $content = ''; # On error return an empty content.
3496: }
1.651 www 3497: if (wantarray) {
3498: return ($content, $response);
3499: } else {
3500: return $content;
3501: }
1.11 albertel 3502: }
3503:
1.112 bowersj2 3504: =pod
3505:
1.648 raeburn 3506: =item * &get_student_answers()
1.112 bowersj2 3507:
3508: show a snapshot of how student was answering problem
3509:
3510: =cut
3511:
1.11 albertel 3512: sub get_student_answers {
1.100 sakharuk 3513: my ($symb,$username,$domain,$courseid,%form) = @_;
1.114 www 3514: my ($map,$id,$feedurl) = &Apache::lonnet::decode_symb($symb);
1.186 albertel 3515: my (%moreenv);
1.11 albertel 3516: my @elements=('symb','courseid','domain','username');
3517: foreach my $element (@elements) {
1.186 albertel 3518: $moreenv{'grade_'.$element}=eval '$'.$element #'
1.10 albertel 3519: }
1.186 albertel 3520: $moreenv{'grade_target'}='answer';
3521: %moreenv=(%form,%moreenv);
1.497 raeburn 3522: $feedurl = &Apache::lonnet::clutter($feedurl);
3523: my $userview=&Apache::lonnet::ssi($feedurl,%moreenv);
1.10 albertel 3524: return $userview;
1.1 albertel 3525: }
1.116 albertel 3526:
3527: =pod
3528:
3529: =item * &submlink()
3530:
1.242 albertel 3531: Inputs: $text $uname $udom $symb $target
1.116 albertel 3532:
3533: Returns: A link to grades.pm such as to see the SUBM view of a student
3534:
3535: =cut
3536:
3537: ###############################################
3538: sub submlink {
1.242 albertel 3539: my ($text,$uname,$udom,$symb,$target)=@_;
1.116 albertel 3540: if (!($uname && $udom)) {
3541: (my $cursymb, my $courseid,$udom,$uname)=
1.463 albertel 3542: &Apache::lonnet::whichuser($symb);
1.116 albertel 3543: if (!$symb) { $symb=$cursymb; }
3544: }
1.254 matthew 3545: if (!$symb) { $symb=&Apache::lonnet::symbread(); }
1.369 www 3546: $symb=&escape($symb);
1.242 albertel 3547: if ($target) { $target="target=\"$target\""; }
3548: return '<a href="/adm/grades?&command=submission&'.
3549: 'symb='.$symb.'&student='.$uname.
3550: '&userdom='.$udom.'" '.$target.'>'.$text.'</a>';
3551: }
3552: ##############################################
3553:
3554: =pod
3555:
3556: =item * &pgrdlink()
3557:
3558: Inputs: $text $uname $udom $symb $target
3559:
3560: Returns: A link to grades.pm such as to see the PGRD view of a student
3561:
3562: =cut
3563:
3564: ###############################################
3565: sub pgrdlink {
3566: my $link=&submlink(@_);
3567: $link=~s/(&command=submission)/$1&showgrading=yes/;
3568: return $link;
3569: }
3570: ##############################################
3571:
3572: =pod
3573:
3574: =item * &pprmlink()
3575:
3576: Inputs: $text $uname $udom $symb $target
3577:
3578: Returns: A link to parmset.pm such as to see the PPRM view of a
1.283 albertel 3579: student and a specific resource
1.242 albertel 3580:
3581: =cut
3582:
3583: ###############################################
3584: sub pprmlink {
3585: my ($text,$uname,$udom,$symb,$target)=@_;
3586: if (!($uname && $udom)) {
3587: (my $cursymb, my $courseid,$udom,$uname)=
1.463 albertel 3588: &Apache::lonnet::whichuser($symb);
1.242 albertel 3589: if (!$symb) { $symb=$cursymb; }
3590: }
1.254 matthew 3591: if (!$symb) { $symb=&Apache::lonnet::symbread(); }
1.369 www 3592: $symb=&escape($symb);
1.242 albertel 3593: if ($target) { $target="target=\"$target\""; }
1.595 albertel 3594: return '<a href="/adm/parmset?command=set&'.
3595: 'symb='.$symb.'&uname='.$uname.
3596: '&udom='.$udom.'" '.$target.'>'.$text.'</a>';
1.116 albertel 3597: }
3598: ##############################################
1.37 matthew 3599:
1.112 bowersj2 3600: =pod
3601:
3602: =back
3603:
3604: =cut
3605:
1.37 matthew 3606: ###############################################
1.51 www 3607:
3608:
3609: sub timehash {
1.687 raeburn 3610: my ($thistime) = @_;
3611: my $timezone = &Apache::lonlocal::gettimezone();
3612: my $dt = DateTime->from_epoch(epoch => $thistime)
3613: ->set_time_zone($timezone);
3614: my $wday = $dt->day_of_week();
3615: if ($wday == 7) { $wday = 0; }
3616: return ( 'second' => $dt->second(),
3617: 'minute' => $dt->minute(),
3618: 'hour' => $dt->hour(),
3619: 'day' => $dt->day_of_month(),
3620: 'month' => $dt->month(),
3621: 'year' => $dt->year(),
3622: 'weekday' => $wday,
3623: 'dayyear' => $dt->day_of_year(),
3624: 'dlsav' => $dt->is_dst() );
1.51 www 3625: }
3626:
1.370 www 3627: sub utc_string {
3628: my ($date)=@_;
1.371 www 3629: return strftime("%Y%m%dT%H%M%SZ",gmtime($date));
1.370 www 3630: }
3631:
1.51 www 3632: sub maketime {
3633: my %th=@_;
1.687 raeburn 3634: my ($epoch_time,$timezone,$dt);
3635: $timezone = &Apache::lonlocal::gettimezone();
3636: eval {
3637: $dt = DateTime->new( year => $th{'year'},
3638: month => $th{'month'},
3639: day => $th{'day'},
3640: hour => $th{'hour'},
3641: minute => $th{'minute'},
3642: second => $th{'second'},
3643: time_zone => $timezone,
3644: );
3645: };
3646: if (!$@) {
3647: $epoch_time = $dt->epoch;
3648: if ($epoch_time) {
3649: return $epoch_time;
3650: }
3651: }
1.51 www 3652: return POSIX::mktime(
3653: ($th{'seconds'},$th{'minutes'},$th{'hours'},
1.210 www 3654: $th{'day'},$th{'month'}-1,$th{'year'}-1900,0,0,-1));
1.70 www 3655: }
3656:
3657: #########################################
1.51 www 3658:
3659: sub findallcourses {
1.482 raeburn 3660: my ($roles,$uname,$udom) = @_;
1.355 albertel 3661: my %roles;
3662: if (ref($roles)) { %roles = map { $_ => 1 } @{$roles}; }
1.348 albertel 3663: my %courses;
1.51 www 3664: my $now=time;
1.482 raeburn 3665: if (!defined($uname)) {
3666: $uname = $env{'user.name'};
3667: }
3668: if (!defined($udom)) {
3669: $udom = $env{'user.domain'};
3670: }
3671: if (($uname ne $env{'user.name'}) || ($udom ne $env{'user.domain'})) {
3672: my %roleshash = &Apache::lonnet::dump('roles',$udom,$uname);
3673: if (!%roles) {
3674: %roles = (
3675: cc => 1,
3676: in => 1,
3677: ep => 1,
3678: ta => 1,
3679: cr => 1,
3680: st => 1,
3681: );
3682: }
3683: foreach my $entry (keys(%roleshash)) {
3684: my ($trole,$tend,$tstart) = split(/_/,$roleshash{$entry});
3685: if ($trole =~ /^cr/) {
3686: next if (!exists($roles{$trole}) && !exists($roles{'cr'}));
3687: } else {
3688: next if (!exists($roles{$trole}));
3689: }
3690: if ($tend) {
3691: next if ($tend < $now);
3692: }
3693: if ($tstart) {
3694: next if ($tstart > $now);
3695: }
3696: my ($cdom,$cnum,$sec,$cnumpart,$secpart,$role,$realsec);
3697: (undef,$cdom,$cnumpart,$secpart) = split(/\//,$entry);
3698: if ($secpart eq '') {
3699: ($cnum,$role) = split(/_/,$cnumpart);
3700: $sec = 'none';
3701: $realsec = '';
3702: } else {
3703: $cnum = $cnumpart;
3704: ($sec,$role) = split(/_/,$secpart);
3705: $realsec = $sec;
1.490 raeburn 3706: }
1.482 raeburn 3707: $courses{$cdom.'_'.$cnum}{$sec} = $trole.'/'.$cdom.'/'.$cnum.'/'.$realsec;
3708: }
3709: } else {
3710: foreach my $key (keys(%env)) {
1.483 albertel 3711: if ( $key=~m{^user\.role\.(\w+)\./($match_domain)/($match_courseid)/?(\w*)$} ||
3712: $key=~m{^user\.role\.(cr/$match_domain/$match_username/\w+)\./($match_domain)/($match_courseid)/?(\w*)$}) {
1.482 raeburn 3713: my ($role,$cdom,$cnum,$sec) = ($1,$2,$3,$4);
3714: next if ($role eq 'ca' || $role eq 'aa');
3715: next if (%roles && !exists($roles{$role}));
3716: my ($starttime,$endtime)=split(/\./,$env{$key});
3717: my $active=1;
3718: if ($starttime) {
3719: if ($now<$starttime) { $active=0; }
3720: }
3721: if ($endtime) {
3722: if ($now>$endtime) { $active=0; }
3723: }
3724: if ($active) {
3725: if ($sec eq '') {
3726: $sec = 'none';
3727: }
3728: $courses{$cdom.'_'.$cnum}{$sec} =
3729: $role.'/'.$cdom.'/'.$cnum.'/'.$sec;
1.474 raeburn 3730: }
3731: }
1.51 www 3732: }
3733: }
1.474 raeburn 3734: return %courses;
1.51 www 3735: }
1.37 matthew 3736:
1.54 www 3737: ###############################################
1.474 raeburn 3738:
3739: sub blockcheck {
1.482 raeburn 3740: my ($setters,$activity,$uname,$udom) = @_;
1.490 raeburn 3741:
3742: if (!defined($udom)) {
3743: $udom = $env{'user.domain'};
3744: }
3745: if (!defined($uname)) {
3746: $uname = $env{'user.name'};
3747: }
3748:
3749: # If uname and udom are for a course, check for blocks in the course.
3750:
3751: if (&Apache::lonnet::is_course($udom,$uname)) {
3752: my %records = &Apache::lonnet::dump('comm_block',$udom,$uname);
1.502 raeburn 3753: my ($startblock,$endblock)=&get_blocks($setters,$activity,$udom,$uname);
1.490 raeburn 3754: return ($startblock,$endblock);
3755: }
1.474 raeburn 3756:
1.502 raeburn 3757: my $startblock = 0;
3758: my $endblock = 0;
1.482 raeburn 3759: my %live_courses = &findallcourses(undef,$uname,$udom);
1.474 raeburn 3760:
1.490 raeburn 3761: # If uname is for a user, and activity is course-specific, i.e.,
3762: # boards, chat or groups, check for blocking in current course only.
1.474 raeburn 3763:
1.490 raeburn 3764: if (($activity eq 'boards' || $activity eq 'chat' ||
3765: $activity eq 'groups') && ($env{'request.course.id'})) {
3766: foreach my $key (keys(%live_courses)) {
3767: if ($key ne $env{'request.course.id'}) {
3768: delete($live_courses{$key});
3769: }
3770: }
3771: }
3772:
3773: my $otheruser = 0;
3774: my %own_courses;
3775: if ((($uname ne $env{'user.name'})) || ($udom ne $env{'user.domain'})) {
3776: # Resource belongs to user other than current user.
3777: $otheruser = 1;
3778: # Gather courses for current user
3779: %own_courses =
3780: &findallcourses(undef,$env{'user.name'},$env{'user.domain'});
3781: }
3782:
3783: # Gather active course roles - course coordinator, instructor,
3784: # exam proctor, ta, student, or custom role.
1.474 raeburn 3785:
3786: foreach my $course (keys(%live_courses)) {
1.482 raeburn 3787: my ($cdom,$cnum);
3788: if ((defined($env{'course.'.$course.'.domain'})) && (defined($env{'course.'.$course.'.num'}))) {
3789: $cdom = $env{'course.'.$course.'.domain'};
3790: $cnum = $env{'course.'.$course.'.num'};
3791: } else {
1.490 raeburn 3792: ($cdom,$cnum) = split(/_/,$course);
1.482 raeburn 3793: }
3794: my $no_ownblock = 0;
3795: my $no_userblock = 0;
1.533 raeburn 3796: if ($otheruser && $activity ne 'com') {
1.490 raeburn 3797: # Check if current user has 'evb' priv for this
3798: if (defined($own_courses{$course})) {
3799: foreach my $sec (keys(%{$own_courses{$course}})) {
3800: my $checkrole = 'cm./'.$cdom.'/'.$cnum;
3801: if ($sec ne 'none') {
3802: $checkrole .= '/'.$sec;
3803: }
3804: if (&Apache::lonnet::allowed('evb',undef,undef,$checkrole)) {
3805: $no_ownblock = 1;
3806: last;
3807: }
3808: }
3809: }
3810: # if they have 'evb' priv and are currently not playing student
3811: next if (($no_ownblock) &&
3812: ($env{'request.role'} !~ m{^st\./$cdom/$cnum}));
3813: }
1.474 raeburn 3814: foreach my $sec (keys(%{$live_courses{$course}})) {
1.482 raeburn 3815: my $checkrole = 'cm./'.$cdom.'/'.$cnum;
1.474 raeburn 3816: if ($sec ne 'none') {
1.482 raeburn 3817: $checkrole .= '/'.$sec;
1.474 raeburn 3818: }
1.490 raeburn 3819: if ($otheruser) {
3820: # Resource belongs to user other than current user.
3821: # Assemble privs for that user, and check for 'evb' priv.
1.482 raeburn 3822: my ($trole,$tdom,$tnum,$tsec);
3823: my $entry = $live_courses{$course}{$sec};
3824: if ($entry =~ /^cr/) {
3825: ($trole,$tdom,$tnum,$tsec) =
3826: ($entry =~ m|^(cr/$match_domain/$match_username/\w+)\./($match_domain)/($match_username)/?(\w*)$|);
3827: } else {
3828: ($trole,$tdom,$tnum,$tsec) = split(/\//,$entry);
3829: }
3830: my ($spec,$area,$trest,%allroles,%userroles);
3831: $area = '/'.$tdom.'/'.$tnum;
3832: $trest = $tnum;
3833: if ($tsec ne '') {
3834: $area .= '/'.$tsec;
3835: $trest .= '/'.$tsec;
3836: }
3837: $spec = $trole.'.'.$area;
3838: if ($trole =~ /^cr/) {
3839: &Apache::lonnet::custom_roleprivs(\%allroles,$trole,
3840: $tdom,$spec,$trest,$area);
3841: } else {
3842: &Apache::lonnet::standard_roleprivs(\%allroles,$trole,
3843: $tdom,$spec,$trest,$area);
3844: }
3845: my ($author,$adv) = &Apache::lonnet::set_userprivs(\%userroles,\%allroles);
1.486 raeburn 3846: if ($userroles{'user.priv.'.$checkrole} =~ /evb\&([^\:]*)/) {
3847: if ($1) {
3848: $no_userblock = 1;
3849: last;
3850: }
3851: }
1.490 raeburn 3852: } else {
3853: # Resource belongs to current user
3854: # Check for 'evb' priv via lonnet::allowed().
1.482 raeburn 3855: if (&Apache::lonnet::allowed('evb',undef,undef,$checkrole)) {
3856: $no_ownblock = 1;
3857: last;
3858: }
1.474 raeburn 3859: }
3860: }
3861: # if they have the evb priv and are currently not playing student
1.482 raeburn 3862: next if (($no_ownblock) &&
1.491 albertel 3863: ($env{'request.role'} !~ m{^st\./\Q$cdom\E/\Q$cnum\E}));
1.482 raeburn 3864: next if ($no_userblock);
1.474 raeburn 3865:
1.866 kalberla 3866: # Retrieve blocking times and identity of locker for course
1.490 raeburn 3867: # of specified user, unless user has 'evb' privilege.
1.502 raeburn 3868:
3869: my ($start,$end)=&get_blocks($setters,$activity,$cdom,$cnum);
3870: if (($start != 0) &&
3871: (($startblock == 0) || ($startblock > $start))) {
3872: $startblock = $start;
3873: }
3874: if (($end != 0) &&
3875: (($endblock == 0) || ($endblock < $end))) {
3876: $endblock = $end;
3877: }
1.490 raeburn 3878: }
3879: return ($startblock,$endblock);
3880: }
3881:
3882: sub get_blocks {
3883: my ($setters,$activity,$cdom,$cnum) = @_;
3884: my $startblock = 0;
3885: my $endblock = 0;
3886: my $course = $cdom.'_'.$cnum;
3887: $setters->{$course} = {};
3888: $setters->{$course}{'staff'} = [];
3889: $setters->{$course}{'times'} = [];
3890: my %records = &Apache::lonnet::dump('comm_block',$cdom,$cnum);
3891: foreach my $record (keys(%records)) {
3892: my ($start,$end) = ($record =~ m/^(\d+)____(\d+)$/);
3893: if ($start <= time && $end >= time) {
3894: my ($staff_name,$staff_dom,$title,$blocks) =
3895: &parse_block_record($records{$record});
3896: if ($blocks->{$activity} eq 'on') {
3897: push(@{$$setters{$course}{'staff'}},[$staff_name,$staff_dom]);
3898: push(@{$$setters{$course}{'times'}}, [$start,$end]);
1.491 albertel 3899: if ( ($startblock == 0) || ($startblock > $start) ) {
3900: $startblock = $start;
1.490 raeburn 3901: }
1.491 albertel 3902: if ( ($endblock == 0) || ($endblock < $end) ) {
3903: $endblock = $end;
1.474 raeburn 3904: }
3905: }
3906: }
3907: }
3908: return ($startblock,$endblock);
3909: }
3910:
3911: sub parse_block_record {
3912: my ($record) = @_;
3913: my ($setuname,$setudom,$title,$blocks);
3914: if (ref($record) eq 'HASH') {
3915: ($setuname,$setudom) = split(/:/,$record->{'setter'});
3916: $title = &unescape($record->{'event'});
3917: $blocks = $record->{'blocks'};
3918: } else {
3919: my @data = split(/:/,$record,3);
3920: if (scalar(@data) eq 2) {
3921: $title = $data[1];
3922: ($setuname,$setudom) = split(/@/,$data[0]);
3923: } else {
3924: ($setuname,$setudom,$title) = @data;
3925: }
3926: $blocks = { 'com' => 'on' };
3927: }
3928: return ($setuname,$setudom,$title,$blocks);
3929: }
3930:
1.854 kalberla 3931: sub blocking_status {
1.867 kalberla 3932: my $blocked;
1.854 kalberla 3933: my ($activity,$uname,$udom) = @_;
1.867 kalberla 3934: my %setters;
3935: my ($startblock,$endblock)=&blockcheck(\%setters,$activity,$uname,$udom);
3936: if ($startblock && $endblock) {
3937: $blocked = 1;
3938: }
1.854 kalberla 3939: if(!wantarray) {
3940: return $blocked;
3941: }
3942: my $output;
3943: my $querystring;
3944: $querystring = "?activity=$activity";
3945:
3946: $output .= <<"END_MYBLOCK";
3947: <script type="text/javascript">
3948: // <![CDATA[
3949: function openWindow(url, wdwName, w, h, toolbar,scrollbar) {
3950: var options = "width=" + w + ",height=" + h + ",";
3951: options += "resizable=yes,scrollbars="+scrollbar+",status=no,";
3952: options += "menubar=no,toolbar="+toolbar+",location=no,directories=no";
3953: var newWin = window.open(url, wdwName, options);
3954: newWin.focus();
3955: }
3956:
3957: // ]]>
3958: </script>
3959: END_MYBLOCK
3960: my $popupUrl = "/adm/blockingstatus/$querystring";
1.867 kalberla 3961: $output .= <<"END_BLOCK";
3962: <div class='LC_comblock'>
1.869 kalberla 3963: <a onclick='openWindow("$popupUrl","Blocking Table",600,300,"no","no");return false;' href='/adm/blockingstatus/$querystring'
3964: title='Communication Blocked'>
3965: <img class='LC_noBorder LC_middle' title='Communication Blocked' src='/res/adm/pages/comblock.png' alt='Communication Blocked'/></a>
3966: <a onclick='openWindow("$popupUrl","Blocking Table",600,300,"no","no");return false;' href='/adm/blockingstatus/$querystring'
3967: title='Communication Blocked'>Communication Blocked</a>
1.867 kalberla 3968: </div>
3969:
3970: END_BLOCK
1.474 raeburn 3971:
1.854 kalberla 3972: return ($blocked, $output);
3973: }
1.490 raeburn 3974:
1.60 matthew 3975: ###############################################
3976:
1.682 raeburn 3977: sub check_ip_acc {
3978: my ($acc)=@_;
3979: &Apache::lonxml::debug("acc is $acc");
3980: if (!defined($acc) || $acc =~ /^\s*$/ || $acc =~/^\s*no\s*$/i) {
3981: return 1;
3982: }
3983: my $allowed=0;
3984: my $ip=$env{'request.host'} || $ENV{'REMOTE_ADDR'};
3985:
3986: my $name;
3987: foreach my $pattern (split(',',$acc)) {
3988: $pattern =~ s/^\s*//;
3989: $pattern =~ s/\s*$//;
3990: if ($pattern =~ /\*$/) {
3991: #35.8.*
3992: $pattern=~s/\*//;
3993: if ($ip =~ /^\Q$pattern\E/) { $allowed=1; }
3994: } elsif ($pattern =~ /(\d+\.\d+\.\d+)\.\[(\d+)-(\d+)\]$/) {
3995: #35.8.3.[34-56]
3996: my $low=$2;
3997: my $high=$3;
3998: $pattern=$1;
3999: if ($ip =~ /^\Q$pattern\E/) {
4000: my $last=(split(/\./,$ip))[3];
4001: if ($last <=$high && $last >=$low) { $allowed=1; }
4002: }
4003: } elsif ($pattern =~ /^\*/) {
4004: #*.msu.edu
4005: $pattern=~s/\*//;
4006: if (!defined($name)) {
4007: use Socket;
4008: my $netaddr=inet_aton($ip);
4009: ($name)=gethostbyaddr($netaddr,AF_INET);
4010: }
4011: if ($name =~ /\Q$pattern\E$/i) { $allowed=1; }
4012: } elsif ($pattern =~ /\d+\.\d+\.\d+\.\d+/) {
4013: #127.0.0.1
4014: if ($ip =~ /^\Q$pattern\E/) { $allowed=1; }
4015: } else {
4016: #some.name.com
4017: if (!defined($name)) {
4018: use Socket;
4019: my $netaddr=inet_aton($ip);
4020: ($name)=gethostbyaddr($netaddr,AF_INET);
4021: }
4022: if ($name =~ /\Q$pattern\E$/i) { $allowed=1; }
4023: }
4024: if ($allowed) { last; }
4025: }
4026: return $allowed;
4027: }
4028:
4029: ###############################################
4030:
1.60 matthew 4031: =pod
4032:
1.112 bowersj2 4033: =head1 Domain Template Functions
4034:
4035: =over 4
4036:
4037: =item * &determinedomain()
1.60 matthew 4038:
4039: Inputs: $domain (usually will be undef)
4040:
1.63 www 4041: Returns: Determines which domain should be used for designs
1.60 matthew 4042:
4043: =cut
1.54 www 4044:
1.60 matthew 4045: ###############################################
1.63 www 4046: sub determinedomain {
4047: my $domain=shift;
1.531 albertel 4048: if (! $domain) {
1.60 matthew 4049: # Determine domain if we have not been given one
4050: $domain = $Apache::lonnet::perlvar{'lonDefDomain'};
1.258 albertel 4051: if ($env{'user.domain'}) { $domain=$env{'user.domain'}; }
4052: if ($env{'request.role.domain'}) {
4053: $domain=$env{'request.role.domain'};
1.60 matthew 4054: }
4055: }
1.63 www 4056: return $domain;
4057: }
4058: ###############################################
1.517 raeburn 4059:
1.518 albertel 4060: sub devalidate_domconfig_cache {
4061: my ($udom)=@_;
4062: &Apache::lonnet::devalidate_cache_new('domainconfig',$udom);
4063: }
4064:
4065: # ---------------------- Get domain configuration for a domain
4066: sub get_domainconf {
4067: my ($udom) = @_;
4068: my $cachetime=1800;
4069: my ($result,$cached)=&Apache::lonnet::is_cached_new('domainconfig',$udom);
4070: if (defined($cached)) { return %{$result}; }
4071:
4072: my %domconfig = &Apache::lonnet::get_dom('configuration',
4073: ['login','rolecolors'],$udom);
1.632 raeburn 4074: my (%designhash,%legacy);
1.518 albertel 4075: if (keys(%domconfig) > 0) {
4076: if (ref($domconfig{'login'}) eq 'HASH') {
1.632 raeburn 4077: if (keys(%{$domconfig{'login'}})) {
4078: foreach my $key (keys(%{$domconfig{'login'}})) {
1.699 raeburn 4079: if (ref($domconfig{'login'}{$key}) eq 'HASH') {
4080: foreach my $img (keys(%{$domconfig{'login'}{$key}})) {
4081: $designhash{$udom.'.login.'.$key.'_'.$img} =
4082: $domconfig{'login'}{$key}{$img};
4083: }
4084: } else {
4085: $designhash{$udom.'.login.'.$key}=$domconfig{'login'}{$key};
4086: }
1.632 raeburn 4087: }
4088: } else {
4089: $legacy{'login'} = 1;
1.518 albertel 4090: }
1.632 raeburn 4091: } else {
4092: $legacy{'login'} = 1;
1.518 albertel 4093: }
4094: if (ref($domconfig{'rolecolors'}) eq 'HASH') {
1.632 raeburn 4095: if (keys(%{$domconfig{'rolecolors'}})) {
4096: foreach my $role (keys(%{$domconfig{'rolecolors'}})) {
4097: if (ref($domconfig{'rolecolors'}{$role}) eq 'HASH') {
4098: foreach my $item (keys(%{$domconfig{'rolecolors'}{$role}})) {
4099: $designhash{$udom.'.'.$role.'.'.$item}=$domconfig{'rolecolors'}{$role}{$item};
4100: }
1.518 albertel 4101: }
4102: }
1.632 raeburn 4103: } else {
4104: $legacy{'rolecolors'} = 1;
1.518 albertel 4105: }
1.632 raeburn 4106: } else {
4107: $legacy{'rolecolors'} = 1;
1.518 albertel 4108: }
1.632 raeburn 4109: if (keys(%legacy) > 0) {
4110: my %legacyhash = &get_legacy_domconf($udom);
4111: foreach my $item (keys(%legacyhash)) {
4112: if ($item =~ /^\Q$udom\E\.login/) {
4113: if ($legacy{'login'}) {
4114: $designhash{$item} = $legacyhash{$item};
4115: }
4116: } else {
4117: if ($legacy{'rolecolors'}) {
4118: $designhash{$item} = $legacyhash{$item};
4119: }
1.518 albertel 4120: }
4121: }
4122: }
1.632 raeburn 4123: } else {
4124: %designhash = &get_legacy_domconf($udom);
1.518 albertel 4125: }
4126: &Apache::lonnet::do_cache_new('domainconfig',$udom,\%designhash,
4127: $cachetime);
4128: return %designhash;
4129: }
4130:
1.632 raeburn 4131: sub get_legacy_domconf {
4132: my ($udom) = @_;
4133: my %legacyhash;
4134: my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors';
4135: my $designfile = $designdir.'/'.$udom.'.tab';
4136: if (-e $designfile) {
4137: if ( open (my $fh,"<$designfile") ) {
4138: while (my $line = <$fh>) {
4139: next if ($line =~ /^\#/);
4140: chomp($line);
4141: my ($key,$val)=(split(/\=/,$line));
4142: if ($val) { $legacyhash{$udom.'.'.$key}=$val; }
4143: }
4144: close($fh);
4145: }
4146: }
4147: if (-e '/home/httpd/html/adm/lonDomLogos/'.$udom.'.gif') {
4148: $legacyhash{$udom.'.login.domlogo'} = "/adm/lonDomLogos/$udom.gif";
4149: }
4150: return %legacyhash;
4151: }
4152:
1.63 www 4153: =pod
4154:
1.112 bowersj2 4155: =item * &domainlogo()
1.63 www 4156:
4157: Inputs: $domain (usually will be undef)
4158:
4159: Returns: A link to a domain logo, if the domain logo exists.
4160: If the domain logo does not exist, a description of the domain.
4161:
4162: =cut
1.112 bowersj2 4163:
1.63 www 4164: ###############################################
4165: sub domainlogo {
1.517 raeburn 4166: my $domain = &determinedomain(shift);
1.518 albertel 4167: my %designhash = &get_domainconf($domain);
1.517 raeburn 4168: # See if there is a logo
4169: if ($designhash{$domain.'.login.domlogo'} ne '') {
1.519 raeburn 4170: my $imgsrc = $designhash{$domain.'.login.domlogo'};
1.538 albertel 4171: if ($imgsrc =~ m{^/(adm|res)/}) {
4172: if ($imgsrc =~ m{^/res/}) {
4173: my $local_name = &Apache::lonnet::filelocation('',$imgsrc);
4174: &Apache::lonnet::repcopy($local_name);
4175: }
4176: $imgsrc = &lonhttpdurl($imgsrc);
1.519 raeburn 4177: }
4178: return '<img src="'.$imgsrc.'" alt="'.$domain.'" />';
1.514 albertel 4179: } elsif (defined(&Apache::lonnet::domain($domain,'description'))) {
4180: return &Apache::lonnet::domain($domain,'description');
1.59 www 4181: } else {
1.60 matthew 4182: return '';
1.59 www 4183: }
4184: }
1.63 www 4185: ##############################################
4186:
4187: =pod
4188:
1.112 bowersj2 4189: =item * &designparm()
1.63 www 4190:
4191: Inputs: $which parameter; $domain (usually will be undef)
4192:
4193: Returns: value of designparamter $which
4194:
4195: =cut
1.112 bowersj2 4196:
1.397 albertel 4197:
1.400 albertel 4198: ##############################################
1.397 albertel 4199: sub designparm {
4200: my ($which,$domain)=@_;
4201: if (exists($env{'environment.color.'.$which})) {
1.817 bisitz 4202: return $env{'environment.color.'.$which};
1.96 www 4203: }
1.63 www 4204: $domain=&determinedomain($domain);
1.518 albertel 4205: my %domdesign = &get_domainconf($domain);
1.520 raeburn 4206: my $output;
1.517 raeburn 4207: if ($domdesign{$domain.'.'.$which} ne '') {
1.817 bisitz 4208: $output = $domdesign{$domain.'.'.$which};
1.63 www 4209: } else {
1.520 raeburn 4210: $output = $defaultdesign{$which};
4211: }
4212: if (($which =~ /^(student|coordinator|author|admin)\.img$/) ||
1.635 raeburn 4213: ($which =~ /login\.(img|logo|domlogo|login)/)) {
1.538 albertel 4214: if ($output =~ m{^/(adm|res)/}) {
1.817 bisitz 4215: if ($output =~ m{^/res/}) {
4216: my $local_name = &Apache::lonnet::filelocation('',$output);
4217: &Apache::lonnet::repcopy($local_name);
4218: }
1.520 raeburn 4219: $output = &lonhttpdurl($output);
4220: }
1.63 www 4221: }
1.520 raeburn 4222: return $output;
1.63 www 4223: }
1.59 www 4224:
1.822 bisitz 4225: ##############################################
4226: =pod
4227:
1.832 bisitz 4228: =item * &authorspace()
4229:
4230: Inputs: ./.
4231:
4232: Returns: Path to the Construction Space of the current user's
4233: accessed author space
4234: The author space will be that of the current user
4235: when accessing the own author space
4236: and that of the co-author/assistent co-author
4237: when accessing the co-author's/assistent co-author's
4238: space
4239:
4240: =cut
4241:
4242: sub authorspace {
4243: my $caname = '';
4244: if ($env{'request.role'} =~ /^ca|^aa/) {
4245: (undef,$caname) =
4246: ($env{'request.role'}=~/($match_domain)\/($match_username)$/);
4247: } else {
4248: $caname = $env{'user.name'};
4249: }
4250: return '/priv/'.$caname.'/';
4251: }
4252:
4253: ##############################################
4254: =pod
4255:
1.822 bisitz 4256: =item * &head_subbox()
4257:
4258: Inputs: $content (contains HTML code with page functions, etc.)
4259:
4260: Returns: HTML div with $content
4261: To be included in page header
4262:
4263: =cut
4264:
4265: sub head_subbox {
4266: my ($content)=@_;
4267: my $output =
1.844 bisitz 4268: '<div id="LC_head_subbox">'
1.822 bisitz 4269: .$content
4270: .'</div>'
4271: }
4272:
4273: ##############################################
4274: =pod
4275:
4276: =item * &CSTR_pageheader()
4277:
4278: Inputs: ./.
4279:
4280: Returns: HTML div with CSTR path and recent box
4281: To be included on Construction Space pages
4282:
4283: =cut
4284:
4285: sub CSTR_pageheader {
4286: # this is for resources; directories have customtitle, and crumbs
4287: # and select recent are created in lonpubdir.pm
4288: my ($uname,$thisdisfn)=
4289: ($env{'request.filename'} =~ m|^/home/([^/]+)/public_html/(.*)|);
4290: my $formaction='/priv/'.$uname.'/'.$thisdisfn;
4291: $formaction=~s/\/+/\//g;
4292:
4293: my $parentpath = '';
4294: my $lastitem = '';
4295: if ($thisdisfn =~ m-(.+/)([^/]*)$-) {
4296: $parentpath = $1;
4297: $lastitem = $2;
4298: } else {
4299: $lastitem = $thisdisfn;
4300: }
4301: return
4302: '<div>'
4303: .&Apache::loncommon::help_open_menu('','',3,'Authoring') #FIXME: Broken? Where is it?
4304: .'<b>'.&mt('Construction Space:').'</b> '
4305: .'<form name="dirs" method="post" action="'.$formaction
4306: .'" target="_top"><tt><b>' #FIXME lonpubdir: target="_parent"
4307: .&Apache::lonhtmlcommon::crumbs($uname.'/'.$parentpath,'_top','/priv','','+1',1)."$lastitem</b></tt><br />"
4308: #FIXME lonpubdir: &Apache::lonhtmlcommon::crumbs($uname.$thisdisfn.'/','_top','/priv','','+1',1)."</b></tt><br />"
4309: .&Apache::lonhtmlcommon::select_recent('construct','recent','this.form.action=this.form.recent.value;this.form.submit()')
4310: .'</form>'
4311: .&Apache::lonmenu::constspaceform()
4312: .'</div>';
4313: }
4314:
1.60 matthew 4315: ###############################################
4316: ###############################################
4317:
4318: =pod
4319:
1.112 bowersj2 4320: =back
4321:
1.549 albertel 4322: =head1 HTML Helpers
1.112 bowersj2 4323:
4324: =over 4
4325:
4326: =item * &bodytag()
1.60 matthew 4327:
4328: Returns a uniform header for LON-CAPA web pages.
4329:
4330: Inputs:
4331:
1.112 bowersj2 4332: =over 4
4333:
4334: =item * $title, A title to be displayed on the page.
4335:
4336: =item * $function, the current role (can be undef).
4337:
4338: =item * $addentries, extra parameters for the <body> tag.
4339:
4340: =item * $bodyonly, if defined, only return the <body> tag.
4341:
4342: =item * $domain, if defined, force a given domain.
4343:
4344: =item * $forcereg, if page should register as content page (relevant for
1.86 www 4345: text interface only)
1.60 matthew 4346:
1.814 bisitz 4347: =item * $no_nav_bar, if true, keep the 'what is this' info but remove the
4348: navigational links
1.317 albertel 4349:
1.338 albertel 4350: =item * $bgcolor, used to override the bgcolor on a webpage to a specific value
4351:
1.361 albertel 4352: =item * $no_inline_link, if true and in remote mode, don't show the
4353: 'Switch To Inline Menu' link
4354:
1.460 albertel 4355: =item * $args, optional argument valid values are
4356: no_auto_mt_title -> prevents &mt()ing the title arg
1.562 albertel 4357: inherit_jsmath -> when creating popup window in a page,
4358: should it have jsmath forced on by the
4359: current page
1.460 albertel 4360:
1.112 bowersj2 4361: =back
4362:
1.60 matthew 4363: Returns: A uniform header for LON-CAPA web pages.
4364: If $bodyonly is nonzero, a string containing a <body> tag will be returned.
4365: If $bodyonly is undef or zero, an html string containing a <body> tag and
4366: other decorations will be returned.
4367:
4368: =cut
4369:
1.54 www 4370: sub bodytag {
1.831 bisitz 4371: my ($title,$function,$addentries,$bodyonly,$domain,$forcereg,
1.816 bisitz 4372: $no_nav_bar,$bgcolor,$no_inline_link,$args)=@_;
1.339 albertel 4373:
1.460 albertel 4374: if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); }
1.339 albertel 4375:
1.183 matthew 4376: $function = &get_users_function() if (!$function);
1.339 albertel 4377: my $img = &designparm($function.'.img',$domain);
4378: my $font = &designparm($function.'.font',$domain);
4379: my $pgbg = $bgcolor || &designparm($function.'.pgbg',$domain);
4380:
1.803 bisitz 4381: my %design = ( 'style' => 'margin-top: 0',
1.535 albertel 4382: 'bgcolor' => $pgbg,
1.339 albertel 4383: 'text' => $font,
4384: 'alink' => &designparm($function.'.alink',$domain),
4385: 'vlink' => &designparm($function.'.vlink',$domain),
4386: 'link' => &designparm($function.'.link',$domain),);
1.438 albertel 4387: @design{keys(%$addentries)} = @$addentries{keys(%$addentries)};
1.339 albertel 4388:
1.63 www 4389: # role and realm
1.378 raeburn 4390: my ($role,$realm) = split(/\./,$env{'request.role'},2);
4391: if ($role eq 'ca') {
1.479 albertel 4392: my ($rdom,$rname) = ($realm =~ m{^/($match_domain)/($match_username)$});
1.500 albertel 4393: $realm = &plainname($rname,$rdom);
1.378 raeburn 4394: }
1.55 www 4395: # realm
1.258 albertel 4396: if ($env{'request.course.id'}) {
1.378 raeburn 4397: if ($env{'request.role'} !~ /^cr/) {
4398: $role = &Apache::lonnet::plaintext($role,&course_type());
4399: }
1.359 albertel 4400: $realm = $env{'course.'.$env{'request.course.id'}.'.description'};
1.378 raeburn 4401: } else {
4402: $role = &Apache::lonnet::plaintext($role);
1.54 www 4403: }
1.433 albertel 4404:
1.359 albertel 4405: if (!$realm) { $realm=' '; }
1.55 www 4406: # Set messages
1.60 matthew 4407: my $messages=&domainlogo($domain);
1.330 albertel 4408:
1.438 albertel 4409: my $extra_body_attr = &make_attr_string($forcereg,\%design);
1.329 albertel 4410:
1.101 www 4411: # construct main body tag
1.359 albertel 4412: my $bodytag = "<body $extra_body_attr>".
1.562 albertel 4413: &Apache::lontexconvert::init_math_support($args->{'inherit_jsmath'});
1.252 albertel 4414:
1.530 albertel 4415: if ($bodyonly) {
1.60 matthew 4416: return $bodytag;
1.798 tempelho 4417: }
1.359 albertel 4418:
1.410 albertel 4419: my $name = &plainname($env{'user.name'},$env{'user.domain'});
1.433 albertel 4420: if ($env{'user.name'} eq 'public' && $env{'user.domain'} eq 'public') {
4421: undef($role);
1.434 albertel 4422: } else {
4423: $name = &aboutmewrapper($name,$env{'user.name'},$env{'user.domain'});
1.433 albertel 4424: }
1.359 albertel 4425:
1.762 bisitz 4426: my $titleinfo = '<h1>'.$title.'</h1>';
1.359 albertel 4427: #
4428: # Extra info if you are the DC
4429: my $dc_info = '';
4430: if ($env{'user.adv'} && exists($env{'user.role.dc./'.
4431: $env{'course.'.$env{'request.course.id'}.
4432: '.domain'}.'/'})) {
4433: my $cid = $env{'request.course.id'};
4434: $dc_info.= $cid.' '.$env{'course.'.$cid.'.internal.coursecode'};
1.380 www 4435: $dc_info =~ s/\s+$//;
1.359 albertel 4436: $dc_info = '('.$dc_info.')';
4437: }
4438:
1.853 droeschl 4439: $role = "($role)" if $role;
4440: &get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['inhibitmenu']);
4441:
1.837 bisitz 4442: if ($env{'environment.remote'} eq 'off') {
1.359 albertel 4443: # No Remote
1.258 albertel 4444: if ($env{'request.state'} eq 'construct') {
1.359 albertel 4445: $forcereg=1;
4446: }
4447:
1.836 bisitz 4448: # if ($env{'request.state'} eq 'construct') {
4449: # $titleinfo = &CSTR_pageheader(); #FIXME: Will be removed once all scripts have their own calls
4450: # }
1.359 albertel 4451:
1.816 bisitz 4452: my $titletable = '<table id="LC_title_bar">'
1.836 bisitz 4453: ."<tr><td> $titleinfo $dc_info</td>"
1.816 bisitz 4454: .'</tr></table>';
4455:
1.814 bisitz 4456: if ($no_nav_bar) {
1.359 albertel 4457: $bodytag .= $titletable;
4458: } else {
1.852 droeschl 4459: $bodytag .= qq|<div id="LC_nav_bar">$name $role<br />
4460: <em>$realm</em> $dc_info</div>| unless $env{'form.inhibitmenu'};
4461:
1.359 albertel 4462: if ($env{'request.state'} eq 'construct') {
1.863 droeschl 4463: $bodytag .= &Apache::lonmenu::menubuttons($forcereg,$titletable);
1.272 raeburn 4464: } else {
1.863 droeschl 4465: $bodytag .= &Apache::lonmenu::menubuttons($forcereg).$titletable;
1.272 raeburn 4466: }
1.235 raeburn 4467: }
4468: return $bodytag;
1.94 www 4469: }
1.95 www 4470:
1.93 www 4471: #
1.95 www 4472: # Top frame rendering, Remote is up
1.93 www 4473: #
1.359 albertel 4474:
1.517 raeburn 4475: my $imgsrc = $img;
4476: if ($img =~ /^\/adm/) {
1.575 albertel 4477: $imgsrc = &lonhttpdurl($img);
1.517 raeburn 4478: }
4479: my $upperleft='<img src="'.$imgsrc.'" alt="'.$function.'" />';
1.359 albertel 4480:
1.305 www 4481: # Explicit link to get inline menu
1.361 albertel 4482: my $menu= ($no_inline_link?''
1.883 droeschl 4483: :'<a href="/adm/remote?action=collapse" target="_top">'.&mt('Switch to Inline Menu Mode').'</a>');
1.853 droeschl 4484: $bodytag .= qq|<div id="LC_nav_bar">$name $role
4485: <em>$realm</em> $dc_info </div>
4486: <ol class="LC_smallMenu LC_right">
4487: <li>$menu</li>
4488: </ol>| unless $env{'form.inhibitmenu'};
1.245 matthew 4489: #
1.94 www 4490: return(<<ENDBODY);
1.60 matthew 4491: $bodytag
1.359 albertel 4492: <table id="LC_title_bar" class="LC_with_remote">
1.791 tempelho 4493: <tr><td>$upperleft</td>
4494: <td>$messages </td>
1.54 www 4495: </tr>
1.359 albertel 4496: <tr><td>$titleinfo $dc_info $menu</td>
1.368 albertel 4497: </tr>
1.356 albertel 4498: </table>
1.54 www 4499: ENDBODY
1.182 matthew 4500: }
4501:
1.330 albertel 4502: sub make_attr_string {
4503: my ($register,$attr_ref) = @_;
4504:
4505: if ($attr_ref && !ref($attr_ref)) {
4506: die("addentries Must be a hash ref ".
4507: join(':',caller(1))." ".
4508: join(':',caller(0))." ");
4509: }
4510:
4511: if ($register) {
1.339 albertel 4512: my ($on_load,$on_unload);
4513: foreach my $key (keys(%{$attr_ref})) {
4514: if (lc($key) eq 'onload') {
4515: $on_load.=$attr_ref->{$key}.';';
4516: delete($attr_ref->{$key});
4517:
4518: } elsif (lc($key) eq 'onunload') {
4519: $on_unload.=$attr_ref->{$key}.';';
4520: delete($attr_ref->{$key});
4521: }
4522: }
4523: $attr_ref->{'onload'} =
4524: &Apache::lonmenu::loadevents(). $on_load;
4525: $attr_ref->{'onunload'}=
4526: &Apache::lonmenu::unloadevents().$on_unload;
4527: }
4528:
4529: # Accessibility font enhance
4530: if ($env{'browser.fontenhance'} eq 'on') {
4531: my $style;
4532: foreach my $key (keys(%{$attr_ref})) {
4533: if (lc($key) eq 'style') {
4534: $style.=$attr_ref->{$key}.';';
4535: delete($attr_ref->{$key});
4536: }
4537: }
4538: $attr_ref->{'style'}=$style.'; font-size: x-large;';
1.330 albertel 4539: }
1.339 albertel 4540:
1.330 albertel 4541: my $attr_string;
4542: foreach my $attr (keys(%$attr_ref)) {
4543: $attr_string .= " $attr=\"".$attr_ref->{$attr}.'" ';
4544: }
4545: return $attr_string;
4546: }
4547:
4548:
1.182 matthew 4549: ###############################################
1.251 albertel 4550: ###############################################
4551:
4552: =pod
4553:
4554: =item * &endbodytag()
4555:
4556: Returns a uniform footer for LON-CAPA web pages.
4557:
1.635 raeburn 4558: Inputs: 1 - optional reference to an args hash
4559: If in the hash, key for noredirectlink has a value which evaluates to true,
4560: a 'Continue' link is not displayed if the page contains an
4561: internal redirect in the <head></head> section,
4562: i.e., $env{'internal.head.redirect'} exists
1.251 albertel 4563:
4564: =cut
4565:
4566: sub endbodytag {
1.635 raeburn 4567: my ($args) = @_;
1.251 albertel 4568: my $endbodytag='</body>';
1.269 albertel 4569: $endbodytag=&Apache::lontexconvert::jsMath_process()."\n".$endbodytag;
1.315 albertel 4570: if ( exists( $env{'internal.head.redirect'} ) ) {
1.635 raeburn 4571: if (!(ref($args) eq 'HASH' && $args->{'noredirectlink'})) {
4572: $endbodytag=
4573: "<br /><a href=\"$env{'internal.head.redirect'}\">".
4574: &mt('Continue').'</a>'.
4575: $endbodytag;
4576: }
1.315 albertel 4577: }
1.251 albertel 4578: return $endbodytag;
4579: }
4580:
1.352 albertel 4581: =pod
4582:
4583: =item * &standard_css()
4584:
4585: Returns a style sheet
4586:
4587: Inputs: (all optional)
4588: domain -> force to color decorate a page for a specific
4589: domain
4590: function -> force usage of a specific rolish color scheme
4591: bgcolor -> override the default page bgcolor
4592:
4593: =cut
4594:
1.343 albertel 4595: sub standard_css {
1.345 albertel 4596: my ($function,$domain,$bgcolor) = @_;
1.352 albertel 4597: $function = &get_users_function() if (!$function);
4598: my $img = &designparm($function.'.img', $domain);
4599: my $tabbg = &designparm($function.'.tabbg', $domain);
4600: my $font = &designparm($function.'.font', $domain);
1.801 tempelho 4601: my $fontmenu = &designparm($function.'.fontmenu', $domain);
1.791 tempelho 4602: #second colour for later usage
1.345 albertel 4603: my $sidebg = &designparm($function.'.sidebg',$domain);
1.382 albertel 4604: my $pgbg_or_bgcolor =
4605: $bgcolor ||
1.352 albertel 4606: &designparm($function.'.pgbg', $domain);
1.382 albertel 4607: my $pgbg = &designparm($function.'.pgbg', $domain);
1.352 albertel 4608: my $alink = &designparm($function.'.alink', $domain);
4609: my $vlink = &designparm($function.'.vlink', $domain);
4610: my $link = &designparm($function.'.link', $domain);
4611:
1.704 muellerd 4612: my $loginbg = &designparm('login.sidebg',$domain);
1.712 muellerd 4613: my $bgcol = &designparm('login.bgcol',$domain);
4614: my $textcol = &designparm('login.textcol',$domain);
1.704 muellerd 4615:
1.602 albertel 4616: my $sans = 'Verdana,Arial,Helvetica,sans-serif';
1.395 albertel 4617: my $mono = 'monospace';
1.850 bisitz 4618: my $data_table_head = $sidebg;
4619: my $data_table_light = '#FAFAFA';
4620: my $data_table_dark = '#F0F0F0';
1.470 banghart 4621: my $data_table_darker = '#CCCCCC';
1.349 albertel 4622: my $data_table_highlight = '#FFFF00';
1.352 albertel 4623: my $mail_new = '#FFBB77';
4624: my $mail_new_hover = '#DD9955';
4625: my $mail_read = '#BBBB77';
4626: my $mail_read_hover = '#999944';
4627: my $mail_replied = '#AAAA88';
4628: my $mail_replied_hover = '#888855';
4629: my $mail_other = '#99BBBB';
4630: my $mail_other_hover = '#669999';
1.391 albertel 4631: my $table_header = '#DDDDDD';
1.489 raeburn 4632: my $feedback_link_bg = '#BBBBBB';
1.701 harmsja 4633: my $lg_border_color = '#C8C8C8';
1.392 albertel 4634:
1.608 albertel 4635: my $border = ($env{'browser.type'} eq 'explorer' ||
1.803 bisitz 4636: $env{'browser.type'} eq 'safari' ) ? '0 2px 0 2px'
4637: : '0 3px 0 4px';
1.448 albertel 4638:
1.523 albertel 4639:
1.343 albertel 4640: return <<END;
1.795 www 4641: body {
4642: font-family: $sans;
4643: line-height:130%;
4644: font-size:0.83em;
4645: color:$font;
4646: }
4647:
4648: a:link, a:visited {
4649: font-size:100%;
4650: }
4651:
4652: a:focus {
4653: color: red;
4654: background: yellow
4655: }
1.698 harmsja 4656:
1.846 bisitz 4657: hr {
4658: clear: both;
4659: color: $tabbg;
4660: background-color: $tabbg;
4661: height: 3px;
4662: border: none;
4663: }
4664:
1.795 www 4665: form, .inline {
4666: display: inline;
4667: }
1.721 harmsja 4668:
1.795 www 4669: .LC_right {
4670: text-align:right;
4671: }
4672:
4673: .LC_middle {
4674: vertical-align:middle;
4675: }
1.721 harmsja 4676:
4677: /* just for tests */
1.754 droeschl 4678: .LC_400Box {width:400px; }
1.721 harmsja 4679: /* end */
4680:
1.778 bisitz 4681: .LC_filename {
4682: font-family: $mono;
4683: white-space:pre;
4684: }
4685:
4686: .LC_fileicon {
4687: border: none;
4688: height: 1.3em;
4689: vertical-align: text-bottom;
4690: margin-right: 0.3em;
4691: text-decoration:none;
4692: }
4693:
1.350 albertel 4694: .LC_error {
4695: color: red;
4696: font-size: larger;
4697: }
1.795 www 4698:
1.457 albertel 4699: .LC_warning,
4700: .LC_diff_removed {
1.733 bisitz 4701: color: red;
1.394 albertel 4702: }
1.532 albertel 4703:
4704: .LC_info,
1.457 albertel 4705: .LC_success,
4706: .LC_diff_added {
1.350 albertel 4707: color: green;
4708: }
1.795 www 4709:
1.802 bisitz 4710: div.LC_confirm_box {
4711: background-color: #FAFAFA;
4712: border: 1px solid $lg_border_color;
4713: margin-right: 0;
4714: padding: 5px;
4715: }
4716:
4717: div.LC_confirm_box .LC_error img,
4718: div.LC_confirm_box .LC_success img {
4719: vertical-align: middle;
4720: }
4721:
1.440 albertel 4722: .LC_icon {
1.771 droeschl 4723: border: none;
1.790 droeschl 4724: vertical-align: middle;
1.771 droeschl 4725: }
4726:
1.543 albertel 4727: .LC_docs_spacer {
4728: width: 25px;
4729: height: 1px;
1.771 droeschl 4730: border: none;
1.543 albertel 4731: }
1.346 albertel 4732:
1.532 albertel 4733: .LC_internal_info {
1.735 bisitz 4734: color: #999999;
1.532 albertel 4735: }
4736:
1.794 www 4737: .LC_discussion {
4738: background: $tabbg;
4739: border: 1px solid black;
4740: margin: 2px;
4741: }
4742:
4743: .LC_disc_action_links_bar {
4744: background: $tabbg;
1.803 bisitz 4745: border: none;
1.795 www 4746: margin: 4px;
1.794 www 4747: }
4748:
4749: .LC_disc_action_left {
4750: text-align: left;
4751: }
4752:
4753: .LC_disc_action_right {
4754: text-align: right;
4755: }
4756:
4757: .LC_disc_new_item {
4758: background: white;
4759: border: 2px solid red;
4760: margin: 2px;
4761: }
4762:
4763: .LC_disc_old_item {
4764: background: white;
4765: border: 1px solid black;
4766: margin: 2px;
4767: }
4768:
1.458 albertel 4769: table.LC_pastsubmission {
4770: border: 1px solid black;
4771: margin: 2px;
4772: }
4773:
1.795 www 4774: table#LC_top_nav,
4775: table#LC_menubuttons,
4776: table#LC_nav_location {
1.345 albertel 4777: width: 100%;
4778: background: $pgbg;
1.392 albertel 4779: border: 2px;
1.402 albertel 4780: border-collapse: separate;
1.803 bisitz 4781: padding: 0;
1.345 albertel 4782: }
1.392 albertel 4783:
1.801 tempelho 4784: table#LC_title_bar a {
4785: color: $fontmenu;
4786: }
1.836 bisitz 4787:
1.807 droeschl 4788: table#LC_title_bar {
1.819 tempelho 4789: clear: both;
1.836 bisitz 4790: display: none;
1.807 droeschl 4791: }
4792:
1.795 www 4793: table#LC_title_bar,
4794: table.LC_breadcrumbs,
1.393 albertel 4795: table#LC_title_bar.LC_with_remote {
1.359 albertel 4796: width: 100%;
1.392 albertel 4797: border-color: $pgbg;
4798: border-style: solid;
4799: border-width: $border;
1.379 albertel 4800: background: $pgbg;
1.801 tempelho 4801: color: $fontmenu;
1.392 albertel 4802: border-collapse: collapse;
1.803 bisitz 4803: padding: 0;
1.819 tempelho 4804: margin: 0;
1.359 albertel 4805: }
1.795 www 4806:
1.359 albertel 4807: table#LC_title_bar td {
4808: background: $tabbg;
4809: }
1.795 www 4810:
1.706 harmsja 4811: table#LC_menubuttons img{
1.803 bisitz 4812: border: none;
1.346 albertel 4813: }
1.795 www 4814:
1.345 albertel 4815: table#LC_top_nav td {
4816: background: $tabbg;
1.803 bisitz 4817: border: none;
1.407 albertel 4818: font-size: small;
1.706 harmsja 4819: vertical-align:top;
4820: padding:2px 5px 2px 5px;
1.345 albertel 4821: }
1.795 www 4822:
4823: table#LC_top_nav td a,
4824: div#LC_top_nav a {
1.345 albertel 4825: color: $font;
4826: }
1.795 www 4827:
1.364 albertel 4828: table#LC_top_nav td.LC_top_nav_logo {
4829: background: $tabbg;
1.432 albertel 4830: text-align: left;
1.408 albertel 4831: white-space: nowrap;
1.432 albertel 4832: width: 31px;
1.408 albertel 4833: }
1.795 www 4834:
1.408 albertel 4835: table#LC_top_nav td.LC_top_nav_logo img {
1.803 bisitz 4836: border: none;
1.408 albertel 4837: vertical-align: bottom;
1.364 albertel 4838: }
1.795 www 4839:
1.777 tempelho 4840: table#LC_top_nav td.LC_top_nav_exit,
1.779 bisitz 4841: table#LC_top_nav td.LC_top_nav_help {
1.777 tempelho 4842: width: 2.0em;
4843: }
1.795 www 4844:
1.442 albertel 4845: table#LC_top_nav td.LC_top_nav_login {
4846: width: 4.0em;
4847: text-align: center;
4848: }
1.795 www 4849:
1.842 droeschl 4850: .LC_breadcrumbs_component {
4851: float: right;
4852: margin: 0 1em;
1.357 albertel 4853: }
1.842 droeschl 4854: .LC_breadcrumbs_component img {
4855: vertical-align: middle;
1.777 tempelho 4856: }
1.795 www 4857:
1.383 albertel 4858: td.LC_table_cell_checkbox {
4859: text-align: center;
4860: }
1.795 www 4861:
1.779 bisitz 4862: table#LC_mainmenu td.LC_mainmenu_column {
4863: vertical-align: top;
1.777 tempelho 4864: }
1.522 albertel 4865:
1.795 www 4866: .LC_fontsize_small {
1.705 tempelho 4867: font-size: 70%;
4868: }
4869:
1.844 bisitz 4870: #LC_breadcrumbs {
1.819 tempelho 4871: clear:both;
4872: background: $sidebg;
1.822 bisitz 4873: border-bottom: 1px solid $lg_border_color;
1.819 tempelho 4874: line-height: 32px;
1.822 bisitz 4875: margin: 0;
1.819 tempelho 4876: padding: 0;
4877: }
1.862 bisitz 4878:
1.839 droeschl 4879: /* Preliminary fix to hide breadcrumbs inside remote control window */
1.844 bisitz 4880: #LC_remote #LC_breadcrumbs {
1.839 droeschl 4881: display:none;
4882: }
1.819 tempelho 4883:
1.844 bisitz 4884: #LC_head_subbox {
1.822 bisitz 4885: clear:both;
4886: background: #F8F8F8; /* $sidebg; */
4887: border-bottom: 1px solid $lg_border_color;
4888: margin: 0 0 10px 0;
4889: padding: 5px;
4890: }
4891:
1.795 www 4892: .LC_fontsize_medium {
1.705 tempelho 4893: font-size: 85%;
4894: }
4895:
1.795 www 4896: .LC_fontsize_large {
1.705 tempelho 4897: font-size: 120%;
4898: }
4899:
1.346 albertel 4900: .LC_menubuttons_inline_text {
4901: color: $font;
1.698 harmsja 4902: font-size: 90%;
1.701 harmsja 4903: padding-left:3px;
1.346 albertel 4904: }
4905:
1.526 www 4906: .LC_menubuttons_link {
4907: text-decoration: none;
4908: }
1.795 www 4909:
1.522 albertel 4910: .LC_menubuttons_category {
1.521 www 4911: color: $font;
1.526 www 4912: background: $pgbg;
1.521 www 4913: font-size: larger;
4914: font-weight: bold;
4915: }
4916:
1.346 albertel 4917: td.LC_menubuttons_text {
1.779 bisitz 4918: color: $font;
1.346 albertel 4919: }
1.706 harmsja 4920:
1.346 albertel 4921: .LC_current_location {
4922: background: $tabbg;
4923: }
1.795 www 4924:
1.346 albertel 4925: .LC_new_mail {
1.634 www 4926: background: $tabbg;
1.346 albertel 4927: font-weight: bold;
4928: }
1.347 albertel 4929:
1.795 www 4930: table.LC_data_table,
4931: table.LC_mail_list {
1.347 albertel 4932: border: 1px solid #000000;
1.402 albertel 4933: border-collapse: separate;
1.426 albertel 4934: border-spacing: 1px;
1.610 albertel 4935: background: $pgbg;
1.347 albertel 4936: }
1.795 www 4937:
1.422 albertel 4938: .LC_data_table_dense {
4939: font-size: small;
4940: }
1.795 www 4941:
1.507 raeburn 4942: table.LC_nested_outer {
4943: border: 1px solid #000000;
1.589 raeburn 4944: border-collapse: collapse;
1.803 bisitz 4945: border-spacing: 0;
1.507 raeburn 4946: width: 100%;
4947: }
1.795 www 4948:
1.879 raeburn 4949: table.LC_innerpickbox,
1.507 raeburn 4950: table.LC_nested {
1.803 bisitz 4951: border: none;
1.589 raeburn 4952: border-collapse: collapse;
1.803 bisitz 4953: border-spacing: 0;
1.507 raeburn 4954: width: 100%;
4955: }
1.795 www 4956:
4957: table.LC_data_table tr th,
4958: table.LC_calendar tr th,
4959: table.LC_mail_list tr th,
1.879 raeburn 4960: table.LC_prior_tries tr th,
4961: table.LC_innerpickbox tr th {
1.349 albertel 4962: font-weight: bold;
4963: background-color: $data_table_head;
1.801 tempelho 4964: color:$fontmenu;
1.701 harmsja 4965: font-size:90%;
1.347 albertel 4966: }
1.795 www 4967:
1.879 raeburn 4968: table.LC_innerpickbox tr th,
4969: table.LC_innerpickbox tr td {
4970: vertical-align: top;
4971: }
4972:
1.711 raeburn 4973: table.LC_data_table tr.LC_info_row > td {
1.735 bisitz 4974: background-color: #CCCCCC;
1.711 raeburn 4975: font-weight: bold;
4976: text-align: left;
4977: }
1.795 www 4978:
1.779 bisitz 4979: table.LC_data_table tr.LC_odd_row > td,
1.809 bisitz 4980: table.LC_pick_box tr > td.LC_odd_row {
1.349 albertel 4981: background-color: $data_table_light;
1.425 albertel 4982: padding: 2px;
1.347 albertel 4983: }
1.795 www 4984:
1.610 albertel 4985: table.LC_data_table tr.LC_even_row > td,
1.809 bisitz 4986: table.LC_pick_box tr > td.LC_even_row {
1.349 albertel 4987: background-color: $data_table_dark;
1.709 bisitz 4988: padding: 2px;
1.347 albertel 4989: }
1.795 www 4990:
1.425 albertel 4991: table.LC_data_table tr.LC_data_table_highlight td {
4992: background-color: $data_table_darker;
4993: }
1.795 www 4994:
1.639 raeburn 4995: table.LC_data_table tr td.LC_leftcol_header {
4996: background-color: $data_table_head;
4997: font-weight: bold;
4998: }
1.795 www 4999:
1.451 albertel 5000: table.LC_data_table tr.LC_empty_row td,
1.507 raeburn 5001: table.LC_nested tr.LC_empty_row td {
1.347 albertel 5002: background-color: #FFFFFF;
1.421 albertel 5003: font-weight: bold;
5004: font-style: italic;
5005: text-align: center;
5006: padding: 8px;
1.347 albertel 5007: }
1.795 www 5008:
1.507 raeburn 5009: table.LC_nested tr.LC_empty_row td {
1.465 albertel 5010: padding: 4ex
5011: }
1.795 www 5012:
1.507 raeburn 5013: table.LC_nested_outer tr th {
5014: font-weight: bold;
1.801 tempelho 5015: color:$fontmenu;
1.507 raeburn 5016: background-color: $data_table_head;
1.701 harmsja 5017: font-size: small;
1.507 raeburn 5018: border-bottom: 1px solid #000000;
5019: }
1.795 www 5020:
1.507 raeburn 5021: table.LC_nested_outer tr td.LC_subheader {
5022: background-color: $data_table_head;
5023: font-weight: bold;
5024: font-size: small;
5025: border-bottom: 1px solid #000000;
5026: text-align: right;
1.451 albertel 5027: }
1.795 www 5028:
1.507 raeburn 5029: table.LC_nested tr.LC_info_row td {
1.735 bisitz 5030: background-color: #CCCCCC;
1.451 albertel 5031: font-weight: bold;
5032: font-size: small;
1.507 raeburn 5033: text-align: center;
5034: }
1.795 www 5035:
1.589 raeburn 5036: table.LC_nested tr.LC_info_row td.LC_left_item,
5037: table.LC_nested_outer tr th.LC_left_item {
1.507 raeburn 5038: text-align: left;
1.451 albertel 5039: }
1.795 www 5040:
1.507 raeburn 5041: table.LC_nested td {
1.735 bisitz 5042: background-color: #FFFFFF;
1.451 albertel 5043: font-size: small;
1.507 raeburn 5044: }
1.795 www 5045:
1.507 raeburn 5046: table.LC_nested_outer tr th.LC_right_item,
5047: table.LC_nested tr.LC_info_row td.LC_right_item,
5048: table.LC_nested tr.LC_odd_row td.LC_right_item,
5049: table.LC_nested tr td.LC_right_item {
1.451 albertel 5050: text-align: right;
5051: }
5052:
1.507 raeburn 5053: table.LC_nested tr.LC_odd_row td {
1.735 bisitz 5054: background-color: #EEEEEE;
1.451 albertel 5055: }
5056:
1.473 raeburn 5057: table.LC_createuser {
5058: }
5059:
5060: table.LC_createuser tr.LC_section_row td {
1.701 harmsja 5061: font-size: small;
1.473 raeburn 5062: }
5063:
5064: table.LC_createuser tr.LC_info_row td {
1.735 bisitz 5065: background-color: #CCCCCC;
1.473 raeburn 5066: font-weight: bold;
5067: text-align: center;
5068: }
5069:
1.349 albertel 5070: table.LC_calendar {
5071: border: 1px solid #000000;
5072: border-collapse: collapse;
5073: }
1.795 www 5074:
1.349 albertel 5075: table.LC_calendar_pickdate {
5076: font-size: xx-small;
5077: }
1.795 www 5078:
1.349 albertel 5079: table.LC_calendar tr td {
5080: border: 1px solid #000000;
5081: vertical-align: top;
5082: }
1.795 www 5083:
1.349 albertel 5084: table.LC_calendar tr td.LC_calendar_day_empty {
5085: background-color: $data_table_dark;
5086: }
1.795 www 5087:
1.779 bisitz 5088: table.LC_calendar tr td.LC_calendar_day_current {
5089: background-color: $data_table_highlight;
1.777 tempelho 5090: }
1.795 www 5091:
1.349 albertel 5092: table.LC_mail_list tr.LC_mail_new {
5093: background-color: $mail_new;
5094: }
1.795 www 5095:
1.349 albertel 5096: table.LC_mail_list tr.LC_mail_new:hover {
5097: background-color: $mail_new_hover;
5098: }
1.795 www 5099:
5100: table.LC_mail_list tr.LC_mail_even {
1.777 tempelho 5101: }
1.795 www 5102:
5103: table.LC_mail_list tr.LC_mail_odd {
1.777 tempelho 5104: }
1.795 www 5105:
1.349 albertel 5106: table.LC_mail_list tr.LC_mail_read {
5107: background-color: $mail_read;
5108: }
1.795 www 5109:
1.349 albertel 5110: table.LC_mail_list tr.LC_mail_read:hover {
5111: background-color: $mail_read_hover;
5112: }
1.795 www 5113:
1.349 albertel 5114: table.LC_mail_list tr.LC_mail_replied {
5115: background-color: $mail_replied;
5116: }
1.795 www 5117:
1.349 albertel 5118: table.LC_mail_list tr.LC_mail_replied:hover {
5119: background-color: $mail_replied_hover;
5120: }
1.795 www 5121:
1.349 albertel 5122: table.LC_mail_list tr.LC_mail_other {
5123: background-color: $mail_other;
5124: }
1.795 www 5125:
1.349 albertel 5126: table.LC_mail_list tr.LC_mail_other:hover {
5127: background-color: $mail_other_hover;
5128: }
1.494 raeburn 5129:
1.777 tempelho 5130: table.LC_data_table tr > td.LC_browser_file,
5131: table.LC_data_table tr > td.LC_browser_file_published {
1.389 albertel 5132: background: #CCFF88;
5133: }
1.795 www 5134:
1.777 tempelho 5135: table.LC_data_table tr > td.LC_browser_file_locked,
5136: table.LC_data_table tr > td.LC_browser_file_unpublished {
1.389 albertel 5137: background: #FFAA99;
1.387 albertel 5138: }
1.795 www 5139:
1.777 tempelho 5140: table.LC_data_table tr > td.LC_browser_file_obsolete {
1.779 bisitz 5141: background: #AAAAAA;
5142: }
1.795 www 5143:
1.777 tempelho 5144: table.LC_data_table tr > td.LC_browser_file_modified,
1.779 bisitz 5145: table.LC_data_table tr > td.LC_browser_file_metamodified {
5146: background: #FFFF77;
1.777 tempelho 5147: }
1.795 www 5148:
1.696 bisitz 5149: table.LC_data_table tr.LC_browser_folder > td {
1.389 albertel 5150: background: #CCCCFF;
1.387 albertel 5151: }
1.696 bisitz 5152:
1.707 bisitz 5153: table.LC_data_table tr > td.LC_roles_is {
5154: /* background: #77FF77; */
5155: }
1.795 www 5156:
1.707 bisitz 5157: table.LC_data_table tr > td.LC_roles_future {
5158: background: #FFFF77;
5159: }
1.795 www 5160:
1.707 bisitz 5161: table.LC_data_table tr > td.LC_roles_will {
5162: background: #FFAA77;
5163: }
1.795 www 5164:
1.707 bisitz 5165: table.LC_data_table tr > td.LC_roles_expired {
5166: background: #FF7777;
5167: }
1.795 www 5168:
1.707 bisitz 5169: table.LC_data_table tr > td.LC_roles_will_not {
5170: background: #AAFF77;
5171: }
1.795 www 5172:
1.707 bisitz 5173: table.LC_data_table tr > td.LC_roles_selected {
5174: background: #11CC55;
5175: }
5176:
1.388 albertel 5177: span.LC_current_location {
1.701 harmsja 5178: font-size:larger;
1.388 albertel 5179: background: $pgbg;
5180: }
1.387 albertel 5181:
1.395 albertel 5182: span.LC_parm_menu_item {
5183: font-size: larger;
5184: }
1.795 www 5185:
1.395 albertel 5186: span.LC_parm_scope_all {
5187: color: red;
5188: }
1.795 www 5189:
1.395 albertel 5190: span.LC_parm_scope_folder {
5191: color: green;
5192: }
1.795 www 5193:
1.395 albertel 5194: span.LC_parm_scope_resource {
5195: color: orange;
5196: }
1.795 www 5197:
1.395 albertel 5198: span.LC_parm_part {
5199: color: blue;
5200: }
1.795 www 5201:
1.395 albertel 5202: span.LC_parm_folder, span.LC_parm_symb {
5203: font-size: x-small;
5204: font-family: $mono;
5205: color: #AAAAAA;
5206: }
5207:
1.795 www 5208: td.LC_parm_overview_level_menu,
5209: td.LC_parm_overview_map_menu,
5210: td.LC_parm_overview_parm_selectors,
5211: td.LC_parm_overview_restrictions {
1.396 albertel 5212: border: 1px solid black;
5213: border-collapse: collapse;
5214: }
1.795 www 5215:
1.396 albertel 5216: table.LC_parm_overview_restrictions td {
5217: border-width: 1px 4px 1px 4px;
5218: border-style: solid;
5219: border-color: $pgbg;
5220: text-align: center;
5221: }
1.795 www 5222:
1.396 albertel 5223: table.LC_parm_overview_restrictions th {
5224: background: $tabbg;
5225: border-width: 1px 4px 1px 4px;
5226: border-style: solid;
5227: border-color: $pgbg;
5228: }
1.795 www 5229:
1.398 albertel 5230: table#LC_helpmenu {
1.803 bisitz 5231: border: none;
1.398 albertel 5232: height: 55px;
1.803 bisitz 5233: border-spacing: 0;
1.398 albertel 5234: }
5235:
5236: table#LC_helpmenu fieldset legend {
5237: font-size: larger;
5238: }
1.795 www 5239:
1.397 albertel 5240: table#LC_helpmenu_links {
5241: width: 100%;
5242: border: 1px solid black;
5243: background: $pgbg;
1.803 bisitz 5244: padding: 0;
1.397 albertel 5245: border-spacing: 1px;
5246: }
1.795 www 5247:
1.397 albertel 5248: table#LC_helpmenu_links tr td {
5249: padding: 1px;
5250: background: $tabbg;
1.399 albertel 5251: text-align: center;
5252: font-weight: bold;
1.397 albertel 5253: }
1.396 albertel 5254:
1.795 www 5255: table#LC_helpmenu_links a:link,
5256: table#LC_helpmenu_links a:visited,
1.397 albertel 5257: table#LC_helpmenu_links a:active {
5258: text-decoration: none;
5259: color: $font;
5260: }
1.795 www 5261:
1.397 albertel 5262: table#LC_helpmenu_links a:hover {
5263: text-decoration: underline;
5264: color: $vlink;
5265: }
1.396 albertel 5266:
1.417 albertel 5267: .LC_chrt_popup_exists {
5268: border: 1px solid #339933;
5269: margin: -1px;
5270: }
1.795 www 5271:
1.417 albertel 5272: .LC_chrt_popup_up {
5273: border: 1px solid yellow;
5274: margin: -1px;
5275: }
1.795 www 5276:
1.417 albertel 5277: .LC_chrt_popup {
5278: border: 1px solid #8888FF;
5279: background: #CCCCFF;
5280: }
1.795 www 5281:
1.421 albertel 5282: table.LC_pick_box {
5283: border-collapse: separate;
5284: background: white;
5285: border: 1px solid black;
5286: border-spacing: 1px;
5287: }
1.795 www 5288:
1.421 albertel 5289: table.LC_pick_box td.LC_pick_box_title {
1.850 bisitz 5290: background: $sidebg;
1.421 albertel 5291: font-weight: bold;
5292: text-align: right;
1.740 bisitz 5293: vertical-align: top;
1.421 albertel 5294: width: 184px;
5295: padding: 8px;
5296: }
1.795 www 5297:
1.579 raeburn 5298: table.LC_pick_box td.LC_pick_box_value {
5299: text-align: left;
5300: padding: 8px;
5301: }
1.795 www 5302:
1.579 raeburn 5303: table.LC_pick_box td.LC_pick_box_select {
5304: text-align: left;
5305: padding: 8px;
5306: }
1.795 www 5307:
1.424 albertel 5308: table.LC_pick_box td.LC_pick_box_separator {
1.803 bisitz 5309: padding: 0;
1.421 albertel 5310: height: 1px;
5311: background: black;
5312: }
1.795 www 5313:
1.421 albertel 5314: table.LC_pick_box td.LC_pick_box_submit {
5315: text-align: right;
5316: }
1.795 www 5317:
1.579 raeburn 5318: table.LC_pick_box td.LC_evenrow_value {
5319: text-align: left;
5320: padding: 8px;
5321: background-color: $data_table_light;
5322: }
1.795 www 5323:
1.579 raeburn 5324: table.LC_pick_box td.LC_oddrow_value {
5325: text-align: left;
5326: padding: 8px;
5327: background-color: $data_table_light;
5328: }
1.795 www 5329:
1.579 raeburn 5330: table.LC_helpform_receipt {
5331: width: 620px;
5332: border-collapse: separate;
5333: background: white;
5334: border: 1px solid black;
5335: border-spacing: 1px;
5336: }
1.795 www 5337:
1.579 raeburn 5338: table.LC_helpform_receipt td.LC_pick_box_title {
5339: background: $tabbg;
5340: font-weight: bold;
5341: text-align: right;
5342: width: 184px;
5343: padding: 8px;
5344: }
1.795 www 5345:
1.579 raeburn 5346: table.LC_helpform_receipt td.LC_evenrow_value {
5347: text-align: left;
5348: padding: 8px;
5349: background-color: $data_table_light;
5350: }
1.795 www 5351:
1.579 raeburn 5352: table.LC_helpform_receipt td.LC_oddrow_value {
5353: text-align: left;
5354: padding: 8px;
5355: background-color: $data_table_light;
5356: }
1.795 www 5357:
1.579 raeburn 5358: table.LC_helpform_receipt td.LC_pick_box_separator {
1.803 bisitz 5359: padding: 0;
1.579 raeburn 5360: height: 1px;
5361: background: black;
5362: }
1.795 www 5363:
1.579 raeburn 5364: span.LC_helpform_receipt_cat {
5365: font-weight: bold;
5366: }
1.795 www 5367:
1.424 albertel 5368: table.LC_group_priv_box {
5369: background: white;
5370: border: 1px solid black;
5371: border-spacing: 1px;
5372: }
1.795 www 5373:
1.424 albertel 5374: table.LC_group_priv_box td.LC_pick_box_title {
5375: background: $tabbg;
5376: font-weight: bold;
5377: text-align: right;
5378: width: 184px;
5379: }
1.795 www 5380:
1.424 albertel 5381: table.LC_group_priv_box td.LC_groups_fixed {
5382: background: $data_table_light;
5383: text-align: center;
5384: }
1.795 www 5385:
1.424 albertel 5386: table.LC_group_priv_box td.LC_groups_optional {
5387: background: $data_table_dark;
5388: text-align: center;
5389: }
1.795 www 5390:
1.424 albertel 5391: table.LC_group_priv_box td.LC_groups_functionality {
5392: background: $data_table_darker;
5393: text-align: center;
5394: font-weight: bold;
5395: }
1.795 www 5396:
1.424 albertel 5397: table.LC_group_priv td {
5398: text-align: left;
1.803 bisitz 5399: padding: 0;
1.424 albertel 5400: }
5401:
1.421 albertel 5402: table.LC_notify_front_page {
5403: background: white;
5404: border: 1px solid black;
5405: padding: 8px;
5406: }
1.795 www 5407:
1.421 albertel 5408: table.LC_notify_front_page td {
5409: padding: 8px;
5410: }
1.795 www 5411:
1.424 albertel 5412: .LC_navbuttons {
5413: margin: 2ex 0ex 2ex 0ex;
5414: }
1.795 www 5415:
1.423 albertel 5416: .LC_topic_bar {
5417: font-weight: bold;
5418: width: 100%;
5419: background: $tabbg;
5420: vertical-align: middle;
5421: margin: 2ex 0ex 2ex 0ex;
1.805 bisitz 5422: padding: 3px;
1.423 albertel 5423: }
1.795 www 5424:
1.423 albertel 5425: .LC_topic_bar span {
5426: vertical-align: middle;
5427: }
1.795 www 5428:
1.423 albertel 5429: .LC_topic_bar img {
5430: vertical-align: bottom;
5431: }
1.795 www 5432:
1.423 albertel 5433: table.LC_course_group_status {
5434: margin: 20px;
5435: }
1.795 www 5436:
1.423 albertel 5437: table.LC_status_selector td {
5438: vertical-align: top;
5439: text-align: center;
1.424 albertel 5440: padding: 4px;
5441: }
1.795 www 5442:
1.599 albertel 5443: div.LC_feedback_link {
1.616 albertel 5444: clear: both;
1.829 kalberla 5445: background: $sidebg;
1.779 bisitz 5446: width: 100%;
1.829 kalberla 5447: padding-bottom: 10px;
5448: border: 1px $tabbg solid;
1.833 kalberla 5449: height: 22px;
5450: line-height: 22px;
5451: padding-top: 5px;
5452: }
5453:
5454: div.LC_feedback_link img {
5455: height: 22px;
1.867 kalberla 5456: vertical-align:middle;
1.829 kalberla 5457: }
5458:
5459: div.LC_feedback_link a{
5460: text-decoration: none;
1.489 raeburn 5461: }
1.795 www 5462:
1.867 kalberla 5463: div.LC_comblock {
5464: display:inline;
5465: color:$font;
5466: font-size:90%;
5467: }
5468:
5469: div.LC_feedback_link div.LC_comblock {
5470: padding-left:5px;
5471: }
5472:
5473: div.LC_feedback_link div.LC_comblock a {
5474: color:$font;
5475: }
5476:
1.489 raeburn 5477: span.LC_feedback_link {
1.858 bisitz 5478: /* background: $feedback_link_bg; */
1.599 albertel 5479: font-size: larger;
5480: }
1.795 www 5481:
1.599 albertel 5482: span.LC_message_link {
1.858 bisitz 5483: /* background: $feedback_link_bg; */
1.599 albertel 5484: font-size: larger;
5485: position: absolute;
5486: right: 1em;
1.489 raeburn 5487: }
1.421 albertel 5488:
1.515 albertel 5489: table.LC_prior_tries {
1.524 albertel 5490: border: 1px solid #000000;
5491: border-collapse: separate;
5492: border-spacing: 1px;
1.515 albertel 5493: }
1.523 albertel 5494:
1.515 albertel 5495: table.LC_prior_tries td {
1.524 albertel 5496: padding: 2px;
1.515 albertel 5497: }
1.523 albertel 5498:
5499: .LC_answer_correct {
1.795 www 5500: background: lightgreen;
5501: color: darkgreen;
5502: padding: 6px;
1.523 albertel 5503: }
1.795 www 5504:
1.523 albertel 5505: .LC_answer_charged_try {
1.797 www 5506: background: #FFAAAA;
1.795 www 5507: color: darkred;
5508: padding: 6px;
1.523 albertel 5509: }
1.795 www 5510:
1.779 bisitz 5511: .LC_answer_not_charged_try,
1.523 albertel 5512: .LC_answer_no_grade,
5513: .LC_answer_late {
1.795 www 5514: background: lightyellow;
1.523 albertel 5515: color: black;
1.795 www 5516: padding: 6px;
1.523 albertel 5517: }
1.795 www 5518:
1.523 albertel 5519: .LC_answer_previous {
1.795 www 5520: background: lightblue;
5521: color: darkblue;
5522: padding: 6px;
1.523 albertel 5523: }
1.795 www 5524:
1.779 bisitz 5525: .LC_answer_no_message {
1.777 tempelho 5526: background: #FFFFFF;
5527: color: black;
1.795 www 5528: padding: 6px;
1.779 bisitz 5529: }
1.795 www 5530:
1.779 bisitz 5531: .LC_answer_unknown {
5532: background: orange;
5533: color: black;
1.795 www 5534: padding: 6px;
1.777 tempelho 5535: }
1.795 www 5536:
1.529 albertel 5537: span.LC_prior_numerical,
5538: span.LC_prior_string,
5539: span.LC_prior_custom,
5540: span.LC_prior_reaction,
5541: span.LC_prior_math {
1.523 albertel 5542: font-family: monospace;
5543: white-space: pre;
5544: }
5545:
1.525 albertel 5546: span.LC_prior_string {
5547: font-family: monospace;
5548: white-space: pre;
5549: }
5550:
1.523 albertel 5551: table.LC_prior_option {
5552: width: 100%;
5553: border-collapse: collapse;
5554: }
1.795 www 5555:
5556: table.LC_prior_rank,
5557: table.LC_prior_match {
1.528 albertel 5558: border-collapse: collapse;
5559: }
1.795 www 5560:
1.528 albertel 5561: table.LC_prior_option tr td,
5562: table.LC_prior_rank tr td,
5563: table.LC_prior_match tr td {
1.524 albertel 5564: border: 1px solid #000000;
1.515 albertel 5565: }
5566:
1.855 bisitz 5567: .LC_nobreak {
1.544 albertel 5568: white-space: nowrap;
1.519 raeburn 5569: }
5570:
1.576 raeburn 5571: span.LC_cusr_emph {
5572: font-style: italic;
5573: }
5574:
1.633 raeburn 5575: span.LC_cusr_subheading {
5576: font-weight: normal;
5577: font-size: 85%;
5578: }
5579:
1.545 albertel 5580: table.LC_docs_documents {
5581: background: #BBBBBB;
1.803 bisitz 5582: border-width: 0;
1.545 albertel 5583: border-collapse: collapse;
5584: }
1.795 www 5585:
1.777 tempelho 5586: table.LC_docs_documents td.LC_docs_document {
1.779 bisitz 5587: border: 2px solid black;
5588: padding: 4px;
1.777 tempelho 5589: }
1.795 www 5590:
1.861 bisitz 5591: div.LC_docs_entry_move {
1.859 bisitz 5592: border: 1px solid #BBBBBB;
1.545 albertel 5593: background: #DDDDDD;
1.861 bisitz 5594: width: 22px;
1.859 bisitz 5595: padding: 1px;
5596: margin: 0;
1.545 albertel 5597: }
5598:
1.861 bisitz 5599: table.LC_data_table tr > td.LC_docs_entry_commands,
5600: table.LC_data_table tr > td.LC_docs_entry_parameter {
1.545 albertel 5601: background: #DDDDDD;
5602: font-size: x-small;
5603: }
1.795 www 5604:
1.861 bisitz 5605: .LC_docs_entry_parameter {
5606: white-space: nowrap;
5607: }
5608:
1.544 albertel 5609: .LC_docs_copy {
1.545 albertel 5610: color: #000099;
1.544 albertel 5611: }
1.795 www 5612:
1.544 albertel 5613: .LC_docs_cut {
1.545 albertel 5614: color: #550044;
1.544 albertel 5615: }
1.795 www 5616:
1.544 albertel 5617: .LC_docs_rename {
1.545 albertel 5618: color: #009900;
1.544 albertel 5619: }
1.795 www 5620:
1.544 albertel 5621: .LC_docs_remove {
1.545 albertel 5622: color: #990000;
5623: }
5624:
1.547 albertel 5625: .LC_docs_reinit_warn,
5626: .LC_docs_ext_edit {
5627: font-size: x-small;
5628: }
5629:
1.545 albertel 5630: table.LC_docs_adddocs td,
5631: table.LC_docs_adddocs th {
5632: border: 1px solid #BBBBBB;
5633: padding: 4px;
5634: background: #DDDDDD;
1.543 albertel 5635: }
5636:
1.584 albertel 5637: table.LC_sty_begin {
5638: background: #BBFFBB;
5639: }
1.795 www 5640:
1.584 albertel 5641: table.LC_sty_end {
5642: background: #FFBBBB;
5643: }
5644:
1.589 raeburn 5645: table.LC_double_column {
1.803 bisitz 5646: border-width: 0;
1.589 raeburn 5647: border-collapse: collapse;
5648: width: 100%;
5649: padding: 2px;
5650: }
5651:
5652: table.LC_double_column tr td.LC_left_col {
1.590 raeburn 5653: top: 2px;
1.589 raeburn 5654: left: 2px;
5655: width: 47%;
5656: vertical-align: top;
5657: }
5658:
5659: table.LC_double_column tr td.LC_right_col {
5660: top: 2px;
1.779 bisitz 5661: right: 2px;
1.589 raeburn 5662: width: 47%;
5663: vertical-align: top;
5664: }
5665:
1.591 raeburn 5666: div.LC_left_float {
5667: float: left;
5668: padding-right: 5%;
1.597 albertel 5669: padding-bottom: 4px;
1.591 raeburn 5670: }
5671:
5672: div.LC_clear_float_header {
1.597 albertel 5673: padding-bottom: 2px;
1.591 raeburn 5674: }
5675:
5676: div.LC_clear_float_footer {
1.597 albertel 5677: padding-top: 10px;
1.591 raeburn 5678: clear: both;
5679: }
5680:
1.597 albertel 5681: div.LC_grade_show_user {
5682: margin-top: 20px;
5683: border: 1px solid black;
5684: }
1.795 www 5685:
1.597 albertel 5686: div.LC_grade_user_name {
5687: background: #DDDDEE;
5688: border-bottom: 1px solid black;
1.705 tempelho 5689: font-weight: bold;
5690: font-size: large;
1.597 albertel 5691: }
1.795 www 5692:
1.597 albertel 5693: div.LC_grade_show_user_odd_row div.LC_grade_user_name {
5694: background: #DDEEDD;
5695: }
5696:
5697: div.LC_grade_show_problem,
5698: div.LC_grade_submissions,
5699: div.LC_grade_message_center,
5700: div.LC_grade_info_links,
5701: div.LC_grade_assign {
5702: margin: 5px;
5703: width: 99%;
5704: background: #FFFFFF;
5705: }
1.795 www 5706:
1.597 albertel 5707: div.LC_grade_show_problem_header,
5708: div.LC_grade_submissions_header,
5709: div.LC_grade_message_center_header,
5710: div.LC_grade_assign_header {
1.705 tempelho 5711: font-weight: bold;
5712: font-size: large;
1.597 albertel 5713: }
1.795 www 5714:
1.597 albertel 5715: div.LC_grade_show_problem_problem,
5716: div.LC_grade_submissions_body,
5717: div.LC_grade_message_center_body,
5718: div.LC_grade_assign_body {
5719: border: 1px solid black;
5720: width: 99%;
5721: background: #FFFFFF;
5722: }
1.795 www 5723:
1.598 albertel 5724: span.LC_grade_check_note {
1.705 tempelho 5725: font-weight: normal;
5726: font-size: medium;
1.598 albertel 5727: display: inline;
5728: position: absolute;
5729: right: 1em;
5730: }
1.597 albertel 5731:
1.613 albertel 5732: table.LC_scantron_action {
5733: width: 100%;
5734: }
1.795 www 5735:
1.613 albertel 5736: table.LC_scantron_action tr th {
1.698 harmsja 5737: font-weight:bold;
5738: font-style:normal;
1.613 albertel 5739: }
1.795 www 5740:
1.779 bisitz 5741: .LC_edit_problem_header,
1.614 albertel 5742: div.LC_edit_problem_footer {
1.705 tempelho 5743: font-weight: normal;
5744: font-size: medium;
1.602 albertel 5745: margin: 2px;
1.600 albertel 5746: }
1.795 www 5747:
1.600 albertel 5748: div.LC_edit_problem_header,
1.602 albertel 5749: div.LC_edit_problem_header div,
1.614 albertel 5750: div.LC_edit_problem_footer,
5751: div.LC_edit_problem_footer div,
1.602 albertel 5752: div.LC_edit_problem_editxml_header,
5753: div.LC_edit_problem_editxml_header div {
1.600 albertel 5754: margin-top: 5px;
5755: }
1.795 www 5756:
1.600 albertel 5757: div.LC_edit_problem_header_title {
1.705 tempelho 5758: font-weight: bold;
5759: font-size: larger;
1.602 albertel 5760: background: $tabbg;
5761: padding: 3px;
5762: }
1.795 www 5763:
1.602 albertel 5764: table.LC_edit_problem_header_title {
1.705 tempelho 5765: font-size: larger;
5766: font-weight: bold;
1.602 albertel 5767: width: 100%;
5768: border-color: $pgbg;
5769: border-style: solid;
5770: border-width: $border;
1.600 albertel 5771: background: $tabbg;
1.602 albertel 5772: border-collapse: collapse;
1.803 bisitz 5773: padding: 0;
1.602 albertel 5774: }
5775:
5776: div.LC_edit_problem_discards {
5777: float: left;
5778: padding-bottom: 5px;
5779: }
1.795 www 5780:
1.602 albertel 5781: div.LC_edit_problem_saves {
5782: float: right;
5783: padding-bottom: 5px;
1.600 albertel 5784: }
1.795 www 5785:
1.679 riegler 5786: img.stift{
1.803 bisitz 5787: border-width: 0;
5788: vertical-align: middle;
1.677 riegler 5789: }
1.680 riegler 5790:
1.681 riegler 5791: table#LC_mainmenu{
5792: margin-top:10px;
5793: width:80%;
5794: }
5795:
1.680 riegler 5796: table#LC_mainmenu td.LC_mainmenu_col_fieldset{
5797: vertical-align: top;
5798: width: 45%;
5799: }
1.795 www 5800:
1.779 bisitz 5801: .LC_mainmenu_fieldset_category {
5802: color: $font;
5803: background: $pgbg;
5804: font-size: small;
5805: font-weight: bold;
1.777 tempelho 5806: }
1.795 www 5807:
1.716 raeburn 5808: div.LC_createcourse {
5809: margin: 10px 10px 10px 10px;
5810: }
5811:
1.693 droeschl 5812: /* ---- Remove when done ----
5813: # The following styles is part of the redesign of LON-CAPA and are
5814: # subject to change during this project.
5815: # Don't rely on their current functionality as they might be
5816: # changed or removed.
5817: # --------------------------*/
5818:
1.698 harmsja 5819: a:hover,
1.721 harmsja 5820: ol.LC_smallMenu a:hover,
5821: ol#LC_MenuBreadcrumbs a:hover,
5822: ol#LC_PathBreadcrumbs a:hover,
5823: ul#LC_TabMainMenuContent a:hover,
5824: .LC_FormSectionClearButton input:hover
1.795 www 5825: ul.LC_TabContent li:hover a {
1.698 harmsja 5826: color:#BF2317;
5827: text-decoration:none;
1.693 droeschl 5828: }
5829:
1.779 bisitz 5830: h1 {
1.813 bisitz 5831: padding: 0;
1.693 droeschl 5832: line-height:130%;
5833: }
1.698 harmsja 5834:
1.795 www 5835: h2,h3,h4,h5,h6 {
1.803 bisitz 5836: margin: 5px 0 5px 0;
5837: padding: 0;
1.721 harmsja 5838: line-height:130%;
1.693 droeschl 5839: }
1.795 www 5840:
5841: .LC_hcell {
1.698 harmsja 5842: padding:3px 15px 3px 15px;
1.803 bisitz 5843: margin: 0;
1.703 harmsja 5844: background-color:$tabbg;
1.801 tempelho 5845: color:$fontmenu;
1.779 bisitz 5846: border-bottom:solid 1px $lg_border_color;
1.693 droeschl 5847: }
1.795 www 5848:
1.840 bisitz 5849: .LC_Box > .LC_hcell {
1.847 tempelho 5850: margin: 0 -10px 10px -10px;
1.835 bisitz 5851: }
5852:
1.721 harmsja 5853: .LC_noBorder {
1.803 bisitz 5854: border: 0;
1.698 harmsja 5855: }
1.693 droeschl 5856:
1.761 tempelho 5857: .LC_Right {
5858: float: right;
1.803 bisitz 5859: margin: 0;
5860: padding: 0;
1.761 tempelho 5861: }
5862:
1.721 harmsja 5863: .LC_FormSectionClearButton input {
1.779 bisitz 5864: background-color:transparent;
1.803 bisitz 5865: border: none;
1.698 harmsja 5866: cursor:pointer;
5867: text-decoration:underline;
1.693 droeschl 5868: }
1.763 bisitz 5869:
5870: .LC_help_open_topic {
5871: color: #FFFFFF;
5872: background-color: #EEEEFF;
5873: margin: 1px;
5874: padding: 4px;
5875: border: 1px solid #000033;
5876: white-space: nowrap;
1.783 amueller 5877: /* vertical-align: middle; */
1.759 neumanie 5878: }
1.693 droeschl 5879:
1.698 harmsja 5880: dl,ul,div,fieldset {
1.803 bisitz 5881: margin: 10px 10px 10px 0;
1.806 bisitz 5882: /* overflow: hidden; */
1.693 droeschl 5883: }
1.795 www 5884:
1.838 bisitz 5885: fieldset > legend {
5886: font-weight: bold;
5887: padding: 0 5px 0 5px;
5888: }
5889:
1.813 bisitz 5890: #LC_nav_bar {
1.807 droeschl 5891: float: left;
1.852 droeschl 5892: margin: 0.2em 0 0 0;
1.807 droeschl 5893: }
5894:
1.813 bisitz 5895: #LC_nav_bar em{
1.807 droeschl 5896: font-weight: bold;
5897: font-style: normal;
5898: }
5899:
5900: ol.LC_smallMenu {
5901: float: right;
1.852 droeschl 5902: margin: 0.2em 0 0 0;
1.807 droeschl 5903: }
5904:
1.852 droeschl 5905: ol#LC_PathBreadcrumbs {
1.803 bisitz 5906: margin: 0;
1.693 droeschl 5907: }
5908:
1.721 harmsja 5909: ol.LC_smallMenu li {
1.693 droeschl 5910: display: inline;
1.803 bisitz 5911: padding: 5px 5px 0 10px;
1.693 droeschl 5912: vertical-align: top;
5913: }
5914:
1.721 harmsja 5915: ol.LC_smallMenu li img {
1.693 droeschl 5916: vertical-align: bottom;
5917: }
5918:
1.721 harmsja 5919: ol.LC_smallMenu a {
1.693 droeschl 5920: font-size: 90%;
5921: color: RGB(80, 80, 80);
5922: text-decoration: none;
5923: }
1.795 www 5924:
1.808 droeschl 5925: ul#LC_TabMainMenuContent {
1.807 droeschl 5926: clear: both;
1.808 droeschl 5927: color: $fontmenu;
5928: background: $tabbg;
5929: list-style: none;
5930: padding: 0;
5931: margin: 0;
5932: width: 100%;
5933: }
5934:
5935: ul#LC_TabMainMenuContent li {
5936: font-weight: bold;
5937: line-height: 1.8em;
5938: padding: 0 0.8em;
5939: border-right: 1px solid black;
5940: display: inline;
5941: vertical-align: middle;
1.807 droeschl 5942: }
5943:
1.847 tempelho 5944: ul.LC_TabContent {
1.721 harmsja 5945: display:block;
1.847 tempelho 5946: background: $sidebg;
1.858 bisitz 5947: border-bottom: solid 1px $lg_border_color;
1.721 harmsja 5948: list-style:none;
1.870 tempelho 5949: margin: 0 -10px;
1.803 bisitz 5950: padding: 0;
1.693 droeschl 5951: }
5952:
1.795 www 5953: ul.LC_TabContent li,
5954: ul.LC_TabContentBigger li {
1.741 harmsja 5955: float:left;
5956: }
1.795 www 5957:
1.808 droeschl 5958: ul#LC_TabMainMenuContent li a {
5959: color: $fontmenu;
1.693 droeschl 5960: text-decoration: none;
5961: }
1.795 www 5962:
1.721 harmsja 5963: ul.LC_TabContent {
1.847 tempelho 5964: min-height:1.5em;
1.721 harmsja 5965: }
1.795 www 5966:
5967: ul.LC_TabContent li {
1.741 harmsja 5968: vertical-align:middle;
1.803 bisitz 5969: padding: 0 10px 0 10px;
1.745 ehlerst 5970: background-color:$tabbg;
5971: border-bottom:solid 1px $lg_border_color;
1.721 harmsja 5972: }
1.795 www 5973:
1.847 tempelho 5974: ul.LC_TabContent .right {
5975: float:right;
5976: }
5977:
1.795 www 5978: ul.LC_TabContent li a, ul.LC_TabContent li {
1.721 harmsja 5979: color:rgb(47,47,47);
5980: text-decoration:none;
5981: font-size:95%;
5982: font-weight:bold;
1.761 tempelho 5983: padding-right: 16px;
1.721 harmsja 5984: }
1.795 www 5985:
5986: ul.LC_TabContent li:hover, ul.LC_TabContent li.active {
1.761 tempelho 5987: background:#FFFFFF url(/adm/lonIcons/open.gif) no-repeat scroll right center;
1.841 tempelho 5988: border-bottom:solid 2px #FFFFFF;
1.761 tempelho 5989: padding-right: 16px;
1.744 ehlerst 5990: }
1.795 www 5991:
1.870 tempelho 5992: #maincoursedoc {
5993: clear:both;
5994: }
5995:
5996: ul.LC_TabContentBigger {
5997: display:block;
5998: list-style:none;
5999: padding: 0;
6000: }
6001:
1.795 www 6002: ul.LC_TabContentBigger li {
1.870 tempelho 6003: vertical-align:bottom;
6004: height: 30px;
6005: font-size:110%;
6006: font-weight:bold;
6007: color: #737373;
1.841 tempelho 6008: }
6009:
1.870 tempelho 6010:
6011: ul.LC_TabContentBigger li a {
6012: background:url('/adm/lonIcons/tabbgleft.gif') left bottom no-repeat;
6013: height: 30px;
6014: line-height: 30px;
6015: text-align: center;
6016: display: block;
6017: text-decoration: none;
1.741 harmsja 6018: }
1.795 www 6019:
1.870 tempelho 6020: ul.LC_TabContentBigger li:hover a,
6021: ul.LC_TabContentBigger li.active a {
6022: background:url('/adm/lonIcons/tabbgleft.gif') left top no-repeat;
1.857 tempelho 6023: color:$font;
1.870 tempelho 6024: text-decoration: underline;
1.744 ehlerst 6025: }
1.795 www 6026:
1.870 tempelho 6027:
6028: ul.LC_TabContentBigger li b {
6029: background: url('/adm/lonIcons/tabbgright.gif') no-repeat right bottom;
6030: display: block;
6031: float: left;
6032: padding: 0 30px;
6033: }
6034:
6035: ul.LC_TabContentBigger li:hover b,
6036: ul.LC_TabContentBigger li.active b {
6037: background:url('/adm/lonIcons/tabbgright.gif') right top no-repeat;
6038: color:$font;
6039: border-bottom: 1px solid #FFFFFF;
1.741 harmsja 6040: }
1.693 droeschl 6041:
1.870 tempelho 6042:
1.862 bisitz 6043: ul.LC_CourseBreadcrumbs {
6044: background: $sidebg;
6045: line-height: 32px;
6046: padding-left: 10px;
6047: margin: 0 0 10px 0;
6048: list-style-position: inside;
6049:
6050: }
6051:
1.795 www 6052: ol#LC_MenuBreadcrumbs,
1.862 bisitz 6053: ol#LC_PathBreadcrumbs {
1.693 droeschl 6054: padding-left: 10px;
1.819 tempelho 6055: margin: 0;
1.693 droeschl 6056: list-style-position: inside;
6057: }
6058:
1.795 www 6059: ol#LC_MenuBreadcrumbs li,
6060: ol#LC_PathBreadcrumbs li,
1.862 bisitz 6061: ul.LC_CourseBreadcrumbs li {
1.842 droeschl 6062: display: inline;
6063: white-space: nowrap;
1.693 droeschl 6064: }
6065:
1.823 bisitz 6066: ol#LC_MenuBreadcrumbs li a,
1.862 bisitz 6067: ul.LC_CourseBreadcrumbs li a {
1.693 droeschl 6068: text-decoration: none;
6069: font-size:90%;
6070: }
1.795 www 6071:
6072: ol#LC_PathBreadcrumbs li a {
1.698 harmsja 6073: text-decoration:none;
6074: font-size:100%;
6075: font-weight:bold;
1.693 droeschl 6076: }
1.795 www 6077:
1.840 bisitz 6078: .LC_Box {
1.835 bisitz 6079: border: solid 1px $lg_border_color;
6080: padding: 0 10px 10px 10px;
1.746 neumanie 6081: }
1.795 www 6082:
6083: .LC_AboutMe_Image {
1.747 neumanie 6084: float:left;
6085: margin-right:10px;
6086: }
1.795 www 6087:
6088: .LC_Clear_AboutMe_Image {
1.747 neumanie 6089: clear:left;
6090: }
1.795 www 6091:
1.721 harmsja 6092: dl.LC_ListStyleClean dt {
1.693 droeschl 6093: padding-right: 5px;
6094: display: table-header-group;
6095: }
6096:
1.721 harmsja 6097: dl.LC_ListStyleClean dd {
1.693 droeschl 6098: display: table-row;
6099: }
6100:
1.721 harmsja 6101: .LC_ListStyleClean,
6102: .LC_ListStyleSimple,
6103: .LC_ListStyleNormal,
1.777 tempelho 6104: .LC_ListStyle_Border,
1.795 www 6105: .LC_ListStyleSpecial {
1.693 droeschl 6106: /*display:block; */
6107: list-style-position: inside;
6108: list-style-type: none;
6109: overflow: hidden;
1.803 bisitz 6110: padding: 0;
1.693 droeschl 6111: }
6112:
1.721 harmsja 6113: .LC_ListStyleSimple li,
6114: .LC_ListStyleSimple dd,
6115: .LC_ListStyleNormal li,
6116: .LC_ListStyleNormal dd,
6117: .LC_ListStyleSpecial li,
1.795 www 6118: .LC_ListStyleSpecial dd {
1.803 bisitz 6119: margin: 0;
1.693 droeschl 6120: padding: 5px 5px 5px 10px;
6121: clear: both;
6122: }
6123:
1.721 harmsja 6124: .LC_ListStyleClean li,
6125: .LC_ListStyleClean dd {
1.803 bisitz 6126: padding-top: 0;
6127: padding-bottom: 0;
1.693 droeschl 6128: }
6129:
1.721 harmsja 6130: .LC_ListStyleSimple dd,
1.795 www 6131: .LC_ListStyleSimple li {
1.698 harmsja 6132: border-bottom: solid 1px $lg_border_color;
1.693 droeschl 6133: }
6134:
1.721 harmsja 6135: .LC_ListStyleSpecial li,
6136: .LC_ListStyleSpecial dd {
1.693 droeschl 6137: list-style-type: none;
6138: background-color: RGB(220, 220, 220);
6139: margin-bottom: 4px;
6140: }
6141:
1.721 harmsja 6142: table.LC_SimpleTable {
1.698 harmsja 6143: margin:5px;
6144: border:solid 1px $lg_border_color;
1.795 www 6145: }
1.693 droeschl 6146:
1.721 harmsja 6147: table.LC_SimpleTable tr {
1.803 bisitz 6148: padding: 0;
1.698 harmsja 6149: border:solid 1px $lg_border_color;
1.693 droeschl 6150: }
1.795 www 6151:
6152: table.LC_SimpleTable thead {
1.698 harmsja 6153: background:rgb(220,220,220);
1.693 droeschl 6154: }
6155:
1.721 harmsja 6156: div.LC_columnSection {
1.693 droeschl 6157: display: block;
6158: clear: both;
6159: overflow: hidden;
1.803 bisitz 6160: margin: 0;
1.693 droeschl 6161: }
6162:
1.721 harmsja 6163: div.LC_columnSection>* {
1.693 droeschl 6164: float: left;
1.803 bisitz 6165: margin: 10px 20px 10px 0;
1.747 neumanie 6166: overflow:hidden;
1.693 droeschl 6167: }
1.721 harmsja 6168:
1.694 tempelho 6169: .LC_loginpage_container {
6170: text-align:left;
6171: margin : 0 auto;
1.785 tempelho 6172: width:90%;
1.694 tempelho 6173: padding: 10px;
6174: height: auto;
1.712 muellerd 6175: background-color:#FFFFFF;
1.694 tempelho 6176: border:1px solid #CCCCCC;
6177: }
6178:
6179:
6180: .LC_loginpage_loginContainer {
6181: float:left;
1.712 muellerd 6182: width: 182px;
1.785 tempelho 6183: padding: 2px;
1.712 muellerd 6184: border:1px solid #CCCCCC;
6185: background-color:$loginbg;
1.694 tempelho 6186: }
6187:
1.795 www 6188: .LC_loginpage_loginContainer h2 {
1.803 bisitz 6189: margin-top: 0;
1.712 muellerd 6190: display:block;
6191: background:$bgcol;
6192: color:$textcol;
6193: padding-left:5px;
6194: }
1.785 tempelho 6195:
1.694 tempelho 6196: .LC_loginpage_loginInfo {
6197: float:left;
1.785 tempelho 6198: width:182px;
1.694 tempelho 6199: border:1px solid #CCCCCC;
1.785 tempelho 6200: padding:2px;
1.712 muellerd 6201: }
6202:
1.694 tempelho 6203: .LC_loginpage_space {
1.754 droeschl 6204: clear: both;
6205: margin-bottom: 20px;
1.694 tempelho 6206: border-bottom: 1px solid #CCCCCC;
6207: }
6208:
1.785 tempelho 6209: .LC_loginpage_floatLeft {
6210: float: left;
6211: width: 200px;
6212: margin: 0;
6213: }
6214:
1.795 www 6215: table em {
1.754 droeschl 6216: font-weight: bold;
6217: font-style: normal;
1.748 schulted 6218: }
1.795 www 6219:
1.779 bisitz 6220: table.LC_tableBrowseRes,
1.795 www 6221: table.LC_tableOfContent {
1.769 schulted 6222: border:none;
1.858 bisitz 6223: border-spacing: 1px;
1.754 droeschl 6224: padding: 3px;
6225: background-color: #FFFFFF;
6226: font-size: 90%;
1.753 droeschl 6227: }
1.789 droeschl 6228:
6229: table.LC_tableOfContent{
6230: border-collapse: collapse;
6231: }
6232:
1.771 droeschl 6233: table.LC_tableBrowseRes a,
1.768 schulted 6234: table.LC_tableOfContent a {
1.771 droeschl 6235: background-color: transparent;
1.753 droeschl 6236: text-decoration: none;
6237: }
6238:
1.771 droeschl 6239: table.LC_tableBrowseRes tr.LC_trOdd,
1.768 schulted 6240: table.LC_tableOfContent tr.LC_trOdd{
1.754 droeschl 6241: background-color: #EEEEEE;
1.753 droeschl 6242: }
6243:
1.795 www 6244: table.LC_tableOfContent img {
1.753 droeschl 6245: border: none;
6246: height: 1.3em;
6247: vertical-align: text-bottom;
6248: margin-right: 0.3em;
6249: }
1.757 schulted 6250:
1.795 www 6251: a#LC_content_toolbar_firsthomework {
1.774 ehlerst 6252: background-image:url(/res/adm/pages/open-first-problem.gif);
6253: }
6254:
1.795 www 6255: a#LC_content_toolbar_launchnav {
1.774 ehlerst 6256: background-image:url(/res/adm/pages/start-navigation.gif);
6257: }
6258:
1.795 www 6259: a#LC_content_toolbar_closenav {
1.774 ehlerst 6260: background-image:url(/res/adm/pages/close-navigation.gif);
6261: }
6262:
1.795 www 6263: a#LC_content_toolbar_everything {
1.774 ehlerst 6264: background-image:url(/res/adm/pages/show-all.gif);
6265: }
6266:
1.795 www 6267: a#LC_content_toolbar_uncompleted {
1.774 ehlerst 6268: background-image:url(/res/adm/pages/show-incomplete-problems.gif);
6269: }
6270:
1.795 www 6271: #LC_content_toolbar_clearbubbles {
1.774 ehlerst 6272: background-image:url(/res/adm/pages/mark-discussionentries-read.gif);
6273: }
6274:
1.795 www 6275: a#LC_content_toolbar_changefolder {
1.757 schulted 6276: background : url(/res/adm/pages/close-all-folders.gif) top center ;
6277: }
6278:
1.795 www 6279: a#LC_content_toolbar_changefolder_toggled {
1.757 schulted 6280: background-image:url(/res/adm/pages/open-all-folders.gif);
6281: }
6282:
1.795 www 6283: ul#LC_toolbar li a:hover {
1.757 schulted 6284: background-position: bottom center;
6285: }
6286:
1.795 www 6287: ul#LC_toolbar {
1.803 bisitz 6288: padding: 0;
1.757 schulted 6289: margin: 2px;
6290: list-style:none;
6291: position:relative;
6292: background-color:white;
6293: }
6294:
1.795 www 6295: ul#LC_toolbar li {
1.757 schulted 6296: border:1px solid white;
1.803 bisitz 6297: padding: 0;
1.757 schulted 6298: margin: 0;
1.795 www 6299: float: left;
1.767 droeschl 6300: display:inline;
1.757 schulted 6301: vertical-align:middle;
1.795 www 6302: }
1.757 schulted 6303:
1.783 amueller 6304:
1.795 www 6305: a.LC_toolbarItem {
1.767 droeschl 6306: display:block;
1.803 bisitz 6307: padding: 0;
6308: margin: 0;
1.757 schulted 6309: height: 32px;
6310: width: 32px;
1.779 bisitz 6311: color:white;
1.803 bisitz 6312: border: none;
1.757 schulted 6313: background-repeat:no-repeat;
6314: background-color:transparent;
6315: }
6316:
1.843 bisitz 6317: ul.LC_funclist li {
1.782 bisitz 6318: float: left;
6319: white-space: nowrap;
6320: height: 35px; /* at least as high as heighest list item */
1.803 bisitz 6321: margin: 0 15px 15px 10px;
1.782 bisitz 6322: }
6323:
1.757 schulted 6324:
1.343 albertel 6325: END
6326: }
6327:
1.306 albertel 6328: =pod
6329:
6330: =item * &headtag()
6331:
6332: Returns a uniform footer for LON-CAPA web pages.
6333:
1.307 albertel 6334: Inputs: $title - optional title for the head
6335: $head_extra - optional extra HTML to put inside the <head>
1.315 albertel 6336: $args - optional arguments
1.319 albertel 6337: force_register - if is true call registerurl so the remote is
6338: informed
1.415 albertel 6339: redirect -> array ref of
6340: 1- seconds before redirect occurs
6341: 2- url to redirect to
6342: 3- whether the side effect should occur
1.315 albertel 6343: (side effect of setting
6344: $env{'internal.head.redirect'} to the url
6345: redirected too)
1.352 albertel 6346: domain -> force to color decorate a page for a specific
6347: domain
6348: function -> force usage of a specific rolish color scheme
6349: bgcolor -> override the default page bgcolor
1.460 albertel 6350: no_auto_mt_title
6351: -> prevent &mt()ing the title arg
1.464 albertel 6352:
1.306 albertel 6353: =cut
6354:
6355: sub headtag {
1.313 albertel 6356: my ($title,$head_extra,$args) = @_;
1.306 albertel 6357:
1.363 albertel 6358: my $function = $args->{'function'} || &get_users_function();
6359: my $domain = $args->{'domain'} || &determinedomain();
6360: my $bgcolor = $args->{'bgcolor'} || &designparm($function.'.pgbg',$domain);
1.418 albertel 6361: my $url = join(':',$env{'user.name'},$env{'user.domain'},
1.458 albertel 6362: $Apache::lonnet::perlvar{'lonVersion'},
1.531 albertel 6363: #time(),
1.418 albertel 6364: $env{'environment.color.timestamp'},
1.363 albertel 6365: $function,$domain,$bgcolor);
6366:
1.369 www 6367: $url = '/adm/css/'.&escape($url).'.css';
1.363 albertel 6368:
1.308 albertel 6369: my $result =
6370: '<head>'.
1.461 albertel 6371: &font_settings();
1.319 albertel 6372:
1.461 albertel 6373: if (!$args->{'frameset'}) {
6374: $result .= &Apache::lonhtmlcommon::htmlareaheaders();
6375: }
1.319 albertel 6376: if ($args->{'force_register'}) {
6377: $result .= &Apache::lonmenu::registerurl(1);
6378: }
1.436 albertel 6379: if (!$args->{'no_nav_bar'}
6380: && !$args->{'only_body'}
6381: && !$args->{'frameset'}) {
6382: $result .= &help_menu_js();
6383: }
1.319 albertel 6384:
1.314 albertel 6385: if (ref($args->{'redirect'})) {
1.414 albertel 6386: my ($time,$url,$inhibit_continue) = @{$args->{'redirect'}};
1.315 albertel 6387: $url = &Apache::lonenc::check_encrypt($url);
1.414 albertel 6388: if (!$inhibit_continue) {
6389: $env{'internal.head.redirect'} = $url;
6390: }
1.313 albertel 6391: $result.=<<ADDMETA
6392: <meta http-equiv="pragma" content="no-cache" />
1.344 albertel 6393: <meta http-equiv="Refresh" content="$time; url=$url" />
1.313 albertel 6394: ADDMETA
6395: }
1.306 albertel 6396: if (!defined($title)) {
6397: $title = 'The LearningOnline Network with CAPA';
6398: }
1.460 albertel 6399: if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); }
6400: $result .= '<title> LON-CAPA '.$title.'</title>'
1.414 albertel 6401: .'<link rel="stylesheet" type="text/css" href="'.$url.'" />'
6402: .$head_extra;
1.306 albertel 6403: return $result;
6404: }
6405:
6406: =pod
6407:
1.340 albertel 6408: =item * &font_settings()
6409:
6410: Returns neccessary <meta> to set the proper encoding
6411:
6412: Inputs: none
6413:
6414: =cut
6415:
6416: sub font_settings {
6417: my $headerstring='';
1.647 www 6418: if (!$env{'browser.mathml'} && $env{'browser.unicode'}) {
1.340 albertel 6419: $headerstring.=
6420: '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
6421: }
6422: return $headerstring;
6423: }
6424:
1.341 albertel 6425: =pod
6426:
6427: =item * &xml_begin()
6428:
6429: Returns the needed doctype and <html>
6430:
6431: Inputs: none
6432:
6433: =cut
6434:
6435: sub xml_begin {
6436: my $output='';
6437:
1.592 albertel 6438: if ($env{'internal.start_page'}==1) {
6439: &Apache::lonhtmlcommon::init_htmlareafields();
6440: }
1.342 albertel 6441:
1.341 albertel 6442: if ($env{'browser.mathml'}) {
6443: $output='<?xml version="1.0"?>'
6444: #.'<?xml-stylesheet type="text/css" href="/adm/MathML/mathml.css"?>'."\n"
6445: # .'<!DOCTYPE html SYSTEM "/adm/MathML/mathml.dtd" '
6446:
6447: # .'<!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">] >'
6448: .'<!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">'
6449: .'<html xmlns:math="http://www.w3.org/1998/Math/MathML" '
6450: .'xmlns="http://www.w3.org/1999/xhtml">';
6451: } else {
1.849 bisitz 6452: $output='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
6453: .'<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';
1.341 albertel 6454: }
6455: return $output;
6456: }
1.340 albertel 6457:
6458: =pod
6459:
1.306 albertel 6460: =item * &endheadtag()
6461:
6462: Returns a uniform </head> for LON-CAPA web pages.
6463:
6464: Inputs: none
6465:
6466: =cut
6467:
6468: sub endheadtag {
6469: return '</head>';
6470: }
6471:
6472: =pod
6473:
6474: =item * &head()
6475:
6476: Returns a uniform complete <head>..</head> section for LON-CAPA web pages.
6477:
1.648 raeburn 6478: Inputs:
6479:
6480: =over 4
6481:
6482: $title - optional title for the page
6483:
6484: $head_extra - optional extra HTML to put inside the <head>
6485:
6486: =back
1.405 albertel 6487:
1.306 albertel 6488: =cut
6489:
6490: sub head {
1.325 albertel 6491: my ($title,$head_extra,$args) = @_;
6492: return &headtag($title,$head_extra,$args).&endheadtag();
1.306 albertel 6493: }
6494:
6495: =pod
6496:
6497: =item * &start_page()
6498:
6499: Returns a complete <html> .. <body> section for LON-CAPA web pages.
6500:
1.648 raeburn 6501: Inputs:
6502:
6503: =over 4
6504:
6505: $title - optional title for the page
6506:
6507: $head_extra - optional extra HTML to incude inside the <head>
6508:
6509: $args - additional optional args supported are:
6510:
6511: =over 8
6512:
6513: only_body -> is true will set &bodytag() onlybodytag
1.317 albertel 6514: arg on
1.814 bisitz 6515: no_nav_bar -> is true will set &bodytag() no_nav_bar arg on
1.648 raeburn 6516: add_entries -> additional attributes to add to the <body>
6517: domain -> force to color decorate a page for a
1.317 albertel 6518: specific domain
1.648 raeburn 6519: function -> force usage of a specific rolish color
1.317 albertel 6520: scheme
1.648 raeburn 6521: redirect -> see &headtag()
6522: bgcolor -> override the default page bg color
6523: js_ready -> return a string ready for being used in
1.317 albertel 6524: a javascript writeln
1.648 raeburn 6525: html_encode -> return a string ready for being used in
1.320 albertel 6526: a html attribute
1.648 raeburn 6527: force_register -> if is true will turn on the &bodytag()
1.317 albertel 6528: $forcereg arg
1.648 raeburn 6529: frameset -> if true will start with a <frameset>
1.330 albertel 6530: rather than <body>
1.648 raeburn 6531: skip_phases -> hash ref of
1.338 albertel 6532: head -> skip the <html><head> generation
6533: body -> skip all <body> generation
1.648 raeburn 6534: no_inline_link -> if true and in remote mode, don't show the
1.361 albertel 6535: 'Switch To Inline Menu' link
1.648 raeburn 6536: no_auto_mt_title -> prevent &mt()ing the title arg
6537: inherit_jsmath -> when creating popup window in a page,
6538: should it have jsmath forced on by the
6539: current page
1.867 kalberla 6540: bread_crumbs -> Array containing breadcrumbs
6541: bread_crumbs_components -> if exists show it as headline else show only the breadcrumbs
1.361 albertel 6542:
1.648 raeburn 6543: =back
1.460 albertel 6544:
1.648 raeburn 6545: =back
1.562 albertel 6546:
1.306 albertel 6547: =cut
6548:
6549: sub start_page {
1.309 albertel 6550: my ($title,$head_extra,$args) = @_;
1.318 albertel 6551: #&Apache::lonnet::logthis("start_page ".join(':',caller(0)));
1.313 albertel 6552: my %head_args;
1.352 albertel 6553: foreach my $arg ('redirect','force_register','domain','function',
1.460 albertel 6554: 'bgcolor','frameset','no_nav_bar','only_body',
6555: 'no_auto_mt_title') {
1.319 albertel 6556: if (defined($args->{$arg})) {
1.324 raeburn 6557: $head_args{$arg} = $args->{$arg};
1.319 albertel 6558: }
1.313 albertel 6559: }
1.319 albertel 6560:
1.315 albertel 6561: $env{'internal.start_page'}++;
1.338 albertel 6562: my $result;
6563: if (! exists($args->{'skip_phases'}{'head'}) ) {
6564: $result.=
1.341 albertel 6565: &xml_begin().
1.338 albertel 6566: &headtag($title,$head_extra,\%head_args).&endheadtag();
6567: }
6568:
6569: if (! exists($args->{'skip_phases'}{'body'}) ) {
6570: if ($args->{'frameset'}) {
6571: my $attr_string = &make_attr_string($args->{'force_register'},
6572: $args->{'add_entries'});
6573: $result .= "\n<frameset $attr_string>\n";
1.831 bisitz 6574: } else {
6575: $result .=
6576: &bodytag($title,
6577: $args->{'function'}, $args->{'add_entries'},
6578: $args->{'only_body'}, $args->{'domain'},
6579: $args->{'force_register'}, $args->{'no_nav_bar'},
6580: $args->{'bgcolor'}, $args->{'no_inline_link'},
6581: $args);
6582: }
1.330 albertel 6583: }
1.338 albertel 6584:
1.315 albertel 6585: if ($args->{'js_ready'}) {
1.713 kaisler 6586: $result = &js_ready($result);
1.315 albertel 6587: }
1.320 albertel 6588: if ($args->{'html_encode'}) {
1.713 kaisler 6589: $result = &html_encode($result);
6590: }
6591:
1.813 bisitz 6592: # Preparation for new and consistent functionlist at top of screen
6593: # if ($args->{'functionlist'}) {
6594: # $result .= &build_functionlist();
6595: #}
6596:
6597: # Don't add anything more if only_body wanted
6598: return $result if $args->{'only_body'};
6599:
6600: #Breadcrumbs
1.758 kaisler 6601: if (exists($args->{'bread_crumbs'}) or exists($args->{'bread_crumbs_component'})) {
6602: &Apache::lonhtmlcommon::clear_breadcrumbs();
6603: #if any br links exists, add them to the breadcrumbs
6604: if (exists($args->{'bread_crumbs'}) and ref($args->{'bread_crumbs'}) eq 'ARRAY') {
6605: foreach my $crumb (@{$args->{'bread_crumbs'}}){
6606: &Apache::lonhtmlcommon::add_breadcrumb($crumb);
6607: }
6608: }
6609:
6610: #if bread_crumbs_component exists show it as headline else show only the breadcrumbs
6611: if(exists($args->{'bread_crumbs_component'})){
6612: $result .= &Apache::lonhtmlcommon::breadcrumbs($args->{'bread_crumbs_component'});
6613: }else{
6614: $result .= &Apache::lonhtmlcommon::breadcrumbs();
6615: }
1.320 albertel 6616: }
1.315 albertel 6617: return $result;
1.306 albertel 6618: }
6619:
1.330 albertel 6620:
1.306 albertel 6621: =pod
6622:
6623: =item * &head()
6624:
6625: Returns a complete </body></html> section for LON-CAPA web pages.
6626:
1.315 albertel 6627: Inputs: $args - additional optional args supported are:
6628: js_ready -> return a string ready for being used in
6629: a javascript writeln
1.320 albertel 6630: html_encode -> return a string ready for being used in
6631: a html attribute
1.330 albertel 6632: frameset -> if true will start with a <frameset>
6633: rather than <body>
1.493 albertel 6634: dicsussion -> if true will get discussion from
6635: lonxml::xmlend
6636: (you can pass the target and parser arguments
6637: through optional 'target' and 'parser' args
6638: to this routine)
1.306 albertel 6639:
6640: =cut
6641:
6642: sub end_page {
1.315 albertel 6643: my ($args) = @_;
6644: $env{'internal.end_page'}++;
1.330 albertel 6645: my $result;
1.335 albertel 6646: if ($args->{'discussion'}) {
6647: my ($target,$parser);
6648: if (ref($args->{'discussion'})) {
6649: ($target,$parser) =($args->{'discussion'}{'target'},
6650: $args->{'discussion'}{'parser'});
6651: }
6652: $result .= &Apache::lonxml::xmlend($target,$parser);
6653: }
6654:
1.330 albertel 6655: if ($args->{'frameset'}) {
6656: $result .= '</frameset>';
6657: } else {
1.635 raeburn 6658: $result .= &endbodytag($args);
1.330 albertel 6659: }
6660: $result .= "\n</html>";
6661:
1.315 albertel 6662: if ($args->{'js_ready'}) {
1.317 albertel 6663: $result = &js_ready($result);
1.315 albertel 6664: }
1.335 albertel 6665:
1.320 albertel 6666: if ($args->{'html_encode'}) {
6667: $result = &html_encode($result);
6668: }
1.335 albertel 6669:
1.315 albertel 6670: return $result;
6671: }
6672:
1.320 albertel 6673: sub html_encode {
6674: my ($result) = @_;
6675:
1.322 albertel 6676: $result = &HTML::Entities::encode($result,'<>&"');
1.320 albertel 6677:
6678: return $result;
6679: }
1.317 albertel 6680: sub js_ready {
6681: my ($result) = @_;
6682:
1.323 albertel 6683: $result =~ s/[\n\r]/ /xmsg;
6684: $result =~ s/\\/\\\\/xmsg;
6685: $result =~ s/'/\\'/xmsg;
1.372 albertel 6686: $result =~ s{</}{<\\/}xmsg;
1.317 albertel 6687:
6688: return $result;
6689: }
6690:
1.315 albertel 6691: sub validate_page {
6692: if ( exists($env{'internal.start_page'})
1.316 albertel 6693: && $env{'internal.start_page'} > 1) {
6694: &Apache::lonnet::logthis('start_page called multiple times '.
1.318 albertel 6695: $env{'internal.start_page'}.' '.
1.316 albertel 6696: $ENV{'request.filename'});
1.315 albertel 6697: }
6698: if ( exists($env{'internal.end_page'})
1.316 albertel 6699: && $env{'internal.end_page'} > 1) {
6700: &Apache::lonnet::logthis('end_page called multiple times '.
1.318 albertel 6701: $env{'internal.end_page'}.' '.
1.316 albertel 6702: $env{'request.filename'});
1.315 albertel 6703: }
6704: if ( exists($env{'internal.start_page'})
6705: && ! exists($env{'internal.end_page'})) {
1.316 albertel 6706: &Apache::lonnet::logthis('start_page called without end_page '.
6707: $env{'request.filename'});
1.315 albertel 6708: }
6709: if ( ! exists($env{'internal.start_page'})
6710: && exists($env{'internal.end_page'})) {
1.316 albertel 6711: &Apache::lonnet::logthis('end_page called without start_page'.
6712: $env{'request.filename'});
1.315 albertel 6713: }
1.306 albertel 6714: }
1.315 albertel 6715:
1.318 albertel 6716: sub simple_error_page {
6717: my ($r,$title,$msg) = @_;
6718: my $page =
6719: &Apache::loncommon::start_page($title).
6720: &mt($msg).
6721: &Apache::loncommon::end_page();
6722: if (ref($r)) {
6723: $r->print($page);
1.327 albertel 6724: return;
1.318 albertel 6725: }
6726: return $page;
6727: }
1.347 albertel 6728:
6729: {
1.610 albertel 6730: my @row_count;
1.347 albertel 6731: sub start_data_table {
1.422 albertel 6732: my ($add_class) = @_;
6733: my $css_class = (join(' ','LC_data_table',$add_class));
1.610 albertel 6734: unshift(@row_count,0);
1.422 albertel 6735: return '<table class="'.$css_class.'">'."\n";
1.347 albertel 6736: }
6737:
6738: sub end_data_table {
1.610 albertel 6739: shift(@row_count);
1.389 albertel 6740: return '</table>'."\n";;
1.347 albertel 6741: }
6742:
6743: sub start_data_table_row {
1.422 albertel 6744: my ($add_class) = @_;
1.610 albertel 6745: $row_count[0]++;
6746: my $css_class = ($row_count[0] % 2)?'LC_odd_row':'LC_even_row';
1.428 albertel 6747: $css_class = (join(' ',$css_class,$add_class));
1.422 albertel 6748: return '<tr class="'.$css_class.'">'."\n";;
1.347 albertel 6749: }
1.471 banghart 6750:
6751: sub continue_data_table_row {
6752: my ($add_class) = @_;
1.610 albertel 6753: my $css_class = ($row_count[0] % 2)?'LC_odd_row':'LC_even_row';
1.471 banghart 6754: $css_class = (join(' ',$css_class,$add_class));
6755: return '<tr class="'.$css_class.'">'."\n";;
6756: }
1.347 albertel 6757:
6758: sub end_data_table_row {
1.389 albertel 6759: return '</tr>'."\n";;
1.347 albertel 6760: }
1.367 www 6761:
1.421 albertel 6762: sub start_data_table_empty_row {
1.707 bisitz 6763: # $row_count[0]++;
1.421 albertel 6764: return '<tr class="LC_empty_row" >'."\n";;
6765: }
6766:
6767: sub end_data_table_empty_row {
6768: return '</tr>'."\n";;
6769: }
6770:
1.367 www 6771: sub start_data_table_header_row {
1.389 albertel 6772: return '<tr class="LC_header_row">'."\n";;
1.367 www 6773: }
6774:
6775: sub end_data_table_header_row {
1.389 albertel 6776: return '</tr>'."\n";;
1.367 www 6777: }
1.347 albertel 6778: }
6779:
1.548 albertel 6780: =pod
6781:
6782: =item * &inhibit_menu_check($arg)
6783:
6784: Checks for a inhibitmenu state and generates output to preserve it
6785:
6786: Inputs: $arg - can be any of
6787: - undef - in which case the return value is a string
6788: to add into arguments list of a uri
6789: - 'input' - in which case the return value is a HTML
6790: <form> <input> field of type hidden to
6791: preserve the value
6792: - a url - in which case the return value is the url with
6793: the neccesary cgi args added to preserve the
6794: inhibitmenu state
6795: - a ref to a url - no return value, but the string is
6796: updated to include the neccessary cgi
6797: args to preserve the inhibitmenu state
6798:
6799: =cut
6800:
6801: sub inhibit_menu_check {
6802: my ($arg) = @_;
6803: &get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['inhibitmenu']);
6804: if ($arg eq 'input') {
6805: if ($env{'form.inhibitmenu'}) {
6806: return '<input type="hidden" name="inhibitmenu" value="'.$env{'form.inhibitmenu'}.'" />';
6807: } else {
6808: return
6809: }
6810: }
6811: if ($env{'form.inhibitmenu'}) {
6812: if (ref($arg)) {
6813: $$arg .= '?inhibitmenu='.$env{'form.inhibitmenu'};
6814: } elsif ($arg eq '') {
6815: $arg .= 'inhibitmenu='.$env{'form.inhibitmenu'};
6816: } else {
6817: $arg .= '?inhibitmenu='.$env{'form.inhibitmenu'};
6818: }
6819: }
6820: if (!ref($arg)) {
6821: return $arg;
6822: }
6823: }
6824:
1.251 albertel 6825: ###############################################
1.182 matthew 6826:
6827: =pod
6828:
1.549 albertel 6829: =back
6830:
6831: =head1 User Information Routines
6832:
6833: =over 4
6834:
1.405 albertel 6835: =item * &get_users_function()
1.182 matthew 6836:
6837: Used by &bodytag to determine the current users primary role.
6838: Returns either 'student','coordinator','admin', or 'author'.
6839:
6840: =cut
6841:
6842: ###############################################
6843: sub get_users_function {
1.815 tempelho 6844: my $function = 'norole';
1.818 tempelho 6845: if ($env{'request.role'}=~/^(st)/) {
6846: $function='student';
6847: }
1.258 albertel 6848: if ($env{'request.role'}=~/^(cc|in|ta|ep)/) {
1.182 matthew 6849: $function='coordinator';
6850: }
1.258 albertel 6851: if ($env{'request.role'}=~/^(su|dc|ad|li)/) {
1.182 matthew 6852: $function='admin';
6853: }
1.826 bisitz 6854: if (($env{'request.role'}=~/^(au|ca|aa)/) ||
1.182 matthew 6855: ($ENV{'REQUEST_URI'}=~/^(\/priv|\~)/)) {
6856: $function='author';
6857: }
6858: return $function;
1.54 www 6859: }
1.99 www 6860:
6861: ###############################################
6862:
1.233 raeburn 6863: =pod
6864:
1.821 raeburn 6865: =item * &show_course()
6866:
6867: Used by lonmenu.pm and lonroles.pm to determine whether to use the word
6868: 'Courses' or 'Roles' in inline navigation and on screen displaying user's roles.
6869:
6870: Inputs:
6871: None
6872:
6873: Outputs:
6874: Scalar: 1 if 'Course' to be used, 0 otherwise.
6875:
6876: =cut
6877:
6878: ###############################################
6879: sub show_course {
6880: my $course = !$env{'user.adv'};
6881: if (!$env{'user.adv'}) {
6882: foreach my $env (keys(%env)) {
6883: next if ($env !~ m/^user\.priv\./);
6884: if ($env !~ m/^user\.priv\.(?:st|cm)/) {
6885: $course = 0;
6886: last;
6887: }
6888: }
6889: }
6890: return $course;
6891: }
6892:
6893: ###############################################
6894:
6895: =pod
6896:
1.542 raeburn 6897: =item * &check_user_status()
1.274 raeburn 6898:
6899: Determines current status of supplied role for a
6900: specific user. Roles can be active, previous or future.
6901:
6902: Inputs:
6903: user's domain, user's username, course's domain,
1.375 raeburn 6904: course's number, optional section ID.
1.274 raeburn 6905:
6906: Outputs:
6907: role status: active, previous or future.
6908:
6909: =cut
6910:
6911: sub check_user_status {
1.412 raeburn 6912: my ($udom,$uname,$cdom,$crs,$role,$sec) = @_;
1.274 raeburn 6913: my %userinfo = &Apache::lonnet::dump('roles',$udom,$uname);
6914: my @uroles = keys %userinfo;
6915: my $srchstr;
6916: my $active_chk = 'none';
1.412 raeburn 6917: my $now = time;
1.274 raeburn 6918: if (@uroles > 0) {
1.412 raeburn 6919: if (($role eq 'cc') || ($sec eq '') || (!defined($sec))) {
1.274 raeburn 6920: $srchstr = '/'.$cdom.'/'.$crs.'_'.$role;
6921: } else {
1.412 raeburn 6922: $srchstr = '/'.$cdom.'/'.$crs.'/'.$sec.'_'.$role;
6923: }
6924: if (grep/^\Q$srchstr\E$/,@uroles) {
1.274 raeburn 6925: my $role_end = 0;
6926: my $role_start = 0;
6927: $active_chk = 'active';
1.412 raeburn 6928: if ($userinfo{$srchstr} =~ m/^\Q$role\E_(\d+)/) {
6929: $role_end = $1;
6930: if ($userinfo{$srchstr} =~ m/^\Q$role\E_\Q$role_end\E_(\d+)$/) {
6931: $role_start = $1;
1.274 raeburn 6932: }
6933: }
6934: if ($role_start > 0) {
1.412 raeburn 6935: if ($now < $role_start) {
1.274 raeburn 6936: $active_chk = 'future';
6937: }
6938: }
6939: if ($role_end > 0) {
1.412 raeburn 6940: if ($now > $role_end) {
1.274 raeburn 6941: $active_chk = 'previous';
6942: }
6943: }
6944: }
6945: }
6946: return $active_chk;
6947: }
6948:
6949: ###############################################
6950:
6951: =pod
6952:
1.405 albertel 6953: =item * &get_sections()
1.233 raeburn 6954:
6955: Determines all the sections for a course including
6956: sections with students and sections containing other roles.
1.419 raeburn 6957: Incoming parameters:
6958:
6959: 1. domain
6960: 2. course number
6961: 3. reference to array containing roles for which sections should
6962: be gathered (optional).
6963: 4. reference to array containing status types for which sections
6964: should be gathered (optional).
6965:
6966: If the third argument is undefined, sections are gathered for any role.
6967: If the fourth argument is undefined, sections are gathered for any status.
6968: Permissible values are 'active' or 'future' or 'previous'.
1.233 raeburn 6969:
1.374 raeburn 6970: Returns section hash (keys are section IDs, values are
6971: number of users in each section), subject to the
1.419 raeburn 6972: optional roles filter, optional status filter
1.233 raeburn 6973:
6974: =cut
6975:
6976: ###############################################
6977: sub get_sections {
1.419 raeburn 6978: my ($cdom,$cnum,$possible_roles,$possible_status) = @_;
1.366 albertel 6979: if (!defined($cdom) || !defined($cnum)) {
6980: my $cid = $env{'request.course.id'};
6981:
6982: return if (!defined($cid));
6983:
6984: $cdom = $env{'course.'.$cid.'.domain'};
6985: $cnum = $env{'course.'.$cid.'.num'};
6986: }
6987:
6988: my %sectioncount;
1.419 raeburn 6989: my $now = time;
1.240 albertel 6990:
1.366 albertel 6991: if (!defined($possible_roles) || (grep(/^st$/,@$possible_roles))) {
1.276 albertel 6992: my ($classlist) = &Apache::loncoursedata::get_classlist($cdom,$cnum);
1.240 albertel 6993: my $sec_index = &Apache::loncoursedata::CL_SECTION();
6994: my $status_index = &Apache::loncoursedata::CL_STATUS();
1.419 raeburn 6995: my $start_index = &Apache::loncoursedata::CL_START();
6996: my $end_index = &Apache::loncoursedata::CL_END();
6997: my $status;
1.366 albertel 6998: while (my ($student,$data) = each(%$classlist)) {
1.419 raeburn 6999: my ($section,$stu_status,$start,$end) = ($data->[$sec_index],
7000: $data->[$status_index],
7001: $data->[$start_index],
7002: $data->[$end_index]);
7003: if ($stu_status eq 'Active') {
7004: $status = 'active';
7005: } elsif ($end < $now) {
7006: $status = 'previous';
7007: } elsif ($start > $now) {
7008: $status = 'future';
7009: }
7010: if ($section ne '-1' && $section !~ /^\s*$/) {
7011: if ((!defined($possible_status)) || (($status ne '') &&
7012: (grep/^\Q$status\E$/,@{$possible_status}))) {
7013: $sectioncount{$section}++;
7014: }
1.240 albertel 7015: }
7016: }
7017: }
7018: my %courseroles = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
7019: foreach my $user (sort(keys(%courseroles))) {
7020: if ($user !~ /^(\w{2})/) { next; }
7021: my ($role) = ($user =~ /^(\w{2})/);
7022: if ($possible_roles && !(grep(/^$role$/,@$possible_roles))) { next; }
1.419 raeburn 7023: my ($section,$status);
1.240 albertel 7024: if ($role eq 'cr' &&
7025: $user =~ m-^$role/[^/]*/[^/]*/[^/]*:[^:]*:[^:]*:(\w+)-) {
7026: $section=$1;
7027: }
7028: if ($user =~ /^$role:[^:]*:[^:]*:(\w+)/) { $section=$1; }
7029: if (!defined($section) || $section eq '-1') { next; }
1.419 raeburn 7030: my ($end,$start) = ($courseroles{$user} =~ /^([^:]*):([^:]*)$/);
7031: if ($end == -1 && $start == -1) {
7032: next; #deleted role
7033: }
7034: if (!defined($possible_status)) {
7035: $sectioncount{$section}++;
7036: } else {
7037: if ((!$end || $end >= $now) && (!$start || $start <= $now)) {
7038: $status = 'active';
7039: } elsif ($end < $now) {
7040: $status = 'future';
7041: } elsif ($start > $now) {
7042: $status = 'previous';
7043: }
7044: if (($status ne '') && (grep/^\Q$status\E$/,@{$possible_status})) {
7045: $sectioncount{$section}++;
7046: }
7047: }
1.233 raeburn 7048: }
1.366 albertel 7049: return %sectioncount;
1.233 raeburn 7050: }
7051:
1.274 raeburn 7052: ###############################################
1.294 raeburn 7053:
7054: =pod
1.405 albertel 7055:
7056: =item * &get_course_users()
7057:
1.275 raeburn 7058: Retrieves usernames:domains for users in the specified course
7059: with specific role(s), and access status.
7060:
7061: Incoming parameters:
1.277 albertel 7062: 1. course domain
7063: 2. course number
7064: 3. access status: users must have - either active,
1.275 raeburn 7065: previous, future, or all.
1.277 albertel 7066: 4. reference to array of permissible roles
1.288 raeburn 7067: 5. reference to array of section restrictions (optional)
7068: 6. reference to results object (hash of hashes).
7069: 7. reference to optional userdata hash
1.609 raeburn 7070: 8. reference to optional statushash
1.630 raeburn 7071: 9. flag if privileged users (except those set to unhide in
7072: course settings) should be excluded
1.609 raeburn 7073: Keys of top level results hash are roles.
1.275 raeburn 7074: Keys of inner hashes are username:domain, with
7075: values set to access type.
1.288 raeburn 7076: Optional userdata hash returns an array with arguments in the
7077: same order as loncoursedata::get_classlist() for student data.
7078:
1.609 raeburn 7079: Optional statushash returns
7080:
1.288 raeburn 7081: Entries for end, start, section and status are blank because
7082: of the possibility of multiple values for non-student roles.
7083:
1.275 raeburn 7084: =cut
1.405 albertel 7085:
1.275 raeburn 7086: ###############################################
1.405 albertel 7087:
1.275 raeburn 7088: sub get_course_users {
1.630 raeburn 7089: my ($cdom,$cnum,$types,$roles,$sections,$users,$userdata,$statushash,$hidepriv) = @_;
1.288 raeburn 7090: my %idx = ();
1.419 raeburn 7091: my %seclists;
1.288 raeburn 7092:
7093: $idx{udom} = &Apache::loncoursedata::CL_SDOM();
7094: $idx{uname} = &Apache::loncoursedata::CL_SNAME();
7095: $idx{end} = &Apache::loncoursedata::CL_END();
7096: $idx{start} = &Apache::loncoursedata::CL_START();
7097: $idx{id} = &Apache::loncoursedata::CL_ID();
7098: $idx{section} = &Apache::loncoursedata::CL_SECTION();
7099: $idx{fullname} = &Apache::loncoursedata::CL_FULLNAME();
7100: $idx{status} = &Apache::loncoursedata::CL_STATUS();
7101:
1.290 albertel 7102: if (grep(/^st$/,@{$roles})) {
1.276 albertel 7103: my ($classlist,$keylist)=&Apache::loncoursedata::get_classlist($cdom,$cnum);
1.278 raeburn 7104: my $now = time;
1.277 albertel 7105: foreach my $student (keys(%{$classlist})) {
1.288 raeburn 7106: my $match = 0;
1.412 raeburn 7107: my $secmatch = 0;
1.419 raeburn 7108: my $section = $$classlist{$student}[$idx{section}];
1.609 raeburn 7109: my $status = $$classlist{$student}[$idx{status}];
1.419 raeburn 7110: if ($section eq '') {
7111: $section = 'none';
7112: }
1.291 albertel 7113: if ((ref($sections) eq 'ARRAY') && (@{$sections} > 0)) {
1.420 albertel 7114: if (grep(/^all$/,@{$sections})) {
1.412 raeburn 7115: $secmatch = 1;
7116: } elsif ($$classlist{$student}[$idx{section}] eq '') {
1.420 albertel 7117: if (grep(/^none$/,@{$sections})) {
1.412 raeburn 7118: $secmatch = 1;
7119: }
7120: } else {
1.419 raeburn 7121: if (grep(/^\Q$section\E$/,@{$sections})) {
1.412 raeburn 7122: $secmatch = 1;
7123: }
1.290 albertel 7124: }
1.412 raeburn 7125: if (!$secmatch) {
7126: next;
7127: }
1.419 raeburn 7128: }
1.275 raeburn 7129: if (defined($$types{'active'})) {
1.288 raeburn 7130: if ($$classlist{$student}[$idx{status}] eq 'Active') {
1.275 raeburn 7131: push(@{$$users{st}{$student}},'active');
1.288 raeburn 7132: $match = 1;
1.275 raeburn 7133: }
7134: }
7135: if (defined($$types{'previous'})) {
1.609 raeburn 7136: if ($$classlist{$student}[$idx{status}] eq 'Expired') {
1.275 raeburn 7137: push(@{$$users{st}{$student}},'previous');
1.288 raeburn 7138: $match = 1;
1.275 raeburn 7139: }
7140: }
7141: if (defined($$types{'future'})) {
1.609 raeburn 7142: if ($$classlist{$student}[$idx{status}] eq 'Future') {
1.275 raeburn 7143: push(@{$$users{st}{$student}},'future');
1.288 raeburn 7144: $match = 1;
1.275 raeburn 7145: }
7146: }
1.609 raeburn 7147: if ($match) {
7148: push(@{$seclists{$student}},$section);
7149: if (ref($userdata) eq 'HASH') {
7150: $$userdata{$student} = $$classlist{$student};
7151: }
7152: if (ref($statushash) eq 'HASH') {
7153: $statushash->{$student}{'st'}{$section} = $status;
7154: }
1.288 raeburn 7155: }
1.275 raeburn 7156: }
7157: }
1.412 raeburn 7158: if ((@{$roles} > 1) || ((@{$roles} == 1) && ($$roles[0] ne "st"))) {
1.439 raeburn 7159: my %coursepersonnel = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
7160: my $now = time;
1.609 raeburn 7161: my %displaystatus = ( previous => 'Expired',
7162: active => 'Active',
7163: future => 'Future',
7164: );
1.630 raeburn 7165: my %nothide;
7166: if ($hidepriv) {
7167: my %coursehash=&Apache::lonnet::coursedescription($cdom.'_'.$cnum);
7168: foreach my $user (split(/\s*\,\s*/,$coursehash{'nothideprivileged'})) {
7169: if ($user !~ /:/) {
7170: $nothide{join(':',split(/[\@]/,$user))}=1;
7171: } else {
7172: $nothide{$user} = 1;
7173: }
7174: }
7175: }
1.439 raeburn 7176: foreach my $person (sort(keys(%coursepersonnel))) {
1.288 raeburn 7177: my $match = 0;
1.412 raeburn 7178: my $secmatch = 0;
1.439 raeburn 7179: my $status;
1.412 raeburn 7180: my ($role,$user,$usec) = ($person =~ /^([^:]*):([^:]+:[^:]+):([^:]*)/);
1.275 raeburn 7181: $user =~ s/:$//;
1.439 raeburn 7182: my ($end,$start) = split(/:/,$coursepersonnel{$person});
7183: if ($end == -1 || $start == -1) {
7184: next;
7185: }
7186: if (($role) && ((grep(/^\Q$role\E$/,@{$roles})) ||
7187: (grep(/^cr$/,@{$roles}) && $role =~ /^cr\//))) {
1.412 raeburn 7188: my ($uname,$udom) = split(/:/,$user);
7189: if ((ref($sections) eq 'ARRAY') && (@{$sections} > 0)) {
1.420 albertel 7190: if (grep(/^all$/,@{$sections})) {
1.412 raeburn 7191: $secmatch = 1;
7192: } elsif ($usec eq '') {
1.420 albertel 7193: if (grep(/^none$/,@{$sections})) {
1.412 raeburn 7194: $secmatch = 1;
7195: }
7196: } else {
7197: if (grep(/^\Q$usec\E$/,@{$sections})) {
7198: $secmatch = 1;
7199: }
7200: }
7201: if (!$secmatch) {
7202: next;
7203: }
1.288 raeburn 7204: }
1.419 raeburn 7205: if ($usec eq '') {
7206: $usec = 'none';
7207: }
1.275 raeburn 7208: if ($uname ne '' && $udom ne '') {
1.630 raeburn 7209: if ($hidepriv) {
7210: if ((&Apache::lonnet::privileged($uname,$udom)) &&
7211: (!$nothide{$uname.':'.$udom})) {
7212: next;
7213: }
7214: }
1.503 raeburn 7215: if ($end > 0 && $end < $now) {
1.439 raeburn 7216: $status = 'previous';
7217: } elsif ($start > $now) {
7218: $status = 'future';
7219: } else {
7220: $status = 'active';
7221: }
1.277 albertel 7222: foreach my $type (keys(%{$types})) {
1.275 raeburn 7223: if ($status eq $type) {
1.420 albertel 7224: if (!grep(/^\Q$type\E$/,@{$$users{$role}{$user}})) {
1.419 raeburn 7225: push(@{$$users{$role}{$user}},$type);
7226: }
1.288 raeburn 7227: $match = 1;
7228: }
7229: }
1.419 raeburn 7230: if (($match) && (ref($userdata) eq 'HASH')) {
7231: if (!exists($$userdata{$uname.':'.$udom})) {
7232: &get_user_info($udom,$uname,\%idx,$userdata);
7233: }
1.420 albertel 7234: if (!grep(/^\Q$usec\E$/,@{$seclists{$uname.':'.$udom}})) {
1.419 raeburn 7235: push(@{$seclists{$uname.':'.$udom}},$usec);
7236: }
1.609 raeburn 7237: if (ref($statushash) eq 'HASH') {
7238: $statushash->{$uname.':'.$udom}{$role}{$usec} = $displaystatus{$status};
7239: }
1.275 raeburn 7240: }
7241: }
7242: }
7243: }
1.290 albertel 7244: if (grep(/^ow$/,@{$roles})) {
1.279 raeburn 7245: if ((defined($cdom)) && (defined($cnum))) {
7246: my %csettings = &Apache::lonnet::get('environment',['internal.courseowner'],$cdom,$cnum);
7247: if ( defined($csettings{'internal.courseowner'}) ) {
7248: my $owner = $csettings{'internal.courseowner'};
1.609 raeburn 7249: next if ($owner eq '');
7250: my ($ownername,$ownerdom);
7251: if ($owner =~ /^([^:]+):([^:]+)$/) {
7252: $ownername = $1;
7253: $ownerdom = $2;
7254: } else {
7255: $ownername = $owner;
7256: $ownerdom = $cdom;
7257: $owner = $ownername.':'.$ownerdom;
1.439 raeburn 7258: }
7259: @{$$users{'ow'}{$owner}} = 'any';
1.290 albertel 7260: if (defined($userdata) &&
1.609 raeburn 7261: !exists($$userdata{$owner})) {
7262: &get_user_info($ownerdom,$ownername,\%idx,$userdata);
7263: if (!grep(/^none$/,@{$seclists{$owner}})) {
7264: push(@{$seclists{$owner}},'none');
7265: }
7266: if (ref($statushash) eq 'HASH') {
7267: $statushash->{$owner}{'ow'}{'none'} = 'Any';
1.419 raeburn 7268: }
1.290 albertel 7269: }
1.279 raeburn 7270: }
7271: }
7272: }
1.419 raeburn 7273: foreach my $user (keys(%seclists)) {
7274: @{$seclists{$user}} = (sort {$a <=> $b} @{$seclists{$user}});
7275: $$userdata{$user}[$idx{section}] = join(',',@{$seclists{$user}});
7276: }
1.275 raeburn 7277: }
7278: return;
7279: }
7280:
1.288 raeburn 7281: sub get_user_info {
7282: my ($udom,$uname,$idx,$userdata) = @_;
1.289 albertel 7283: $$userdata{$uname.':'.$udom}[$$idx{fullname}] =
7284: &plainname($uname,$udom,'lastname');
1.291 albertel 7285: $$userdata{$uname.':'.$udom}[$$idx{uname}] = $uname;
1.297 raeburn 7286: $$userdata{$uname.':'.$udom}[$$idx{udom}] = $udom;
1.609 raeburn 7287: my %idhash = &Apache::lonnet::idrget($udom,($uname));
7288: $$userdata{$uname.':'.$udom}[$$idx{id}] = $idhash{$uname};
1.288 raeburn 7289: return;
7290: }
1.275 raeburn 7291:
1.472 raeburn 7292: ###############################################
7293:
7294: =pod
7295:
7296: =item * &get_user_quota()
7297:
7298: Retrieves quota assigned for storage of portfolio files for a user
7299:
7300: Incoming parameters:
7301: 1. user's username
7302: 2. user's domain
7303:
7304: Returns:
1.536 raeburn 7305: 1. Disk quota (in Mb) assigned to student.
7306: 2. (Optional) Type of setting: custom or default
7307: (individually assigned or default for user's
7308: institutional status).
7309: 3. (Optional) - User's institutional status (e.g., faculty, staff
7310: or student - types as defined in localenroll::inst_usertypes
7311: for user's domain, which determines default quota for user.
7312: 4. (Optional) - Default quota which would apply to the user.
1.472 raeburn 7313:
7314: If a value has been stored in the user's environment,
1.536 raeburn 7315: it will return that, otherwise it returns the maximal default
7316: defined for the user's instituional status(es) in the domain.
1.472 raeburn 7317:
7318: =cut
7319:
7320: ###############################################
7321:
7322:
7323: sub get_user_quota {
7324: my ($uname,$udom) = @_;
1.536 raeburn 7325: my ($quota,$quotatype,$settingstatus,$defquota);
1.472 raeburn 7326: if (!defined($udom)) {
7327: $udom = $env{'user.domain'};
7328: }
7329: if (!defined($uname)) {
7330: $uname = $env{'user.name'};
7331: }
7332: if (($udom eq '' || $uname eq '') ||
7333: ($udom eq 'public') && ($uname eq 'public')) {
7334: $quota = 0;
1.536 raeburn 7335: $quotatype = 'default';
7336: $defquota = 0;
1.472 raeburn 7337: } else {
1.536 raeburn 7338: my $inststatus;
1.472 raeburn 7339: if ($udom eq $env{'user.domain'} && $uname eq $env{'user.name'}) {
7340: $quota = $env{'environment.portfolioquota'};
1.536 raeburn 7341: $inststatus = $env{'environment.inststatus'};
1.472 raeburn 7342: } else {
1.536 raeburn 7343: my %userenv =
7344: &Apache::lonnet::get('environment',['portfolioquota',
7345: 'inststatus'],$udom,$uname);
1.472 raeburn 7346: my ($tmp) = keys(%userenv);
7347: if ($tmp !~ /^(con_lost|error|no_such_host)/i) {
7348: $quota = $userenv{'portfolioquota'};
1.536 raeburn 7349: $inststatus = $userenv{'inststatus'};
1.472 raeburn 7350: } else {
7351: undef(%userenv);
7352: }
7353: }
1.536 raeburn 7354: ($defquota,$settingstatus) = &default_quota($udom,$inststatus);
1.472 raeburn 7355: if ($quota eq '') {
1.536 raeburn 7356: $quota = $defquota;
7357: $quotatype = 'default';
7358: } else {
7359: $quotatype = 'custom';
1.472 raeburn 7360: }
7361: }
1.536 raeburn 7362: if (wantarray) {
7363: return ($quota,$quotatype,$settingstatus,$defquota);
7364: } else {
7365: return $quota;
7366: }
1.472 raeburn 7367: }
7368:
7369: ###############################################
7370:
7371: =pod
7372:
7373: =item * &default_quota()
7374:
1.536 raeburn 7375: Retrieves default quota assigned for storage of user portfolio files,
7376: given an (optional) user's institutional status.
1.472 raeburn 7377:
7378: Incoming parameters:
7379: 1. domain
1.536 raeburn 7380: 2. (Optional) institutional status(es). This is a : separated list of
7381: status types (e.g., faculty, staff, student etc.)
7382: which apply to the user for whom the default is being retrieved.
7383: If the institutional status string in undefined, the domain
7384: default quota will be returned.
1.472 raeburn 7385:
7386: Returns:
7387: 1. Default disk quota (in Mb) for user portfolios in the domain.
1.536 raeburn 7388: 2. (Optional) institutional type which determined the value of the
7389: default quota.
1.472 raeburn 7390:
7391: If a value has been stored in the domain's configuration db,
7392: it will return that, otherwise it returns 20 (for backwards
7393: compatibility with domains which have not set up a configuration
7394: db file; the original statically defined portfolio quota was 20 Mb).
7395:
1.536 raeburn 7396: If the user's status includes multiple types (e.g., staff and student),
7397: the largest default quota which applies to the user determines the
7398: default quota returned.
7399:
1.780 raeburn 7400: =back
7401:
1.472 raeburn 7402: =cut
7403:
7404: ###############################################
7405:
7406:
7407: sub default_quota {
1.536 raeburn 7408: my ($udom,$inststatus) = @_;
7409: my ($defquota,$settingstatus);
7410: my %quotahash = &Apache::lonnet::get_dom('configuration',
1.622 raeburn 7411: ['quotas'],$udom);
7412: if (ref($quotahash{'quotas'}) eq 'HASH') {
1.536 raeburn 7413: if ($inststatus ne '') {
1.765 raeburn 7414: my @statuses = map { &unescape($_); } split(/:/,$inststatus);
1.536 raeburn 7415: foreach my $item (@statuses) {
1.711 raeburn 7416: if (ref($quotahash{'quotas'}{'defaultquota'}) eq 'HASH') {
7417: if ($quotahash{'quotas'}{'defaultquota'}{$item} ne '') {
7418: if ($defquota eq '') {
7419: $defquota = $quotahash{'quotas'}{'defaultquota'}{$item};
7420: $settingstatus = $item;
7421: } elsif ($quotahash{'quotas'}{'defaultquota'}{$item} > $defquota) {
7422: $defquota = $quotahash{'quotas'}{'defaultquota'}{$item};
7423: $settingstatus = $item;
7424: }
7425: }
7426: } else {
7427: if ($quotahash{'quotas'}{$item} ne '') {
7428: if ($defquota eq '') {
7429: $defquota = $quotahash{'quotas'}{$item};
7430: $settingstatus = $item;
7431: } elsif ($quotahash{'quotas'}{$item} > $defquota) {
7432: $defquota = $quotahash{'quotas'}{$item};
7433: $settingstatus = $item;
7434: }
1.536 raeburn 7435: }
7436: }
7437: }
7438: }
7439: if ($defquota eq '') {
1.711 raeburn 7440: if (ref($quotahash{'quotas'}{'defaultquota'}) eq 'HASH') {
7441: $defquota = $quotahash{'quotas'}{'defaultquota'}{'default'};
7442: } else {
7443: $defquota = $quotahash{'quotas'}{'default'};
7444: }
1.536 raeburn 7445: $settingstatus = 'default';
7446: }
7447: } else {
7448: $settingstatus = 'default';
7449: $defquota = 20;
7450: }
7451: if (wantarray) {
7452: return ($defquota,$settingstatus);
1.472 raeburn 7453: } else {
1.536 raeburn 7454: return $defquota;
1.472 raeburn 7455: }
7456: }
7457:
1.384 raeburn 7458: sub get_secgrprole_info {
7459: my ($cdom,$cnum,$needroles,$type) = @_;
7460: my %sections_count = &get_sections($cdom,$cnum);
7461: my @sections = (sort {$a <=> $b} keys(%sections_count));
7462: my %curr_groups = &Apache::longroup::coursegroups($cdom,$cnum);
7463: my @groups = sort(keys(%curr_groups));
7464: my $allroles = [];
7465: my $rolehash;
7466: my $accesshash = {
7467: active => 'Currently has access',
7468: future => 'Will have future access',
7469: previous => 'Previously had access',
7470: };
7471: if ($needroles) {
7472: $rolehash = {'all' => 'all'};
1.385 albertel 7473: my %user_roles = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
7474: if (&Apache::lonnet::error(%user_roles)) {
7475: undef(%user_roles);
7476: }
7477: foreach my $item (keys(%user_roles)) {
1.384 raeburn 7478: my ($role)=split(/\:/,$item,2);
7479: if ($role eq 'cr') { next; }
7480: if ($role =~ /^cr/) {
7481: $$rolehash{$role} = (split('/',$role))[3];
7482: } else {
7483: $$rolehash{$role} = &Apache::lonnet::plaintext($role,$type);
7484: }
7485: }
7486: foreach my $key (sort(keys(%{$rolehash}))) {
7487: push(@{$allroles},$key);
7488: }
7489: push (@{$allroles},'st');
7490: $$rolehash{'st'} = &Apache::lonnet::plaintext('st',$type);
7491: }
7492: return (\@sections,\@groups,$allroles,$rolehash,$accesshash);
7493: }
7494:
1.555 raeburn 7495: sub user_picker {
1.627 raeburn 7496: my ($dom,$srch,$forcenewuser,$caller,$cancreate,$usertype) = @_;
1.555 raeburn 7497: my $currdom = $dom;
7498: my %curr_selected = (
7499: srchin => 'dom',
1.580 raeburn 7500: srchby => 'lastname',
1.555 raeburn 7501: );
7502: my $srchterm;
1.625 raeburn 7503: if ((ref($srch) eq 'HASH') && ($env{'form.origform'} ne 'crtusername')) {
1.555 raeburn 7504: if ($srch->{'srchby'} ne '') {
7505: $curr_selected{'srchby'} = $srch->{'srchby'};
7506: }
7507: if ($srch->{'srchin'} ne '') {
7508: $curr_selected{'srchin'} = $srch->{'srchin'};
7509: }
7510: if ($srch->{'srchtype'} ne '') {
7511: $curr_selected{'srchtype'} = $srch->{'srchtype'};
7512: }
7513: if ($srch->{'srchdomain'} ne '') {
7514: $currdom = $srch->{'srchdomain'};
7515: }
7516: $srchterm = $srch->{'srchterm'};
7517: }
7518: my %lt=&Apache::lonlocal::texthash(
1.573 raeburn 7519: 'usr' => 'Search criteria',
1.563 raeburn 7520: 'doma' => 'Domain/institution to search',
1.558 albertel 7521: 'uname' => 'username',
7522: 'lastname' => 'last name',
1.555 raeburn 7523: 'lastfirst' => 'last name, first name',
1.558 albertel 7524: 'crs' => 'in this course',
1.576 raeburn 7525: 'dom' => 'in selected LON-CAPA domain',
1.558 albertel 7526: 'alc' => 'all LON-CAPA',
1.573 raeburn 7527: 'instd' => 'in institutional directory for selected domain',
1.558 albertel 7528: 'exact' => 'is',
7529: 'contains' => 'contains',
1.569 raeburn 7530: 'begins' => 'begins with',
1.571 raeburn 7531: 'youm' => "You must include some text to search for.",
7532: 'thte' => "The text you are searching for must contain at least two characters when using a 'begins' type search.",
7533: 'thet' => "The text you are searching for must contain at least three characters when using a 'contains' type search.",
7534: 'yomc' => "You must choose a domain when using an institutional directory search.",
7535: 'ymcd' => "You must choose a domain when using a domain search.",
7536: 'whus' => "When using searching by last,first you must include a comma as separator between last name and first name.",
7537: 'whse' => "When searching by last,first you must include at least one character in the first name.",
7538: 'thfo' => "The following need to be corrected before the search can be run:",
1.555 raeburn 7539: );
1.563 raeburn 7540: my $domform = &select_dom_form($currdom,'srchdomain',1,1);
7541: my $srchinsel = ' <select name="srchin">';
1.555 raeburn 7542:
7543: my @srchins = ('crs','dom','alc','instd');
7544:
7545: foreach my $option (@srchins) {
7546: # FIXME 'alc' option unavailable until
7547: # loncreateuser::print_user_query_page()
7548: # has been completed.
7549: next if ($option eq 'alc');
1.880 raeburn 7550: next if (($option eq 'crs') && ($env{'form.form'} eq 'requestcrs'));
1.555 raeburn 7551: next if ($option eq 'crs' && !$env{'request.course.id'});
1.563 raeburn 7552: if ($curr_selected{'srchin'} eq $option) {
7553: $srchinsel .= '
7554: <option value="'.$option.'" selected="selected">'.$lt{$option}.'</option>';
7555: } else {
7556: $srchinsel .= '
7557: <option value="'.$option.'">'.$lt{$option}.'</option>';
7558: }
1.555 raeburn 7559: }
1.563 raeburn 7560: $srchinsel .= "\n </select>\n";
1.555 raeburn 7561:
7562: my $srchbysel = ' <select name="srchby">';
1.580 raeburn 7563: foreach my $option ('lastname','lastfirst','uname') {
1.555 raeburn 7564: if ($curr_selected{'srchby'} eq $option) {
7565: $srchbysel .= '
7566: <option value="'.$option.'" selected="selected">'.$lt{$option}.'</option>';
7567: } else {
7568: $srchbysel .= '
7569: <option value="'.$option.'">'.$lt{$option}.'</option>';
7570: }
7571: }
7572: $srchbysel .= "\n </select>\n";
7573:
7574: my $srchtypesel = ' <select name="srchtype">';
1.580 raeburn 7575: foreach my $option ('begins','contains','exact') {
1.555 raeburn 7576: if ($curr_selected{'srchtype'} eq $option) {
7577: $srchtypesel .= '
7578: <option value="'.$option.'" selected="selected">'.$lt{$option}.'</option>';
7579: } else {
7580: $srchtypesel .= '
7581: <option value="'.$option.'">'.$lt{$option}.'</option>';
7582: }
7583: }
7584: $srchtypesel .= "\n </select>\n";
7585:
1.558 albertel 7586: my ($newuserscript,$new_user_create);
1.556 raeburn 7587:
7588: if ($forcenewuser) {
1.576 raeburn 7589: if (ref($srch) eq 'HASH') {
7590: if ($srch->{'srchby'} eq 'uname' && $srch->{'srchtype'} eq 'exact' && $srch->{'srchin'} eq 'dom' && $srch->{'srchdomain'} eq $env{'request.role.domain'}) {
1.627 raeburn 7591: if ($cancreate) {
7592: $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>';
7593: } else {
1.799 bisitz 7594: my $helplink = 'javascript:helpMenu('."'display'".')';
1.627 raeburn 7595: my %usertypetext = (
7596: official => 'institutional',
7597: unofficial => 'non-institutional',
7598: );
1.799 bisitz 7599: $new_user_create = '<p class="LC_warning">'
7600: .&mt("You are not authorized to create new $usertypetext{$usertype} users in this domain.")
7601: .' '
7602: .&mt('Please contact the [_1]helpdesk[_2] for assistance.'
7603: ,'<a href="'.$helplink.'">','</a>')
7604: .'</p><br />';
1.627 raeburn 7605: }
1.576 raeburn 7606: }
7607: }
7608:
1.556 raeburn 7609: $newuserscript = <<"ENDSCRIPT";
7610:
1.570 raeburn 7611: function setSearch(createnew,callingForm) {
1.556 raeburn 7612: if (createnew == 1) {
1.570 raeburn 7613: for (var i=0; i<callingForm.srchby.length; i++) {
7614: if (callingForm.srchby.options[i].value == 'uname') {
7615: callingForm.srchby.selectedIndex = i;
1.556 raeburn 7616: }
7617: }
1.570 raeburn 7618: for (var i=0; i<callingForm.srchin.length; i++) {
7619: if ( callingForm.srchin.options[i].value == 'dom') {
7620: callingForm.srchin.selectedIndex = i;
1.556 raeburn 7621: }
7622: }
1.570 raeburn 7623: for (var i=0; i<callingForm.srchtype.length; i++) {
7624: if (callingForm.srchtype.options[i].value == 'exact') {
7625: callingForm.srchtype.selectedIndex = i;
1.556 raeburn 7626: }
7627: }
1.570 raeburn 7628: for (var i=0; i<callingForm.srchdomain.length; i++) {
7629: if (callingForm.srchdomain.options[i].value == '$env{'request.role.domain'}') {
7630: callingForm.srchdomain.selectedIndex = i;
1.556 raeburn 7631: }
7632: }
7633: }
7634: }
7635: ENDSCRIPT
1.558 albertel 7636:
1.556 raeburn 7637: }
7638:
1.555 raeburn 7639: my $output = <<"END_BLOCK";
1.556 raeburn 7640: <script type="text/javascript">
1.824 bisitz 7641: // <![CDATA[
1.570 raeburn 7642: function validateEntry(callingForm) {
1.558 albertel 7643:
1.556 raeburn 7644: var checkok = 1;
1.558 albertel 7645: var srchin;
1.570 raeburn 7646: for (var i=0; i<callingForm.srchin.length; i++) {
7647: if ( callingForm.srchin[i].checked ) {
7648: srchin = callingForm.srchin[i].value;
1.558 albertel 7649: }
7650: }
7651:
1.570 raeburn 7652: var srchtype = callingForm.srchtype.options[callingForm.srchtype.selectedIndex].value;
7653: var srchby = callingForm.srchby.options[callingForm.srchby.selectedIndex].value;
7654: var srchdomain = callingForm.srchdomain.options[callingForm.srchdomain.selectedIndex].value;
7655: var srchterm = callingForm.srchterm.value;
7656: var srchin = callingForm.srchin.options[callingForm.srchin.selectedIndex].value;
1.556 raeburn 7657: var msg = "";
7658:
7659: if (srchterm == "") {
7660: checkok = 0;
1.571 raeburn 7661: msg += "$lt{'youm'}\\n";
1.556 raeburn 7662: }
7663:
1.569 raeburn 7664: if (srchtype== 'begins') {
7665: if (srchterm.length < 2) {
7666: checkok = 0;
1.571 raeburn 7667: msg += "$lt{'thte'}\\n";
1.569 raeburn 7668: }
7669: }
7670:
1.556 raeburn 7671: if (srchtype== 'contains') {
7672: if (srchterm.length < 3) {
7673: checkok = 0;
1.571 raeburn 7674: msg += "$lt{'thet'}\\n";
1.556 raeburn 7675: }
7676: }
7677: if (srchin == 'instd') {
7678: if (srchdomain == '') {
7679: checkok = 0;
1.571 raeburn 7680: msg += "$lt{'yomc'}\\n";
1.556 raeburn 7681: }
7682: }
7683: if (srchin == 'dom') {
7684: if (srchdomain == '') {
7685: checkok = 0;
1.571 raeburn 7686: msg += "$lt{'ymcd'}\\n";
1.556 raeburn 7687: }
7688: }
7689: if (srchby == 'lastfirst') {
7690: if (srchterm.indexOf(",") == -1) {
7691: checkok = 0;
1.571 raeburn 7692: msg += "$lt{'whus'}\\n";
1.556 raeburn 7693: }
7694: if (srchterm.indexOf(",") == srchterm.length -1) {
7695: checkok = 0;
1.571 raeburn 7696: msg += "$lt{'whse'}\\n";
1.556 raeburn 7697: }
7698: }
7699: if (checkok == 0) {
1.571 raeburn 7700: alert("$lt{'thfo'}\\n"+msg);
1.556 raeburn 7701: return;
7702: }
7703: if (checkok == 1) {
1.570 raeburn 7704: callingForm.submit();
1.556 raeburn 7705: }
7706: }
7707:
7708: $newuserscript
7709:
1.824 bisitz 7710: // ]]>
1.556 raeburn 7711: </script>
1.558 albertel 7712:
7713: $new_user_create
7714:
1.555 raeburn 7715: END_BLOCK
1.558 albertel 7716:
1.876 raeburn 7717: $output .= &Apache::lonhtmlcommon::start_pick_box().
7718: &Apache::lonhtmlcommon::row_title($lt{'doma'}).
7719: $domform.
7720: &Apache::lonhtmlcommon::row_closure().
7721: &Apache::lonhtmlcommon::row_title($lt{'usr'}).
7722: $srchbysel.
7723: $srchtypesel.
7724: '<input type="text" size="15" name="srchterm" value="'.$srchterm.'" />'.
7725: $srchinsel.
7726: &Apache::lonhtmlcommon::row_closure(1).
7727: &Apache::lonhtmlcommon::end_pick_box().
7728: '<br />';
1.555 raeburn 7729: return $output;
7730: }
7731:
1.612 raeburn 7732: sub user_rule_check {
1.615 raeburn 7733: my ($usershash,$checks,$alerts,$rulematch,$inst_results,$curr_rules,$got_rules) = @_;
1.612 raeburn 7734: my $response;
7735: if (ref($usershash) eq 'HASH') {
7736: foreach my $user (keys(%{$usershash})) {
7737: my ($uname,$udom) = split(/:/,$user);
7738: next if ($udom eq '' || $uname eq '');
1.615 raeburn 7739: my ($id,$newuser);
1.612 raeburn 7740: if (ref($usershash->{$user}) eq 'HASH') {
1.615 raeburn 7741: $newuser = $usershash->{$user}->{'newuser'};
1.612 raeburn 7742: $id = $usershash->{$user}->{'id'};
7743: }
7744: my $inst_response;
7745: if (ref($checks) eq 'HASH') {
7746: if (defined($checks->{'username'})) {
1.615 raeburn 7747: ($inst_response,%{$inst_results->{$user}}) =
1.612 raeburn 7748: &Apache::lonnet::get_instuser($udom,$uname);
7749: } elsif (defined($checks->{'id'})) {
1.615 raeburn 7750: ($inst_response,%{$inst_results->{$user}}) =
1.612 raeburn 7751: &Apache::lonnet::get_instuser($udom,undef,$id);
7752: }
1.615 raeburn 7753: } else {
7754: ($inst_response,%{$inst_results->{$user}}) =
7755: &Apache::lonnet::get_instuser($udom,$uname);
7756: return;
1.612 raeburn 7757: }
1.615 raeburn 7758: if (!$got_rules->{$udom}) {
1.612 raeburn 7759: my %domconfig = &Apache::lonnet::get_dom('configuration',
7760: ['usercreation'],$udom);
7761: if (ref($domconfig{'usercreation'}) eq 'HASH') {
1.615 raeburn 7762: foreach my $item ('username','id') {
1.612 raeburn 7763: if (ref($domconfig{'usercreation'}{$item.'_rule'}) eq 'ARRAY') {
7764: $$curr_rules{$udom}{$item} =
7765: $domconfig{'usercreation'}{$item.'_rule'};
1.585 raeburn 7766: }
7767: }
7768: }
1.615 raeburn 7769: $got_rules->{$udom} = 1;
1.585 raeburn 7770: }
1.612 raeburn 7771: foreach my $item (keys(%{$checks})) {
7772: if (ref($$curr_rules{$udom}) eq 'HASH') {
7773: if (ref($$curr_rules{$udom}{$item}) eq 'ARRAY') {
7774: if (@{$$curr_rules{$udom}{$item}} > 0) {
7775: my %rule_check = &Apache::lonnet::inst_rulecheck($udom,$uname,$id,$item,$$curr_rules{$udom}{$item});
7776: foreach my $rule (@{$$curr_rules{$udom}{$item}}) {
7777: if ($rule_check{$rule}) {
7778: $$rulematch{$user}{$item} = $rule;
7779: if ($inst_response eq 'ok') {
1.615 raeburn 7780: if (ref($inst_results) eq 'HASH') {
7781: if (ref($inst_results->{$user}) eq 'HASH') {
7782: if (keys(%{$inst_results->{$user}}) == 0) {
7783: $$alerts{$item}{$udom}{$uname} = 1;
7784: }
1.612 raeburn 7785: }
7786: }
1.615 raeburn 7787: }
7788: last;
1.585 raeburn 7789: }
7790: }
7791: }
7792: }
7793: }
7794: }
7795: }
7796: }
1.612 raeburn 7797: return;
7798: }
7799:
7800: sub user_rule_formats {
7801: my ($domain,$domdesc,$curr_rules,$check) = @_;
7802: my %text = (
7803: 'username' => 'Usernames',
7804: 'id' => 'IDs',
7805: );
7806: my $output;
7807: my ($rules,$ruleorder) = &Apache::lonnet::inst_userrules($domain,$check);
7808: if ((ref($rules) eq 'HASH') && (ref($ruleorder) eq 'ARRAY')) {
7809: if (@{$ruleorder} > 0) {
7810: $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>';
7811: foreach my $rule (@{$ruleorder}) {
7812: if (ref($curr_rules) eq 'ARRAY') {
7813: if (grep(/^\Q$rule\E$/,@{$curr_rules})) {
7814: if (ref($rules->{$rule}) eq 'HASH') {
7815: $output .= '<li>'.$rules->{$rule}{'name'}.': '.
7816: $rules->{$rule}{'desc'}.'</li>';
7817: }
7818: }
7819: }
7820: }
7821: $output .= '</ul>';
7822: }
7823: }
7824: return $output;
7825: }
7826:
7827: sub instrule_disallow_msg {
1.615 raeburn 7828: my ($checkitem,$domdesc,$count,$mode) = @_;
1.612 raeburn 7829: my $response;
7830: my %text = (
7831: item => 'username',
7832: items => 'usernames',
7833: match => 'matches',
7834: do => 'does',
7835: action => 'a username',
7836: one => 'one',
7837: );
7838: if ($count > 1) {
7839: $text{'item'} = 'usernames';
7840: $text{'match'} ='match';
7841: $text{'do'} = 'do';
7842: $text{'action'} = 'usernames',
7843: $text{'one'} = 'ones';
7844: }
7845: if ($checkitem eq 'id') {
7846: $text{'items'} = 'IDs';
7847: $text{'item'} = 'ID';
7848: $text{'action'} = 'an ID';
1.615 raeburn 7849: if ($count > 1) {
7850: $text{'item'} = 'IDs';
7851: $text{'action'} = 'IDs';
7852: }
1.612 raeburn 7853: }
1.674 bisitz 7854: $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 7855: if ($mode eq 'upload') {
7856: if ($checkitem eq 'username') {
7857: $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'}.");
7858: } elsif ($checkitem eq 'id') {
1.674 bisitz 7859: $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 7860: }
1.669 raeburn 7861: } elsif ($mode eq 'selfcreate') {
7862: if ($checkitem eq 'id') {
7863: $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.");
7864: }
1.615 raeburn 7865: } else {
7866: if ($checkitem eq 'username') {
7867: $response .= &mt("You must choose $text{'action'} with a different format -- $text{'one'} that will not conflict with 'official' institutional $text{'items'}.");
7868: } elsif ($checkitem eq 'id') {
7869: $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.");
7870: }
1.612 raeburn 7871: }
7872: return $response;
1.585 raeburn 7873: }
7874:
1.624 raeburn 7875: sub personal_data_fieldtitles {
7876: my %fieldtitles = &Apache::lonlocal::texthash (
7877: id => 'Student/Employee ID',
7878: permanentemail => 'E-mail address',
7879: lastname => 'Last Name',
7880: firstname => 'First Name',
7881: middlename => 'Middle Name',
7882: generation => 'Generation',
7883: gen => 'Generation',
1.765 raeburn 7884: inststatus => 'Affiliation',
1.624 raeburn 7885: );
7886: return %fieldtitles;
7887: }
7888:
1.642 raeburn 7889: sub sorted_inst_types {
7890: my ($dom) = @_;
7891: my ($usertypes,$order) = &Apache::lonnet::retrieve_inst_usertypes($dom);
7892: my $othertitle = &mt('All users');
7893: if ($env{'request.course.id'}) {
1.668 raeburn 7894: $othertitle = &mt('Any users');
1.642 raeburn 7895: }
7896: my @types;
7897: if (ref($order) eq 'ARRAY') {
7898: @types = @{$order};
7899: }
7900: if (@types == 0) {
7901: if (ref($usertypes) eq 'HASH') {
7902: @types = sort(keys(%{$usertypes}));
7903: }
7904: }
7905: if (keys(%{$usertypes}) > 0) {
7906: $othertitle = &mt('Other users');
7907: }
7908: return ($othertitle,$usertypes,\@types);
7909: }
7910:
1.645 raeburn 7911: sub get_institutional_codes {
7912: my ($settings,$allcourses,$LC_code) = @_;
7913: # Get complete list of course sections to update
7914: my @currsections = ();
7915: my @currxlists = ();
7916: my $coursecode = $$settings{'internal.coursecode'};
7917:
7918: if ($$settings{'internal.sectionnums'} ne '') {
7919: @currsections = split(/,/,$$settings{'internal.sectionnums'});
7920: }
7921:
7922: if ($$settings{'internal.crosslistings'} ne '') {
7923: @currxlists = split(/,/,$$settings{'internal.crosslistings'});
7924: }
7925:
7926: if (@currxlists > 0) {
7927: foreach (@currxlists) {
7928: if (m/^([^:]+):(\w*)$/) {
7929: unless (grep/^$1$/,@{$allcourses}) {
7930: push @{$allcourses},$1;
7931: $$LC_code{$1} = $2;
7932: }
7933: }
7934: }
7935: }
7936:
7937: if (@currsections > 0) {
7938: foreach (@currsections) {
7939: if (m/^(\w+):(\w*)$/) {
7940: my $sec = $coursecode.$1;
7941: my $lc_sec = $2;
7942: unless (grep/^$sec$/,@{$allcourses}) {
7943: push @{$allcourses},$sec;
7944: $$LC_code{$sec} = $lc_sec;
7945: }
7946: }
7947: }
7948: }
7949: return;
7950: }
7951:
1.112 bowersj2 7952: =pod
7953:
1.780 raeburn 7954: =head1 Slot Helpers
7955:
7956: =over 4
7957:
7958: =item * sorted_slots()
7959:
7960: Sorts an array of slot names in order of slot start time (earliest first).
7961:
7962: Inputs:
7963:
7964: =over 4
7965:
7966: slotsarr - Reference to array of unsorted slot names.
7967:
7968: slots - Reference to hash of hash, where outer hash keys are slot names.
7969:
1.549 albertel 7970: =back
7971:
1.780 raeburn 7972: Returns:
7973:
7974: =over 4
7975:
7976: sorted - An array of slot names sorted by the start time of the slot.
7977:
7978: =back
7979:
7980: =back
7981:
7982: =cut
7983:
7984:
7985: sub sorted_slots {
7986: my ($slotsarr,$slots) = @_;
7987: my @sorted;
7988: if ((ref($slotsarr) eq 'ARRAY') && (ref($slots) eq 'HASH')) {
7989: @sorted =
7990: sort {
7991: if (ref($slots->{$a}) && ref($slots->{$b})) {
7992: return $slots->{$a}{'starttime'} <=> $slots->{$b}{'starttime'}
7993: }
7994: if (ref($slots->{$a})) { return -1;}
7995: if (ref($slots->{$b})) { return 1;}
7996: return 0;
7997: } @{$slotsarr};
7998: }
7999: return @sorted;
8000: }
8001:
8002:
8003: =pod
8004:
1.549 albertel 8005: =head1 HTTP Helpers
8006:
8007: =over 4
8008:
1.648 raeburn 8009: =item * &get_unprocessed_cgi($query,$possible_names)
1.112 bowersj2 8010:
1.258 albertel 8011: Modify the %env hash to contain unprocessed CGI form parameters held in
1.112 bowersj2 8012: $query. The parameters listed in $possible_names (an array reference),
1.258 albertel 8013: will be set in $env{'form.name'} if they do not already exist.
1.112 bowersj2 8014:
8015: Typically called with $ENV{'QUERY_STRING'} as the first parameter.
8016: $possible_names is an ref to an array of form element names. As an example:
8017: get_unprocessed_cgi($ENV{'QUERY_STRING'},['uname','udom']);
1.258 albertel 8018: will result in $env{'form.uname'} and $env{'form.udom'} being set.
1.112 bowersj2 8019:
8020: =cut
1.1 albertel 8021:
1.6 albertel 8022: sub get_unprocessed_cgi {
1.25 albertel 8023: my ($query,$possible_names)= @_;
1.26 matthew 8024: # $Apache::lonxml::debug=1;
1.356 albertel 8025: foreach my $pair (split(/&/,$query)) {
8026: my ($name, $value) = split(/=/,$pair);
1.369 www 8027: $name = &unescape($name);
1.25 albertel 8028: if (!defined($possible_names) || (grep {$_ eq $name} @$possible_names)) {
8029: $value =~ tr/+/ /;
8030: $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
1.258 albertel 8031: unless (defined($env{'form.'.$name})) { &add_to_env('form.'.$name,$value) };
1.25 albertel 8032: }
1.16 harris41 8033: }
1.6 albertel 8034: }
8035:
1.112 bowersj2 8036: =pod
8037:
1.648 raeburn 8038: =item * &cacheheader()
1.112 bowersj2 8039:
8040: returns cache-controlling header code
8041:
8042: =cut
8043:
1.7 albertel 8044: sub cacheheader {
1.258 albertel 8045: unless ($env{'request.method'} eq 'GET') { return ''; }
1.216 albertel 8046: my $date=strftime("%a, %d %b %Y %H:%M:%S GMT",gmtime);
8047: my $output .='<meta HTTP-EQUIV="Expires" CONTENT="'.$date.'" />
1.7 albertel 8048: <meta HTTP-EQUIV="Cache-control" CONTENT="no-cache" />
8049: <meta HTTP-EQUIV="Pragma" CONTENT="no-cache" />';
1.216 albertel 8050: return $output;
1.7 albertel 8051: }
8052:
1.112 bowersj2 8053: =pod
8054:
1.648 raeburn 8055: =item * &no_cache($r)
1.112 bowersj2 8056:
8057: specifies header code to not have cache
8058:
8059: =cut
8060:
1.9 albertel 8061: sub no_cache {
1.216 albertel 8062: my ($r) = @_;
8063: if ($ENV{'REQUEST_METHOD'} ne 'GET' &&
1.258 albertel 8064: $env{'request.method'} ne 'GET') { return ''; }
1.216 albertel 8065: my $date=strftime("%a, %d %b %Y %H:%M:%S GMT",gmtime(time));
8066: $r->no_cache(1);
8067: $r->header_out("Expires" => $date);
8068: $r->header_out("Pragma" => "no-cache");
1.123 www 8069: }
8070:
8071: sub content_type {
1.181 albertel 8072: my ($r,$type,$charset) = @_;
1.299 foxr 8073: if ($r) {
8074: # Note that printout.pl calls this with undef for $r.
8075: &no_cache($r);
8076: }
1.258 albertel 8077: if ($env{'browser.mathml'} && $type eq 'text/html') { $type='text/xml'; }
1.181 albertel 8078: unless ($charset) {
8079: $charset=&Apache::lonlocal::current_encoding;
8080: }
8081: if ($charset) { $type.='; charset='.$charset; }
8082: if ($r) {
8083: $r->content_type($type);
8084: } else {
8085: print("Content-type: $type\n\n");
8086: }
1.9 albertel 8087: }
1.25 albertel 8088:
1.112 bowersj2 8089: =pod
8090:
1.648 raeburn 8091: =item * &add_to_env($name,$value)
1.112 bowersj2 8092:
1.258 albertel 8093: adds $name to the %env hash with value
1.112 bowersj2 8094: $value, if $name already exists, the entry is converted to an array
8095: reference and $value is added to the array.
8096:
8097: =cut
8098:
1.25 albertel 8099: sub add_to_env {
8100: my ($name,$value)=@_;
1.258 albertel 8101: if (defined($env{$name})) {
8102: if (ref($env{$name})) {
1.25 albertel 8103: #already have multiple values
1.258 albertel 8104: push(@{ $env{$name} },$value);
1.25 albertel 8105: } else {
8106: #first time seeing multiple values, convert hash entry to an arrayref
1.258 albertel 8107: my $first=$env{$name};
8108: undef($env{$name});
8109: push(@{ $env{$name} },$first,$value);
1.25 albertel 8110: }
8111: } else {
1.258 albertel 8112: $env{$name}=$value;
1.25 albertel 8113: }
1.31 albertel 8114: }
1.149 albertel 8115:
8116: =pod
8117:
1.648 raeburn 8118: =item * &get_env_multiple($name)
1.149 albertel 8119:
1.258 albertel 8120: gets $name from the %env hash, it seemlessly handles the cases where multiple
1.149 albertel 8121: values may be defined and end up as an array ref.
8122:
8123: returns an array of values
8124:
8125: =cut
8126:
8127: sub get_env_multiple {
8128: my ($name) = @_;
8129: my @values;
1.258 albertel 8130: if (defined($env{$name})) {
1.149 albertel 8131: # exists is it an array
1.258 albertel 8132: if (ref($env{$name})) {
8133: @values=@{ $env{$name} };
1.149 albertel 8134: } else {
1.258 albertel 8135: $values[0]=$env{$name};
1.149 albertel 8136: }
8137: }
8138: return(@values);
8139: }
8140:
1.660 raeburn 8141: sub ask_for_embedded_content {
8142: my ($actionurl,$state,$allfiles,$codebase,$args)=@_;
8143: my $upload_output = '
8144: <form name="upload_embedded" action="'.$actionurl.'"
8145: method="post" enctype="multipart/form-data">';
8146: $upload_output .= $state;
1.661 raeburn 8147: $upload_output .= '<b>Upload embedded files</b>:<br />'.&start_data_table();
1.660 raeburn 8148:
8149: my $num = 0;
8150: foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%{$allfiles})) {
8151: $upload_output .= &start_data_table_row().
8152: '<td>'.$embed_file.'</td><td>';
8153: if ($args->{'ignore_remote_references'}
8154: && $embed_file =~ m{^\w+://}) {
8155: $upload_output.='<span class="LC_warning">'.&mt("URL points to other server.").'</span>';
8156: } elsif ($args->{'error_on_invalid_names'}
8157: && $embed_file ne &Apache::lonnet::clean_filename($embed_file,{'keep_path' => 1,})) {
8158:
8159: $upload_output.='<span class="LC_warning">'.&mt("Invalid characters").'</span>';
8160:
8161: } else {
8162: $upload_output .='
1.661 raeburn 8163: <input name="embedded_item_'.$num.'" type="file" value="" />
1.660 raeburn 8164: <input name="embedded_orig_'.$num.'" type="hidden" value="'.&escape($embed_file).'" />';
8165: my $attrib = join(':',@{$$allfiles{$embed_file}});
8166: $upload_output .=
8167: "\n\t\t".
8168: '<input name="embedded_attrib_'.$num.'" type="hidden" value="'.
8169: $attrib.'" />';
8170: if (exists($$codebase{$embed_file})) {
8171: $upload_output .=
8172: "\n\t\t".
8173: '<input name="codebase_'.$num.'" type="hidden" value="'.
8174: &escape($$codebase{$embed_file}).'" />';
8175: }
8176: }
8177: $upload_output .= '</td>'.&Apache::loncommon::end_data_table_row();
8178: $num++;
8179: }
8180: $upload_output .= &Apache::loncommon::end_data_table().'<br />
8181: <input type ="hidden" name="number_embedded_items" value="'.$num.'" />
8182: <input type ="submit" value="'.&mt('Upload Listed Files').'" />
8183: '.&mt('(only files for which a location has been provided will be uploaded)').'
8184: </form>';
8185: return $upload_output;
8186: }
8187:
1.661 raeburn 8188: sub upload_embedded {
8189: my ($context,$dirpath,$uname,$udom,$dir_root,$url_root,$group,$disk_quota,
8190: $current_disk_usage) = @_;
8191: my $output;
8192: for (my $i=0; $i<$env{'form.number_embedded_items'}; $i++) {
8193: next if (!exists($env{'form.embedded_item_'.$i.'.filename'}));
8194: my $orig_uploaded_filename =
8195: $env{'form.embedded_item_'.$i.'.filename'};
8196:
8197: $env{'form.embedded_orig_'.$i} =
8198: &unescape($env{'form.embedded_orig_'.$i});
8199: my ($path,$fname) =
8200: ($env{'form.embedded_orig_'.$i} =~ m{(.*/)([^/]*)});
8201: # no path, whole string is fname
8202: if (!$fname) { $fname = $env{'form.embedded_orig_'.$i} };
8203:
8204: $path = $env{'form.currentpath'}.$path;
8205: $fname = &Apache::lonnet::clean_filename($fname);
8206: # See if there is anything left
8207: next if ($fname eq '');
8208:
8209: # Check if file already exists as a file or directory.
8210: my ($state,$msg);
8211: if ($context eq 'portfolio') {
8212: my $port_path = $dirpath;
8213: if ($group ne '') {
8214: $port_path = "groups/$group/$port_path";
8215: }
8216: ($state,$msg) = &check_for_upload($path,$fname,$group,'embedded_item_'.$i,
8217: $dir_root,$port_path,$disk_quota,
8218: $current_disk_usage,$uname,$udom);
8219: if ($state eq 'will_exceed_quota'
8220: || $state eq 'file_locked'
8221: || $state eq 'file_exists' ) {
8222: $output .= $msg;
8223: next;
8224: }
8225: } elsif (($context eq 'author') || ($context eq 'testbank')) {
8226: ($state,$msg) = &check_for_existing($path,$fname,'embedded_item_'.$i);
8227: if ($state eq 'exists') {
8228: $output .= $msg;
8229: next;
8230: }
8231: }
8232: # Check if extension is valid
8233: if (($fname =~ /\.(\w+)$/) &&
8234: (&Apache::loncommon::fileembstyle($1) eq 'hdn')) {
8235: $output .= &mt('Invalid file extension ([_1]) - reserved for LONCAPA use - rename the file with a different extension and re-upload. ',$1);
8236: next;
8237: } elsif (($fname =~ /\.(\w+)$/) &&
8238: (!defined(&Apache::loncommon::fileembstyle($1)))) {
8239: $output .= &mt('Unrecognized file extension ([_1]) - rename the file with a proper extension and re-upload.',$1);
8240: next;
8241: } elsif ($fname=~/\.(\d+)\.(\w+)$/) {
8242: $output .= &mt('File name not allowed - rename the file to remove the number immediately before the file extension([_1]) and re-upload.',$2);
8243: next;
8244: }
8245:
8246: $env{'form.embedded_item_'.$i.'.filename'}=$fname;
8247: if ($context eq 'portfolio') {
8248: my $result=
8249: &Apache::lonnet::userfileupload('embedded_item_'.$i,'',
8250: $dirpath.$path);
8251: if ($result !~ m|^/uploaded/|) {
8252: $output .= '<span class="LC_error">'
8253: .&mt('An error occurred ([_1]) while trying to upload [_2] for embedded element [_3].'
8254: ,$result,$orig_uploaded_filename,$env{'form.embedded_orig_'.$i})
8255: .'</span><br />';
8256: next;
8257: } else {
8258: $output .= '<p>'.&mt('Uploaded [_1]','<span class="LC_filename">'.
8259: $path.$fname.'</span>').'</p>';
8260: }
8261: } else {
8262: # Save the file
8263: my $target = $env{'form.embedded_item_'.$i};
8264: my $fullpath = $dir_root.$dirpath.'/'.$path;
8265: my $dest = $fullpath.$fname;
8266: my $url = $url_root.$dirpath.'/'.$path.$fname;
8267: my @parts=split(/\//,$fullpath);
8268: my $count;
8269: my $filepath = $dir_root;
8270: for ($count=4;$count<=$#parts;$count++) {
8271: $filepath .= "/$parts[$count]";
8272: if ((-e $filepath)!=1) {
8273: mkdir($filepath,0770);
8274: }
8275: }
8276: my $fh;
8277: if (!open($fh,'>'.$dest)) {
8278: &Apache::lonnet::logthis('Failed to create '.$dest);
8279: $output .= '<span class="LC_error">'.
8280: &mt('An error occurred while trying to upload [_1] for embedded element [_2].',$orig_uploaded_filename,$env{'form.embedded_orig_'.$i}).
8281: '</span><br />';
8282: } else {
8283: if (!print $fh $env{'form.embedded_item_'.$i}) {
8284: &Apache::lonnet::logthis('Failed to write to '.$dest);
8285: $output .= '<span class="LC_error">'.
8286: &mt('An error occurred while writing the file [_1] for embedded element [_2].',$orig_uploaded_filename,$env{'form.embedded_orig_'.$i}).
8287: '</span><br />';
8288: } else {
8289: if ($context eq 'testbank') {
8290: $output .= &mt('Embedded file uploaded successfully:').
8291: ' <a href="'.$url.'">'.
8292: $orig_uploaded_filename.'</a><br />';
8293: } else {
1.705 tempelho 8294: $output .= '<span class=\"LC_fontsize_large\">'.
1.661 raeburn 8295: &mt('View embedded file: [_1]','<a href="'.$url.'">'.
1.705 tempelho 8296: $orig_uploaded_filename.'</a>').'</span><br />';
1.661 raeburn 8297: }
8298: }
8299: close($fh);
8300: }
8301: }
8302: }
8303: return $output;
8304: }
8305:
8306: sub check_for_existing {
8307: my ($path,$fname,$element) = @_;
8308: my ($state,$msg);
8309: if (-d $path.'/'.$fname) {
8310: $state = 'exists';
8311: $msg = &mt('Unable to upload [_1]. A directory by that name was found in [_2].','<span class="LC_filename">'.$fname.'</span>',$path);
8312: } elsif (-e $path.'/'.$fname) {
8313: $state = 'exists';
8314: $msg = &mt('Unable to upload [_1]. A file by that name was found in [_2].','<span class="LC_filename">'.$fname.'</span>',$path);
8315: }
8316: if ($state eq 'exists') {
8317: $msg = '<span class="LC_error">'.$msg.'</span><br />';
8318: }
8319: return ($state,$msg);
8320: }
8321:
8322: sub check_for_upload {
8323: my ($path,$fname,$group,$element,$portfolio_root,$port_path,
8324: $disk_quota,$current_disk_usage,$uname,$udom) = @_;
8325: my $filesize = (length($env{'form.'.$element})) / 1000; #express in k (1024?)
8326: my $getpropath = 1;
8327: my @dir_list = &Apache::lonnet::dirlist($portfolio_root.$path,$udom,$uname,
8328: $getpropath);
8329: my $found_file = 0;
8330: my $locked_file = 0;
8331: foreach my $line (@dir_list) {
8332: my ($file_name)=split(/\&/,$line,2);
8333: if ($file_name eq $fname){
8334: $file_name = $path.$file_name;
8335: if ($group ne '') {
8336: $file_name = $group.$file_name;
8337: }
8338: $found_file = 1;
8339: if (&Apache::lonnet::is_locked($file_name,$udom,$uname) eq 'true') {
8340: $locked_file = 1;
8341: }
8342: }
8343: }
8344: if (($current_disk_usage + $filesize) > $disk_quota){
8345: my $msg = '<span class="LC_error">'.
8346: &mt('Unable to upload [_1]. (size = [_2] kilobytes). Disk quota will be exceeded.','<span class="LC_filename">'.$fname.'</span>',$filesize).'</span>'.
8347: '<br />'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.',$disk_quota,$current_disk_usage);
8348: return ('will_exceed_quota',$msg);
8349: } elsif ($found_file) {
8350: if ($locked_file) {
8351: my $msg = '<span class="LC_error">';
8352: $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>');
8353: $msg .= '</span><br />';
8354: $msg .= &mt('You will be able to rename or delete existing [_1] after a grade has been assigned.','<span class="LC_filename">'.$fname.'</span>');
8355: return ('file_locked',$msg);
8356: } else {
8357: my $msg = '<span class="LC_error">';
8358: $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'});
8359: $msg .= '</span>';
8360: $msg .= '<br />';
8361: $msg .= &mt('To upload, rename or delete existing [_1] in [_2].','<span class="LC_filename">'.$fname.'</span>', $port_path.$env{'form.currentpath'});
8362: return ('file_exists',$msg);
8363: }
8364: }
8365: }
8366:
1.31 albertel 8367:
1.41 ng 8368: =pod
1.45 matthew 8369:
1.464 albertel 8370: =back
1.41 ng 8371:
1.112 bowersj2 8372: =head1 CSV Upload/Handling functions
1.38 albertel 8373:
1.41 ng 8374: =over 4
8375:
1.648 raeburn 8376: =item * &upfile_store($r)
1.41 ng 8377:
8378: Store uploaded file, $r should be the HTTP Request object,
1.258 albertel 8379: needs $env{'form.upfile'}
1.41 ng 8380: returns $datatoken to be put into hidden field
8381:
8382: =cut
1.31 albertel 8383:
8384: sub upfile_store {
8385: my $r=shift;
1.258 albertel 8386: $env{'form.upfile'}=~s/\r/\n/gs;
8387: $env{'form.upfile'}=~s/\f/\n/gs;
8388: $env{'form.upfile'}=~s/\n+/\n/gs;
8389: $env{'form.upfile'}=~s/\n+$//gs;
1.31 albertel 8390:
1.258 albertel 8391: my $datatoken=$env{'user.name'}.'_'.$env{'user.domain'}.
8392: '_enroll_'.$env{'request.course.id'}.'_'.time.'_'.$$;
1.31 albertel 8393: {
1.158 raeburn 8394: my $datafile = $r->dir_config('lonDaemons').
8395: '/tmp/'.$datatoken.'.tmp';
8396: if ( open(my $fh,">$datafile") ) {
1.258 albertel 8397: print $fh $env{'form.upfile'};
1.158 raeburn 8398: close($fh);
8399: }
1.31 albertel 8400: }
8401: return $datatoken;
8402: }
8403:
1.56 matthew 8404: =pod
8405:
1.648 raeburn 8406: =item * &load_tmp_file($r)
1.41 ng 8407:
8408: Load uploaded file from tmp, $r should be the HTTP Request object,
1.258 albertel 8409: needs $env{'form.datatoken'},
8410: sets $env{'form.upfile'} to the contents of the file
1.41 ng 8411:
8412: =cut
1.31 albertel 8413:
8414: sub load_tmp_file {
8415: my $r=shift;
8416: my @studentdata=();
8417: {
1.158 raeburn 8418: my $studentfile = $r->dir_config('lonDaemons').
1.258 albertel 8419: '/tmp/'.$env{'form.datatoken'}.'.tmp';
1.158 raeburn 8420: if ( open(my $fh,"<$studentfile") ) {
8421: @studentdata=<$fh>;
8422: close($fh);
8423: }
1.31 albertel 8424: }
1.258 albertel 8425: $env{'form.upfile'}=join('',@studentdata);
1.31 albertel 8426: }
8427:
1.56 matthew 8428: =pod
8429:
1.648 raeburn 8430: =item * &upfile_record_sep()
1.41 ng 8431:
8432: Separate uploaded file into records
8433: returns array of records,
1.258 albertel 8434: needs $env{'form.upfile'} and $env{'form.upfiletype'}
1.41 ng 8435:
8436: =cut
1.31 albertel 8437:
8438: sub upfile_record_sep {
1.258 albertel 8439: if ($env{'form.upfiletype'} eq 'xml') {
1.31 albertel 8440: } else {
1.248 albertel 8441: my @records;
1.258 albertel 8442: foreach my $line (split(/\n/,$env{'form.upfile'})) {
1.248 albertel 8443: if ($line=~/^\s*$/) { next; }
8444: push(@records,$line);
8445: }
8446: return @records;
1.31 albertel 8447: }
8448: }
8449:
1.56 matthew 8450: =pod
8451:
1.648 raeburn 8452: =item * &record_sep($record)
1.41 ng 8453:
1.258 albertel 8454: Separate a record into fields $record should be an item from the upfile_record_sep(), needs $env{'form.upfiletype'}
1.41 ng 8455:
8456: =cut
8457:
1.263 www 8458: sub takeleft {
8459: my $index=shift;
8460: return substr('0000'.$index,-4,4);
8461: }
8462:
1.31 albertel 8463: sub record_sep {
8464: my $record=shift;
8465: my %components=();
1.258 albertel 8466: if ($env{'form.upfiletype'} eq 'xml') {
8467: } elsif ($env{'form.upfiletype'} eq 'space') {
1.31 albertel 8468: my $i=0;
1.356 albertel 8469: foreach my $field (split(/\s+/,$record)) {
1.31 albertel 8470: $field=~s/^(\"|\')//;
8471: $field=~s/(\"|\')$//;
1.263 www 8472: $components{&takeleft($i)}=$field;
1.31 albertel 8473: $i++;
8474: }
1.258 albertel 8475: } elsif ($env{'form.upfiletype'} eq 'tab') {
1.31 albertel 8476: my $i=0;
1.356 albertel 8477: foreach my $field (split(/\t/,$record)) {
1.31 albertel 8478: $field=~s/^(\"|\')//;
8479: $field=~s/(\"|\')$//;
1.263 www 8480: $components{&takeleft($i)}=$field;
1.31 albertel 8481: $i++;
8482: }
8483: } else {
1.561 www 8484: my $separator=',';
1.480 banghart 8485: if ($env{'form.upfiletype'} eq 'semisv') {
1.561 www 8486: $separator=';';
1.480 banghart 8487: }
1.31 albertel 8488: my $i=0;
1.561 www 8489: # the character we are looking for to indicate the end of a quote or a record
8490: my $looking_for=$separator;
8491: # do not add the characters to the fields
8492: my $ignore=0;
8493: # we just encountered a separator (or the beginning of the record)
8494: my $just_found_separator=1;
8495: # store the field we are working on here
8496: my $field='';
8497: # work our way through all characters in record
8498: foreach my $character ($record=~/(.)/g) {
8499: if ($character eq $looking_for) {
8500: if ($character ne $separator) {
8501: # Found the end of a quote, again looking for separator
8502: $looking_for=$separator;
8503: $ignore=1;
8504: } else {
8505: # Found a separator, store away what we got
8506: $components{&takeleft($i)}=$field;
8507: $i++;
8508: $just_found_separator=1;
8509: $ignore=0;
8510: $field='';
8511: }
8512: next;
8513: }
8514: # single or double quotation marks after a separator indicate beginning of a quote
8515: # we are now looking for the end of the quote and need to ignore separators
8516: if ((($character eq '"') || ($character eq "'")) && ($just_found_separator)) {
8517: $looking_for=$character;
8518: next;
8519: }
8520: # ignore would be true after we reached the end of a quote
8521: if ($ignore) { next; }
8522: if (($just_found_separator) && ($character=~/\s/)) { next; }
8523: $field.=$character;
8524: $just_found_separator=0;
1.31 albertel 8525: }
1.561 www 8526: # catch the very last entry, since we never encountered the separator
8527: $components{&takeleft($i)}=$field;
1.31 albertel 8528: }
8529: return %components;
8530: }
8531:
1.144 matthew 8532: ######################################################
8533: ######################################################
8534:
1.56 matthew 8535: =pod
8536:
1.648 raeburn 8537: =item * &upfile_select_html()
1.41 ng 8538:
1.144 matthew 8539: Return HTML code to select a file from the users machine and specify
8540: the file type.
1.41 ng 8541:
8542: =cut
8543:
1.144 matthew 8544: ######################################################
8545: ######################################################
1.31 albertel 8546: sub upfile_select_html {
1.144 matthew 8547: my %Types = (
8548: csv => &mt('CSV (comma separated values, spreadsheet)'),
1.480 banghart 8549: semisv => &mt('Semicolon separated values'),
1.144 matthew 8550: space => &mt('Space separated'),
8551: tab => &mt('Tabulator separated'),
8552: # xml => &mt('HTML/XML'),
8553: );
8554: my $Str = '<input type="file" name="upfile" size="50" />'.
1.727 riegler 8555: '<br />'.&mt('Type').': <select name="upfiletype">';
1.144 matthew 8556: foreach my $type (sort(keys(%Types))) {
8557: $Str .= '<option value="'.$type.'" >'.$Types{$type}."</option>\n";
8558: }
8559: $Str .= "</select>\n";
8560: return $Str;
1.31 albertel 8561: }
8562:
1.301 albertel 8563: sub get_samples {
8564: my ($records,$toget) = @_;
8565: my @samples=({});
8566: my $got=0;
8567: foreach my $rec (@$records) {
8568: my %temp = &record_sep($rec);
8569: if (! grep(/\S/, values(%temp))) { next; }
8570: if (%temp) {
8571: $samples[$got]=\%temp;
8572: $got++;
8573: if ($got == $toget) { last; }
8574: }
8575: }
8576: return \@samples;
8577: }
8578:
1.144 matthew 8579: ######################################################
8580: ######################################################
8581:
1.56 matthew 8582: =pod
8583:
1.648 raeburn 8584: =item * &csv_print_samples($r,$records)
1.41 ng 8585:
8586: Prints a table of sample values from each column uploaded $r is an
8587: Apache Request ref, $records is an arrayref from
8588: &Apache::loncommon::upfile_record_sep
8589:
8590: =cut
8591:
1.144 matthew 8592: ######################################################
8593: ######################################################
1.31 albertel 8594: sub csv_print_samples {
8595: my ($r,$records) = @_;
1.662 bisitz 8596: my $samples = &get_samples($records,5);
1.301 albertel 8597:
1.594 raeburn 8598: $r->print(&mt('Samples').'<br />'.&start_data_table().
8599: &start_data_table_header_row());
1.356 albertel 8600: foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) {
1.845 bisitz 8601: $r->print('<th>'.&mt('Column [_1]',($sample+1)).'</th>'); }
1.594 raeburn 8602: $r->print(&end_data_table_header_row());
1.301 albertel 8603: foreach my $hash (@$samples) {
1.594 raeburn 8604: $r->print(&start_data_table_row());
1.356 albertel 8605: foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) {
1.31 albertel 8606: $r->print('<td>');
1.356 albertel 8607: if (defined($$hash{$sample})) { $r->print($$hash{$sample}); }
1.31 albertel 8608: $r->print('</td>');
8609: }
1.594 raeburn 8610: $r->print(&end_data_table_row());
1.31 albertel 8611: }
1.594 raeburn 8612: $r->print(&end_data_table().'<br />'."\n");
1.31 albertel 8613: }
8614:
1.144 matthew 8615: ######################################################
8616: ######################################################
8617:
1.56 matthew 8618: =pod
8619:
1.648 raeburn 8620: =item * &csv_print_select_table($r,$records,$d)
1.41 ng 8621:
8622: Prints a table to create associations between values and table columns.
1.144 matthew 8623:
1.41 ng 8624: $r is an Apache Request ref,
8625: $records is an arrayref from &Apache::loncommon::upfile_record_sep,
1.174 matthew 8626: $d is an array of 2 element arrays (internal name, displayed name,defaultcol)
1.41 ng 8627:
8628: =cut
8629:
1.144 matthew 8630: ######################################################
8631: ######################################################
1.31 albertel 8632: sub csv_print_select_table {
8633: my ($r,$records,$d) = @_;
1.301 albertel 8634: my $i=0;
8635: my $samples = &get_samples($records,1);
1.144 matthew 8636: $r->print(&mt('Associate columns with student attributes.')."\n".
1.594 raeburn 8637: &start_data_table().&start_data_table_header_row().
1.144 matthew 8638: '<th>'.&mt('Attribute').'</th>'.
1.594 raeburn 8639: '<th>'.&mt('Column').'</th>'.
8640: &end_data_table_header_row()."\n");
1.356 albertel 8641: foreach my $array_ref (@$d) {
8642: my ($value,$display,$defaultcol)=@{ $array_ref };
1.729 raeburn 8643: $r->print(&start_data_table_row().'<td>'.$display.'</td>');
1.31 albertel 8644:
1.875 bisitz 8645: $r->print('<td><select name="f'.$i.'"'.
1.32 matthew 8646: ' onchange="javascript:flip(this.form,'.$i.');">');
1.31 albertel 8647: $r->print('<option value="none"></option>');
1.356 albertel 8648: foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) {
8649: $r->print('<option value="'.$sample.'"'.
8650: ($sample eq $defaultcol ? ' selected="selected" ' : '').
1.662 bisitz 8651: '>'.&mt('Column [_1]',($sample+1)).'</option>');
1.31 albertel 8652: }
1.594 raeburn 8653: $r->print('</select></td>'.&end_data_table_row()."\n");
1.31 albertel 8654: $i++;
8655: }
1.594 raeburn 8656: $r->print(&end_data_table());
1.31 albertel 8657: $i--;
8658: return $i;
8659: }
1.56 matthew 8660:
1.144 matthew 8661: ######################################################
8662: ######################################################
8663:
1.56 matthew 8664: =pod
1.31 albertel 8665:
1.648 raeburn 8666: =item * &csv_samples_select_table($r,$records,$d)
1.41 ng 8667:
8668: Prints a table of sample values from the upload and can make associate samples to internal names.
8669:
8670: $r is an Apache Request ref,
8671: $records is an arrayref from &Apache::loncommon::upfile_record_sep,
8672: $d is an array of 2 element arrays (internal name, displayed name)
8673:
8674: =cut
8675:
1.144 matthew 8676: ######################################################
8677: ######################################################
1.31 albertel 8678: sub csv_samples_select_table {
8679: my ($r,$records,$d) = @_;
8680: my $i=0;
1.144 matthew 8681: #
1.662 bisitz 8682: my $max_samples = 5;
8683: my $samples = &get_samples($records,$max_samples);
1.594 raeburn 8684: $r->print(&start_data_table().
8685: &start_data_table_header_row().'<th>'.
8686: &mt('Field').'</th><th>'.&mt('Samples').'</th>'.
8687: &end_data_table_header_row());
1.301 albertel 8688:
8689: foreach my $key (sort(keys(%{ $samples->[0] }))) {
1.594 raeburn 8690: $r->print(&start_data_table_row().'<td><select name="f'.$i.'"'.
1.32 matthew 8691: ' onchange="javascript:flip(this.form,'.$i.');">');
1.301 albertel 8692: foreach my $option (@$d) {
8693: my ($value,$display,$defaultcol)=@{ $option };
1.174 matthew 8694: $r->print('<option value="'.$value.'"'.
1.253 albertel 8695: ($i eq $defaultcol ? ' selected="selected" ':'').'>'.
1.174 matthew 8696: $display.'</option>');
1.31 albertel 8697: }
8698: $r->print('</select></td><td>');
1.662 bisitz 8699: foreach my $line (0..($max_samples-1)) {
1.301 albertel 8700: if (defined($samples->[$line]{$key})) {
8701: $r->print($samples->[$line]{$key}."<br />\n");
8702: }
8703: }
1.594 raeburn 8704: $r->print('</td>'.&end_data_table_row());
1.31 albertel 8705: $i++;
8706: }
1.594 raeburn 8707: $r->print(&end_data_table());
1.31 albertel 8708: $i--;
8709: return($i);
1.115 matthew 8710: }
8711:
1.144 matthew 8712: ######################################################
8713: ######################################################
8714:
1.115 matthew 8715: =pod
8716:
1.648 raeburn 8717: =item * &clean_excel_name($name)
1.115 matthew 8718:
8719: Returns a replacement for $name which does not contain any illegal characters.
8720:
8721: =cut
8722:
1.144 matthew 8723: ######################################################
8724: ######################################################
1.115 matthew 8725: sub clean_excel_name {
8726: my ($name) = @_;
8727: $name =~ s/[:\*\?\/\\]//g;
8728: if (length($name) > 31) {
8729: $name = substr($name,0,31);
8730: }
8731: return $name;
1.25 albertel 8732: }
1.84 albertel 8733:
1.85 albertel 8734: =pod
8735:
1.648 raeburn 8736: =item * &check_if_partid_hidden($id,$symb,$udom,$uname)
1.85 albertel 8737:
8738: Returns either 1 or undef
8739:
8740: 1 if the part is to be hidden, undef if it is to be shown
8741:
8742: Arguments are:
8743:
8744: $id the id of the part to be checked
8745: $symb, optional the symb of the resource to check
8746: $udom, optional the domain of the user to check for
8747: $uname, optional the username of the user to check for
8748:
8749: =cut
1.84 albertel 8750:
8751: sub check_if_partid_hidden {
8752: my ($id,$symb,$udom,$uname) = @_;
1.133 albertel 8753: my $hiddenparts=&Apache::lonnet::EXT('resource.0.hiddenparts',
1.84 albertel 8754: $symb,$udom,$uname);
1.141 albertel 8755: my $truth=1;
8756: #if the string starts with !, then the list is the list to show not hide
8757: if ($hiddenparts=~s/^\s*!//) { $truth=undef; }
1.84 albertel 8758: my @hiddenlist=split(/,/,$hiddenparts);
8759: foreach my $checkid (@hiddenlist) {
1.141 albertel 8760: if ($checkid =~ /^\s*\Q$id\E\s*$/) { return $truth; }
1.84 albertel 8761: }
1.141 albertel 8762: return !$truth;
1.84 albertel 8763: }
1.127 matthew 8764:
1.138 matthew 8765:
8766: ############################################################
8767: ############################################################
8768:
8769: =pod
8770:
1.157 matthew 8771: =back
8772:
1.138 matthew 8773: =head1 cgi-bin script and graphing routines
8774:
1.157 matthew 8775: =over 4
8776:
1.648 raeburn 8777: =item * &get_cgi_id()
1.138 matthew 8778:
8779: Inputs: none
8780:
8781: Returns an id which can be used to pass environment variables
8782: to various cgi-bin scripts. These environment variables will
8783: be removed from the users environment after a given time by
8784: the routine &Apache::lonnet::transfer_profile_to_env.
8785:
8786: =cut
8787:
8788: ############################################################
8789: ############################################################
1.152 albertel 8790: my $uniq=0;
1.136 matthew 8791: sub get_cgi_id {
1.154 albertel 8792: $uniq=($uniq+1)%100000;
1.280 albertel 8793: return (time.'_'.$$.'_'.$uniq);
1.136 matthew 8794: }
8795:
1.127 matthew 8796: ############################################################
8797: ############################################################
8798:
8799: =pod
8800:
1.648 raeburn 8801: =item * &DrawBarGraph()
1.127 matthew 8802:
1.138 matthew 8803: Facilitates the plotting of data in a (stacked) bar graph.
8804: Puts plot definition data into the users environment in order for
8805: graph.png to plot it. Returns an <img> tag for the plot.
8806: The bars on the plot are labeled '1','2',...,'n'.
8807:
8808: Inputs:
8809:
8810: =over 4
8811:
8812: =item $Title: string, the title of the plot
8813:
8814: =item $xlabel: string, text describing the X-axis of the plot
8815:
8816: =item $ylabel: string, text describing the Y-axis of the plot
8817:
8818: =item $Max: scalar, the maximum Y value to use in the plot
8819: If $Max is < any data point, the graph will not be rendered.
8820:
1.140 matthew 8821: =item $colors: array ref holding the colors to be used for the data sets when
1.138 matthew 8822: they are plotted. If undefined, default values will be used.
8823:
1.178 matthew 8824: =item $labels: array ref holding the labels to use on the x-axis for the bars.
8825:
1.138 matthew 8826: =item @Values: An array of array references. Each array reference holds data
8827: to be plotted in a stacked bar chart.
8828:
1.239 matthew 8829: =item If the final element of @Values is a hash reference the key/value
8830: pairs will be added to the graph definition.
8831:
1.138 matthew 8832: =back
8833:
8834: Returns:
8835:
8836: An <img> tag which references graph.png and the appropriate identifying
8837: information for the plot.
8838:
1.127 matthew 8839: =cut
8840:
8841: ############################################################
8842: ############################################################
1.134 matthew 8843: sub DrawBarGraph {
1.178 matthew 8844: my ($Title,$xlabel,$ylabel,$Max,$colors,$labels,@Values)=@_;
1.134 matthew 8845: #
8846: if (! defined($colors)) {
8847: $colors = ['#33ff00',
8848: '#0033cc', '#990000', '#aaaa66', '#663399', '#ff9933',
8849: '#66ccff', '#ff9999', '#cccc33', '#660000', '#33cc66',
8850: ];
8851: }
1.228 matthew 8852: my $extra_settings = {};
8853: if (ref($Values[-1]) eq 'HASH') {
8854: $extra_settings = pop(@Values);
8855: }
1.127 matthew 8856: #
1.136 matthew 8857: my $identifier = &get_cgi_id();
8858: my $id = 'cgi.'.$identifier;
1.129 matthew 8859: if (! @Values || ref($Values[0]) ne 'ARRAY') {
1.127 matthew 8860: return '';
8861: }
1.225 matthew 8862: #
8863: my @Labels;
8864: if (defined($labels)) {
8865: @Labels = @$labels;
8866: } else {
8867: for (my $i=0;$i<@{$Values[0]};$i++) {
8868: push (@Labels,$i+1);
8869: }
8870: }
8871: #
1.129 matthew 8872: my $NumBars = scalar(@{$Values[0]});
1.225 matthew 8873: if ($NumBars < scalar(@Labels)) { $NumBars = scalar(@Labels); }
1.129 matthew 8874: my %ValuesHash;
8875: my $NumSets=1;
8876: foreach my $array (@Values) {
8877: next if (! ref($array));
1.136 matthew 8878: $ValuesHash{$id.'.data.'.$NumSets++} =
1.132 matthew 8879: join(',',@$array);
1.129 matthew 8880: }
1.127 matthew 8881: #
1.136 matthew 8882: my ($height,$width,$xskip,$bar_width) = (200,120,1,15);
1.225 matthew 8883: if ($NumBars < 3) {
8884: $width = 120+$NumBars*32;
1.220 matthew 8885: $xskip = 1;
1.225 matthew 8886: $bar_width = 30;
8887: } elsif ($NumBars < 5) {
8888: $width = 120+$NumBars*20;
8889: $xskip = 1;
8890: $bar_width = 20;
1.220 matthew 8891: } elsif ($NumBars < 10) {
1.136 matthew 8892: $width = 120+$NumBars*15;
8893: $xskip = 1;
8894: $bar_width = 15;
8895: } elsif ($NumBars <= 25) {
8896: $width = 120+$NumBars*11;
8897: $xskip = 5;
8898: $bar_width = 8;
8899: } elsif ($NumBars <= 50) {
8900: $width = 120+$NumBars*8;
8901: $xskip = 5;
8902: $bar_width = 4;
8903: } else {
8904: $width = 120+$NumBars*8;
8905: $xskip = 5;
8906: $bar_width = 4;
8907: }
8908: #
1.137 matthew 8909: $Max = 1 if ($Max < 1);
8910: if ( int($Max) < $Max ) {
8911: $Max++;
8912: $Max = int($Max);
8913: }
1.127 matthew 8914: $Title = '' if (! defined($Title));
8915: $xlabel = '' if (! defined($xlabel));
8916: $ylabel = '' if (! defined($ylabel));
1.369 www 8917: $ValuesHash{$id.'.title'} = &escape($Title);
8918: $ValuesHash{$id.'.xlabel'} = &escape($xlabel);
8919: $ValuesHash{$id.'.ylabel'} = &escape($ylabel);
1.137 matthew 8920: $ValuesHash{$id.'.y_max_value'} = $Max;
1.136 matthew 8921: $ValuesHash{$id.'.NumBars'} = $NumBars;
8922: $ValuesHash{$id.'.NumSets'} = $NumSets;
8923: $ValuesHash{$id.'.PlotType'} = 'bar';
8924: $ValuesHash{$id.'.Colors'} = join(',',@{$colors});
8925: $ValuesHash{$id.'.height'} = $height;
8926: $ValuesHash{$id.'.width'} = $width;
8927: $ValuesHash{$id.'.xskip'} = $xskip;
8928: $ValuesHash{$id.'.bar_width'} = $bar_width;
8929: $ValuesHash{$id.'.labels'} = join(',',@Labels);
1.127 matthew 8930: #
1.228 matthew 8931: # Deal with other parameters
8932: while (my ($key,$value) = each(%$extra_settings)) {
8933: $ValuesHash{$id.'.'.$key} = $value;
8934: }
8935: #
1.646 raeburn 8936: &Apache::lonnet::appenv(\%ValuesHash);
1.137 matthew 8937: return '<img src="/cgi-bin/graph.png?'.$identifier.'" border="1" />';
8938: }
8939:
8940: ############################################################
8941: ############################################################
8942:
8943: =pod
8944:
1.648 raeburn 8945: =item * &DrawXYGraph()
1.137 matthew 8946:
1.138 matthew 8947: Facilitates the plotting of data in an XY graph.
8948: Puts plot definition data into the users environment in order for
8949: graph.png to plot it. Returns an <img> tag for the plot.
8950:
8951: Inputs:
8952:
8953: =over 4
8954:
8955: =item $Title: string, the title of the plot
8956:
8957: =item $xlabel: string, text describing the X-axis of the plot
8958:
8959: =item $ylabel: string, text describing the Y-axis of the plot
8960:
8961: =item $Max: scalar, the maximum Y value to use in the plot
8962: If $Max is < any data point, the graph will not be rendered.
8963:
8964: =item $colors: Array ref containing the hex color codes for the data to be
8965: plotted in. If undefined, default values will be used.
8966:
8967: =item $Xlabels: Array ref containing the labels to be used for the X-axis.
8968:
8969: =item $Ydata: Array ref containing Array refs.
1.185 www 8970: Each of the contained arrays will be plotted as a separate curve.
1.138 matthew 8971:
8972: =item %Values: hash indicating or overriding any default values which are
8973: passed to graph.png.
8974: Possible values are: width, xskip, x_ticks, x_tick_offset, among others.
8975:
8976: =back
8977:
8978: Returns:
8979:
8980: An <img> tag which references graph.png and the appropriate identifying
8981: information for the plot.
8982:
1.137 matthew 8983: =cut
8984:
8985: ############################################################
8986: ############################################################
8987: sub DrawXYGraph {
8988: my ($Title,$xlabel,$ylabel,$Max,$colors,$Xlabels,$Ydata,%Values)=@_;
8989: #
8990: # Create the identifier for the graph
8991: my $identifier = &get_cgi_id();
8992: my $id = 'cgi.'.$identifier;
8993: #
8994: $Title = '' if (! defined($Title));
8995: $xlabel = '' if (! defined($xlabel));
8996: $ylabel = '' if (! defined($ylabel));
8997: my %ValuesHash =
8998: (
1.369 www 8999: $id.'.title' => &escape($Title),
9000: $id.'.xlabel' => &escape($xlabel),
9001: $id.'.ylabel' => &escape($ylabel),
1.137 matthew 9002: $id.'.y_max_value'=> $Max,
9003: $id.'.labels' => join(',',@$Xlabels),
9004: $id.'.PlotType' => 'XY',
9005: );
9006: #
9007: if (defined($colors) && ref($colors) eq 'ARRAY') {
9008: $ValuesHash{$id.'.Colors'} = join(',',@{$colors});
9009: }
9010: #
9011: if (! ref($Ydata) || ref($Ydata) ne 'ARRAY') {
9012: return '';
9013: }
9014: my $NumSets=1;
1.138 matthew 9015: foreach my $array (@{$Ydata}){
1.137 matthew 9016: next if (! ref($array));
9017: $ValuesHash{$id.'.data.'.$NumSets++} = join(',',@$array);
9018: }
1.138 matthew 9019: $ValuesHash{$id.'.NumSets'} = $NumSets-1;
1.137 matthew 9020: #
9021: # Deal with other parameters
9022: while (my ($key,$value) = each(%Values)) {
9023: $ValuesHash{$id.'.'.$key} = $value;
1.127 matthew 9024: }
9025: #
1.646 raeburn 9026: &Apache::lonnet::appenv(\%ValuesHash);
1.136 matthew 9027: return '<img src="/cgi-bin/graph.png?'.$identifier.'" border="1" />';
9028: }
9029:
9030: ############################################################
9031: ############################################################
9032:
9033: =pod
9034:
1.648 raeburn 9035: =item * &DrawXYYGraph()
1.138 matthew 9036:
9037: Facilitates the plotting of data in an XY graph with two Y axes.
9038: Puts plot definition data into the users environment in order for
9039: graph.png to plot it. Returns an <img> tag for the plot.
9040:
9041: Inputs:
9042:
9043: =over 4
9044:
9045: =item $Title: string, the title of the plot
9046:
9047: =item $xlabel: string, text describing the X-axis of the plot
9048:
9049: =item $ylabel: string, text describing the Y-axis of the plot
9050:
9051: =item $colors: Array ref containing the hex color codes for the data to be
9052: plotted in. If undefined, default values will be used.
9053:
9054: =item $Xlabels: Array ref containing the labels to be used for the X-axis.
9055:
9056: =item $Ydata1: The first data set
9057:
9058: =item $Min1: The minimum value of the left Y-axis
9059:
9060: =item $Max1: The maximum value of the left Y-axis
9061:
9062: =item $Ydata2: The second data set
9063:
9064: =item $Min2: The minimum value of the right Y-axis
9065:
9066: =item $Max2: The maximum value of the left Y-axis
9067:
9068: =item %Values: hash indicating or overriding any default values which are
9069: passed to graph.png.
9070: Possible values are: width, xskip, x_ticks, x_tick_offset, among others.
9071:
9072: =back
9073:
9074: Returns:
9075:
9076: An <img> tag which references graph.png and the appropriate identifying
9077: information for the plot.
1.136 matthew 9078:
9079: =cut
9080:
9081: ############################################################
9082: ############################################################
1.137 matthew 9083: sub DrawXYYGraph {
9084: my ($Title,$xlabel,$ylabel,$colors,$Xlabels,$Ydata1,$Min1,$Max1,
9085: $Ydata2,$Min2,$Max2,%Values)=@_;
1.136 matthew 9086: #
9087: # Create the identifier for the graph
9088: my $identifier = &get_cgi_id();
9089: my $id = 'cgi.'.$identifier;
9090: #
9091: $Title = '' if (! defined($Title));
9092: $xlabel = '' if (! defined($xlabel));
9093: $ylabel = '' if (! defined($ylabel));
9094: my %ValuesHash =
9095: (
1.369 www 9096: $id.'.title' => &escape($Title),
9097: $id.'.xlabel' => &escape($xlabel),
9098: $id.'.ylabel' => &escape($ylabel),
1.136 matthew 9099: $id.'.labels' => join(',',@$Xlabels),
9100: $id.'.PlotType' => 'XY',
9101: $id.'.NumSets' => 2,
1.137 matthew 9102: $id.'.two_axes' => 1,
9103: $id.'.y1_max_value' => $Max1,
9104: $id.'.y1_min_value' => $Min1,
9105: $id.'.y2_max_value' => $Max2,
9106: $id.'.y2_min_value' => $Min2,
1.136 matthew 9107: );
9108: #
1.137 matthew 9109: if (defined($colors) && ref($colors) eq 'ARRAY') {
9110: $ValuesHash{$id.'.Colors'} = join(',',@{$colors});
9111: }
9112: #
9113: if (! ref($Ydata1) || ref($Ydata1) ne 'ARRAY' ||
9114: ! ref($Ydata2) || ref($Ydata2) ne 'ARRAY'){
1.136 matthew 9115: return '';
9116: }
9117: my $NumSets=1;
1.137 matthew 9118: foreach my $array ($Ydata1,$Ydata2){
1.136 matthew 9119: next if (! ref($array));
9120: $ValuesHash{$id.'.data.'.$NumSets++} = join(',',@$array);
1.137 matthew 9121: }
9122: #
9123: # Deal with other parameters
9124: while (my ($key,$value) = each(%Values)) {
9125: $ValuesHash{$id.'.'.$key} = $value;
1.136 matthew 9126: }
9127: #
1.646 raeburn 9128: &Apache::lonnet::appenv(\%ValuesHash);
1.130 albertel 9129: return '<img src="/cgi-bin/graph.png?'.$identifier.'" border="1" />';
1.139 matthew 9130: }
9131:
9132: ############################################################
9133: ############################################################
9134:
9135: =pod
9136:
1.157 matthew 9137: =back
9138:
1.139 matthew 9139: =head1 Statistics helper routines?
9140:
9141: Bad place for them but what the hell.
9142:
1.157 matthew 9143: =over 4
9144:
1.648 raeburn 9145: =item * &chartlink()
1.139 matthew 9146:
9147: Returns a link to the chart for a specific student.
9148:
9149: Inputs:
9150:
9151: =over 4
9152:
9153: =item $linktext: The text of the link
9154:
9155: =item $sname: The students username
9156:
9157: =item $sdomain: The students domain
9158:
9159: =back
9160:
1.157 matthew 9161: =back
9162:
1.139 matthew 9163: =cut
9164:
9165: ############################################################
9166: ############################################################
9167: sub chartlink {
9168: my ($linktext, $sname, $sdomain) = @_;
9169: my $link = '<a href="/adm/statistics?reportSelected=student_assessment'.
1.369 www 9170: '&SelectedStudent='.&escape($sname.':'.$sdomain).
1.219 albertel 9171: '&chartoutputmode='.HTML::Entities::encode('html, with all links').
1.139 matthew 9172: '">'.$linktext.'</a>';
1.153 matthew 9173: }
9174:
9175: #######################################################
9176: #######################################################
9177:
9178: =pod
9179:
9180: =head1 Course Environment Routines
1.157 matthew 9181:
9182: =over 4
1.153 matthew 9183:
1.648 raeburn 9184: =item * &restore_course_settings()
1.153 matthew 9185:
1.648 raeburn 9186: =item * &store_course_settings()
1.153 matthew 9187:
9188: Restores/Store indicated form parameters from the course environment.
9189: Will not overwrite existing values of the form parameters.
9190:
9191: Inputs:
9192: a scalar describing the data (e.g. 'chart', 'problem_analysis')
9193:
9194: a hash ref describing the data to be stored. For example:
9195:
9196: %Save_Parameters = ('Status' => 'scalar',
9197: 'chartoutputmode' => 'scalar',
9198: 'chartoutputdata' => 'scalar',
9199: 'Section' => 'array',
1.373 raeburn 9200: 'Group' => 'array',
1.153 matthew 9201: 'StudentData' => 'array',
9202: 'Maps' => 'array');
9203:
9204: Returns: both routines return nothing
9205:
1.631 raeburn 9206: =back
9207:
1.153 matthew 9208: =cut
9209:
9210: #######################################################
9211: #######################################################
9212: sub store_course_settings {
1.496 albertel 9213: return &store_settings($env{'request.course.id'},@_);
9214: }
9215:
9216: sub store_settings {
1.153 matthew 9217: # save to the environment
9218: # appenv the same items, just to be safe
1.300 albertel 9219: my $udom = $env{'user.domain'};
9220: my $uname = $env{'user.name'};
1.496 albertel 9221: my ($context,$prefix,$Settings) = @_;
1.153 matthew 9222: my %SaveHash;
9223: my %AppHash;
9224: while (my ($setting,$type) = each(%$Settings)) {
1.496 albertel 9225: my $basename = join('.','internal',$context,$prefix,$setting);
1.300 albertel 9226: my $envname = 'environment.'.$basename;
1.258 albertel 9227: if (exists($env{'form.'.$setting})) {
1.153 matthew 9228: # Save this value away
9229: if ($type eq 'scalar' &&
1.258 albertel 9230: (! exists($env{$envname}) ||
9231: $env{$envname} ne $env{'form.'.$setting})) {
9232: $SaveHash{$basename} = $env{'form.'.$setting};
9233: $AppHash{$envname} = $env{'form.'.$setting};
1.153 matthew 9234: } elsif ($type eq 'array') {
9235: my $stored_form;
1.258 albertel 9236: if (ref($env{'form.'.$setting})) {
1.153 matthew 9237: $stored_form = join(',',
9238: map {
1.369 www 9239: &escape($_);
1.258 albertel 9240: } sort(@{$env{'form.'.$setting}}));
1.153 matthew 9241: } else {
9242: $stored_form =
1.369 www 9243: &escape($env{'form.'.$setting});
1.153 matthew 9244: }
9245: # Determine if the array contents are the same.
1.258 albertel 9246: if ($stored_form ne $env{$envname}) {
1.153 matthew 9247: $SaveHash{$basename} = $stored_form;
9248: $AppHash{$envname} = $stored_form;
9249: }
9250: }
9251: }
9252: }
9253: my $put_result = &Apache::lonnet::put('environment',\%SaveHash,
1.300 albertel 9254: $udom,$uname);
1.153 matthew 9255: if ($put_result !~ /^(ok|delayed)/) {
9256: &Apache::lonnet::logthis('unable to save form parameters, '.
9257: 'got error:'.$put_result);
9258: }
9259: # Make sure these settings stick around in this session, too
1.646 raeburn 9260: &Apache::lonnet::appenv(\%AppHash);
1.153 matthew 9261: return;
9262: }
9263:
9264: sub restore_course_settings {
1.499 albertel 9265: return &restore_settings($env{'request.course.id'},@_);
1.496 albertel 9266: }
9267:
9268: sub restore_settings {
9269: my ($context,$prefix,$Settings) = @_;
1.153 matthew 9270: while (my ($setting,$type) = each(%$Settings)) {
1.258 albertel 9271: next if (exists($env{'form.'.$setting}));
1.496 albertel 9272: my $envname = 'environment.internal.'.$context.'.'.$prefix.
1.153 matthew 9273: '.'.$setting;
1.258 albertel 9274: if (exists($env{$envname})) {
1.153 matthew 9275: if ($type eq 'scalar') {
1.258 albertel 9276: $env{'form.'.$setting} = $env{$envname};
1.153 matthew 9277: } elsif ($type eq 'array') {
1.258 albertel 9278: $env{'form.'.$setting} = [
1.153 matthew 9279: map {
1.369 www 9280: &unescape($_);
1.258 albertel 9281: } split(',',$env{$envname})
1.153 matthew 9282: ];
9283: }
9284: }
9285: }
1.127 matthew 9286: }
9287:
1.618 raeburn 9288: #######################################################
9289: #######################################################
9290:
9291: =pod
9292:
9293: =head1 Domain E-mail Routines
9294:
9295: =over 4
9296:
1.648 raeburn 9297: =item * &build_recipient_list()
1.618 raeburn 9298:
1.884 raeburn 9299: Build recipient lists for five types of e-mail:
1.766 raeburn 9300: (a) Error Reports, (b) Package Updates, (c) lonstatus warnings/errors
1.884 raeburn 9301: (d) Help requests, (e) Course requests needing approval, generated by
9302: lonerrorhandler.pm, CHECKRPMS, loncron, lonsupportreq.pm and
9303: loncoursequeueadmin.pm respectively.
1.618 raeburn 9304:
9305: Inputs:
1.619 raeburn 9306: defmail (scalar - email address of default recipient),
1.618 raeburn 9307: mailing type (scalar - errormail, packagesmail, or helpdeskmail),
1.619 raeburn 9308: defdom (domain for which to retrieve configuration settings),
9309: origmail (scalar - email address of recipient from loncapa.conf,
9310: i.e., predates configuration by DC via domainprefs.pm
1.618 raeburn 9311:
1.655 raeburn 9312: Returns: comma separated list of addresses to which to send e-mail.
9313:
9314: =back
1.618 raeburn 9315:
9316: =cut
9317:
9318: ############################################################
9319: ############################################################
9320: sub build_recipient_list {
1.619 raeburn 9321: my ($defmail,$mailing,$defdom,$origmail) = @_;
1.618 raeburn 9322: my @recipients;
9323: my $otheremails;
9324: my %domconfig =
9325: &Apache::lonnet::get_dom('configuration',['contacts'],$defdom);
9326: if (ref($domconfig{'contacts'}) eq 'HASH') {
1.766 raeburn 9327: if (exists($domconfig{'contacts'}{$mailing})) {
9328: if (ref($domconfig{'contacts'}{$mailing}) eq 'HASH') {
9329: my @contacts = ('adminemail','supportemail');
9330: foreach my $item (@contacts) {
9331: if ($domconfig{'contacts'}{$mailing}{$item}) {
9332: my $addr = $domconfig{'contacts'}{$item};
9333: if (!grep(/^\Q$addr\E$/,@recipients)) {
9334: push(@recipients,$addr);
9335: }
1.619 raeburn 9336: }
1.766 raeburn 9337: $otheremails = $domconfig{'contacts'}{$mailing}{'others'};
1.618 raeburn 9338: }
9339: }
1.766 raeburn 9340: } elsif ($origmail ne '') {
9341: push(@recipients,$origmail);
1.618 raeburn 9342: }
1.619 raeburn 9343: } elsif ($origmail ne '') {
9344: push(@recipients,$origmail);
1.618 raeburn 9345: }
1.688 raeburn 9346: if (defined($defmail)) {
9347: if ($defmail ne '') {
9348: push(@recipients,$defmail);
9349: }
1.618 raeburn 9350: }
9351: if ($otheremails) {
1.619 raeburn 9352: my @others;
9353: if ($otheremails =~ /,/) {
9354: @others = split(/,/,$otheremails);
1.618 raeburn 9355: } else {
1.619 raeburn 9356: push(@others,$otheremails);
9357: }
9358: foreach my $addr (@others) {
9359: if (!grep(/^\Q$addr\E$/,@recipients)) {
9360: push(@recipients,$addr);
9361: }
1.618 raeburn 9362: }
9363: }
1.619 raeburn 9364: my $recipientlist = join(',',@recipients);
1.618 raeburn 9365: return $recipientlist;
9366: }
9367:
1.127 matthew 9368: ############################################################
9369: ############################################################
1.154 albertel 9370:
1.655 raeburn 9371: =pod
9372:
9373: =head1 Course Catalog Routines
9374:
9375: =over 4
9376:
9377: =item * &gather_categories()
9378:
9379: Converts category definitions - keys of categories hash stored in
9380: coursecategories in configuration.db on the primary library server in a
9381: domain - to an array. Also generates javascript and idx hash used to
9382: generate Domain Coordinator interface for editing Course Categories.
9383:
9384: Inputs:
1.663 raeburn 9385:
1.655 raeburn 9386: categories (reference to hash of category definitions).
1.663 raeburn 9387:
1.655 raeburn 9388: cats (reference to array of arrays/hashes which encapsulates hierarchy of
9389: categories and subcategories).
1.663 raeburn 9390:
1.655 raeburn 9391: idx (reference to hash of counters used in Domain Coordinator interface for
9392: editing Course Categories).
1.663 raeburn 9393:
1.655 raeburn 9394: jsarray (reference to array of categories used to create Javascript arrays for
9395: Domain Coordinator interface for editing Course Categories).
9396:
9397: Returns: nothing
9398:
9399: Side effects: populates cats, idx and jsarray.
9400:
9401: =cut
9402:
9403: sub gather_categories {
9404: my ($categories,$cats,$idx,$jsarray) = @_;
9405: my %counters;
9406: my $num = 0;
9407: foreach my $item (keys(%{$categories})) {
9408: my ($cat,$container,$depth) = map { &unescape($_); } split(/:/,$item);
9409: if ($container eq '' && $depth == 0) {
9410: $cats->[$depth][$categories->{$item}] = $cat;
9411: } else {
9412: $cats->[$depth]{$container}[$categories->{$item}] = $cat;
9413: }
9414: my ($escitem,$tail) = split(/:/,$item,2);
9415: if ($counters{$tail} eq '') {
9416: $counters{$tail} = $num;
9417: $num ++;
9418: }
9419: if (ref($idx) eq 'HASH') {
9420: $idx->{$item} = $counters{$tail};
9421: }
9422: if (ref($jsarray) eq 'ARRAY') {
9423: push(@{$jsarray->[$counters{$tail}]},$item);
9424: }
9425: }
9426: return;
9427: }
9428:
9429: =pod
9430:
9431: =item * &extract_categories()
9432:
9433: Used to generate breadcrumb trails for course categories.
9434:
9435: Inputs:
1.663 raeburn 9436:
1.655 raeburn 9437: categories (reference to hash of category definitions).
1.663 raeburn 9438:
1.655 raeburn 9439: cats (reference to array of arrays/hashes which encapsulates hierarchy of
9440: categories and subcategories).
1.663 raeburn 9441:
1.655 raeburn 9442: trails (reference to array of breacrumb trails for each category).
1.663 raeburn 9443:
1.655 raeburn 9444: allitems (reference to hash - key is category key
9445: (format: escaped(name):escaped(parent category):depth in hierarchy).
1.663 raeburn 9446:
1.655 raeburn 9447: idx (reference to hash of counters used in Domain Coordinator interface for
9448: editing Course Categories).
1.663 raeburn 9449:
1.655 raeburn 9450: jsarray (reference to array of categories used to create Javascript arrays for
9451: Domain Coordinator interface for editing Course Categories).
9452:
1.665 raeburn 9453: subcats (reference to hash of arrays containing all subcategories within each
9454: category, -recursive)
9455:
1.655 raeburn 9456: Returns: nothing
9457:
9458: Side effects: populates trails and allitems hash references.
9459:
9460: =cut
9461:
9462: sub extract_categories {
1.665 raeburn 9463: my ($categories,$cats,$trails,$allitems,$idx,$jsarray,$subcats) = @_;
1.655 raeburn 9464: if (ref($categories) eq 'HASH') {
9465: &gather_categories($categories,$cats,$idx,$jsarray);
9466: if (ref($cats->[0]) eq 'ARRAY') {
9467: for (my $i=0; $i<@{$cats->[0]}; $i++) {
9468: my $name = $cats->[0][$i];
9469: my $item = &escape($name).'::0';
9470: my $trailstr;
9471: if ($name eq 'instcode') {
9472: $trailstr = &mt('Official courses (with institutional codes)');
9473: } else {
9474: $trailstr = $name;
9475: }
9476: if ($allitems->{$item} eq '') {
9477: push(@{$trails},$trailstr);
9478: $allitems->{$item} = scalar(@{$trails})-1;
9479: }
9480: my @parents = ($name);
9481: if (ref($cats->[1]{$name}) eq 'ARRAY') {
9482: for (my $j=0; $j<@{$cats->[1]{$name}}; $j++) {
9483: my $category = $cats->[1]{$name}[$j];
1.665 raeburn 9484: if (ref($subcats) eq 'HASH') {
9485: push(@{$subcats->{$item}},&escape($category).':'.&escape($name).':1');
9486: }
9487: &recurse_categories($cats,2,$category,$trails,$allitems,\@parents,$subcats);
9488: }
9489: } else {
9490: if (ref($subcats) eq 'HASH') {
9491: $subcats->{$item} = [];
1.655 raeburn 9492: }
9493: }
9494: }
9495: }
9496: }
9497: return;
9498: }
9499:
9500: =pod
9501:
9502: =item *&recurse_categories()
9503:
9504: Recursively used to generate breadcrumb trails for course categories.
9505:
9506: Inputs:
1.663 raeburn 9507:
1.655 raeburn 9508: cats (reference to array of arrays/hashes which encapsulates hierarchy of
9509: categories and subcategories).
1.663 raeburn 9510:
1.655 raeburn 9511: depth (current depth in hierarchy of categories and sub-categories - 0 indexed).
1.663 raeburn 9512:
9513: category (current course category, for which breadcrumb trail is being generated).
9514:
9515: trails (reference to array of breadcrumb trails for each category).
9516:
1.655 raeburn 9517: allitems (reference to hash - key is category key
9518: (format: escaped(name):escaped(parent category):depth in hierarchy).
1.663 raeburn 9519:
1.655 raeburn 9520: parents (array containing containers directories for current category,
9521: back to top level).
9522:
9523: Returns: nothing
9524:
9525: Side effects: populates trails and allitems hash references
9526:
9527: =cut
9528:
9529: sub recurse_categories {
1.665 raeburn 9530: my ($cats,$depth,$category,$trails,$allitems,$parents,$subcats) = @_;
1.655 raeburn 9531: my $shallower = $depth - 1;
9532: if (ref($cats->[$depth]{$category}) eq 'ARRAY') {
9533: for (my $k=0; $k<@{$cats->[$depth]{$category}}; $k++) {
9534: my $name = $cats->[$depth]{$category}[$k];
9535: my $item = &escape($category).':'.&escape($parents->[-1]).':'.$shallower;
9536: my $trailstr = join(' -> ',(@{$parents},$category));
9537: if ($allitems->{$item} eq '') {
9538: push(@{$trails},$trailstr);
9539: $allitems->{$item} = scalar(@{$trails})-1;
9540: }
9541: my $deeper = $depth+1;
9542: push(@{$parents},$category);
1.665 raeburn 9543: if (ref($subcats) eq 'HASH') {
9544: my $subcat = &escape($name).':'.$category.':'.$depth;
9545: for (my $j=@{$parents}; $j>=0; $j--) {
9546: my $higher;
9547: if ($j > 0) {
9548: $higher = &escape($parents->[$j]).':'.
9549: &escape($parents->[$j-1]).':'.$j;
9550: } else {
9551: $higher = &escape($parents->[$j]).'::'.$j;
9552: }
9553: push(@{$subcats->{$higher}},$subcat);
9554: }
9555: }
9556: &recurse_categories($cats,$deeper,$name,$trails,$allitems,$parents,
9557: $subcats);
1.655 raeburn 9558: pop(@{$parents});
9559: }
9560: } else {
9561: my $item = &escape($category).':'.&escape($parents->[-1]).':'.$shallower;
9562: my $trailstr = join(' -> ',(@{$parents},$category));
9563: if ($allitems->{$item} eq '') {
9564: push(@{$trails},$trailstr);
9565: $allitems->{$item} = scalar(@{$trails})-1;
9566: }
9567: }
9568: return;
9569: }
9570:
1.663 raeburn 9571: =pod
9572:
9573: =item *&assign_categories_table()
9574:
9575: Create a datatable for display of hierarchical categories in a domain,
9576: with checkboxes to allow a course to be categorized.
9577:
9578: Inputs:
9579:
9580: cathash - reference to hash of categories defined for the domain (from
9581: configuration.db)
9582:
9583: currcat - scalar with an & separated list of categories assigned to a course.
9584:
9585: Returns: $output (markup to be displayed)
9586:
9587: =cut
9588:
9589: sub assign_categories_table {
9590: my ($cathash,$currcat) = @_;
9591: my $output;
9592: if (ref($cathash) eq 'HASH') {
9593: my (@cats,@trails,%allitems,%idx,@jsarray,@path,$maxdepth);
9594: &extract_categories($cathash,\@cats,\@trails,\%allitems,\%idx,\@jsarray);
9595: $maxdepth = scalar(@cats);
9596: if (@cats > 0) {
9597: my $itemcount = 0;
9598: if (ref($cats[0]) eq 'ARRAY') {
9599: $output = &Apache::loncommon::start_data_table();
9600: my @currcategories;
9601: if ($currcat ne '') {
9602: @currcategories = split('&',$currcat);
9603: }
9604: for (my $i=0; $i<@{$cats[0]}; $i++) {
9605: my $parent = $cats[0][$i];
9606: my $css_class = $itemcount%2?' class="LC_odd_row"':'';
9607: next if ($parent eq 'instcode');
9608: my $item = &escape($parent).'::0';
9609: my $checked = '';
9610: if (@currcategories > 0) {
9611: if (grep(/^\Q$item\E$/,@currcategories)) {
1.772 bisitz 9612: $checked = ' checked="checked"';
1.663 raeburn 9613: }
9614: }
1.675 raeburn 9615: $output .= '<tr '.$css_class.'><td><span class="LC_nobreak">'.
9616: '<input type="checkbox" name="usecategory" value="'.
9617: $item.'"'.$checked.' />'.$parent.'</span>'.
9618: '<input type="hidden" name="catname" value="'.$parent.'" /></td>';
1.663 raeburn 9619: my $depth = 1;
9620: push(@path,$parent);
9621: $output .= &assign_category_rows($itemcount,\@cats,$depth,$parent,\@path,\@currcategories);
9622: pop(@path);
9623: $output .= '</tr><tr><td colspan="'.$maxdepth.'" class="LC_row_separator"></td></tr>';
9624: $itemcount ++;
9625: }
9626: $output .= &Apache::loncommon::end_data_table();
9627: }
9628: }
9629: }
9630: return $output;
9631: }
9632:
9633: =pod
9634:
9635: =item *&assign_category_rows()
9636:
9637: Create a datatable row for display of nested categories in a domain,
9638: with checkboxes to allow a course to be categorized,called recursively.
9639:
9640: Inputs:
9641:
9642: itemcount - track row number for alternating colors
9643:
9644: cats - reference to array of arrays/hashes which encapsulates hierarchy of
9645: categories and subcategories.
9646:
9647: depth - current depth in hierarchy of categories and sub-categories - 0 indexed.
9648:
9649: parent - parent of current category item
9650:
9651: path - Array containing all categories back up through the hierarchy from the
9652: current category to the top level.
9653:
9654: currcategories - reference to array of current categories assigned to the course
9655:
9656: Returns: $output (markup to be displayed).
9657:
9658: =cut
9659:
9660: sub assign_category_rows {
9661: my ($itemcount,$cats,$depth,$parent,$path,$currcategories) = @_;
9662: my ($text,$name,$item,$chgstr);
9663: if (ref($cats) eq 'ARRAY') {
9664: my $maxdepth = scalar(@{$cats});
9665: if (ref($cats->[$depth]) eq 'HASH') {
9666: if (ref($cats->[$depth]{$parent}) eq 'ARRAY') {
9667: my $numchildren = @{$cats->[$depth]{$parent}};
9668: my $css_class = $itemcount%2?' class="LC_odd_row"':'';
9669: $text .= '<td><table class="LC_datatable">';
9670: for (my $j=0; $j<$numchildren; $j++) {
9671: $name = $cats->[$depth]{$parent}[$j];
9672: $item = &escape($name).':'.&escape($parent).':'.$depth;
9673: my $deeper = $depth+1;
9674: my $checked = '';
9675: if (ref($currcategories) eq 'ARRAY') {
9676: if (@{$currcategories} > 0) {
9677: if (grep(/^\Q$item\E$/,@{$currcategories})) {
1.772 bisitz 9678: $checked = ' checked="checked"';
1.663 raeburn 9679: }
9680: }
9681: }
1.664 raeburn 9682: $text .= '<tr><td><span class="LC_nobreak"><label>'.
9683: '<input type="checkbox" name="usecategory" value="'.
1.675 raeburn 9684: $item.'"'.$checked.' />'.$name.'</label></span>'.
9685: '<input type="hidden" name="catname" value="'.$name.'" />'.
9686: '</td><td>';
1.663 raeburn 9687: if (ref($path) eq 'ARRAY') {
9688: push(@{$path},$name);
9689: $text .= &assign_category_rows($itemcount,$cats,$deeper,$name,$path,$currcategories);
9690: pop(@{$path});
9691: }
9692: $text .= '</td></tr>';
9693: }
9694: $text .= '</table></td>';
9695: }
9696: }
9697: }
9698: return $text;
9699: }
9700:
1.655 raeburn 9701: ############################################################
9702: ############################################################
9703:
9704:
1.443 albertel 9705: sub commit_customrole {
1.664 raeburn 9706: my ($udom,$uname,$url,$three,$four,$five,$start,$end,$context) = @_;
1.630 raeburn 9707: my $output = &mt('Assigning custom role').' "'.$five.'" by '.$four.':'.$three.' in '.$url.
1.443 albertel 9708: ($start?', '.&mt('starting').' '.localtime($start):'').
9709: ($end?', ending '.localtime($end):'').': <b>'.
9710: &Apache::lonnet::assigncustomrole(
1.664 raeburn 9711: $udom,$uname,$url,$three,$four,$five,$end,$start,undef,undef,$context).
1.443 albertel 9712: '</b><br />';
9713: return $output;
9714: }
9715:
9716: sub commit_standardrole {
1.541 raeburn 9717: my ($udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context) = @_;
9718: my ($output,$logmsg,$linefeed);
9719: if ($context eq 'auto') {
9720: $linefeed = "\n";
9721: } else {
9722: $linefeed = "<br />\n";
9723: }
1.443 albertel 9724: if ($three eq 'st') {
1.541 raeburn 9725: my $result = &commit_studentrole(\$logmsg,$udom,$uname,$url,$three,$start,$end,
9726: $one,$two,$sec,$context);
9727: if (($result =~ /^error/) || ($result eq 'not_in_class') ||
1.626 raeburn 9728: ($result eq 'unknown_course') || ($result eq 'refused')) {
9729: $output = $logmsg.' '.&mt('Error: ').$result."\n";
1.443 albertel 9730: } else {
1.541 raeburn 9731: $output = $logmsg.$linefeed.&mt('Assigning').' '.$three.' in '.$url.
1.443 albertel 9732: ($start?', '.&mt('starting').' '.localtime($start):'').
1.541 raeburn 9733: ($end?', '.&mt('ending').' '.localtime($end):'').': ';
9734: if ($context eq 'auto') {
9735: $output .= $result.$linefeed.&mt('Add to classlist').': ok';
9736: } else {
9737: $output .= '<b>'.$result.'</b>'.$linefeed.
9738: &mt('Add to classlist').': <b>ok</b>';
9739: }
9740: $output .= $linefeed;
1.443 albertel 9741: }
9742: } else {
9743: $output = &mt('Assigning').' '.$three.' in '.$url.
9744: ($start?', '.&mt('starting').' '.localtime($start):'').
1.541 raeburn 9745: ($end?', '.&mt('ending').' '.localtime($end):'').': ';
1.652 raeburn 9746: my $result = &Apache::lonnet::assignrole($udom,$uname,$url,$three,$end,$start,'','',$context);
1.541 raeburn 9747: if ($context eq 'auto') {
9748: $output .= $result.$linefeed;
9749: } else {
9750: $output .= '<b>'.$result.'</b>'.$linefeed;
9751: }
1.443 albertel 9752: }
9753: return $output;
9754: }
9755:
9756: sub commit_studentrole {
1.541 raeburn 9757: my ($logmsg,$udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context) = @_;
1.626 raeburn 9758: my ($result,$linefeed,$oldsecurl,$newsecurl);
1.541 raeburn 9759: if ($context eq 'auto') {
9760: $linefeed = "\n";
9761: } else {
9762: $linefeed = '<br />'."\n";
9763: }
1.443 albertel 9764: if (defined($one) && defined($two)) {
9765: my $cid=$one.'_'.$two;
9766: my $oldsec=&Apache::lonnet::getsection($udom,$uname,$cid);
9767: my $secchange = 0;
9768: my $expire_role_result;
9769: my $modify_section_result;
1.628 raeburn 9770: if ($oldsec ne '-1') {
9771: if ($oldsec ne $sec) {
1.443 albertel 9772: $secchange = 1;
1.628 raeburn 9773: my $now = time;
1.443 albertel 9774: my $uurl='/'.$cid;
9775: $uurl=~s/\_/\//g;
9776: if ($oldsec) {
9777: $uurl.='/'.$oldsec;
9778: }
1.626 raeburn 9779: $oldsecurl = $uurl;
1.628 raeburn 9780: $expire_role_result =
1.652 raeburn 9781: &Apache::lonnet::assignrole($udom,$uname,$uurl,'st',$now,'','',$context);
1.628 raeburn 9782: if ($env{'request.course.sec'} ne '') {
9783: if ($expire_role_result eq 'refused') {
9784: my @roles = ('st');
9785: my @statuses = ('previous');
9786: my @roledoms = ($one);
9787: my $withsec = 1;
9788: my %roleshash =
9789: &Apache::lonnet::get_my_roles($uname,$udom,'userroles',
9790: \@statuses,\@roles,\@roledoms,$withsec);
9791: if (defined ($roleshash{$two.':'.$one.':st:'.$oldsec})) {
9792: my ($oldstart,$oldend) =
9793: split(':',$roleshash{$two.':'.$one.':st:'.$oldsec});
9794: if ($oldend > 0 && $oldend <= $now) {
9795: $expire_role_result = 'ok';
9796: }
9797: }
9798: }
9799: }
1.443 albertel 9800: $result = $expire_role_result;
9801: }
9802: }
9803: if (($expire_role_result eq 'ok') || ($secchange == 0)) {
1.652 raeburn 9804: $modify_section_result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,'','',$cid,'',$context);
1.443 albertel 9805: if ($modify_section_result =~ /^ok/) {
9806: if ($secchange == 1) {
1.628 raeburn 9807: if ($sec eq '') {
9808: $$logmsg .= &mt('Section for [_1] switched from (possibly expired) old section: [_2] to student role without a section.',$uname,$oldsec).$linefeed;
9809: } else {
9810: $$logmsg .= &mt('Section for [_1] switched from (possibly expired) old section: [_2] to new section: [_3].',$uname,$oldsec,$sec).$linefeed;
9811: }
1.443 albertel 9812: } elsif ($oldsec eq '-1') {
1.628 raeburn 9813: if ($sec eq '') {
9814: $$logmsg .= &mt('New student role without a section for [_1] in course [_2].',$uname,$cid).$linefeed;
9815: } else {
9816: $$logmsg .= &mt('New student role for [_1] in section [_2] in course [_3].',$uname,$sec,$cid).$linefeed;
9817: }
1.443 albertel 9818: } else {
1.628 raeburn 9819: if ($sec eq '') {
9820: $$logmsg .= &mt('Student [_1] assigned to course [_2] without a section.',$uname,$cid).$linefeed;
9821: } else {
9822: $$logmsg .= &mt('Student [_1] assigned to section [_2] in course [_3].',$uname,$sec,$cid).$linefeed;
9823: }
1.443 albertel 9824: }
9825: } else {
1.628 raeburn 9826: if ($secchange) {
9827: $$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;
9828: } else {
9829: $$logmsg .= &mt('Error when attempting to modify role for [_1] for section: "[_2]" in course [_3] -error:',$uname,$sec,$cid).' '.$modify_section_result.$linefeed;
9830: }
1.443 albertel 9831: }
9832: $result = $modify_section_result;
9833: } elsif ($secchange == 1) {
1.628 raeburn 9834: if ($oldsec eq '') {
9835: $$logmsg .= &mt('Error when attempting to expire existing role without a section for [_1] in course [_3] -error: ',$uname,$cid).' '.$expire_role_result.$linefeed;
9836: } else {
9837: $$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;
9838: }
1.626 raeburn 9839: if ($expire_role_result eq 'refused') {
9840: my $newsecurl = '/'.$cid;
9841: $newsecurl =~ s/\_/\//g;
9842: if ($sec ne '') {
9843: $newsecurl.='/'.$sec;
9844: }
9845: if (&Apache::lonnet::allowed('cst',$newsecurl) && !(&Apache::lonnet::allowed('cst',$oldsecurl))) {
9846: if ($sec eq '') {
9847: $$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;
9848: } else {
9849: $$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;
9850: }
9851: }
9852: }
1.443 albertel 9853: }
9854: } else {
1.626 raeburn 9855: $$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 9856: $result = "error: incomplete course id\n";
9857: }
9858: return $result;
9859: }
9860:
9861: ############################################################
9862: ############################################################
9863:
1.566 albertel 9864: sub check_clone {
1.578 raeburn 9865: my ($args,$linefeed) = @_;
1.566 albertel 9866: my $cloneid='/'.$args->{'clonedomain'}.'/'.$args->{'clonecourse'};
9867: my ($clonecrsudom,$clonecrsunum)= &LONCAPA::split_courseid($cloneid);
9868: my $clonehome=&Apache::lonnet::homeserver($clonecrsunum,$clonecrsudom);
9869: my $clonemsg;
9870: my $can_clone = 0;
9871:
9872: if ($clonehome eq 'no_host') {
1.578 raeburn 9873: $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 9874: } else {
9875: my %clonedesc = &Apache::lonnet::coursedescription($cloneid,{'one_time' => 1});
1.882 raeburn 9876: if (($env{'request.role.domain'} eq $args->{'clonedomain'}) &&
9877: (&Apache::lonnet::allowed('ccc',$env{'request.role.domain'}))) {
1.566 albertel 9878: $can_clone = 1;
9879: } else {
9880: my %clonehash = &Apache::lonnet::get('environment',['cloners'],
9881: $args->{'clonedomain'},$args->{'clonecourse'});
9882: my @cloners = split(/,/,$clonehash{'cloners'});
1.578 raeburn 9883: if (grep(/^\*$/,@cloners)) {
9884: $can_clone = 1;
9885: } elsif (grep(/^\*\:\Q$args->{'ccdomain'}\E$/,@cloners)) {
9886: $can_clone = 1;
9887: } else {
9888: my %roleshash =
9889: &Apache::lonnet::get_my_roles($args->{'ccuname'},
9890: $args->{'ccdomain'},
9891: 'userroles',['active'],['cc'],
9892: [$args->{'clonedomain'}]);
9893: if (($roleshash{$args->{'clonecourse'}.':'.$args->{'clonedomain'}.':cc'}) || (grep(/^\Q$args->{'ccuname'}\E:\Q$args->{'ccdomain'}\E$/,@cloners))) {
9894: $can_clone = 1;
9895: } else {
9896: $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'});
9897: }
1.566 albertel 9898: }
1.578 raeburn 9899: }
1.566 albertel 9900: }
9901: return ($can_clone, $clonemsg, $cloneid, $clonehome);
9902: }
9903:
1.444 albertel 9904: sub construct_course {
1.885 raeburn 9905: my ($args,$logmsg,$courseid,$crsudom,$crsunum,$udom,$uname,$context,$cnum,$category) = @_;
1.444 albertel 9906: my $outcome;
1.541 raeburn 9907: my $linefeed = '<br />'."\n";
9908: if ($context eq 'auto') {
9909: $linefeed = "\n";
9910: }
1.566 albertel 9911:
9912: #
9913: # Are we cloning?
9914: #
9915: my ($can_clone, $clonemsg, $cloneid, $clonehome);
9916: if (($args->{'clonecourse'}) && ($args->{'clonedomain'})) {
1.578 raeburn 9917: ($can_clone, $clonemsg, $cloneid, $clonehome) = &check_clone($args,$linefeed);
1.566 albertel 9918: if ($context ne 'auto') {
1.578 raeburn 9919: if ($clonemsg ne '') {
9920: $clonemsg = '<span class="LC_error">'.$clonemsg.'</span>';
9921: }
1.566 albertel 9922: }
9923: $outcome .= $clonemsg.$linefeed;
9924:
9925: if (!$can_clone) {
9926: return (0,$outcome);
9927: }
9928: }
9929:
1.444 albertel 9930: #
9931: # Open course
9932: #
9933: my $crstype = lc($args->{'crstype'});
9934: my %cenv=();
9935: $$courseid=&Apache::lonnet::createcourse($args->{'course_domain'},
9936: $args->{'cdescr'},
9937: $args->{'curl'},
9938: $args->{'course_home'},
9939: $args->{'nonstandard'},
9940: $args->{'crscode'},
9941: $args->{'ccuname'}.':'.
9942: $args->{'ccdomain'},
1.882 raeburn 9943: $args->{'crstype'},
1.885 raeburn 9944: $cnum,$context,$category);
1.444 albertel 9945:
9946: # Note: The testing routines depend on this being output; see
9947: # Utils::Course. This needs to at least be output as a comment
9948: # if anyone ever decides to not show this, and Utils::Course::new
9949: # will need to be suitably modified.
1.541 raeburn 9950: $outcome .= &mt('New LON-CAPA [_1] ID: [_2]',$crstype,$$courseid).$linefeed;
1.444 albertel 9951: #
9952: # Check if created correctly
9953: #
1.479 albertel 9954: ($$crsudom,$$crsunum)= &LONCAPA::split_courseid($$courseid);
1.444 albertel 9955: my $crsuhome=&Apache::lonnet::homeserver($$crsunum,$$crsudom);
1.541 raeburn 9956: $outcome .= &mt('Created on').': '.$crsuhome.$linefeed;
1.566 albertel 9957:
1.444 albertel 9958: #
1.566 albertel 9959: # Do the cloning
9960: #
9961: if ($can_clone && $cloneid) {
9962: $clonemsg = &mt('Cloning [_1] from [_2]',$crstype,$clonehome);
9963: if ($context ne 'auto') {
9964: $clonemsg = '<span class="LC_success">'.$clonemsg.'</span>';
9965: }
9966: $outcome .= $clonemsg.$linefeed;
9967: my %oldcenv=&Apache::lonnet::dump('environment',$$crsudom,$$crsunum);
1.444 albertel 9968: # Copy all files
1.637 www 9969: &Apache::lonclonecourse::copycoursefiles($cloneid,$$courseid,$args->{'datemode'},$args->{'dateshift'});
1.444 albertel 9970: # Restore URL
1.566 albertel 9971: $cenv{'url'}=$oldcenv{'url'};
1.444 albertel 9972: # Restore title
1.566 albertel 9973: $cenv{'description'}=$oldcenv{'description'};
1.444 albertel 9974: # Mark as cloned
1.566 albertel 9975: $cenv{'clonedfrom'}=$cloneid;
1.638 www 9976: # Need to clone grading mode
9977: my %newenv=&Apache::lonnet::get('environment',['grading'],$$crsudom,$$crsunum);
9978: $cenv{'grading'}=$newenv{'grading'};
9979: # Do not clone these environment entries
9980: &Apache::lonnet::del('environment',
9981: ['default_enrollment_start_date',
9982: 'default_enrollment_end_date',
9983: 'question.email',
9984: 'policy.email',
9985: 'comment.email',
9986: 'pch.users.denied',
1.725 raeburn 9987: 'plc.users.denied',
9988: 'hidefromcat',
9989: 'categories'],
1.638 www 9990: $$crsudom,$$crsunum);
1.444 albertel 9991: }
1.566 albertel 9992:
1.444 albertel 9993: #
9994: # Set environment (will override cloned, if existing)
9995: #
9996: my @sections = ();
9997: my @xlists = ();
9998: if ($args->{'crstype'}) {
9999: $cenv{'type'}=$args->{'crstype'};
10000: }
10001: if ($args->{'crsid'}) {
10002: $cenv{'courseid'}=$args->{'crsid'};
10003: }
10004: if ($args->{'crscode'}) {
10005: $cenv{'internal.coursecode'}=$args->{'crscode'};
10006: }
10007: if ($args->{'crsquota'} ne '') {
10008: $cenv{'internal.coursequota'}=$args->{'crsquota'};
10009: } else {
10010: $cenv{'internal.coursequota'}=$args->{'crsquota'} = 20;
10011: }
10012: if ($args->{'ccuname'}) {
10013: $cenv{'internal.courseowner'} = $args->{'ccuname'}.
10014: ':'.$args->{'ccdomain'};
10015: } else {
10016: $cenv{'internal.courseowner'} = $args->{'curruser'};
10017: }
10018: my @badclasses = (); # Used to accumulate sections/crosslistings that did not pass classlist access check for course owner.
10019: if ($args->{'crssections'}) {
10020: $cenv{'internal.sectionnums'} = '';
10021: if ($args->{'crssections'} =~ m/,/) {
10022: @sections = split/,/,$args->{'crssections'};
10023: } else {
10024: $sections[0] = $args->{'crssections'};
10025: }
10026: if (@sections > 0) {
10027: foreach my $item (@sections) {
10028: my ($sec,$gp) = split/:/,$item;
10029: my $class = $args->{'crscode'}.$sec;
10030: my $addcheck = &Apache::lonnet::auto_new_course($$crsunum,$$crsudom,$class,$cenv{'internal.courseowner'});
10031: $cenv{'internal.sectionnums'} .= $item.',';
10032: unless ($addcheck eq 'ok') {
10033: push @badclasses, $class;
10034: }
10035: }
10036: $cenv{'internal.sectionnums'} =~ s/,$//;
10037: }
10038: }
10039: # do not hide course coordinator from staff listing,
10040: # even if privileged
10041: $cenv{'nothideprivileged'}=$args->{'ccuname'}.':'.$args->{'ccdomain'};
10042: # add crosslistings
10043: if ($args->{'crsxlist'}) {
10044: $cenv{'internal.crosslistings'}='';
10045: if ($args->{'crsxlist'} =~ m/,/) {
10046: @xlists = split/,/,$args->{'crsxlist'};
10047: } else {
10048: $xlists[0] = $args->{'crsxlist'};
10049: }
10050: if (@xlists > 0) {
10051: foreach my $item (@xlists) {
10052: my ($xl,$gp) = split/:/,$item;
10053: my $addcheck = &Apache::lonnet::auto_new_course($$crsunum,$$crsudom,$xl,$cenv{'internal.courseowner'});
10054: $cenv{'internal.crosslistings'} .= $item.',';
10055: unless ($addcheck eq 'ok') {
10056: push @badclasses, $xl;
10057: }
10058: }
10059: $cenv{'internal.crosslistings'} =~ s/,$//;
10060: }
10061: }
10062: if ($args->{'autoadds'}) {
10063: $cenv{'internal.autoadds'}=$args->{'autoadds'};
10064: }
10065: if ($args->{'autodrops'}) {
10066: $cenv{'internal.autodrops'}=$args->{'autodrops'};
10067: }
10068: # check for notification of enrollment changes
10069: my @notified = ();
10070: if ($args->{'notify_owner'}) {
10071: if ($args->{'ccuname'} ne '') {
10072: push(@notified,$args->{'ccuname'}.':'.$args->{'ccdomain'});
10073: }
10074: }
10075: if ($args->{'notify_dc'}) {
10076: if ($uname ne '') {
1.630 raeburn 10077: push(@notified,$uname.':'.$udom);
1.444 albertel 10078: }
10079: }
10080: if (@notified > 0) {
10081: my $notifylist;
10082: if (@notified > 1) {
10083: $notifylist = join(',',@notified);
10084: } else {
10085: $notifylist = $notified[0];
10086: }
10087: $cenv{'internal.notifylist'} = $notifylist;
10088: }
10089: if (@badclasses > 0) {
10090: my %lt=&Apache::lonlocal::texthash(
10091: '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',
10092: 'dnhr' => 'does not have rights to access enrollment in these classes',
10093: 'adby' => 'as determined by the policies of your institution on access to official classlists'
10094: );
1.541 raeburn 10095: my $badclass_msg = $cenv{'internal.courseowner'}.') - '.$lt{'dnhr'}.
10096: ' ('.$lt{'adby'}.')';
10097: if ($context eq 'auto') {
10098: $outcome .= $badclass_msg.$linefeed;
1.566 albertel 10099: $outcome .= '<div class="LC_warning">'.$badclass_msg.$linefeed.'<ul>'."\n";
1.541 raeburn 10100: foreach my $item (@badclasses) {
10101: if ($context eq 'auto') {
10102: $outcome .= " - $item\n";
10103: } else {
10104: $outcome .= "<li>$item</li>\n";
10105: }
10106: }
10107: if ($context eq 'auto') {
10108: $outcome .= $linefeed;
10109: } else {
1.566 albertel 10110: $outcome .= "</ul><br /><br /></div>\n";
1.541 raeburn 10111: }
10112: }
1.444 albertel 10113: }
10114: if ($args->{'no_end_date'}) {
10115: $args->{'endaccess'} = 0;
10116: }
10117: $cenv{'internal.autostart'}=$args->{'enrollstart'};
10118: $cenv{'internal.autoend'}=$args->{'enrollend'};
10119: $cenv{'default_enrollment_start_date'}=$args->{'startaccess'};
10120: $cenv{'default_enrollment_end_date'}=$args->{'endaccess'};
10121: if ($args->{'showphotos'}) {
10122: $cenv{'internal.showphotos'}=$args->{'showphotos'};
10123: }
10124: $cenv{'internal.authtype'} = $args->{'authtype'};
10125: $cenv{'internal.autharg'} = $args->{'autharg'};
10126: if ( ($cenv{'internal.authtype'} =~ /^krb/) && ($cenv{'internal.autoadds'} == 1)) {
10127: if (! defined($cenv{'internal.autharg'}) || $cenv{'internal.autharg'} eq '') {
1.541 raeburn 10128: 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');
10129: if ($context eq 'auto') {
10130: $outcome .= $krb_msg;
10131: } else {
1.566 albertel 10132: $outcome .= '<span class="LC_error">'.$krb_msg.'</span>';
1.541 raeburn 10133: }
10134: $outcome .= $linefeed;
1.444 albertel 10135: }
10136: }
10137: if (($args->{'ccdomain'}) && ($args->{'ccuname'})) {
10138: if ($args->{'setpolicy'}) {
10139: $cenv{'policy.email'}=$args->{'ccuname'}.':'.$args->{'ccdomain'};
10140: }
10141: if ($args->{'setcontent'}) {
10142: $cenv{'question.email'}=$args->{'ccuname'}.':'.$args->{'ccdomain'};
10143: }
10144: }
10145: if ($args->{'reshome'}) {
10146: $cenv{'reshome'}=$args->{'reshome'}.'/';
10147: $cenv{'reshome'}=~s/\/+$/\//;
10148: }
10149: #
10150: # course has keyed access
10151: #
10152: if ($args->{'setkeys'}) {
10153: $cenv{'keyaccess'}='yes';
10154: }
10155: # if specified, key authority is not course, but user
10156: # only active if keyaccess is yes
10157: if ($args->{'keyauth'}) {
1.487 albertel 10158: my ($user,$domain) = split(':',$args->{'keyauth'});
10159: $user = &LONCAPA::clean_username($user);
10160: $domain = &LONCAPA::clean_username($domain);
1.488 foxr 10161: if ($user ne '' && $domain ne '') {
1.487 albertel 10162: $cenv{'keyauth'}=$user.':'.$domain;
1.444 albertel 10163: }
10164: }
10165:
10166: if ($args->{'disresdis'}) {
10167: $cenv{'pch.roles.denied'}='st';
10168: }
10169: if ($args->{'disablechat'}) {
10170: $cenv{'plc.roles.denied'}='st';
10171: }
10172:
10173: # Record we've not yet viewed the Course Initialization Helper for this
10174: # course
10175: $cenv{'course.helper.not.run'} = 1;
10176: #
10177: # Use new Randomseed
10178: #
10179: $cenv{'rndseed'}=&Apache::lonnet::latest_rnd_algorithm_id();;
10180: $cenv{'receiptalg'}=&Apache::lonnet::latest_receipt_algorithm_id();;
10181: #
10182: # The encryption code and receipt prefix for this course
10183: #
10184: $cenv{'internal.encseed'}=$Apache::lonnet::perlvar{'lonReceipt'}.$$.time.int(rand(9999));
10185: $cenv{'internal.encpref'}=100+int(9*rand(99));
10186: #
10187: # By default, use standard grading
10188: if (!defined($cenv{'grading'})) { $cenv{'grading'} = 'standard'; }
10189:
1.541 raeburn 10190: $outcome .= $linefeed.&mt('Setting environment').': '.
10191: &Apache::lonnet::put('environment',\%cenv,$$crsudom,$$crsunum).$linefeed;
1.444 albertel 10192: #
10193: # Open all assignments
10194: #
10195: if ($args->{'openall'}) {
10196: my $storeunder=$$crsudom.'_'.$$crsunum.'.0.opendate';
10197: my %storecontent = ($storeunder => time,
10198: $storeunder.'.type' => 'date_start');
10199:
10200: $outcome .= &mt('Opening all assignments').': '.&Apache::lonnet::cput
1.541 raeburn 10201: ('resourcedata',\%storecontent,$$crsudom,$$crsunum).$linefeed;
1.444 albertel 10202: }
10203: #
10204: # Set first page
10205: #
10206: unless (($args->{'nonstandard'}) || ($args->{'firstres'} eq 'blank')
10207: || ($cloneid)) {
1.445 albertel 10208: use LONCAPA::map;
1.444 albertel 10209: $outcome .= &mt('Setting first resource').': ';
1.445 albertel 10210:
10211: my $map = '/uploaded/'.$$crsudom.'/'.$$crsunum.'/default.sequence';
10212: my ($errtext,$fatal)=&LONCAPA::map::mapread($map);
10213:
1.444 albertel 10214: $outcome .= ($fatal?$errtext:'read ok').' - ';
10215: my $title; my $url;
10216: if ($args->{'firstres'} eq 'syl') {
1.690 bisitz 10217: $title=&mt('Syllabus');
1.444 albertel 10218: $url='/public/'.$$crsudom.'/'.$$crsunum.'/syllabus';
10219: } else {
1.690 bisitz 10220: $title=&mt('Navigate Contents');
1.444 albertel 10221: $url='/adm/navmaps';
10222: }
1.445 albertel 10223:
10224: $LONCAPA::map::resources[1]=$title.':'.$url.':false:start:res';
10225: (my $outtext,$errtext) = &LONCAPA::map::storemap($map,1);
10226:
10227: if ($errtext) { $fatal=2; }
1.541 raeburn 10228: $outcome .= ($fatal?$errtext:'write ok').$linefeed;
1.444 albertel 10229: }
1.566 albertel 10230:
10231: return (1,$outcome);
1.444 albertel 10232: }
10233:
10234: ############################################################
10235: ############################################################
10236:
1.378 raeburn 10237: sub course_type {
10238: my ($cid) = @_;
10239: if (!defined($cid)) {
10240: $cid = $env{'request.course.id'};
10241: }
1.404 albertel 10242: if (defined($env{'course.'.$cid.'.type'})) {
10243: return $env{'course.'.$cid.'.type'};
1.378 raeburn 10244: } else {
10245: return 'Course';
1.377 raeburn 10246: }
10247: }
1.156 albertel 10248:
1.406 raeburn 10249: sub group_term {
10250: my $crstype = &course_type();
10251: my %names = (
10252: 'Course' => 'group',
1.865 raeburn 10253: 'Community' => 'group',
1.406 raeburn 10254: );
10255: return $names{$crstype};
10256: }
10257:
1.156 albertel 10258: sub icon {
10259: my ($file)=@_;
1.505 albertel 10260: my $curfext = lc((split(/\./,$file))[-1]);
1.168 albertel 10261: my $iconname=$Apache::lonnet::perlvar{'lonIconsURL'}.'/unknown.gif';
1.156 albertel 10262: my $embstyle = &Apache::loncommon::fileembstyle($curfext);
1.168 albertel 10263: if (!(!defined($embstyle) || $embstyle eq 'unk' || $embstyle eq 'hdn')) {
10264: if (-e $Apache::lonnet::perlvar{'lonDocRoot'}.'/'.
10265: $Apache::lonnet::perlvar{'lonIconsURL'}.'/'.
10266: $curfext.".gif") {
10267: $iconname=$Apache::lonnet::perlvar{'lonIconsURL'}.'/'.
10268: $curfext.".gif";
10269: }
10270: }
1.249 albertel 10271: return &lonhttpdurl($iconname);
1.154 albertel 10272: }
1.84 albertel 10273:
1.575 albertel 10274: sub lonhttpdurl {
1.692 www 10275: #
10276: # Had been used for "small fry" static images on separate port 8080.
10277: # Modify here if lightweight http functionality desired again.
10278: # Currently eliminated due to increasing firewall issues.
10279: #
1.575 albertel 10280: my ($url)=@_;
1.692 www 10281: return $url;
1.215 albertel 10282: }
10283:
1.213 albertel 10284: sub connection_aborted {
10285: my ($r)=@_;
10286: $r->print(" ");$r->rflush();
10287: my $c = $r->connection;
10288: return $c->aborted();
10289: }
10290:
1.221 foxr 10291: # Escapes strings that may have embedded 's that will be put into
1.222 foxr 10292: # strings as 'strings'.
10293: sub escape_single {
1.221 foxr 10294: my ($input) = @_;
1.223 albertel 10295: $input =~ s/\\/\\\\/g; # Escape the \'s..(must be first)>
1.221 foxr 10296: $input =~ s/\'/\\\'/g; # Esacpe the 's....
10297: return $input;
10298: }
1.223 albertel 10299:
1.222 foxr 10300: # Same as escape_single, but escape's "'s This
10301: # can be used for "strings"
10302: sub escape_double {
10303: my ($input) = @_;
10304: $input =~ s/\\/\\\\/g; # Escape the /'s..(must be first)>
10305: $input =~ s/\"/\\\"/g; # Esacpe the "s....
10306: return $input;
10307: }
1.223 albertel 10308:
1.222 foxr 10309: # Escapes the last element of a full URL.
10310: sub escape_url {
10311: my ($url) = @_;
1.238 raeburn 10312: my @urlslices = split(/\//, $url,-1);
1.369 www 10313: my $lastitem = &escape(pop(@urlslices));
1.223 albertel 10314: return join('/',@urlslices).'/'.$lastitem;
1.222 foxr 10315: }
1.462 albertel 10316:
1.820 raeburn 10317: sub compare_arrays {
10318: my ($arrayref1,$arrayref2) = @_;
10319: my (@difference,%count);
10320: @difference = ();
10321: %count = ();
10322: if ((ref($arrayref1) eq 'ARRAY') && (ref($arrayref2) eq 'ARRAY')) {
10323: foreach my $element (@{$arrayref1}, @{$arrayref2}) { $count{$element}++; }
10324: foreach my $element (keys(%count)) {
10325: if ($count{$element} == 1) {
10326: push(@difference,$element);
10327: }
10328: }
10329: }
10330: return @difference;
10331: }
10332:
1.817 bisitz 10333: # -------------------------------------------------------- Initialize user login
1.462 albertel 10334: sub init_user_environment {
1.463 albertel 10335: my ($r, $username, $domain, $authhost, $form, $args) = @_;
1.462 albertel 10336: my $lonids=$Apache::lonnet::perlvar{'lonIDsDir'};
10337:
10338: my $public=($username eq 'public' && $domain eq 'public');
10339:
10340: # See if old ID present, if so, remove
10341:
10342: my ($filename,$cookie,$userroles);
10343: my $now=time;
10344:
10345: if ($public) {
10346: my $max_public=100;
10347: my $oldest;
10348: my $oldest_time=0;
10349: for(my $next=1;$next<=$max_public;$next++) {
10350: if (-e $lonids."/publicuser_$next.id") {
10351: my $mtime=(stat($lonids."/publicuser_$next.id"))[9];
10352: if ($mtime<$oldest_time || !$oldest_time) {
10353: $oldest_time=$mtime;
10354: $oldest=$next;
10355: }
10356: } else {
10357: $cookie="publicuser_$next";
10358: last;
10359: }
10360: }
10361: if (!$cookie) { $cookie="publicuser_$oldest"; }
10362: } else {
1.463 albertel 10363: # if this isn't a robot, kill any existing non-robot sessions
10364: if (!$args->{'robot'}) {
10365: opendir(DIR,$lonids);
10366: while ($filename=readdir(DIR)) {
10367: if ($filename=~/^$username\_\d+\_$domain\_$authhost\.id$/) {
10368: unlink($lonids.'/'.$filename);
10369: }
1.462 albertel 10370: }
1.463 albertel 10371: closedir(DIR);
1.462 albertel 10372: }
10373: # Give them a new cookie
1.463 albertel 10374: my $id = ($args->{'robot'} ? 'robot'.$args->{'robot'}
1.684 www 10375: : $now.$$.int(rand(10000)));
1.463 albertel 10376: $cookie="$username\_$id\_$domain\_$authhost";
1.462 albertel 10377:
10378: # Initialize roles
10379:
10380: $userroles=&Apache::lonnet::rolesinit($domain,$username,$authhost);
10381: }
10382: # ------------------------------------ Check browser type and MathML capability
10383:
10384: my ($httpbrowser,$clientbrowser,$clientversion,$clientmathml,
10385: $clientunicode,$clientos) = &decode_user_agent($r);
10386:
10387: # ------------------------------------------------------------- Get environment
10388:
10389: my %userenv = &Apache::lonnet::dump('environment',$domain,$username);
10390: my ($tmp) = keys(%userenv);
10391: if ($tmp !~ /^(con_lost|error|no_such_host)/i) {
10392: # default remote control to off
10393: if ($userenv{'remote'} ne 'on') { $userenv{'remote'} = 'off'; }
10394: } else {
10395: undef(%userenv);
10396: }
10397: if (($userenv{'interface'}) && (!$form->{'interface'})) {
10398: $form->{'interface'}=$userenv{'interface'};
10399: }
10400: $env{'environment.remote'}=$userenv{'remote'};
10401: if ($userenv{'texengine'} eq 'ttm') { $clientmathml=1; }
10402:
10403: # --------------- Do not trust query string to be put directly into environment
1.817 bisitz 10404: foreach my $option ('interface','localpath','localres') {
10405: $form->{$option}=~s/[\n\r\=]//gs;
1.462 albertel 10406: }
10407: # --------------------------------------------------------- Write first profile
10408:
10409: {
10410: my %initial_env =
10411: ("user.name" => $username,
10412: "user.domain" => $domain,
10413: "user.home" => $authhost,
10414: "browser.type" => $clientbrowser,
10415: "browser.version" => $clientversion,
10416: "browser.mathml" => $clientmathml,
10417: "browser.unicode" => $clientunicode,
10418: "browser.os" => $clientos,
10419: "server.domain" => $Apache::lonnet::perlvar{'lonDefDomain'},
10420: "request.course.fn" => '',
10421: "request.course.uri" => '',
10422: "request.course.sec" => '',
10423: "request.role" => 'cm',
10424: "request.role.adv" => $env{'user.adv'},
10425: "request.host" => $ENV{'REMOTE_ADDR'},);
10426:
10427: if ($form->{'localpath'}) {
10428: $initial_env{"browser.localpath"} = $form->{'localpath'};
10429: $initial_env{"browser.localres"} = $form->{'localres'};
10430: }
10431:
10432: if ($public) {
10433: $initial_env{"environment.remote"} = "off";
10434: }
10435: if ($form->{'interface'}) {
10436: $form->{'interface'}=~s/\W//gs;
10437: $initial_env{"browser.interface"} = $form->{'interface'};
10438: $env{'browser.interface'}=$form->{'interface'};
10439: }
10440:
1.724 raeburn 10441: foreach my $tool ('aboutme','blog','portfolio') {
10442: $userenv{'availabletools.'.$tool} =
10443: &Apache::lonnet::usertools_access($username,$domain,$tool,'reload');
10444: }
10445:
1.864 raeburn 10446: foreach my $crstype ('official','unofficial','community') {
1.765 raeburn 10447: $userenv{'canrequest.'.$crstype} =
10448: &Apache::lonnet::usertools_access($username,$domain,$crstype,
10449: 'reload','requestcourses');
10450: }
10451:
1.462 albertel 10452: $env{'user.environment'} = "$lonids/$cookie.id";
10453:
10454: if (tie(my %disk_env,'GDBM_File',"$lonids/$cookie.id",
10455: &GDBM_WRCREAT(),0640)) {
10456: &_add_to_env(\%disk_env,\%initial_env);
10457: &_add_to_env(\%disk_env,\%userenv,'environment.');
10458: &_add_to_env(\%disk_env,$userroles);
1.463 albertel 10459: if (ref($args->{'extra_env'})) {
10460: &_add_to_env(\%disk_env,$args->{'extra_env'});
10461: }
1.462 albertel 10462: untie(%disk_env);
10463: } else {
1.705 tempelho 10464: &Apache::lonnet::logthis("<span style=\"color:blue;\">WARNING: ".
10465: 'Could not create environment storage in lonauth: '.$!.'</span>');
1.462 albertel 10466: return 'error: '.$!;
10467: }
10468: }
10469: $env{'request.role'}='cm';
10470: $env{'request.role.adv'}=$env{'user.adv'};
10471: $env{'browser.type'}=$clientbrowser;
10472:
10473: return $cookie;
10474:
10475: }
10476:
10477: sub _add_to_env {
10478: my ($idf,$env_data,$prefix) = @_;
1.676 raeburn 10479: if (ref($env_data) eq 'HASH') {
10480: while (my ($key,$value) = each(%$env_data)) {
10481: $idf->{$prefix.$key} = $value;
10482: $env{$prefix.$key} = $value;
10483: }
1.462 albertel 10484: }
10485: }
10486:
1.685 tempelho 10487: # --- Get the symbolic name of a problem and the url
10488: sub get_symb {
10489: my ($request,$silent) = @_;
1.726 raeburn 10490: (my $url=$env{'form.url'}) =~ s-^https?\://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;
1.685 tempelho 10491: my $symb=($env{'form.symb'} ne '' ? $env{'form.symb'} : (&Apache::lonnet::symbread($url)));
10492: if ($symb eq '') {
10493: if (!$silent) {
10494: $request->print("Unable to handle ambiguous references:$url:.");
10495: return ();
10496: }
10497: }
10498: &Apache::lonenc::check_decrypt(\$symb);
10499: return ($symb);
10500: }
10501:
10502: # --------------------------------------------------------------Get annotation
10503:
10504: sub get_annotation {
10505: my ($symb,$enc) = @_;
10506:
10507: my $key = $symb;
10508: if (!$enc) {
10509: $key =
10510: &Apache::lonnet::clutter((&Apache::lonnet::decode_symb($symb))[2]);
10511: }
10512: my %annotation=&Apache::lonnet::get('nohist_annotations',[$key]);
10513: return $annotation{$key};
10514: }
10515:
10516: sub clean_symb {
1.731 raeburn 10517: my ($symb,$delete_enc) = @_;
1.685 tempelho 10518:
10519: &Apache::lonenc::check_decrypt(\$symb);
10520: my $enc = $env{'request.enc'};
1.731 raeburn 10521: if ($delete_enc) {
1.730 raeburn 10522: delete($env{'request.enc'});
10523: }
1.685 tempelho 10524:
10525: return ($symb,$enc);
10526: }
1.462 albertel 10527:
1.41 ng 10528: =pod
10529:
10530: =back
10531:
1.112 bowersj2 10532: =cut
1.41 ng 10533:
1.112 bowersj2 10534: 1;
10535: __END__;
1.41 ng 10536:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>