Annotation of loncom/interface/loncommon.pm, revision 1.905
1.10 albertel 1: # The LearningOnline Network with CAPA
1.1 albertel 2: # a pile of common routines
1.10 albertel 3: #
1.905 ! raeburn 4: # $Id: loncommon.pm,v 1.904 2009/10/28 08:47:56 droeschl 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.905 ! raeburn 485: my ($domainfilter,$sec_element,$formname,$role_element)=@_;
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.895 raeburn 496: var formid = getFormIdByName(formname);
1.876 raeburn 497: var domainfilter = getDomainFromSelectbox(formname,udom);
1.128 albertel 498: if (domainfilter != null) {
499: if (domainfilter != '') {
500: url += 'domainfilter='+domainfilter+'&';
501: }
502: }
1.91 www 503: url += 'form=' + formname + '&cnumelement='+uname+
1.187 albertel 504: '&cdomelement='+udom+
505: '&cnameelement='+desc;
1.468 raeburn 506: if (extra_element !=null && extra_element != '') {
1.594 raeburn 507: if (formname == 'rolechoice' || formname == 'studentform') {
1.468 raeburn 508: url += '&roleelement='+extra_element;
509: if (domainfilter == null || domainfilter == '') {
510: url += '&domainfilter='+extra_element;
511: }
1.234 raeburn 512: }
1.468 raeburn 513: else {
514: if (formname == 'portform') {
515: url += '&setroles='+extra_element;
1.800 raeburn 516: } else {
517: if (formname == 'rules') {
518: url += '&fixeddom='+extra_element;
519: }
1.468 raeburn 520: }
521: }
1.230 raeburn 522: }
1.872 raeburn 523: if (formname == 'ccrs') {
524: var ownername = document.forms[formid].ccuname.value;
525: var ownerdom = document.forms[formid].ccdomain.options[document.forms[formid].ccdomain.selectedIndex].value;
526: url += '&cloner='+ownername+':'+ownerdom;
527: }
1.293 raeburn 528: if (multflag !=null && multflag != '') {
529: url += '&multiple='+multflag;
530: }
1.865 raeburn 531: if (crstype == 'Course/Community') {
1.377 raeburn 532: if (formname == 'cu') {
533: crstype = document.cu.crstype.options[document.cu.crstype.selectedIndex].value;
534: if (crstype == "") {
535: alert("$crs_or_grp_alert");
536: return;
537: }
538: }
539: }
540: if (crstype !=null && crstype != '') {
541: url += '&type='+crstype;
542: }
1.102 www 543: var title = 'Course_Browser';
1.91 www 544: var options = 'scrollbars=1,resizable=1,menubar=0';
545: options += ',width=700,height=600';
546: stdeditbrowser = open(url,title,options,'1');
547: stdeditbrowser.focus();
548: }
1.876 raeburn 549: $id_functions
550: ENDSTDBRW
1.905 ! raeburn 551: if (($sec_element ne '') || ($role_element ne '')) {
! 552: $output .= &setsec_javascript($sec_element,$formname,$role_element);
1.876 raeburn 553: }
554: $output .= '
555: // ]]>
556: </script>';
557: return $output;
558: }
559:
560: sub javascript_index_functions {
561: return <<"ENDJS";
562:
563: function getFormIdByName(formname) {
564: for (var i=0;i<document.forms.length;i++) {
565: if (document.forms[i].name == formname) {
566: return i;
567: }
568: }
569: return -1;
570: }
571:
572: function getIndexByName(formid,item) {
573: for (var i=0;i<document.forms[formid].elements.length;i++) {
574: if (document.forms[formid].elements[i].name == item) {
575: return i;
576: }
577: }
578: return -1;
579: }
1.468 raeburn 580:
1.876 raeburn 581: function getDomainFromSelectbox(formname,udom) {
582: var userdom;
583: var formid = getFormIdByName(formname);
584: if (formid > -1) {
585: var domid = getIndexByName(formid,udom);
586: if (domid > -1) {
587: if (document.forms[formid].elements[domid].type == 'select-one') {
588: userdom=document.forms[formid].elements[domid].options[document.forms[formid].elements[domid].selectedIndex].value;
589: }
590: if (document.forms[formid].elements[domid].type == 'hidden') {
591: userdom=document.forms[formid].elements[domid].value;
1.468 raeburn 592: }
593: }
594: }
1.876 raeburn 595: return userdom;
596: }
597:
598: ENDJS
1.468 raeburn 599:
1.876 raeburn 600: }
601:
602: sub userbrowser_javascript {
603: my $id_functions = &javascript_index_functions();
604: return <<"ENDUSERBRW";
605:
1.888 raeburn 606: function openuserbrowser(formname,uname,udom,ulast,ufirst,uemail,hideudom,crsdom,caller) {
1.876 raeburn 607: var url = '/adm/pickuser?';
608: var userdom = getDomainFromSelectbox(formname,udom);
609: if (userdom != null) {
610: if (userdom != '') {
611: url += 'srchdom='+userdom+'&';
612: }
613: }
614: url += 'form=' + formname + '&unameelement='+uname+
615: '&udomelement='+udom+
616: '&ulastelement='+ulast+
617: '&ufirstelement='+ufirst+
618: '&uemailelement='+uemail+
1.881 raeburn 619: '&hideudomelement='+hideudom+
620: '&coursedom='+crsdom;
1.888 raeburn 621: if ((caller != null) && (caller != undefined)) {
622: url += '&caller='+caller;
623: }
1.876 raeburn 624: var title = 'User_Browser';
625: var options = 'scrollbars=1,resizable=1,menubar=0';
626: options += ',width=700,height=600';
627: var stdeditbrowser = open(url,title,options,'1');
628: stdeditbrowser.focus();
629: }
630:
1.888 raeburn 631: function fix_domain (formname,udom,origdom,uname) {
1.876 raeburn 632: var formid = getFormIdByName(formname);
633: if (formid > -1) {
1.888 raeburn 634: var unameid = getIndexByName(formid,uname);
1.876 raeburn 635: var domid = getIndexByName(formid,udom);
636: var hidedomid = getIndexByName(formid,origdom);
637: if (hidedomid > -1) {
638: var fixeddom = document.forms[formid].elements[hidedomid].value;
1.888 raeburn 639: var unameval = document.forms[formid].elements[unameid].value;
640: if ((fixeddom != '') && (fixeddom != undefined) && (fixeddom != null) && (unameval != '') && (unameval != undefined) && (unameval != null)) {
641: if (domid > -1) {
642: var slct = document.forms[formid].elements[domid];
643: if (slct.type == 'select-one') {
644: var i;
645: for (i=0;i<slct.length;i++) {
646: if (slct.options[i].value==fixeddom) { slct.selectedIndex=i; }
647: }
648: }
649: if (slct.type == 'hidden') {
650: slct.value = fixeddom;
1.876 raeburn 651: }
652: }
1.468 raeburn 653: }
654: }
655: }
1.876 raeburn 656: return;
657: }
658:
659: $id_functions
660: ENDUSERBRW
1.468 raeburn 661: }
662:
663: sub setsec_javascript {
1.905 ! raeburn 664: my ($sec_element,$formname,$role_element) = @_;
! 665: my (@courserolenames,@communityrolenames,$rolestr,$courserolestr,
! 666: $communityrolestr);
! 667: if ($role_element ne '') {
! 668: my @allroles = ('st','ta','ep','in','ad');
! 669: foreach my $crstype ('Course','Community') {
! 670: if ($crstype eq 'Community') {
! 671: foreach my $role (@allroles) {
! 672: push(@communityrolenames,&Apache::lonnet::plaintext($role,$crstype));
! 673: }
! 674: push(@communityrolenames,&Apache::lonnet::plaintext('co'));
! 675: } else {
! 676: foreach my $role (@allroles) {
! 677: push(@courserolenames,&Apache::lonnet::plaintext($role,$crstype));
! 678: }
! 679: push(@courserolenames,&Apache::lonnet::plaintext('cc'));
! 680: }
! 681: }
! 682: $rolestr = '"'.join('","',@allroles).'"';
! 683: $courserolestr = '"'.join('","',@courserolenames).'"';
! 684: $communityrolestr = '"'.join('","',@communityrolenames).'"';
! 685: }
1.468 raeburn 686: my $setsections = qq|
687: function setSect(sectionlist) {
1.629 raeburn 688: var sectionsArray = new Array();
689: if ((sectionlist != '') && (typeof sectionlist != "undefined")) {
690: sectionsArray = sectionlist.split(",");
691: }
1.468 raeburn 692: var numSections = sectionsArray.length;
693: document.$formname.$sec_element.length = 0;
694: if (numSections == 0) {
695: document.$formname.$sec_element.multiple=false;
696: document.$formname.$sec_element.size=1;
697: document.$formname.$sec_element.options[0] = new Option('No existing sections','',false,false)
698: } else {
699: if (numSections == 1) {
700: document.$formname.$sec_element.multiple=false;
701: document.$formname.$sec_element.size=1;
702: document.$formname.$sec_element.options[0] = new Option('Select','',true,true);
703: document.$formname.$sec_element.options[1] = new Option('No section','',false,false)
704: document.$formname.$sec_element.options[2] = new Option(sectionsArray[0],sectionsArray[0],false,false);
705: } else {
706: for (var i=0; i<numSections; i++) {
707: document.$formname.$sec_element.options[i] = new Option(sectionsArray[i],sectionsArray[i],false,false)
708: }
709: document.$formname.$sec_element.multiple=true
710: if (numSections < 3) {
711: document.$formname.$sec_element.size=numSections;
712: } else {
713: document.$formname.$sec_element.size=3;
714: }
715: document.$formname.$sec_element.options[0].selected = false
716: }
717: }
1.91 www 718: }
1.905 ! raeburn 719:
! 720: function setRole(crstype) {
1.468 raeburn 721: |;
1.905 ! raeburn 722: if ($role_element eq '') {
! 723: $setsections .= ' return;
! 724: }
! 725: ';
! 726: } else {
! 727: $setsections .= qq|
! 728: var elementLength = document.$formname.$role_element.length;
! 729: var allroles = Array($rolestr);
! 730: var courserolenames = Array($courserolestr);
! 731: var communityrolenames = Array($communityrolestr);
! 732: if (elementLength != undefined) {
! 733: if (document.$formname.$role_element.options[5].value == 'cc') {
! 734: if (crstype == 'Course') {
! 735: return;
! 736: } else {
! 737: allroles[5] = 'co';
! 738: for (var i=0; i<6; i++) {
! 739: document.$formname.$role_element.options[i].value = allroles[i];
! 740: document.$formname.$role_element.options[i].text = communityrolenames[i];
! 741: }
! 742: }
! 743: } else {
! 744: if (crstype == 'Community') {
! 745: return;
! 746: } else {
! 747: allroles[5] = 'cc';
! 748: for (var i=0; i<6; i++) {
! 749: document.$formname.$role_element.options[i].value = allroles[i];
! 750: document.$formname.$role_element.options[i].text = courserolenames[i];
! 751: }
! 752: }
! 753: }
! 754: }
! 755: return;
! 756: }
! 757: |;
! 758: }
1.468 raeburn 759: return $setsections;
760: }
761:
1.91 www 762: sub selectcourse_link {
1.377 raeburn 763: my ($form,$unameele,$udomele,$desc,$extra_element,$multflag,$selecttype)=@_;
1.871 raeburn 764: my $linktext = &mt('Select Course');
765: if ($selecttype eq 'Community') {
766: $linktext = &mt('Select Community');
767: }
1.787 bisitz 768: return '<span class="LC_nobreak">'
769: ."<a href='"
770: .'javascript:opencrsbrowser("'.$form.'","'.$unameele
771: .'","'.$udomele.'","'.$desc.'","'.$extra_element
772: .'","'.$multflag.'","'.$selecttype.'");'
1.871 raeburn 773: ."'>".$linktext.'</a>'
1.787 bisitz 774: .'</span>';
1.74 www 775: }
1.42 matthew 776:
1.653 raeburn 777: sub selectauthor_link {
778: my ($form,$udom)=@_;
779: return '<a href="javascript:openauthorbrowser('."'$form','$udom'".');">'.
780: &mt('Select Author').'</a>';
781: }
782:
1.876 raeburn 783: sub selectuser_link {
1.881 raeburn 784: my ($form,$unameelem,$domelem,$lastelem,$firstelem,$emailelem,$hdomelem,
1.888 raeburn 785: $coursedom,$linktext,$caller) = @_;
1.876 raeburn 786: return '<a href="javascript:openuserbrowser('."'$form','$unameelem','$domelem',".
1.888 raeburn 787: "'$lastelem','$firstelem','$emailelem','$hdomelem','$coursedom','$caller'".
1.881 raeburn 788: ');">'.$linktext.'</a>';
1.876 raeburn 789: }
790:
1.273 raeburn 791: sub check_uncheck_jscript {
792: my $jscript = <<"ENDSCRT";
793: function checkAll(field) {
794: if (field.length > 0) {
795: for (i = 0; i < field.length; i++) {
796: field[i].checked = true ;
797: }
798: } else {
799: field.checked = true
800: }
801: }
802:
803: function uncheckAll(field) {
804: if (field.length > 0) {
805: for (i = 0; i < field.length; i++) {
806: field[i].checked = false ;
1.543 albertel 807: }
808: } else {
1.273 raeburn 809: field.checked = false ;
810: }
811: }
812: ENDSCRT
813: return $jscript;
814: }
815:
1.656 www 816: sub select_timezone {
1.659 raeburn 817: my ($name,$selected,$onchange,$includeempty)=@_;
818: my $output='<select name="'.$name.'" '.$onchange.'>'."\n";
819: if ($includeempty) {
820: $output .= '<option value=""';
821: if (($selected eq '') || ($selected eq 'local')) {
822: $output .= ' selected="selected" ';
823: }
824: $output .= '> </option>';
825: }
1.657 raeburn 826: my @timezones = DateTime::TimeZone->all_names;
827: foreach my $tzone (@timezones) {
828: $output.= '<option value="'.$tzone.'"';
829: if ($tzone eq $selected) {
830: $output.=' selected="selected"';
831: }
832: $output.=">$tzone</option>\n";
1.656 www 833: }
834: $output.="</select>";
835: return $output;
836: }
1.273 raeburn 837:
1.687 raeburn 838: sub select_datelocale {
839: my ($name,$selected,$onchange,$includeempty)=@_;
840: my $output='<select name="'.$name.'" '.$onchange.'>'."\n";
841: if ($includeempty) {
842: $output .= '<option value=""';
843: if ($selected eq '') {
844: $output .= ' selected="selected" ';
845: }
846: $output .= '> </option>';
847: }
848: my (@possibles,%locale_names);
849: my @locales = DateTime::Locale::Catalog::Locales;
850: foreach my $locale (@locales) {
851: if (ref($locale) eq 'HASH') {
852: my $id = $locale->{'id'};
853: if ($id ne '') {
854: my $en_terr = $locale->{'en_territory'};
855: my $native_terr = $locale->{'native_territory'};
1.695 raeburn 856: my @languages = &Apache::lonlocal::preferred_languages();
1.687 raeburn 857: if (grep(/^en$/,@languages) || !@languages) {
858: if ($en_terr ne '') {
859: $locale_names{$id} = '('.$en_terr.')';
860: } elsif ($native_terr ne '') {
861: $locale_names{$id} = $native_terr;
862: }
863: } else {
864: if ($native_terr ne '') {
865: $locale_names{$id} = $native_terr.' ';
866: } elsif ($en_terr ne '') {
867: $locale_names{$id} = '('.$en_terr.')';
868: }
869: }
870: push (@possibles,$id);
871: }
872: }
873: }
874: foreach my $item (sort(@possibles)) {
875: $output.= '<option value="'.$item.'"';
876: if ($item eq $selected) {
877: $output.=' selected="selected"';
878: }
879: $output.=">$item";
880: if ($locale_names{$item} ne '') {
881: $output.=" $locale_names{$item}</option>\n";
882: }
883: $output.="</option>\n";
884: }
885: $output.="</select>";
886: return $output;
887: }
888:
1.792 raeburn 889: sub select_language {
890: my ($name,$selected,$includeempty) = @_;
891: my %langchoices;
892: if ($includeempty) {
893: %langchoices = ('' => 'No language preference');
894: }
895: foreach my $id (&languageids()) {
896: my $code = &supportedlanguagecode($id);
897: if ($code) {
898: $langchoices{$code} = &plainlanguagedescription($id);
899: }
900: }
901: return &select_form($selected,$name,%langchoices);
902: }
903:
1.42 matthew 904: =pod
1.36 matthew 905:
1.648 raeburn 906: =item * &linked_select_forms(...)
1.36 matthew 907:
908: linked_select_forms returns a string containing a <script></script> block
909: and html for two <select> menus. The select menus will be linked in that
910: changing the value of the first menu will result in new values being placed
911: in the second menu. The values in the select menu will appear in alphabetical
1.609 raeburn 912: order unless a defined order is provided.
1.36 matthew 913:
914: linked_select_forms takes the following ordered inputs:
915:
916: =over 4
917:
1.112 bowersj2 918: =item * $formname, the name of the <form> tag
1.36 matthew 919:
1.112 bowersj2 920: =item * $middletext, the text which appears between the <select> tags
1.36 matthew 921:
1.112 bowersj2 922: =item * $firstdefault, the default value for the first menu
1.36 matthew 923:
1.112 bowersj2 924: =item * $firstselectname, the name of the first <select> tag
1.36 matthew 925:
1.112 bowersj2 926: =item * $secondselectname, the name of the second <select> tag
1.36 matthew 927:
1.112 bowersj2 928: =item * $hashref, a reference to a hash containing the data for the menus.
1.36 matthew 929:
1.609 raeburn 930: =item * $menuorder, the order of values in the first menu
931:
1.41 ng 932: =back
933:
1.36 matthew 934: Below is an example of such a hash. Only the 'text', 'default', and
935: 'select2' keys must appear as stated. keys(%menu) are the possible
936: values for the first select menu. The text that coincides with the
1.41 ng 937: first menu value is given in $menu{$choice1}->{'text'}. The values
1.36 matthew 938: and text for the second menu are given in the hash pointed to by
939: $menu{$choice1}->{'select2'}.
940:
1.112 bowersj2 941: my %menu = ( A1 => { text =>"Choice A1" ,
942: default => "B3",
943: select2 => {
944: B1 => "Choice B1",
945: B2 => "Choice B2",
946: B3 => "Choice B3",
947: B4 => "Choice B4"
1.609 raeburn 948: },
949: order => ['B4','B3','B1','B2'],
1.112 bowersj2 950: },
951: A2 => { text =>"Choice A2" ,
952: default => "C2",
953: select2 => {
954: C1 => "Choice C1",
955: C2 => "Choice C2",
956: C3 => "Choice C3"
1.609 raeburn 957: },
958: order => ['C2','C1','C3'],
1.112 bowersj2 959: },
960: A3 => { text =>"Choice A3" ,
961: default => "D6",
962: select2 => {
963: D1 => "Choice D1",
964: D2 => "Choice D2",
965: D3 => "Choice D3",
966: D4 => "Choice D4",
967: D5 => "Choice D5",
968: D6 => "Choice D6",
969: D7 => "Choice D7"
1.609 raeburn 970: },
971: order => ['D4','D3','D2','D1','D7','D6','D5'],
1.112 bowersj2 972: }
973: );
1.36 matthew 974:
975: =cut
976:
977: sub linked_select_forms {
978: my ($formname,
979: $middletext,
980: $firstdefault,
981: $firstselectname,
982: $secondselectname,
1.609 raeburn 983: $hashref,
984: $menuorder,
1.36 matthew 985: ) = @_;
986: my $second = "document.$formname.$secondselectname";
987: my $first = "document.$formname.$firstselectname";
988: # output the javascript to do the changing
989: my $result = '';
1.776 bisitz 990: $result.='<script type="text/javascript" language="JavaScript">'."\n";
1.824 bisitz 991: $result.="// <![CDATA[\n";
1.36 matthew 992: $result.="var select2data = new Object();\n";
993: $" = '","';
994: my $debug = '';
995: foreach my $s1 (sort(keys(%$hashref))) {
996: $result.="select2data.d_$s1 = new Object();\n";
997: $result.="select2data.d_$s1.def = new String('".
998: $hashref->{$s1}->{'default'}."');\n";
1.609 raeburn 999: $result.="select2data.d_$s1.values = new Array(";
1.36 matthew 1000: my @s2values = sort(keys( %{ $hashref->{$s1}->{'select2'} } ));
1.609 raeburn 1001: if (ref($hashref->{$s1}->{'order'}) eq 'ARRAY') {
1002: @s2values = @{$hashref->{$s1}->{'order'}};
1003: }
1.36 matthew 1004: $result.="\"@s2values\");\n";
1005: $result.="select2data.d_$s1.texts = new Array(";
1006: my @s2texts;
1007: foreach my $value (@s2values) {
1008: push @s2texts, $hashref->{$s1}->{'select2'}->{$value};
1009: }
1010: $result.="\"@s2texts\");\n";
1011: }
1012: $"=' ';
1013: $result.= <<"END";
1014:
1015: function select1_changed() {
1016: // Determine new choice
1017: var newvalue = "d_" + $first.value;
1018: // update select2
1019: var values = select2data[newvalue].values;
1020: var texts = select2data[newvalue].texts;
1021: var select2def = select2data[newvalue].def;
1022: var i;
1023: // out with the old
1024: for (i = 0; i < $second.options.length; i++) {
1025: $second.options[i] = null;
1026: }
1027: // in with the nuclear
1028: for (i=0;i<values.length; i++) {
1029: $second.options[i] = new Option(values[i]);
1.143 matthew 1030: $second.options[i].value = values[i];
1.36 matthew 1031: $second.options[i].text = texts[i];
1032: if (values[i] == select2def) {
1033: $second.options[i].selected = true;
1034: }
1035: }
1036: }
1.824 bisitz 1037: // ]]>
1.36 matthew 1038: </script>
1039: END
1040: # output the initial values for the selection lists
1041: $result .= "<select size=\"1\" name=\"$firstselectname\" onchange=\"select1_changed()\">\n";
1.609 raeburn 1042: my @order = sort(keys(%{$hashref}));
1043: if (ref($menuorder) eq 'ARRAY') {
1044: @order = @{$menuorder};
1045: }
1046: foreach my $value (@order) {
1.36 matthew 1047: $result.=" <option value=\"$value\" ";
1.253 albertel 1048: $result.=" selected=\"selected\" " if ($value eq $firstdefault);
1.119 www 1049: $result.=">".&mt($hashref->{$value}->{'text'})."</option>\n";
1.36 matthew 1050: }
1051: $result .= "</select>\n";
1052: my %select2 = %{$hashref->{$firstdefault}->{'select2'}};
1053: $result .= $middletext;
1054: $result .= "<select size=\"1\" name=\"$secondselectname\">\n";
1055: my $seconddefault = $hashref->{$firstdefault}->{'default'};
1.609 raeburn 1056:
1057: my @secondorder = sort(keys(%select2));
1058: if (ref($hashref->{$firstdefault}->{'order'}) eq 'ARRAY') {
1059: @secondorder = @{$hashref->{$firstdefault}->{'order'}};
1060: }
1061: foreach my $value (@secondorder) {
1.36 matthew 1062: $result.=" <option value=\"$value\" ";
1.253 albertel 1063: $result.=" selected=\"selected\" " if ($value eq $seconddefault);
1.119 www 1064: $result.=">".&mt($select2{$value})."</option>\n";
1.36 matthew 1065: }
1066: $result .= "</select>\n";
1067: # return $debug;
1068: return $result;
1069: } # end of sub linked_select_forms {
1070:
1.45 matthew 1071: =pod
1.44 bowersj2 1072:
1.648 raeburn 1073: =item * &help_open_topic($topic,$text,$stayOnPage,$width,$height)
1.44 bowersj2 1074:
1.112 bowersj2 1075: Returns a string corresponding to an HTML link to the given help
1076: $topic, where $topic corresponds to the name of a .tex file in
1077: /home/httpd/html/adm/help/tex, with underscores replaced by
1078: spaces.
1079:
1080: $text will optionally be linked to the same topic, allowing you to
1081: link text in addition to the graphic. If you do not want to link
1082: text, but wish to specify one of the later parameters, pass an
1083: empty string.
1084:
1085: $stayOnPage is a value that will be interpreted as a boolean. If true,
1086: the link will not open a new window. If false, the link will open
1087: a new window using Javascript. (Default is false.)
1088:
1089: $width and $height are optional numerical parameters that will
1090: override the width and height of the popped up window, which may
1091: be useful for certain help topics with big pictures included.
1.44 bowersj2 1092:
1093: =cut
1094:
1095: sub help_open_topic {
1.48 bowersj2 1096: my ($topic, $text, $stayOnPage, $width, $height) = @_;
1097: $text = "" if (not defined $text);
1.44 bowersj2 1098: $stayOnPage = 0 if (not defined $stayOnPage);
1099: $width = 350 if (not defined $width);
1100: $height = 400 if (not defined $height);
1101: my $filename = $topic;
1102: $filename =~ s/ /_/g;
1103:
1.48 bowersj2 1104: my $template = "";
1105: my $link;
1.572 banghart 1106:
1.159 www 1107: $topic=~s/\W/\_/g;
1.44 bowersj2 1108:
1.572 banghart 1109: if (!$stayOnPage) {
1.72 bowersj2 1110: $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 1111: } else {
1.48 bowersj2 1112: $link = "/adm/help/${filename}.hlp";
1113: }
1114:
1115: # Add the text
1.755 neumanie 1116: if ($text ne "") {
1.763 bisitz 1117: $template.='<span class="LC_help_open_topic">'
1118: .'<a target="_top" href="'.$link.'">'
1119: .$text.'</a>';
1.48 bowersj2 1120: }
1121:
1.763 bisitz 1122: # (Always) Add the graphic
1.179 matthew 1123: my $title = &mt('Online Help');
1.667 raeburn 1124: my $helpicon=&lonhttpdurl("/adm/help/help.png");
1.763 bisitz 1125: $template.=' <a target="_top" href="'.$link.'" title="'.$title.'">'
1126: .'<img src="'.$helpicon.'" border="0"'
1127: .' alt="'.&mt('Help: [_1]',$topic).'"'
1.783 amueller 1128: .' title="'.$title.'"'
1.763 bisitz 1129: .' /></a>';
1130: if ($text ne "") {
1131: $template.='</span>';
1132: }
1.44 bowersj2 1133: return $template;
1134:
1.106 bowersj2 1135: }
1136:
1137: # This is a quicky function for Latex cheatsheet editing, since it
1138: # appears in at least four places
1139: sub helpLatexCheatsheet {
1.732 raeburn 1140: my ($topic,$text,$not_author) = @_;
1141: my $out;
1.106 bowersj2 1142: my $addOther = '';
1.732 raeburn 1143: if ($topic) {
1.763 bisitz 1144: $addOther = '<span>'.&Apache::loncommon::help_open_topic($topic,&mt($text),
1145: undef, undef, 600).
1146: '</span> ';
1147: }
1148: $out = '<span>' # Start cheatsheet
1149: .$addOther
1150: .'<span>'
1151: .&Apache::loncommon::help_open_topic('Greek_Symbols',&mt('Greek Symbols'),
1152: undef,undef,600)
1153: .'</span> <span>'
1154: .&Apache::loncommon::help_open_topic('Other_Symbols',&mt('Other Symbols'),
1155: undef,undef,600)
1156: .'</span>';
1.732 raeburn 1157: unless ($not_author) {
1.763 bisitz 1158: $out .= ' <span>'
1159: .&Apache::loncommon::help_open_topic('Authoring_Output_Tags',&mt('Output Tags'),
1160: undef,undef,600)
1161: .'</span>';
1.732 raeburn 1162: }
1.763 bisitz 1163: $out .= '</span>'; # End cheatsheet
1.732 raeburn 1164: return $out;
1.172 www 1165: }
1166:
1.430 albertel 1167: sub general_help {
1168: my $helptopic='Student_Intro';
1169: if ($env{'request.role'}=~/^(ca|au)/) {
1170: $helptopic='Authoring_Intro';
1171: } elsif ($env{'request.role'}=~/^cc/) {
1172: $helptopic='Course_Coordination_Intro';
1.672 raeburn 1173: } elsif ($env{'request.role'}=~/^dc/) {
1174: $helptopic='Domain_Coordination_Intro';
1.430 albertel 1175: }
1176: return $helptopic;
1177: }
1178:
1179: sub update_help_link {
1180: my ($topic,$component_help,$faq,$bug,$stayOnPage) = @_;
1181: my $origurl = $ENV{'REQUEST_URI'};
1182: $origurl=~s|^/~|/priv/|;
1183: my $timestamp = time;
1184: foreach my $datum (\$topic,\$component_help,\$faq,\$bug,\$origurl) {
1185: $$datum = &escape($$datum);
1186: }
1187:
1188: my $banner_link = "/adm/helpmenu?page=banner&topic=$topic&component_help=$component_help&faq=$faq&bug=$bug&origurl=$origurl&stamp=$timestamp&stayonpage=$stayOnPage";
1189: my $output .= <<"ENDOUTPUT";
1190: <script type="text/javascript">
1.824 bisitz 1191: // <![CDATA[
1.430 albertel 1192: banner_link = '$banner_link';
1.824 bisitz 1193: // ]]>
1.430 albertel 1194: </script>
1195: ENDOUTPUT
1196: return $output;
1197: }
1198:
1199: # now just updates the help link and generates a blue icon
1.193 raeburn 1200: sub help_open_menu {
1.430 albertel 1201: my ($topic,$component_help,$faq,$bug,$stayOnPage,$width,$height,$text)
1.552 banghart 1202: = @_;
1.430 albertel 1203: $stayOnPage = 0 if (not defined $stayOnPage);
1.572 banghart 1204: # only use pop-up help (stayOnPage == 0)
1.552 banghart 1205: # if environment.remote is on (using remote control UI)
1.798 tempelho 1206: if ($env{'environment.remote'} eq 'off' ) {
1.552 banghart 1207: $stayOnPage=1;
1.430 albertel 1208: }
1209: my $output;
1210: if ($component_help) {
1211: if (!$text) {
1212: $output=&help_open_topic($component_help,undef,$stayOnPage,
1213: $width,$height);
1214: } else {
1215: my $help_text;
1216: $help_text=&unescape($topic);
1217: $output='<table><tr><td>'.
1218: &help_open_topic($component_help,$help_text,$stayOnPage,
1219: $width,$height).'</td></tr></table>';
1220: }
1221: }
1222: my $banner_link = &update_help_link($topic,$component_help,$faq,$bug,$stayOnPage);
1223: return $output.$banner_link;
1224: }
1225:
1226: sub top_nav_help {
1227: my ($text) = @_;
1.436 albertel 1228: $text = &mt($text);
1.572 banghart 1229: my $stay_on_page =
1.798 tempelho 1230: ($env{'environment.remote'} eq 'off' );
1.572 banghart 1231: my $link = ($stay_on_page) ? "javascript:helpMenu('display')"
1.436 albertel 1232: : "javascript:helpMenu('open')";
1.572 banghart 1233: my $banner_link = &update_help_link(undef,undef,undef,undef,$stay_on_page);
1.436 albertel 1234:
1.201 raeburn 1235: my $title = &mt('Get help');
1.436 albertel 1236:
1237: return <<"END";
1238: $banner_link
1239: <a href="$link" title="$title">$text</a>
1240: END
1241: }
1242:
1243: sub help_menu_js {
1244: my ($text) = @_;
1245:
1246: my $stayOnPage =
1.798 tempelho 1247: ($env{'environment.remote'} eq 'off' );
1.436 albertel 1248:
1249: my $width = 620;
1250: my $height = 600;
1.430 albertel 1251: my $helptopic=&general_help();
1252: my $details_link = '/adm/help/'.$helptopic.'.hlp';
1.261 albertel 1253: my $nothing=&Apache::lonhtmlcommon::javascript_nothing();
1.331 albertel 1254: my $start_page =
1255: &Apache::loncommon::start_page('Help Menu', undef,
1256: {'frameset' => 1,
1257: 'js_ready' => 1,
1258: 'add_entries' => {
1259: 'border' => '0',
1.579 raeburn 1260: 'rows' => "110,*",},});
1.331 albertel 1261: my $end_page =
1262: &Apache::loncommon::end_page({'frameset' => 1,
1263: 'js_ready' => 1,});
1264:
1.436 albertel 1265: my $template .= <<"ENDTEMPLATE";
1266: <script type="text/javascript">
1.877 bisitz 1267: // <![CDATA[
1.253 albertel 1268: // <!-- BEGIN LON-CAPA Internal
1.430 albertel 1269: var banner_link = '';
1.243 raeburn 1270: function helpMenu(target) {
1271: var caller = this;
1272: if (target == 'open') {
1273: var newWindow = null;
1274: try {
1.262 albertel 1275: newWindow = window.open($nothing,"helpmenu","HEIGHT=$height,WIDTH=$width,resizable=yes,scrollbars=yes" )
1.243 raeburn 1276: }
1277: catch(error) {
1278: writeHelp(caller);
1279: return;
1280: }
1281: if (newWindow) {
1282: caller = newWindow;
1283: }
1.193 raeburn 1284: }
1.243 raeburn 1285: writeHelp(caller);
1286: return;
1287: }
1288: function writeHelp(caller) {
1.430 albertel 1289: caller.document.writeln('$start_page<frame name="bannerframe" src="'+banner_link+'" /><frame name="bodyframe" src="$details_link" /> $end_page')
1.243 raeburn 1290: caller.document.close()
1291: caller.focus()
1.193 raeburn 1292: }
1.877 bisitz 1293: // END LON-CAPA Internal -->
1.253 albertel 1294: // ]]>
1.436 albertel 1295: </script>
1.193 raeburn 1296: ENDTEMPLATE
1297: return $template;
1298: }
1299:
1.172 www 1300: sub help_open_bug {
1301: my ($topic, $text, $stayOnPage, $width, $height) = @_;
1.258 albertel 1302: unless ($env{'user.adv'}) { return ''; }
1.172 www 1303: unless ($Apache::lonnet::perlvar{'BugzillaHost'}) { return ''; }
1304: $text = "" if (not defined $text);
1305: $stayOnPage = 0 if (not defined $stayOnPage);
1.798 tempelho 1306: if ($env{'environment.remote'} eq 'off' ) {
1.172 www 1307: $stayOnPage=1;
1308: }
1.184 albertel 1309: $width = 600 if (not defined $width);
1310: $height = 600 if (not defined $height);
1.172 www 1311:
1312: $topic=~s/\W+/\+/g;
1313: my $link='';
1314: my $template='';
1.379 albertel 1315: my $url=$Apache::lonnet::perlvar{'BugzillaHost'}.'enter_bug.cgi?product=LON-CAPA&bug_file_loc='.
1316: &escape($ENV{'REQUEST_URI'}).'&component='.$topic;
1.172 www 1317: if (!$stayOnPage)
1318: {
1319: $link = "javascript:void(open('$url', 'Bugzilla', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))";
1320: }
1321: else
1322: {
1323: $link = $url;
1324: }
1325: # Add the text
1326: if ($text ne "")
1327: {
1328: $template .=
1329: "<table bgcolor='#AA3333' cellspacing='1' cellpadding='1' border='0'><tr>".
1.705 tempelho 1330: "<td bgcolor='#FF5555'><a target=\"_top\" href=\"$link\"><span style=\"color:#FFFFFF;font-size:10pt;\">$text</span></a>";
1.172 www 1331: }
1332:
1333: # Add the graphic
1.179 matthew 1334: my $title = &mt('Report a Bug');
1.215 albertel 1335: my $bugicon=&lonhttpdurl("/adm/lonMisc/smallBug.gif");
1.172 www 1336: $template .= <<"ENDTEMPLATE";
1.436 albertel 1337: <a target="_top" href="$link" title="$title"><img src="$bugicon" border="0" alt="(Bug: $topic)" /></a>
1.172 www 1338: ENDTEMPLATE
1339: if ($text ne '') { $template.='</td></tr></table>' };
1340: return $template;
1341:
1342: }
1343:
1344: sub help_open_faq {
1345: my ($topic, $text, $stayOnPage, $width, $height) = @_;
1.258 albertel 1346: unless ($env{'user.adv'}) { return ''; }
1.172 www 1347: unless ($Apache::lonnet::perlvar{'FAQHost'}) { return ''; }
1348: $text = "" if (not defined $text);
1349: $stayOnPage = 0 if (not defined $stayOnPage);
1.798 tempelho 1350: if ($env{'environment.remote'} eq 'off' ) {
1.172 www 1351: $stayOnPage=1;
1352: }
1353: $width = 350 if (not defined $width);
1354: $height = 400 if (not defined $height);
1355:
1356: $topic=~s/\W+/\+/g;
1357: my $link='';
1358: my $template='';
1359: my $url=$Apache::lonnet::perlvar{'FAQHost'}.'/fom/cache/'.$topic.'.html';
1360: if (!$stayOnPage)
1361: {
1362: $link = "javascript:void(open('$url', 'FAQ-O-Matic', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))";
1363: }
1364: else
1365: {
1366: $link = $url;
1367: }
1368:
1369: # Add the text
1370: if ($text ne "")
1371: {
1372: $template .=
1.173 www 1373: "<table bgcolor='#337733' cellspacing='1' cellpadding='1' border='0'><tr>".
1.705 tempelho 1374: "<td bgcolor='#448844'><a target=\"_top\" href=\"$link\"><span style=\"color:#FFFFFF; font-size:10pt;\">$text</span></a>";
1.172 www 1375: }
1376:
1377: # Add the graphic
1.179 matthew 1378: my $title = &mt('View the FAQ');
1.215 albertel 1379: my $faqicon=&lonhttpdurl("/adm/lonMisc/smallFAQ.gif");
1.172 www 1380: $template .= <<"ENDTEMPLATE";
1.436 albertel 1381: <a target="_top" href="$link" title="$title"><img src="$faqicon" border="0" alt="(FAQ: $topic)" /></a>
1.172 www 1382: ENDTEMPLATE
1383: if ($text ne '') { $template.='</td></tr></table>' };
1384: return $template;
1385:
1.44 bowersj2 1386: }
1.37 matthew 1387:
1.180 matthew 1388: ###############################################################
1389: ###############################################################
1390:
1.45 matthew 1391: =pod
1392:
1.648 raeburn 1393: =item * &change_content_javascript():
1.256 matthew 1394:
1395: This and the next function allow you to create small sections of an
1396: otherwise static HTML page that you can update on the fly with
1397: Javascript, even in Netscape 4.
1398:
1399: The Javascript fragment returned by this function (no E<lt>scriptE<gt> tag)
1400: must be written to the HTML page once. It will prove the Javascript
1401: function "change(name, content)". Calling the change function with the
1402: name of the section
1403: you want to update, matching the name passed to C<changable_area>, and
1404: the new content you want to put in there, will put the content into
1405: that area.
1406:
1407: B<Note>: Netscape 4 only reserves enough space for the changable area
1408: to contain room for the original contents. You need to "make space"
1409: for whatever changes you wish to make, and be B<sure> to check your
1410: code in Netscape 4. This feature in Netscape 4 is B<not> powerful;
1411: it's adequate for updating a one-line status display, but little more.
1412: This script will set the space to 100% width, so you only need to
1413: worry about height in Netscape 4.
1414:
1415: Modern browsers are much less limiting, and if you can commit to the
1416: user not using Netscape 4, this feature may be used freely with
1417: pretty much any HTML.
1418:
1419: =cut
1420:
1421: sub change_content_javascript {
1422: # If we're on Netscape 4, we need to use Layer-based code
1.258 albertel 1423: if ($env{'browser.type'} eq 'netscape' &&
1424: $env{'browser.version'} =~ /^4\./) {
1.256 matthew 1425: return (<<NETSCAPE4);
1426: function change(name, content) {
1427: doc = document.layers[name+"___escape"].layers[0].document;
1428: doc.open();
1429: doc.write(content);
1430: doc.close();
1431: }
1432: NETSCAPE4
1433: } else {
1434: # Otherwise, we need to use semi-standards-compliant code
1435: # (technically, "innerHTML" isn't standard but the equivalent
1436: # is really scary, and every useful browser supports it
1437: return (<<DOMBASED);
1438: function change(name, content) {
1439: element = document.getElementById(name);
1440: element.innerHTML = content;
1441: }
1442: DOMBASED
1443: }
1444: }
1445:
1446: =pod
1447:
1.648 raeburn 1448: =item * &changable_area($name,$origContent):
1.256 matthew 1449:
1450: This provides a "changable area" that can be modified on the fly via
1451: the Javascript code provided in C<change_content_javascript>. $name is
1452: the name you will use to reference the area later; do not repeat the
1453: same name on a given HTML page more then once. $origContent is what
1454: the area will originally contain, which can be left blank.
1455:
1456: =cut
1457:
1458: sub changable_area {
1459: my ($name, $origContent) = @_;
1460:
1.258 albertel 1461: if ($env{'browser.type'} eq 'netscape' &&
1462: $env{'browser.version'} =~ /^4\./) {
1.256 matthew 1463: # If this is netscape 4, we need to use the Layer tag
1464: return "<ilayer width='100%' id='${name}___escape' overflow='none'><layer width='100%' id='$name' overflow='none'>$origContent</layer></ilayer>";
1465: } else {
1466: return "<span id='$name'>$origContent</span>";
1467: }
1468: }
1469:
1470: =pod
1471:
1.648 raeburn 1472: =item * &viewport_geometry_js
1.590 raeburn 1473:
1474: Provides javascript object (Geometry) which can provide information about the viewport geometry for the client browser.
1475:
1476: =cut
1477:
1478:
1479: sub viewport_geometry_js {
1480: return <<"GEOMETRY";
1481: var Geometry = {};
1482: function init_geometry() {
1483: if (Geometry.init) { return };
1484: Geometry.init=1;
1485: if (window.innerHeight) {
1486: Geometry.getViewportHeight = function() { return window.innerHeight; };
1487: Geometry.getViewportWidth = function() { return window.innerWidth; };
1488: Geometry.getHorizontalScroll = function() { return window.pageXOffset; };
1489: Geometry.getVerticalScroll = function() { return window.pageYOffset; };
1490: }
1491: else if (document.documentElement && document.documentElement.clientHeight) {
1492: Geometry.getViewportHeight =
1493: function() { return document.documentElement.clientHeight; };
1494: Geometry.getViewportWidth =
1495: function() { return document.documentElement.clientWidth; };
1496:
1497: Geometry.getHorizontalScroll =
1498: function() { return document.documentElement.scrollLeft; };
1499: Geometry.getVerticalScroll =
1500: function() { return document.documentElement.scrollTop; };
1501: }
1502: else if (document.body.clientHeight) {
1503: Geometry.getViewportHeight =
1504: function() { return document.body.clientHeight; };
1505: Geometry.getViewportWidth =
1506: function() { return document.body.clientWidth; };
1507: Geometry.getHorizontalScroll =
1508: function() { return document.body.scrollLeft; };
1509: Geometry.getVerticalScroll =
1510: function() { return document.body.scrollTop; };
1511: }
1512: }
1513:
1514: GEOMETRY
1515: }
1516:
1517: =pod
1518:
1.648 raeburn 1519: =item * &viewport_size_js()
1.590 raeburn 1520:
1521: 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.
1522:
1523: =cut
1524:
1525: sub viewport_size_js {
1526: my $geometry = &viewport_geometry_js();
1527: return <<"DIMS";
1528:
1529: $geometry
1530:
1531: function getViewportDims(width,height) {
1532: init_geometry();
1533: width.value = Geometry.getViewportWidth();
1534: height.value = Geometry.getViewportHeight();
1535: return;
1536: }
1537:
1538: DIMS
1539: }
1540:
1541: =pod
1542:
1.648 raeburn 1543: =item * &resize_textarea_js()
1.565 albertel 1544:
1545: emits the needed javascript to resize a textarea to be as big as possible
1546:
1547: creates a function resize_textrea that takes two IDs first should be
1548: the id of the element to resize, second should be the id of a div that
1549: surrounds everything that comes after the textarea, this routine needs
1550: to be attached to the <body> for the onload and onresize events.
1551:
1.648 raeburn 1552: =back
1.565 albertel 1553:
1554: =cut
1555:
1556: sub resize_textarea_js {
1.590 raeburn 1557: my $geometry = &viewport_geometry_js();
1.565 albertel 1558: return <<"RESIZE";
1559: <script type="text/javascript">
1.824 bisitz 1560: // <![CDATA[
1.590 raeburn 1561: $geometry
1.565 albertel 1562:
1.588 albertel 1563: function getX(element) {
1564: var x = 0;
1565: while (element) {
1566: x += element.offsetLeft;
1567: element = element.offsetParent;
1568: }
1569: return x;
1570: }
1571: function getY(element) {
1572: var y = 0;
1573: while (element) {
1574: y += element.offsetTop;
1575: element = element.offsetParent;
1576: }
1577: return y;
1578: }
1579:
1580:
1.565 albertel 1581: function resize_textarea(textarea_id,bottom_id) {
1582: init_geometry();
1583: var textarea = document.getElementById(textarea_id);
1584: //alert(textarea);
1585:
1.588 albertel 1586: var textarea_top = getY(textarea);
1.565 albertel 1587: var textarea_height = textarea.offsetHeight;
1588: var bottom = document.getElementById(bottom_id);
1.588 albertel 1589: var bottom_top = getY(bottom);
1.565 albertel 1590: var bottom_height = bottom.offsetHeight;
1591: var window_height = Geometry.getViewportHeight();
1.588 albertel 1592: var fudge = 23;
1.565 albertel 1593: var new_height = window_height-fudge-textarea_top-bottom_height;
1594: if (new_height < 300) {
1595: new_height = 300;
1596: }
1597: textarea.style.height=new_height+'px';
1598: }
1.824 bisitz 1599: // ]]>
1.565 albertel 1600: </script>
1601: RESIZE
1602:
1603: }
1604:
1605: =pod
1606:
1.256 matthew 1607: =head1 Excel and CSV file utility routines
1608:
1609: =over 4
1610:
1611: =cut
1612:
1613: ###############################################################
1614: ###############################################################
1615:
1616: =pod
1617:
1.648 raeburn 1618: =item * &csv_translate($text)
1.37 matthew 1619:
1.185 www 1620: Translate $text to allow it to be output as a 'comma separated values'
1.37 matthew 1621: format.
1622:
1623: =cut
1624:
1.180 matthew 1625: ###############################################################
1626: ###############################################################
1.37 matthew 1627: sub csv_translate {
1628: my $text = shift;
1629: $text =~ s/\"/\"\"/g;
1.209 albertel 1630: $text =~ s/\n/ /g;
1.37 matthew 1631: return $text;
1632: }
1.180 matthew 1633:
1634: ###############################################################
1635: ###############################################################
1636:
1637: =pod
1638:
1.648 raeburn 1639: =item * &define_excel_formats()
1.180 matthew 1640:
1641: Define some commonly used Excel cell formats.
1642:
1643: Currently supported formats:
1644:
1645: =over 4
1646:
1647: =item header
1648:
1649: =item bold
1650:
1651: =item h1
1652:
1653: =item h2
1654:
1655: =item h3
1656:
1.256 matthew 1657: =item h4
1658:
1659: =item i
1660:
1.180 matthew 1661: =item date
1662:
1663: =back
1664:
1665: Inputs: $workbook
1666:
1667: Returns: $format, a hash reference.
1668:
1669: =cut
1670:
1671: ###############################################################
1672: ###############################################################
1673: sub define_excel_formats {
1674: my ($workbook) = @_;
1675: my $format;
1676: $format->{'header'} = $workbook->add_format(bold => 1,
1677: bottom => 1,
1678: align => 'center');
1679: $format->{'bold'} = $workbook->add_format(bold=>1);
1680: $format->{'h1'} = $workbook->add_format(bold=>1, size=>18);
1681: $format->{'h2'} = $workbook->add_format(bold=>1, size=>16);
1682: $format->{'h3'} = $workbook->add_format(bold=>1, size=>14);
1.255 matthew 1683: $format->{'h4'} = $workbook->add_format(bold=>1, size=>12);
1.246 matthew 1684: $format->{'i'} = $workbook->add_format(italic=>1);
1.180 matthew 1685: $format->{'date'} = $workbook->add_format(num_format=>
1.207 matthew 1686: 'mm/dd/yyyy hh:mm:ss');
1.180 matthew 1687: return $format;
1688: }
1689:
1690: ###############################################################
1691: ###############################################################
1.113 bowersj2 1692:
1693: =pod
1694:
1.648 raeburn 1695: =item * &create_workbook()
1.255 matthew 1696:
1697: Create an Excel worksheet. If it fails, output message on the
1698: request object and return undefs.
1699:
1700: Inputs: Apache request object
1701:
1702: Returns (undef) on failure,
1703: Excel worksheet object, scalar with filename, and formats
1704: from &Apache::loncommon::define_excel_formats on success
1705:
1706: =cut
1707:
1708: ###############################################################
1709: ###############################################################
1710: sub create_workbook {
1711: my ($r) = @_;
1712: #
1713: # Create the excel spreadsheet
1714: my $filename = '/prtspool/'.
1.258 albertel 1715: $env{'user.name'}.'_'.$env{'user.domain'}.'_'.
1.255 matthew 1716: time.'_'.rand(1000000000).'.xls';
1717: my $workbook = Spreadsheet::WriteExcel->new('/home/httpd'.$filename);
1718: if (! defined($workbook)) {
1719: $r->log_error("Error creating excel spreadsheet $filename: $!");
1720: $r->print('<p>'.&mt("Unable to create new Excel file. ".
1721: "This error has been logged. ".
1722: "Please alert your LON-CAPA administrator").
1723: '</p>');
1724: return (undef);
1725: }
1726: #
1727: $workbook->set_tempdir('/home/httpd/perl/tmp');
1728: #
1729: my $format = &Apache::loncommon::define_excel_formats($workbook);
1730: return ($workbook,$filename,$format);
1731: }
1732:
1733: ###############################################################
1734: ###############################################################
1735:
1736: =pod
1737:
1.648 raeburn 1738: =item * &create_text_file()
1.113 bowersj2 1739:
1.542 raeburn 1740: Create a file to write to and eventually make available to the user.
1.256 matthew 1741: If file creation fails, outputs an error message on the request object and
1742: return undefs.
1.113 bowersj2 1743:
1.256 matthew 1744: Inputs: Apache request object, and file suffix
1.113 bowersj2 1745:
1.256 matthew 1746: Returns (undef) on failure,
1747: Filehandle and filename on success.
1.113 bowersj2 1748:
1749: =cut
1750:
1.256 matthew 1751: ###############################################################
1752: ###############################################################
1753: sub create_text_file {
1754: my ($r,$suffix) = @_;
1755: if (! defined($suffix)) { $suffix = 'txt'; };
1756: my $fh;
1757: my $filename = '/prtspool/'.
1.258 albertel 1758: $env{'user.name'}.'_'.$env{'user.domain'}.'_'.
1.256 matthew 1759: time.'_'.rand(1000000000).'.'.$suffix;
1760: $fh = Apache::File->new('>/home/httpd'.$filename);
1761: if (! defined($fh)) {
1762: $r->log_error("Couldn't open $filename for output $!");
1.683 bisitz 1763: $r->print(&mt('Problems occurred in creating the output file. '
1764: .'This error has been logged. '
1765: .'Please alert your LON-CAPA administrator.'));
1.113 bowersj2 1766: }
1.256 matthew 1767: return ($fh,$filename)
1.113 bowersj2 1768: }
1769:
1770:
1.256 matthew 1771: =pod
1.113 bowersj2 1772:
1773: =back
1774:
1775: =cut
1.37 matthew 1776:
1777: ###############################################################
1.33 matthew 1778: ## Home server <option> list generating code ##
1779: ###############################################################
1.35 matthew 1780:
1.169 www 1781: # ------------------------------------------
1782:
1783: sub domain_select {
1784: my ($name,$value,$multiple)=@_;
1785: my %domains=map {
1.514 albertel 1786: $_ => $_.' '. &Apache::lonnet::domain($_,'description')
1.512 albertel 1787: } &Apache::lonnet::all_domains();
1.169 www 1788: if ($multiple) {
1789: $domains{''}=&mt('Any domain');
1.550 albertel 1790: $domains{'select_form_order'} = [sort {lc($a) cmp lc($b) } (keys(%domains))];
1.287 albertel 1791: return &multiple_select_form($name,$value,4,\%domains);
1.169 www 1792: } else {
1.550 albertel 1793: $domains{'select_form_order'} = [sort {lc($a) cmp lc($b) } (keys(%domains))];
1.169 www 1794: return &select_form($name,$value,%domains);
1795: }
1796: }
1797:
1.282 albertel 1798: #-------------------------------------------
1799:
1800: =pod
1801:
1.519 raeburn 1802: =head1 Routines for form select boxes
1803:
1804: =over 4
1805:
1.648 raeburn 1806: =item * &multiple_select_form($name,$value,$size,$hash,$order)
1.282 albertel 1807:
1808: Returns a string containing a <select> element int multiple mode
1809:
1810:
1811: Args:
1812: $name - name of the <select> element
1.506 raeburn 1813: $value - scalar or array ref of values that should already be selected
1.282 albertel 1814: $size - number of rows long the select element is
1.283 albertel 1815: $hash - the elements should be 'option' => 'shown text'
1.282 albertel 1816: (shown text should already have been &mt())
1.506 raeburn 1817: $order - (optional) array ref of the order to show the elements in
1.283 albertel 1818:
1.282 albertel 1819: =cut
1820:
1821: #-------------------------------------------
1.169 www 1822: sub multiple_select_form {
1.284 albertel 1823: my ($name,$value,$size,$hash,$order)=@_;
1.169 www 1824: my %selected = map { $_ => 1 } ref($value)?@{$value}:($value);
1825: my $output='';
1.191 matthew 1826: if (! defined($size)) {
1827: $size = 4;
1.283 albertel 1828: if (scalar(keys(%$hash))<4) {
1829: $size = scalar(keys(%$hash));
1.191 matthew 1830: }
1831: }
1.734 bisitz 1832: $output.="\n".'<select name="'.$name.'" size="'.$size.'" multiple="multiple">';
1.501 banghart 1833: my @order;
1.506 raeburn 1834: if (ref($order) eq 'ARRAY') {
1835: @order = @{$order};
1836: } else {
1837: @order = sort(keys(%$hash));
1.501 banghart 1838: }
1839: if (exists($$hash{'select_form_order'})) {
1840: @order = @{$$hash{'select_form_order'}};
1841: }
1842:
1.284 albertel 1843: foreach my $key (@order) {
1.356 albertel 1844: $output.='<option value="'.&HTML::Entities::encode($key,'"<>&').'" ';
1.284 albertel 1845: $output.='selected="selected" ' if ($selected{$key});
1846: $output.='>'.$hash->{$key}."</option>\n";
1.169 www 1847: }
1848: $output.="</select>\n";
1849: return $output;
1850: }
1851:
1.88 www 1852: #-------------------------------------------
1853:
1854: =pod
1855:
1.648 raeburn 1856: =item * &select_form($defdom,$name,%hash)
1.88 www 1857:
1858: Returns a string containing a <select name='$name' size='1'> form to
1859: allow a user to select options from a hash option_name => displayed text.
1860: See lonrights.pm for an example invocation and use.
1861:
1862: =cut
1863:
1864: #-------------------------------------------
1865: sub select_form {
1866: my ($def,$name,%hash) = @_;
1867: my $selectform = "<select name=\"$name\" size=\"1\">\n";
1.128 albertel 1868: my @keys;
1869: if (exists($hash{'select_form_order'})) {
1870: @keys=@{$hash{'select_form_order'}};
1871: } else {
1872: @keys=sort(keys(%hash));
1873: }
1.356 albertel 1874: foreach my $key (@keys) {
1875: $selectform.=
1876: '<option value="'.&HTML::Entities::encode($key,'"<>&').'" '.
1877: ($key eq $def ? 'selected="selected" ' : '').
1878: ">".&mt($hash{$key})."</option>\n";
1.88 www 1879: }
1880: $selectform.="</select>";
1881: return $selectform;
1882: }
1883:
1.475 www 1884: # For display filters
1885:
1886: sub display_filter {
1887: if (!$env{'form.show'}) { $env{'form.show'}=10; }
1.477 www 1888: if (!$env{'form.displayfilter'}) { $env{'form.displayfilter'}='currentfolder'; }
1.714 bisitz 1889: return '<span class="LC_nobreak"><label>'.&mt('Records [_1]',
1.475 www 1890: &Apache::lonmeta::selectbox('show',$env{'form.show'},undef,
1891: (&mt('all'),10,20,50,100,1000,10000))).
1.714 bisitz 1892: '</label></span> <span class="LC_nobreak">'.
1.475 www 1893: &mt('Filter [_1]',
1.477 www 1894: &select_form($env{'form.displayfilter'},
1895: 'displayfilter',
1896: ('currentfolder' => 'Current folder/page',
1897: 'containing' => 'Containing phrase',
1898: 'none' => 'None'))).
1.714 bisitz 1899: '<input type="text" name="containingphrase" size="30" value="'.&HTML::Entities::encode($env{'form.containingphrase'}).'" /></span>';
1.475 www 1900: }
1901:
1.167 www 1902: sub gradeleveldescription {
1903: my $gradelevel=shift;
1904: my %gradelevels=(0 => 'Not specified',
1905: 1 => 'Grade 1',
1906: 2 => 'Grade 2',
1907: 3 => 'Grade 3',
1908: 4 => 'Grade 4',
1909: 5 => 'Grade 5',
1910: 6 => 'Grade 6',
1911: 7 => 'Grade 7',
1912: 8 => 'Grade 8',
1913: 9 => 'Grade 9',
1914: 10 => 'Grade 10',
1915: 11 => 'Grade 11',
1916: 12 => 'Grade 12',
1917: 13 => 'Grade 13',
1918: 14 => '100 Level',
1919: 15 => '200 Level',
1920: 16 => '300 Level',
1921: 17 => '400 Level',
1922: 18 => 'Graduate Level');
1923: return &mt($gradelevels{$gradelevel});
1924: }
1925:
1.163 www 1926: sub select_level_form {
1927: my ($deflevel,$name)=@_;
1928: unless ($deflevel) { $deflevel=0; }
1.167 www 1929: my $selectform = "<select name=\"$name\" size=\"1\">\n";
1930: for (my $i=0; $i<=18; $i++) {
1931: $selectform.="<option value=\"$i\" ".
1.253 albertel 1932: ($i==$deflevel ? 'selected="selected" ' : '').
1.167 www 1933: ">".&gradeleveldescription($i)."</option>\n";
1934: }
1935: $selectform.="</select>";
1936: return $selectform;
1.163 www 1937: }
1.167 www 1938:
1.35 matthew 1939: #-------------------------------------------
1940:
1.45 matthew 1941: =pod
1942:
1.873 raeburn 1943: =item * &select_dom_form($defdom,$name,$includeempty,$showdomdesc,$onchange)
1.35 matthew 1944:
1945: Returns a string containing a <select name='$name' size='1'> form to
1946: allow a user to select the domain to preform an operation in.
1947: See loncreateuser.pm for an example invocation and use.
1948:
1.90 www 1949: If the $includeempty flag is set, it also includes an empty choice ("no domain
1950: selected");
1951:
1.743 raeburn 1952: If the $showdomdesc flag is set, the domain name is followed by the domain description.
1953:
1.872 raeburn 1954: 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 1955:
1.35 matthew 1956: =cut
1957:
1958: #-------------------------------------------
1.34 matthew 1959: sub select_dom_form {
1.872 raeburn 1960: my ($defdom,$name,$includeempty,$showdomdesc,$onchange) = @_;
1961: if ($onchange) {
1.874 raeburn 1962: $onchange = ' onchange="'.$onchange.'"';
1.743 raeburn 1963: }
1.550 albertel 1964: my @domains = sort {lc($a) cmp lc($b)} (&Apache::lonnet::all_domains());
1.90 www 1965: if ($includeempty) { @domains=('',@domains); }
1.743 raeburn 1966: my $selectdomain = "<select name=\"$name\" size=\"1\"$onchange>\n";
1.356 albertel 1967: foreach my $dom (@domains) {
1968: $selectdomain.="<option value=\"$dom\" ".
1.563 raeburn 1969: ($dom eq $defdom ? 'selected="selected" ' : '').'>'.$dom;
1970: if ($showdomdesc) {
1971: if ($dom ne '') {
1972: my $domdesc = &Apache::lonnet::domain($dom,'description');
1973: if ($domdesc ne '') {
1974: $selectdomain .= ' ('.$domdesc.')';
1975: }
1976: }
1977: }
1978: $selectdomain .= "</option>\n";
1.34 matthew 1979: }
1980: $selectdomain.="</select>";
1981: return $selectdomain;
1982: }
1983:
1.35 matthew 1984: #-------------------------------------------
1985:
1.45 matthew 1986: =pod
1987:
1.648 raeburn 1988: =item * &home_server_form_item($domain,$name,$defaultflag)
1.35 matthew 1989:
1.586 raeburn 1990: input: 4 arguments (two required, two optional) -
1991: $domain - domain of new user
1992: $name - name of form element
1993: $default - Value of 'default' causes a default item to be first
1994: option, and selected by default.
1995: $hide - Value of 'hide' causes hiding of the name of the server,
1996: if 1 server found, or default, if 0 found.
1.594 raeburn 1997: output: returns 2 items:
1.586 raeburn 1998: (a) form element which contains either:
1999: (i) <select name="$name">
2000: <option value="$hostid1">$hostid $servers{$hostid}</option>
2001: <option value="$hostid2">$hostid $servers{$hostid}</option>
2002: </select>
2003: form item if there are multiple library servers in $domain, or
2004: (ii) an <input type="hidden" name="$name" value="$hostid" /> form item
2005: if there is only one library server in $domain.
2006:
2007: (b) number of library servers found.
2008:
2009: See loncreateuser.pm for example of use.
1.35 matthew 2010:
2011: =cut
2012:
2013: #-------------------------------------------
1.586 raeburn 2014: sub home_server_form_item {
2015: my ($domain,$name,$default,$hide) = @_;
1.513 albertel 2016: my %servers = &Apache::lonnet::get_servers($domain,'library');
1.586 raeburn 2017: my $result;
2018: my $numlib = keys(%servers);
2019: if ($numlib > 1) {
2020: $result .= '<select name="'.$name.'" />'."\n";
2021: if ($default) {
1.804 bisitz 2022: $result .= '<option value="default" selected="selected">'.&mt('default').
1.586 raeburn 2023: '</option>'."\n";
2024: }
2025: foreach my $hostid (sort(keys(%servers))) {
2026: $result.= '<option value="'.$hostid.'">'.
2027: $hostid.' '.$servers{$hostid}."</option>\n";
2028: }
2029: $result .= '</select>'."\n";
2030: } elsif ($numlib == 1) {
2031: my $hostid;
2032: foreach my $item (keys(%servers)) {
2033: $hostid = $item;
2034: }
2035: $result .= '<input type="hidden" name="'.$name.'" value="'.
2036: $hostid.'" />';
2037: if (!$hide) {
2038: $result .= $hostid.' '.$servers{$hostid};
2039: }
2040: $result .= "\n";
2041: } elsif ($default) {
2042: $result .= '<input type="hidden" name="'.$name.
2043: '" value="default" />';
2044: if (!$hide) {
2045: $result .= &mt('default');
2046: }
2047: $result .= "\n";
1.33 matthew 2048: }
1.586 raeburn 2049: return ($result,$numlib);
1.33 matthew 2050: }
1.112 bowersj2 2051:
2052: =pod
2053:
1.534 albertel 2054: =back
2055:
1.112 bowersj2 2056: =cut
1.87 matthew 2057:
2058: ###############################################################
1.112 bowersj2 2059: ## Decoding User Agent ##
1.87 matthew 2060: ###############################################################
2061:
2062: =pod
2063:
1.112 bowersj2 2064: =head1 Decoding the User Agent
2065:
2066: =over 4
2067:
2068: =item * &decode_user_agent()
1.87 matthew 2069:
2070: Inputs: $r
2071:
2072: Outputs:
2073:
2074: =over 4
2075:
1.112 bowersj2 2076: =item * $httpbrowser
1.87 matthew 2077:
1.112 bowersj2 2078: =item * $clientbrowser
1.87 matthew 2079:
1.112 bowersj2 2080: =item * $clientversion
1.87 matthew 2081:
1.112 bowersj2 2082: =item * $clientmathml
1.87 matthew 2083:
1.112 bowersj2 2084: =item * $clientunicode
1.87 matthew 2085:
1.112 bowersj2 2086: =item * $clientos
1.87 matthew 2087:
2088: =back
2089:
1.157 matthew 2090: =back
2091:
1.87 matthew 2092: =cut
2093:
2094: ###############################################################
2095: ###############################################################
2096: sub decode_user_agent {
1.247 albertel 2097: my ($r)=@_;
1.87 matthew 2098: my @browsertype=split(/\&/,$Apache::lonnet::perlvar{"lonBrowsDet"});
2099: my %mathcap=split(/\&/,$$Apache::lonnet::perlvar{"lonMathML"});
2100: my $httpbrowser=$ENV{"HTTP_USER_AGENT"};
1.247 albertel 2101: if (!$httpbrowser && $r) { $httpbrowser=$r->header_in('User-Agent'); }
1.87 matthew 2102: my $clientbrowser='unknown';
2103: my $clientversion='0';
2104: my $clientmathml='';
2105: my $clientunicode='0';
2106: for (my $i=0;$i<=$#browsertype;$i++) {
2107: my ($bname,$match,$notmatch,$vreg,$minv,$univ)=split(/\:/,$browsertype[$i]);
2108: if (($httpbrowser=~/$match/i) && ($httpbrowser!~/$notmatch/i)) {
2109: $clientbrowser=$bname;
2110: $httpbrowser=~/$vreg/i;
2111: $clientversion=$1;
2112: $clientmathml=($clientversion>=$minv);
2113: $clientunicode=($clientversion>=$univ);
2114: }
2115: }
2116: my $clientos='unknown';
2117: if (($httpbrowser=~/linux/i) ||
2118: ($httpbrowser=~/unix/i) ||
2119: ($httpbrowser=~/ux/i) ||
2120: ($httpbrowser=~/solaris/i)) { $clientos='unix'; }
2121: if (($httpbrowser=~/vax/i) ||
2122: ($httpbrowser=~/vms/i)) { $clientos='vms'; }
2123: if ($httpbrowser=~/next/i) { $clientos='next'; }
2124: if (($httpbrowser=~/mac/i) ||
2125: ($httpbrowser=~/powerpc/i)) { $clientos='mac'; }
2126: if ($httpbrowser=~/win/i) { $clientos='win'; }
2127: if ($httpbrowser=~/embed/i) { $clientos='pda'; }
2128: return ($httpbrowser,$clientbrowser,$clientversion,$clientmathml,
2129: $clientunicode,$clientos,);
2130: }
2131:
1.32 matthew 2132: ###############################################################
2133: ## Authentication changing form generation subroutines ##
2134: ###############################################################
2135: ##
2136: ## All of the authform_xxxxxxx subroutines take their inputs in a
2137: ## hash, and have reasonable default values.
2138: ##
2139: ## formname = the name given in the <form> tag.
1.35 matthew 2140: #-------------------------------------------
2141:
1.45 matthew 2142: =pod
2143:
1.112 bowersj2 2144: =head1 Authentication Routines
2145:
2146: =over 4
2147:
1.648 raeburn 2148: =item * &authform_xxxxxx()
1.35 matthew 2149:
2150: The authform_xxxxxx subroutines provide javascript and html forms which
2151: handle some of the conveniences required for authentication forms.
2152: This is not an optimal method, but it works.
2153:
2154: =over 4
2155:
1.112 bowersj2 2156: =item * authform_header
1.35 matthew 2157:
1.112 bowersj2 2158: =item * authform_authorwarning
1.35 matthew 2159:
1.112 bowersj2 2160: =item * authform_nochange
1.35 matthew 2161:
1.112 bowersj2 2162: =item * authform_kerberos
1.35 matthew 2163:
1.112 bowersj2 2164: =item * authform_internal
1.35 matthew 2165:
1.112 bowersj2 2166: =item * authform_filesystem
1.35 matthew 2167:
2168: =back
2169:
1.648 raeburn 2170: See loncreateuser.pm for invocation and use examples.
1.157 matthew 2171:
1.35 matthew 2172: =cut
2173:
2174: #-------------------------------------------
1.32 matthew 2175: sub authform_header{
2176: my %in = (
2177: formname => 'cu',
1.80 albertel 2178: kerb_def_dom => '',
1.32 matthew 2179: @_,
2180: );
2181: $in{'formname'} = 'document.' . $in{'formname'};
2182: my $result='';
1.80 albertel 2183:
2184: #---------------------------------------------- Code for upper case translation
2185: my $Javascript_toUpperCase;
2186: unless ($in{kerb_def_dom}) {
2187: $Javascript_toUpperCase =<<"END";
2188: switch (choice) {
2189: case 'krb': currentform.elements[choicearg].value =
2190: currentform.elements[choicearg].value.toUpperCase();
2191: break;
2192: default:
2193: }
2194: END
2195: } else {
2196: $Javascript_toUpperCase = "";
2197: }
2198:
1.165 raeburn 2199: my $radioval = "'nochange'";
1.591 raeburn 2200: if (defined($in{'curr_authtype'})) {
2201: if ($in{'curr_authtype'} ne '') {
2202: $radioval = "'".$in{'curr_authtype'}."arg'";
2203: }
1.174 matthew 2204: }
1.165 raeburn 2205: my $argfield = 'null';
1.591 raeburn 2206: if (defined($in{'mode'})) {
1.165 raeburn 2207: if ($in{'mode'} eq 'modifycourse') {
1.591 raeburn 2208: if (defined($in{'curr_autharg'})) {
2209: if ($in{'curr_autharg'} ne '') {
1.165 raeburn 2210: $argfield = "'$in{'curr_autharg'}'";
2211: }
2212: }
2213: }
2214: }
2215:
1.32 matthew 2216: $result.=<<"END";
2217: var current = new Object();
1.165 raeburn 2218: current.radiovalue = $radioval;
2219: current.argfield = $argfield;
1.32 matthew 2220:
2221: function changed_radio(choice,currentform) {
2222: var choicearg = choice + 'arg';
2223: // If a radio button in changed, we need to change the argfield
2224: if (current.radiovalue != choice) {
2225: current.radiovalue = choice;
2226: if (current.argfield != null) {
2227: currentform.elements[current.argfield].value = '';
2228: }
2229: if (choice == 'nochange') {
2230: current.argfield = null;
2231: } else {
2232: current.argfield = choicearg;
2233: switch(choice) {
2234: case 'krb':
2235: currentform.elements[current.argfield].value =
2236: "$in{'kerb_def_dom'}";
2237: break;
2238: default:
2239: break;
2240: }
2241: }
2242: }
2243: return;
2244: }
1.22 www 2245:
1.32 matthew 2246: function changed_text(choice,currentform) {
2247: var choicearg = choice + 'arg';
2248: if (currentform.elements[choicearg].value !='') {
1.80 albertel 2249: $Javascript_toUpperCase
1.32 matthew 2250: // clear old field
2251: if ((current.argfield != choicearg) && (current.argfield != null)) {
2252: currentform.elements[current.argfield].value = '';
2253: }
2254: current.argfield = choicearg;
2255: }
2256: set_auth_radio_buttons(choice,currentform);
2257: return;
1.20 www 2258: }
1.32 matthew 2259:
2260: function set_auth_radio_buttons(newvalue,currentform) {
2261: var i=0;
2262: while (i < currentform.login.length) {
2263: if (currentform.login[i].value == newvalue) { break; }
2264: i++;
2265: }
2266: if (i == currentform.login.length) {
2267: return;
2268: }
2269: current.radiovalue = newvalue;
2270: currentform.login[i].checked = true;
2271: return;
2272: }
2273: END
2274: return $result;
2275: }
2276:
2277: sub authform_authorwarning{
2278: my $result='';
1.144 matthew 2279: $result='<i>'.
2280: &mt('As a general rule, only authors or co-authors should be '.
2281: 'filesystem authenticated '.
2282: '(which allows access to the server filesystem).')."</i>\n";
1.32 matthew 2283: return $result;
2284: }
2285:
2286: sub authform_nochange{
2287: my %in = (
2288: formname => 'document.cu',
2289: kerb_def_dom => 'MSU.EDU',
2290: @_,
2291: );
1.586 raeburn 2292: my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
2293: my $result;
2294: if (keys(%can_assign) == 0) {
2295: $result = &mt('Under you current role you are not permitted to change login settings for this user');
2296: } else {
2297: $result = '<label>'.&mt('[_1] Do not change login data',
2298: '<input type="radio" name="login" value="nochange" '.
2299: 'checked="checked" onclick="'.
1.281 albertel 2300: "javascript:changed_radio('nochange',$in{'formname'});".'" />').
2301: '</label>';
1.586 raeburn 2302: }
1.32 matthew 2303: return $result;
2304: }
2305:
1.591 raeburn 2306: sub authform_kerberos {
1.32 matthew 2307: my %in = (
2308: formname => 'document.cu',
2309: kerb_def_dom => 'MSU.EDU',
1.80 albertel 2310: kerb_def_auth => 'krb4',
1.32 matthew 2311: @_,
2312: );
1.586 raeburn 2313: my ($check4,$check5,$krbcheck,$krbarg,$krbver,$result,$authtype,
2314: $autharg,$jscall);
2315: my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
1.80 albertel 2316: if ($in{'kerb_def_auth'} eq 'krb5') {
1.772 bisitz 2317: $check5 = ' checked="checked"';
1.80 albertel 2318: } else {
1.772 bisitz 2319: $check4 = ' checked="checked"';
1.80 albertel 2320: }
1.165 raeburn 2321: $krbarg = $in{'kerb_def_dom'};
1.591 raeburn 2322: if (defined($in{'curr_authtype'})) {
2323: if ($in{'curr_authtype'} eq 'krb') {
1.772 bisitz 2324: $krbcheck = ' checked="checked"';
1.623 raeburn 2325: if (defined($in{'mode'})) {
2326: if ($in{'mode'} eq 'modifyuser') {
2327: $krbcheck = '';
2328: }
2329: }
1.591 raeburn 2330: if (defined($in{'curr_kerb_ver'})) {
2331: if ($in{'curr_krb_ver'} eq '5') {
1.772 bisitz 2332: $check5 = ' checked="checked"';
1.591 raeburn 2333: $check4 = '';
2334: } else {
1.772 bisitz 2335: $check4 = ' checked="checked"';
1.591 raeburn 2336: $check5 = '';
2337: }
1.586 raeburn 2338: }
1.591 raeburn 2339: if (defined($in{'curr_autharg'})) {
1.165 raeburn 2340: $krbarg = $in{'curr_autharg'};
2341: }
1.586 raeburn 2342: if (!$can_assign{'krb4'} && !$can_assign{'krb5'}) {
1.591 raeburn 2343: if (defined($in{'curr_autharg'})) {
1.586 raeburn 2344: $result =
2345: &mt('Currently Kerberos authenticated with domain [_1] Version [_2].',
2346: $in{'curr_autharg'},$krbver);
2347: } else {
2348: $result =
2349: &mt('Currently Kerberos authenticated, Version [_1].',$krbver);
2350: }
2351: return $result;
2352: }
2353: }
2354: } else {
2355: if ($authnum == 1) {
1.784 bisitz 2356: $authtype = '<input type="hidden" name="login" value="krb" />';
1.165 raeburn 2357: }
2358: }
1.586 raeburn 2359: if (!$can_assign{'krb4'} && !$can_assign{'krb5'}) {
2360: return;
1.587 raeburn 2361: } elsif ($authtype eq '') {
1.591 raeburn 2362: if (defined($in{'mode'})) {
1.587 raeburn 2363: if ($in{'mode'} eq 'modifycourse') {
2364: if ($authnum == 1) {
1.784 bisitz 2365: $authtype = '<input type="hidden" name="login" value="krb" />';
1.587 raeburn 2366: }
2367: }
2368: }
1.586 raeburn 2369: }
2370: $jscall = "javascript:changed_radio('krb',$in{'formname'});";
2371: if ($authtype eq '') {
2372: $authtype = '<input type="radio" name="login" value="krb" '.
2373: 'onclick="'.$jscall.'" onchange="'.$jscall.'"'.
2374: $krbcheck.' />';
2375: }
2376: if (($can_assign{'krb4'} && $can_assign{'krb5'}) ||
2377: ($can_assign{'krb4'} && !$can_assign{'krb5'} &&
2378: $in{'curr_authtype'} eq 'krb5') ||
2379: (!$can_assign{'krb4'} && $can_assign{'krb5'} &&
2380: $in{'curr_authtype'} eq 'krb4')) {
2381: $result .= &mt
1.144 matthew 2382: ('[_1] Kerberos authenticated with domain [_2] '.
1.281 albertel 2383: '[_3] Version 4 [_4] Version 5 [_5]',
1.586 raeburn 2384: '<label>'.$authtype,
1.281 albertel 2385: '</label><input type="text" size="10" name="krbarg" '.
1.165 raeburn 2386: 'value="'.$krbarg.'" '.
1.144 matthew 2387: 'onchange="'.$jscall.'" />',
1.281 albertel 2388: '<label><input type="radio" name="krbver" value="4" '.$check4.' />',
2389: '</label><label><input type="radio" name="krbver" value="5" '.$check5.' />',
2390: '</label>');
1.586 raeburn 2391: } elsif ($can_assign{'krb4'}) {
2392: $result .= &mt
2393: ('[_1] Kerberos authenticated with domain [_2] '.
2394: '[_3] Version 4 [_4]',
2395: '<label>'.$authtype,
2396: '</label><input type="text" size="10" name="krbarg" '.
2397: 'value="'.$krbarg.'" '.
2398: 'onchange="'.$jscall.'" />',
2399: '<label><input type="hidden" name="krbver" value="4" />',
2400: '</label>');
2401: } elsif ($can_assign{'krb5'}) {
2402: $result .= &mt
2403: ('[_1] Kerberos authenticated with domain [_2] '.
2404: '[_3] Version 5 [_4]',
2405: '<label>'.$authtype,
2406: '</label><input type="text" size="10" name="krbarg" '.
2407: 'value="'.$krbarg.'" '.
2408: 'onchange="'.$jscall.'" />',
2409: '<label><input type="hidden" name="krbver" value="5" />',
2410: '</label>');
2411: }
1.32 matthew 2412: return $result;
2413: }
2414:
2415: sub authform_internal{
1.586 raeburn 2416: my %in = (
1.32 matthew 2417: formname => 'document.cu',
2418: kerb_def_dom => 'MSU.EDU',
2419: @_,
2420: );
1.586 raeburn 2421: my ($intcheck,$intarg,$result,$authtype,$autharg,$jscall);
2422: my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
1.591 raeburn 2423: if (defined($in{'curr_authtype'})) {
2424: if ($in{'curr_authtype'} eq 'int') {
1.586 raeburn 2425: if ($can_assign{'int'}) {
1.772 bisitz 2426: $intcheck = 'checked="checked" ';
1.623 raeburn 2427: if (defined($in{'mode'})) {
2428: if ($in{'mode'} eq 'modifyuser') {
2429: $intcheck = '';
2430: }
2431: }
1.591 raeburn 2432: if (defined($in{'curr_autharg'})) {
1.586 raeburn 2433: $intarg = $in{'curr_autharg'};
2434: }
2435: } else {
2436: $result = &mt('Currently internally authenticated.');
2437: return $result;
1.165 raeburn 2438: }
2439: }
1.586 raeburn 2440: } else {
2441: if ($authnum == 1) {
1.784 bisitz 2442: $authtype = '<input type="hidden" name="login" value="int" />';
1.586 raeburn 2443: }
2444: }
2445: if (!$can_assign{'int'}) {
2446: return;
1.587 raeburn 2447: } elsif ($authtype eq '') {
1.591 raeburn 2448: if (defined($in{'mode'})) {
1.587 raeburn 2449: if ($in{'mode'} eq 'modifycourse') {
2450: if ($authnum == 1) {
1.784 bisitz 2451: $authtype = '<input type="hidden" name="login" value="int" />';
1.587 raeburn 2452: }
2453: }
2454: }
1.165 raeburn 2455: }
1.586 raeburn 2456: $jscall = "javascript:changed_radio('int',$in{'formname'});";
2457: if ($authtype eq '') {
2458: $authtype = '<input type="radio" name="login" value="int" '.$intcheck.
2459: ' onchange="'.$jscall.'" onclick="'.$jscall.'" />';
2460: }
1.605 bisitz 2461: $autharg = '<input type="password" size="10" name="intarg" value="'.
1.586 raeburn 2462: $intarg.'" onchange="'.$jscall.'" />';
2463: $result = &mt
1.144 matthew 2464: ('[_1] Internally authenticated (with initial password [_2])',
1.586 raeburn 2465: '<label>'.$authtype,'</label>'.$autharg);
1.824 bisitz 2466: $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 2467: return $result;
2468: }
2469:
2470: sub authform_local{
2471: my %in = (
2472: formname => 'document.cu',
2473: kerb_def_dom => 'MSU.EDU',
2474: @_,
2475: );
1.586 raeburn 2476: my ($loccheck,$locarg,$result,$authtype,$autharg,$jscall);
2477: my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
1.591 raeburn 2478: if (defined($in{'curr_authtype'})) {
2479: if ($in{'curr_authtype'} eq 'loc') {
1.586 raeburn 2480: if ($can_assign{'loc'}) {
1.772 bisitz 2481: $loccheck = 'checked="checked" ';
1.623 raeburn 2482: if (defined($in{'mode'})) {
2483: if ($in{'mode'} eq 'modifyuser') {
2484: $loccheck = '';
2485: }
2486: }
1.591 raeburn 2487: if (defined($in{'curr_autharg'})) {
1.586 raeburn 2488: $locarg = $in{'curr_autharg'};
2489: }
2490: } else {
2491: $result = &mt('Currently using local (institutional) authentication.');
2492: return $result;
1.165 raeburn 2493: }
2494: }
1.586 raeburn 2495: } else {
2496: if ($authnum == 1) {
1.784 bisitz 2497: $authtype = '<input type="hidden" name="login" value="loc" />';
1.586 raeburn 2498: }
2499: }
2500: if (!$can_assign{'loc'}) {
2501: return;
1.587 raeburn 2502: } elsif ($authtype eq '') {
1.591 raeburn 2503: if (defined($in{'mode'})) {
1.587 raeburn 2504: if ($in{'mode'} eq 'modifycourse') {
2505: if ($authnum == 1) {
1.784 bisitz 2506: $authtype = '<input type="hidden" name="login" value="loc" />';
1.587 raeburn 2507: }
2508: }
2509: }
1.165 raeburn 2510: }
1.586 raeburn 2511: $jscall = "javascript:changed_radio('loc',$in{'formname'});";
2512: if ($authtype eq '') {
2513: $authtype = '<input type="radio" name="login" value="loc" '.
2514: $loccheck.' onchange="'.$jscall.'" onclick="'.
2515: $jscall.'" />';
2516: }
2517: $autharg = '<input type="text" size="10" name="locarg" value="'.
2518: $locarg.'" onchange="'.$jscall.'" />';
2519: $result = &mt('[_1] Local Authentication with argument [_2]',
2520: '<label>'.$authtype,'</label>'.$autharg);
1.32 matthew 2521: return $result;
2522: }
2523:
2524: sub authform_filesystem{
2525: my %in = (
2526: formname => 'document.cu',
2527: kerb_def_dom => 'MSU.EDU',
2528: @_,
2529: );
1.586 raeburn 2530: my ($fsyscheck,$result,$authtype,$autharg,$jscall);
2531: my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
1.591 raeburn 2532: if (defined($in{'curr_authtype'})) {
2533: if ($in{'curr_authtype'} eq 'fsys') {
1.586 raeburn 2534: if ($can_assign{'fsys'}) {
1.772 bisitz 2535: $fsyscheck = 'checked="checked" ';
1.623 raeburn 2536: if (defined($in{'mode'})) {
2537: if ($in{'mode'} eq 'modifyuser') {
2538: $fsyscheck = '';
2539: }
2540: }
1.586 raeburn 2541: } else {
2542: $result = &mt('Currently Filesystem Authenticated.');
2543: return $result;
2544: }
2545: }
2546: } else {
2547: if ($authnum == 1) {
1.784 bisitz 2548: $authtype = '<input type="hidden" name="login" value="fsys" />';
1.586 raeburn 2549: }
2550: }
2551: if (!$can_assign{'fsys'}) {
2552: return;
1.587 raeburn 2553: } elsif ($authtype eq '') {
1.591 raeburn 2554: if (defined($in{'mode'})) {
1.587 raeburn 2555: if ($in{'mode'} eq 'modifycourse') {
2556: if ($authnum == 1) {
1.784 bisitz 2557: $authtype = '<input type="hidden" name="login" value="fsys" />';
1.587 raeburn 2558: }
2559: }
2560: }
1.586 raeburn 2561: }
2562: $jscall = "javascript:changed_radio('fsys',$in{'formname'});";
2563: if ($authtype eq '') {
2564: $authtype = '<input type="radio" name="login" value="fsys" '.
2565: $fsyscheck.' onchange="'.$jscall.'" onclick="'.
2566: $jscall.'" />';
2567: }
2568: $autharg = '<input type="text" size="10" name="fsysarg" value=""'.
2569: ' onchange="'.$jscall.'" />';
2570: $result = &mt
1.144 matthew 2571: ('[_1] Filesystem Authenticated (with initial password [_2])',
1.281 albertel 2572: '<label><input type="radio" name="login" value="fsys" '.
1.586 raeburn 2573: $fsyscheck.'onchange="'.$jscall.'" onclick="'.$jscall.'" />',
1.605 bisitz 2574: '</label><input type="password" size="10" name="fsysarg" value="" '.
1.144 matthew 2575: 'onchange="'.$jscall.'" />');
1.32 matthew 2576: return $result;
2577: }
2578:
1.586 raeburn 2579: sub get_assignable_auth {
2580: my ($dom) = @_;
2581: if ($dom eq '') {
2582: $dom = $env{'request.role.domain'};
2583: }
2584: my %can_assign = (
2585: krb4 => 1,
2586: krb5 => 1,
2587: int => 1,
2588: loc => 1,
2589: );
2590: my %domconfig = &Apache::lonnet::get_dom('configuration',['usercreation'],$dom);
2591: if (ref($domconfig{'usercreation'}) eq 'HASH') {
2592: if (ref($domconfig{'usercreation'}{'authtypes'}) eq 'HASH') {
2593: my $authhash = $domconfig{'usercreation'}{'authtypes'};
2594: my $context;
2595: if ($env{'request.role'} =~ /^au/) {
2596: $context = 'author';
2597: } elsif ($env{'request.role'} =~ /^dc/) {
2598: $context = 'domain';
2599: } elsif ($env{'request.course.id'}) {
2600: $context = 'course';
2601: }
2602: if ($context) {
2603: if (ref($authhash->{$context}) eq 'HASH') {
2604: %can_assign = %{$authhash->{$context}};
2605: }
2606: }
2607: }
2608: }
2609: my $authnum = 0;
2610: foreach my $key (keys(%can_assign)) {
2611: if ($can_assign{$key}) {
2612: $authnum ++;
2613: }
2614: }
2615: if ($can_assign{'krb4'} && $can_assign{'krb5'}) {
2616: $authnum --;
2617: }
2618: return ($authnum,%can_assign);
2619: }
2620:
1.80 albertel 2621: ###############################################################
2622: ## Get Kerberos Defaults for Domain ##
2623: ###############################################################
2624: ##
2625: ## Returns default kerberos version and an associated argument
2626: ## as listed in file domain.tab. If not listed, provides
2627: ## appropriate default domain and kerberos version.
2628: ##
2629: #-------------------------------------------
2630:
2631: =pod
2632:
1.648 raeburn 2633: =item * &get_kerberos_defaults()
1.80 albertel 2634:
2635: get_kerberos_defaults($target_domain) returns the default kerberos
1.641 raeburn 2636: version and domain. If not found, it defaults to version 4 and the
2637: domain of the server.
1.80 albertel 2638:
1.648 raeburn 2639: =over 4
2640:
1.80 albertel 2641: ($def_version, $def_krb_domain) = &get_kerberos_defaults($target_domain);
2642:
1.648 raeburn 2643: =back
2644:
2645: =back
2646:
1.80 albertel 2647: =cut
2648:
2649: #-------------------------------------------
2650: sub get_kerberos_defaults {
2651: my $domain=shift;
1.641 raeburn 2652: my ($krbdef,$krbdefdom);
2653: my %domdefaults = &Apache::lonnet::get_domain_defaults($domain);
2654: if (($domdefaults{'auth_def'} =~/^krb(4|5)$/) && ($domdefaults{'auth_arg_def'} ne '')) {
2655: $krbdef = $domdefaults{'auth_def'};
2656: $krbdefdom = $domdefaults{'auth_arg_def'};
2657: } else {
1.80 albertel 2658: $ENV{'SERVER_NAME'}=~/(\w+\.\w+)$/;
2659: my $krbdefdom=$1;
2660: $krbdefdom=~tr/a-z/A-Z/;
2661: $krbdef = "krb4";
2662: }
2663: return ($krbdef,$krbdefdom);
2664: }
1.112 bowersj2 2665:
1.32 matthew 2666:
1.46 matthew 2667: ###############################################################
2668: ## Thesaurus Functions ##
2669: ###############################################################
1.20 www 2670:
1.46 matthew 2671: =pod
1.20 www 2672:
1.112 bowersj2 2673: =head1 Thesaurus Functions
2674:
2675: =over 4
2676:
1.648 raeburn 2677: =item * &initialize_keywords()
1.46 matthew 2678:
2679: Initializes the package variable %Keywords if it is empty. Uses the
2680: package variable $thesaurus_db_file.
2681:
2682: =cut
2683:
2684: ###################################################
2685:
2686: sub initialize_keywords {
2687: return 1 if (scalar keys(%Keywords));
2688: # If we are here, %Keywords is empty, so fill it up
2689: # Make sure the file we need exists...
2690: if (! -e $thesaurus_db_file) {
2691: &Apache::lonnet::logthis("Attempt to access $thesaurus_db_file".
2692: " failed because it does not exist");
2693: return 0;
2694: }
2695: # Set up the hash as a database
2696: my %thesaurus_db;
2697: if (! tie(%thesaurus_db,'GDBM_File',
1.53 albertel 2698: $thesaurus_db_file,&GDBM_READER(),0640)){
1.46 matthew 2699: &Apache::lonnet::logthis("Could not tie \%thesaurus_db to ".
2700: $thesaurus_db_file);
2701: return 0;
2702: }
2703: # Get the average number of appearances of a word.
2704: my $avecount = $thesaurus_db{'average.count'};
2705: # Put keywords (those that appear > average) into %Keywords
2706: while (my ($word,$data)=each (%thesaurus_db)) {
2707: my ($count,undef) = split /:/,$data;
2708: $Keywords{$word}++ if ($count > $avecount);
2709: }
2710: untie %thesaurus_db;
2711: # Remove special values from %Keywords.
1.356 albertel 2712: foreach my $value ('total.count','average.count') {
2713: delete($Keywords{$value}) if (exists($Keywords{$value}));
1.586 raeburn 2714: }
1.46 matthew 2715: return 1;
2716: }
2717:
2718: ###################################################
2719:
2720: =pod
2721:
1.648 raeburn 2722: =item * &keyword($word)
1.46 matthew 2723:
2724: Returns true if $word is a keyword. A keyword is a word that appears more
2725: than the average number of times in the thesaurus database. Calls
2726: &initialize_keywords
2727:
2728: =cut
2729:
2730: ###################################################
1.20 www 2731:
2732: sub keyword {
1.46 matthew 2733: return if (!&initialize_keywords());
2734: my $word=lc(shift());
2735: $word=~s/\W//g;
2736: return exists($Keywords{$word});
1.20 www 2737: }
1.46 matthew 2738:
2739: ###############################################################
2740:
2741: =pod
1.20 www 2742:
1.648 raeburn 2743: =item * &get_related_words()
1.46 matthew 2744:
1.160 matthew 2745: Look up a word in the thesaurus. Takes a scalar argument and returns
1.46 matthew 2746: an array of words. If the keyword is not in the thesaurus, an empty array
2747: will be returned. The order of the words returned is determined by the
2748: database which holds them.
2749:
2750: Uses global $thesaurus_db_file.
2751:
2752: =cut
2753:
2754: ###############################################################
2755: sub get_related_words {
2756: my $keyword = shift;
2757: my %thesaurus_db;
2758: if (! -e $thesaurus_db_file) {
2759: &Apache::lonnet::logthis("Attempt to access $thesaurus_db_file ".
2760: "failed because the file does not exist");
2761: return ();
2762: }
2763: if (! tie(%thesaurus_db,'GDBM_File',
1.53 albertel 2764: $thesaurus_db_file,&GDBM_READER(),0640)){
1.46 matthew 2765: return ();
2766: }
2767: my @Words=();
1.429 www 2768: my $count=0;
1.46 matthew 2769: if (exists($thesaurus_db{$keyword})) {
1.356 albertel 2770: # The first element is the number of times
2771: # the word appears. We do not need it now.
1.429 www 2772: my (undef,@RelatedWords) = (split(/:/,$thesaurus_db{$keyword}));
2773: my (undef,$mostfrequentcount)=split(/\,/,$RelatedWords[0]);
2774: my $threshold=$mostfrequentcount/10;
2775: foreach my $possibleword (@RelatedWords) {
2776: my ($word,$wordcount)=split(/\,/,$possibleword);
2777: if ($wordcount>$threshold) {
2778: push(@Words,$word);
2779: $count++;
2780: if ($count>10) { last; }
2781: }
1.20 www 2782: }
2783: }
1.46 matthew 2784: untie %thesaurus_db;
2785: return @Words;
1.14 harris41 2786: }
1.46 matthew 2787:
1.112 bowersj2 2788: =pod
2789:
2790: =back
2791:
2792: =cut
1.61 www 2793:
2794: # -------------------------------------------------------------- Plaintext name
1.81 albertel 2795: =pod
2796:
1.112 bowersj2 2797: =head1 User Name Functions
2798:
2799: =over 4
2800:
1.648 raeburn 2801: =item * &plainname($uname,$udom,$first)
1.81 albertel 2802:
1.112 bowersj2 2803: Takes a users logon name and returns it as a string in
1.226 albertel 2804: "first middle last generation" form
2805: if $first is set to 'lastname' then it returns it as
2806: 'lastname generation, firstname middlename' if their is a lastname
1.81 albertel 2807:
2808: =cut
1.61 www 2809:
1.295 www 2810:
1.81 albertel 2811: ###############################################################
1.61 www 2812: sub plainname {
1.226 albertel 2813: my ($uname,$udom,$first)=@_;
1.537 albertel 2814: return if (!defined($uname) || !defined($udom));
1.295 www 2815: my %names=&getnames($uname,$udom);
1.226 albertel 2816: my $name=&Apache::lonnet::format_name($names{'firstname'},
2817: $names{'middlename'},
2818: $names{'lastname'},
2819: $names{'generation'},$first);
2820: $name=~s/^\s+//;
1.62 www 2821: $name=~s/\s+$//;
2822: $name=~s/\s+/ /g;
1.353 albertel 2823: if ($name !~ /\S/) { $name=$uname.':'.$udom; }
1.62 www 2824: return $name;
1.61 www 2825: }
1.66 www 2826:
2827: # -------------------------------------------------------------------- Nickname
1.81 albertel 2828: =pod
2829:
1.648 raeburn 2830: =item * &nickname($uname,$udom)
1.81 albertel 2831:
2832: Gets a users name and returns it as a string as
2833:
2834: ""nickname""
1.66 www 2835:
1.81 albertel 2836: if the user has a nickname or
2837:
2838: "first middle last generation"
2839:
2840: if the user does not
2841:
2842: =cut
1.66 www 2843:
2844: sub nickname {
2845: my ($uname,$udom)=@_;
1.537 albertel 2846: return if (!defined($uname) || !defined($udom));
1.295 www 2847: my %names=&getnames($uname,$udom);
1.68 albertel 2848: my $name=$names{'nickname'};
1.66 www 2849: if ($name) {
2850: $name='"'.$name.'"';
2851: } else {
2852: $name=$names{'firstname'}.' '.$names{'middlename'}.' '.
2853: $names{'lastname'}.' '.$names{'generation'};
2854: $name=~s/\s+$//;
2855: $name=~s/\s+/ /g;
2856: }
2857: return $name;
2858: }
2859:
1.295 www 2860: sub getnames {
2861: my ($uname,$udom)=@_;
1.537 albertel 2862: return if (!defined($uname) || !defined($udom));
1.433 albertel 2863: if ($udom eq 'public' && $uname eq 'public') {
2864: return ('lastname' => &mt('Public'));
2865: }
1.295 www 2866: my $id=$uname.':'.$udom;
2867: my ($names,$cached)=&Apache::lonnet::is_cached_new('namescache',$id);
2868: if ($cached) {
2869: return %{$names};
2870: } else {
2871: my %loadnames=&Apache::lonnet::get('environment',
2872: ['firstname','middlename','lastname','generation','nickname'],
2873: $udom,$uname);
2874: &Apache::lonnet::do_cache_new('namescache',$id,\%loadnames);
2875: return %loadnames;
2876: }
2877: }
1.61 www 2878:
1.542 raeburn 2879: # -------------------------------------------------------------------- getemails
1.648 raeburn 2880:
1.542 raeburn 2881: =pod
2882:
1.648 raeburn 2883: =item * &getemails($uname,$udom)
1.542 raeburn 2884:
2885: Gets a user's email information and returns it as a hash with keys:
2886: notification, critnotification, permanentemail
2887:
2888: For notification and critnotification, values are comma-separated lists
1.648 raeburn 2889: of e-mail addresses; for permanentemail, value is a single e-mail address.
1.542 raeburn 2890:
1.648 raeburn 2891:
1.542 raeburn 2892: =cut
2893:
1.648 raeburn 2894:
1.466 albertel 2895: sub getemails {
2896: my ($uname,$udom)=@_;
2897: if ($udom eq 'public' && $uname eq 'public') {
2898: return;
2899: }
1.467 www 2900: if (!$udom) { $udom=$env{'user.domain'}; }
2901: if (!$uname) { $uname=$env{'user.name'}; }
1.466 albertel 2902: my $id=$uname.':'.$udom;
2903: my ($names,$cached)=&Apache::lonnet::is_cached_new('emailscache',$id);
2904: if ($cached) {
2905: return %{$names};
2906: } else {
2907: my %loadnames=&Apache::lonnet::get('environment',
2908: ['notification','critnotification',
2909: 'permanentemail'],
2910: $udom,$uname);
2911: &Apache::lonnet::do_cache_new('emailscache',$id,\%loadnames);
2912: return %loadnames;
2913: }
2914: }
2915:
1.551 albertel 2916: sub flush_email_cache {
2917: my ($uname,$udom)=@_;
2918: if (!$udom) { $udom =$env{'user.domain'}; }
2919: if (!$uname) { $uname=$env{'user.name'}; }
2920: return if ($udom eq 'public' && $uname eq 'public');
2921: my $id=$uname.':'.$udom;
2922: &Apache::lonnet::devalidate_cache_new('emailscache',$id);
2923: }
2924:
1.728 raeburn 2925: # -------------------------------------------------------------------- getlangs
2926:
2927: =pod
2928:
2929: =item * &getlangs($uname,$udom)
2930:
2931: Gets a user's language preference and returns it as a hash with key:
2932: language.
2933:
2934: =cut
2935:
2936:
2937: sub getlangs {
2938: my ($uname,$udom) = @_;
2939: if (!$udom) { $udom =$env{'user.domain'}; }
2940: if (!$uname) { $uname=$env{'user.name'}; }
2941: my $id=$uname.':'.$udom;
2942: my ($langs,$cached)=&Apache::lonnet::is_cached_new('userlangs',$id);
2943: if ($cached) {
2944: return %{$langs};
2945: } else {
2946: my %loadlangs=&Apache::lonnet::get('environment',['languages'],
2947: $udom,$uname);
2948: &Apache::lonnet::do_cache_new('userlangs',$id,\%loadlangs);
2949: return %loadlangs;
2950: }
2951: }
2952:
2953: sub flush_langs_cache {
2954: my ($uname,$udom)=@_;
2955: if (!$udom) { $udom =$env{'user.domain'}; }
2956: if (!$uname) { $uname=$env{'user.name'}; }
2957: return if ($udom eq 'public' && $uname eq 'public');
2958: my $id=$uname.':'.$udom;
2959: &Apache::lonnet::devalidate_cache_new('userlangs',$id);
2960: }
2961:
1.61 www 2962: # ------------------------------------------------------------------ Screenname
1.81 albertel 2963:
2964: =pod
2965:
1.648 raeburn 2966: =item * &screenname($uname,$udom)
1.81 albertel 2967:
2968: Gets a users screenname and returns it as a string
2969:
2970: =cut
1.61 www 2971:
2972: sub screenname {
2973: my ($uname,$udom)=@_;
1.258 albertel 2974: if ($uname eq $env{'user.name'} &&
2975: $udom eq $env{'user.domain'}) {return $env{'environment.screenname'};}
1.212 albertel 2976: my %names=&Apache::lonnet::get('environment',['screenname'],$udom,$uname);
1.68 albertel 2977: return $names{'screenname'};
1.62 www 2978: }
2979:
1.212 albertel 2980:
1.802 bisitz 2981: # ------------------------------------------------------------- Confirm Wrapper
2982: =pod
2983:
2984: =item confirmwrapper
2985:
2986: Wrap messages about completion of operation in box
2987:
2988: =cut
2989:
2990: sub confirmwrapper {
2991: my ($message)=@_;
2992: if ($message) {
2993: return "\n".'<div class="LC_confirm_box">'."\n"
2994: .$message."\n"
2995: .'</div>'."\n";
2996: } else {
2997: return $message;
2998: }
2999: }
3000:
1.62 www 3001: # ------------------------------------------------------------- Message Wrapper
3002:
3003: sub messagewrapper {
1.369 www 3004: my ($link,$username,$domain,$subject,$text)=@_;
1.62 www 3005: return
1.441 albertel 3006: '<a href="/adm/email?compose=individual&'.
3007: 'recname='.$username.'&recdom='.$domain.
3008: '&subject='.&escape($subject).'&text='.&escape($text).'" '.
1.200 matthew 3009: 'title="'.&mt('Send message').'">'.$link.'</a>';
1.74 www 3010: }
1.802 bisitz 3011:
1.74 www 3012: # --------------------------------------------------------------- Notes Wrapper
3013:
3014: sub noteswrapper {
3015: my ($link,$un,$do)=@_;
3016: return
1.896 amueller 3017: "<a href='/adm/email?recordftf=retrieve&recname=$un&recdom=$do'>$link</a>";
1.62 www 3018: }
1.802 bisitz 3019:
1.62 www 3020: # ------------------------------------------------------------- Aboutme Wrapper
3021:
3022: sub aboutmewrapper {
1.166 www 3023: my ($link,$username,$domain,$target)=@_;
1.447 raeburn 3024: if (!defined($username) && !defined($domain)) {
3025: return;
3026: }
1.892 amueller 3027: return '<a href="/adm/'.$domain.'/'.$username.'/aboutme?forcestudent=1"'.
1.756 weissno 3028: ($target?' target="$target"':'').' title="'.&mt("View this user's personal information page").'">'.$link.'</a>';
1.62 www 3029: }
3030:
3031: # ------------------------------------------------------------ Syllabus Wrapper
3032:
3033: sub syllabuswrapper {
1.707 bisitz 3034: my ($linktext,$coursedir,$domain)=@_;
1.208 matthew 3035: return qq{<a href="/public/$domain/$coursedir/syllabus">$linktext</a>};
1.61 www 3036: }
1.14 harris41 3037:
1.802 bisitz 3038: # -----------------------------------------------------------------------------
3039:
1.208 matthew 3040: sub track_student_link {
1.887 raeburn 3041: my ($linktext,$sname,$sdom,$target,$start,$only_body) = @_;
1.268 albertel 3042: my $link ="/adm/trackstudent?";
1.208 matthew 3043: my $title = 'View recent activity';
3044: if (defined($sname) && $sname !~ /^\s*$/ &&
3045: defined($sdom) && $sdom !~ /^\s*$/) {
1.268 albertel 3046: $link .= "selected_student=$sname:$sdom";
1.208 matthew 3047: $title .= ' of this student';
1.268 albertel 3048: }
1.208 matthew 3049: if (defined($target) && $target !~ /^\s*$/) {
3050: $target = qq{target="$target"};
3051: } else {
3052: $target = '';
3053: }
1.268 albertel 3054: if ($start) { $link.='&start='.$start; }
1.887 raeburn 3055: if ($only_body) { $link .= '&only_body=1'; }
1.554 albertel 3056: $title = &mt($title);
3057: $linktext = &mt($linktext);
1.448 albertel 3058: return qq{<a href="$link" title="$title" $target>$linktext</a>}.
3059: &help_open_topic('View_recent_activity');
1.208 matthew 3060: }
3061:
1.781 raeburn 3062: sub slot_reservations_link {
3063: my ($linktext,$sname,$sdom,$target) = @_;
3064: my $link ="/adm/slotrequest?command=showresv&origin=aboutme";
3065: my $title = 'View slot reservation history';
3066: if (defined($sname) && $sname !~ /^\s*$/ &&
3067: defined($sdom) && $sdom !~ /^\s*$/) {
3068: $link .= "&uname=$sname&udom=$sdom";
3069: $title .= ' of this student';
3070: }
3071: if (defined($target) && $target !~ /^\s*$/) {
3072: $target = qq{target="$target"};
3073: } else {
3074: $target = '';
3075: }
3076: $title = &mt($title);
3077: $linktext = &mt($linktext);
3078: return qq{<a href="$link" title="$title" $target>$linktext</a>};
3079: # FIXME uncomment when help item created: &help_open_topic('Slot_Reservation_History');
3080:
3081: }
3082:
1.508 www 3083: # ===================================================== Display a student photo
3084:
3085:
1.509 albertel 3086: sub student_image_tag {
1.508 www 3087: my ($domain,$user)=@_;
3088: my $imgsrc=&Apache::lonnet::studentphoto($domain,$user,'jpg');
3089: if (($imgsrc) && ($imgsrc ne '/adm/lonKaputt/lonlogo_broken.gif')) {
3090: return '<img src="'.$imgsrc.'" align="right" />';
3091: } else {
3092: return '';
3093: }
3094: }
3095:
1.112 bowersj2 3096: =pod
3097:
3098: =back
3099:
3100: =head1 Access .tab File Data
3101:
3102: =over 4
3103:
1.648 raeburn 3104: =item * &languageids()
1.112 bowersj2 3105:
3106: returns list of all language ids
3107:
3108: =cut
3109:
1.14 harris41 3110: sub languageids {
1.16 harris41 3111: return sort(keys(%language));
1.14 harris41 3112: }
3113:
1.112 bowersj2 3114: =pod
3115:
1.648 raeburn 3116: =item * &languagedescription()
1.112 bowersj2 3117:
3118: returns description of a specified language id
3119:
3120: =cut
3121:
1.14 harris41 3122: sub languagedescription {
1.125 www 3123: my $code=shift;
3124: return ($supported_language{$code}?'* ':'').
3125: $language{$code}.
1.126 www 3126: ($supported_language{$code}?' ('.&mt('interface available').')':'');
1.145 www 3127: }
3128:
3129: sub plainlanguagedescription {
3130: my $code=shift;
3131: return $language{$code};
3132: }
3133:
3134: sub supportedlanguagecode {
3135: my $code=shift;
3136: return $supported_language{$code};
1.97 www 3137: }
3138:
1.112 bowersj2 3139: =pod
3140:
1.648 raeburn 3141: =item * ©rightids()
1.112 bowersj2 3142:
3143: returns list of all copyrights
3144:
3145: =cut
3146:
3147: sub copyrightids {
3148: return sort(keys(%cprtag));
3149: }
3150:
3151: =pod
3152:
1.648 raeburn 3153: =item * ©rightdescription()
1.112 bowersj2 3154:
3155: returns description of a specified copyright id
3156:
3157: =cut
3158:
3159: sub copyrightdescription {
1.166 www 3160: return &mt($cprtag{shift(@_)});
1.112 bowersj2 3161: }
1.197 matthew 3162:
3163: =pod
3164:
1.648 raeburn 3165: =item * &source_copyrightids()
1.192 taceyjo1 3166:
3167: returns list of all source copyrights
3168:
3169: =cut
3170:
3171: sub source_copyrightids {
3172: return sort(keys(%scprtag));
3173: }
3174:
3175: =pod
3176:
1.648 raeburn 3177: =item * &source_copyrightdescription()
1.192 taceyjo1 3178:
3179: returns description of a specified source copyright id
3180:
3181: =cut
3182:
3183: sub source_copyrightdescription {
3184: return &mt($scprtag{shift(@_)});
3185: }
1.112 bowersj2 3186:
3187: =pod
3188:
1.648 raeburn 3189: =item * &filecategories()
1.112 bowersj2 3190:
3191: returns list of all file categories
3192:
3193: =cut
3194:
3195: sub filecategories {
3196: return sort(keys(%category_extensions));
3197: }
3198:
3199: =pod
3200:
1.648 raeburn 3201: =item * &filecategorytypes()
1.112 bowersj2 3202:
3203: returns list of file types belonging to a given file
3204: category
3205:
3206: =cut
3207:
3208: sub filecategorytypes {
1.356 albertel 3209: my ($cat) = @_;
3210: return @{$category_extensions{lc($cat)}};
1.112 bowersj2 3211: }
3212:
3213: =pod
3214:
1.648 raeburn 3215: =item * &fileembstyle()
1.112 bowersj2 3216:
3217: returns embedding style for a specified file type
3218:
3219: =cut
3220:
3221: sub fileembstyle {
3222: return $fe{lc(shift(@_))};
1.169 www 3223: }
3224:
1.351 www 3225: sub filemimetype {
3226: return $fm{lc(shift(@_))};
3227: }
3228:
1.169 www 3229:
3230: sub filecategoryselect {
3231: my ($name,$value)=@_;
1.189 matthew 3232: return &select_form($value,$name,
1.169 www 3233: '' => &mt('Any category'),
3234: map { $_,$_ } sort(keys(%category_extensions)));
1.112 bowersj2 3235: }
3236:
3237: =pod
3238:
1.648 raeburn 3239: =item * &filedescription()
1.112 bowersj2 3240:
3241: returns description for a specified file type
3242:
3243: =cut
3244:
3245: sub filedescription {
1.188 matthew 3246: my $file_description = $fd{lc(shift())};
3247: $file_description =~ s:([\[\]]):~$1:g;
3248: return &mt($file_description);
1.112 bowersj2 3249: }
3250:
3251: =pod
3252:
1.648 raeburn 3253: =item * &filedescriptionex()
1.112 bowersj2 3254:
3255: returns description for a specified file type with
3256: extra formatting
3257:
3258: =cut
3259:
3260: sub filedescriptionex {
3261: my $ex=shift;
1.188 matthew 3262: my $file_description = $fd{lc($ex)};
3263: $file_description =~ s:([\[\]]):~$1:g;
3264: return '.'.$ex.' '.&mt($file_description);
1.112 bowersj2 3265: }
3266:
3267: # End of .tab access
3268: =pod
3269:
3270: =back
3271:
3272: =cut
3273:
3274: # ------------------------------------------------------------------ File Types
3275: sub fileextensions {
3276: return sort(keys(%fe));
3277: }
3278:
1.97 www 3279: # ----------------------------------------------------------- Display Languages
3280: # returns a hash with all desired display languages
3281: #
3282:
3283: sub display_languages {
3284: my %languages=();
1.695 raeburn 3285: foreach my $lang (&Apache::lonlocal::preferred_languages()) {
1.356 albertel 3286: $languages{$lang}=1;
1.97 www 3287: }
3288: &get_unprocessed_cgi($ENV{'QUERY_STRING'},['displaylanguage']);
1.258 albertel 3289: if ($env{'form.displaylanguage'}) {
1.356 albertel 3290: foreach my $lang (split(/\s*(\,|\;|\:)\s*/,$env{'form.displaylanguage'})) {
3291: $languages{$lang}=1;
1.97 www 3292: }
3293: }
3294: return %languages;
1.14 harris41 3295: }
3296:
1.582 albertel 3297: sub languages {
3298: my ($possible_langs) = @_;
1.695 raeburn 3299: my @preferred_langs = &Apache::lonlocal::preferred_languages();
1.582 albertel 3300: if (!ref($possible_langs)) {
3301: if( wantarray ) {
3302: return @preferred_langs;
3303: } else {
3304: return $preferred_langs[0];
3305: }
3306: }
3307: my %possibilities = map { $_ => 1 } (@$possible_langs);
3308: my @preferred_possibilities;
3309: foreach my $preferred_lang (@preferred_langs) {
3310: if (exists($possibilities{$preferred_lang})) {
3311: push(@preferred_possibilities, $preferred_lang);
3312: }
3313: }
3314: if( wantarray ) {
3315: return @preferred_possibilities;
3316: }
3317: return $preferred_possibilities[0];
3318: }
3319:
1.742 raeburn 3320: sub user_lang {
3321: my ($touname,$toudom,$fromcid) = @_;
3322: my @userlangs;
3323: if (($fromcid ne '') && ($env{'course.'.$fromcid.'.languages'} ne '')) {
3324: @userlangs=(@userlangs,split(/\s*(\,|\;|\:)\s*/,
3325: $env{'course.'.$fromcid.'.languages'}));
3326: } else {
3327: my %langhash = &getlangs($touname,$toudom);
3328: if ($langhash{'languages'} ne '') {
3329: @userlangs = split(/\s*(\,|\;|\:)\s*/,$langhash{'languages'});
3330: } else {
3331: my %domdefs = &Apache::lonnet::get_domain_defaults($toudom);
3332: if ($domdefs{'lang_def'} ne '') {
3333: @userlangs = ($domdefs{'lang_def'});
3334: }
3335: }
3336: }
3337: my @languages=&Apache::lonlocal::get_genlanguages(@userlangs);
3338: my $user_lh = Apache::localize->get_handle(@languages);
3339: return $user_lh;
3340: }
3341:
3342:
1.112 bowersj2 3343: ###############################################################
3344: ## Student Answer Attempts ##
3345: ###############################################################
3346:
3347: =pod
3348:
3349: =head1 Alternate Problem Views
3350:
3351: =over 4
3352:
1.648 raeburn 3353: =item * &get_previous_attempt($symb, $username, $domain, $course,
1.112 bowersj2 3354: $getattempt, $regexp, $gradesub)
3355:
3356: Return string with previous attempt on problem. Arguments:
3357:
3358: =over 4
3359:
3360: =item * $symb: Problem, including path
3361:
3362: =item * $username: username of the desired student
3363:
3364: =item * $domain: domain of the desired student
1.14 harris41 3365:
1.112 bowersj2 3366: =item * $course: Course ID
1.14 harris41 3367:
1.112 bowersj2 3368: =item * $getattempt: Leave blank for all attempts, otherwise put
3369: something
1.14 harris41 3370:
1.112 bowersj2 3371: =item * $regexp: if string matches this regexp, the string will be
3372: sent to $gradesub
1.14 harris41 3373:
1.112 bowersj2 3374: =item * $gradesub: routine that processes the string if it matches $regexp
1.14 harris41 3375:
1.112 bowersj2 3376: =back
1.14 harris41 3377:
1.112 bowersj2 3378: The output string is a table containing all desired attempts, if any.
1.16 harris41 3379:
1.112 bowersj2 3380: =cut
1.1 albertel 3381:
3382: sub get_previous_attempt {
1.43 ng 3383: my ($symb,$username,$domain,$course,$getattempt,$regexp,$gradesub)=@_;
1.1 albertel 3384: my $prevattempts='';
1.43 ng 3385: no strict 'refs';
1.1 albertel 3386: if ($symb) {
1.3 albertel 3387: my (%returnhash)=
3388: &Apache::lonnet::restore($symb,$course,$domain,$username);
1.1 albertel 3389: if ($returnhash{'version'}) {
3390: my %lasthash=();
3391: my $version;
3392: for ($version=1;$version<=$returnhash{'version'};$version++) {
1.356 albertel 3393: foreach my $key (sort(split(/\:/,$returnhash{$version.':keys'}))) {
3394: $lasthash{$key}=$returnhash{$version.':'.$key};
1.19 harris41 3395: }
1.1 albertel 3396: }
1.596 albertel 3397: $prevattempts=&start_data_table().&start_data_table_header_row();
3398: $prevattempts.='<th>'.&mt('History').'</th>';
1.356 albertel 3399: foreach my $key (sort(keys(%lasthash))) {
3400: my ($ign,@parts) = split(/\./,$key);
1.41 ng 3401: if ($#parts > 0) {
1.31 albertel 3402: my $data=$parts[-1];
3403: pop(@parts);
1.596 albertel 3404: $prevattempts.='<th>'.&mt('Part ').join('.',@parts).'<br />'.$data.' </th>';
1.31 albertel 3405: } else {
1.41 ng 3406: if ($#parts == 0) {
3407: $prevattempts.='<th>'.$parts[0].'</th>';
3408: } else {
3409: $prevattempts.='<th>'.$ign.'</th>';
3410: }
1.31 albertel 3411: }
1.16 harris41 3412: }
1.596 albertel 3413: $prevattempts.=&end_data_table_header_row();
1.40 ng 3414: if ($getattempt eq '') {
3415: for ($version=1;$version<=$returnhash{'version'};$version++) {
1.596 albertel 3416: $prevattempts.=&start_data_table_row().
3417: '<td>'.&mt('Transaction [_1]',$version).'</td>';
1.356 albertel 3418: foreach my $key (sort(keys(%lasthash))) {
1.581 albertel 3419: my $value = &format_previous_attempt_value($key,
3420: $returnhash{$version.':'.$key});
3421: $prevattempts.='<td>'.$value.' </td>';
1.40 ng 3422: }
1.596 albertel 3423: $prevattempts.=&end_data_table_row();
1.40 ng 3424: }
1.1 albertel 3425: }
1.596 albertel 3426: $prevattempts.=&start_data_table_row().'<td>'.&mt('Current').'</td>';
1.356 albertel 3427: foreach my $key (sort(keys(%lasthash))) {
1.581 albertel 3428: my $value = &format_previous_attempt_value($key,$lasthash{$key});
1.356 albertel 3429: if ($key =~/$regexp$/ && (defined &$gradesub)) {$value = &$gradesub($value)}
1.40 ng 3430: $prevattempts.='<td>'.$value.' </td>';
1.16 harris41 3431: }
1.596 albertel 3432: $prevattempts.= &end_data_table_row().&end_data_table();
1.1 albertel 3433: } else {
1.596 albertel 3434: $prevattempts=
3435: &start_data_table().&start_data_table_row().
3436: '<td>'.&mt('Nothing submitted - no attempts.').'</td>'.
3437: &end_data_table_row().&end_data_table();
1.1 albertel 3438: }
3439: } else {
1.596 albertel 3440: $prevattempts=
3441: &start_data_table().&start_data_table_row().
3442: '<td>'.&mt('No data.').'</td>'.
3443: &end_data_table_row().&end_data_table();
1.1 albertel 3444: }
1.10 albertel 3445: }
3446:
1.581 albertel 3447: sub format_previous_attempt_value {
3448: my ($key,$value) = @_;
3449: if ($key =~ /timestamp/) {
3450: $value = &Apache::lonlocal::locallocaltime($value);
3451: } elsif (ref($value) eq 'ARRAY') {
3452: $value = '('.join(', ', @{ $value }).')';
3453: } else {
3454: $value = &unescape($value);
3455: }
3456: return $value;
3457: }
3458:
3459:
1.107 albertel 3460: sub relative_to_absolute {
3461: my ($url,$output)=@_;
3462: my $parser=HTML::TokeParser->new(\$output);
3463: my $token;
3464: my $thisdir=$url;
3465: my @rlinks=();
3466: while ($token=$parser->get_token) {
3467: if ($token->[0] eq 'S') {
3468: if ($token->[1] eq 'a') {
3469: if ($token->[2]->{'href'}) {
3470: $rlinks[$#rlinks+1]=$token->[2]->{'href'};
3471: }
3472: } elsif ($token->[1] eq 'img' || $token->[1] eq 'embed' ) {
3473: $rlinks[$#rlinks+1]=$token->[2]->{'src'};
3474: } elsif ($token->[1] eq 'base') {
3475: $thisdir=$token->[2]->{'href'};
3476: }
3477: }
3478: }
3479: $thisdir=~s-/[^/]*$--;
1.356 albertel 3480: foreach my $link (@rlinks) {
1.726 raeburn 3481: unless (($link=~/^https?\:\/\//i) ||
1.356 albertel 3482: ($link=~/^\//) ||
3483: ($link=~/^javascript:/i) ||
3484: ($link=~/^mailto:/i) ||
3485: ($link=~/^\#/)) {
3486: my $newlocation=&Apache::lonnet::hreflocation($thisdir,$link);
3487: $output=~s/(\"|\'|\=\s*)\Q$link\E(\"|\'|\s|\>)/$1$newlocation$2/;
1.107 albertel 3488: }
3489: }
3490: # -------------------------------------------------- Deal with Applet codebases
3491: $output=~s/(\<applet[^\>]+)(codebase\=[^\S\>]+)*([^\>]*)\>/$1.($2?$2:' codebase="'.$thisdir.'"').$3.'>'/gei;
3492: return $output;
3493: }
3494:
1.112 bowersj2 3495: =pod
3496:
1.648 raeburn 3497: =item * &get_student_view()
1.112 bowersj2 3498:
3499: show a snapshot of what student was looking at
3500:
3501: =cut
3502:
1.10 albertel 3503: sub get_student_view {
1.186 albertel 3504: my ($symb,$username,$domain,$courseid,$target,$moreenv) = @_;
1.114 www 3505: my ($map,$id,$feedurl) = &Apache::lonnet::decode_symb($symb);
1.186 albertel 3506: my (%form);
1.10 albertel 3507: my @elements=('symb','courseid','domain','username');
3508: foreach my $element (@elements) {
1.186 albertel 3509: $form{'grade_'.$element}=eval '$'.$element #'
1.10 albertel 3510: }
1.186 albertel 3511: if (defined($moreenv)) {
3512: %form=(%form,%{$moreenv});
3513: }
1.236 albertel 3514: if (defined($target)) { $form{'grade_target'} = $target; }
1.107 albertel 3515: $feedurl=&Apache::lonnet::clutter($feedurl);
1.650 www 3516: my ($userview,$response)=&Apache::lonnet::ssi_body($feedurl,%form);
1.11 albertel 3517: $userview=~s/\<body[^\>]*\>//gi;
3518: $userview=~s/\<\/body\>//gi;
3519: $userview=~s/\<html\>//gi;
3520: $userview=~s/\<\/html\>//gi;
3521: $userview=~s/\<head\>//gi;
3522: $userview=~s/\<\/head\>//gi;
3523: $userview=~s/action\s*\=/would_be_action\=/gi;
1.107 albertel 3524: $userview=&relative_to_absolute($feedurl,$userview);
1.650 www 3525: if (wantarray) {
3526: return ($userview,$response);
3527: } else {
3528: return $userview;
3529: }
3530: }
3531:
3532: sub get_student_view_with_retries {
3533: my ($symb,$retries,$username,$domain,$courseid,$target,$moreenv) = @_;
3534:
3535: my $ok = 0; # True if we got a good response.
3536: my $content;
3537: my $response;
3538:
3539: # Try to get the student_view done. within the retries count:
3540:
3541: do {
3542: ($content, $response) = &get_student_view($symb,$username,$domain,$courseid,$target,$moreenv);
3543: $ok = $response->is_success;
3544: if (!$ok) {
3545: &Apache::lonnet::logthis("Failed get_student_view_with_retries on $symb: ".$response->is_success.', '.$response->code.', '.$response->message);
3546: }
3547: $retries--;
3548: } while (!$ok && ($retries > 0));
3549:
3550: if (!$ok) {
3551: $content = ''; # On error return an empty content.
3552: }
1.651 www 3553: if (wantarray) {
3554: return ($content, $response);
3555: } else {
3556: return $content;
3557: }
1.11 albertel 3558: }
3559:
1.112 bowersj2 3560: =pod
3561:
1.648 raeburn 3562: =item * &get_student_answers()
1.112 bowersj2 3563:
3564: show a snapshot of how student was answering problem
3565:
3566: =cut
3567:
1.11 albertel 3568: sub get_student_answers {
1.100 sakharuk 3569: my ($symb,$username,$domain,$courseid,%form) = @_;
1.114 www 3570: my ($map,$id,$feedurl) = &Apache::lonnet::decode_symb($symb);
1.186 albertel 3571: my (%moreenv);
1.11 albertel 3572: my @elements=('symb','courseid','domain','username');
3573: foreach my $element (@elements) {
1.186 albertel 3574: $moreenv{'grade_'.$element}=eval '$'.$element #'
1.10 albertel 3575: }
1.186 albertel 3576: $moreenv{'grade_target'}='answer';
3577: %moreenv=(%form,%moreenv);
1.497 raeburn 3578: $feedurl = &Apache::lonnet::clutter($feedurl);
3579: my $userview=&Apache::lonnet::ssi($feedurl,%moreenv);
1.10 albertel 3580: return $userview;
1.1 albertel 3581: }
1.116 albertel 3582:
3583: =pod
3584:
3585: =item * &submlink()
3586:
1.242 albertel 3587: Inputs: $text $uname $udom $symb $target
1.116 albertel 3588:
3589: Returns: A link to grades.pm such as to see the SUBM view of a student
3590:
3591: =cut
3592:
3593: ###############################################
3594: sub submlink {
1.242 albertel 3595: my ($text,$uname,$udom,$symb,$target)=@_;
1.116 albertel 3596: if (!($uname && $udom)) {
3597: (my $cursymb, my $courseid,$udom,$uname)=
1.463 albertel 3598: &Apache::lonnet::whichuser($symb);
1.116 albertel 3599: if (!$symb) { $symb=$cursymb; }
3600: }
1.254 matthew 3601: if (!$symb) { $symb=&Apache::lonnet::symbread(); }
1.369 www 3602: $symb=&escape($symb);
1.242 albertel 3603: if ($target) { $target="target=\"$target\""; }
3604: return '<a href="/adm/grades?&command=submission&'.
3605: 'symb='.$symb.'&student='.$uname.
3606: '&userdom='.$udom.'" '.$target.'>'.$text.'</a>';
3607: }
3608: ##############################################
3609:
3610: =pod
3611:
3612: =item * &pgrdlink()
3613:
3614: Inputs: $text $uname $udom $symb $target
3615:
3616: Returns: A link to grades.pm such as to see the PGRD view of a student
3617:
3618: =cut
3619:
3620: ###############################################
3621: sub pgrdlink {
3622: my $link=&submlink(@_);
3623: $link=~s/(&command=submission)/$1&showgrading=yes/;
3624: return $link;
3625: }
3626: ##############################################
3627:
3628: =pod
3629:
3630: =item * &pprmlink()
3631:
3632: Inputs: $text $uname $udom $symb $target
3633:
3634: Returns: A link to parmset.pm such as to see the PPRM view of a
1.283 albertel 3635: student and a specific resource
1.242 albertel 3636:
3637: =cut
3638:
3639: ###############################################
3640: sub pprmlink {
3641: my ($text,$uname,$udom,$symb,$target)=@_;
3642: if (!($uname && $udom)) {
3643: (my $cursymb, my $courseid,$udom,$uname)=
1.463 albertel 3644: &Apache::lonnet::whichuser($symb);
1.242 albertel 3645: if (!$symb) { $symb=$cursymb; }
3646: }
1.254 matthew 3647: if (!$symb) { $symb=&Apache::lonnet::symbread(); }
1.369 www 3648: $symb=&escape($symb);
1.242 albertel 3649: if ($target) { $target="target=\"$target\""; }
1.595 albertel 3650: return '<a href="/adm/parmset?command=set&'.
3651: 'symb='.$symb.'&uname='.$uname.
3652: '&udom='.$udom.'" '.$target.'>'.$text.'</a>';
1.116 albertel 3653: }
3654: ##############################################
1.37 matthew 3655:
1.112 bowersj2 3656: =pod
3657:
3658: =back
3659:
3660: =cut
3661:
1.37 matthew 3662: ###############################################
1.51 www 3663:
3664:
3665: sub timehash {
1.687 raeburn 3666: my ($thistime) = @_;
3667: my $timezone = &Apache::lonlocal::gettimezone();
3668: my $dt = DateTime->from_epoch(epoch => $thistime)
3669: ->set_time_zone($timezone);
3670: my $wday = $dt->day_of_week();
3671: if ($wday == 7) { $wday = 0; }
3672: return ( 'second' => $dt->second(),
3673: 'minute' => $dt->minute(),
3674: 'hour' => $dt->hour(),
3675: 'day' => $dt->day_of_month(),
3676: 'month' => $dt->month(),
3677: 'year' => $dt->year(),
3678: 'weekday' => $wday,
3679: 'dayyear' => $dt->day_of_year(),
3680: 'dlsav' => $dt->is_dst() );
1.51 www 3681: }
3682:
1.370 www 3683: sub utc_string {
3684: my ($date)=@_;
1.371 www 3685: return strftime("%Y%m%dT%H%M%SZ",gmtime($date));
1.370 www 3686: }
3687:
1.51 www 3688: sub maketime {
3689: my %th=@_;
1.687 raeburn 3690: my ($epoch_time,$timezone,$dt);
3691: $timezone = &Apache::lonlocal::gettimezone();
3692: eval {
3693: $dt = DateTime->new( year => $th{'year'},
3694: month => $th{'month'},
3695: day => $th{'day'},
3696: hour => $th{'hour'},
3697: minute => $th{'minute'},
3698: second => $th{'second'},
3699: time_zone => $timezone,
3700: );
3701: };
3702: if (!$@) {
3703: $epoch_time = $dt->epoch;
3704: if ($epoch_time) {
3705: return $epoch_time;
3706: }
3707: }
1.51 www 3708: return POSIX::mktime(
3709: ($th{'seconds'},$th{'minutes'},$th{'hours'},
1.210 www 3710: $th{'day'},$th{'month'}-1,$th{'year'}-1900,0,0,-1));
1.70 www 3711: }
3712:
3713: #########################################
1.51 www 3714:
3715: sub findallcourses {
1.482 raeburn 3716: my ($roles,$uname,$udom) = @_;
1.355 albertel 3717: my %roles;
3718: if (ref($roles)) { %roles = map { $_ => 1 } @{$roles}; }
1.348 albertel 3719: my %courses;
1.51 www 3720: my $now=time;
1.482 raeburn 3721: if (!defined($uname)) {
3722: $uname = $env{'user.name'};
3723: }
3724: if (!defined($udom)) {
3725: $udom = $env{'user.domain'};
3726: }
3727: if (($uname ne $env{'user.name'}) || ($udom ne $env{'user.domain'})) {
3728: my %roleshash = &Apache::lonnet::dump('roles',$udom,$uname);
3729: if (!%roles) {
3730: %roles = (
3731: cc => 1,
3732: in => 1,
3733: ep => 1,
3734: ta => 1,
3735: cr => 1,
3736: st => 1,
3737: );
3738: }
3739: foreach my $entry (keys(%roleshash)) {
3740: my ($trole,$tend,$tstart) = split(/_/,$roleshash{$entry});
3741: if ($trole =~ /^cr/) {
3742: next if (!exists($roles{$trole}) && !exists($roles{'cr'}));
3743: } else {
3744: next if (!exists($roles{$trole}));
3745: }
3746: if ($tend) {
3747: next if ($tend < $now);
3748: }
3749: if ($tstart) {
3750: next if ($tstart > $now);
3751: }
3752: my ($cdom,$cnum,$sec,$cnumpart,$secpart,$role,$realsec);
3753: (undef,$cdom,$cnumpart,$secpart) = split(/\//,$entry);
3754: if ($secpart eq '') {
3755: ($cnum,$role) = split(/_/,$cnumpart);
3756: $sec = 'none';
3757: $realsec = '';
3758: } else {
3759: $cnum = $cnumpart;
3760: ($sec,$role) = split(/_/,$secpart);
3761: $realsec = $sec;
1.490 raeburn 3762: }
1.482 raeburn 3763: $courses{$cdom.'_'.$cnum}{$sec} = $trole.'/'.$cdom.'/'.$cnum.'/'.$realsec;
3764: }
3765: } else {
3766: foreach my $key (keys(%env)) {
1.483 albertel 3767: if ( $key=~m{^user\.role\.(\w+)\./($match_domain)/($match_courseid)/?(\w*)$} ||
3768: $key=~m{^user\.role\.(cr/$match_domain/$match_username/\w+)\./($match_domain)/($match_courseid)/?(\w*)$}) {
1.482 raeburn 3769: my ($role,$cdom,$cnum,$sec) = ($1,$2,$3,$4);
3770: next if ($role eq 'ca' || $role eq 'aa');
3771: next if (%roles && !exists($roles{$role}));
3772: my ($starttime,$endtime)=split(/\./,$env{$key});
3773: my $active=1;
3774: if ($starttime) {
3775: if ($now<$starttime) { $active=0; }
3776: }
3777: if ($endtime) {
3778: if ($now>$endtime) { $active=0; }
3779: }
3780: if ($active) {
3781: if ($sec eq '') {
3782: $sec = 'none';
3783: }
3784: $courses{$cdom.'_'.$cnum}{$sec} =
3785: $role.'/'.$cdom.'/'.$cnum.'/'.$sec;
1.474 raeburn 3786: }
3787: }
1.51 www 3788: }
3789: }
1.474 raeburn 3790: return %courses;
1.51 www 3791: }
1.37 matthew 3792:
1.54 www 3793: ###############################################
1.474 raeburn 3794:
3795: sub blockcheck {
1.482 raeburn 3796: my ($setters,$activity,$uname,$udom) = @_;
1.490 raeburn 3797:
3798: if (!defined($udom)) {
3799: $udom = $env{'user.domain'};
3800: }
3801: if (!defined($uname)) {
3802: $uname = $env{'user.name'};
3803: }
3804:
3805: # If uname and udom are for a course, check for blocks in the course.
3806:
3807: if (&Apache::lonnet::is_course($udom,$uname)) {
3808: my %records = &Apache::lonnet::dump('comm_block',$udom,$uname);
1.502 raeburn 3809: my ($startblock,$endblock)=&get_blocks($setters,$activity,$udom,$uname);
1.490 raeburn 3810: return ($startblock,$endblock);
3811: }
1.474 raeburn 3812:
1.502 raeburn 3813: my $startblock = 0;
3814: my $endblock = 0;
1.482 raeburn 3815: my %live_courses = &findallcourses(undef,$uname,$udom);
1.474 raeburn 3816:
1.490 raeburn 3817: # If uname is for a user, and activity is course-specific, i.e.,
3818: # boards, chat or groups, check for blocking in current course only.
1.474 raeburn 3819:
1.490 raeburn 3820: if (($activity eq 'boards' || $activity eq 'chat' ||
3821: $activity eq 'groups') && ($env{'request.course.id'})) {
3822: foreach my $key (keys(%live_courses)) {
3823: if ($key ne $env{'request.course.id'}) {
3824: delete($live_courses{$key});
3825: }
3826: }
3827: }
3828:
3829: my $otheruser = 0;
3830: my %own_courses;
3831: if ((($uname ne $env{'user.name'})) || ($udom ne $env{'user.domain'})) {
3832: # Resource belongs to user other than current user.
3833: $otheruser = 1;
3834: # Gather courses for current user
3835: %own_courses =
3836: &findallcourses(undef,$env{'user.name'},$env{'user.domain'});
3837: }
3838:
3839: # Gather active course roles - course coordinator, instructor,
3840: # exam proctor, ta, student, or custom role.
1.474 raeburn 3841:
3842: foreach my $course (keys(%live_courses)) {
1.482 raeburn 3843: my ($cdom,$cnum);
3844: if ((defined($env{'course.'.$course.'.domain'})) && (defined($env{'course.'.$course.'.num'}))) {
3845: $cdom = $env{'course.'.$course.'.domain'};
3846: $cnum = $env{'course.'.$course.'.num'};
3847: } else {
1.490 raeburn 3848: ($cdom,$cnum) = split(/_/,$course);
1.482 raeburn 3849: }
3850: my $no_ownblock = 0;
3851: my $no_userblock = 0;
1.533 raeburn 3852: if ($otheruser && $activity ne 'com') {
1.490 raeburn 3853: # Check if current user has 'evb' priv for this
3854: if (defined($own_courses{$course})) {
3855: foreach my $sec (keys(%{$own_courses{$course}})) {
3856: my $checkrole = 'cm./'.$cdom.'/'.$cnum;
3857: if ($sec ne 'none') {
3858: $checkrole .= '/'.$sec;
3859: }
3860: if (&Apache::lonnet::allowed('evb',undef,undef,$checkrole)) {
3861: $no_ownblock = 1;
3862: last;
3863: }
3864: }
3865: }
3866: # if they have 'evb' priv and are currently not playing student
3867: next if (($no_ownblock) &&
3868: ($env{'request.role'} !~ m{^st\./$cdom/$cnum}));
3869: }
1.474 raeburn 3870: foreach my $sec (keys(%{$live_courses{$course}})) {
1.482 raeburn 3871: my $checkrole = 'cm./'.$cdom.'/'.$cnum;
1.474 raeburn 3872: if ($sec ne 'none') {
1.482 raeburn 3873: $checkrole .= '/'.$sec;
1.474 raeburn 3874: }
1.490 raeburn 3875: if ($otheruser) {
3876: # Resource belongs to user other than current user.
3877: # Assemble privs for that user, and check for 'evb' priv.
1.482 raeburn 3878: my ($trole,$tdom,$tnum,$tsec);
3879: my $entry = $live_courses{$course}{$sec};
3880: if ($entry =~ /^cr/) {
3881: ($trole,$tdom,$tnum,$tsec) =
3882: ($entry =~ m|^(cr/$match_domain/$match_username/\w+)\./($match_domain)/($match_username)/?(\w*)$|);
3883: } else {
3884: ($trole,$tdom,$tnum,$tsec) = split(/\//,$entry);
3885: }
3886: my ($spec,$area,$trest,%allroles,%userroles);
3887: $area = '/'.$tdom.'/'.$tnum;
3888: $trest = $tnum;
3889: if ($tsec ne '') {
3890: $area .= '/'.$tsec;
3891: $trest .= '/'.$tsec;
3892: }
3893: $spec = $trole.'.'.$area;
3894: if ($trole =~ /^cr/) {
3895: &Apache::lonnet::custom_roleprivs(\%allroles,$trole,
3896: $tdom,$spec,$trest,$area);
3897: } else {
3898: &Apache::lonnet::standard_roleprivs(\%allroles,$trole,
3899: $tdom,$spec,$trest,$area);
3900: }
3901: my ($author,$adv) = &Apache::lonnet::set_userprivs(\%userroles,\%allroles);
1.486 raeburn 3902: if ($userroles{'user.priv.'.$checkrole} =~ /evb\&([^\:]*)/) {
3903: if ($1) {
3904: $no_userblock = 1;
3905: last;
3906: }
3907: }
1.490 raeburn 3908: } else {
3909: # Resource belongs to current user
3910: # Check for 'evb' priv via lonnet::allowed().
1.482 raeburn 3911: if (&Apache::lonnet::allowed('evb',undef,undef,$checkrole)) {
3912: $no_ownblock = 1;
3913: last;
3914: }
1.474 raeburn 3915: }
3916: }
3917: # if they have the evb priv and are currently not playing student
1.482 raeburn 3918: next if (($no_ownblock) &&
1.491 albertel 3919: ($env{'request.role'} !~ m{^st\./\Q$cdom\E/\Q$cnum\E}));
1.482 raeburn 3920: next if ($no_userblock);
1.474 raeburn 3921:
1.866 kalberla 3922: # Retrieve blocking times and identity of locker for course
1.490 raeburn 3923: # of specified user, unless user has 'evb' privilege.
1.502 raeburn 3924:
3925: my ($start,$end)=&get_blocks($setters,$activity,$cdom,$cnum);
3926: if (($start != 0) &&
3927: (($startblock == 0) || ($startblock > $start))) {
3928: $startblock = $start;
3929: }
3930: if (($end != 0) &&
3931: (($endblock == 0) || ($endblock < $end))) {
3932: $endblock = $end;
3933: }
1.490 raeburn 3934: }
3935: return ($startblock,$endblock);
3936: }
3937:
3938: sub get_blocks {
3939: my ($setters,$activity,$cdom,$cnum) = @_;
3940: my $startblock = 0;
3941: my $endblock = 0;
3942: my $course = $cdom.'_'.$cnum;
3943: $setters->{$course} = {};
3944: $setters->{$course}{'staff'} = [];
3945: $setters->{$course}{'times'} = [];
3946: my %records = &Apache::lonnet::dump('comm_block',$cdom,$cnum);
3947: foreach my $record (keys(%records)) {
3948: my ($start,$end) = ($record =~ m/^(\d+)____(\d+)$/);
3949: if ($start <= time && $end >= time) {
3950: my ($staff_name,$staff_dom,$title,$blocks) =
3951: &parse_block_record($records{$record});
3952: if ($blocks->{$activity} eq 'on') {
3953: push(@{$$setters{$course}{'staff'}},[$staff_name,$staff_dom]);
3954: push(@{$$setters{$course}{'times'}}, [$start,$end]);
1.491 albertel 3955: if ( ($startblock == 0) || ($startblock > $start) ) {
3956: $startblock = $start;
1.490 raeburn 3957: }
1.491 albertel 3958: if ( ($endblock == 0) || ($endblock < $end) ) {
3959: $endblock = $end;
1.474 raeburn 3960: }
3961: }
3962: }
3963: }
3964: return ($startblock,$endblock);
3965: }
3966:
3967: sub parse_block_record {
3968: my ($record) = @_;
3969: my ($setuname,$setudom,$title,$blocks);
3970: if (ref($record) eq 'HASH') {
3971: ($setuname,$setudom) = split(/:/,$record->{'setter'});
3972: $title = &unescape($record->{'event'});
3973: $blocks = $record->{'blocks'};
3974: } else {
3975: my @data = split(/:/,$record,3);
3976: if (scalar(@data) eq 2) {
3977: $title = $data[1];
3978: ($setuname,$setudom) = split(/@/,$data[0]);
3979: } else {
3980: ($setuname,$setudom,$title) = @data;
3981: }
3982: $blocks = { 'com' => 'on' };
3983: }
3984: return ($setuname,$setudom,$title,$blocks);
3985: }
3986:
1.854 kalberla 3987: sub blocking_status {
3988: my ($activity,$uname,$udom) = @_;
1.867 kalberla 3989: my %setters;
1.890 droeschl 3990:
3991: # check for active blocking
1.867 kalberla 3992: my ($startblock,$endblock)=&blockcheck(\%setters,$activity,$uname,$udom);
1.854 kalberla 3993:
1.890 droeschl 3994: my $blocked = $startblock && $endblock ? 1 : 0;
3995:
3996: # caller just wants to know whether a block is active
3997: if (!wantarray) { return $blocked; }
3998:
3999: # build a link to a popup window containing the details
4000: my $querystring = "?activity=$activity";
4001: # $uname and $udom decide whose portfolio the user is trying to look at
4002: $querystring .= "&udom=$udom" if $udom;
4003: $querystring .= "&uname=$uname" if $uname;
4004:
4005: my $output .= <<'END_MYBLOCK';
1.854 kalberla 4006: function openWindow(url, wdwName, w, h, toolbar,scrollbar) {
4007: var options = "width=" + w + ",height=" + h + ",";
4008: options += "resizable=yes,scrollbars="+scrollbar+",status=no,";
4009: options += "menubar=no,toolbar="+toolbar+",location=no,directories=no";
4010: var newWin = window.open(url, wdwName, options);
4011: newWin.focus();
4012: }
1.890 droeschl 4013: END_MYBLOCK
1.854 kalberla 4014:
1.890 droeschl 4015: $output = Apache::lonhtmlcommon::scripttag($output);
4016:
1.854 kalberla 4017: my $popupUrl = "/adm/blockingstatus/$querystring";
1.890 droeschl 4018: my $text = mt('Communication Blocked');
4019:
1.867 kalberla 4020: $output .= <<"END_BLOCK";
4021: <div class='LC_comblock'>
1.869 kalberla 4022: <a onclick='openWindow("$popupUrl","Blocking Table",600,300,"no","no");return false;' href='/adm/blockingstatus/$querystring'
1.890 droeschl 4023: title='$text'>
4024: <img class='LC_noBorder LC_middle' title='$text' src='/res/adm/pages/comblock.png' alt='$text'/></a>
1.869 kalberla 4025: <a onclick='openWindow("$popupUrl","Blocking Table",600,300,"no","no");return false;' href='/adm/blockingstatus/$querystring'
1.890 droeschl 4026: title='$text'>$text</a>
1.867 kalberla 4027: </div>
4028:
4029: END_BLOCK
1.474 raeburn 4030:
1.854 kalberla 4031: return ($blocked, $output);
4032: }
1.490 raeburn 4033:
1.60 matthew 4034: ###############################################
4035:
1.682 raeburn 4036: sub check_ip_acc {
4037: my ($acc)=@_;
4038: &Apache::lonxml::debug("acc is $acc");
4039: if (!defined($acc) || $acc =~ /^\s*$/ || $acc =~/^\s*no\s*$/i) {
4040: return 1;
4041: }
4042: my $allowed=0;
4043: my $ip=$env{'request.host'} || $ENV{'REMOTE_ADDR'};
4044:
4045: my $name;
4046: foreach my $pattern (split(',',$acc)) {
4047: $pattern =~ s/^\s*//;
4048: $pattern =~ s/\s*$//;
4049: if ($pattern =~ /\*$/) {
4050: #35.8.*
4051: $pattern=~s/\*//;
4052: if ($ip =~ /^\Q$pattern\E/) { $allowed=1; }
4053: } elsif ($pattern =~ /(\d+\.\d+\.\d+)\.\[(\d+)-(\d+)\]$/) {
4054: #35.8.3.[34-56]
4055: my $low=$2;
4056: my $high=$3;
4057: $pattern=$1;
4058: if ($ip =~ /^\Q$pattern\E/) {
4059: my $last=(split(/\./,$ip))[3];
4060: if ($last <=$high && $last >=$low) { $allowed=1; }
4061: }
4062: } elsif ($pattern =~ /^\*/) {
4063: #*.msu.edu
4064: $pattern=~s/\*//;
4065: if (!defined($name)) {
4066: use Socket;
4067: my $netaddr=inet_aton($ip);
4068: ($name)=gethostbyaddr($netaddr,AF_INET);
4069: }
4070: if ($name =~ /\Q$pattern\E$/i) { $allowed=1; }
4071: } elsif ($pattern =~ /\d+\.\d+\.\d+\.\d+/) {
4072: #127.0.0.1
4073: if ($ip =~ /^\Q$pattern\E/) { $allowed=1; }
4074: } else {
4075: #some.name.com
4076: if (!defined($name)) {
4077: use Socket;
4078: my $netaddr=inet_aton($ip);
4079: ($name)=gethostbyaddr($netaddr,AF_INET);
4080: }
4081: if ($name =~ /\Q$pattern\E$/i) { $allowed=1; }
4082: }
4083: if ($allowed) { last; }
4084: }
4085: return $allowed;
4086: }
4087:
4088: ###############################################
4089:
1.60 matthew 4090: =pod
4091:
1.112 bowersj2 4092: =head1 Domain Template Functions
4093:
4094: =over 4
4095:
4096: =item * &determinedomain()
1.60 matthew 4097:
4098: Inputs: $domain (usually will be undef)
4099:
1.63 www 4100: Returns: Determines which domain should be used for designs
1.60 matthew 4101:
4102: =cut
1.54 www 4103:
1.60 matthew 4104: ###############################################
1.63 www 4105: sub determinedomain {
4106: my $domain=shift;
1.531 albertel 4107: if (! $domain) {
1.60 matthew 4108: # Determine domain if we have not been given one
1.893 raeburn 4109: $domain = &Apache::lonnet::default_login_domain();
1.258 albertel 4110: if ($env{'user.domain'}) { $domain=$env{'user.domain'}; }
4111: if ($env{'request.role.domain'}) {
4112: $domain=$env{'request.role.domain'};
1.60 matthew 4113: }
4114: }
1.63 www 4115: return $domain;
4116: }
4117: ###############################################
1.517 raeburn 4118:
1.518 albertel 4119: sub devalidate_domconfig_cache {
4120: my ($udom)=@_;
4121: &Apache::lonnet::devalidate_cache_new('domainconfig',$udom);
4122: }
4123:
4124: # ---------------------- Get domain configuration for a domain
4125: sub get_domainconf {
4126: my ($udom) = @_;
4127: my $cachetime=1800;
4128: my ($result,$cached)=&Apache::lonnet::is_cached_new('domainconfig',$udom);
4129: if (defined($cached)) { return %{$result}; }
4130:
4131: my %domconfig = &Apache::lonnet::get_dom('configuration',
4132: ['login','rolecolors'],$udom);
1.632 raeburn 4133: my (%designhash,%legacy);
1.518 albertel 4134: if (keys(%domconfig) > 0) {
4135: if (ref($domconfig{'login'}) eq 'HASH') {
1.632 raeburn 4136: if (keys(%{$domconfig{'login'}})) {
4137: foreach my $key (keys(%{$domconfig{'login'}})) {
1.699 raeburn 4138: if (ref($domconfig{'login'}{$key}) eq 'HASH') {
4139: foreach my $img (keys(%{$domconfig{'login'}{$key}})) {
4140: $designhash{$udom.'.login.'.$key.'_'.$img} =
4141: $domconfig{'login'}{$key}{$img};
4142: }
4143: } else {
4144: $designhash{$udom.'.login.'.$key}=$domconfig{'login'}{$key};
4145: }
1.632 raeburn 4146: }
4147: } else {
4148: $legacy{'login'} = 1;
1.518 albertel 4149: }
1.632 raeburn 4150: } else {
4151: $legacy{'login'} = 1;
1.518 albertel 4152: }
4153: if (ref($domconfig{'rolecolors'}) eq 'HASH') {
1.632 raeburn 4154: if (keys(%{$domconfig{'rolecolors'}})) {
4155: foreach my $role (keys(%{$domconfig{'rolecolors'}})) {
4156: if (ref($domconfig{'rolecolors'}{$role}) eq 'HASH') {
4157: foreach my $item (keys(%{$domconfig{'rolecolors'}{$role}})) {
4158: $designhash{$udom.'.'.$role.'.'.$item}=$domconfig{'rolecolors'}{$role}{$item};
4159: }
1.518 albertel 4160: }
4161: }
1.632 raeburn 4162: } else {
4163: $legacy{'rolecolors'} = 1;
1.518 albertel 4164: }
1.632 raeburn 4165: } else {
4166: $legacy{'rolecolors'} = 1;
1.518 albertel 4167: }
1.632 raeburn 4168: if (keys(%legacy) > 0) {
4169: my %legacyhash = &get_legacy_domconf($udom);
4170: foreach my $item (keys(%legacyhash)) {
4171: if ($item =~ /^\Q$udom\E\.login/) {
4172: if ($legacy{'login'}) {
4173: $designhash{$item} = $legacyhash{$item};
4174: }
4175: } else {
4176: if ($legacy{'rolecolors'}) {
4177: $designhash{$item} = $legacyhash{$item};
4178: }
1.518 albertel 4179: }
4180: }
4181: }
1.632 raeburn 4182: } else {
4183: %designhash = &get_legacy_domconf($udom);
1.518 albertel 4184: }
4185: &Apache::lonnet::do_cache_new('domainconfig',$udom,\%designhash,
4186: $cachetime);
4187: return %designhash;
4188: }
4189:
1.632 raeburn 4190: sub get_legacy_domconf {
4191: my ($udom) = @_;
4192: my %legacyhash;
4193: my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors';
4194: my $designfile = $designdir.'/'.$udom.'.tab';
4195: if (-e $designfile) {
4196: if ( open (my $fh,"<$designfile") ) {
4197: while (my $line = <$fh>) {
4198: next if ($line =~ /^\#/);
4199: chomp($line);
4200: my ($key,$val)=(split(/\=/,$line));
4201: if ($val) { $legacyhash{$udom.'.'.$key}=$val; }
4202: }
4203: close($fh);
4204: }
4205: }
4206: if (-e '/home/httpd/html/adm/lonDomLogos/'.$udom.'.gif') {
4207: $legacyhash{$udom.'.login.domlogo'} = "/adm/lonDomLogos/$udom.gif";
4208: }
4209: return %legacyhash;
4210: }
4211:
1.63 www 4212: =pod
4213:
1.112 bowersj2 4214: =item * &domainlogo()
1.63 www 4215:
4216: Inputs: $domain (usually will be undef)
4217:
4218: Returns: A link to a domain logo, if the domain logo exists.
4219: If the domain logo does not exist, a description of the domain.
4220:
4221: =cut
1.112 bowersj2 4222:
1.63 www 4223: ###############################################
4224: sub domainlogo {
1.517 raeburn 4225: my $domain = &determinedomain(shift);
1.518 albertel 4226: my %designhash = &get_domainconf($domain);
1.517 raeburn 4227: # See if there is a logo
4228: if ($designhash{$domain.'.login.domlogo'} ne '') {
1.519 raeburn 4229: my $imgsrc = $designhash{$domain.'.login.domlogo'};
1.538 albertel 4230: if ($imgsrc =~ m{^/(adm|res)/}) {
4231: if ($imgsrc =~ m{^/res/}) {
4232: my $local_name = &Apache::lonnet::filelocation('',$imgsrc);
4233: &Apache::lonnet::repcopy($local_name);
4234: }
4235: $imgsrc = &lonhttpdurl($imgsrc);
1.519 raeburn 4236: }
4237: return '<img src="'.$imgsrc.'" alt="'.$domain.'" />';
1.514 albertel 4238: } elsif (defined(&Apache::lonnet::domain($domain,'description'))) {
4239: return &Apache::lonnet::domain($domain,'description');
1.59 www 4240: } else {
1.60 matthew 4241: return '';
1.59 www 4242: }
4243: }
1.63 www 4244: ##############################################
4245:
4246: =pod
4247:
1.112 bowersj2 4248: =item * &designparm()
1.63 www 4249:
4250: Inputs: $which parameter; $domain (usually will be undef)
4251:
4252: Returns: value of designparamter $which
4253:
4254: =cut
1.112 bowersj2 4255:
1.397 albertel 4256:
1.400 albertel 4257: ##############################################
1.397 albertel 4258: sub designparm {
4259: my ($which,$domain)=@_;
4260: if (exists($env{'environment.color.'.$which})) {
1.817 bisitz 4261: return $env{'environment.color.'.$which};
1.96 www 4262: }
1.63 www 4263: $domain=&determinedomain($domain);
1.518 albertel 4264: my %domdesign = &get_domainconf($domain);
1.520 raeburn 4265: my $output;
1.517 raeburn 4266: if ($domdesign{$domain.'.'.$which} ne '') {
1.817 bisitz 4267: $output = $domdesign{$domain.'.'.$which};
1.63 www 4268: } else {
1.520 raeburn 4269: $output = $defaultdesign{$which};
4270: }
4271: if (($which =~ /^(student|coordinator|author|admin)\.img$/) ||
1.635 raeburn 4272: ($which =~ /login\.(img|logo|domlogo|login)/)) {
1.538 albertel 4273: if ($output =~ m{^/(adm|res)/}) {
1.817 bisitz 4274: if ($output =~ m{^/res/}) {
4275: my $local_name = &Apache::lonnet::filelocation('',$output);
4276: &Apache::lonnet::repcopy($local_name);
4277: }
1.520 raeburn 4278: $output = &lonhttpdurl($output);
4279: }
1.63 www 4280: }
1.520 raeburn 4281: return $output;
1.63 www 4282: }
1.59 www 4283:
1.822 bisitz 4284: ##############################################
4285: =pod
4286:
1.832 bisitz 4287: =item * &authorspace()
4288:
4289: Inputs: ./.
4290:
4291: Returns: Path to the Construction Space of the current user's
4292: accessed author space
4293: The author space will be that of the current user
4294: when accessing the own author space
4295: and that of the co-author/assistent co-author
4296: when accessing the co-author's/assistent co-author's
4297: space
4298:
4299: =cut
4300:
4301: sub authorspace {
4302: my $caname = '';
4303: if ($env{'request.role'} =~ /^ca|^aa/) {
4304: (undef,$caname) =
4305: ($env{'request.role'}=~/($match_domain)\/($match_username)$/);
4306: } else {
4307: $caname = $env{'user.name'};
4308: }
4309: return '/priv/'.$caname.'/';
4310: }
4311:
4312: ##############################################
4313: =pod
4314:
1.822 bisitz 4315: =item * &head_subbox()
4316:
4317: Inputs: $content (contains HTML code with page functions, etc.)
4318:
4319: Returns: HTML div with $content
4320: To be included in page header
4321:
4322: =cut
4323:
4324: sub head_subbox {
4325: my ($content)=@_;
4326: my $output =
1.844 bisitz 4327: '<div id="LC_head_subbox">'
1.822 bisitz 4328: .$content
4329: .'</div>'
4330: }
4331:
4332: ##############################################
4333: =pod
4334:
4335: =item * &CSTR_pageheader()
4336:
4337: Inputs: ./.
4338:
4339: Returns: HTML div with CSTR path and recent box
4340: To be included on Construction Space pages
4341:
4342: =cut
4343:
4344: sub CSTR_pageheader {
4345: # this is for resources; directories have customtitle, and crumbs
4346: # and select recent are created in lonpubdir.pm
4347: my ($uname,$thisdisfn)=
4348: ($env{'request.filename'} =~ m|^/home/([^/]+)/public_html/(.*)|);
4349: my $formaction='/priv/'.$uname.'/'.$thisdisfn;
4350: $formaction=~s/\/+/\//g;
4351:
4352: my $parentpath = '';
4353: my $lastitem = '';
4354: if ($thisdisfn =~ m-(.+/)([^/]*)$-) {
4355: $parentpath = $1;
4356: $lastitem = $2;
4357: } else {
4358: $lastitem = $thisdisfn;
4359: }
4360: return
4361: '<div>'
4362: .&Apache::loncommon::help_open_menu('','',3,'Authoring') #FIXME: Broken? Where is it?
4363: .'<b>'.&mt('Construction Space:').'</b> '
4364: .'<form name="dirs" method="post" action="'.$formaction
4365: .'" target="_top"><tt><b>' #FIXME lonpubdir: target="_parent"
4366: .&Apache::lonhtmlcommon::crumbs($uname.'/'.$parentpath,'_top','/priv','','+1',1)."$lastitem</b></tt><br />"
4367: #FIXME lonpubdir: &Apache::lonhtmlcommon::crumbs($uname.$thisdisfn.'/','_top','/priv','','+1',1)."</b></tt><br />"
4368: .&Apache::lonhtmlcommon::select_recent('construct','recent','this.form.action=this.form.recent.value;this.form.submit()')
4369: .'</form>'
4370: .&Apache::lonmenu::constspaceform()
4371: .'</div>';
4372: }
4373:
1.60 matthew 4374: ###############################################
4375: ###############################################
4376:
4377: =pod
4378:
1.112 bowersj2 4379: =back
4380:
1.549 albertel 4381: =head1 HTML Helpers
1.112 bowersj2 4382:
4383: =over 4
4384:
4385: =item * &bodytag()
1.60 matthew 4386:
4387: Returns a uniform header for LON-CAPA web pages.
4388:
4389: Inputs:
4390:
1.112 bowersj2 4391: =over 4
4392:
4393: =item * $title, A title to be displayed on the page.
4394:
4395: =item * $function, the current role (can be undef).
4396:
4397: =item * $addentries, extra parameters for the <body> tag.
4398:
4399: =item * $bodyonly, if defined, only return the <body> tag.
4400:
4401: =item * $domain, if defined, force a given domain.
4402:
4403: =item * $forcereg, if page should register as content page (relevant for
1.86 www 4404: text interface only)
1.60 matthew 4405:
1.814 bisitz 4406: =item * $no_nav_bar, if true, keep the 'what is this' info but remove the
4407: navigational links
1.317 albertel 4408:
1.338 albertel 4409: =item * $bgcolor, used to override the bgcolor on a webpage to a specific value
4410:
1.361 albertel 4411: =item * $no_inline_link, if true and in remote mode, don't show the
4412: 'Switch To Inline Menu' link
4413:
1.460 albertel 4414: =item * $args, optional argument valid values are
4415: no_auto_mt_title -> prevents &mt()ing the title arg
1.562 albertel 4416: inherit_jsmath -> when creating popup window in a page,
4417: should it have jsmath forced on by the
4418: current page
1.460 albertel 4419:
1.112 bowersj2 4420: =back
4421:
1.60 matthew 4422: Returns: A uniform header for LON-CAPA web pages.
4423: If $bodyonly is nonzero, a string containing a <body> tag will be returned.
4424: If $bodyonly is undef or zero, an html string containing a <body> tag and
4425: other decorations will be returned.
4426:
4427: =cut
4428:
1.54 www 4429: sub bodytag {
1.831 bisitz 4430: my ($title,$function,$addentries,$bodyonly,$domain,$forcereg,
1.816 bisitz 4431: $no_nav_bar,$bgcolor,$no_inline_link,$args)=@_;
1.339 albertel 4432:
1.460 albertel 4433: if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); }
1.339 albertel 4434:
1.183 matthew 4435: $function = &get_users_function() if (!$function);
1.339 albertel 4436: my $img = &designparm($function.'.img',$domain);
4437: my $font = &designparm($function.'.font',$domain);
4438: my $pgbg = $bgcolor || &designparm($function.'.pgbg',$domain);
4439:
1.803 bisitz 4440: my %design = ( 'style' => 'margin-top: 0',
1.535 albertel 4441: 'bgcolor' => $pgbg,
1.339 albertel 4442: 'text' => $font,
4443: 'alink' => &designparm($function.'.alink',$domain),
4444: 'vlink' => &designparm($function.'.vlink',$domain),
4445: 'link' => &designparm($function.'.link',$domain),);
1.438 albertel 4446: @design{keys(%$addentries)} = @$addentries{keys(%$addentries)};
1.339 albertel 4447:
1.63 www 4448: # role and realm
1.378 raeburn 4449: my ($role,$realm) = split(/\./,$env{'request.role'},2);
4450: if ($role eq 'ca') {
1.479 albertel 4451: my ($rdom,$rname) = ($realm =~ m{^/($match_domain)/($match_username)$});
1.500 albertel 4452: $realm = &plainname($rname,$rdom);
1.378 raeburn 4453: }
1.55 www 4454: # realm
1.258 albertel 4455: if ($env{'request.course.id'}) {
1.378 raeburn 4456: if ($env{'request.role'} !~ /^cr/) {
4457: $role = &Apache::lonnet::plaintext($role,&course_type());
4458: }
1.898 raeburn 4459: if ($env{'request.course.sec'}) {
4460: $role .= (' 'x2).'- '.&mt('section:').' '.$env{'request.course.sec'};
4461: }
1.359 albertel 4462: $realm = $env{'course.'.$env{'request.course.id'}.'.description'};
1.378 raeburn 4463: } else {
4464: $role = &Apache::lonnet::plaintext($role);
1.54 www 4465: }
1.433 albertel 4466:
1.359 albertel 4467: if (!$realm) { $realm=' '; }
1.55 www 4468: # Set messages
1.60 matthew 4469: my $messages=&domainlogo($domain);
1.330 albertel 4470:
1.438 albertel 4471: my $extra_body_attr = &make_attr_string($forcereg,\%design);
1.329 albertel 4472:
1.101 www 4473: # construct main body tag
1.359 albertel 4474: my $bodytag = "<body $extra_body_attr>".
1.562 albertel 4475: &Apache::lontexconvert::init_math_support($args->{'inherit_jsmath'});
1.252 albertel 4476:
1.530 albertel 4477: if ($bodyonly) {
1.60 matthew 4478: return $bodytag;
1.798 tempelho 4479: }
1.359 albertel 4480:
1.410 albertel 4481: my $name = &plainname($env{'user.name'},$env{'user.domain'});
1.433 albertel 4482: if ($env{'user.name'} eq 'public' && $env{'user.domain'} eq 'public') {
4483: undef($role);
1.434 albertel 4484: } else {
4485: $name = &aboutmewrapper($name,$env{'user.name'},$env{'user.domain'});
1.433 albertel 4486: }
1.359 albertel 4487:
1.762 bisitz 4488: my $titleinfo = '<h1>'.$title.'</h1>';
1.359 albertel 4489: #
4490: # Extra info if you are the DC
4491: my $dc_info = '';
4492: if ($env{'user.adv'} && exists($env{'user.role.dc./'.
4493: $env{'course.'.$env{'request.course.id'}.
4494: '.domain'}.'/'})) {
4495: my $cid = $env{'request.course.id'};
4496: $dc_info.= $cid.' '.$env{'course.'.$cid.'.internal.coursecode'};
1.380 www 4497: $dc_info =~ s/\s+$//;
1.359 albertel 4498: $dc_info = '('.$dc_info.')';
4499: }
4500:
1.898 raeburn 4501: $role = '<span class="LC_nobreak">('.$role.')</span>' if $role;
1.853 droeschl 4502: &get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['inhibitmenu']);
4503:
1.837 bisitz 4504: if ($env{'environment.remote'} eq 'off') {
1.359 albertel 4505: # No Remote
1.903 droeschl 4506: if ($no_nav_bar) { return $bodytag; }
4507:
4508: if ($env{'request.state'} eq 'construct') { $forcereg=1; }
4509:
4510: # if ($env{'request.state'} eq 'construct') {
4511: # $titleinfo = &CSTR_pageheader(); #FIXME: Will be removed once all scripts have their own calls
4512: # }
4513:
4514: $bodytag .= qq|<div id="LC_nav_bar">$name $role<br />
4515: <em>$realm</em> $dc_info</div>| unless $env{'form.inhibitmenu'};
1.359 albertel 4516:
1.903 droeschl 4517: if ( $env{'form.inhibitmenu'} eq 'yes'
4518: || $ENV{'REQUEST_URI'} eq '/adm/logout'
4519: || $env{'request.noversionuri'} =~ m{^/res/adm/pages/}) {
1.359 albertel 4520:
1.903 droeschl 4521: return $bodytag;
4522: }
1.894 droeschl 4523:
1.903 droeschl 4524: $bodytag .= Apache::lonhtmlcommon::scripttag(
4525: Apache::lonmenu::utilityfunctions(), 'start');
1.816 bisitz 4526:
1.903 droeschl 4527: $bodytag .= Apache::lonmenu::primary_menu();
1.852 droeschl 4528:
1.903 droeschl 4529: #don't show menus for public users
4530: if($env{'user.name'} ne 'public' && $env{'user.domain'} ne 'public'){
4531: $bodytag .= Apache::lonmenu::secondary_menu();
4532: $bodytag .= Apache::lonmenu::serverform();
4533: $bodytag .= Apache::lonhtmlcommon::scripttag('', 'end');
4534: $bodytag .= Apache::lonmenu::innerregister($forcereg) if $forcereg;
4535: }else{
4536: # this is to seperate menu from content when there's no secondary
4537: # menu. Especially needed for public accessible ressources.
4538: $bodytag .= '<hr style="clear:both" />';
4539: $bodytag .= Apache::lonhtmlcommon::scripttag('', 'end');
1.235 raeburn 4540: }
1.903 droeschl 4541:
4542: #SD testing
4543: #$bodytag .= Apache::lonmenu::menubuttons($forcereg);
1.235 raeburn 4544: return $bodytag;
1.94 www 4545: }
1.95 www 4546:
1.93 www 4547: #
1.95 www 4548: # Top frame rendering, Remote is up
1.93 www 4549: #
1.359 albertel 4550:
1.517 raeburn 4551: my $imgsrc = $img;
4552: if ($img =~ /^\/adm/) {
1.575 albertel 4553: $imgsrc = &lonhttpdurl($img);
1.517 raeburn 4554: }
4555: my $upperleft='<img src="'.$imgsrc.'" alt="'.$function.'" />';
1.359 albertel 4556:
1.305 www 4557: # Explicit link to get inline menu
1.361 albertel 4558: my $menu= ($no_inline_link?''
1.883 droeschl 4559: :'<a href="/adm/remote?action=collapse" target="_top">'.&mt('Switch to Inline Menu Mode').'</a>');
1.853 droeschl 4560: $bodytag .= qq|<div id="LC_nav_bar">$name $role
4561: <em>$realm</em> $dc_info </div>
1.897 wenzelju 4562: <ol class="LC_primary_menu LC_right">
1.853 droeschl 4563: <li>$menu</li>
4564: </ol>| unless $env{'form.inhibitmenu'};
1.245 matthew 4565: #
1.94 www 4566: return(<<ENDBODY);
1.60 matthew 4567: $bodytag
1.359 albertel 4568: <table id="LC_title_bar" class="LC_with_remote">
1.791 tempelho 4569: <tr><td>$upperleft</td>
4570: <td>$messages </td>
1.54 www 4571: </tr>
1.359 albertel 4572: <tr><td>$titleinfo $dc_info $menu</td>
1.368 albertel 4573: </tr>
1.356 albertel 4574: </table>
1.54 www 4575: ENDBODY
1.182 matthew 4576: }
4577:
1.330 albertel 4578: sub make_attr_string {
4579: my ($register,$attr_ref) = @_;
4580:
4581: if ($attr_ref && !ref($attr_ref)) {
4582: die("addentries Must be a hash ref ".
4583: join(':',caller(1))." ".
4584: join(':',caller(0))." ");
4585: }
4586:
4587: if ($register) {
1.339 albertel 4588: my ($on_load,$on_unload);
4589: foreach my $key (keys(%{$attr_ref})) {
4590: if (lc($key) eq 'onload') {
4591: $on_load.=$attr_ref->{$key}.';';
4592: delete($attr_ref->{$key});
4593:
4594: } elsif (lc($key) eq 'onunload') {
4595: $on_unload.=$attr_ref->{$key}.';';
4596: delete($attr_ref->{$key});
4597: }
4598: }
4599: $attr_ref->{'onload'} =
4600: &Apache::lonmenu::loadevents(). $on_load;
4601: $attr_ref->{'onunload'}=
4602: &Apache::lonmenu::unloadevents().$on_unload;
4603: }
4604:
4605: # Accessibility font enhance
4606: if ($env{'browser.fontenhance'} eq 'on') {
4607: my $style;
4608: foreach my $key (keys(%{$attr_ref})) {
4609: if (lc($key) eq 'style') {
4610: $style.=$attr_ref->{$key}.';';
4611: delete($attr_ref->{$key});
4612: }
4613: }
4614: $attr_ref->{'style'}=$style.'; font-size: x-large;';
1.330 albertel 4615: }
1.339 albertel 4616:
1.330 albertel 4617: my $attr_string;
4618: foreach my $attr (keys(%$attr_ref)) {
4619: $attr_string .= " $attr=\"".$attr_ref->{$attr}.'" ';
4620: }
4621: return $attr_string;
4622: }
4623:
4624:
1.182 matthew 4625: ###############################################
1.251 albertel 4626: ###############################################
4627:
4628: =pod
4629:
4630: =item * &endbodytag()
4631:
4632: Returns a uniform footer for LON-CAPA web pages.
4633:
1.635 raeburn 4634: Inputs: 1 - optional reference to an args hash
4635: If in the hash, key for noredirectlink has a value which evaluates to true,
4636: a 'Continue' link is not displayed if the page contains an
4637: internal redirect in the <head></head> section,
4638: i.e., $env{'internal.head.redirect'} exists
1.251 albertel 4639:
4640: =cut
4641:
4642: sub endbodytag {
1.635 raeburn 4643: my ($args) = @_;
1.251 albertel 4644: my $endbodytag='</body>';
1.269 albertel 4645: $endbodytag=&Apache::lontexconvert::jsMath_process()."\n".$endbodytag;
1.315 albertel 4646: if ( exists( $env{'internal.head.redirect'} ) ) {
1.635 raeburn 4647: if (!(ref($args) eq 'HASH' && $args->{'noredirectlink'})) {
4648: $endbodytag=
4649: "<br /><a href=\"$env{'internal.head.redirect'}\">".
4650: &mt('Continue').'</a>'.
4651: $endbodytag;
4652: }
1.315 albertel 4653: }
1.251 albertel 4654: return $endbodytag;
4655: }
4656:
1.352 albertel 4657: =pod
4658:
4659: =item * &standard_css()
4660:
4661: Returns a style sheet
4662:
4663: Inputs: (all optional)
4664: domain -> force to color decorate a page for a specific
4665: domain
4666: function -> force usage of a specific rolish color scheme
4667: bgcolor -> override the default page bgcolor
4668:
4669: =cut
4670:
1.343 albertel 4671: sub standard_css {
1.345 albertel 4672: my ($function,$domain,$bgcolor) = @_;
1.352 albertel 4673: $function = &get_users_function() if (!$function);
4674: my $img = &designparm($function.'.img', $domain);
4675: my $tabbg = &designparm($function.'.tabbg', $domain);
4676: my $font = &designparm($function.'.font', $domain);
1.801 tempelho 4677: my $fontmenu = &designparm($function.'.fontmenu', $domain);
1.791 tempelho 4678: #second colour for later usage
1.345 albertel 4679: my $sidebg = &designparm($function.'.sidebg',$domain);
1.382 albertel 4680: my $pgbg_or_bgcolor =
4681: $bgcolor ||
1.352 albertel 4682: &designparm($function.'.pgbg', $domain);
1.382 albertel 4683: my $pgbg = &designparm($function.'.pgbg', $domain);
1.352 albertel 4684: my $alink = &designparm($function.'.alink', $domain);
4685: my $vlink = &designparm($function.'.vlink', $domain);
4686: my $link = &designparm($function.'.link', $domain);
4687:
1.704 muellerd 4688: my $loginbg = &designparm('login.sidebg',$domain);
1.712 muellerd 4689: my $bgcol = &designparm('login.bgcol',$domain);
4690: my $textcol = &designparm('login.textcol',$domain);
1.704 muellerd 4691:
1.602 albertel 4692: my $sans = 'Verdana,Arial,Helvetica,sans-serif';
1.395 albertel 4693: my $mono = 'monospace';
1.850 bisitz 4694: my $data_table_head = $sidebg;
4695: my $data_table_light = '#FAFAFA';
4696: my $data_table_dark = '#F0F0F0';
1.470 banghart 4697: my $data_table_darker = '#CCCCCC';
1.349 albertel 4698: my $data_table_highlight = '#FFFF00';
1.352 albertel 4699: my $mail_new = '#FFBB77';
4700: my $mail_new_hover = '#DD9955';
4701: my $mail_read = '#BBBB77';
4702: my $mail_read_hover = '#999944';
4703: my $mail_replied = '#AAAA88';
4704: my $mail_replied_hover = '#888855';
4705: my $mail_other = '#99BBBB';
4706: my $mail_other_hover = '#669999';
1.391 albertel 4707: my $table_header = '#DDDDDD';
1.489 raeburn 4708: my $feedback_link_bg = '#BBBBBB';
1.701 harmsja 4709: my $lg_border_color = '#C8C8C8';
1.392 albertel 4710:
1.608 albertel 4711: my $border = ($env{'browser.type'} eq 'explorer' ||
1.803 bisitz 4712: $env{'browser.type'} eq 'safari' ) ? '0 2px 0 2px'
4713: : '0 3px 0 4px';
1.448 albertel 4714:
1.523 albertel 4715:
1.343 albertel 4716: return <<END;
1.795 www 4717: body {
4718: font-family: $sans;
4719: line-height:130%;
4720: font-size:0.83em;
4721: color:$font;
4722: }
4723:
4724: a:link, a:visited {
4725: font-size:100%;
4726: }
4727:
4728: a:focus {
4729: color: red;
4730: background: yellow
4731: }
1.698 harmsja 4732:
1.795 www 4733: form, .inline {
4734: display: inline;
4735: }
1.721 harmsja 4736:
1.795 www 4737: .LC_right {
4738: text-align:right;
4739: }
4740:
4741: .LC_middle {
4742: vertical-align:middle;
4743: }
1.721 harmsja 4744:
4745: /* just for tests */
1.754 droeschl 4746: .LC_400Box {width:400px; }
1.721 harmsja 4747: /* end */
4748:
1.778 bisitz 4749: .LC_filename {
4750: font-family: $mono;
4751: white-space:pre;
4752: }
4753:
4754: .LC_fileicon {
4755: border: none;
4756: height: 1.3em;
4757: vertical-align: text-bottom;
4758: margin-right: 0.3em;
4759: text-decoration:none;
4760: }
4761:
1.350 albertel 4762: .LC_error {
4763: color: red;
4764: font-size: larger;
4765: }
1.795 www 4766:
1.457 albertel 4767: .LC_warning,
4768: .LC_diff_removed {
1.733 bisitz 4769: color: red;
1.394 albertel 4770: }
1.532 albertel 4771:
4772: .LC_info,
1.457 albertel 4773: .LC_success,
4774: .LC_diff_added {
1.350 albertel 4775: color: green;
4776: }
1.795 www 4777:
1.802 bisitz 4778: div.LC_confirm_box {
4779: background-color: #FAFAFA;
4780: border: 1px solid $lg_border_color;
4781: margin-right: 0;
4782: padding: 5px;
4783: }
4784:
4785: div.LC_confirm_box .LC_error img,
4786: div.LC_confirm_box .LC_success img {
4787: vertical-align: middle;
4788: }
4789:
1.440 albertel 4790: .LC_icon {
1.771 droeschl 4791: border: none;
1.790 droeschl 4792: vertical-align: middle;
1.771 droeschl 4793: }
4794:
1.543 albertel 4795: .LC_docs_spacer {
4796: width: 25px;
4797: height: 1px;
1.771 droeschl 4798: border: none;
1.543 albertel 4799: }
1.346 albertel 4800:
1.532 albertel 4801: .LC_internal_info {
1.735 bisitz 4802: color: #999999;
1.532 albertel 4803: }
4804:
1.794 www 4805: .LC_discussion {
4806: background: $tabbg;
4807: border: 1px solid black;
4808: margin: 2px;
4809: }
4810:
4811: .LC_disc_action_links_bar {
4812: background: $tabbg;
1.803 bisitz 4813: border: none;
1.795 www 4814: margin: 4px;
1.794 www 4815: }
4816:
4817: .LC_disc_action_left {
4818: text-align: left;
4819: }
4820:
4821: .LC_disc_action_right {
4822: text-align: right;
4823: }
4824:
4825: .LC_disc_new_item {
4826: background: white;
4827: border: 2px solid red;
4828: margin: 2px;
4829: }
4830:
4831: .LC_disc_old_item {
4832: background: white;
4833: border: 1px solid black;
4834: margin: 2px;
4835: }
4836:
1.458 albertel 4837: table.LC_pastsubmission {
4838: border: 1px solid black;
4839: margin: 2px;
4840: }
4841:
1.795 www 4842: table#LC_top_nav,
4843: table#LC_menubuttons,
4844: table#LC_nav_location {
1.345 albertel 4845: width: 100%;
4846: background: $pgbg;
1.392 albertel 4847: border: 2px;
1.402 albertel 4848: border-collapse: separate;
1.803 bisitz 4849: padding: 0;
1.345 albertel 4850: }
1.392 albertel 4851:
1.801 tempelho 4852: table#LC_title_bar a {
4853: color: $fontmenu;
4854: }
1.836 bisitz 4855:
1.807 droeschl 4856: table#LC_title_bar {
1.819 tempelho 4857: clear: both;
1.836 bisitz 4858: display: none;
1.807 droeschl 4859: }
4860:
1.795 www 4861: table#LC_title_bar,
4862: table.LC_breadcrumbs,
1.393 albertel 4863: table#LC_title_bar.LC_with_remote {
1.359 albertel 4864: width: 100%;
1.392 albertel 4865: border-color: $pgbg;
4866: border-style: solid;
4867: border-width: $border;
1.379 albertel 4868: background: $pgbg;
1.801 tempelho 4869: color: $fontmenu;
1.392 albertel 4870: border-collapse: collapse;
1.803 bisitz 4871: padding: 0;
1.819 tempelho 4872: margin: 0;
1.359 albertel 4873: }
1.795 www 4874:
1.359 albertel 4875: table#LC_title_bar td {
4876: background: $tabbg;
4877: }
1.795 www 4878:
1.706 harmsja 4879: table#LC_menubuttons img{
1.803 bisitz 4880: border: none;
1.346 albertel 4881: }
1.795 www 4882:
1.345 albertel 4883: table#LC_top_nav td {
4884: background: $tabbg;
1.803 bisitz 4885: border: none;
1.407 albertel 4886: font-size: small;
1.706 harmsja 4887: vertical-align:top;
4888: padding:2px 5px 2px 5px;
1.345 albertel 4889: }
1.795 www 4890:
4891: table#LC_top_nav td a,
4892: div#LC_top_nav a {
1.345 albertel 4893: color: $font;
4894: }
1.795 www 4895:
1.364 albertel 4896: table#LC_top_nav td.LC_top_nav_logo {
4897: background: $tabbg;
1.432 albertel 4898: text-align: left;
1.408 albertel 4899: white-space: nowrap;
1.432 albertel 4900: width: 31px;
1.408 albertel 4901: }
1.795 www 4902:
1.408 albertel 4903: table#LC_top_nav td.LC_top_nav_logo img {
1.803 bisitz 4904: border: none;
1.408 albertel 4905: vertical-align: bottom;
1.364 albertel 4906: }
1.795 www 4907:
1.777 tempelho 4908: table#LC_top_nav td.LC_top_nav_exit,
1.779 bisitz 4909: table#LC_top_nav td.LC_top_nav_help {
1.777 tempelho 4910: width: 2.0em;
4911: }
1.795 www 4912:
1.442 albertel 4913: table#LC_top_nav td.LC_top_nav_login {
4914: width: 4.0em;
4915: text-align: center;
4916: }
1.795 www 4917:
1.842 droeschl 4918: .LC_breadcrumbs_component {
4919: float: right;
4920: margin: 0 1em;
1.357 albertel 4921: }
1.842 droeschl 4922: .LC_breadcrumbs_component img {
4923: vertical-align: middle;
1.777 tempelho 4924: }
1.795 www 4925:
1.383 albertel 4926: td.LC_table_cell_checkbox {
4927: text-align: center;
4928: }
1.795 www 4929:
1.779 bisitz 4930: table#LC_mainmenu td.LC_mainmenu_column {
4931: vertical-align: top;
1.777 tempelho 4932: }
1.522 albertel 4933:
1.795 www 4934: .LC_fontsize_small {
1.705 tempelho 4935: font-size: 70%;
4936: }
4937:
1.844 bisitz 4938: #LC_breadcrumbs {
1.819 tempelho 4939: clear:both;
4940: background: $sidebg;
1.822 bisitz 4941: border-bottom: 1px solid $lg_border_color;
1.904 droeschl 4942: line-height: 2.5em;
4943: /* SD working here
4944: height: 2.5em;
4945: overflow: hidden; */
1.822 bisitz 4946: margin: 0;
1.819 tempelho 4947: padding: 0;
4948: }
1.862 bisitz 4949:
1.839 droeschl 4950: /* Preliminary fix to hide breadcrumbs inside remote control window */
1.844 bisitz 4951: #LC_remote #LC_breadcrumbs {
1.839 droeschl 4952: display:none;
4953: }
1.819 tempelho 4954:
1.844 bisitz 4955: #LC_head_subbox {
1.822 bisitz 4956: clear:both;
4957: background: #F8F8F8; /* $sidebg; */
4958: border-bottom: 1px solid $lg_border_color;
4959: margin: 0 0 10px 0;
4960: padding: 5px;
4961: }
4962:
1.795 www 4963: .LC_fontsize_medium {
1.705 tempelho 4964: font-size: 85%;
4965: }
4966:
1.795 www 4967: .LC_fontsize_large {
1.705 tempelho 4968: font-size: 120%;
4969: }
4970:
1.346 albertel 4971: .LC_menubuttons_inline_text {
4972: color: $font;
1.698 harmsja 4973: font-size: 90%;
1.701 harmsja 4974: padding-left:3px;
1.346 albertel 4975: }
4976:
1.526 www 4977: .LC_menubuttons_link {
4978: text-decoration: none;
4979: }
1.795 www 4980:
1.522 albertel 4981: .LC_menubuttons_category {
1.521 www 4982: color: $font;
1.526 www 4983: background: $pgbg;
1.521 www 4984: font-size: larger;
4985: font-weight: bold;
4986: }
4987:
1.346 albertel 4988: td.LC_menubuttons_text {
1.779 bisitz 4989: color: $font;
1.346 albertel 4990: }
1.706 harmsja 4991:
1.346 albertel 4992: .LC_current_location {
4993: background: $tabbg;
4994: }
1.795 www 4995:
1.346 albertel 4996: .LC_new_mail {
1.634 www 4997: background: $tabbg;
1.346 albertel 4998: font-weight: bold;
4999: }
1.347 albertel 5000:
1.795 www 5001: table.LC_data_table,
5002: table.LC_mail_list {
1.347 albertel 5003: border: 1px solid #000000;
1.402 albertel 5004: border-collapse: separate;
1.426 albertel 5005: border-spacing: 1px;
1.610 albertel 5006: background: $pgbg;
1.347 albertel 5007: }
1.795 www 5008:
1.422 albertel 5009: .LC_data_table_dense {
5010: font-size: small;
5011: }
1.795 www 5012:
1.507 raeburn 5013: table.LC_nested_outer {
5014: border: 1px solid #000000;
1.589 raeburn 5015: border-collapse: collapse;
1.803 bisitz 5016: border-spacing: 0;
1.507 raeburn 5017: width: 100%;
5018: }
1.795 www 5019:
1.879 raeburn 5020: table.LC_innerpickbox,
1.507 raeburn 5021: table.LC_nested {
1.803 bisitz 5022: border: none;
1.589 raeburn 5023: border-collapse: collapse;
1.803 bisitz 5024: border-spacing: 0;
1.507 raeburn 5025: width: 100%;
5026: }
1.795 www 5027:
5028: table.LC_data_table tr th,
5029: table.LC_calendar tr th,
5030: table.LC_mail_list tr th,
1.879 raeburn 5031: table.LC_prior_tries tr th,
5032: table.LC_innerpickbox tr th {
1.349 albertel 5033: font-weight: bold;
5034: background-color: $data_table_head;
1.801 tempelho 5035: color:$fontmenu;
1.701 harmsja 5036: font-size:90%;
1.347 albertel 5037: }
1.795 www 5038:
1.879 raeburn 5039: table.LC_innerpickbox tr th,
5040: table.LC_innerpickbox tr td {
5041: vertical-align: top;
5042: }
5043:
1.711 raeburn 5044: table.LC_data_table tr.LC_info_row > td {
1.735 bisitz 5045: background-color: #CCCCCC;
1.711 raeburn 5046: font-weight: bold;
5047: text-align: left;
5048: }
1.795 www 5049:
1.779 bisitz 5050: table.LC_data_table tr.LC_odd_row > td,
1.809 bisitz 5051: table.LC_pick_box tr > td.LC_odd_row {
1.349 albertel 5052: background-color: $data_table_light;
1.425 albertel 5053: padding: 2px;
1.900 bisitz 5054: vertical-align: top;
1.347 albertel 5055: }
1.795 www 5056:
1.610 albertel 5057: table.LC_data_table tr.LC_even_row > td,
1.809 bisitz 5058: table.LC_pick_box tr > td.LC_even_row {
1.349 albertel 5059: background-color: $data_table_dark;
1.709 bisitz 5060: padding: 2px;
1.900 bisitz 5061: vertical-align: top;
1.347 albertel 5062: }
1.795 www 5063:
1.425 albertel 5064: table.LC_data_table tr.LC_data_table_highlight td {
5065: background-color: $data_table_darker;
5066: }
1.795 www 5067:
1.639 raeburn 5068: table.LC_data_table tr td.LC_leftcol_header {
5069: background-color: $data_table_head;
5070: font-weight: bold;
5071: }
1.795 www 5072:
1.451 albertel 5073: table.LC_data_table tr.LC_empty_row td,
1.507 raeburn 5074: table.LC_nested tr.LC_empty_row td {
1.347 albertel 5075: background-color: #FFFFFF;
1.421 albertel 5076: font-weight: bold;
5077: font-style: italic;
5078: text-align: center;
5079: padding: 8px;
1.347 albertel 5080: }
1.795 www 5081:
1.890 droeschl 5082: table.LC_caption {
5083: }
5084:
1.507 raeburn 5085: table.LC_nested tr.LC_empty_row td {
1.465 albertel 5086: padding: 4ex
5087: }
1.795 www 5088:
1.507 raeburn 5089: table.LC_nested_outer tr th {
5090: font-weight: bold;
1.801 tempelho 5091: color:$fontmenu;
1.507 raeburn 5092: background-color: $data_table_head;
1.701 harmsja 5093: font-size: small;
1.507 raeburn 5094: border-bottom: 1px solid #000000;
5095: }
1.795 www 5096:
1.507 raeburn 5097: table.LC_nested_outer tr td.LC_subheader {
5098: background-color: $data_table_head;
5099: font-weight: bold;
5100: font-size: small;
5101: border-bottom: 1px solid #000000;
5102: text-align: right;
1.451 albertel 5103: }
1.795 www 5104:
1.507 raeburn 5105: table.LC_nested tr.LC_info_row td {
1.735 bisitz 5106: background-color: #CCCCCC;
1.451 albertel 5107: font-weight: bold;
5108: font-size: small;
1.507 raeburn 5109: text-align: center;
5110: }
1.795 www 5111:
1.589 raeburn 5112: table.LC_nested tr.LC_info_row td.LC_left_item,
5113: table.LC_nested_outer tr th.LC_left_item {
1.507 raeburn 5114: text-align: left;
1.451 albertel 5115: }
1.795 www 5116:
1.507 raeburn 5117: table.LC_nested td {
1.735 bisitz 5118: background-color: #FFFFFF;
1.451 albertel 5119: font-size: small;
1.507 raeburn 5120: }
1.795 www 5121:
1.507 raeburn 5122: table.LC_nested_outer tr th.LC_right_item,
5123: table.LC_nested tr.LC_info_row td.LC_right_item,
5124: table.LC_nested tr.LC_odd_row td.LC_right_item,
5125: table.LC_nested tr td.LC_right_item {
1.451 albertel 5126: text-align: right;
5127: }
5128:
1.507 raeburn 5129: table.LC_nested tr.LC_odd_row td {
1.735 bisitz 5130: background-color: #EEEEEE;
1.451 albertel 5131: }
5132:
1.473 raeburn 5133: table.LC_createuser {
5134: }
5135:
5136: table.LC_createuser tr.LC_section_row td {
1.701 harmsja 5137: font-size: small;
1.473 raeburn 5138: }
5139:
5140: table.LC_createuser tr.LC_info_row td {
1.735 bisitz 5141: background-color: #CCCCCC;
1.473 raeburn 5142: font-weight: bold;
5143: text-align: center;
5144: }
5145:
1.349 albertel 5146: table.LC_calendar {
5147: border: 1px solid #000000;
5148: border-collapse: collapse;
5149: }
1.795 www 5150:
1.349 albertel 5151: table.LC_calendar_pickdate {
5152: font-size: xx-small;
5153: }
1.795 www 5154:
1.349 albertel 5155: table.LC_calendar tr td {
5156: border: 1px solid #000000;
5157: vertical-align: top;
5158: }
1.795 www 5159:
1.349 albertel 5160: table.LC_calendar tr td.LC_calendar_day_empty {
5161: background-color: $data_table_dark;
5162: }
1.795 www 5163:
1.779 bisitz 5164: table.LC_calendar tr td.LC_calendar_day_current {
5165: background-color: $data_table_highlight;
1.777 tempelho 5166: }
1.795 www 5167:
1.349 albertel 5168: table.LC_mail_list tr.LC_mail_new {
5169: background-color: $mail_new;
5170: }
1.795 www 5171:
1.349 albertel 5172: table.LC_mail_list tr.LC_mail_new:hover {
5173: background-color: $mail_new_hover;
5174: }
1.795 www 5175:
5176: table.LC_mail_list tr.LC_mail_even {
1.777 tempelho 5177: }
1.795 www 5178:
5179: table.LC_mail_list tr.LC_mail_odd {
1.777 tempelho 5180: }
1.795 www 5181:
1.349 albertel 5182: table.LC_mail_list tr.LC_mail_read {
5183: background-color: $mail_read;
5184: }
1.795 www 5185:
1.349 albertel 5186: table.LC_mail_list tr.LC_mail_read:hover {
5187: background-color: $mail_read_hover;
5188: }
1.795 www 5189:
1.349 albertel 5190: table.LC_mail_list tr.LC_mail_replied {
5191: background-color: $mail_replied;
5192: }
1.795 www 5193:
1.349 albertel 5194: table.LC_mail_list tr.LC_mail_replied:hover {
5195: background-color: $mail_replied_hover;
5196: }
1.795 www 5197:
1.349 albertel 5198: table.LC_mail_list tr.LC_mail_other {
5199: background-color: $mail_other;
5200: }
1.795 www 5201:
1.349 albertel 5202: table.LC_mail_list tr.LC_mail_other:hover {
5203: background-color: $mail_other_hover;
5204: }
1.494 raeburn 5205:
1.777 tempelho 5206: table.LC_data_table tr > td.LC_browser_file,
5207: table.LC_data_table tr > td.LC_browser_file_published {
1.899 bisitz 5208: background: #AAEE77;
1.389 albertel 5209: }
1.795 www 5210:
1.777 tempelho 5211: table.LC_data_table tr > td.LC_browser_file_locked,
5212: table.LC_data_table tr > td.LC_browser_file_unpublished {
1.389 albertel 5213: background: #FFAA99;
1.387 albertel 5214: }
1.795 www 5215:
1.777 tempelho 5216: table.LC_data_table tr > td.LC_browser_file_obsolete {
1.899 bisitz 5217: background: #888888;
1.779 bisitz 5218: }
1.795 www 5219:
1.777 tempelho 5220: table.LC_data_table tr > td.LC_browser_file_modified,
1.779 bisitz 5221: table.LC_data_table tr > td.LC_browser_file_metamodified {
1.899 bisitz 5222: background: #F8F866;
1.777 tempelho 5223: }
1.795 www 5224:
1.696 bisitz 5225: table.LC_data_table tr.LC_browser_folder > td {
1.899 bisitz 5226: background: #E0E8FF;
1.387 albertel 5227: }
1.696 bisitz 5228:
1.707 bisitz 5229: table.LC_data_table tr > td.LC_roles_is {
5230: /* background: #77FF77; */
5231: }
1.795 www 5232:
1.707 bisitz 5233: table.LC_data_table tr > td.LC_roles_future {
5234: background: #FFFF77;
5235: }
1.795 www 5236:
1.707 bisitz 5237: table.LC_data_table tr > td.LC_roles_will {
5238: background: #FFAA77;
5239: }
1.795 www 5240:
1.707 bisitz 5241: table.LC_data_table tr > td.LC_roles_expired {
5242: background: #FF7777;
5243: }
1.795 www 5244:
1.707 bisitz 5245: table.LC_data_table tr > td.LC_roles_will_not {
5246: background: #AAFF77;
5247: }
1.795 www 5248:
1.707 bisitz 5249: table.LC_data_table tr > td.LC_roles_selected {
5250: background: #11CC55;
5251: }
5252:
1.388 albertel 5253: span.LC_current_location {
1.701 harmsja 5254: font-size:larger;
1.388 albertel 5255: background: $pgbg;
5256: }
1.387 albertel 5257:
1.395 albertel 5258: span.LC_parm_menu_item {
5259: font-size: larger;
5260: }
1.795 www 5261:
1.395 albertel 5262: span.LC_parm_scope_all {
5263: color: red;
5264: }
1.795 www 5265:
1.395 albertel 5266: span.LC_parm_scope_folder {
5267: color: green;
5268: }
1.795 www 5269:
1.395 albertel 5270: span.LC_parm_scope_resource {
5271: color: orange;
5272: }
1.795 www 5273:
1.395 albertel 5274: span.LC_parm_part {
5275: color: blue;
5276: }
1.795 www 5277:
1.395 albertel 5278: span.LC_parm_folder, span.LC_parm_symb {
5279: font-size: x-small;
5280: font-family: $mono;
5281: color: #AAAAAA;
5282: }
5283:
1.795 www 5284: td.LC_parm_overview_level_menu,
5285: td.LC_parm_overview_map_menu,
5286: td.LC_parm_overview_parm_selectors,
5287: td.LC_parm_overview_restrictions {
1.396 albertel 5288: border: 1px solid black;
5289: border-collapse: collapse;
5290: }
1.795 www 5291:
1.396 albertel 5292: table.LC_parm_overview_restrictions td {
5293: border-width: 1px 4px 1px 4px;
5294: border-style: solid;
5295: border-color: $pgbg;
5296: text-align: center;
5297: }
1.795 www 5298:
1.396 albertel 5299: table.LC_parm_overview_restrictions th {
5300: background: $tabbg;
5301: border-width: 1px 4px 1px 4px;
5302: border-style: solid;
5303: border-color: $pgbg;
5304: }
1.795 www 5305:
1.398 albertel 5306: table#LC_helpmenu {
1.803 bisitz 5307: border: none;
1.398 albertel 5308: height: 55px;
1.803 bisitz 5309: border-spacing: 0;
1.398 albertel 5310: }
5311:
5312: table#LC_helpmenu fieldset legend {
5313: font-size: larger;
5314: }
1.795 www 5315:
1.397 albertel 5316: table#LC_helpmenu_links {
5317: width: 100%;
5318: border: 1px solid black;
5319: background: $pgbg;
1.803 bisitz 5320: padding: 0;
1.397 albertel 5321: border-spacing: 1px;
5322: }
1.795 www 5323:
1.397 albertel 5324: table#LC_helpmenu_links tr td {
5325: padding: 1px;
5326: background: $tabbg;
1.399 albertel 5327: text-align: center;
5328: font-weight: bold;
1.397 albertel 5329: }
1.396 albertel 5330:
1.795 www 5331: table#LC_helpmenu_links a:link,
5332: table#LC_helpmenu_links a:visited,
1.397 albertel 5333: table#LC_helpmenu_links a:active {
5334: text-decoration: none;
5335: color: $font;
5336: }
1.795 www 5337:
1.397 albertel 5338: table#LC_helpmenu_links a:hover {
5339: text-decoration: underline;
5340: color: $vlink;
5341: }
1.396 albertel 5342:
1.417 albertel 5343: .LC_chrt_popup_exists {
5344: border: 1px solid #339933;
5345: margin: -1px;
5346: }
1.795 www 5347:
1.417 albertel 5348: .LC_chrt_popup_up {
5349: border: 1px solid yellow;
5350: margin: -1px;
5351: }
1.795 www 5352:
1.417 albertel 5353: .LC_chrt_popup {
5354: border: 1px solid #8888FF;
5355: background: #CCCCFF;
5356: }
1.795 www 5357:
1.421 albertel 5358: table.LC_pick_box {
5359: border-collapse: separate;
5360: background: white;
5361: border: 1px solid black;
5362: border-spacing: 1px;
5363: }
1.795 www 5364:
1.421 albertel 5365: table.LC_pick_box td.LC_pick_box_title {
1.850 bisitz 5366: background: $sidebg;
1.421 albertel 5367: font-weight: bold;
1.900 bisitz 5368: text-align: left;
1.740 bisitz 5369: vertical-align: top;
1.421 albertel 5370: width: 184px;
5371: padding: 8px;
5372: }
1.795 www 5373:
1.579 raeburn 5374: table.LC_pick_box td.LC_pick_box_value {
5375: text-align: left;
5376: padding: 8px;
5377: }
1.795 www 5378:
1.579 raeburn 5379: table.LC_pick_box td.LC_pick_box_select {
5380: text-align: left;
5381: padding: 8px;
5382: }
1.795 www 5383:
1.424 albertel 5384: table.LC_pick_box td.LC_pick_box_separator {
1.803 bisitz 5385: padding: 0;
1.421 albertel 5386: height: 1px;
5387: background: black;
5388: }
1.795 www 5389:
1.421 albertel 5390: table.LC_pick_box td.LC_pick_box_submit {
5391: text-align: right;
5392: }
1.795 www 5393:
1.579 raeburn 5394: table.LC_pick_box td.LC_evenrow_value {
5395: text-align: left;
5396: padding: 8px;
5397: background-color: $data_table_light;
5398: }
1.795 www 5399:
1.579 raeburn 5400: table.LC_pick_box td.LC_oddrow_value {
5401: text-align: left;
5402: padding: 8px;
5403: background-color: $data_table_light;
5404: }
1.795 www 5405:
1.579 raeburn 5406: span.LC_helpform_receipt_cat {
5407: font-weight: bold;
5408: }
1.795 www 5409:
1.424 albertel 5410: table.LC_group_priv_box {
5411: background: white;
5412: border: 1px solid black;
5413: border-spacing: 1px;
5414: }
1.795 www 5415:
1.424 albertel 5416: table.LC_group_priv_box td.LC_pick_box_title {
5417: background: $tabbg;
5418: font-weight: bold;
5419: text-align: right;
5420: width: 184px;
5421: }
1.795 www 5422:
1.424 albertel 5423: table.LC_group_priv_box td.LC_groups_fixed {
5424: background: $data_table_light;
5425: text-align: center;
5426: }
1.795 www 5427:
1.424 albertel 5428: table.LC_group_priv_box td.LC_groups_optional {
5429: background: $data_table_dark;
5430: text-align: center;
5431: }
1.795 www 5432:
1.424 albertel 5433: table.LC_group_priv_box td.LC_groups_functionality {
5434: background: $data_table_darker;
5435: text-align: center;
5436: font-weight: bold;
5437: }
1.795 www 5438:
1.424 albertel 5439: table.LC_group_priv td {
5440: text-align: left;
1.803 bisitz 5441: padding: 0;
1.424 albertel 5442: }
5443:
1.421 albertel 5444: table.LC_notify_front_page {
5445: background: white;
5446: border: 1px solid black;
5447: padding: 8px;
5448: }
1.795 www 5449:
1.421 albertel 5450: table.LC_notify_front_page td {
5451: padding: 8px;
5452: }
1.795 www 5453:
1.424 albertel 5454: .LC_navbuttons {
5455: margin: 2ex 0ex 2ex 0ex;
5456: }
1.795 www 5457:
1.423 albertel 5458: .LC_topic_bar {
5459: font-weight: bold;
5460: width: 100%;
5461: background: $tabbg;
5462: vertical-align: middle;
5463: margin: 2ex 0ex 2ex 0ex;
1.805 bisitz 5464: padding: 3px;
1.423 albertel 5465: }
1.795 www 5466:
1.423 albertel 5467: .LC_topic_bar span {
5468: vertical-align: middle;
5469: }
1.795 www 5470:
1.423 albertel 5471: .LC_topic_bar img {
5472: vertical-align: bottom;
5473: }
1.795 www 5474:
1.423 albertel 5475: table.LC_course_group_status {
5476: margin: 20px;
5477: }
1.795 www 5478:
1.423 albertel 5479: table.LC_status_selector td {
5480: vertical-align: top;
5481: text-align: center;
1.424 albertel 5482: padding: 4px;
5483: }
1.795 www 5484:
1.599 albertel 5485: div.LC_feedback_link {
1.616 albertel 5486: clear: both;
1.829 kalberla 5487: background: $sidebg;
1.779 bisitz 5488: width: 100%;
1.829 kalberla 5489: padding-bottom: 10px;
5490: border: 1px $tabbg solid;
1.833 kalberla 5491: height: 22px;
5492: line-height: 22px;
5493: padding-top: 5px;
5494: }
5495:
5496: div.LC_feedback_link img {
5497: height: 22px;
1.867 kalberla 5498: vertical-align:middle;
1.829 kalberla 5499: }
5500:
5501: div.LC_feedback_link a{
5502: text-decoration: none;
1.489 raeburn 5503: }
1.795 www 5504:
1.867 kalberla 5505: div.LC_comblock {
5506: display:inline;
5507: color:$font;
5508: font-size:90%;
5509: }
5510:
5511: div.LC_feedback_link div.LC_comblock {
5512: padding-left:5px;
5513: }
5514:
5515: div.LC_feedback_link div.LC_comblock a {
5516: color:$font;
5517: }
5518:
1.489 raeburn 5519: span.LC_feedback_link {
1.858 bisitz 5520: /* background: $feedback_link_bg; */
1.599 albertel 5521: font-size: larger;
5522: }
1.795 www 5523:
1.599 albertel 5524: span.LC_message_link {
1.858 bisitz 5525: /* background: $feedback_link_bg; */
1.599 albertel 5526: font-size: larger;
5527: position: absolute;
5528: right: 1em;
1.489 raeburn 5529: }
1.421 albertel 5530:
1.515 albertel 5531: table.LC_prior_tries {
1.524 albertel 5532: border: 1px solid #000000;
5533: border-collapse: separate;
5534: border-spacing: 1px;
1.515 albertel 5535: }
1.523 albertel 5536:
1.515 albertel 5537: table.LC_prior_tries td {
1.524 albertel 5538: padding: 2px;
1.515 albertel 5539: }
1.523 albertel 5540:
5541: .LC_answer_correct {
1.795 www 5542: background: lightgreen;
5543: color: darkgreen;
5544: padding: 6px;
1.523 albertel 5545: }
1.795 www 5546:
1.523 albertel 5547: .LC_answer_charged_try {
1.797 www 5548: background: #FFAAAA;
1.795 www 5549: color: darkred;
5550: padding: 6px;
1.523 albertel 5551: }
1.795 www 5552:
1.779 bisitz 5553: .LC_answer_not_charged_try,
1.523 albertel 5554: .LC_answer_no_grade,
5555: .LC_answer_late {
1.795 www 5556: background: lightyellow;
1.523 albertel 5557: color: black;
1.795 www 5558: padding: 6px;
1.523 albertel 5559: }
1.795 www 5560:
1.523 albertel 5561: .LC_answer_previous {
1.795 www 5562: background: lightblue;
5563: color: darkblue;
5564: padding: 6px;
1.523 albertel 5565: }
1.795 www 5566:
1.779 bisitz 5567: .LC_answer_no_message {
1.777 tempelho 5568: background: #FFFFFF;
5569: color: black;
1.795 www 5570: padding: 6px;
1.779 bisitz 5571: }
1.795 www 5572:
1.779 bisitz 5573: .LC_answer_unknown {
5574: background: orange;
5575: color: black;
1.795 www 5576: padding: 6px;
1.777 tempelho 5577: }
1.795 www 5578:
1.529 albertel 5579: span.LC_prior_numerical,
5580: span.LC_prior_string,
5581: span.LC_prior_custom,
5582: span.LC_prior_reaction,
5583: span.LC_prior_math {
1.523 albertel 5584: font-family: monospace;
5585: white-space: pre;
5586: }
5587:
1.525 albertel 5588: span.LC_prior_string {
5589: font-family: monospace;
5590: white-space: pre;
5591: }
5592:
1.523 albertel 5593: table.LC_prior_option {
5594: width: 100%;
5595: border-collapse: collapse;
5596: }
1.795 www 5597:
5598: table.LC_prior_rank,
5599: table.LC_prior_match {
1.528 albertel 5600: border-collapse: collapse;
5601: }
1.795 www 5602:
1.528 albertel 5603: table.LC_prior_option tr td,
5604: table.LC_prior_rank tr td,
5605: table.LC_prior_match tr td {
1.524 albertel 5606: border: 1px solid #000000;
1.515 albertel 5607: }
5608:
1.855 bisitz 5609: .LC_nobreak {
1.544 albertel 5610: white-space: nowrap;
1.519 raeburn 5611: }
5612:
1.576 raeburn 5613: span.LC_cusr_emph {
5614: font-style: italic;
5615: }
5616:
1.633 raeburn 5617: span.LC_cusr_subheading {
5618: font-weight: normal;
5619: font-size: 85%;
5620: }
5621:
1.545 albertel 5622: table.LC_docs_documents {
5623: background: #BBBBBB;
1.803 bisitz 5624: border-width: 0;
1.545 albertel 5625: border-collapse: collapse;
5626: }
1.795 www 5627:
1.777 tempelho 5628: table.LC_docs_documents td.LC_docs_document {
1.779 bisitz 5629: border: 2px solid black;
5630: padding: 4px;
1.777 tempelho 5631: }
1.795 www 5632:
1.861 bisitz 5633: div.LC_docs_entry_move {
1.859 bisitz 5634: border: 1px solid #BBBBBB;
1.545 albertel 5635: background: #DDDDDD;
1.861 bisitz 5636: width: 22px;
1.859 bisitz 5637: padding: 1px;
5638: margin: 0;
1.545 albertel 5639: }
5640:
1.861 bisitz 5641: table.LC_data_table tr > td.LC_docs_entry_commands,
5642: table.LC_data_table tr > td.LC_docs_entry_parameter {
1.545 albertel 5643: background: #DDDDDD;
5644: font-size: x-small;
5645: }
1.795 www 5646:
1.861 bisitz 5647: .LC_docs_entry_parameter {
5648: white-space: nowrap;
5649: }
5650:
1.544 albertel 5651: .LC_docs_copy {
1.545 albertel 5652: color: #000099;
1.544 albertel 5653: }
1.795 www 5654:
1.544 albertel 5655: .LC_docs_cut {
1.545 albertel 5656: color: #550044;
1.544 albertel 5657: }
1.795 www 5658:
1.544 albertel 5659: .LC_docs_rename {
1.545 albertel 5660: color: #009900;
1.544 albertel 5661: }
1.795 www 5662:
1.544 albertel 5663: .LC_docs_remove {
1.545 albertel 5664: color: #990000;
5665: }
5666:
1.547 albertel 5667: .LC_docs_reinit_warn,
5668: .LC_docs_ext_edit {
5669: font-size: x-small;
5670: }
5671:
1.545 albertel 5672: table.LC_docs_adddocs td,
5673: table.LC_docs_adddocs th {
5674: border: 1px solid #BBBBBB;
5675: padding: 4px;
5676: background: #DDDDDD;
1.543 albertel 5677: }
5678:
1.584 albertel 5679: table.LC_sty_begin {
5680: background: #BBFFBB;
5681: }
1.795 www 5682:
1.584 albertel 5683: table.LC_sty_end {
5684: background: #FFBBBB;
5685: }
5686:
1.589 raeburn 5687: table.LC_double_column {
1.803 bisitz 5688: border-width: 0;
1.589 raeburn 5689: border-collapse: collapse;
5690: width: 100%;
5691: padding: 2px;
5692: }
5693:
5694: table.LC_double_column tr td.LC_left_col {
1.590 raeburn 5695: top: 2px;
1.589 raeburn 5696: left: 2px;
5697: width: 47%;
5698: vertical-align: top;
5699: }
5700:
5701: table.LC_double_column tr td.LC_right_col {
5702: top: 2px;
1.779 bisitz 5703: right: 2px;
1.589 raeburn 5704: width: 47%;
5705: vertical-align: top;
5706: }
5707:
1.591 raeburn 5708: div.LC_left_float {
5709: float: left;
5710: padding-right: 5%;
1.597 albertel 5711: padding-bottom: 4px;
1.591 raeburn 5712: }
5713:
5714: div.LC_clear_float_header {
1.597 albertel 5715: padding-bottom: 2px;
1.591 raeburn 5716: }
5717:
5718: div.LC_clear_float_footer {
1.597 albertel 5719: padding-top: 10px;
1.591 raeburn 5720: clear: both;
5721: }
5722:
1.597 albertel 5723: div.LC_grade_show_user {
5724: margin-top: 20px;
5725: border: 1px solid black;
5726: }
1.795 www 5727:
1.597 albertel 5728: div.LC_grade_user_name {
5729: background: #DDDDEE;
5730: border-bottom: 1px solid black;
1.705 tempelho 5731: font-weight: bold;
5732: font-size: large;
1.597 albertel 5733: }
1.795 www 5734:
1.597 albertel 5735: div.LC_grade_show_user_odd_row div.LC_grade_user_name {
5736: background: #DDEEDD;
5737: }
5738:
5739: div.LC_grade_show_problem,
5740: div.LC_grade_submissions,
5741: div.LC_grade_message_center,
5742: div.LC_grade_info_links,
5743: div.LC_grade_assign {
5744: margin: 5px;
5745: width: 99%;
5746: background: #FFFFFF;
5747: }
1.795 www 5748:
1.597 albertel 5749: div.LC_grade_show_problem_header,
5750: div.LC_grade_submissions_header,
5751: div.LC_grade_message_center_header,
5752: div.LC_grade_assign_header {
1.705 tempelho 5753: font-weight: bold;
5754: font-size: large;
1.597 albertel 5755: }
1.795 www 5756:
1.597 albertel 5757: div.LC_grade_show_problem_problem,
5758: div.LC_grade_submissions_body,
5759: div.LC_grade_message_center_body,
5760: div.LC_grade_assign_body {
5761: border: 1px solid black;
5762: width: 99%;
5763: background: #FFFFFF;
5764: }
1.795 www 5765:
1.598 albertel 5766: span.LC_grade_check_note {
1.705 tempelho 5767: font-weight: normal;
5768: font-size: medium;
1.598 albertel 5769: display: inline;
5770: position: absolute;
5771: right: 1em;
5772: }
1.597 albertel 5773:
1.613 albertel 5774: table.LC_scantron_action {
5775: width: 100%;
5776: }
1.795 www 5777:
1.613 albertel 5778: table.LC_scantron_action tr th {
1.698 harmsja 5779: font-weight:bold;
5780: font-style:normal;
1.613 albertel 5781: }
1.795 www 5782:
1.779 bisitz 5783: .LC_edit_problem_header,
1.614 albertel 5784: div.LC_edit_problem_footer {
1.705 tempelho 5785: font-weight: normal;
5786: font-size: medium;
1.602 albertel 5787: margin: 2px;
1.600 albertel 5788: }
1.795 www 5789:
1.600 albertel 5790: div.LC_edit_problem_header,
1.602 albertel 5791: div.LC_edit_problem_header div,
1.614 albertel 5792: div.LC_edit_problem_footer,
5793: div.LC_edit_problem_footer div,
1.602 albertel 5794: div.LC_edit_problem_editxml_header,
5795: div.LC_edit_problem_editxml_header div {
1.600 albertel 5796: margin-top: 5px;
5797: }
1.795 www 5798:
1.600 albertel 5799: div.LC_edit_problem_header_title {
1.705 tempelho 5800: font-weight: bold;
5801: font-size: larger;
1.602 albertel 5802: background: $tabbg;
5803: padding: 3px;
5804: }
1.795 www 5805:
1.602 albertel 5806: table.LC_edit_problem_header_title {
1.705 tempelho 5807: font-size: larger;
5808: font-weight: bold;
1.602 albertel 5809: width: 100%;
5810: border-color: $pgbg;
5811: border-style: solid;
5812: border-width: $border;
1.600 albertel 5813: background: $tabbg;
1.602 albertel 5814: border-collapse: collapse;
1.803 bisitz 5815: padding: 0;
1.602 albertel 5816: }
5817:
5818: div.LC_edit_problem_discards {
5819: float: left;
5820: padding-bottom: 5px;
5821: }
1.795 www 5822:
1.602 albertel 5823: div.LC_edit_problem_saves {
5824: float: right;
5825: padding-bottom: 5px;
1.600 albertel 5826: }
1.795 www 5827:
1.679 riegler 5828: img.stift{
1.803 bisitz 5829: border-width: 0;
5830: vertical-align: middle;
1.677 riegler 5831: }
1.680 riegler 5832:
1.681 riegler 5833: table#LC_mainmenu{
5834: margin-top:10px;
5835: width:80%;
5836: }
5837:
1.680 riegler 5838: table#LC_mainmenu td.LC_mainmenu_col_fieldset{
5839: vertical-align: top;
5840: width: 45%;
5841: }
1.795 www 5842:
1.779 bisitz 5843: .LC_mainmenu_fieldset_category {
5844: color: $font;
5845: background: $pgbg;
5846: font-size: small;
5847: font-weight: bold;
1.777 tempelho 5848: }
1.795 www 5849:
1.716 raeburn 5850: div.LC_createcourse {
5851: margin: 10px 10px 10px 10px;
5852: }
5853:
1.693 droeschl 5854: /* ---- Remove when done ----
5855: # The following styles is part of the redesign of LON-CAPA and are
5856: # subject to change during this project.
5857: # Don't rely on their current functionality as they might be
5858: # changed or removed.
5859: # --------------------------*/
5860:
1.698 harmsja 5861: a:hover,
1.897 wenzelju 5862: ol.LC_primary_menu a:hover,
1.721 harmsja 5863: ol#LC_MenuBreadcrumbs a:hover,
5864: ol#LC_PathBreadcrumbs a:hover,
1.897 wenzelju 5865: ul#LC_secondary_menu a:hover,
1.721 harmsja 5866: .LC_FormSectionClearButton input:hover
1.795 www 5867: ul.LC_TabContent li:hover a {
1.698 harmsja 5868: color:#BF2317;
1.904 droeschl 5869: text-decoration:none;
1.693 droeschl 5870: }
5871:
1.779 bisitz 5872: h1 {
1.813 bisitz 5873: padding: 0;
1.693 droeschl 5874: line-height:130%;
5875: }
1.698 harmsja 5876:
1.795 www 5877: h2,h3,h4,h5,h6 {
1.803 bisitz 5878: margin: 5px 0 5px 0;
5879: padding: 0;
1.721 harmsja 5880: line-height:130%;
1.693 droeschl 5881: }
1.795 www 5882:
5883: .LC_hcell {
1.698 harmsja 5884: padding:3px 15px 3px 15px;
1.803 bisitz 5885: margin: 0;
1.703 harmsja 5886: background-color:$tabbg;
1.801 tempelho 5887: color:$fontmenu;
1.779 bisitz 5888: border-bottom:solid 1px $lg_border_color;
1.693 droeschl 5889: }
1.795 www 5890:
1.840 bisitz 5891: .LC_Box > .LC_hcell {
1.847 tempelho 5892: margin: 0 -10px 10px -10px;
1.835 bisitz 5893: }
5894:
1.721 harmsja 5895: .LC_noBorder {
1.803 bisitz 5896: border: 0;
1.698 harmsja 5897: }
1.693 droeschl 5898:
1.761 tempelho 5899: .LC_Right {
5900: float: right;
1.803 bisitz 5901: margin: 0;
5902: padding: 0;
1.761 tempelho 5903: }
5904:
1.721 harmsja 5905: .LC_FormSectionClearButton input {
1.779 bisitz 5906: background-color:transparent;
1.803 bisitz 5907: border: none;
1.698 harmsja 5908: cursor:pointer;
5909: text-decoration:underline;
1.693 droeschl 5910: }
1.763 bisitz 5911:
5912: .LC_help_open_topic {
5913: color: #FFFFFF;
5914: background-color: #EEEEFF;
5915: margin: 1px;
5916: padding: 4px;
5917: border: 1px solid #000033;
5918: white-space: nowrap;
1.783 amueller 5919: /* vertical-align: middle; */
1.759 neumanie 5920: }
1.693 droeschl 5921:
1.698 harmsja 5922: dl,ul,div,fieldset {
1.803 bisitz 5923: margin: 10px 10px 10px 0;
1.806 bisitz 5924: /* overflow: hidden; */
1.693 droeschl 5925: }
1.795 www 5926:
1.838 bisitz 5927: fieldset > legend {
5928: font-weight: bold;
5929: padding: 0 5px 0 5px;
5930: }
5931:
1.813 bisitz 5932: #LC_nav_bar {
1.807 droeschl 5933: float: left;
1.852 droeschl 5934: margin: 0.2em 0 0 0;
1.807 droeschl 5935: }
5936:
1.813 bisitz 5937: #LC_nav_bar em{
1.807 droeschl 5938: font-weight: bold;
5939: font-style: normal;
5940: }
5941:
1.897 wenzelju 5942: ol.LC_primary_menu {
1.807 droeschl 5943: float: right;
1.852 droeschl 5944: margin: 0.2em 0 0 0;
1.807 droeschl 5945: }
5946:
1.852 droeschl 5947: ol#LC_PathBreadcrumbs {
1.803 bisitz 5948: margin: 0;
1.693 droeschl 5949: }
5950:
1.897 wenzelju 5951: ol.LC_primary_menu li {
1.693 droeschl 5952: display: inline;
1.803 bisitz 5953: padding: 5px 5px 0 10px;
1.693 droeschl 5954: vertical-align: top;
5955: }
5956:
1.897 wenzelju 5957: ol.LC_primary_menu li img {
1.693 droeschl 5958: vertical-align: bottom;
5959: }
5960:
1.897 wenzelju 5961: ol.LC_primary_menu a {
1.693 droeschl 5962: font-size: 90%;
5963: color: RGB(80, 80, 80);
5964: text-decoration: none;
5965: }
1.795 www 5966:
1.897 wenzelju 5967: ul#LC_secondary_menu {
1.807 droeschl 5968: clear: both;
1.808 droeschl 5969: color: $fontmenu;
5970: background: $tabbg;
5971: list-style: none;
5972: padding: 0;
5973: margin: 0;
5974: width: 100%;
5975: }
5976:
1.897 wenzelju 5977: ul#LC_secondary_menu li {
1.808 droeschl 5978: font-weight: bold;
5979: line-height: 1.8em;
5980: padding: 0 0.8em;
5981: border-right: 1px solid black;
5982: display: inline;
5983: vertical-align: middle;
1.807 droeschl 5984: }
5985:
1.847 tempelho 5986: ul.LC_TabContent {
1.721 harmsja 5987: display:block;
1.847 tempelho 5988: background: $sidebg;
1.858 bisitz 5989: border-bottom: solid 1px $lg_border_color;
1.721 harmsja 5990: list-style:none;
1.870 tempelho 5991: margin: 0 -10px;
1.803 bisitz 5992: padding: 0;
1.693 droeschl 5993: }
5994:
1.795 www 5995: ul.LC_TabContent li,
5996: ul.LC_TabContentBigger li {
1.741 harmsja 5997: float:left;
5998: }
1.795 www 5999:
1.897 wenzelju 6000: ul#LC_secondary_menu li a {
1.808 droeschl 6001: color: $fontmenu;
1.693 droeschl 6002: text-decoration: none;
6003: }
1.795 www 6004:
1.721 harmsja 6005: ul.LC_TabContent {
1.847 tempelho 6006: min-height:1.5em;
1.721 harmsja 6007: }
1.795 www 6008:
6009: ul.LC_TabContent li {
1.741 harmsja 6010: vertical-align:middle;
1.803 bisitz 6011: padding: 0 10px 0 10px;
1.745 ehlerst 6012: background-color:$tabbg;
6013: border-bottom:solid 1px $lg_border_color;
1.721 harmsja 6014: }
1.795 www 6015:
1.847 tempelho 6016: ul.LC_TabContent .right {
6017: float:right;
6018: }
6019:
1.795 www 6020: ul.LC_TabContent li a, ul.LC_TabContent li {
1.721 harmsja 6021: color:rgb(47,47,47);
6022: text-decoration:none;
6023: font-size:95%;
6024: font-weight:bold;
1.761 tempelho 6025: padding-right: 16px;
1.721 harmsja 6026: }
1.795 www 6027:
6028: ul.LC_TabContent li:hover, ul.LC_TabContent li.active {
1.761 tempelho 6029: background:#FFFFFF url(/adm/lonIcons/open.gif) no-repeat scroll right center;
1.841 tempelho 6030: border-bottom:solid 2px #FFFFFF;
1.761 tempelho 6031: padding-right: 16px;
1.744 ehlerst 6032: }
1.795 www 6033:
1.870 tempelho 6034: #maincoursedoc {
6035: clear:both;
6036: }
6037:
6038: ul.LC_TabContentBigger {
6039: display:block;
6040: list-style:none;
6041: padding: 0;
6042: }
6043:
1.795 www 6044: ul.LC_TabContentBigger li {
1.870 tempelho 6045: vertical-align:bottom;
6046: height: 30px;
6047: font-size:110%;
6048: font-weight:bold;
6049: color: #737373;
1.841 tempelho 6050: }
6051:
1.870 tempelho 6052:
6053: ul.LC_TabContentBigger li a {
6054: background:url('/adm/lonIcons/tabbgleft.gif') left bottom no-repeat;
6055: height: 30px;
6056: line-height: 30px;
6057: text-align: center;
6058: display: block;
6059: text-decoration: none;
1.741 harmsja 6060: }
1.795 www 6061:
1.870 tempelho 6062: ul.LC_TabContentBigger li:hover a,
6063: ul.LC_TabContentBigger li.active a {
6064: background:url('/adm/lonIcons/tabbgleft.gif') left top no-repeat;
1.857 tempelho 6065: color:$font;
1.870 tempelho 6066: text-decoration: underline;
1.744 ehlerst 6067: }
1.795 www 6068:
1.870 tempelho 6069:
6070: ul.LC_TabContentBigger li b {
6071: background: url('/adm/lonIcons/tabbgright.gif') no-repeat right bottom;
6072: display: block;
6073: float: left;
6074: padding: 0 30px;
6075: }
6076:
6077: ul.LC_TabContentBigger li:hover b,
6078: ul.LC_TabContentBigger li.active b {
6079: background:url('/adm/lonIcons/tabbgright.gif') right top no-repeat;
6080: color:$font;
6081: border-bottom: 1px solid #FFFFFF;
1.741 harmsja 6082: }
1.693 droeschl 6083:
1.870 tempelho 6084:
1.862 bisitz 6085: ul.LC_CourseBreadcrumbs {
6086: background: $sidebg;
6087: line-height: 32px;
6088: padding-left: 10px;
6089: margin: 0 0 10px 0;
6090: list-style-position: inside;
6091:
6092: }
6093:
1.795 www 6094: ol#LC_MenuBreadcrumbs,
1.862 bisitz 6095: ol#LC_PathBreadcrumbs {
1.693 droeschl 6096: padding-left: 10px;
1.819 tempelho 6097: margin: 0;
1.693 droeschl 6098: list-style-position: inside;
1.904 droeschl 6099: /* SD working here
6100: white-space: nowrap; */
1.693 droeschl 6101: }
6102:
1.795 www 6103: ol#LC_MenuBreadcrumbs li,
6104: ol#LC_PathBreadcrumbs li,
1.862 bisitz 6105: ul.LC_CourseBreadcrumbs li {
1.842 droeschl 6106: display: inline;
6107: white-space: nowrap;
1.904 droeschl 6108: /* SD working here
6109: white-space: normal; */
1.693 droeschl 6110: }
6111:
1.823 bisitz 6112: ol#LC_MenuBreadcrumbs li a,
1.862 bisitz 6113: ul.LC_CourseBreadcrumbs li a {
1.693 droeschl 6114: text-decoration: none;
6115: font-size:90%;
6116: }
1.795 www 6117:
6118: ol#LC_PathBreadcrumbs li a {
1.698 harmsja 6119: text-decoration:none;
6120: font-size:100%;
6121: font-weight:bold;
1.693 droeschl 6122: }
1.795 www 6123:
1.840 bisitz 6124: .LC_Box {
1.835 bisitz 6125: border: solid 1px $lg_border_color;
6126: padding: 0 10px 10px 10px;
1.746 neumanie 6127: }
1.795 www 6128:
6129: .LC_AboutMe_Image {
1.747 neumanie 6130: float:left;
6131: margin-right:10px;
6132: }
1.795 www 6133:
6134: .LC_Clear_AboutMe_Image {
1.747 neumanie 6135: clear:left;
6136: }
1.795 www 6137:
1.721 harmsja 6138: dl.LC_ListStyleClean dt {
1.693 droeschl 6139: padding-right: 5px;
6140: display: table-header-group;
6141: }
6142:
1.721 harmsja 6143: dl.LC_ListStyleClean dd {
1.693 droeschl 6144: display: table-row;
6145: }
6146:
1.721 harmsja 6147: .LC_ListStyleClean,
6148: .LC_ListStyleSimple,
6149: .LC_ListStyleNormal,
1.777 tempelho 6150: .LC_ListStyle_Border,
1.795 www 6151: .LC_ListStyleSpecial {
1.693 droeschl 6152: /*display:block; */
6153: list-style-position: inside;
6154: list-style-type: none;
6155: overflow: hidden;
1.803 bisitz 6156: padding: 0;
1.693 droeschl 6157: }
6158:
1.721 harmsja 6159: .LC_ListStyleSimple li,
6160: .LC_ListStyleSimple dd,
6161: .LC_ListStyleNormal li,
6162: .LC_ListStyleNormal dd,
6163: .LC_ListStyleSpecial li,
1.795 www 6164: .LC_ListStyleSpecial dd {
1.803 bisitz 6165: margin: 0;
1.693 droeschl 6166: padding: 5px 5px 5px 10px;
6167: clear: both;
6168: }
6169:
1.721 harmsja 6170: .LC_ListStyleClean li,
6171: .LC_ListStyleClean dd {
1.803 bisitz 6172: padding-top: 0;
6173: padding-bottom: 0;
1.693 droeschl 6174: }
6175:
1.721 harmsja 6176: .LC_ListStyleSimple dd,
1.795 www 6177: .LC_ListStyleSimple li {
1.698 harmsja 6178: border-bottom: solid 1px $lg_border_color;
1.693 droeschl 6179: }
6180:
1.721 harmsja 6181: .LC_ListStyleSpecial li,
6182: .LC_ListStyleSpecial dd {
1.693 droeschl 6183: list-style-type: none;
6184: background-color: RGB(220, 220, 220);
6185: margin-bottom: 4px;
6186: }
6187:
1.721 harmsja 6188: table.LC_SimpleTable {
1.698 harmsja 6189: margin:5px;
6190: border:solid 1px $lg_border_color;
1.795 www 6191: }
1.693 droeschl 6192:
1.721 harmsja 6193: table.LC_SimpleTable tr {
1.803 bisitz 6194: padding: 0;
1.698 harmsja 6195: border:solid 1px $lg_border_color;
1.693 droeschl 6196: }
1.795 www 6197:
6198: table.LC_SimpleTable thead {
1.698 harmsja 6199: background:rgb(220,220,220);
1.693 droeschl 6200: }
6201:
1.721 harmsja 6202: div.LC_columnSection {
1.693 droeschl 6203: display: block;
6204: clear: both;
6205: overflow: hidden;
1.803 bisitz 6206: margin: 0;
1.693 droeschl 6207: }
6208:
1.721 harmsja 6209: div.LC_columnSection>* {
1.693 droeschl 6210: float: left;
1.803 bisitz 6211: margin: 10px 20px 10px 0;
1.747 neumanie 6212: overflow:hidden;
1.693 droeschl 6213: }
1.721 harmsja 6214:
1.694 tempelho 6215: .LC_loginpage_container {
6216: text-align:left;
6217: margin : 0 auto;
1.785 tempelho 6218: width:90%;
1.694 tempelho 6219: padding: 10px;
6220: height: auto;
1.712 muellerd 6221: background-color:#FFFFFF;
1.694 tempelho 6222: border:1px solid #CCCCCC;
6223: }
6224:
6225:
6226: .LC_loginpage_loginContainer {
6227: float:left;
1.712 muellerd 6228: width: 182px;
1.785 tempelho 6229: padding: 2px;
1.712 muellerd 6230: border:1px solid #CCCCCC;
6231: background-color:$loginbg;
1.694 tempelho 6232: }
6233:
1.795 www 6234: .LC_loginpage_loginContainer h2 {
1.803 bisitz 6235: margin-top: 0;
1.712 muellerd 6236: display:block;
6237: background:$bgcol;
6238: color:$textcol;
6239: padding-left:5px;
6240: }
1.785 tempelho 6241:
1.694 tempelho 6242: .LC_loginpage_loginInfo {
6243: float:left;
1.785 tempelho 6244: width:182px;
1.694 tempelho 6245: border:1px solid #CCCCCC;
1.785 tempelho 6246: padding:2px;
1.712 muellerd 6247: }
6248:
1.694 tempelho 6249: .LC_loginpage_space {
1.754 droeschl 6250: clear: both;
6251: margin-bottom: 20px;
1.694 tempelho 6252: border-bottom: 1px solid #CCCCCC;
6253: }
6254:
1.785 tempelho 6255: .LC_loginpage_floatLeft {
6256: float: left;
6257: width: 200px;
6258: margin: 0;
6259: }
6260:
1.795 www 6261: table em {
1.754 droeschl 6262: font-weight: bold;
6263: font-style: normal;
1.748 schulted 6264: }
1.795 www 6265:
1.779 bisitz 6266: table.LC_tableBrowseRes,
1.795 www 6267: table.LC_tableOfContent {
1.769 schulted 6268: border:none;
1.858 bisitz 6269: border-spacing: 1px;
1.754 droeschl 6270: padding: 3px;
6271: background-color: #FFFFFF;
6272: font-size: 90%;
1.753 droeschl 6273: }
1.789 droeschl 6274:
6275: table.LC_tableOfContent{
6276: border-collapse: collapse;
6277: }
6278:
1.771 droeschl 6279: table.LC_tableBrowseRes a,
1.768 schulted 6280: table.LC_tableOfContent a {
1.771 droeschl 6281: background-color: transparent;
1.753 droeschl 6282: text-decoration: none;
6283: }
6284:
1.771 droeschl 6285: table.LC_tableBrowseRes tr.LC_trOdd,
1.768 schulted 6286: table.LC_tableOfContent tr.LC_trOdd{
1.754 droeschl 6287: background-color: #EEEEEE;
1.753 droeschl 6288: }
6289:
1.795 www 6290: table.LC_tableOfContent img {
1.753 droeschl 6291: border: none;
6292: height: 1.3em;
6293: vertical-align: text-bottom;
6294: margin-right: 0.3em;
6295: }
1.757 schulted 6296:
1.795 www 6297: a#LC_content_toolbar_firsthomework {
1.774 ehlerst 6298: background-image:url(/res/adm/pages/open-first-problem.gif);
6299: }
6300:
1.795 www 6301: a#LC_content_toolbar_launchnav {
1.774 ehlerst 6302: background-image:url(/res/adm/pages/start-navigation.gif);
6303: }
6304:
1.795 www 6305: a#LC_content_toolbar_closenav {
1.774 ehlerst 6306: background-image:url(/res/adm/pages/close-navigation.gif);
6307: }
6308:
1.795 www 6309: a#LC_content_toolbar_everything {
1.774 ehlerst 6310: background-image:url(/res/adm/pages/show-all.gif);
6311: }
6312:
1.795 www 6313: a#LC_content_toolbar_uncompleted {
1.774 ehlerst 6314: background-image:url(/res/adm/pages/show-incomplete-problems.gif);
6315: }
6316:
1.795 www 6317: #LC_content_toolbar_clearbubbles {
1.774 ehlerst 6318: background-image:url(/res/adm/pages/mark-discussionentries-read.gif);
6319: }
6320:
1.795 www 6321: a#LC_content_toolbar_changefolder {
1.757 schulted 6322: background : url(/res/adm/pages/close-all-folders.gif) top center ;
6323: }
6324:
1.795 www 6325: a#LC_content_toolbar_changefolder_toggled {
1.757 schulted 6326: background-image:url(/res/adm/pages/open-all-folders.gif);
6327: }
6328:
1.795 www 6329: ul#LC_toolbar li a:hover {
1.757 schulted 6330: background-position: bottom center;
6331: }
6332:
1.795 www 6333: ul#LC_toolbar {
1.803 bisitz 6334: padding: 0;
1.757 schulted 6335: margin: 2px;
6336: list-style:none;
6337: position:relative;
6338: background-color:white;
6339: }
6340:
1.795 www 6341: ul#LC_toolbar li {
1.757 schulted 6342: border:1px solid white;
1.803 bisitz 6343: padding: 0;
1.757 schulted 6344: margin: 0;
1.795 www 6345: float: left;
1.767 droeschl 6346: display:inline;
1.757 schulted 6347: vertical-align:middle;
1.795 www 6348: }
1.757 schulted 6349:
1.783 amueller 6350:
1.795 www 6351: a.LC_toolbarItem {
1.767 droeschl 6352: display:block;
1.803 bisitz 6353: padding: 0;
6354: margin: 0;
1.757 schulted 6355: height: 32px;
6356: width: 32px;
1.779 bisitz 6357: color:white;
1.803 bisitz 6358: border: none;
1.757 schulted 6359: background-repeat:no-repeat;
6360: background-color:transparent;
6361: }
6362:
1.843 bisitz 6363: ul.LC_funclist li {
1.782 bisitz 6364: float: left;
6365: white-space: nowrap;
6366: height: 35px; /* at least as high as heighest list item */
1.803 bisitz 6367: margin: 0 15px 15px 10px;
1.782 bisitz 6368: }
6369:
1.757 schulted 6370:
1.343 albertel 6371: END
6372: }
6373:
1.306 albertel 6374: =pod
6375:
6376: =item * &headtag()
6377:
6378: Returns a uniform footer for LON-CAPA web pages.
6379:
1.307 albertel 6380: Inputs: $title - optional title for the head
6381: $head_extra - optional extra HTML to put inside the <head>
1.315 albertel 6382: $args - optional arguments
1.319 albertel 6383: force_register - if is true call registerurl so the remote is
6384: informed
1.415 albertel 6385: redirect -> array ref of
6386: 1- seconds before redirect occurs
6387: 2- url to redirect to
6388: 3- whether the side effect should occur
1.315 albertel 6389: (side effect of setting
6390: $env{'internal.head.redirect'} to the url
6391: redirected too)
1.352 albertel 6392: domain -> force to color decorate a page for a specific
6393: domain
6394: function -> force usage of a specific rolish color scheme
6395: bgcolor -> override the default page bgcolor
1.460 albertel 6396: no_auto_mt_title
6397: -> prevent &mt()ing the title arg
1.464 albertel 6398:
1.306 albertel 6399: =cut
6400:
6401: sub headtag {
1.313 albertel 6402: my ($title,$head_extra,$args) = @_;
1.306 albertel 6403:
1.363 albertel 6404: my $function = $args->{'function'} || &get_users_function();
6405: my $domain = $args->{'domain'} || &determinedomain();
6406: my $bgcolor = $args->{'bgcolor'} || &designparm($function.'.pgbg',$domain);
1.418 albertel 6407: my $url = join(':',$env{'user.name'},$env{'user.domain'},
1.458 albertel 6408: $Apache::lonnet::perlvar{'lonVersion'},
1.531 albertel 6409: #time(),
1.418 albertel 6410: $env{'environment.color.timestamp'},
1.363 albertel 6411: $function,$domain,$bgcolor);
6412:
1.369 www 6413: $url = '/adm/css/'.&escape($url).'.css';
1.363 albertel 6414:
1.308 albertel 6415: my $result =
6416: '<head>'.
1.461 albertel 6417: &font_settings();
1.319 albertel 6418:
1.461 albertel 6419: if (!$args->{'frameset'}) {
6420: $result .= &Apache::lonhtmlcommon::htmlareaheaders();
6421: }
1.319 albertel 6422: if ($args->{'force_register'}) {
6423: $result .= &Apache::lonmenu::registerurl(1);
6424: }
1.436 albertel 6425: if (!$args->{'no_nav_bar'}
6426: && !$args->{'only_body'}
6427: && !$args->{'frameset'}) {
6428: $result .= &help_menu_js();
6429: }
1.319 albertel 6430:
1.314 albertel 6431: if (ref($args->{'redirect'})) {
1.414 albertel 6432: my ($time,$url,$inhibit_continue) = @{$args->{'redirect'}};
1.315 albertel 6433: $url = &Apache::lonenc::check_encrypt($url);
1.414 albertel 6434: if (!$inhibit_continue) {
6435: $env{'internal.head.redirect'} = $url;
6436: }
1.313 albertel 6437: $result.=<<ADDMETA
6438: <meta http-equiv="pragma" content="no-cache" />
1.344 albertel 6439: <meta http-equiv="Refresh" content="$time; url=$url" />
1.313 albertel 6440: ADDMETA
6441: }
1.306 albertel 6442: if (!defined($title)) {
6443: $title = 'The LearningOnline Network with CAPA';
6444: }
1.460 albertel 6445: if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); }
6446: $result .= '<title> LON-CAPA '.$title.'</title>'
1.414 albertel 6447: .'<link rel="stylesheet" type="text/css" href="'.$url.'" />'
6448: .$head_extra;
1.306 albertel 6449: return $result;
6450: }
6451:
6452: =pod
6453:
1.340 albertel 6454: =item * &font_settings()
6455:
6456: Returns neccessary <meta> to set the proper encoding
6457:
6458: Inputs: none
6459:
6460: =cut
6461:
6462: sub font_settings {
6463: my $headerstring='';
1.647 www 6464: if (!$env{'browser.mathml'} && $env{'browser.unicode'}) {
1.340 albertel 6465: $headerstring.=
6466: '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
6467: }
6468: return $headerstring;
6469: }
6470:
1.341 albertel 6471: =pod
6472:
6473: =item * &xml_begin()
6474:
6475: Returns the needed doctype and <html>
6476:
6477: Inputs: none
6478:
6479: =cut
6480:
6481: sub xml_begin {
6482: my $output='';
6483:
1.592 albertel 6484: if ($env{'internal.start_page'}==1) {
6485: &Apache::lonhtmlcommon::init_htmlareafields();
6486: }
1.342 albertel 6487:
1.341 albertel 6488: if ($env{'browser.mathml'}) {
6489: $output='<?xml version="1.0"?>'
6490: #.'<?xml-stylesheet type="text/css" href="/adm/MathML/mathml.css"?>'."\n"
6491: # .'<!DOCTYPE html SYSTEM "/adm/MathML/mathml.dtd" '
6492:
6493: # .'<!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">] >'
6494: .'<!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">'
6495: .'<html xmlns:math="http://www.w3.org/1998/Math/MathML" '
6496: .'xmlns="http://www.w3.org/1999/xhtml">';
6497: } else {
1.849 bisitz 6498: $output='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
6499: .'<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';
1.341 albertel 6500: }
6501: return $output;
6502: }
1.340 albertel 6503:
6504: =pod
6505:
1.306 albertel 6506: =item * &endheadtag()
6507:
6508: Returns a uniform </head> for LON-CAPA web pages.
6509:
6510: Inputs: none
6511:
6512: =cut
6513:
6514: sub endheadtag {
6515: return '</head>';
6516: }
6517:
6518: =pod
6519:
6520: =item * &head()
6521:
6522: Returns a uniform complete <head>..</head> section for LON-CAPA web pages.
6523:
1.648 raeburn 6524: Inputs:
6525:
6526: =over 4
6527:
6528: $title - optional title for the page
6529:
6530: $head_extra - optional extra HTML to put inside the <head>
6531:
6532: =back
1.405 albertel 6533:
1.306 albertel 6534: =cut
6535:
6536: sub head {
1.325 albertel 6537: my ($title,$head_extra,$args) = @_;
6538: return &headtag($title,$head_extra,$args).&endheadtag();
1.306 albertel 6539: }
6540:
6541: =pod
6542:
6543: =item * &start_page()
6544:
6545: Returns a complete <html> .. <body> section for LON-CAPA web pages.
6546:
1.648 raeburn 6547: Inputs:
6548:
6549: =over 4
6550:
6551: $title - optional title for the page
6552:
6553: $head_extra - optional extra HTML to incude inside the <head>
6554:
6555: $args - additional optional args supported are:
6556:
6557: =over 8
6558:
6559: only_body -> is true will set &bodytag() onlybodytag
1.317 albertel 6560: arg on
1.814 bisitz 6561: no_nav_bar -> is true will set &bodytag() no_nav_bar arg on
1.648 raeburn 6562: add_entries -> additional attributes to add to the <body>
6563: domain -> force to color decorate a page for a
1.317 albertel 6564: specific domain
1.648 raeburn 6565: function -> force usage of a specific rolish color
1.317 albertel 6566: scheme
1.648 raeburn 6567: redirect -> see &headtag()
6568: bgcolor -> override the default page bg color
6569: js_ready -> return a string ready for being used in
1.317 albertel 6570: a javascript writeln
1.648 raeburn 6571: html_encode -> return a string ready for being used in
1.320 albertel 6572: a html attribute
1.648 raeburn 6573: force_register -> if is true will turn on the &bodytag()
1.317 albertel 6574: $forcereg arg
1.648 raeburn 6575: frameset -> if true will start with a <frameset>
1.330 albertel 6576: rather than <body>
1.648 raeburn 6577: skip_phases -> hash ref of
1.338 albertel 6578: head -> skip the <html><head> generation
6579: body -> skip all <body> generation
1.648 raeburn 6580: no_inline_link -> if true and in remote mode, don't show the
1.361 albertel 6581: 'Switch To Inline Menu' link
1.648 raeburn 6582: no_auto_mt_title -> prevent &mt()ing the title arg
6583: inherit_jsmath -> when creating popup window in a page,
6584: should it have jsmath forced on by the
6585: current page
1.867 kalberla 6586: bread_crumbs -> Array containing breadcrumbs
6587: bread_crumbs_components -> if exists show it as headline else show only the breadcrumbs
1.361 albertel 6588:
1.648 raeburn 6589: =back
1.460 albertel 6590:
1.648 raeburn 6591: =back
1.562 albertel 6592:
1.306 albertel 6593: =cut
6594:
6595: sub start_page {
1.309 albertel 6596: my ($title,$head_extra,$args) = @_;
1.318 albertel 6597: #&Apache::lonnet::logthis("start_page ".join(':',caller(0)));
1.313 albertel 6598: my %head_args;
1.352 albertel 6599: foreach my $arg ('redirect','force_register','domain','function',
1.460 albertel 6600: 'bgcolor','frameset','no_nav_bar','only_body',
6601: 'no_auto_mt_title') {
1.319 albertel 6602: if (defined($args->{$arg})) {
1.324 raeburn 6603: $head_args{$arg} = $args->{$arg};
1.319 albertel 6604: }
1.313 albertel 6605: }
1.319 albertel 6606:
1.315 albertel 6607: $env{'internal.start_page'}++;
1.338 albertel 6608: my $result;
6609: if (! exists($args->{'skip_phases'}{'head'}) ) {
6610: $result.=
1.341 albertel 6611: &xml_begin().
1.338 albertel 6612: &headtag($title,$head_extra,\%head_args).&endheadtag();
6613: }
6614:
6615: if (! exists($args->{'skip_phases'}{'body'}) ) {
6616: if ($args->{'frameset'}) {
6617: my $attr_string = &make_attr_string($args->{'force_register'},
6618: $args->{'add_entries'});
6619: $result .= "\n<frameset $attr_string>\n";
1.831 bisitz 6620: } else {
6621: $result .=
6622: &bodytag($title,
6623: $args->{'function'}, $args->{'add_entries'},
6624: $args->{'only_body'}, $args->{'domain'},
6625: $args->{'force_register'}, $args->{'no_nav_bar'},
6626: $args->{'bgcolor'}, $args->{'no_inline_link'},
6627: $args);
6628: }
1.330 albertel 6629: }
1.338 albertel 6630:
1.315 albertel 6631: if ($args->{'js_ready'}) {
1.713 kaisler 6632: $result = &js_ready($result);
1.315 albertel 6633: }
1.320 albertel 6634: if ($args->{'html_encode'}) {
1.713 kaisler 6635: $result = &html_encode($result);
6636: }
6637:
1.813 bisitz 6638: # Preparation for new and consistent functionlist at top of screen
6639: # if ($args->{'functionlist'}) {
6640: # $result .= &build_functionlist();
6641: #}
6642:
6643: # Don't add anything more if only_body wanted
6644: return $result if $args->{'only_body'};
6645:
6646: #Breadcrumbs
1.758 kaisler 6647: if (exists($args->{'bread_crumbs'}) or exists($args->{'bread_crumbs_component'})) {
6648: &Apache::lonhtmlcommon::clear_breadcrumbs();
6649: #if any br links exists, add them to the breadcrumbs
6650: if (exists($args->{'bread_crumbs'}) and ref($args->{'bread_crumbs'}) eq 'ARRAY') {
6651: foreach my $crumb (@{$args->{'bread_crumbs'}}){
6652: &Apache::lonhtmlcommon::add_breadcrumb($crumb);
6653: }
6654: }
6655:
6656: #if bread_crumbs_component exists show it as headline else show only the breadcrumbs
6657: if(exists($args->{'bread_crumbs_component'})){
6658: $result .= &Apache::lonhtmlcommon::breadcrumbs($args->{'bread_crumbs_component'});
6659: }else{
6660: $result .= &Apache::lonhtmlcommon::breadcrumbs();
6661: }
1.320 albertel 6662: }
1.315 albertel 6663: return $result;
1.306 albertel 6664: }
6665:
1.330 albertel 6666:
1.306 albertel 6667: =pod
6668:
6669: =item * &head()
6670:
6671: Returns a complete </body></html> section for LON-CAPA web pages.
6672:
1.315 albertel 6673: Inputs: $args - additional optional args supported are:
6674: js_ready -> return a string ready for being used in
6675: a javascript writeln
1.320 albertel 6676: html_encode -> return a string ready for being used in
6677: a html attribute
1.330 albertel 6678: frameset -> if true will start with a <frameset>
6679: rather than <body>
1.493 albertel 6680: dicsussion -> if true will get discussion from
6681: lonxml::xmlend
6682: (you can pass the target and parser arguments
6683: through optional 'target' and 'parser' args
6684: to this routine)
1.306 albertel 6685:
6686: =cut
6687:
6688: sub end_page {
1.315 albertel 6689: my ($args) = @_;
6690: $env{'internal.end_page'}++;
1.330 albertel 6691: my $result;
1.335 albertel 6692: if ($args->{'discussion'}) {
6693: my ($target,$parser);
6694: if (ref($args->{'discussion'})) {
6695: ($target,$parser) =($args->{'discussion'}{'target'},
6696: $args->{'discussion'}{'parser'});
6697: }
6698: $result .= &Apache::lonxml::xmlend($target,$parser);
6699: }
6700:
1.330 albertel 6701: if ($args->{'frameset'}) {
6702: $result .= '</frameset>';
6703: } else {
1.635 raeburn 6704: $result .= &endbodytag($args);
1.330 albertel 6705: }
6706: $result .= "\n</html>";
6707:
1.315 albertel 6708: if ($args->{'js_ready'}) {
1.317 albertel 6709: $result = &js_ready($result);
1.315 albertel 6710: }
1.335 albertel 6711:
1.320 albertel 6712: if ($args->{'html_encode'}) {
6713: $result = &html_encode($result);
6714: }
1.335 albertel 6715:
1.315 albertel 6716: return $result;
6717: }
6718:
1.320 albertel 6719: sub html_encode {
6720: my ($result) = @_;
6721:
1.322 albertel 6722: $result = &HTML::Entities::encode($result,'<>&"');
1.320 albertel 6723:
6724: return $result;
6725: }
1.317 albertel 6726: sub js_ready {
6727: my ($result) = @_;
6728:
1.323 albertel 6729: $result =~ s/[\n\r]/ /xmsg;
6730: $result =~ s/\\/\\\\/xmsg;
6731: $result =~ s/'/\\'/xmsg;
1.372 albertel 6732: $result =~ s{</}{<\\/}xmsg;
1.317 albertel 6733:
6734: return $result;
6735: }
6736:
1.315 albertel 6737: sub validate_page {
6738: if ( exists($env{'internal.start_page'})
1.316 albertel 6739: && $env{'internal.start_page'} > 1) {
6740: &Apache::lonnet::logthis('start_page called multiple times '.
1.318 albertel 6741: $env{'internal.start_page'}.' '.
1.316 albertel 6742: $ENV{'request.filename'});
1.315 albertel 6743: }
6744: if ( exists($env{'internal.end_page'})
1.316 albertel 6745: && $env{'internal.end_page'} > 1) {
6746: &Apache::lonnet::logthis('end_page called multiple times '.
1.318 albertel 6747: $env{'internal.end_page'}.' '.
1.316 albertel 6748: $env{'request.filename'});
1.315 albertel 6749: }
6750: if ( exists($env{'internal.start_page'})
6751: && ! exists($env{'internal.end_page'})) {
1.316 albertel 6752: &Apache::lonnet::logthis('start_page called without end_page '.
6753: $env{'request.filename'});
1.315 albertel 6754: }
6755: if ( ! exists($env{'internal.start_page'})
6756: && exists($env{'internal.end_page'})) {
1.316 albertel 6757: &Apache::lonnet::logthis('end_page called without start_page'.
6758: $env{'request.filename'});
1.315 albertel 6759: }
1.306 albertel 6760: }
1.315 albertel 6761:
1.318 albertel 6762: sub simple_error_page {
6763: my ($r,$title,$msg) = @_;
6764: my $page =
6765: &Apache::loncommon::start_page($title).
6766: &mt($msg).
6767: &Apache::loncommon::end_page();
6768: if (ref($r)) {
6769: $r->print($page);
1.327 albertel 6770: return;
1.318 albertel 6771: }
6772: return $page;
6773: }
1.347 albertel 6774:
6775: {
1.610 albertel 6776: my @row_count;
1.347 albertel 6777: sub start_data_table {
1.422 albertel 6778: my ($add_class) = @_;
6779: my $css_class = (join(' ','LC_data_table',$add_class));
1.610 albertel 6780: unshift(@row_count,0);
1.422 albertel 6781: return '<table class="'.$css_class.'">'."\n";
1.347 albertel 6782: }
6783:
6784: sub end_data_table {
1.610 albertel 6785: shift(@row_count);
1.389 albertel 6786: return '</table>'."\n";;
1.347 albertel 6787: }
6788:
6789: sub start_data_table_row {
1.422 albertel 6790: my ($add_class) = @_;
1.610 albertel 6791: $row_count[0]++;
6792: my $css_class = ($row_count[0] % 2)?'LC_odd_row':'LC_even_row';
1.900 bisitz 6793: $css_class = (join(' ',$css_class,$add_class)) unless ($add_class eq '');
1.422 albertel 6794: return '<tr class="'.$css_class.'">'."\n";;
1.347 albertel 6795: }
1.471 banghart 6796:
6797: sub continue_data_table_row {
6798: my ($add_class) = @_;
1.610 albertel 6799: my $css_class = ($row_count[0] % 2)?'LC_odd_row':'LC_even_row';
1.900 bisitz 6800: $css_class = (join(' ',$css_class,$add_class)) unless ($add_class eq '');;
1.471 banghart 6801: return '<tr class="'.$css_class.'">'."\n";;
6802: }
1.347 albertel 6803:
6804: sub end_data_table_row {
1.389 albertel 6805: return '</tr>'."\n";;
1.347 albertel 6806: }
1.367 www 6807:
1.421 albertel 6808: sub start_data_table_empty_row {
1.707 bisitz 6809: # $row_count[0]++;
1.421 albertel 6810: return '<tr class="LC_empty_row" >'."\n";;
6811: }
6812:
6813: sub end_data_table_empty_row {
6814: return '</tr>'."\n";;
6815: }
6816:
1.367 www 6817: sub start_data_table_header_row {
1.389 albertel 6818: return '<tr class="LC_header_row">'."\n";;
1.367 www 6819: }
6820:
6821: sub end_data_table_header_row {
1.389 albertel 6822: return '</tr>'."\n";;
1.367 www 6823: }
1.890 droeschl 6824:
6825: sub data_table_caption {
6826: my $caption = shift;
6827: return "<caption class=\"LC_caption\">$caption</caption>";
6828: }
1.347 albertel 6829: }
6830:
1.548 albertel 6831: =pod
6832:
6833: =item * &inhibit_menu_check($arg)
6834:
6835: Checks for a inhibitmenu state and generates output to preserve it
6836:
6837: Inputs: $arg - can be any of
6838: - undef - in which case the return value is a string
6839: to add into arguments list of a uri
6840: - 'input' - in which case the return value is a HTML
6841: <form> <input> field of type hidden to
6842: preserve the value
6843: - a url - in which case the return value is the url with
6844: the neccesary cgi args added to preserve the
6845: inhibitmenu state
6846: - a ref to a url - no return value, but the string is
6847: updated to include the neccessary cgi
6848: args to preserve the inhibitmenu state
6849:
6850: =cut
6851:
6852: sub inhibit_menu_check {
6853: my ($arg) = @_;
6854: &get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['inhibitmenu']);
6855: if ($arg eq 'input') {
6856: if ($env{'form.inhibitmenu'}) {
6857: return '<input type="hidden" name="inhibitmenu" value="'.$env{'form.inhibitmenu'}.'" />';
6858: } else {
6859: return
6860: }
6861: }
6862: if ($env{'form.inhibitmenu'}) {
6863: if (ref($arg)) {
6864: $$arg .= '?inhibitmenu='.$env{'form.inhibitmenu'};
6865: } elsif ($arg eq '') {
6866: $arg .= 'inhibitmenu='.$env{'form.inhibitmenu'};
6867: } else {
6868: $arg .= '?inhibitmenu='.$env{'form.inhibitmenu'};
6869: }
6870: }
6871: if (!ref($arg)) {
6872: return $arg;
6873: }
6874: }
6875:
1.251 albertel 6876: ###############################################
1.182 matthew 6877:
6878: =pod
6879:
1.549 albertel 6880: =back
6881:
6882: =head1 User Information Routines
6883:
6884: =over 4
6885:
1.405 albertel 6886: =item * &get_users_function()
1.182 matthew 6887:
6888: Used by &bodytag to determine the current users primary role.
6889: Returns either 'student','coordinator','admin', or 'author'.
6890:
6891: =cut
6892:
6893: ###############################################
6894: sub get_users_function {
1.815 tempelho 6895: my $function = 'norole';
1.818 tempelho 6896: if ($env{'request.role'}=~/^(st)/) {
6897: $function='student';
6898: }
1.258 albertel 6899: if ($env{'request.role'}=~/^(cc|in|ta|ep)/) {
1.182 matthew 6900: $function='coordinator';
6901: }
1.258 albertel 6902: if ($env{'request.role'}=~/^(su|dc|ad|li)/) {
1.182 matthew 6903: $function='admin';
6904: }
1.826 bisitz 6905: if (($env{'request.role'}=~/^(au|ca|aa)/) ||
1.182 matthew 6906: ($ENV{'REQUEST_URI'}=~/^(\/priv|\~)/)) {
6907: $function='author';
6908: }
6909: return $function;
1.54 www 6910: }
1.99 www 6911:
6912: ###############################################
6913:
1.233 raeburn 6914: =pod
6915:
1.821 raeburn 6916: =item * &show_course()
6917:
6918: Used by lonmenu.pm and lonroles.pm to determine whether to use the word
6919: 'Courses' or 'Roles' in inline navigation and on screen displaying user's roles.
6920:
6921: Inputs:
6922: None
6923:
6924: Outputs:
6925: Scalar: 1 if 'Course' to be used, 0 otherwise.
6926:
6927: =cut
6928:
6929: ###############################################
6930: sub show_course {
6931: my $course = !$env{'user.adv'};
6932: if (!$env{'user.adv'}) {
6933: foreach my $env (keys(%env)) {
6934: next if ($env !~ m/^user\.priv\./);
6935: if ($env !~ m/^user\.priv\.(?:st|cm)/) {
6936: $course = 0;
6937: last;
6938: }
6939: }
6940: }
6941: return $course;
6942: }
6943:
6944: ###############################################
6945:
6946: =pod
6947:
1.542 raeburn 6948: =item * &check_user_status()
1.274 raeburn 6949:
6950: Determines current status of supplied role for a
6951: specific user. Roles can be active, previous or future.
6952:
6953: Inputs:
6954: user's domain, user's username, course's domain,
1.375 raeburn 6955: course's number, optional section ID.
1.274 raeburn 6956:
6957: Outputs:
6958: role status: active, previous or future.
6959:
6960: =cut
6961:
6962: sub check_user_status {
1.412 raeburn 6963: my ($udom,$uname,$cdom,$crs,$role,$sec) = @_;
1.274 raeburn 6964: my %userinfo = &Apache::lonnet::dump('roles',$udom,$uname);
6965: my @uroles = keys %userinfo;
6966: my $srchstr;
6967: my $active_chk = 'none';
1.412 raeburn 6968: my $now = time;
1.274 raeburn 6969: if (@uroles > 0) {
1.412 raeburn 6970: if (($role eq 'cc') || ($sec eq '') || (!defined($sec))) {
1.274 raeburn 6971: $srchstr = '/'.$cdom.'/'.$crs.'_'.$role;
6972: } else {
1.412 raeburn 6973: $srchstr = '/'.$cdom.'/'.$crs.'/'.$sec.'_'.$role;
6974: }
6975: if (grep/^\Q$srchstr\E$/,@uroles) {
1.274 raeburn 6976: my $role_end = 0;
6977: my $role_start = 0;
6978: $active_chk = 'active';
1.412 raeburn 6979: if ($userinfo{$srchstr} =~ m/^\Q$role\E_(\d+)/) {
6980: $role_end = $1;
6981: if ($userinfo{$srchstr} =~ m/^\Q$role\E_\Q$role_end\E_(\d+)$/) {
6982: $role_start = $1;
1.274 raeburn 6983: }
6984: }
6985: if ($role_start > 0) {
1.412 raeburn 6986: if ($now < $role_start) {
1.274 raeburn 6987: $active_chk = 'future';
6988: }
6989: }
6990: if ($role_end > 0) {
1.412 raeburn 6991: if ($now > $role_end) {
1.274 raeburn 6992: $active_chk = 'previous';
6993: }
6994: }
6995: }
6996: }
6997: return $active_chk;
6998: }
6999:
7000: ###############################################
7001:
7002: =pod
7003:
1.405 albertel 7004: =item * &get_sections()
1.233 raeburn 7005:
7006: Determines all the sections for a course including
7007: sections with students and sections containing other roles.
1.419 raeburn 7008: Incoming parameters:
7009:
7010: 1. domain
7011: 2. course number
7012: 3. reference to array containing roles for which sections should
7013: be gathered (optional).
7014: 4. reference to array containing status types for which sections
7015: should be gathered (optional).
7016:
7017: If the third argument is undefined, sections are gathered for any role.
7018: If the fourth argument is undefined, sections are gathered for any status.
7019: Permissible values are 'active' or 'future' or 'previous'.
1.233 raeburn 7020:
1.374 raeburn 7021: Returns section hash (keys are section IDs, values are
7022: number of users in each section), subject to the
1.419 raeburn 7023: optional roles filter, optional status filter
1.233 raeburn 7024:
7025: =cut
7026:
7027: ###############################################
7028: sub get_sections {
1.419 raeburn 7029: my ($cdom,$cnum,$possible_roles,$possible_status) = @_;
1.366 albertel 7030: if (!defined($cdom) || !defined($cnum)) {
7031: my $cid = $env{'request.course.id'};
7032:
7033: return if (!defined($cid));
7034:
7035: $cdom = $env{'course.'.$cid.'.domain'};
7036: $cnum = $env{'course.'.$cid.'.num'};
7037: }
7038:
7039: my %sectioncount;
1.419 raeburn 7040: my $now = time;
1.240 albertel 7041:
1.366 albertel 7042: if (!defined($possible_roles) || (grep(/^st$/,@$possible_roles))) {
1.276 albertel 7043: my ($classlist) = &Apache::loncoursedata::get_classlist($cdom,$cnum);
1.240 albertel 7044: my $sec_index = &Apache::loncoursedata::CL_SECTION();
7045: my $status_index = &Apache::loncoursedata::CL_STATUS();
1.419 raeburn 7046: my $start_index = &Apache::loncoursedata::CL_START();
7047: my $end_index = &Apache::loncoursedata::CL_END();
7048: my $status;
1.366 albertel 7049: while (my ($student,$data) = each(%$classlist)) {
1.419 raeburn 7050: my ($section,$stu_status,$start,$end) = ($data->[$sec_index],
7051: $data->[$status_index],
7052: $data->[$start_index],
7053: $data->[$end_index]);
7054: if ($stu_status eq 'Active') {
7055: $status = 'active';
7056: } elsif ($end < $now) {
7057: $status = 'previous';
7058: } elsif ($start > $now) {
7059: $status = 'future';
7060: }
7061: if ($section ne '-1' && $section !~ /^\s*$/) {
7062: if ((!defined($possible_status)) || (($status ne '') &&
7063: (grep/^\Q$status\E$/,@{$possible_status}))) {
7064: $sectioncount{$section}++;
7065: }
1.240 albertel 7066: }
7067: }
7068: }
7069: my %courseroles = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
7070: foreach my $user (sort(keys(%courseroles))) {
7071: if ($user !~ /^(\w{2})/) { next; }
7072: my ($role) = ($user =~ /^(\w{2})/);
7073: if ($possible_roles && !(grep(/^$role$/,@$possible_roles))) { next; }
1.419 raeburn 7074: my ($section,$status);
1.240 albertel 7075: if ($role eq 'cr' &&
7076: $user =~ m-^$role/[^/]*/[^/]*/[^/]*:[^:]*:[^:]*:(\w+)-) {
7077: $section=$1;
7078: }
7079: if ($user =~ /^$role:[^:]*:[^:]*:(\w+)/) { $section=$1; }
7080: if (!defined($section) || $section eq '-1') { next; }
1.419 raeburn 7081: my ($end,$start) = ($courseroles{$user} =~ /^([^:]*):([^:]*)$/);
7082: if ($end == -1 && $start == -1) {
7083: next; #deleted role
7084: }
7085: if (!defined($possible_status)) {
7086: $sectioncount{$section}++;
7087: } else {
7088: if ((!$end || $end >= $now) && (!$start || $start <= $now)) {
7089: $status = 'active';
7090: } elsif ($end < $now) {
7091: $status = 'future';
7092: } elsif ($start > $now) {
7093: $status = 'previous';
7094: }
7095: if (($status ne '') && (grep/^\Q$status\E$/,@{$possible_status})) {
7096: $sectioncount{$section}++;
7097: }
7098: }
1.233 raeburn 7099: }
1.366 albertel 7100: return %sectioncount;
1.233 raeburn 7101: }
7102:
1.274 raeburn 7103: ###############################################
1.294 raeburn 7104:
7105: =pod
1.405 albertel 7106:
7107: =item * &get_course_users()
7108:
1.275 raeburn 7109: Retrieves usernames:domains for users in the specified course
7110: with specific role(s), and access status.
7111:
7112: Incoming parameters:
1.277 albertel 7113: 1. course domain
7114: 2. course number
7115: 3. access status: users must have - either active,
1.275 raeburn 7116: previous, future, or all.
1.277 albertel 7117: 4. reference to array of permissible roles
1.288 raeburn 7118: 5. reference to array of section restrictions (optional)
7119: 6. reference to results object (hash of hashes).
7120: 7. reference to optional userdata hash
1.609 raeburn 7121: 8. reference to optional statushash
1.630 raeburn 7122: 9. flag if privileged users (except those set to unhide in
7123: course settings) should be excluded
1.609 raeburn 7124: Keys of top level results hash are roles.
1.275 raeburn 7125: Keys of inner hashes are username:domain, with
7126: values set to access type.
1.288 raeburn 7127: Optional userdata hash returns an array with arguments in the
7128: same order as loncoursedata::get_classlist() for student data.
7129:
1.609 raeburn 7130: Optional statushash returns
7131:
1.288 raeburn 7132: Entries for end, start, section and status are blank because
7133: of the possibility of multiple values for non-student roles.
7134:
1.275 raeburn 7135: =cut
1.405 albertel 7136:
1.275 raeburn 7137: ###############################################
1.405 albertel 7138:
1.275 raeburn 7139: sub get_course_users {
1.630 raeburn 7140: my ($cdom,$cnum,$types,$roles,$sections,$users,$userdata,$statushash,$hidepriv) = @_;
1.288 raeburn 7141: my %idx = ();
1.419 raeburn 7142: my %seclists;
1.288 raeburn 7143:
7144: $idx{udom} = &Apache::loncoursedata::CL_SDOM();
7145: $idx{uname} = &Apache::loncoursedata::CL_SNAME();
7146: $idx{end} = &Apache::loncoursedata::CL_END();
7147: $idx{start} = &Apache::loncoursedata::CL_START();
7148: $idx{id} = &Apache::loncoursedata::CL_ID();
7149: $idx{section} = &Apache::loncoursedata::CL_SECTION();
7150: $idx{fullname} = &Apache::loncoursedata::CL_FULLNAME();
7151: $idx{status} = &Apache::loncoursedata::CL_STATUS();
7152:
1.290 albertel 7153: if (grep(/^st$/,@{$roles})) {
1.276 albertel 7154: my ($classlist,$keylist)=&Apache::loncoursedata::get_classlist($cdom,$cnum);
1.278 raeburn 7155: my $now = time;
1.277 albertel 7156: foreach my $student (keys(%{$classlist})) {
1.288 raeburn 7157: my $match = 0;
1.412 raeburn 7158: my $secmatch = 0;
1.419 raeburn 7159: my $section = $$classlist{$student}[$idx{section}];
1.609 raeburn 7160: my $status = $$classlist{$student}[$idx{status}];
1.419 raeburn 7161: if ($section eq '') {
7162: $section = 'none';
7163: }
1.291 albertel 7164: if ((ref($sections) eq 'ARRAY') && (@{$sections} > 0)) {
1.420 albertel 7165: if (grep(/^all$/,@{$sections})) {
1.412 raeburn 7166: $secmatch = 1;
7167: } elsif ($$classlist{$student}[$idx{section}] eq '') {
1.420 albertel 7168: if (grep(/^none$/,@{$sections})) {
1.412 raeburn 7169: $secmatch = 1;
7170: }
7171: } else {
1.419 raeburn 7172: if (grep(/^\Q$section\E$/,@{$sections})) {
1.412 raeburn 7173: $secmatch = 1;
7174: }
1.290 albertel 7175: }
1.412 raeburn 7176: if (!$secmatch) {
7177: next;
7178: }
1.419 raeburn 7179: }
1.275 raeburn 7180: if (defined($$types{'active'})) {
1.288 raeburn 7181: if ($$classlist{$student}[$idx{status}] eq 'Active') {
1.275 raeburn 7182: push(@{$$users{st}{$student}},'active');
1.288 raeburn 7183: $match = 1;
1.275 raeburn 7184: }
7185: }
7186: if (defined($$types{'previous'})) {
1.609 raeburn 7187: if ($$classlist{$student}[$idx{status}] eq 'Expired') {
1.275 raeburn 7188: push(@{$$users{st}{$student}},'previous');
1.288 raeburn 7189: $match = 1;
1.275 raeburn 7190: }
7191: }
7192: if (defined($$types{'future'})) {
1.609 raeburn 7193: if ($$classlist{$student}[$idx{status}] eq 'Future') {
1.275 raeburn 7194: push(@{$$users{st}{$student}},'future');
1.288 raeburn 7195: $match = 1;
1.275 raeburn 7196: }
7197: }
1.609 raeburn 7198: if ($match) {
7199: push(@{$seclists{$student}},$section);
7200: if (ref($userdata) eq 'HASH') {
7201: $$userdata{$student} = $$classlist{$student};
7202: }
7203: if (ref($statushash) eq 'HASH') {
7204: $statushash->{$student}{'st'}{$section} = $status;
7205: }
1.288 raeburn 7206: }
1.275 raeburn 7207: }
7208: }
1.412 raeburn 7209: if ((@{$roles} > 1) || ((@{$roles} == 1) && ($$roles[0] ne "st"))) {
1.439 raeburn 7210: my %coursepersonnel = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
7211: my $now = time;
1.609 raeburn 7212: my %displaystatus = ( previous => 'Expired',
7213: active => 'Active',
7214: future => 'Future',
7215: );
1.630 raeburn 7216: my %nothide;
7217: if ($hidepriv) {
7218: my %coursehash=&Apache::lonnet::coursedescription($cdom.'_'.$cnum);
7219: foreach my $user (split(/\s*\,\s*/,$coursehash{'nothideprivileged'})) {
7220: if ($user !~ /:/) {
7221: $nothide{join(':',split(/[\@]/,$user))}=1;
7222: } else {
7223: $nothide{$user} = 1;
7224: }
7225: }
7226: }
1.439 raeburn 7227: foreach my $person (sort(keys(%coursepersonnel))) {
1.288 raeburn 7228: my $match = 0;
1.412 raeburn 7229: my $secmatch = 0;
1.439 raeburn 7230: my $status;
1.412 raeburn 7231: my ($role,$user,$usec) = ($person =~ /^([^:]*):([^:]+:[^:]+):([^:]*)/);
1.275 raeburn 7232: $user =~ s/:$//;
1.439 raeburn 7233: my ($end,$start) = split(/:/,$coursepersonnel{$person});
7234: if ($end == -1 || $start == -1) {
7235: next;
7236: }
7237: if (($role) && ((grep(/^\Q$role\E$/,@{$roles})) ||
7238: (grep(/^cr$/,@{$roles}) && $role =~ /^cr\//))) {
1.412 raeburn 7239: my ($uname,$udom) = split(/:/,$user);
7240: if ((ref($sections) eq 'ARRAY') && (@{$sections} > 0)) {
1.420 albertel 7241: if (grep(/^all$/,@{$sections})) {
1.412 raeburn 7242: $secmatch = 1;
7243: } elsif ($usec eq '') {
1.420 albertel 7244: if (grep(/^none$/,@{$sections})) {
1.412 raeburn 7245: $secmatch = 1;
7246: }
7247: } else {
7248: if (grep(/^\Q$usec\E$/,@{$sections})) {
7249: $secmatch = 1;
7250: }
7251: }
7252: if (!$secmatch) {
7253: next;
7254: }
1.288 raeburn 7255: }
1.419 raeburn 7256: if ($usec eq '') {
7257: $usec = 'none';
7258: }
1.275 raeburn 7259: if ($uname ne '' && $udom ne '') {
1.630 raeburn 7260: if ($hidepriv) {
7261: if ((&Apache::lonnet::privileged($uname,$udom)) &&
7262: (!$nothide{$uname.':'.$udom})) {
7263: next;
7264: }
7265: }
1.503 raeburn 7266: if ($end > 0 && $end < $now) {
1.439 raeburn 7267: $status = 'previous';
7268: } elsif ($start > $now) {
7269: $status = 'future';
7270: } else {
7271: $status = 'active';
7272: }
1.277 albertel 7273: foreach my $type (keys(%{$types})) {
1.275 raeburn 7274: if ($status eq $type) {
1.420 albertel 7275: if (!grep(/^\Q$type\E$/,@{$$users{$role}{$user}})) {
1.419 raeburn 7276: push(@{$$users{$role}{$user}},$type);
7277: }
1.288 raeburn 7278: $match = 1;
7279: }
7280: }
1.419 raeburn 7281: if (($match) && (ref($userdata) eq 'HASH')) {
7282: if (!exists($$userdata{$uname.':'.$udom})) {
7283: &get_user_info($udom,$uname,\%idx,$userdata);
7284: }
1.420 albertel 7285: if (!grep(/^\Q$usec\E$/,@{$seclists{$uname.':'.$udom}})) {
1.419 raeburn 7286: push(@{$seclists{$uname.':'.$udom}},$usec);
7287: }
1.609 raeburn 7288: if (ref($statushash) eq 'HASH') {
7289: $statushash->{$uname.':'.$udom}{$role}{$usec} = $displaystatus{$status};
7290: }
1.275 raeburn 7291: }
7292: }
7293: }
7294: }
1.290 albertel 7295: if (grep(/^ow$/,@{$roles})) {
1.279 raeburn 7296: if ((defined($cdom)) && (defined($cnum))) {
7297: my %csettings = &Apache::lonnet::get('environment',['internal.courseowner'],$cdom,$cnum);
7298: if ( defined($csettings{'internal.courseowner'}) ) {
7299: my $owner = $csettings{'internal.courseowner'};
1.609 raeburn 7300: next if ($owner eq '');
7301: my ($ownername,$ownerdom);
7302: if ($owner =~ /^([^:]+):([^:]+)$/) {
7303: $ownername = $1;
7304: $ownerdom = $2;
7305: } else {
7306: $ownername = $owner;
7307: $ownerdom = $cdom;
7308: $owner = $ownername.':'.$ownerdom;
1.439 raeburn 7309: }
7310: @{$$users{'ow'}{$owner}} = 'any';
1.290 albertel 7311: if (defined($userdata) &&
1.609 raeburn 7312: !exists($$userdata{$owner})) {
7313: &get_user_info($ownerdom,$ownername,\%idx,$userdata);
7314: if (!grep(/^none$/,@{$seclists{$owner}})) {
7315: push(@{$seclists{$owner}},'none');
7316: }
7317: if (ref($statushash) eq 'HASH') {
7318: $statushash->{$owner}{'ow'}{'none'} = 'Any';
1.419 raeburn 7319: }
1.290 albertel 7320: }
1.279 raeburn 7321: }
7322: }
7323: }
1.419 raeburn 7324: foreach my $user (keys(%seclists)) {
7325: @{$seclists{$user}} = (sort {$a <=> $b} @{$seclists{$user}});
7326: $$userdata{$user}[$idx{section}] = join(',',@{$seclists{$user}});
7327: }
1.275 raeburn 7328: }
7329: return;
7330: }
7331:
1.288 raeburn 7332: sub get_user_info {
7333: my ($udom,$uname,$idx,$userdata) = @_;
1.289 albertel 7334: $$userdata{$uname.':'.$udom}[$$idx{fullname}] =
7335: &plainname($uname,$udom,'lastname');
1.291 albertel 7336: $$userdata{$uname.':'.$udom}[$$idx{uname}] = $uname;
1.297 raeburn 7337: $$userdata{$uname.':'.$udom}[$$idx{udom}] = $udom;
1.609 raeburn 7338: my %idhash = &Apache::lonnet::idrget($udom,($uname));
7339: $$userdata{$uname.':'.$udom}[$$idx{id}] = $idhash{$uname};
1.288 raeburn 7340: return;
7341: }
1.275 raeburn 7342:
1.472 raeburn 7343: ###############################################
7344:
7345: =pod
7346:
7347: =item * &get_user_quota()
7348:
7349: Retrieves quota assigned for storage of portfolio files for a user
7350:
7351: Incoming parameters:
7352: 1. user's username
7353: 2. user's domain
7354:
7355: Returns:
1.536 raeburn 7356: 1. Disk quota (in Mb) assigned to student.
7357: 2. (Optional) Type of setting: custom or default
7358: (individually assigned or default for user's
7359: institutional status).
7360: 3. (Optional) - User's institutional status (e.g., faculty, staff
7361: or student - types as defined in localenroll::inst_usertypes
7362: for user's domain, which determines default quota for user.
7363: 4. (Optional) - Default quota which would apply to the user.
1.472 raeburn 7364:
7365: If a value has been stored in the user's environment,
1.536 raeburn 7366: it will return that, otherwise it returns the maximal default
7367: defined for the user's instituional status(es) in the domain.
1.472 raeburn 7368:
7369: =cut
7370:
7371: ###############################################
7372:
7373:
7374: sub get_user_quota {
7375: my ($uname,$udom) = @_;
1.536 raeburn 7376: my ($quota,$quotatype,$settingstatus,$defquota);
1.472 raeburn 7377: if (!defined($udom)) {
7378: $udom = $env{'user.domain'};
7379: }
7380: if (!defined($uname)) {
7381: $uname = $env{'user.name'};
7382: }
7383: if (($udom eq '' || $uname eq '') ||
7384: ($udom eq 'public') && ($uname eq 'public')) {
7385: $quota = 0;
1.536 raeburn 7386: $quotatype = 'default';
7387: $defquota = 0;
1.472 raeburn 7388: } else {
1.536 raeburn 7389: my $inststatus;
1.472 raeburn 7390: if ($udom eq $env{'user.domain'} && $uname eq $env{'user.name'}) {
7391: $quota = $env{'environment.portfolioquota'};
1.536 raeburn 7392: $inststatus = $env{'environment.inststatus'};
1.472 raeburn 7393: } else {
1.536 raeburn 7394: my %userenv =
7395: &Apache::lonnet::get('environment',['portfolioquota',
7396: 'inststatus'],$udom,$uname);
1.472 raeburn 7397: my ($tmp) = keys(%userenv);
7398: if ($tmp !~ /^(con_lost|error|no_such_host)/i) {
7399: $quota = $userenv{'portfolioquota'};
1.536 raeburn 7400: $inststatus = $userenv{'inststatus'};
1.472 raeburn 7401: } else {
7402: undef(%userenv);
7403: }
7404: }
1.536 raeburn 7405: ($defquota,$settingstatus) = &default_quota($udom,$inststatus);
1.472 raeburn 7406: if ($quota eq '') {
1.536 raeburn 7407: $quota = $defquota;
7408: $quotatype = 'default';
7409: } else {
7410: $quotatype = 'custom';
1.472 raeburn 7411: }
7412: }
1.536 raeburn 7413: if (wantarray) {
7414: return ($quota,$quotatype,$settingstatus,$defquota);
7415: } else {
7416: return $quota;
7417: }
1.472 raeburn 7418: }
7419:
7420: ###############################################
7421:
7422: =pod
7423:
7424: =item * &default_quota()
7425:
1.536 raeburn 7426: Retrieves default quota assigned for storage of user portfolio files,
7427: given an (optional) user's institutional status.
1.472 raeburn 7428:
7429: Incoming parameters:
7430: 1. domain
1.536 raeburn 7431: 2. (Optional) institutional status(es). This is a : separated list of
7432: status types (e.g., faculty, staff, student etc.)
7433: which apply to the user for whom the default is being retrieved.
7434: If the institutional status string in undefined, the domain
7435: default quota will be returned.
1.472 raeburn 7436:
7437: Returns:
7438: 1. Default disk quota (in Mb) for user portfolios in the domain.
1.536 raeburn 7439: 2. (Optional) institutional type which determined the value of the
7440: default quota.
1.472 raeburn 7441:
7442: If a value has been stored in the domain's configuration db,
7443: it will return that, otherwise it returns 20 (for backwards
7444: compatibility with domains which have not set up a configuration
7445: db file; the original statically defined portfolio quota was 20 Mb).
7446:
1.536 raeburn 7447: If the user's status includes multiple types (e.g., staff and student),
7448: the largest default quota which applies to the user determines the
7449: default quota returned.
7450:
1.780 raeburn 7451: =back
7452:
1.472 raeburn 7453: =cut
7454:
7455: ###############################################
7456:
7457:
7458: sub default_quota {
1.536 raeburn 7459: my ($udom,$inststatus) = @_;
7460: my ($defquota,$settingstatus);
7461: my %quotahash = &Apache::lonnet::get_dom('configuration',
1.622 raeburn 7462: ['quotas'],$udom);
7463: if (ref($quotahash{'quotas'}) eq 'HASH') {
1.536 raeburn 7464: if ($inststatus ne '') {
1.765 raeburn 7465: my @statuses = map { &unescape($_); } split(/:/,$inststatus);
1.536 raeburn 7466: foreach my $item (@statuses) {
1.711 raeburn 7467: if (ref($quotahash{'quotas'}{'defaultquota'}) eq 'HASH') {
7468: if ($quotahash{'quotas'}{'defaultquota'}{$item} ne '') {
7469: if ($defquota eq '') {
7470: $defquota = $quotahash{'quotas'}{'defaultquota'}{$item};
7471: $settingstatus = $item;
7472: } elsif ($quotahash{'quotas'}{'defaultquota'}{$item} > $defquota) {
7473: $defquota = $quotahash{'quotas'}{'defaultquota'}{$item};
7474: $settingstatus = $item;
7475: }
7476: }
7477: } else {
7478: if ($quotahash{'quotas'}{$item} ne '') {
7479: if ($defquota eq '') {
7480: $defquota = $quotahash{'quotas'}{$item};
7481: $settingstatus = $item;
7482: } elsif ($quotahash{'quotas'}{$item} > $defquota) {
7483: $defquota = $quotahash{'quotas'}{$item};
7484: $settingstatus = $item;
7485: }
1.536 raeburn 7486: }
7487: }
7488: }
7489: }
7490: if ($defquota eq '') {
1.711 raeburn 7491: if (ref($quotahash{'quotas'}{'defaultquota'}) eq 'HASH') {
7492: $defquota = $quotahash{'quotas'}{'defaultquota'}{'default'};
7493: } else {
7494: $defquota = $quotahash{'quotas'}{'default'};
7495: }
1.536 raeburn 7496: $settingstatus = 'default';
7497: }
7498: } else {
7499: $settingstatus = 'default';
7500: $defquota = 20;
7501: }
7502: if (wantarray) {
7503: return ($defquota,$settingstatus);
1.472 raeburn 7504: } else {
1.536 raeburn 7505: return $defquota;
1.472 raeburn 7506: }
7507: }
7508:
1.384 raeburn 7509: sub get_secgrprole_info {
7510: my ($cdom,$cnum,$needroles,$type) = @_;
7511: my %sections_count = &get_sections($cdom,$cnum);
7512: my @sections = (sort {$a <=> $b} keys(%sections_count));
7513: my %curr_groups = &Apache::longroup::coursegroups($cdom,$cnum);
7514: my @groups = sort(keys(%curr_groups));
7515: my $allroles = [];
7516: my $rolehash;
7517: my $accesshash = {
7518: active => 'Currently has access',
7519: future => 'Will have future access',
7520: previous => 'Previously had access',
7521: };
7522: if ($needroles) {
7523: $rolehash = {'all' => 'all'};
1.385 albertel 7524: my %user_roles = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
7525: if (&Apache::lonnet::error(%user_roles)) {
7526: undef(%user_roles);
7527: }
7528: foreach my $item (keys(%user_roles)) {
1.384 raeburn 7529: my ($role)=split(/\:/,$item,2);
7530: if ($role eq 'cr') { next; }
7531: if ($role =~ /^cr/) {
7532: $$rolehash{$role} = (split('/',$role))[3];
7533: } else {
7534: $$rolehash{$role} = &Apache::lonnet::plaintext($role,$type);
7535: }
7536: }
7537: foreach my $key (sort(keys(%{$rolehash}))) {
7538: push(@{$allroles},$key);
7539: }
7540: push (@{$allroles},'st');
7541: $$rolehash{'st'} = &Apache::lonnet::plaintext('st',$type);
7542: }
7543: return (\@sections,\@groups,$allroles,$rolehash,$accesshash);
7544: }
7545:
1.555 raeburn 7546: sub user_picker {
1.627 raeburn 7547: my ($dom,$srch,$forcenewuser,$caller,$cancreate,$usertype) = @_;
1.555 raeburn 7548: my $currdom = $dom;
7549: my %curr_selected = (
7550: srchin => 'dom',
1.580 raeburn 7551: srchby => 'lastname',
1.555 raeburn 7552: );
7553: my $srchterm;
1.625 raeburn 7554: if ((ref($srch) eq 'HASH') && ($env{'form.origform'} ne 'crtusername')) {
1.555 raeburn 7555: if ($srch->{'srchby'} ne '') {
7556: $curr_selected{'srchby'} = $srch->{'srchby'};
7557: }
7558: if ($srch->{'srchin'} ne '') {
7559: $curr_selected{'srchin'} = $srch->{'srchin'};
7560: }
7561: if ($srch->{'srchtype'} ne '') {
7562: $curr_selected{'srchtype'} = $srch->{'srchtype'};
7563: }
7564: if ($srch->{'srchdomain'} ne '') {
7565: $currdom = $srch->{'srchdomain'};
7566: }
7567: $srchterm = $srch->{'srchterm'};
7568: }
7569: my %lt=&Apache::lonlocal::texthash(
1.573 raeburn 7570: 'usr' => 'Search criteria',
1.563 raeburn 7571: 'doma' => 'Domain/institution to search',
1.558 albertel 7572: 'uname' => 'username',
7573: 'lastname' => 'last name',
1.555 raeburn 7574: 'lastfirst' => 'last name, first name',
1.558 albertel 7575: 'crs' => 'in this course',
1.576 raeburn 7576: 'dom' => 'in selected LON-CAPA domain',
1.558 albertel 7577: 'alc' => 'all LON-CAPA',
1.573 raeburn 7578: 'instd' => 'in institutional directory for selected domain',
1.558 albertel 7579: 'exact' => 'is',
7580: 'contains' => 'contains',
1.569 raeburn 7581: 'begins' => 'begins with',
1.571 raeburn 7582: 'youm' => "You must include some text to search for.",
7583: 'thte' => "The text you are searching for must contain at least two characters when using a 'begins' type search.",
7584: 'thet' => "The text you are searching for must contain at least three characters when using a 'contains' type search.",
7585: 'yomc' => "You must choose a domain when using an institutional directory search.",
7586: 'ymcd' => "You must choose a domain when using a domain search.",
7587: 'whus' => "When using searching by last,first you must include a comma as separator between last name and first name.",
7588: 'whse' => "When searching by last,first you must include at least one character in the first name.",
7589: 'thfo' => "The following need to be corrected before the search can be run:",
1.555 raeburn 7590: );
1.563 raeburn 7591: my $domform = &select_dom_form($currdom,'srchdomain',1,1);
7592: my $srchinsel = ' <select name="srchin">';
1.555 raeburn 7593:
7594: my @srchins = ('crs','dom','alc','instd');
7595:
7596: foreach my $option (@srchins) {
7597: # FIXME 'alc' option unavailable until
7598: # loncreateuser::print_user_query_page()
7599: # has been completed.
7600: next if ($option eq 'alc');
1.880 raeburn 7601: next if (($option eq 'crs') && ($env{'form.form'} eq 'requestcrs'));
1.555 raeburn 7602: next if ($option eq 'crs' && !$env{'request.course.id'});
1.563 raeburn 7603: if ($curr_selected{'srchin'} eq $option) {
7604: $srchinsel .= '
7605: <option value="'.$option.'" selected="selected">'.$lt{$option}.'</option>';
7606: } else {
7607: $srchinsel .= '
7608: <option value="'.$option.'">'.$lt{$option}.'</option>';
7609: }
1.555 raeburn 7610: }
1.563 raeburn 7611: $srchinsel .= "\n </select>\n";
1.555 raeburn 7612:
7613: my $srchbysel = ' <select name="srchby">';
1.580 raeburn 7614: foreach my $option ('lastname','lastfirst','uname') {
1.555 raeburn 7615: if ($curr_selected{'srchby'} eq $option) {
7616: $srchbysel .= '
7617: <option value="'.$option.'" selected="selected">'.$lt{$option}.'</option>';
7618: } else {
7619: $srchbysel .= '
7620: <option value="'.$option.'">'.$lt{$option}.'</option>';
7621: }
7622: }
7623: $srchbysel .= "\n </select>\n";
7624:
7625: my $srchtypesel = ' <select name="srchtype">';
1.580 raeburn 7626: foreach my $option ('begins','contains','exact') {
1.555 raeburn 7627: if ($curr_selected{'srchtype'} eq $option) {
7628: $srchtypesel .= '
7629: <option value="'.$option.'" selected="selected">'.$lt{$option}.'</option>';
7630: } else {
7631: $srchtypesel .= '
7632: <option value="'.$option.'">'.$lt{$option}.'</option>';
7633: }
7634: }
7635: $srchtypesel .= "\n </select>\n";
7636:
1.558 albertel 7637: my ($newuserscript,$new_user_create);
1.556 raeburn 7638:
7639: if ($forcenewuser) {
1.576 raeburn 7640: if (ref($srch) eq 'HASH') {
7641: if ($srch->{'srchby'} eq 'uname' && $srch->{'srchtype'} eq 'exact' && $srch->{'srchin'} eq 'dom' && $srch->{'srchdomain'} eq $env{'request.role.domain'}) {
1.627 raeburn 7642: if ($cancreate) {
7643: $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>';
7644: } else {
1.799 bisitz 7645: my $helplink = 'javascript:helpMenu('."'display'".')';
1.627 raeburn 7646: my %usertypetext = (
7647: official => 'institutional',
7648: unofficial => 'non-institutional',
7649: );
1.799 bisitz 7650: $new_user_create = '<p class="LC_warning">'
7651: .&mt("You are not authorized to create new $usertypetext{$usertype} users in this domain.")
7652: .' '
7653: .&mt('Please contact the [_1]helpdesk[_2] for assistance.'
7654: ,'<a href="'.$helplink.'">','</a>')
7655: .'</p><br />';
1.627 raeburn 7656: }
1.576 raeburn 7657: }
7658: }
7659:
1.556 raeburn 7660: $newuserscript = <<"ENDSCRIPT";
7661:
1.570 raeburn 7662: function setSearch(createnew,callingForm) {
1.556 raeburn 7663: if (createnew == 1) {
1.570 raeburn 7664: for (var i=0; i<callingForm.srchby.length; i++) {
7665: if (callingForm.srchby.options[i].value == 'uname') {
7666: callingForm.srchby.selectedIndex = i;
1.556 raeburn 7667: }
7668: }
1.570 raeburn 7669: for (var i=0; i<callingForm.srchin.length; i++) {
7670: if ( callingForm.srchin.options[i].value == 'dom') {
7671: callingForm.srchin.selectedIndex = i;
1.556 raeburn 7672: }
7673: }
1.570 raeburn 7674: for (var i=0; i<callingForm.srchtype.length; i++) {
7675: if (callingForm.srchtype.options[i].value == 'exact') {
7676: callingForm.srchtype.selectedIndex = i;
1.556 raeburn 7677: }
7678: }
1.570 raeburn 7679: for (var i=0; i<callingForm.srchdomain.length; i++) {
7680: if (callingForm.srchdomain.options[i].value == '$env{'request.role.domain'}') {
7681: callingForm.srchdomain.selectedIndex = i;
1.556 raeburn 7682: }
7683: }
7684: }
7685: }
7686: ENDSCRIPT
1.558 albertel 7687:
1.556 raeburn 7688: }
7689:
1.555 raeburn 7690: my $output = <<"END_BLOCK";
1.556 raeburn 7691: <script type="text/javascript">
1.824 bisitz 7692: // <![CDATA[
1.570 raeburn 7693: function validateEntry(callingForm) {
1.558 albertel 7694:
1.556 raeburn 7695: var checkok = 1;
1.558 albertel 7696: var srchin;
1.570 raeburn 7697: for (var i=0; i<callingForm.srchin.length; i++) {
7698: if ( callingForm.srchin[i].checked ) {
7699: srchin = callingForm.srchin[i].value;
1.558 albertel 7700: }
7701: }
7702:
1.570 raeburn 7703: var srchtype = callingForm.srchtype.options[callingForm.srchtype.selectedIndex].value;
7704: var srchby = callingForm.srchby.options[callingForm.srchby.selectedIndex].value;
7705: var srchdomain = callingForm.srchdomain.options[callingForm.srchdomain.selectedIndex].value;
7706: var srchterm = callingForm.srchterm.value;
7707: var srchin = callingForm.srchin.options[callingForm.srchin.selectedIndex].value;
1.556 raeburn 7708: var msg = "";
7709:
7710: if (srchterm == "") {
7711: checkok = 0;
1.571 raeburn 7712: msg += "$lt{'youm'}\\n";
1.556 raeburn 7713: }
7714:
1.569 raeburn 7715: if (srchtype== 'begins') {
7716: if (srchterm.length < 2) {
7717: checkok = 0;
1.571 raeburn 7718: msg += "$lt{'thte'}\\n";
1.569 raeburn 7719: }
7720: }
7721:
1.556 raeburn 7722: if (srchtype== 'contains') {
7723: if (srchterm.length < 3) {
7724: checkok = 0;
1.571 raeburn 7725: msg += "$lt{'thet'}\\n";
1.556 raeburn 7726: }
7727: }
7728: if (srchin == 'instd') {
7729: if (srchdomain == '') {
7730: checkok = 0;
1.571 raeburn 7731: msg += "$lt{'yomc'}\\n";
1.556 raeburn 7732: }
7733: }
7734: if (srchin == 'dom') {
7735: if (srchdomain == '') {
7736: checkok = 0;
1.571 raeburn 7737: msg += "$lt{'ymcd'}\\n";
1.556 raeburn 7738: }
7739: }
7740: if (srchby == 'lastfirst') {
7741: if (srchterm.indexOf(",") == -1) {
7742: checkok = 0;
1.571 raeburn 7743: msg += "$lt{'whus'}\\n";
1.556 raeburn 7744: }
7745: if (srchterm.indexOf(",") == srchterm.length -1) {
7746: checkok = 0;
1.571 raeburn 7747: msg += "$lt{'whse'}\\n";
1.556 raeburn 7748: }
7749: }
7750: if (checkok == 0) {
1.571 raeburn 7751: alert("$lt{'thfo'}\\n"+msg);
1.556 raeburn 7752: return;
7753: }
7754: if (checkok == 1) {
1.570 raeburn 7755: callingForm.submit();
1.556 raeburn 7756: }
7757: }
7758:
7759: $newuserscript
7760:
1.824 bisitz 7761: // ]]>
1.556 raeburn 7762: </script>
1.558 albertel 7763:
7764: $new_user_create
7765:
1.555 raeburn 7766: END_BLOCK
1.558 albertel 7767:
1.876 raeburn 7768: $output .= &Apache::lonhtmlcommon::start_pick_box().
7769: &Apache::lonhtmlcommon::row_title($lt{'doma'}).
7770: $domform.
7771: &Apache::lonhtmlcommon::row_closure().
7772: &Apache::lonhtmlcommon::row_title($lt{'usr'}).
7773: $srchbysel.
7774: $srchtypesel.
7775: '<input type="text" size="15" name="srchterm" value="'.$srchterm.'" />'.
7776: $srchinsel.
7777: &Apache::lonhtmlcommon::row_closure(1).
7778: &Apache::lonhtmlcommon::end_pick_box().
7779: '<br />';
1.555 raeburn 7780: return $output;
7781: }
7782:
1.612 raeburn 7783: sub user_rule_check {
1.615 raeburn 7784: my ($usershash,$checks,$alerts,$rulematch,$inst_results,$curr_rules,$got_rules) = @_;
1.612 raeburn 7785: my $response;
7786: if (ref($usershash) eq 'HASH') {
7787: foreach my $user (keys(%{$usershash})) {
7788: my ($uname,$udom) = split(/:/,$user);
7789: next if ($udom eq '' || $uname eq '');
1.615 raeburn 7790: my ($id,$newuser);
1.612 raeburn 7791: if (ref($usershash->{$user}) eq 'HASH') {
1.615 raeburn 7792: $newuser = $usershash->{$user}->{'newuser'};
1.612 raeburn 7793: $id = $usershash->{$user}->{'id'};
7794: }
7795: my $inst_response;
7796: if (ref($checks) eq 'HASH') {
7797: if (defined($checks->{'username'})) {
1.615 raeburn 7798: ($inst_response,%{$inst_results->{$user}}) =
1.612 raeburn 7799: &Apache::lonnet::get_instuser($udom,$uname);
7800: } elsif (defined($checks->{'id'})) {
1.615 raeburn 7801: ($inst_response,%{$inst_results->{$user}}) =
1.612 raeburn 7802: &Apache::lonnet::get_instuser($udom,undef,$id);
7803: }
1.615 raeburn 7804: } else {
7805: ($inst_response,%{$inst_results->{$user}}) =
7806: &Apache::lonnet::get_instuser($udom,$uname);
7807: return;
1.612 raeburn 7808: }
1.615 raeburn 7809: if (!$got_rules->{$udom}) {
1.612 raeburn 7810: my %domconfig = &Apache::lonnet::get_dom('configuration',
7811: ['usercreation'],$udom);
7812: if (ref($domconfig{'usercreation'}) eq 'HASH') {
1.615 raeburn 7813: foreach my $item ('username','id') {
1.612 raeburn 7814: if (ref($domconfig{'usercreation'}{$item.'_rule'}) eq 'ARRAY') {
7815: $$curr_rules{$udom}{$item} =
7816: $domconfig{'usercreation'}{$item.'_rule'};
1.585 raeburn 7817: }
7818: }
7819: }
1.615 raeburn 7820: $got_rules->{$udom} = 1;
1.585 raeburn 7821: }
1.612 raeburn 7822: foreach my $item (keys(%{$checks})) {
7823: if (ref($$curr_rules{$udom}) eq 'HASH') {
7824: if (ref($$curr_rules{$udom}{$item}) eq 'ARRAY') {
7825: if (@{$$curr_rules{$udom}{$item}} > 0) {
7826: my %rule_check = &Apache::lonnet::inst_rulecheck($udom,$uname,$id,$item,$$curr_rules{$udom}{$item});
7827: foreach my $rule (@{$$curr_rules{$udom}{$item}}) {
7828: if ($rule_check{$rule}) {
7829: $$rulematch{$user}{$item} = $rule;
7830: if ($inst_response eq 'ok') {
1.615 raeburn 7831: if (ref($inst_results) eq 'HASH') {
7832: if (ref($inst_results->{$user}) eq 'HASH') {
7833: if (keys(%{$inst_results->{$user}}) == 0) {
7834: $$alerts{$item}{$udom}{$uname} = 1;
7835: }
1.612 raeburn 7836: }
7837: }
1.615 raeburn 7838: }
7839: last;
1.585 raeburn 7840: }
7841: }
7842: }
7843: }
7844: }
7845: }
7846: }
7847: }
1.612 raeburn 7848: return;
7849: }
7850:
7851: sub user_rule_formats {
7852: my ($domain,$domdesc,$curr_rules,$check) = @_;
7853: my %text = (
7854: 'username' => 'Usernames',
7855: 'id' => 'IDs',
7856: );
7857: my $output;
7858: my ($rules,$ruleorder) = &Apache::lonnet::inst_userrules($domain,$check);
7859: if ((ref($rules) eq 'HASH') && (ref($ruleorder) eq 'ARRAY')) {
7860: if (@{$ruleorder} > 0) {
7861: $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>';
7862: foreach my $rule (@{$ruleorder}) {
7863: if (ref($curr_rules) eq 'ARRAY') {
7864: if (grep(/^\Q$rule\E$/,@{$curr_rules})) {
7865: if (ref($rules->{$rule}) eq 'HASH') {
7866: $output .= '<li>'.$rules->{$rule}{'name'}.': '.
7867: $rules->{$rule}{'desc'}.'</li>';
7868: }
7869: }
7870: }
7871: }
7872: $output .= '</ul>';
7873: }
7874: }
7875: return $output;
7876: }
7877:
7878: sub instrule_disallow_msg {
1.615 raeburn 7879: my ($checkitem,$domdesc,$count,$mode) = @_;
1.612 raeburn 7880: my $response;
7881: my %text = (
7882: item => 'username',
7883: items => 'usernames',
7884: match => 'matches',
7885: do => 'does',
7886: action => 'a username',
7887: one => 'one',
7888: );
7889: if ($count > 1) {
7890: $text{'item'} = 'usernames';
7891: $text{'match'} ='match';
7892: $text{'do'} = 'do';
7893: $text{'action'} = 'usernames',
7894: $text{'one'} = 'ones';
7895: }
7896: if ($checkitem eq 'id') {
7897: $text{'items'} = 'IDs';
7898: $text{'item'} = 'ID';
7899: $text{'action'} = 'an ID';
1.615 raeburn 7900: if ($count > 1) {
7901: $text{'item'} = 'IDs';
7902: $text{'action'} = 'IDs';
7903: }
1.612 raeburn 7904: }
1.674 bisitz 7905: $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 7906: if ($mode eq 'upload') {
7907: if ($checkitem eq 'username') {
7908: $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'}.");
7909: } elsif ($checkitem eq 'id') {
1.674 bisitz 7910: $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 7911: }
1.669 raeburn 7912: } elsif ($mode eq 'selfcreate') {
7913: if ($checkitem eq 'id') {
7914: $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.");
7915: }
1.615 raeburn 7916: } else {
7917: if ($checkitem eq 'username') {
7918: $response .= &mt("You must choose $text{'action'} with a different format -- $text{'one'} that will not conflict with 'official' institutional $text{'items'}.");
7919: } elsif ($checkitem eq 'id') {
7920: $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.");
7921: }
1.612 raeburn 7922: }
7923: return $response;
1.585 raeburn 7924: }
7925:
1.624 raeburn 7926: sub personal_data_fieldtitles {
7927: my %fieldtitles = &Apache::lonlocal::texthash (
7928: id => 'Student/Employee ID',
7929: permanentemail => 'E-mail address',
7930: lastname => 'Last Name',
7931: firstname => 'First Name',
7932: middlename => 'Middle Name',
7933: generation => 'Generation',
7934: gen => 'Generation',
1.765 raeburn 7935: inststatus => 'Affiliation',
1.624 raeburn 7936: );
7937: return %fieldtitles;
7938: }
7939:
1.642 raeburn 7940: sub sorted_inst_types {
7941: my ($dom) = @_;
7942: my ($usertypes,$order) = &Apache::lonnet::retrieve_inst_usertypes($dom);
7943: my $othertitle = &mt('All users');
7944: if ($env{'request.course.id'}) {
1.668 raeburn 7945: $othertitle = &mt('Any users');
1.642 raeburn 7946: }
7947: my @types;
7948: if (ref($order) eq 'ARRAY') {
7949: @types = @{$order};
7950: }
7951: if (@types == 0) {
7952: if (ref($usertypes) eq 'HASH') {
7953: @types = sort(keys(%{$usertypes}));
7954: }
7955: }
7956: if (keys(%{$usertypes}) > 0) {
7957: $othertitle = &mt('Other users');
7958: }
7959: return ($othertitle,$usertypes,\@types);
7960: }
7961:
1.645 raeburn 7962: sub get_institutional_codes {
7963: my ($settings,$allcourses,$LC_code) = @_;
7964: # Get complete list of course sections to update
7965: my @currsections = ();
7966: my @currxlists = ();
7967: my $coursecode = $$settings{'internal.coursecode'};
7968:
7969: if ($$settings{'internal.sectionnums'} ne '') {
7970: @currsections = split(/,/,$$settings{'internal.sectionnums'});
7971: }
7972:
7973: if ($$settings{'internal.crosslistings'} ne '') {
7974: @currxlists = split(/,/,$$settings{'internal.crosslistings'});
7975: }
7976:
7977: if (@currxlists > 0) {
7978: foreach (@currxlists) {
7979: if (m/^([^:]+):(\w*)$/) {
7980: unless (grep/^$1$/,@{$allcourses}) {
7981: push @{$allcourses},$1;
7982: $$LC_code{$1} = $2;
7983: }
7984: }
7985: }
7986: }
7987:
7988: if (@currsections > 0) {
7989: foreach (@currsections) {
7990: if (m/^(\w+):(\w*)$/) {
7991: my $sec = $coursecode.$1;
7992: my $lc_sec = $2;
7993: unless (grep/^$sec$/,@{$allcourses}) {
7994: push @{$allcourses},$sec;
7995: $$LC_code{$sec} = $lc_sec;
7996: }
7997: }
7998: }
7999: }
8000: return;
8001: }
8002:
1.112 bowersj2 8003: =pod
8004:
1.780 raeburn 8005: =head1 Slot Helpers
8006:
8007: =over 4
8008:
8009: =item * sorted_slots()
8010:
8011: Sorts an array of slot names in order of slot start time (earliest first).
8012:
8013: Inputs:
8014:
8015: =over 4
8016:
8017: slotsarr - Reference to array of unsorted slot names.
8018:
8019: slots - Reference to hash of hash, where outer hash keys are slot names.
8020:
1.549 albertel 8021: =back
8022:
1.780 raeburn 8023: Returns:
8024:
8025: =over 4
8026:
8027: sorted - An array of slot names sorted by the start time of the slot.
8028:
8029: =back
8030:
8031: =back
8032:
8033: =cut
8034:
8035:
8036: sub sorted_slots {
8037: my ($slotsarr,$slots) = @_;
8038: my @sorted;
8039: if ((ref($slotsarr) eq 'ARRAY') && (ref($slots) eq 'HASH')) {
8040: @sorted =
8041: sort {
8042: if (ref($slots->{$a}) && ref($slots->{$b})) {
8043: return $slots->{$a}{'starttime'} <=> $slots->{$b}{'starttime'}
8044: }
8045: if (ref($slots->{$a})) { return -1;}
8046: if (ref($slots->{$b})) { return 1;}
8047: return 0;
8048: } @{$slotsarr};
8049: }
8050: return @sorted;
8051: }
8052:
8053:
8054: =pod
8055:
1.549 albertel 8056: =head1 HTTP Helpers
8057:
8058: =over 4
8059:
1.648 raeburn 8060: =item * &get_unprocessed_cgi($query,$possible_names)
1.112 bowersj2 8061:
1.258 albertel 8062: Modify the %env hash to contain unprocessed CGI form parameters held in
1.112 bowersj2 8063: $query. The parameters listed in $possible_names (an array reference),
1.258 albertel 8064: will be set in $env{'form.name'} if they do not already exist.
1.112 bowersj2 8065:
8066: Typically called with $ENV{'QUERY_STRING'} as the first parameter.
8067: $possible_names is an ref to an array of form element names. As an example:
8068: get_unprocessed_cgi($ENV{'QUERY_STRING'},['uname','udom']);
1.258 albertel 8069: will result in $env{'form.uname'} and $env{'form.udom'} being set.
1.112 bowersj2 8070:
8071: =cut
1.1 albertel 8072:
1.6 albertel 8073: sub get_unprocessed_cgi {
1.25 albertel 8074: my ($query,$possible_names)= @_;
1.26 matthew 8075: # $Apache::lonxml::debug=1;
1.356 albertel 8076: foreach my $pair (split(/&/,$query)) {
8077: my ($name, $value) = split(/=/,$pair);
1.369 www 8078: $name = &unescape($name);
1.25 albertel 8079: if (!defined($possible_names) || (grep {$_ eq $name} @$possible_names)) {
8080: $value =~ tr/+/ /;
8081: $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
1.258 albertel 8082: unless (defined($env{'form.'.$name})) { &add_to_env('form.'.$name,$value) };
1.25 albertel 8083: }
1.16 harris41 8084: }
1.6 albertel 8085: }
8086:
1.112 bowersj2 8087: =pod
8088:
1.648 raeburn 8089: =item * &cacheheader()
1.112 bowersj2 8090:
8091: returns cache-controlling header code
8092:
8093: =cut
8094:
1.7 albertel 8095: sub cacheheader {
1.258 albertel 8096: unless ($env{'request.method'} eq 'GET') { return ''; }
1.216 albertel 8097: my $date=strftime("%a, %d %b %Y %H:%M:%S GMT",gmtime);
8098: my $output .='<meta HTTP-EQUIV="Expires" CONTENT="'.$date.'" />
1.7 albertel 8099: <meta HTTP-EQUIV="Cache-control" CONTENT="no-cache" />
8100: <meta HTTP-EQUIV="Pragma" CONTENT="no-cache" />';
1.216 albertel 8101: return $output;
1.7 albertel 8102: }
8103:
1.112 bowersj2 8104: =pod
8105:
1.648 raeburn 8106: =item * &no_cache($r)
1.112 bowersj2 8107:
8108: specifies header code to not have cache
8109:
8110: =cut
8111:
1.9 albertel 8112: sub no_cache {
1.216 albertel 8113: my ($r) = @_;
8114: if ($ENV{'REQUEST_METHOD'} ne 'GET' &&
1.258 albertel 8115: $env{'request.method'} ne 'GET') { return ''; }
1.216 albertel 8116: my $date=strftime("%a, %d %b %Y %H:%M:%S GMT",gmtime(time));
8117: $r->no_cache(1);
8118: $r->header_out("Expires" => $date);
8119: $r->header_out("Pragma" => "no-cache");
1.123 www 8120: }
8121:
8122: sub content_type {
1.181 albertel 8123: my ($r,$type,$charset) = @_;
1.299 foxr 8124: if ($r) {
8125: # Note that printout.pl calls this with undef for $r.
8126: &no_cache($r);
8127: }
1.258 albertel 8128: if ($env{'browser.mathml'} && $type eq 'text/html') { $type='text/xml'; }
1.181 albertel 8129: unless ($charset) {
8130: $charset=&Apache::lonlocal::current_encoding;
8131: }
8132: if ($charset) { $type.='; charset='.$charset; }
8133: if ($r) {
8134: $r->content_type($type);
8135: } else {
8136: print("Content-type: $type\n\n");
8137: }
1.9 albertel 8138: }
1.25 albertel 8139:
1.112 bowersj2 8140: =pod
8141:
1.648 raeburn 8142: =item * &add_to_env($name,$value)
1.112 bowersj2 8143:
1.258 albertel 8144: adds $name to the %env hash with value
1.112 bowersj2 8145: $value, if $name already exists, the entry is converted to an array
8146: reference and $value is added to the array.
8147:
8148: =cut
8149:
1.25 albertel 8150: sub add_to_env {
8151: my ($name,$value)=@_;
1.258 albertel 8152: if (defined($env{$name})) {
8153: if (ref($env{$name})) {
1.25 albertel 8154: #already have multiple values
1.258 albertel 8155: push(@{ $env{$name} },$value);
1.25 albertel 8156: } else {
8157: #first time seeing multiple values, convert hash entry to an arrayref
1.258 albertel 8158: my $first=$env{$name};
8159: undef($env{$name});
8160: push(@{ $env{$name} },$first,$value);
1.25 albertel 8161: }
8162: } else {
1.258 albertel 8163: $env{$name}=$value;
1.25 albertel 8164: }
1.31 albertel 8165: }
1.149 albertel 8166:
8167: =pod
8168:
1.648 raeburn 8169: =item * &get_env_multiple($name)
1.149 albertel 8170:
1.258 albertel 8171: gets $name from the %env hash, it seemlessly handles the cases where multiple
1.149 albertel 8172: values may be defined and end up as an array ref.
8173:
8174: returns an array of values
8175:
8176: =cut
8177:
8178: sub get_env_multiple {
8179: my ($name) = @_;
8180: my @values;
1.258 albertel 8181: if (defined($env{$name})) {
1.149 albertel 8182: # exists is it an array
1.258 albertel 8183: if (ref($env{$name})) {
8184: @values=@{ $env{$name} };
1.149 albertel 8185: } else {
1.258 albertel 8186: $values[0]=$env{$name};
1.149 albertel 8187: }
8188: }
8189: return(@values);
8190: }
8191:
1.660 raeburn 8192: sub ask_for_embedded_content {
8193: my ($actionurl,$state,$allfiles,$codebase,$args)=@_;
8194: my $upload_output = '
8195: <form name="upload_embedded" action="'.$actionurl.'"
8196: method="post" enctype="multipart/form-data">';
8197: $upload_output .= $state;
1.661 raeburn 8198: $upload_output .= '<b>Upload embedded files</b>:<br />'.&start_data_table();
1.660 raeburn 8199:
8200: my $num = 0;
8201: foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%{$allfiles})) {
8202: $upload_output .= &start_data_table_row().
8203: '<td>'.$embed_file.'</td><td>';
8204: if ($args->{'ignore_remote_references'}
8205: && $embed_file =~ m{^\w+://}) {
8206: $upload_output.='<span class="LC_warning">'.&mt("URL points to other server.").'</span>';
8207: } elsif ($args->{'error_on_invalid_names'}
8208: && $embed_file ne &Apache::lonnet::clean_filename($embed_file,{'keep_path' => 1,})) {
8209:
8210: $upload_output.='<span class="LC_warning">'.&mt("Invalid characters").'</span>';
8211:
8212: } else {
8213: $upload_output .='
1.661 raeburn 8214: <input name="embedded_item_'.$num.'" type="file" value="" />
1.660 raeburn 8215: <input name="embedded_orig_'.$num.'" type="hidden" value="'.&escape($embed_file).'" />';
8216: my $attrib = join(':',@{$$allfiles{$embed_file}});
8217: $upload_output .=
8218: "\n\t\t".
8219: '<input name="embedded_attrib_'.$num.'" type="hidden" value="'.
8220: $attrib.'" />';
8221: if (exists($$codebase{$embed_file})) {
8222: $upload_output .=
8223: "\n\t\t".
8224: '<input name="codebase_'.$num.'" type="hidden" value="'.
8225: &escape($$codebase{$embed_file}).'" />';
8226: }
8227: }
8228: $upload_output .= '</td>'.&Apache::loncommon::end_data_table_row();
8229: $num++;
8230: }
8231: $upload_output .= &Apache::loncommon::end_data_table().'<br />
8232: <input type ="hidden" name="number_embedded_items" value="'.$num.'" />
8233: <input type ="submit" value="'.&mt('Upload Listed Files').'" />
8234: '.&mt('(only files for which a location has been provided will be uploaded)').'
8235: </form>';
8236: return $upload_output;
8237: }
8238:
1.661 raeburn 8239: sub upload_embedded {
8240: my ($context,$dirpath,$uname,$udom,$dir_root,$url_root,$group,$disk_quota,
8241: $current_disk_usage) = @_;
8242: my $output;
8243: for (my $i=0; $i<$env{'form.number_embedded_items'}; $i++) {
8244: next if (!exists($env{'form.embedded_item_'.$i.'.filename'}));
8245: my $orig_uploaded_filename =
8246: $env{'form.embedded_item_'.$i.'.filename'};
8247:
8248: $env{'form.embedded_orig_'.$i} =
8249: &unescape($env{'form.embedded_orig_'.$i});
8250: my ($path,$fname) =
8251: ($env{'form.embedded_orig_'.$i} =~ m{(.*/)([^/]*)});
8252: # no path, whole string is fname
8253: if (!$fname) { $fname = $env{'form.embedded_orig_'.$i} };
8254:
8255: $path = $env{'form.currentpath'}.$path;
8256: $fname = &Apache::lonnet::clean_filename($fname);
8257: # See if there is anything left
8258: next if ($fname eq '');
8259:
8260: # Check if file already exists as a file or directory.
8261: my ($state,$msg);
8262: if ($context eq 'portfolio') {
8263: my $port_path = $dirpath;
8264: if ($group ne '') {
8265: $port_path = "groups/$group/$port_path";
8266: }
8267: ($state,$msg) = &check_for_upload($path,$fname,$group,'embedded_item_'.$i,
8268: $dir_root,$port_path,$disk_quota,
8269: $current_disk_usage,$uname,$udom);
8270: if ($state eq 'will_exceed_quota'
8271: || $state eq 'file_locked'
8272: || $state eq 'file_exists' ) {
8273: $output .= $msg;
8274: next;
8275: }
8276: } elsif (($context eq 'author') || ($context eq 'testbank')) {
8277: ($state,$msg) = &check_for_existing($path,$fname,'embedded_item_'.$i);
8278: if ($state eq 'exists') {
8279: $output .= $msg;
8280: next;
8281: }
8282: }
8283: # Check if extension is valid
8284: if (($fname =~ /\.(\w+)$/) &&
8285: (&Apache::loncommon::fileembstyle($1) eq 'hdn')) {
8286: $output .= &mt('Invalid file extension ([_1]) - reserved for LONCAPA use - rename the file with a different extension and re-upload. ',$1);
8287: next;
8288: } elsif (($fname =~ /\.(\w+)$/) &&
8289: (!defined(&Apache::loncommon::fileembstyle($1)))) {
8290: $output .= &mt('Unrecognized file extension ([_1]) - rename the file with a proper extension and re-upload.',$1);
8291: next;
8292: } elsif ($fname=~/\.(\d+)\.(\w+)$/) {
8293: $output .= &mt('File name not allowed - rename the file to remove the number immediately before the file extension([_1]) and re-upload.',$2);
8294: next;
8295: }
8296:
8297: $env{'form.embedded_item_'.$i.'.filename'}=$fname;
8298: if ($context eq 'portfolio') {
8299: my $result=
8300: &Apache::lonnet::userfileupload('embedded_item_'.$i,'',
8301: $dirpath.$path);
8302: if ($result !~ m|^/uploaded/|) {
8303: $output .= '<span class="LC_error">'
8304: .&mt('An error occurred ([_1]) while trying to upload [_2] for embedded element [_3].'
8305: ,$result,$orig_uploaded_filename,$env{'form.embedded_orig_'.$i})
8306: .'</span><br />';
8307: next;
8308: } else {
8309: $output .= '<p>'.&mt('Uploaded [_1]','<span class="LC_filename">'.
8310: $path.$fname.'</span>').'</p>';
8311: }
8312: } else {
8313: # Save the file
8314: my $target = $env{'form.embedded_item_'.$i};
8315: my $fullpath = $dir_root.$dirpath.'/'.$path;
8316: my $dest = $fullpath.$fname;
8317: my $url = $url_root.$dirpath.'/'.$path.$fname;
8318: my @parts=split(/\//,$fullpath);
8319: my $count;
8320: my $filepath = $dir_root;
8321: for ($count=4;$count<=$#parts;$count++) {
8322: $filepath .= "/$parts[$count]";
8323: if ((-e $filepath)!=1) {
8324: mkdir($filepath,0770);
8325: }
8326: }
8327: my $fh;
8328: if (!open($fh,'>'.$dest)) {
8329: &Apache::lonnet::logthis('Failed to create '.$dest);
8330: $output .= '<span class="LC_error">'.
8331: &mt('An error occurred while trying to upload [_1] for embedded element [_2].',$orig_uploaded_filename,$env{'form.embedded_orig_'.$i}).
8332: '</span><br />';
8333: } else {
8334: if (!print $fh $env{'form.embedded_item_'.$i}) {
8335: &Apache::lonnet::logthis('Failed to write to '.$dest);
8336: $output .= '<span class="LC_error">'.
8337: &mt('An error occurred while writing the file [_1] for embedded element [_2].',$orig_uploaded_filename,$env{'form.embedded_orig_'.$i}).
8338: '</span><br />';
8339: } else {
8340: if ($context eq 'testbank') {
8341: $output .= &mt('Embedded file uploaded successfully:').
8342: ' <a href="'.$url.'">'.
8343: $orig_uploaded_filename.'</a><br />';
8344: } else {
1.705 tempelho 8345: $output .= '<span class=\"LC_fontsize_large\">'.
1.661 raeburn 8346: &mt('View embedded file: [_1]','<a href="'.$url.'">'.
1.705 tempelho 8347: $orig_uploaded_filename.'</a>').'</span><br />';
1.661 raeburn 8348: }
8349: }
8350: close($fh);
8351: }
8352: }
8353: }
8354: return $output;
8355: }
8356:
8357: sub check_for_existing {
8358: my ($path,$fname,$element) = @_;
8359: my ($state,$msg);
8360: if (-d $path.'/'.$fname) {
8361: $state = 'exists';
8362: $msg = &mt('Unable to upload [_1]. A directory by that name was found in [_2].','<span class="LC_filename">'.$fname.'</span>',$path);
8363: } elsif (-e $path.'/'.$fname) {
8364: $state = 'exists';
8365: $msg = &mt('Unable to upload [_1]. A file by that name was found in [_2].','<span class="LC_filename">'.$fname.'</span>',$path);
8366: }
8367: if ($state eq 'exists') {
8368: $msg = '<span class="LC_error">'.$msg.'</span><br />';
8369: }
8370: return ($state,$msg);
8371: }
8372:
8373: sub check_for_upload {
8374: my ($path,$fname,$group,$element,$portfolio_root,$port_path,
8375: $disk_quota,$current_disk_usage,$uname,$udom) = @_;
8376: my $filesize = (length($env{'form.'.$element})) / 1000; #express in k (1024?)
8377: my $getpropath = 1;
8378: my @dir_list = &Apache::lonnet::dirlist($portfolio_root.$path,$udom,$uname,
8379: $getpropath);
8380: my $found_file = 0;
8381: my $locked_file = 0;
8382: foreach my $line (@dir_list) {
8383: my ($file_name)=split(/\&/,$line,2);
8384: if ($file_name eq $fname){
8385: $file_name = $path.$file_name;
8386: if ($group ne '') {
8387: $file_name = $group.$file_name;
8388: }
8389: $found_file = 1;
8390: if (&Apache::lonnet::is_locked($file_name,$udom,$uname) eq 'true') {
8391: $locked_file = 1;
8392: }
8393: }
8394: }
8395: if (($current_disk_usage + $filesize) > $disk_quota){
8396: my $msg = '<span class="LC_error">'.
8397: &mt('Unable to upload [_1]. (size = [_2] kilobytes). Disk quota will be exceeded.','<span class="LC_filename">'.$fname.'</span>',$filesize).'</span>'.
8398: '<br />'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.',$disk_quota,$current_disk_usage);
8399: return ('will_exceed_quota',$msg);
8400: } elsif ($found_file) {
8401: if ($locked_file) {
8402: my $msg = '<span class="LC_error">';
8403: $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>');
8404: $msg .= '</span><br />';
8405: $msg .= &mt('You will be able to rename or delete existing [_1] after a grade has been assigned.','<span class="LC_filename">'.$fname.'</span>');
8406: return ('file_locked',$msg);
8407: } else {
8408: my $msg = '<span class="LC_error">';
8409: $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'});
8410: $msg .= '</span>';
8411: $msg .= '<br />';
8412: $msg .= &mt('To upload, rename or delete existing [_1] in [_2].','<span class="LC_filename">'.$fname.'</span>', $port_path.$env{'form.currentpath'});
8413: return ('file_exists',$msg);
8414: }
8415: }
8416: }
8417:
1.31 albertel 8418:
1.41 ng 8419: =pod
1.45 matthew 8420:
1.464 albertel 8421: =back
1.41 ng 8422:
1.112 bowersj2 8423: =head1 CSV Upload/Handling functions
1.38 albertel 8424:
1.41 ng 8425: =over 4
8426:
1.648 raeburn 8427: =item * &upfile_store($r)
1.41 ng 8428:
8429: Store uploaded file, $r should be the HTTP Request object,
1.258 albertel 8430: needs $env{'form.upfile'}
1.41 ng 8431: returns $datatoken to be put into hidden field
8432:
8433: =cut
1.31 albertel 8434:
8435: sub upfile_store {
8436: my $r=shift;
1.258 albertel 8437: $env{'form.upfile'}=~s/\r/\n/gs;
8438: $env{'form.upfile'}=~s/\f/\n/gs;
8439: $env{'form.upfile'}=~s/\n+/\n/gs;
8440: $env{'form.upfile'}=~s/\n+$//gs;
1.31 albertel 8441:
1.258 albertel 8442: my $datatoken=$env{'user.name'}.'_'.$env{'user.domain'}.
8443: '_enroll_'.$env{'request.course.id'}.'_'.time.'_'.$$;
1.31 albertel 8444: {
1.158 raeburn 8445: my $datafile = $r->dir_config('lonDaemons').
8446: '/tmp/'.$datatoken.'.tmp';
8447: if ( open(my $fh,">$datafile") ) {
1.258 albertel 8448: print $fh $env{'form.upfile'};
1.158 raeburn 8449: close($fh);
8450: }
1.31 albertel 8451: }
8452: return $datatoken;
8453: }
8454:
1.56 matthew 8455: =pod
8456:
1.648 raeburn 8457: =item * &load_tmp_file($r)
1.41 ng 8458:
8459: Load uploaded file from tmp, $r should be the HTTP Request object,
1.258 albertel 8460: needs $env{'form.datatoken'},
8461: sets $env{'form.upfile'} to the contents of the file
1.41 ng 8462:
8463: =cut
1.31 albertel 8464:
8465: sub load_tmp_file {
8466: my $r=shift;
8467: my @studentdata=();
8468: {
1.158 raeburn 8469: my $studentfile = $r->dir_config('lonDaemons').
1.258 albertel 8470: '/tmp/'.$env{'form.datatoken'}.'.tmp';
1.158 raeburn 8471: if ( open(my $fh,"<$studentfile") ) {
8472: @studentdata=<$fh>;
8473: close($fh);
8474: }
1.31 albertel 8475: }
1.258 albertel 8476: $env{'form.upfile'}=join('',@studentdata);
1.31 albertel 8477: }
8478:
1.56 matthew 8479: =pod
8480:
1.648 raeburn 8481: =item * &upfile_record_sep()
1.41 ng 8482:
8483: Separate uploaded file into records
8484: returns array of records,
1.258 albertel 8485: needs $env{'form.upfile'} and $env{'form.upfiletype'}
1.41 ng 8486:
8487: =cut
1.31 albertel 8488:
8489: sub upfile_record_sep {
1.258 albertel 8490: if ($env{'form.upfiletype'} eq 'xml') {
1.31 albertel 8491: } else {
1.248 albertel 8492: my @records;
1.258 albertel 8493: foreach my $line (split(/\n/,$env{'form.upfile'})) {
1.248 albertel 8494: if ($line=~/^\s*$/) { next; }
8495: push(@records,$line);
8496: }
8497: return @records;
1.31 albertel 8498: }
8499: }
8500:
1.56 matthew 8501: =pod
8502:
1.648 raeburn 8503: =item * &record_sep($record)
1.41 ng 8504:
1.258 albertel 8505: Separate a record into fields $record should be an item from the upfile_record_sep(), needs $env{'form.upfiletype'}
1.41 ng 8506:
8507: =cut
8508:
1.263 www 8509: sub takeleft {
8510: my $index=shift;
8511: return substr('0000'.$index,-4,4);
8512: }
8513:
1.31 albertel 8514: sub record_sep {
8515: my $record=shift;
8516: my %components=();
1.258 albertel 8517: if ($env{'form.upfiletype'} eq 'xml') {
8518: } elsif ($env{'form.upfiletype'} eq 'space') {
1.31 albertel 8519: my $i=0;
1.356 albertel 8520: foreach my $field (split(/\s+/,$record)) {
1.31 albertel 8521: $field=~s/^(\"|\')//;
8522: $field=~s/(\"|\')$//;
1.263 www 8523: $components{&takeleft($i)}=$field;
1.31 albertel 8524: $i++;
8525: }
1.258 albertel 8526: } elsif ($env{'form.upfiletype'} eq 'tab') {
1.31 albertel 8527: my $i=0;
1.356 albertel 8528: foreach my $field (split(/\t/,$record)) {
1.31 albertel 8529: $field=~s/^(\"|\')//;
8530: $field=~s/(\"|\')$//;
1.263 www 8531: $components{&takeleft($i)}=$field;
1.31 albertel 8532: $i++;
8533: }
8534: } else {
1.561 www 8535: my $separator=',';
1.480 banghart 8536: if ($env{'form.upfiletype'} eq 'semisv') {
1.561 www 8537: $separator=';';
1.480 banghart 8538: }
1.31 albertel 8539: my $i=0;
1.561 www 8540: # the character we are looking for to indicate the end of a quote or a record
8541: my $looking_for=$separator;
8542: # do not add the characters to the fields
8543: my $ignore=0;
8544: # we just encountered a separator (or the beginning of the record)
8545: my $just_found_separator=1;
8546: # store the field we are working on here
8547: my $field='';
8548: # work our way through all characters in record
8549: foreach my $character ($record=~/(.)/g) {
8550: if ($character eq $looking_for) {
8551: if ($character ne $separator) {
8552: # Found the end of a quote, again looking for separator
8553: $looking_for=$separator;
8554: $ignore=1;
8555: } else {
8556: # Found a separator, store away what we got
8557: $components{&takeleft($i)}=$field;
8558: $i++;
8559: $just_found_separator=1;
8560: $ignore=0;
8561: $field='';
8562: }
8563: next;
8564: }
8565: # single or double quotation marks after a separator indicate beginning of a quote
8566: # we are now looking for the end of the quote and need to ignore separators
8567: if ((($character eq '"') || ($character eq "'")) && ($just_found_separator)) {
8568: $looking_for=$character;
8569: next;
8570: }
8571: # ignore would be true after we reached the end of a quote
8572: if ($ignore) { next; }
8573: if (($just_found_separator) && ($character=~/\s/)) { next; }
8574: $field.=$character;
8575: $just_found_separator=0;
1.31 albertel 8576: }
1.561 www 8577: # catch the very last entry, since we never encountered the separator
8578: $components{&takeleft($i)}=$field;
1.31 albertel 8579: }
8580: return %components;
8581: }
8582:
1.144 matthew 8583: ######################################################
8584: ######################################################
8585:
1.56 matthew 8586: =pod
8587:
1.648 raeburn 8588: =item * &upfile_select_html()
1.41 ng 8589:
1.144 matthew 8590: Return HTML code to select a file from the users machine and specify
8591: the file type.
1.41 ng 8592:
8593: =cut
8594:
1.144 matthew 8595: ######################################################
8596: ######################################################
1.31 albertel 8597: sub upfile_select_html {
1.144 matthew 8598: my %Types = (
8599: csv => &mt('CSV (comma separated values, spreadsheet)'),
1.480 banghart 8600: semisv => &mt('Semicolon separated values'),
1.144 matthew 8601: space => &mt('Space separated'),
8602: tab => &mt('Tabulator separated'),
8603: # xml => &mt('HTML/XML'),
8604: );
8605: my $Str = '<input type="file" name="upfile" size="50" />'.
1.727 riegler 8606: '<br />'.&mt('Type').': <select name="upfiletype">';
1.144 matthew 8607: foreach my $type (sort(keys(%Types))) {
8608: $Str .= '<option value="'.$type.'" >'.$Types{$type}."</option>\n";
8609: }
8610: $Str .= "</select>\n";
8611: return $Str;
1.31 albertel 8612: }
8613:
1.301 albertel 8614: sub get_samples {
8615: my ($records,$toget) = @_;
8616: my @samples=({});
8617: my $got=0;
8618: foreach my $rec (@$records) {
8619: my %temp = &record_sep($rec);
8620: if (! grep(/\S/, values(%temp))) { next; }
8621: if (%temp) {
8622: $samples[$got]=\%temp;
8623: $got++;
8624: if ($got == $toget) { last; }
8625: }
8626: }
8627: return \@samples;
8628: }
8629:
1.144 matthew 8630: ######################################################
8631: ######################################################
8632:
1.56 matthew 8633: =pod
8634:
1.648 raeburn 8635: =item * &csv_print_samples($r,$records)
1.41 ng 8636:
8637: Prints a table of sample values from each column uploaded $r is an
8638: Apache Request ref, $records is an arrayref from
8639: &Apache::loncommon::upfile_record_sep
8640:
8641: =cut
8642:
1.144 matthew 8643: ######################################################
8644: ######################################################
1.31 albertel 8645: sub csv_print_samples {
8646: my ($r,$records) = @_;
1.662 bisitz 8647: my $samples = &get_samples($records,5);
1.301 albertel 8648:
1.594 raeburn 8649: $r->print(&mt('Samples').'<br />'.&start_data_table().
8650: &start_data_table_header_row());
1.356 albertel 8651: foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) {
1.845 bisitz 8652: $r->print('<th>'.&mt('Column [_1]',($sample+1)).'</th>'); }
1.594 raeburn 8653: $r->print(&end_data_table_header_row());
1.301 albertel 8654: foreach my $hash (@$samples) {
1.594 raeburn 8655: $r->print(&start_data_table_row());
1.356 albertel 8656: foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) {
1.31 albertel 8657: $r->print('<td>');
1.356 albertel 8658: if (defined($$hash{$sample})) { $r->print($$hash{$sample}); }
1.31 albertel 8659: $r->print('</td>');
8660: }
1.594 raeburn 8661: $r->print(&end_data_table_row());
1.31 albertel 8662: }
1.594 raeburn 8663: $r->print(&end_data_table().'<br />'."\n");
1.31 albertel 8664: }
8665:
1.144 matthew 8666: ######################################################
8667: ######################################################
8668:
1.56 matthew 8669: =pod
8670:
1.648 raeburn 8671: =item * &csv_print_select_table($r,$records,$d)
1.41 ng 8672:
8673: Prints a table to create associations between values and table columns.
1.144 matthew 8674:
1.41 ng 8675: $r is an Apache Request ref,
8676: $records is an arrayref from &Apache::loncommon::upfile_record_sep,
1.174 matthew 8677: $d is an array of 2 element arrays (internal name, displayed name,defaultcol)
1.41 ng 8678:
8679: =cut
8680:
1.144 matthew 8681: ######################################################
8682: ######################################################
1.31 albertel 8683: sub csv_print_select_table {
8684: my ($r,$records,$d) = @_;
1.301 albertel 8685: my $i=0;
8686: my $samples = &get_samples($records,1);
1.144 matthew 8687: $r->print(&mt('Associate columns with student attributes.')."\n".
1.594 raeburn 8688: &start_data_table().&start_data_table_header_row().
1.144 matthew 8689: '<th>'.&mt('Attribute').'</th>'.
1.594 raeburn 8690: '<th>'.&mt('Column').'</th>'.
8691: &end_data_table_header_row()."\n");
1.356 albertel 8692: foreach my $array_ref (@$d) {
8693: my ($value,$display,$defaultcol)=@{ $array_ref };
1.729 raeburn 8694: $r->print(&start_data_table_row().'<td>'.$display.'</td>');
1.31 albertel 8695:
1.875 bisitz 8696: $r->print('<td><select name="f'.$i.'"'.
1.32 matthew 8697: ' onchange="javascript:flip(this.form,'.$i.');">');
1.31 albertel 8698: $r->print('<option value="none"></option>');
1.356 albertel 8699: foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) {
8700: $r->print('<option value="'.$sample.'"'.
8701: ($sample eq $defaultcol ? ' selected="selected" ' : '').
1.662 bisitz 8702: '>'.&mt('Column [_1]',($sample+1)).'</option>');
1.31 albertel 8703: }
1.594 raeburn 8704: $r->print('</select></td>'.&end_data_table_row()."\n");
1.31 albertel 8705: $i++;
8706: }
1.594 raeburn 8707: $r->print(&end_data_table());
1.31 albertel 8708: $i--;
8709: return $i;
8710: }
1.56 matthew 8711:
1.144 matthew 8712: ######################################################
8713: ######################################################
8714:
1.56 matthew 8715: =pod
1.31 albertel 8716:
1.648 raeburn 8717: =item * &csv_samples_select_table($r,$records,$d)
1.41 ng 8718:
8719: Prints a table of sample values from the upload and can make associate samples to internal names.
8720:
8721: $r is an Apache Request ref,
8722: $records is an arrayref from &Apache::loncommon::upfile_record_sep,
8723: $d is an array of 2 element arrays (internal name, displayed name)
8724:
8725: =cut
8726:
1.144 matthew 8727: ######################################################
8728: ######################################################
1.31 albertel 8729: sub csv_samples_select_table {
8730: my ($r,$records,$d) = @_;
8731: my $i=0;
1.144 matthew 8732: #
1.662 bisitz 8733: my $max_samples = 5;
8734: my $samples = &get_samples($records,$max_samples);
1.594 raeburn 8735: $r->print(&start_data_table().
8736: &start_data_table_header_row().'<th>'.
8737: &mt('Field').'</th><th>'.&mt('Samples').'</th>'.
8738: &end_data_table_header_row());
1.301 albertel 8739:
8740: foreach my $key (sort(keys(%{ $samples->[0] }))) {
1.594 raeburn 8741: $r->print(&start_data_table_row().'<td><select name="f'.$i.'"'.
1.32 matthew 8742: ' onchange="javascript:flip(this.form,'.$i.');">');
1.301 albertel 8743: foreach my $option (@$d) {
8744: my ($value,$display,$defaultcol)=@{ $option };
1.174 matthew 8745: $r->print('<option value="'.$value.'"'.
1.253 albertel 8746: ($i eq $defaultcol ? ' selected="selected" ':'').'>'.
1.174 matthew 8747: $display.'</option>');
1.31 albertel 8748: }
8749: $r->print('</select></td><td>');
1.662 bisitz 8750: foreach my $line (0..($max_samples-1)) {
1.301 albertel 8751: if (defined($samples->[$line]{$key})) {
8752: $r->print($samples->[$line]{$key}."<br />\n");
8753: }
8754: }
1.594 raeburn 8755: $r->print('</td>'.&end_data_table_row());
1.31 albertel 8756: $i++;
8757: }
1.594 raeburn 8758: $r->print(&end_data_table());
1.31 albertel 8759: $i--;
8760: return($i);
1.115 matthew 8761: }
8762:
1.144 matthew 8763: ######################################################
8764: ######################################################
8765:
1.115 matthew 8766: =pod
8767:
1.648 raeburn 8768: =item * &clean_excel_name($name)
1.115 matthew 8769:
8770: Returns a replacement for $name which does not contain any illegal characters.
8771:
8772: =cut
8773:
1.144 matthew 8774: ######################################################
8775: ######################################################
1.115 matthew 8776: sub clean_excel_name {
8777: my ($name) = @_;
8778: $name =~ s/[:\*\?\/\\]//g;
8779: if (length($name) > 31) {
8780: $name = substr($name,0,31);
8781: }
8782: return $name;
1.25 albertel 8783: }
1.84 albertel 8784:
1.85 albertel 8785: =pod
8786:
1.648 raeburn 8787: =item * &check_if_partid_hidden($id,$symb,$udom,$uname)
1.85 albertel 8788:
8789: Returns either 1 or undef
8790:
8791: 1 if the part is to be hidden, undef if it is to be shown
8792:
8793: Arguments are:
8794:
8795: $id the id of the part to be checked
8796: $symb, optional the symb of the resource to check
8797: $udom, optional the domain of the user to check for
8798: $uname, optional the username of the user to check for
8799:
8800: =cut
1.84 albertel 8801:
8802: sub check_if_partid_hidden {
8803: my ($id,$symb,$udom,$uname) = @_;
1.133 albertel 8804: my $hiddenparts=&Apache::lonnet::EXT('resource.0.hiddenparts',
1.84 albertel 8805: $symb,$udom,$uname);
1.141 albertel 8806: my $truth=1;
8807: #if the string starts with !, then the list is the list to show not hide
8808: if ($hiddenparts=~s/^\s*!//) { $truth=undef; }
1.84 albertel 8809: my @hiddenlist=split(/,/,$hiddenparts);
8810: foreach my $checkid (@hiddenlist) {
1.141 albertel 8811: if ($checkid =~ /^\s*\Q$id\E\s*$/) { return $truth; }
1.84 albertel 8812: }
1.141 albertel 8813: return !$truth;
1.84 albertel 8814: }
1.127 matthew 8815:
1.138 matthew 8816:
8817: ############################################################
8818: ############################################################
8819:
8820: =pod
8821:
1.157 matthew 8822: =back
8823:
1.138 matthew 8824: =head1 cgi-bin script and graphing routines
8825:
1.157 matthew 8826: =over 4
8827:
1.648 raeburn 8828: =item * &get_cgi_id()
1.138 matthew 8829:
8830: Inputs: none
8831:
8832: Returns an id which can be used to pass environment variables
8833: to various cgi-bin scripts. These environment variables will
8834: be removed from the users environment after a given time by
8835: the routine &Apache::lonnet::transfer_profile_to_env.
8836:
8837: =cut
8838:
8839: ############################################################
8840: ############################################################
1.152 albertel 8841: my $uniq=0;
1.136 matthew 8842: sub get_cgi_id {
1.154 albertel 8843: $uniq=($uniq+1)%100000;
1.280 albertel 8844: return (time.'_'.$$.'_'.$uniq);
1.136 matthew 8845: }
8846:
1.127 matthew 8847: ############################################################
8848: ############################################################
8849:
8850: =pod
8851:
1.648 raeburn 8852: =item * &DrawBarGraph()
1.127 matthew 8853:
1.138 matthew 8854: Facilitates the plotting of data in a (stacked) bar graph.
8855: Puts plot definition data into the users environment in order for
8856: graph.png to plot it. Returns an <img> tag for the plot.
8857: The bars on the plot are labeled '1','2',...,'n'.
8858:
8859: Inputs:
8860:
8861: =over 4
8862:
8863: =item $Title: string, the title of the plot
8864:
8865: =item $xlabel: string, text describing the X-axis of the plot
8866:
8867: =item $ylabel: string, text describing the Y-axis of the plot
8868:
8869: =item $Max: scalar, the maximum Y value to use in the plot
8870: If $Max is < any data point, the graph will not be rendered.
8871:
1.140 matthew 8872: =item $colors: array ref holding the colors to be used for the data sets when
1.138 matthew 8873: they are plotted. If undefined, default values will be used.
8874:
1.178 matthew 8875: =item $labels: array ref holding the labels to use on the x-axis for the bars.
8876:
1.138 matthew 8877: =item @Values: An array of array references. Each array reference holds data
8878: to be plotted in a stacked bar chart.
8879:
1.239 matthew 8880: =item If the final element of @Values is a hash reference the key/value
8881: pairs will be added to the graph definition.
8882:
1.138 matthew 8883: =back
8884:
8885: Returns:
8886:
8887: An <img> tag which references graph.png and the appropriate identifying
8888: information for the plot.
8889:
1.127 matthew 8890: =cut
8891:
8892: ############################################################
8893: ############################################################
1.134 matthew 8894: sub DrawBarGraph {
1.178 matthew 8895: my ($Title,$xlabel,$ylabel,$Max,$colors,$labels,@Values)=@_;
1.134 matthew 8896: #
8897: if (! defined($colors)) {
8898: $colors = ['#33ff00',
8899: '#0033cc', '#990000', '#aaaa66', '#663399', '#ff9933',
8900: '#66ccff', '#ff9999', '#cccc33', '#660000', '#33cc66',
8901: ];
8902: }
1.228 matthew 8903: my $extra_settings = {};
8904: if (ref($Values[-1]) eq 'HASH') {
8905: $extra_settings = pop(@Values);
8906: }
1.127 matthew 8907: #
1.136 matthew 8908: my $identifier = &get_cgi_id();
8909: my $id = 'cgi.'.$identifier;
1.129 matthew 8910: if (! @Values || ref($Values[0]) ne 'ARRAY') {
1.127 matthew 8911: return '';
8912: }
1.225 matthew 8913: #
8914: my @Labels;
8915: if (defined($labels)) {
8916: @Labels = @$labels;
8917: } else {
8918: for (my $i=0;$i<@{$Values[0]};$i++) {
8919: push (@Labels,$i+1);
8920: }
8921: }
8922: #
1.129 matthew 8923: my $NumBars = scalar(@{$Values[0]});
1.225 matthew 8924: if ($NumBars < scalar(@Labels)) { $NumBars = scalar(@Labels); }
1.129 matthew 8925: my %ValuesHash;
8926: my $NumSets=1;
8927: foreach my $array (@Values) {
8928: next if (! ref($array));
1.136 matthew 8929: $ValuesHash{$id.'.data.'.$NumSets++} =
1.132 matthew 8930: join(',',@$array);
1.129 matthew 8931: }
1.127 matthew 8932: #
1.136 matthew 8933: my ($height,$width,$xskip,$bar_width) = (200,120,1,15);
1.225 matthew 8934: if ($NumBars < 3) {
8935: $width = 120+$NumBars*32;
1.220 matthew 8936: $xskip = 1;
1.225 matthew 8937: $bar_width = 30;
8938: } elsif ($NumBars < 5) {
8939: $width = 120+$NumBars*20;
8940: $xskip = 1;
8941: $bar_width = 20;
1.220 matthew 8942: } elsif ($NumBars < 10) {
1.136 matthew 8943: $width = 120+$NumBars*15;
8944: $xskip = 1;
8945: $bar_width = 15;
8946: } elsif ($NumBars <= 25) {
8947: $width = 120+$NumBars*11;
8948: $xskip = 5;
8949: $bar_width = 8;
8950: } elsif ($NumBars <= 50) {
8951: $width = 120+$NumBars*8;
8952: $xskip = 5;
8953: $bar_width = 4;
8954: } else {
8955: $width = 120+$NumBars*8;
8956: $xskip = 5;
8957: $bar_width = 4;
8958: }
8959: #
1.137 matthew 8960: $Max = 1 if ($Max < 1);
8961: if ( int($Max) < $Max ) {
8962: $Max++;
8963: $Max = int($Max);
8964: }
1.127 matthew 8965: $Title = '' if (! defined($Title));
8966: $xlabel = '' if (! defined($xlabel));
8967: $ylabel = '' if (! defined($ylabel));
1.369 www 8968: $ValuesHash{$id.'.title'} = &escape($Title);
8969: $ValuesHash{$id.'.xlabel'} = &escape($xlabel);
8970: $ValuesHash{$id.'.ylabel'} = &escape($ylabel);
1.137 matthew 8971: $ValuesHash{$id.'.y_max_value'} = $Max;
1.136 matthew 8972: $ValuesHash{$id.'.NumBars'} = $NumBars;
8973: $ValuesHash{$id.'.NumSets'} = $NumSets;
8974: $ValuesHash{$id.'.PlotType'} = 'bar';
8975: $ValuesHash{$id.'.Colors'} = join(',',@{$colors});
8976: $ValuesHash{$id.'.height'} = $height;
8977: $ValuesHash{$id.'.width'} = $width;
8978: $ValuesHash{$id.'.xskip'} = $xskip;
8979: $ValuesHash{$id.'.bar_width'} = $bar_width;
8980: $ValuesHash{$id.'.labels'} = join(',',@Labels);
1.127 matthew 8981: #
1.228 matthew 8982: # Deal with other parameters
8983: while (my ($key,$value) = each(%$extra_settings)) {
8984: $ValuesHash{$id.'.'.$key} = $value;
8985: }
8986: #
1.646 raeburn 8987: &Apache::lonnet::appenv(\%ValuesHash);
1.137 matthew 8988: return '<img src="/cgi-bin/graph.png?'.$identifier.'" border="1" />';
8989: }
8990:
8991: ############################################################
8992: ############################################################
8993:
8994: =pod
8995:
1.648 raeburn 8996: =item * &DrawXYGraph()
1.137 matthew 8997:
1.138 matthew 8998: Facilitates the plotting of data in an XY graph.
8999: Puts plot definition data into the users environment in order for
9000: graph.png to plot it. Returns an <img> tag for the plot.
9001:
9002: Inputs:
9003:
9004: =over 4
9005:
9006: =item $Title: string, the title of the plot
9007:
9008: =item $xlabel: string, text describing the X-axis of the plot
9009:
9010: =item $ylabel: string, text describing the Y-axis of the plot
9011:
9012: =item $Max: scalar, the maximum Y value to use in the plot
9013: If $Max is < any data point, the graph will not be rendered.
9014:
9015: =item $colors: Array ref containing the hex color codes for the data to be
9016: plotted in. If undefined, default values will be used.
9017:
9018: =item $Xlabels: Array ref containing the labels to be used for the X-axis.
9019:
9020: =item $Ydata: Array ref containing Array refs.
1.185 www 9021: Each of the contained arrays will be plotted as a separate curve.
1.138 matthew 9022:
9023: =item %Values: hash indicating or overriding any default values which are
9024: passed to graph.png.
9025: Possible values are: width, xskip, x_ticks, x_tick_offset, among others.
9026:
9027: =back
9028:
9029: Returns:
9030:
9031: An <img> tag which references graph.png and the appropriate identifying
9032: information for the plot.
9033:
1.137 matthew 9034: =cut
9035:
9036: ############################################################
9037: ############################################################
9038: sub DrawXYGraph {
9039: my ($Title,$xlabel,$ylabel,$Max,$colors,$Xlabels,$Ydata,%Values)=@_;
9040: #
9041: # Create the identifier for the graph
9042: my $identifier = &get_cgi_id();
9043: my $id = 'cgi.'.$identifier;
9044: #
9045: $Title = '' if (! defined($Title));
9046: $xlabel = '' if (! defined($xlabel));
9047: $ylabel = '' if (! defined($ylabel));
9048: my %ValuesHash =
9049: (
1.369 www 9050: $id.'.title' => &escape($Title),
9051: $id.'.xlabel' => &escape($xlabel),
9052: $id.'.ylabel' => &escape($ylabel),
1.137 matthew 9053: $id.'.y_max_value'=> $Max,
9054: $id.'.labels' => join(',',@$Xlabels),
9055: $id.'.PlotType' => 'XY',
9056: );
9057: #
9058: if (defined($colors) && ref($colors) eq 'ARRAY') {
9059: $ValuesHash{$id.'.Colors'} = join(',',@{$colors});
9060: }
9061: #
9062: if (! ref($Ydata) || ref($Ydata) ne 'ARRAY') {
9063: return '';
9064: }
9065: my $NumSets=1;
1.138 matthew 9066: foreach my $array (@{$Ydata}){
1.137 matthew 9067: next if (! ref($array));
9068: $ValuesHash{$id.'.data.'.$NumSets++} = join(',',@$array);
9069: }
1.138 matthew 9070: $ValuesHash{$id.'.NumSets'} = $NumSets-1;
1.137 matthew 9071: #
9072: # Deal with other parameters
9073: while (my ($key,$value) = each(%Values)) {
9074: $ValuesHash{$id.'.'.$key} = $value;
1.127 matthew 9075: }
9076: #
1.646 raeburn 9077: &Apache::lonnet::appenv(\%ValuesHash);
1.136 matthew 9078: return '<img src="/cgi-bin/graph.png?'.$identifier.'" border="1" />';
9079: }
9080:
9081: ############################################################
9082: ############################################################
9083:
9084: =pod
9085:
1.648 raeburn 9086: =item * &DrawXYYGraph()
1.138 matthew 9087:
9088: Facilitates the plotting of data in an XY graph with two Y axes.
9089: Puts plot definition data into the users environment in order for
9090: graph.png to plot it. Returns an <img> tag for the plot.
9091:
9092: Inputs:
9093:
9094: =over 4
9095:
9096: =item $Title: string, the title of the plot
9097:
9098: =item $xlabel: string, text describing the X-axis of the plot
9099:
9100: =item $ylabel: string, text describing the Y-axis of the plot
9101:
9102: =item $colors: Array ref containing the hex color codes for the data to be
9103: plotted in. If undefined, default values will be used.
9104:
9105: =item $Xlabels: Array ref containing the labels to be used for the X-axis.
9106:
9107: =item $Ydata1: The first data set
9108:
9109: =item $Min1: The minimum value of the left Y-axis
9110:
9111: =item $Max1: The maximum value of the left Y-axis
9112:
9113: =item $Ydata2: The second data set
9114:
9115: =item $Min2: The minimum value of the right Y-axis
9116:
9117: =item $Max2: The maximum value of the left Y-axis
9118:
9119: =item %Values: hash indicating or overriding any default values which are
9120: passed to graph.png.
9121: Possible values are: width, xskip, x_ticks, x_tick_offset, among others.
9122:
9123: =back
9124:
9125: Returns:
9126:
9127: An <img> tag which references graph.png and the appropriate identifying
9128: information for the plot.
1.136 matthew 9129:
9130: =cut
9131:
9132: ############################################################
9133: ############################################################
1.137 matthew 9134: sub DrawXYYGraph {
9135: my ($Title,$xlabel,$ylabel,$colors,$Xlabels,$Ydata1,$Min1,$Max1,
9136: $Ydata2,$Min2,$Max2,%Values)=@_;
1.136 matthew 9137: #
9138: # Create the identifier for the graph
9139: my $identifier = &get_cgi_id();
9140: my $id = 'cgi.'.$identifier;
9141: #
9142: $Title = '' if (! defined($Title));
9143: $xlabel = '' if (! defined($xlabel));
9144: $ylabel = '' if (! defined($ylabel));
9145: my %ValuesHash =
9146: (
1.369 www 9147: $id.'.title' => &escape($Title),
9148: $id.'.xlabel' => &escape($xlabel),
9149: $id.'.ylabel' => &escape($ylabel),
1.136 matthew 9150: $id.'.labels' => join(',',@$Xlabels),
9151: $id.'.PlotType' => 'XY',
9152: $id.'.NumSets' => 2,
1.137 matthew 9153: $id.'.two_axes' => 1,
9154: $id.'.y1_max_value' => $Max1,
9155: $id.'.y1_min_value' => $Min1,
9156: $id.'.y2_max_value' => $Max2,
9157: $id.'.y2_min_value' => $Min2,
1.136 matthew 9158: );
9159: #
1.137 matthew 9160: if (defined($colors) && ref($colors) eq 'ARRAY') {
9161: $ValuesHash{$id.'.Colors'} = join(',',@{$colors});
9162: }
9163: #
9164: if (! ref($Ydata1) || ref($Ydata1) ne 'ARRAY' ||
9165: ! ref($Ydata2) || ref($Ydata2) ne 'ARRAY'){
1.136 matthew 9166: return '';
9167: }
9168: my $NumSets=1;
1.137 matthew 9169: foreach my $array ($Ydata1,$Ydata2){
1.136 matthew 9170: next if (! ref($array));
9171: $ValuesHash{$id.'.data.'.$NumSets++} = join(',',@$array);
1.137 matthew 9172: }
9173: #
9174: # Deal with other parameters
9175: while (my ($key,$value) = each(%Values)) {
9176: $ValuesHash{$id.'.'.$key} = $value;
1.136 matthew 9177: }
9178: #
1.646 raeburn 9179: &Apache::lonnet::appenv(\%ValuesHash);
1.130 albertel 9180: return '<img src="/cgi-bin/graph.png?'.$identifier.'" border="1" />';
1.139 matthew 9181: }
9182:
9183: ############################################################
9184: ############################################################
9185:
9186: =pod
9187:
1.157 matthew 9188: =back
9189:
1.139 matthew 9190: =head1 Statistics helper routines?
9191:
9192: Bad place for them but what the hell.
9193:
1.157 matthew 9194: =over 4
9195:
1.648 raeburn 9196: =item * &chartlink()
1.139 matthew 9197:
9198: Returns a link to the chart for a specific student.
9199:
9200: Inputs:
9201:
9202: =over 4
9203:
9204: =item $linktext: The text of the link
9205:
9206: =item $sname: The students username
9207:
9208: =item $sdomain: The students domain
9209:
9210: =back
9211:
1.157 matthew 9212: =back
9213:
1.139 matthew 9214: =cut
9215:
9216: ############################################################
9217: ############################################################
9218: sub chartlink {
9219: my ($linktext, $sname, $sdomain) = @_;
9220: my $link = '<a href="/adm/statistics?reportSelected=student_assessment'.
1.369 www 9221: '&SelectedStudent='.&escape($sname.':'.$sdomain).
1.219 albertel 9222: '&chartoutputmode='.HTML::Entities::encode('html, with all links').
1.139 matthew 9223: '">'.$linktext.'</a>';
1.153 matthew 9224: }
9225:
9226: #######################################################
9227: #######################################################
9228:
9229: =pod
9230:
9231: =head1 Course Environment Routines
1.157 matthew 9232:
9233: =over 4
1.153 matthew 9234:
1.648 raeburn 9235: =item * &restore_course_settings()
1.153 matthew 9236:
1.648 raeburn 9237: =item * &store_course_settings()
1.153 matthew 9238:
9239: Restores/Store indicated form parameters from the course environment.
9240: Will not overwrite existing values of the form parameters.
9241:
9242: Inputs:
9243: a scalar describing the data (e.g. 'chart', 'problem_analysis')
9244:
9245: a hash ref describing the data to be stored. For example:
9246:
9247: %Save_Parameters = ('Status' => 'scalar',
9248: 'chartoutputmode' => 'scalar',
9249: 'chartoutputdata' => 'scalar',
9250: 'Section' => 'array',
1.373 raeburn 9251: 'Group' => 'array',
1.153 matthew 9252: 'StudentData' => 'array',
9253: 'Maps' => 'array');
9254:
9255: Returns: both routines return nothing
9256:
1.631 raeburn 9257: =back
9258:
1.153 matthew 9259: =cut
9260:
9261: #######################################################
9262: #######################################################
9263: sub store_course_settings {
1.496 albertel 9264: return &store_settings($env{'request.course.id'},@_);
9265: }
9266:
9267: sub store_settings {
1.153 matthew 9268: # save to the environment
9269: # appenv the same items, just to be safe
1.300 albertel 9270: my $udom = $env{'user.domain'};
9271: my $uname = $env{'user.name'};
1.496 albertel 9272: my ($context,$prefix,$Settings) = @_;
1.153 matthew 9273: my %SaveHash;
9274: my %AppHash;
9275: while (my ($setting,$type) = each(%$Settings)) {
1.496 albertel 9276: my $basename = join('.','internal',$context,$prefix,$setting);
1.300 albertel 9277: my $envname = 'environment.'.$basename;
1.258 albertel 9278: if (exists($env{'form.'.$setting})) {
1.153 matthew 9279: # Save this value away
9280: if ($type eq 'scalar' &&
1.258 albertel 9281: (! exists($env{$envname}) ||
9282: $env{$envname} ne $env{'form.'.$setting})) {
9283: $SaveHash{$basename} = $env{'form.'.$setting};
9284: $AppHash{$envname} = $env{'form.'.$setting};
1.153 matthew 9285: } elsif ($type eq 'array') {
9286: my $stored_form;
1.258 albertel 9287: if (ref($env{'form.'.$setting})) {
1.153 matthew 9288: $stored_form = join(',',
9289: map {
1.369 www 9290: &escape($_);
1.258 albertel 9291: } sort(@{$env{'form.'.$setting}}));
1.153 matthew 9292: } else {
9293: $stored_form =
1.369 www 9294: &escape($env{'form.'.$setting});
1.153 matthew 9295: }
9296: # Determine if the array contents are the same.
1.258 albertel 9297: if ($stored_form ne $env{$envname}) {
1.153 matthew 9298: $SaveHash{$basename} = $stored_form;
9299: $AppHash{$envname} = $stored_form;
9300: }
9301: }
9302: }
9303: }
9304: my $put_result = &Apache::lonnet::put('environment',\%SaveHash,
1.300 albertel 9305: $udom,$uname);
1.153 matthew 9306: if ($put_result !~ /^(ok|delayed)/) {
9307: &Apache::lonnet::logthis('unable to save form parameters, '.
9308: 'got error:'.$put_result);
9309: }
9310: # Make sure these settings stick around in this session, too
1.646 raeburn 9311: &Apache::lonnet::appenv(\%AppHash);
1.153 matthew 9312: return;
9313: }
9314:
9315: sub restore_course_settings {
1.499 albertel 9316: return &restore_settings($env{'request.course.id'},@_);
1.496 albertel 9317: }
9318:
9319: sub restore_settings {
9320: my ($context,$prefix,$Settings) = @_;
1.153 matthew 9321: while (my ($setting,$type) = each(%$Settings)) {
1.258 albertel 9322: next if (exists($env{'form.'.$setting}));
1.496 albertel 9323: my $envname = 'environment.internal.'.$context.'.'.$prefix.
1.153 matthew 9324: '.'.$setting;
1.258 albertel 9325: if (exists($env{$envname})) {
1.153 matthew 9326: if ($type eq 'scalar') {
1.258 albertel 9327: $env{'form.'.$setting} = $env{$envname};
1.153 matthew 9328: } elsif ($type eq 'array') {
1.258 albertel 9329: $env{'form.'.$setting} = [
1.153 matthew 9330: map {
1.369 www 9331: &unescape($_);
1.258 albertel 9332: } split(',',$env{$envname})
1.153 matthew 9333: ];
9334: }
9335: }
9336: }
1.127 matthew 9337: }
9338:
1.618 raeburn 9339: #######################################################
9340: #######################################################
9341:
9342: =pod
9343:
9344: =head1 Domain E-mail Routines
9345:
9346: =over 4
9347:
1.648 raeburn 9348: =item * &build_recipient_list()
1.618 raeburn 9349:
1.884 raeburn 9350: Build recipient lists for five types of e-mail:
1.766 raeburn 9351: (a) Error Reports, (b) Package Updates, (c) lonstatus warnings/errors
1.884 raeburn 9352: (d) Help requests, (e) Course requests needing approval, generated by
9353: lonerrorhandler.pm, CHECKRPMS, loncron, lonsupportreq.pm and
9354: loncoursequeueadmin.pm respectively.
1.618 raeburn 9355:
9356: Inputs:
1.619 raeburn 9357: defmail (scalar - email address of default recipient),
1.618 raeburn 9358: mailing type (scalar - errormail, packagesmail, or helpdeskmail),
1.619 raeburn 9359: defdom (domain for which to retrieve configuration settings),
9360: origmail (scalar - email address of recipient from loncapa.conf,
9361: i.e., predates configuration by DC via domainprefs.pm
1.618 raeburn 9362:
1.655 raeburn 9363: Returns: comma separated list of addresses to which to send e-mail.
9364:
9365: =back
1.618 raeburn 9366:
9367: =cut
9368:
9369: ############################################################
9370: ############################################################
9371: sub build_recipient_list {
1.619 raeburn 9372: my ($defmail,$mailing,$defdom,$origmail) = @_;
1.618 raeburn 9373: my @recipients;
9374: my $otheremails;
9375: my %domconfig =
9376: &Apache::lonnet::get_dom('configuration',['contacts'],$defdom);
9377: if (ref($domconfig{'contacts'}) eq 'HASH') {
1.766 raeburn 9378: if (exists($domconfig{'contacts'}{$mailing})) {
9379: if (ref($domconfig{'contacts'}{$mailing}) eq 'HASH') {
9380: my @contacts = ('adminemail','supportemail');
9381: foreach my $item (@contacts) {
9382: if ($domconfig{'contacts'}{$mailing}{$item}) {
9383: my $addr = $domconfig{'contacts'}{$item};
9384: if (!grep(/^\Q$addr\E$/,@recipients)) {
9385: push(@recipients,$addr);
9386: }
1.619 raeburn 9387: }
1.766 raeburn 9388: $otheremails = $domconfig{'contacts'}{$mailing}{'others'};
1.618 raeburn 9389: }
9390: }
1.766 raeburn 9391: } elsif ($origmail ne '') {
9392: push(@recipients,$origmail);
1.618 raeburn 9393: }
1.619 raeburn 9394: } elsif ($origmail ne '') {
9395: push(@recipients,$origmail);
1.618 raeburn 9396: }
1.688 raeburn 9397: if (defined($defmail)) {
9398: if ($defmail ne '') {
9399: push(@recipients,$defmail);
9400: }
1.618 raeburn 9401: }
9402: if ($otheremails) {
1.619 raeburn 9403: my @others;
9404: if ($otheremails =~ /,/) {
9405: @others = split(/,/,$otheremails);
1.618 raeburn 9406: } else {
1.619 raeburn 9407: push(@others,$otheremails);
9408: }
9409: foreach my $addr (@others) {
9410: if (!grep(/^\Q$addr\E$/,@recipients)) {
9411: push(@recipients,$addr);
9412: }
1.618 raeburn 9413: }
9414: }
1.619 raeburn 9415: my $recipientlist = join(',',@recipients);
1.618 raeburn 9416: return $recipientlist;
9417: }
9418:
1.127 matthew 9419: ############################################################
9420: ############################################################
1.154 albertel 9421:
1.655 raeburn 9422: =pod
9423:
9424: =head1 Course Catalog Routines
9425:
9426: =over 4
9427:
9428: =item * &gather_categories()
9429:
9430: Converts category definitions - keys of categories hash stored in
9431: coursecategories in configuration.db on the primary library server in a
9432: domain - to an array. Also generates javascript and idx hash used to
9433: generate Domain Coordinator interface for editing 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: idx (reference to hash of counters used in Domain Coordinator interface for
9443: editing Course Categories).
1.663 raeburn 9444:
1.655 raeburn 9445: jsarray (reference to array of categories used to create Javascript arrays for
9446: Domain Coordinator interface for editing Course Categories).
9447:
9448: Returns: nothing
9449:
9450: Side effects: populates cats, idx and jsarray.
9451:
9452: =cut
9453:
9454: sub gather_categories {
9455: my ($categories,$cats,$idx,$jsarray) = @_;
9456: my %counters;
9457: my $num = 0;
9458: foreach my $item (keys(%{$categories})) {
9459: my ($cat,$container,$depth) = map { &unescape($_); } split(/:/,$item);
9460: if ($container eq '' && $depth == 0) {
9461: $cats->[$depth][$categories->{$item}] = $cat;
9462: } else {
9463: $cats->[$depth]{$container}[$categories->{$item}] = $cat;
9464: }
9465: my ($escitem,$tail) = split(/:/,$item,2);
9466: if ($counters{$tail} eq '') {
9467: $counters{$tail} = $num;
9468: $num ++;
9469: }
9470: if (ref($idx) eq 'HASH') {
9471: $idx->{$item} = $counters{$tail};
9472: }
9473: if (ref($jsarray) eq 'ARRAY') {
9474: push(@{$jsarray->[$counters{$tail}]},$item);
9475: }
9476: }
9477: return;
9478: }
9479:
9480: =pod
9481:
9482: =item * &extract_categories()
9483:
9484: Used to generate breadcrumb trails for course categories.
9485:
9486: Inputs:
1.663 raeburn 9487:
1.655 raeburn 9488: categories (reference to hash of category definitions).
1.663 raeburn 9489:
1.655 raeburn 9490: cats (reference to array of arrays/hashes which encapsulates hierarchy of
9491: categories and subcategories).
1.663 raeburn 9492:
1.655 raeburn 9493: trails (reference to array of breacrumb trails for each category).
1.663 raeburn 9494:
1.655 raeburn 9495: allitems (reference to hash - key is category key
9496: (format: escaped(name):escaped(parent category):depth in hierarchy).
1.663 raeburn 9497:
1.655 raeburn 9498: idx (reference to hash of counters used in Domain Coordinator interface for
9499: editing Course Categories).
1.663 raeburn 9500:
1.655 raeburn 9501: jsarray (reference to array of categories used to create Javascript arrays for
9502: Domain Coordinator interface for editing Course Categories).
9503:
1.665 raeburn 9504: subcats (reference to hash of arrays containing all subcategories within each
9505: category, -recursive)
9506:
1.655 raeburn 9507: Returns: nothing
9508:
9509: Side effects: populates trails and allitems hash references.
9510:
9511: =cut
9512:
9513: sub extract_categories {
1.665 raeburn 9514: my ($categories,$cats,$trails,$allitems,$idx,$jsarray,$subcats) = @_;
1.655 raeburn 9515: if (ref($categories) eq 'HASH') {
9516: &gather_categories($categories,$cats,$idx,$jsarray);
9517: if (ref($cats->[0]) eq 'ARRAY') {
9518: for (my $i=0; $i<@{$cats->[0]}; $i++) {
9519: my $name = $cats->[0][$i];
9520: my $item = &escape($name).'::0';
9521: my $trailstr;
9522: if ($name eq 'instcode') {
9523: $trailstr = &mt('Official courses (with institutional codes)');
9524: } else {
9525: $trailstr = $name;
9526: }
9527: if ($allitems->{$item} eq '') {
9528: push(@{$trails},$trailstr);
9529: $allitems->{$item} = scalar(@{$trails})-1;
9530: }
9531: my @parents = ($name);
9532: if (ref($cats->[1]{$name}) eq 'ARRAY') {
9533: for (my $j=0; $j<@{$cats->[1]{$name}}; $j++) {
9534: my $category = $cats->[1]{$name}[$j];
1.665 raeburn 9535: if (ref($subcats) eq 'HASH') {
9536: push(@{$subcats->{$item}},&escape($category).':'.&escape($name).':1');
9537: }
9538: &recurse_categories($cats,2,$category,$trails,$allitems,\@parents,$subcats);
9539: }
9540: } else {
9541: if (ref($subcats) eq 'HASH') {
9542: $subcats->{$item} = [];
1.655 raeburn 9543: }
9544: }
9545: }
9546: }
9547: }
9548: return;
9549: }
9550:
9551: =pod
9552:
9553: =item *&recurse_categories()
9554:
9555: Recursively used to generate breadcrumb trails for course categories.
9556:
9557: Inputs:
1.663 raeburn 9558:
1.655 raeburn 9559: cats (reference to array of arrays/hashes which encapsulates hierarchy of
9560: categories and subcategories).
1.663 raeburn 9561:
1.655 raeburn 9562: depth (current depth in hierarchy of categories and sub-categories - 0 indexed).
1.663 raeburn 9563:
9564: category (current course category, for which breadcrumb trail is being generated).
9565:
9566: trails (reference to array of breadcrumb trails for each category).
9567:
1.655 raeburn 9568: allitems (reference to hash - key is category key
9569: (format: escaped(name):escaped(parent category):depth in hierarchy).
1.663 raeburn 9570:
1.655 raeburn 9571: parents (array containing containers directories for current category,
9572: back to top level).
9573:
9574: Returns: nothing
9575:
9576: Side effects: populates trails and allitems hash references
9577:
9578: =cut
9579:
9580: sub recurse_categories {
1.665 raeburn 9581: my ($cats,$depth,$category,$trails,$allitems,$parents,$subcats) = @_;
1.655 raeburn 9582: my $shallower = $depth - 1;
9583: if (ref($cats->[$depth]{$category}) eq 'ARRAY') {
9584: for (my $k=0; $k<@{$cats->[$depth]{$category}}; $k++) {
9585: my $name = $cats->[$depth]{$category}[$k];
9586: my $item = &escape($category).':'.&escape($parents->[-1]).':'.$shallower;
9587: my $trailstr = join(' -> ',(@{$parents},$category));
9588: if ($allitems->{$item} eq '') {
9589: push(@{$trails},$trailstr);
9590: $allitems->{$item} = scalar(@{$trails})-1;
9591: }
9592: my $deeper = $depth+1;
9593: push(@{$parents},$category);
1.665 raeburn 9594: if (ref($subcats) eq 'HASH') {
9595: my $subcat = &escape($name).':'.$category.':'.$depth;
9596: for (my $j=@{$parents}; $j>=0; $j--) {
9597: my $higher;
9598: if ($j > 0) {
9599: $higher = &escape($parents->[$j]).':'.
9600: &escape($parents->[$j-1]).':'.$j;
9601: } else {
9602: $higher = &escape($parents->[$j]).'::'.$j;
9603: }
9604: push(@{$subcats->{$higher}},$subcat);
9605: }
9606: }
9607: &recurse_categories($cats,$deeper,$name,$trails,$allitems,$parents,
9608: $subcats);
1.655 raeburn 9609: pop(@{$parents});
9610: }
9611: } else {
9612: my $item = &escape($category).':'.&escape($parents->[-1]).':'.$shallower;
9613: my $trailstr = join(' -> ',(@{$parents},$category));
9614: if ($allitems->{$item} eq '') {
9615: push(@{$trails},$trailstr);
9616: $allitems->{$item} = scalar(@{$trails})-1;
9617: }
9618: }
9619: return;
9620: }
9621:
1.663 raeburn 9622: =pod
9623:
9624: =item *&assign_categories_table()
9625:
9626: Create a datatable for display of hierarchical categories in a domain,
9627: with checkboxes to allow a course to be categorized.
9628:
9629: Inputs:
9630:
9631: cathash - reference to hash of categories defined for the domain (from
9632: configuration.db)
9633:
9634: currcat - scalar with an & separated list of categories assigned to a course.
9635:
9636: Returns: $output (markup to be displayed)
9637:
9638: =cut
9639:
9640: sub assign_categories_table {
9641: my ($cathash,$currcat) = @_;
9642: my $output;
9643: if (ref($cathash) eq 'HASH') {
9644: my (@cats,@trails,%allitems,%idx,@jsarray,@path,$maxdepth);
9645: &extract_categories($cathash,\@cats,\@trails,\%allitems,\%idx,\@jsarray);
9646: $maxdepth = scalar(@cats);
9647: if (@cats > 0) {
9648: my $itemcount = 0;
9649: if (ref($cats[0]) eq 'ARRAY') {
9650: $output = &Apache::loncommon::start_data_table();
9651: my @currcategories;
9652: if ($currcat ne '') {
9653: @currcategories = split('&',$currcat);
9654: }
9655: for (my $i=0; $i<@{$cats[0]}; $i++) {
9656: my $parent = $cats[0][$i];
9657: my $css_class = $itemcount%2?' class="LC_odd_row"':'';
9658: next if ($parent eq 'instcode');
9659: my $item = &escape($parent).'::0';
9660: my $checked = '';
9661: if (@currcategories > 0) {
9662: if (grep(/^\Q$item\E$/,@currcategories)) {
1.772 bisitz 9663: $checked = ' checked="checked"';
1.663 raeburn 9664: }
9665: }
1.675 raeburn 9666: $output .= '<tr '.$css_class.'><td><span class="LC_nobreak">'.
9667: '<input type="checkbox" name="usecategory" value="'.
9668: $item.'"'.$checked.' />'.$parent.'</span>'.
9669: '<input type="hidden" name="catname" value="'.$parent.'" /></td>';
1.663 raeburn 9670: my $depth = 1;
9671: push(@path,$parent);
9672: $output .= &assign_category_rows($itemcount,\@cats,$depth,$parent,\@path,\@currcategories);
9673: pop(@path);
9674: $output .= '</tr><tr><td colspan="'.$maxdepth.'" class="LC_row_separator"></td></tr>';
9675: $itemcount ++;
9676: }
9677: $output .= &Apache::loncommon::end_data_table();
9678: }
9679: }
9680: }
9681: return $output;
9682: }
9683:
9684: =pod
9685:
9686: =item *&assign_category_rows()
9687:
9688: Create a datatable row for display of nested categories in a domain,
9689: with checkboxes to allow a course to be categorized,called recursively.
9690:
9691: Inputs:
9692:
9693: itemcount - track row number for alternating colors
9694:
9695: cats - reference to array of arrays/hashes which encapsulates hierarchy of
9696: categories and subcategories.
9697:
9698: depth - current depth in hierarchy of categories and sub-categories - 0 indexed.
9699:
9700: parent - parent of current category item
9701:
9702: path - Array containing all categories back up through the hierarchy from the
9703: current category to the top level.
9704:
9705: currcategories - reference to array of current categories assigned to the course
9706:
9707: Returns: $output (markup to be displayed).
9708:
9709: =cut
9710:
9711: sub assign_category_rows {
9712: my ($itemcount,$cats,$depth,$parent,$path,$currcategories) = @_;
9713: my ($text,$name,$item,$chgstr);
9714: if (ref($cats) eq 'ARRAY') {
9715: my $maxdepth = scalar(@{$cats});
9716: if (ref($cats->[$depth]) eq 'HASH') {
9717: if (ref($cats->[$depth]{$parent}) eq 'ARRAY') {
9718: my $numchildren = @{$cats->[$depth]{$parent}};
9719: my $css_class = $itemcount%2?' class="LC_odd_row"':'';
9720: $text .= '<td><table class="LC_datatable">';
9721: for (my $j=0; $j<$numchildren; $j++) {
9722: $name = $cats->[$depth]{$parent}[$j];
9723: $item = &escape($name).':'.&escape($parent).':'.$depth;
9724: my $deeper = $depth+1;
9725: my $checked = '';
9726: if (ref($currcategories) eq 'ARRAY') {
9727: if (@{$currcategories} > 0) {
9728: if (grep(/^\Q$item\E$/,@{$currcategories})) {
1.772 bisitz 9729: $checked = ' checked="checked"';
1.663 raeburn 9730: }
9731: }
9732: }
1.664 raeburn 9733: $text .= '<tr><td><span class="LC_nobreak"><label>'.
9734: '<input type="checkbox" name="usecategory" value="'.
1.675 raeburn 9735: $item.'"'.$checked.' />'.$name.'</label></span>'.
9736: '<input type="hidden" name="catname" value="'.$name.'" />'.
9737: '</td><td>';
1.663 raeburn 9738: if (ref($path) eq 'ARRAY') {
9739: push(@{$path},$name);
9740: $text .= &assign_category_rows($itemcount,$cats,$deeper,$name,$path,$currcategories);
9741: pop(@{$path});
9742: }
9743: $text .= '</td></tr>';
9744: }
9745: $text .= '</table></td>';
9746: }
9747: }
9748: }
9749: return $text;
9750: }
9751:
1.655 raeburn 9752: ############################################################
9753: ############################################################
9754:
9755:
1.443 albertel 9756: sub commit_customrole {
1.664 raeburn 9757: my ($udom,$uname,$url,$three,$four,$five,$start,$end,$context) = @_;
1.630 raeburn 9758: my $output = &mt('Assigning custom role').' "'.$five.'" by '.$four.':'.$three.' in '.$url.
1.443 albertel 9759: ($start?', '.&mt('starting').' '.localtime($start):'').
9760: ($end?', ending '.localtime($end):'').': <b>'.
9761: &Apache::lonnet::assigncustomrole(
1.664 raeburn 9762: $udom,$uname,$url,$three,$four,$five,$end,$start,undef,undef,$context).
1.443 albertel 9763: '</b><br />';
9764: return $output;
9765: }
9766:
9767: sub commit_standardrole {
1.541 raeburn 9768: my ($udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context) = @_;
9769: my ($output,$logmsg,$linefeed);
9770: if ($context eq 'auto') {
9771: $linefeed = "\n";
9772: } else {
9773: $linefeed = "<br />\n";
9774: }
1.443 albertel 9775: if ($three eq 'st') {
1.541 raeburn 9776: my $result = &commit_studentrole(\$logmsg,$udom,$uname,$url,$three,$start,$end,
9777: $one,$two,$sec,$context);
9778: if (($result =~ /^error/) || ($result eq 'not_in_class') ||
1.626 raeburn 9779: ($result eq 'unknown_course') || ($result eq 'refused')) {
9780: $output = $logmsg.' '.&mt('Error: ').$result."\n";
1.443 albertel 9781: } else {
1.541 raeburn 9782: $output = $logmsg.$linefeed.&mt('Assigning').' '.$three.' in '.$url.
1.443 albertel 9783: ($start?', '.&mt('starting').' '.localtime($start):'').
1.541 raeburn 9784: ($end?', '.&mt('ending').' '.localtime($end):'').': ';
9785: if ($context eq 'auto') {
9786: $output .= $result.$linefeed.&mt('Add to classlist').': ok';
9787: } else {
9788: $output .= '<b>'.$result.'</b>'.$linefeed.
9789: &mt('Add to classlist').': <b>ok</b>';
9790: }
9791: $output .= $linefeed;
1.443 albertel 9792: }
9793: } else {
9794: $output = &mt('Assigning').' '.$three.' in '.$url.
9795: ($start?', '.&mt('starting').' '.localtime($start):'').
1.541 raeburn 9796: ($end?', '.&mt('ending').' '.localtime($end):'').': ';
1.652 raeburn 9797: my $result = &Apache::lonnet::assignrole($udom,$uname,$url,$three,$end,$start,'','',$context);
1.541 raeburn 9798: if ($context eq 'auto') {
9799: $output .= $result.$linefeed;
9800: } else {
9801: $output .= '<b>'.$result.'</b>'.$linefeed;
9802: }
1.443 albertel 9803: }
9804: return $output;
9805: }
9806:
9807: sub commit_studentrole {
1.541 raeburn 9808: my ($logmsg,$udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context) = @_;
1.626 raeburn 9809: my ($result,$linefeed,$oldsecurl,$newsecurl);
1.541 raeburn 9810: if ($context eq 'auto') {
9811: $linefeed = "\n";
9812: } else {
9813: $linefeed = '<br />'."\n";
9814: }
1.443 albertel 9815: if (defined($one) && defined($two)) {
9816: my $cid=$one.'_'.$two;
9817: my $oldsec=&Apache::lonnet::getsection($udom,$uname,$cid);
9818: my $secchange = 0;
9819: my $expire_role_result;
9820: my $modify_section_result;
1.628 raeburn 9821: if ($oldsec ne '-1') {
9822: if ($oldsec ne $sec) {
1.443 albertel 9823: $secchange = 1;
1.628 raeburn 9824: my $now = time;
1.443 albertel 9825: my $uurl='/'.$cid;
9826: $uurl=~s/\_/\//g;
9827: if ($oldsec) {
9828: $uurl.='/'.$oldsec;
9829: }
1.626 raeburn 9830: $oldsecurl = $uurl;
1.628 raeburn 9831: $expire_role_result =
1.652 raeburn 9832: &Apache::lonnet::assignrole($udom,$uname,$uurl,'st',$now,'','',$context);
1.628 raeburn 9833: if ($env{'request.course.sec'} ne '') {
9834: if ($expire_role_result eq 'refused') {
9835: my @roles = ('st');
9836: my @statuses = ('previous');
9837: my @roledoms = ($one);
9838: my $withsec = 1;
9839: my %roleshash =
9840: &Apache::lonnet::get_my_roles($uname,$udom,'userroles',
9841: \@statuses,\@roles,\@roledoms,$withsec);
9842: if (defined ($roleshash{$two.':'.$one.':st:'.$oldsec})) {
9843: my ($oldstart,$oldend) =
9844: split(':',$roleshash{$two.':'.$one.':st:'.$oldsec});
9845: if ($oldend > 0 && $oldend <= $now) {
9846: $expire_role_result = 'ok';
9847: }
9848: }
9849: }
9850: }
1.443 albertel 9851: $result = $expire_role_result;
9852: }
9853: }
9854: if (($expire_role_result eq 'ok') || ($secchange == 0)) {
1.652 raeburn 9855: $modify_section_result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,'','',$cid,'',$context);
1.443 albertel 9856: if ($modify_section_result =~ /^ok/) {
9857: if ($secchange == 1) {
1.628 raeburn 9858: if ($sec eq '') {
9859: $$logmsg .= &mt('Section for [_1] switched from (possibly expired) old section: [_2] to student role without a section.',$uname,$oldsec).$linefeed;
9860: } else {
9861: $$logmsg .= &mt('Section for [_1] switched from (possibly expired) old section: [_2] to new section: [_3].',$uname,$oldsec,$sec).$linefeed;
9862: }
1.443 albertel 9863: } elsif ($oldsec eq '-1') {
1.628 raeburn 9864: if ($sec eq '') {
9865: $$logmsg .= &mt('New student role without a section for [_1] in course [_2].',$uname,$cid).$linefeed;
9866: } else {
9867: $$logmsg .= &mt('New student role for [_1] in section [_2] in course [_3].',$uname,$sec,$cid).$linefeed;
9868: }
1.443 albertel 9869: } else {
1.628 raeburn 9870: if ($sec eq '') {
9871: $$logmsg .= &mt('Student [_1] assigned to course [_2] without a section.',$uname,$cid).$linefeed;
9872: } else {
9873: $$logmsg .= &mt('Student [_1] assigned to section [_2] in course [_3].',$uname,$sec,$cid).$linefeed;
9874: }
1.443 albertel 9875: }
9876: } else {
1.628 raeburn 9877: if ($secchange) {
9878: $$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;
9879: } else {
9880: $$logmsg .= &mt('Error when attempting to modify role for [_1] for section: "[_2]" in course [_3] -error:',$uname,$sec,$cid).' '.$modify_section_result.$linefeed;
9881: }
1.443 albertel 9882: }
9883: $result = $modify_section_result;
9884: } elsif ($secchange == 1) {
1.628 raeburn 9885: if ($oldsec eq '') {
9886: $$logmsg .= &mt('Error when attempting to expire existing role without a section for [_1] in course [_3] -error: ',$uname,$cid).' '.$expire_role_result.$linefeed;
9887: } else {
9888: $$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;
9889: }
1.626 raeburn 9890: if ($expire_role_result eq 'refused') {
9891: my $newsecurl = '/'.$cid;
9892: $newsecurl =~ s/\_/\//g;
9893: if ($sec ne '') {
9894: $newsecurl.='/'.$sec;
9895: }
9896: if (&Apache::lonnet::allowed('cst',$newsecurl) && !(&Apache::lonnet::allowed('cst',$oldsecurl))) {
9897: if ($sec eq '') {
9898: $$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;
9899: } else {
9900: $$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;
9901: }
9902: }
9903: }
1.443 albertel 9904: }
9905: } else {
1.626 raeburn 9906: $$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 9907: $result = "error: incomplete course id\n";
9908: }
9909: return $result;
9910: }
9911:
9912: ############################################################
9913: ############################################################
9914:
1.566 albertel 9915: sub check_clone {
1.578 raeburn 9916: my ($args,$linefeed) = @_;
1.566 albertel 9917: my $cloneid='/'.$args->{'clonedomain'}.'/'.$args->{'clonecourse'};
9918: my ($clonecrsudom,$clonecrsunum)= &LONCAPA::split_courseid($cloneid);
9919: my $clonehome=&Apache::lonnet::homeserver($clonecrsunum,$clonecrsudom);
9920: my $clonemsg;
9921: my $can_clone = 0;
9922:
9923: if ($clonehome eq 'no_host') {
1.578 raeburn 9924: $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 9925: } else {
9926: my %clonedesc = &Apache::lonnet::coursedescription($cloneid,{'one_time' => 1});
1.882 raeburn 9927: if (($env{'request.role.domain'} eq $args->{'clonedomain'}) &&
9928: (&Apache::lonnet::allowed('ccc',$env{'request.role.domain'}))) {
1.566 albertel 9929: $can_clone = 1;
9930: } else {
9931: my %clonehash = &Apache::lonnet::get('environment',['cloners'],
9932: $args->{'clonedomain'},$args->{'clonecourse'});
9933: my @cloners = split(/,/,$clonehash{'cloners'});
1.578 raeburn 9934: if (grep(/^\*$/,@cloners)) {
9935: $can_clone = 1;
9936: } elsif (grep(/^\*\:\Q$args->{'ccdomain'}\E$/,@cloners)) {
9937: $can_clone = 1;
9938: } else {
9939: my %roleshash =
9940: &Apache::lonnet::get_my_roles($args->{'ccuname'},
9941: $args->{'ccdomain'},
9942: 'userroles',['active'],['cc'],
9943: [$args->{'clonedomain'}]);
9944: if (($roleshash{$args->{'clonecourse'}.':'.$args->{'clonedomain'}.':cc'}) || (grep(/^\Q$args->{'ccuname'}\E:\Q$args->{'ccdomain'}\E$/,@cloners))) {
9945: $can_clone = 1;
9946: } else {
9947: $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'});
9948: }
1.566 albertel 9949: }
1.578 raeburn 9950: }
1.566 albertel 9951: }
9952: return ($can_clone, $clonemsg, $cloneid, $clonehome);
9953: }
9954:
1.444 albertel 9955: sub construct_course {
1.885 raeburn 9956: my ($args,$logmsg,$courseid,$crsudom,$crsunum,$udom,$uname,$context,$cnum,$category) = @_;
1.444 albertel 9957: my $outcome;
1.541 raeburn 9958: my $linefeed = '<br />'."\n";
9959: if ($context eq 'auto') {
9960: $linefeed = "\n";
9961: }
1.566 albertel 9962:
9963: #
9964: # Are we cloning?
9965: #
9966: my ($can_clone, $clonemsg, $cloneid, $clonehome);
9967: if (($args->{'clonecourse'}) && ($args->{'clonedomain'})) {
1.578 raeburn 9968: ($can_clone, $clonemsg, $cloneid, $clonehome) = &check_clone($args,$linefeed);
1.566 albertel 9969: if ($context ne 'auto') {
1.578 raeburn 9970: if ($clonemsg ne '') {
9971: $clonemsg = '<span class="LC_error">'.$clonemsg.'</span>';
9972: }
1.566 albertel 9973: }
9974: $outcome .= $clonemsg.$linefeed;
9975:
9976: if (!$can_clone) {
9977: return (0,$outcome);
9978: }
9979: }
9980:
1.444 albertel 9981: #
9982: # Open course
9983: #
9984: my $crstype = lc($args->{'crstype'});
9985: my %cenv=();
9986: $$courseid=&Apache::lonnet::createcourse($args->{'course_domain'},
9987: $args->{'cdescr'},
9988: $args->{'curl'},
9989: $args->{'course_home'},
9990: $args->{'nonstandard'},
9991: $args->{'crscode'},
9992: $args->{'ccuname'}.':'.
9993: $args->{'ccdomain'},
1.882 raeburn 9994: $args->{'crstype'},
1.885 raeburn 9995: $cnum,$context,$category);
1.444 albertel 9996:
9997: # Note: The testing routines depend on this being output; see
9998: # Utils::Course. This needs to at least be output as a comment
9999: # if anyone ever decides to not show this, and Utils::Course::new
10000: # will need to be suitably modified.
1.541 raeburn 10001: $outcome .= &mt('New LON-CAPA [_1] ID: [_2]',$crstype,$$courseid).$linefeed;
1.444 albertel 10002: #
10003: # Check if created correctly
10004: #
1.479 albertel 10005: ($$crsudom,$$crsunum)= &LONCAPA::split_courseid($$courseid);
1.444 albertel 10006: my $crsuhome=&Apache::lonnet::homeserver($$crsunum,$$crsudom);
1.541 raeburn 10007: $outcome .= &mt('Created on').': '.$crsuhome.$linefeed;
1.566 albertel 10008:
1.444 albertel 10009: #
1.566 albertel 10010: # Do the cloning
10011: #
10012: if ($can_clone && $cloneid) {
10013: $clonemsg = &mt('Cloning [_1] from [_2]',$crstype,$clonehome);
10014: if ($context ne 'auto') {
10015: $clonemsg = '<span class="LC_success">'.$clonemsg.'</span>';
10016: }
10017: $outcome .= $clonemsg.$linefeed;
10018: my %oldcenv=&Apache::lonnet::dump('environment',$$crsudom,$$crsunum);
1.444 albertel 10019: # Copy all files
1.637 www 10020: &Apache::lonclonecourse::copycoursefiles($cloneid,$$courseid,$args->{'datemode'},$args->{'dateshift'});
1.444 albertel 10021: # Restore URL
1.566 albertel 10022: $cenv{'url'}=$oldcenv{'url'};
1.444 albertel 10023: # Restore title
1.566 albertel 10024: $cenv{'description'}=$oldcenv{'description'};
1.444 albertel 10025: # Mark as cloned
1.566 albertel 10026: $cenv{'clonedfrom'}=$cloneid;
1.638 www 10027: # Need to clone grading mode
10028: my %newenv=&Apache::lonnet::get('environment',['grading'],$$crsudom,$$crsunum);
10029: $cenv{'grading'}=$newenv{'grading'};
10030: # Do not clone these environment entries
10031: &Apache::lonnet::del('environment',
10032: ['default_enrollment_start_date',
10033: 'default_enrollment_end_date',
10034: 'question.email',
10035: 'policy.email',
10036: 'comment.email',
10037: 'pch.users.denied',
1.725 raeburn 10038: 'plc.users.denied',
10039: 'hidefromcat',
10040: 'categories'],
1.638 www 10041: $$crsudom,$$crsunum);
1.444 albertel 10042: }
1.566 albertel 10043:
1.444 albertel 10044: #
10045: # Set environment (will override cloned, if existing)
10046: #
10047: my @sections = ();
10048: my @xlists = ();
10049: if ($args->{'crstype'}) {
10050: $cenv{'type'}=$args->{'crstype'};
10051: }
10052: if ($args->{'crsid'}) {
10053: $cenv{'courseid'}=$args->{'crsid'};
10054: }
10055: if ($args->{'crscode'}) {
10056: $cenv{'internal.coursecode'}=$args->{'crscode'};
10057: }
10058: if ($args->{'crsquota'} ne '') {
10059: $cenv{'internal.coursequota'}=$args->{'crsquota'};
10060: } else {
10061: $cenv{'internal.coursequota'}=$args->{'crsquota'} = 20;
10062: }
10063: if ($args->{'ccuname'}) {
10064: $cenv{'internal.courseowner'} = $args->{'ccuname'}.
10065: ':'.$args->{'ccdomain'};
10066: } else {
10067: $cenv{'internal.courseowner'} = $args->{'curruser'};
10068: }
10069: my @badclasses = (); # Used to accumulate sections/crosslistings that did not pass classlist access check for course owner.
10070: if ($args->{'crssections'}) {
10071: $cenv{'internal.sectionnums'} = '';
10072: if ($args->{'crssections'} =~ m/,/) {
10073: @sections = split/,/,$args->{'crssections'};
10074: } else {
10075: $sections[0] = $args->{'crssections'};
10076: }
10077: if (@sections > 0) {
10078: foreach my $item (@sections) {
10079: my ($sec,$gp) = split/:/,$item;
10080: my $class = $args->{'crscode'}.$sec;
10081: my $addcheck = &Apache::lonnet::auto_new_course($$crsunum,$$crsudom,$class,$cenv{'internal.courseowner'});
10082: $cenv{'internal.sectionnums'} .= $item.',';
10083: unless ($addcheck eq 'ok') {
10084: push @badclasses, $class;
10085: }
10086: }
10087: $cenv{'internal.sectionnums'} =~ s/,$//;
10088: }
10089: }
10090: # do not hide course coordinator from staff listing,
10091: # even if privileged
10092: $cenv{'nothideprivileged'}=$args->{'ccuname'}.':'.$args->{'ccdomain'};
10093: # add crosslistings
10094: if ($args->{'crsxlist'}) {
10095: $cenv{'internal.crosslistings'}='';
10096: if ($args->{'crsxlist'} =~ m/,/) {
10097: @xlists = split/,/,$args->{'crsxlist'};
10098: } else {
10099: $xlists[0] = $args->{'crsxlist'};
10100: }
10101: if (@xlists > 0) {
10102: foreach my $item (@xlists) {
10103: my ($xl,$gp) = split/:/,$item;
10104: my $addcheck = &Apache::lonnet::auto_new_course($$crsunum,$$crsudom,$xl,$cenv{'internal.courseowner'});
10105: $cenv{'internal.crosslistings'} .= $item.',';
10106: unless ($addcheck eq 'ok') {
10107: push @badclasses, $xl;
10108: }
10109: }
10110: $cenv{'internal.crosslistings'} =~ s/,$//;
10111: }
10112: }
10113: if ($args->{'autoadds'}) {
10114: $cenv{'internal.autoadds'}=$args->{'autoadds'};
10115: }
10116: if ($args->{'autodrops'}) {
10117: $cenv{'internal.autodrops'}=$args->{'autodrops'};
10118: }
10119: # check for notification of enrollment changes
10120: my @notified = ();
10121: if ($args->{'notify_owner'}) {
10122: if ($args->{'ccuname'} ne '') {
10123: push(@notified,$args->{'ccuname'}.':'.$args->{'ccdomain'});
10124: }
10125: }
10126: if ($args->{'notify_dc'}) {
10127: if ($uname ne '') {
1.630 raeburn 10128: push(@notified,$uname.':'.$udom);
1.444 albertel 10129: }
10130: }
10131: if (@notified > 0) {
10132: my $notifylist;
10133: if (@notified > 1) {
10134: $notifylist = join(',',@notified);
10135: } else {
10136: $notifylist = $notified[0];
10137: }
10138: $cenv{'internal.notifylist'} = $notifylist;
10139: }
10140: if (@badclasses > 0) {
10141: my %lt=&Apache::lonlocal::texthash(
10142: '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',
10143: 'dnhr' => 'does not have rights to access enrollment in these classes',
10144: 'adby' => 'as determined by the policies of your institution on access to official classlists'
10145: );
1.541 raeburn 10146: my $badclass_msg = $cenv{'internal.courseowner'}.') - '.$lt{'dnhr'}.
10147: ' ('.$lt{'adby'}.')';
10148: if ($context eq 'auto') {
10149: $outcome .= $badclass_msg.$linefeed;
1.566 albertel 10150: $outcome .= '<div class="LC_warning">'.$badclass_msg.$linefeed.'<ul>'."\n";
1.541 raeburn 10151: foreach my $item (@badclasses) {
10152: if ($context eq 'auto') {
10153: $outcome .= " - $item\n";
10154: } else {
10155: $outcome .= "<li>$item</li>\n";
10156: }
10157: }
10158: if ($context eq 'auto') {
10159: $outcome .= $linefeed;
10160: } else {
1.566 albertel 10161: $outcome .= "</ul><br /><br /></div>\n";
1.541 raeburn 10162: }
10163: }
1.444 albertel 10164: }
10165: if ($args->{'no_end_date'}) {
10166: $args->{'endaccess'} = 0;
10167: }
10168: $cenv{'internal.autostart'}=$args->{'enrollstart'};
10169: $cenv{'internal.autoend'}=$args->{'enrollend'};
10170: $cenv{'default_enrollment_start_date'}=$args->{'startaccess'};
10171: $cenv{'default_enrollment_end_date'}=$args->{'endaccess'};
10172: if ($args->{'showphotos'}) {
10173: $cenv{'internal.showphotos'}=$args->{'showphotos'};
10174: }
10175: $cenv{'internal.authtype'} = $args->{'authtype'};
10176: $cenv{'internal.autharg'} = $args->{'autharg'};
10177: if ( ($cenv{'internal.authtype'} =~ /^krb/) && ($cenv{'internal.autoadds'} == 1)) {
10178: if (! defined($cenv{'internal.autharg'}) || $cenv{'internal.autharg'} eq '') {
1.541 raeburn 10179: 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');
10180: if ($context eq 'auto') {
10181: $outcome .= $krb_msg;
10182: } else {
1.566 albertel 10183: $outcome .= '<span class="LC_error">'.$krb_msg.'</span>';
1.541 raeburn 10184: }
10185: $outcome .= $linefeed;
1.444 albertel 10186: }
10187: }
10188: if (($args->{'ccdomain'}) && ($args->{'ccuname'})) {
10189: if ($args->{'setpolicy'}) {
10190: $cenv{'policy.email'}=$args->{'ccuname'}.':'.$args->{'ccdomain'};
10191: }
10192: if ($args->{'setcontent'}) {
10193: $cenv{'question.email'}=$args->{'ccuname'}.':'.$args->{'ccdomain'};
10194: }
10195: }
10196: if ($args->{'reshome'}) {
10197: $cenv{'reshome'}=$args->{'reshome'}.'/';
10198: $cenv{'reshome'}=~s/\/+$/\//;
10199: }
10200: #
10201: # course has keyed access
10202: #
10203: if ($args->{'setkeys'}) {
10204: $cenv{'keyaccess'}='yes';
10205: }
10206: # if specified, key authority is not course, but user
10207: # only active if keyaccess is yes
10208: if ($args->{'keyauth'}) {
1.487 albertel 10209: my ($user,$domain) = split(':',$args->{'keyauth'});
10210: $user = &LONCAPA::clean_username($user);
10211: $domain = &LONCAPA::clean_username($domain);
1.488 foxr 10212: if ($user ne '' && $domain ne '') {
1.487 albertel 10213: $cenv{'keyauth'}=$user.':'.$domain;
1.444 albertel 10214: }
10215: }
10216:
10217: if ($args->{'disresdis'}) {
10218: $cenv{'pch.roles.denied'}='st';
10219: }
10220: if ($args->{'disablechat'}) {
10221: $cenv{'plc.roles.denied'}='st';
10222: }
10223:
10224: # Record we've not yet viewed the Course Initialization Helper for this
10225: # course
10226: $cenv{'course.helper.not.run'} = 1;
10227: #
10228: # Use new Randomseed
10229: #
10230: $cenv{'rndseed'}=&Apache::lonnet::latest_rnd_algorithm_id();;
10231: $cenv{'receiptalg'}=&Apache::lonnet::latest_receipt_algorithm_id();;
10232: #
10233: # The encryption code and receipt prefix for this course
10234: #
10235: $cenv{'internal.encseed'}=$Apache::lonnet::perlvar{'lonReceipt'}.$$.time.int(rand(9999));
10236: $cenv{'internal.encpref'}=100+int(9*rand(99));
10237: #
10238: # By default, use standard grading
10239: if (!defined($cenv{'grading'})) { $cenv{'grading'} = 'standard'; }
10240:
1.541 raeburn 10241: $outcome .= $linefeed.&mt('Setting environment').': '.
10242: &Apache::lonnet::put('environment',\%cenv,$$crsudom,$$crsunum).$linefeed;
1.444 albertel 10243: #
10244: # Open all assignments
10245: #
10246: if ($args->{'openall'}) {
10247: my $storeunder=$$crsudom.'_'.$$crsunum.'.0.opendate';
10248: my %storecontent = ($storeunder => time,
10249: $storeunder.'.type' => 'date_start');
10250:
10251: $outcome .= &mt('Opening all assignments').': '.&Apache::lonnet::cput
1.541 raeburn 10252: ('resourcedata',\%storecontent,$$crsudom,$$crsunum).$linefeed;
1.444 albertel 10253: }
10254: #
10255: # Set first page
10256: #
10257: unless (($args->{'nonstandard'}) || ($args->{'firstres'} eq 'blank')
10258: || ($cloneid)) {
1.445 albertel 10259: use LONCAPA::map;
1.444 albertel 10260: $outcome .= &mt('Setting first resource').': ';
1.445 albertel 10261:
10262: my $map = '/uploaded/'.$$crsudom.'/'.$$crsunum.'/default.sequence';
10263: my ($errtext,$fatal)=&LONCAPA::map::mapread($map);
10264:
1.444 albertel 10265: $outcome .= ($fatal?$errtext:'read ok').' - ';
10266: my $title; my $url;
10267: if ($args->{'firstres'} eq 'syl') {
1.690 bisitz 10268: $title=&mt('Syllabus');
1.444 albertel 10269: $url='/public/'.$$crsudom.'/'.$$crsunum.'/syllabus';
10270: } else {
1.690 bisitz 10271: $title=&mt('Navigate Contents');
1.444 albertel 10272: $url='/adm/navmaps';
10273: }
1.445 albertel 10274:
10275: $LONCAPA::map::resources[1]=$title.':'.$url.':false:start:res';
10276: (my $outtext,$errtext) = &LONCAPA::map::storemap($map,1);
10277:
10278: if ($errtext) { $fatal=2; }
1.541 raeburn 10279: $outcome .= ($fatal?$errtext:'write ok').$linefeed;
1.444 albertel 10280: }
1.566 albertel 10281:
10282: return (1,$outcome);
1.444 albertel 10283: }
10284:
10285: ############################################################
10286: ############################################################
10287:
1.378 raeburn 10288: sub course_type {
10289: my ($cid) = @_;
10290: if (!defined($cid)) {
10291: $cid = $env{'request.course.id'};
10292: }
1.404 albertel 10293: if (defined($env{'course.'.$cid.'.type'})) {
10294: return $env{'course.'.$cid.'.type'};
1.378 raeburn 10295: } else {
10296: return 'Course';
1.377 raeburn 10297: }
10298: }
1.156 albertel 10299:
1.406 raeburn 10300: sub group_term {
10301: my $crstype = &course_type();
10302: my %names = (
10303: 'Course' => 'group',
1.865 raeburn 10304: 'Community' => 'group',
1.406 raeburn 10305: );
10306: return $names{$crstype};
10307: }
10308:
1.902 raeburn 10309: sub course_types {
10310: my @types = ('official','unofficial','community');
10311: my %typename = (
10312: official => 'Official course',
10313: unofficial => 'Unofficial course',
10314: community => 'Community',
10315: );
10316: return (\@types,\%typename);
10317: }
10318:
1.156 albertel 10319: sub icon {
10320: my ($file)=@_;
1.505 albertel 10321: my $curfext = lc((split(/\./,$file))[-1]);
1.168 albertel 10322: my $iconname=$Apache::lonnet::perlvar{'lonIconsURL'}.'/unknown.gif';
1.156 albertel 10323: my $embstyle = &Apache::loncommon::fileembstyle($curfext);
1.168 albertel 10324: if (!(!defined($embstyle) || $embstyle eq 'unk' || $embstyle eq 'hdn')) {
10325: if (-e $Apache::lonnet::perlvar{'lonDocRoot'}.'/'.
10326: $Apache::lonnet::perlvar{'lonIconsURL'}.'/'.
10327: $curfext.".gif") {
10328: $iconname=$Apache::lonnet::perlvar{'lonIconsURL'}.'/'.
10329: $curfext.".gif";
10330: }
10331: }
1.249 albertel 10332: return &lonhttpdurl($iconname);
1.154 albertel 10333: }
1.84 albertel 10334:
1.575 albertel 10335: sub lonhttpdurl {
1.692 www 10336: #
10337: # Had been used for "small fry" static images on separate port 8080.
10338: # Modify here if lightweight http functionality desired again.
10339: # Currently eliminated due to increasing firewall issues.
10340: #
1.575 albertel 10341: my ($url)=@_;
1.692 www 10342: return $url;
1.215 albertel 10343: }
10344:
1.213 albertel 10345: sub connection_aborted {
10346: my ($r)=@_;
10347: $r->print(" ");$r->rflush();
10348: my $c = $r->connection;
10349: return $c->aborted();
10350: }
10351:
1.221 foxr 10352: # Escapes strings that may have embedded 's that will be put into
1.222 foxr 10353: # strings as 'strings'.
10354: sub escape_single {
1.221 foxr 10355: my ($input) = @_;
1.223 albertel 10356: $input =~ s/\\/\\\\/g; # Escape the \'s..(must be first)>
1.221 foxr 10357: $input =~ s/\'/\\\'/g; # Esacpe the 's....
10358: return $input;
10359: }
1.223 albertel 10360:
1.222 foxr 10361: # Same as escape_single, but escape's "'s This
10362: # can be used for "strings"
10363: sub escape_double {
10364: my ($input) = @_;
10365: $input =~ s/\\/\\\\/g; # Escape the /'s..(must be first)>
10366: $input =~ s/\"/\\\"/g; # Esacpe the "s....
10367: return $input;
10368: }
1.223 albertel 10369:
1.222 foxr 10370: # Escapes the last element of a full URL.
10371: sub escape_url {
10372: my ($url) = @_;
1.238 raeburn 10373: my @urlslices = split(/\//, $url,-1);
1.369 www 10374: my $lastitem = &escape(pop(@urlslices));
1.223 albertel 10375: return join('/',@urlslices).'/'.$lastitem;
1.222 foxr 10376: }
1.462 albertel 10377:
1.820 raeburn 10378: sub compare_arrays {
10379: my ($arrayref1,$arrayref2) = @_;
10380: my (@difference,%count);
10381: @difference = ();
10382: %count = ();
10383: if ((ref($arrayref1) eq 'ARRAY') && (ref($arrayref2) eq 'ARRAY')) {
10384: foreach my $element (@{$arrayref1}, @{$arrayref2}) { $count{$element}++; }
10385: foreach my $element (keys(%count)) {
10386: if ($count{$element} == 1) {
10387: push(@difference,$element);
10388: }
10389: }
10390: }
10391: return @difference;
10392: }
10393:
1.817 bisitz 10394: # -------------------------------------------------------- Initialize user login
1.462 albertel 10395: sub init_user_environment {
1.463 albertel 10396: my ($r, $username, $domain, $authhost, $form, $args) = @_;
1.462 albertel 10397: my $lonids=$Apache::lonnet::perlvar{'lonIDsDir'};
10398:
10399: my $public=($username eq 'public' && $domain eq 'public');
10400:
10401: # See if old ID present, if so, remove
10402:
10403: my ($filename,$cookie,$userroles);
10404: my $now=time;
10405:
10406: if ($public) {
10407: my $max_public=100;
10408: my $oldest;
10409: my $oldest_time=0;
10410: for(my $next=1;$next<=$max_public;$next++) {
10411: if (-e $lonids."/publicuser_$next.id") {
10412: my $mtime=(stat($lonids."/publicuser_$next.id"))[9];
10413: if ($mtime<$oldest_time || !$oldest_time) {
10414: $oldest_time=$mtime;
10415: $oldest=$next;
10416: }
10417: } else {
10418: $cookie="publicuser_$next";
10419: last;
10420: }
10421: }
10422: if (!$cookie) { $cookie="publicuser_$oldest"; }
10423: } else {
1.463 albertel 10424: # if this isn't a robot, kill any existing non-robot sessions
10425: if (!$args->{'robot'}) {
10426: opendir(DIR,$lonids);
10427: while ($filename=readdir(DIR)) {
10428: if ($filename=~/^$username\_\d+\_$domain\_$authhost\.id$/) {
10429: unlink($lonids.'/'.$filename);
10430: }
1.462 albertel 10431: }
1.463 albertel 10432: closedir(DIR);
1.462 albertel 10433: }
10434: # Give them a new cookie
1.463 albertel 10435: my $id = ($args->{'robot'} ? 'robot'.$args->{'robot'}
1.684 www 10436: : $now.$$.int(rand(10000)));
1.463 albertel 10437: $cookie="$username\_$id\_$domain\_$authhost";
1.462 albertel 10438:
10439: # Initialize roles
10440:
10441: $userroles=&Apache::lonnet::rolesinit($domain,$username,$authhost);
10442: }
10443: # ------------------------------------ Check browser type and MathML capability
10444:
10445: my ($httpbrowser,$clientbrowser,$clientversion,$clientmathml,
10446: $clientunicode,$clientos) = &decode_user_agent($r);
10447:
10448: # ------------------------------------------------------------- Get environment
10449:
10450: my %userenv = &Apache::lonnet::dump('environment',$domain,$username);
10451: my ($tmp) = keys(%userenv);
10452: if ($tmp !~ /^(con_lost|error|no_such_host)/i) {
10453: # default remote control to off
10454: if ($userenv{'remote'} ne 'on') { $userenv{'remote'} = 'off'; }
10455: } else {
10456: undef(%userenv);
10457: }
10458: if (($userenv{'interface'}) && (!$form->{'interface'})) {
10459: $form->{'interface'}=$userenv{'interface'};
10460: }
10461: $env{'environment.remote'}=$userenv{'remote'};
10462: if ($userenv{'texengine'} eq 'ttm') { $clientmathml=1; }
10463:
10464: # --------------- Do not trust query string to be put directly into environment
1.817 bisitz 10465: foreach my $option ('interface','localpath','localres') {
10466: $form->{$option}=~s/[\n\r\=]//gs;
1.462 albertel 10467: }
10468: # --------------------------------------------------------- Write first profile
10469:
10470: {
10471: my %initial_env =
10472: ("user.name" => $username,
10473: "user.domain" => $domain,
10474: "user.home" => $authhost,
10475: "browser.type" => $clientbrowser,
10476: "browser.version" => $clientversion,
10477: "browser.mathml" => $clientmathml,
10478: "browser.unicode" => $clientunicode,
10479: "browser.os" => $clientos,
10480: "server.domain" => $Apache::lonnet::perlvar{'lonDefDomain'},
10481: "request.course.fn" => '',
10482: "request.course.uri" => '',
10483: "request.course.sec" => '',
10484: "request.role" => 'cm',
10485: "request.role.adv" => $env{'user.adv'},
10486: "request.host" => $ENV{'REMOTE_ADDR'},);
10487:
10488: if ($form->{'localpath'}) {
10489: $initial_env{"browser.localpath"} = $form->{'localpath'};
10490: $initial_env{"browser.localres"} = $form->{'localres'};
10491: }
10492:
10493: if ($public) {
10494: $initial_env{"environment.remote"} = "off";
10495: }
10496: if ($form->{'interface'}) {
10497: $form->{'interface'}=~s/\W//gs;
10498: $initial_env{"browser.interface"} = $form->{'interface'};
10499: $env{'browser.interface'}=$form->{'interface'};
10500: }
10501:
1.724 raeburn 10502: foreach my $tool ('aboutme','blog','portfolio') {
10503: $userenv{'availabletools.'.$tool} =
10504: &Apache::lonnet::usertools_access($username,$domain,$tool,'reload');
10505: }
10506:
1.864 raeburn 10507: foreach my $crstype ('official','unofficial','community') {
1.765 raeburn 10508: $userenv{'canrequest.'.$crstype} =
10509: &Apache::lonnet::usertools_access($username,$domain,$crstype,
10510: 'reload','requestcourses');
10511: }
10512:
1.462 albertel 10513: $env{'user.environment'} = "$lonids/$cookie.id";
10514:
10515: if (tie(my %disk_env,'GDBM_File',"$lonids/$cookie.id",
10516: &GDBM_WRCREAT(),0640)) {
10517: &_add_to_env(\%disk_env,\%initial_env);
10518: &_add_to_env(\%disk_env,\%userenv,'environment.');
10519: &_add_to_env(\%disk_env,$userroles);
1.463 albertel 10520: if (ref($args->{'extra_env'})) {
10521: &_add_to_env(\%disk_env,$args->{'extra_env'});
10522: }
1.462 albertel 10523: untie(%disk_env);
10524: } else {
1.705 tempelho 10525: &Apache::lonnet::logthis("<span style=\"color:blue;\">WARNING: ".
10526: 'Could not create environment storage in lonauth: '.$!.'</span>');
1.462 albertel 10527: return 'error: '.$!;
10528: }
10529: }
10530: $env{'request.role'}='cm';
10531: $env{'request.role.adv'}=$env{'user.adv'};
10532: $env{'browser.type'}=$clientbrowser;
10533:
10534: return $cookie;
10535:
10536: }
10537:
10538: sub _add_to_env {
10539: my ($idf,$env_data,$prefix) = @_;
1.676 raeburn 10540: if (ref($env_data) eq 'HASH') {
10541: while (my ($key,$value) = each(%$env_data)) {
10542: $idf->{$prefix.$key} = $value;
10543: $env{$prefix.$key} = $value;
10544: }
1.462 albertel 10545: }
10546: }
10547:
1.685 tempelho 10548: # --- Get the symbolic name of a problem and the url
10549: sub get_symb {
10550: my ($request,$silent) = @_;
1.726 raeburn 10551: (my $url=$env{'form.url'}) =~ s-^https?\://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;
1.685 tempelho 10552: my $symb=($env{'form.symb'} ne '' ? $env{'form.symb'} : (&Apache::lonnet::symbread($url)));
10553: if ($symb eq '') {
10554: if (!$silent) {
10555: $request->print("Unable to handle ambiguous references:$url:.");
10556: return ();
10557: }
10558: }
10559: &Apache::lonenc::check_decrypt(\$symb);
10560: return ($symb);
10561: }
10562:
10563: # --------------------------------------------------------------Get annotation
10564:
10565: sub get_annotation {
10566: my ($symb,$enc) = @_;
10567:
10568: my $key = $symb;
10569: if (!$enc) {
10570: $key =
10571: &Apache::lonnet::clutter((&Apache::lonnet::decode_symb($symb))[2]);
10572: }
10573: my %annotation=&Apache::lonnet::get('nohist_annotations',[$key]);
10574: return $annotation{$key};
10575: }
10576:
10577: sub clean_symb {
1.731 raeburn 10578: my ($symb,$delete_enc) = @_;
1.685 tempelho 10579:
10580: &Apache::lonenc::check_decrypt(\$symb);
10581: my $enc = $env{'request.enc'};
1.731 raeburn 10582: if ($delete_enc) {
1.730 raeburn 10583: delete($env{'request.enc'});
10584: }
1.685 tempelho 10585:
10586: return ($symb,$enc);
10587: }
1.462 albertel 10588:
1.41 ng 10589: =pod
10590:
10591: =back
10592:
1.112 bowersj2 10593: =cut
1.41 ng 10594:
1.112 bowersj2 10595: 1;
10596: __END__;
1.41 ng 10597:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>