Annotation of loncom/interface/loncommon.pm, revision 1.1075.2.94
1.10 albertel 1: # The LearningOnline Network with CAPA
1.1 albertel 2: # a pile of common routines
1.10 albertel 3: #
1.1075.2.94! raeburn 4: # $Id: loncommon.pm,v 1.1075.2.93 2015/04/20 11:48:27 raeburn Exp $
1.10 albertel 5: #
6: # Copyright Michigan State University Board of Trustees
7: #
8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
9: #
10: # LON-CAPA is free software; you can redistribute it and/or modify
11: # it under the terms of the GNU General Public License as published by
12: # the Free Software Foundation; either version 2 of the License, or
13: # (at your option) any later version.
14: #
15: # LON-CAPA is distributed in the hope that it will be useful,
16: # but WITHOUT ANY WARRANTY; without even the implied warranty of
17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18: # GNU General Public License for more details.
19: #
20: # You should have received a copy of the GNU General Public License
21: # along with LON-CAPA; if not, write to the Free Software
22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23: #
24: # /home/httpd/html/adm/gpl.txt
25: #
26: # http://www.lon-capa.org/
27: #
1.1 albertel 28:
29: # Makes a table out of the previous attempts
1.2 albertel 30: # Inputs result_from_symbread, user, domain, course_id
1.16 harris41 31: # Reads in non-network-related .tab files
1.1 albertel 32:
1.35 matthew 33: # POD header:
34:
1.45 matthew 35: =pod
36:
1.35 matthew 37: =head1 NAME
38:
39: Apache::loncommon - pile of common routines
40:
41: =head1 SYNOPSIS
42:
1.112 bowersj2 43: Common routines for manipulating connections, student answers,
44: domains, common Javascript fragments, etc.
1.35 matthew 45:
1.112 bowersj2 46: =head1 OVERVIEW
1.35 matthew 47:
1.112 bowersj2 48: A collection of commonly used subroutines that don't have a natural
49: home anywhere else. This collection helps remove
1.35 matthew 50: redundancy from other modules and increase efficiency of memory usage.
51:
52: =cut
53:
54: # End of POD header
1.1 albertel 55: package Apache::loncommon;
56:
57: use strict;
1.258 albertel 58: use Apache::lonnet;
1.46 matthew 59: use GDBM_File;
1.51 www 60: use POSIX qw(strftime mktime);
1.82 www 61: use Apache::lonmenu();
1.498 albertel 62: use Apache::lonenc();
1.117 www 63: use Apache::lonlocal;
1.685 tempelho 64: use Apache::lonnet();
1.139 matthew 65: use HTML::Entities;
1.334 albertel 66: use Apache::lonhtmlcommon();
67: use Apache::loncoursedata();
1.344 albertel 68: use Apache::lontexconvert();
1.444 albertel 69: use Apache::lonclonecourse();
1.1075.2.25 raeburn 70: use Apache::lonuserutils();
1.1075.2.27 raeburn 71: use Apache::lonuserstate();
1.1075.2.69 raeburn 72: use Apache::courseclassifier();
1.479 albertel 73: use LONCAPA qw(:DEFAULT :match);
1.657 raeburn 74: use DateTime::TimeZone;
1.687 raeburn 75: use DateTime::Locale::Catalog;
1.1075.2.94! raeburn 76: use Encode();
1.1075.2.14 raeburn 77: use Authen::Captcha;
78: use Captcha::reCAPTCHA;
1.1075.2.64 raeburn 79: use Crypt::DES;
80: use DynaLoader; # for Crypt::DES version
1.117 www 81:
1.517 raeburn 82: # ---------------------------------------------- Designs
83: use vars qw(%defaultdesign);
84:
1.22 www 85: my $readit;
86:
1.517 raeburn 87:
1.157 matthew 88: ##
89: ## Global Variables
90: ##
1.46 matthew 91:
1.643 foxr 92:
93: # ----------------------------------------------- SSI with retries:
94: #
95:
96: =pod
97:
1.648 raeburn 98: =head1 Server Side include with retries:
1.643 foxr 99:
100: =over 4
101:
1.648 raeburn 102: =item * &ssi_with_retries(resource,retries form)
1.643 foxr 103:
104: Performs an ssi with some number of retries. Retries continue either
105: until the result is ok or until the retry count supplied by the
106: caller is exhausted.
107:
108: Inputs:
1.648 raeburn 109:
110: =over 4
111:
1.643 foxr 112: resource - Identifies the resource to insert.
1.648 raeburn 113:
1.643 foxr 114: retries - Count of the number of retries allowed.
1.648 raeburn 115:
1.643 foxr 116: form - Hash that identifies the rendering options.
117:
1.648 raeburn 118: =back
119:
120: Returns:
121:
122: =over 4
123:
1.643 foxr 124: content - The content of the response. If retries were exhausted this is empty.
1.648 raeburn 125:
1.643 foxr 126: response - The response from the last attempt (which may or may not have been successful.
127:
1.648 raeburn 128: =back
129:
130: =back
131:
1.643 foxr 132: =cut
133:
134: sub ssi_with_retries {
135: my ($resource, $retries, %form) = @_;
136:
137:
138: my $ok = 0; # True if we got a good response.
139: my $content;
140: my $response;
141:
142: # Try to get the ssi done. within the retries count:
143:
144: do {
145: ($content, $response) = &Apache::lonnet::ssi($resource, %form);
146: $ok = $response->is_success;
1.650 www 147: if (!$ok) {
148: &Apache::lonnet::logthis("Failed ssi_with_retries on $resource: ".$response->is_success.', '.$response->code.', '.$response->message);
149: }
1.643 foxr 150: $retries--;
151: } while (!$ok && ($retries > 0));
152:
153: if (!$ok) {
154: $content = ''; # On error return an empty content.
155: }
156: return ($content, $response);
157:
158: }
159:
160:
161:
1.20 www 162: # ----------------------------------------------- Filetypes/Languages/Copyright
1.12 harris41 163: my %language;
1.124 www 164: my %supported_language;
1.1048 foxr 165: my %latex_language; # For choosing hyphenation in <transl..>
166: my %latex_language_bykey; # for choosing hyphenation from metadata
1.12 harris41 167: my %cprtag;
1.192 taceyjo1 168: my %scprtag;
1.351 www 169: my %fe; my %fd; my %fm;
1.41 ng 170: my %category_extensions;
1.12 harris41 171:
1.46 matthew 172: # ---------------------------------------------- Thesaurus variables
1.144 matthew 173: #
174: # %Keywords:
175: # A hash used by &keyword to determine if a word is considered a keyword.
176: # $thesaurus_db_file
177: # Scalar containing the full path to the thesaurus database.
1.46 matthew 178:
179: my %Keywords;
180: my $thesaurus_db_file;
181:
1.144 matthew 182: #
183: # Initialize values from language.tab, copyright.tab, filetypes.tab,
184: # thesaurus.tab, and filecategories.tab.
185: #
1.18 www 186: BEGIN {
1.46 matthew 187: # Variable initialization
188: $thesaurus_db_file = $Apache::lonnet::perlvar{'lonTabDir'}."/thesaurus.db";
189: #
1.22 www 190: unless ($readit) {
1.12 harris41 191: # ------------------------------------------------------------------- languages
192: {
1.158 raeburn 193: my $langtabfile = $Apache::lonnet::perlvar{'lonTabDir'}.
194: '/language.tab';
195: if ( open(my $fh,"<$langtabfile") ) {
1.356 albertel 196: while (my $line = <$fh>) {
197: next if ($line=~/^\#/);
198: chomp($line);
1.1048 foxr 199: my ($key,$two,$country,$three,$enc,$val,$sup,$latex)=(split(/\t/,$line));
1.158 raeburn 200: $language{$key}=$val.' - '.$enc;
201: if ($sup) {
202: $supported_language{$key}=$sup;
203: }
1.1048 foxr 204: if ($latex) {
205: $latex_language_bykey{$key} = $latex;
206: $latex_language{$two} = $latex;
207: }
1.158 raeburn 208: }
209: close($fh);
210: }
1.12 harris41 211: }
212: # ------------------------------------------------------------------ copyrights
213: {
1.158 raeburn 214: my $copyrightfile = $Apache::lonnet::perlvar{'lonIncludes'}.
215: '/copyright.tab';
216: if ( open (my $fh,"<$copyrightfile") ) {
1.356 albertel 217: while (my $line = <$fh>) {
218: next if ($line=~/^\#/);
219: chomp($line);
220: my ($key,$val)=(split(/\s+/,$line,2));
1.158 raeburn 221: $cprtag{$key}=$val;
222: }
223: close($fh);
224: }
1.12 harris41 225: }
1.351 www 226: # ----------------------------------------------------------- source copyrights
1.192 taceyjo1 227: {
228: my $sourcecopyrightfile = $Apache::lonnet::perlvar{'lonIncludes'}.
229: '/source_copyright.tab';
230: if ( open (my $fh,"<$sourcecopyrightfile") ) {
1.356 albertel 231: while (my $line = <$fh>) {
232: next if ($line =~ /^\#/);
233: chomp($line);
234: my ($key,$val)=(split(/\s+/,$line,2));
1.192 taceyjo1 235: $scprtag{$key}=$val;
236: }
237: close($fh);
238: }
239: }
1.63 www 240:
1.517 raeburn 241: # -------------------------------------------------------------- default domain designs
1.63 www 242: my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors';
1.517 raeburn 243: my $designfile = $designdir.'/default.tab';
244: if ( open (my $fh,"<$designfile") ) {
245: while (my $line = <$fh>) {
246: next if ($line =~ /^\#/);
247: chomp($line);
248: my ($key,$val)=(split(/\=/,$line));
249: if ($val) { $defaultdesign{$key}=$val; }
250: }
251: close($fh);
1.63 www 252: }
253:
1.15 harris41 254: # ------------------------------------------------------------- file categories
255: {
1.158 raeburn 256: my $categoryfile = $Apache::lonnet::perlvar{'lonTabDir'}.
257: '/filecategories.tab';
258: if ( open (my $fh,"<$categoryfile") ) {
1.356 albertel 259: while (my $line = <$fh>) {
260: next if ($line =~ /^\#/);
261: chomp($line);
262: my ($extension,$category)=(split(/\s+/,$line,2));
1.158 raeburn 263: push @{$category_extensions{lc($category)}},$extension;
264: }
265: close($fh);
266: }
267:
1.15 harris41 268: }
1.12 harris41 269: # ------------------------------------------------------------------ file types
270: {
1.158 raeburn 271: my $typesfile = $Apache::lonnet::perlvar{'lonTabDir'}.
272: '/filetypes.tab';
273: if ( open (my $fh,"<$typesfile") ) {
1.356 albertel 274: while (my $line = <$fh>) {
275: next if ($line =~ /^\#/);
276: chomp($line);
277: my ($ending,$emb,$mime,$descr)=split(/\s+/,$line,4);
1.158 raeburn 278: if ($descr ne '') {
279: $fe{$ending}=lc($emb);
280: $fd{$ending}=$descr;
1.351 www 281: if ($mime ne 'unk') { $fm{$ending}=$mime; }
1.158 raeburn 282: }
283: }
284: close($fh);
285: }
1.12 harris41 286: }
1.22 www 287: &Apache::lonnet::logthis(
1.705 tempelho 288: "<span style='color:yellow;'>INFO: Read file types</span>");
1.22 www 289: $readit=1;
1.46 matthew 290: } # end of unless($readit)
1.32 matthew 291:
292: }
1.112 bowersj2 293:
1.42 matthew 294: ###############################################################
295: ## HTML and Javascript Helper Functions ##
296: ###############################################################
297:
298: =pod
299:
1.112 bowersj2 300: =head1 HTML and Javascript Functions
1.42 matthew 301:
1.112 bowersj2 302: =over 4
303:
1.648 raeburn 304: =item * &browser_and_searcher_javascript()
1.112 bowersj2 305:
306: X<browsing, javascript>X<searching, javascript>Returns a string
307: containing javascript with two functions, C<openbrowser> and
308: C<opensearcher>. Returned string does not contain E<lt>scriptE<gt>
309: tags.
1.42 matthew 310:
1.648 raeburn 311: =item * &openbrowser(formname,elementname,only,omit) [javascript]
1.42 matthew 312:
313: inputs: formname, elementname, only, omit
314:
315: formname and elementname indicate the name of the html form and name of
316: the element that the results of the browsing selection are to be placed in.
317:
318: Specifying 'only' will restrict the browser to displaying only files
1.185 www 319: with the given extension. Can be a comma separated list.
1.42 matthew 320:
321: Specifying 'omit' will restrict the browser to NOT displaying files
1.185 www 322: with the given extension. Can be a comma separated list.
1.42 matthew 323:
1.648 raeburn 324: =item * &opensearcher(formname,elementname) [javascript]
1.42 matthew 325:
326: Inputs: formname, elementname
327:
328: formname and elementname specify the name of the html form and the name
329: of the element the selection from the search results will be placed in.
1.542 raeburn 330:
1.42 matthew 331: =cut
332:
333: sub browser_and_searcher_javascript {
1.199 albertel 334: my ($mode)=@_;
335: if (!defined($mode)) { $mode='edit'; }
1.453 albertel 336: my $resurl=&escape_single(&lastresurl());
1.42 matthew 337: return <<END;
1.219 albertel 338: // <!-- BEGIN LON-CAPA Internal
1.50 matthew 339: var editbrowser = null;
1.135 albertel 340: function openbrowser(formname,elementname,only,omit,titleelement) {
1.170 www 341: var url = '$resurl/?';
1.42 matthew 342: if (editbrowser == null) {
343: url += 'launch=1&';
344: }
345: url += 'catalogmode=interactive&';
1.199 albertel 346: url += 'mode=$mode&';
1.611 albertel 347: url += 'inhibitmenu=yes&';
1.42 matthew 348: url += 'form=' + formname + '&';
349: if (only != null) {
350: url += 'only=' + only + '&';
1.217 albertel 351: } else {
352: url += 'only=&';
353: }
1.42 matthew 354: if (omit != null) {
355: url += 'omit=' + omit + '&';
1.217 albertel 356: } else {
357: url += 'omit=&';
358: }
1.135 albertel 359: if (titleelement != null) {
360: url += 'titleelement=' + titleelement + '&';
1.217 albertel 361: } else {
362: url += 'titleelement=&';
363: }
1.42 matthew 364: url += 'element=' + elementname + '';
365: var title = 'Browser';
1.435 albertel 366: var options = 'scrollbars=1,resizable=1,menubar=0,toolbar=1,location=1';
1.42 matthew 367: options += ',width=700,height=600';
368: editbrowser = open(url,title,options,'1');
369: editbrowser.focus();
370: }
371: var editsearcher;
1.135 albertel 372: function opensearcher(formname,elementname,titleelement) {
1.42 matthew 373: var url = '/adm/searchcat?';
374: if (editsearcher == null) {
375: url += 'launch=1&';
376: }
377: url += 'catalogmode=interactive&';
1.199 albertel 378: url += 'mode=$mode&';
1.42 matthew 379: url += 'form=' + formname + '&';
1.135 albertel 380: if (titleelement != null) {
381: url += 'titleelement=' + titleelement + '&';
1.217 albertel 382: } else {
383: url += 'titleelement=&';
384: }
1.42 matthew 385: url += 'element=' + elementname + '';
386: var title = 'Search';
1.435 albertel 387: var options = 'scrollbars=1,resizable=1,menubar=0,toolbar=1,location=1';
1.42 matthew 388: options += ',width=700,height=600';
389: editsearcher = open(url,title,options,'1');
390: editsearcher.focus();
391: }
1.219 albertel 392: // END LON-CAPA Internal -->
1.42 matthew 393: END
1.170 www 394: }
395:
396: sub lastresurl {
1.258 albertel 397: if ($env{'environment.lastresurl'}) {
398: return $env{'environment.lastresurl'}
1.170 www 399: } else {
400: return '/res';
401: }
402: }
403:
404: sub storeresurl {
405: my $resurl=&Apache::lonnet::clutter(shift);
406: unless ($resurl=~/^\/res/) { return 0; }
407: $resurl=~s/\/$//;
408: &Apache::lonnet::put('environment',{'lastresurl' => $resurl});
1.646 raeburn 409: &Apache::lonnet::appenv({'environment.lastresurl' => $resurl});
1.170 www 410: return 1;
1.42 matthew 411: }
412:
1.74 www 413: sub studentbrowser_javascript {
1.111 www 414: unless (
1.258 albertel 415: (($env{'request.course.id'}) &&
1.302 albertel 416: (&Apache::lonnet::allowed('srm',$env{'request.course.id'})
417: || &Apache::lonnet::allowed('srm',$env{'request.course.id'}.
418: '/'.$env{'request.course.sec'})
419: ))
1.258 albertel 420: || ($env{'request.role'}=~/^(au|dc|su)/)
1.111 www 421: ) { return ''; }
1.74 www 422: return (<<'ENDSTDBRW');
1.776 bisitz 423: <script type="text/javascript" language="Javascript">
1.824 bisitz 424: // <![CDATA[
1.74 www 425: var stdeditbrowser;
1.999 www 426: function openstdbrowser(formname,uname,udom,clicker,roleflag,ignorefilter,courseadvonly) {
1.74 www 427: var url = '/adm/pickstudent?';
428: var filter;
1.558 albertel 429: if (!ignorefilter) {
430: eval('filter=document.'+formname+'.'+uname+'.value;');
431: }
1.74 www 432: if (filter != null) {
433: if (filter != '') {
434: url += 'filter='+filter+'&';
435: }
436: }
437: url += 'form=' + formname + '&unameelement='+uname+
1.999 www 438: '&udomelement='+udom+
439: '&clicker='+clicker;
1.111 www 440: if (roleflag) { url+="&roles=1"; }
1.793 raeburn 441: if (courseadvonly) { url+="&courseadvonly=1"; }
1.102 www 442: var title = 'Student_Browser';
1.74 www 443: var options = 'scrollbars=1,resizable=1,menubar=0';
444: options += ',width=700,height=600';
445: stdeditbrowser = open(url,title,options,'1');
446: stdeditbrowser.focus();
447: }
1.824 bisitz 448: // ]]>
1.74 www 449: </script>
450: ENDSTDBRW
451: }
1.42 matthew 452:
1.1003 www 453: sub resourcebrowser_javascript {
454: unless ($env{'request.course.id'}) { return ''; }
1.1004 www 455: return (<<'ENDRESBRW');
1.1003 www 456: <script type="text/javascript" language="Javascript">
457: // <![CDATA[
458: var reseditbrowser;
1.1004 www 459: function openresbrowser(formname,reslink) {
1.1005 www 460: var url = '/adm/pickresource?form='+formname+'&reslink='+reslink;
1.1003 www 461: var title = 'Resource_Browser';
462: var options = 'scrollbars=1,resizable=1,menubar=0';
1.1005 www 463: options += ',width=700,height=500';
1.1004 www 464: reseditbrowser = open(url,title,options,'1');
465: reseditbrowser.focus();
1.1003 www 466: }
467: // ]]>
468: </script>
1.1004 www 469: ENDRESBRW
1.1003 www 470: }
471:
1.74 www 472: sub selectstudent_link {
1.999 www 473: my ($form,$unameele,$udomele,$courseadvonly,$clickerid)=@_;
474: my $callargs = "'".&Apache::lonhtmlcommon::entity_encode($form)."','".
475: &Apache::lonhtmlcommon::entity_encode($unameele)."','".
476: &Apache::lonhtmlcommon::entity_encode($udomele)."'";
1.258 albertel 477: if ($env{'request.course.id'}) {
1.302 albertel 478: if (!&Apache::lonnet::allowed('srm',$env{'request.course.id'})
479: && !&Apache::lonnet::allowed('srm',$env{'request.course.id'}.
480: '/'.$env{'request.course.sec'})) {
1.111 www 481: return '';
482: }
1.999 www 483: $callargs.=",'".&Apache::lonhtmlcommon::entity_encode($clickerid)."'";
1.793 raeburn 484: if ($courseadvonly) {
485: $callargs .= ",'',1,1";
486: }
487: return '<span class="LC_nobreak">'.
488: '<a href="javascript:openstdbrowser('.$callargs.');">'.
489: &mt('Select User').'</a></span>';
1.74 www 490: }
1.258 albertel 491: if ($env{'request.role'}=~/^(au|dc|su)/) {
1.1012 www 492: $callargs .= ",'',1";
1.793 raeburn 493: return '<span class="LC_nobreak">'.
494: '<a href="javascript:openstdbrowser('.$callargs.');">'.
495: &mt('Select User').'</a></span>';
1.111 www 496: }
497: return '';
1.91 www 498: }
499:
1.1004 www 500: sub selectresource_link {
501: my ($form,$reslink,$arg)=@_;
502:
503: my $callargs = "'".&Apache::lonhtmlcommon::entity_encode($form)."','".
504: &Apache::lonhtmlcommon::entity_encode($reslink)."'";
505: unless ($env{'request.course.id'}) { return $arg; }
506: return '<span class="LC_nobreak">'.
507: '<a href="javascript:openresbrowser('.$callargs.');">'.
508: $arg.'</a></span>';
509: }
510:
511:
512:
1.653 raeburn 513: sub authorbrowser_javascript {
514: return <<"ENDAUTHORBRW";
1.776 bisitz 515: <script type="text/javascript" language="JavaScript">
1.824 bisitz 516: // <![CDATA[
1.653 raeburn 517: var stdeditbrowser;
518:
519: function openauthorbrowser(formname,udom) {
520: var url = '/adm/pickauthor?';
521: url += 'form='+formname+'&roledom='+udom;
522: var title = 'Author_Browser';
523: var options = 'scrollbars=1,resizable=1,menubar=0';
524: options += ',width=700,height=600';
525: stdeditbrowser = open(url,title,options,'1');
526: stdeditbrowser.focus();
527: }
528:
1.824 bisitz 529: // ]]>
1.653 raeburn 530: </script>
531: ENDAUTHORBRW
532: }
533:
1.91 www 534: sub coursebrowser_javascript {
1.1075.2.31 raeburn 535: my ($domainfilter,$sec_element,$formname,$role_element,$crstype,
536: $credits_element) = @_;
1.932 raeburn 537: my $wintitle = 'Course_Browser';
1.931 raeburn 538: if ($crstype eq 'Community') {
1.932 raeburn 539: $wintitle = 'Community_Browser';
1.909 raeburn 540: }
1.876 raeburn 541: my $id_functions = &javascript_index_functions();
542: my $output = '
1.776 bisitz 543: <script type="text/javascript" language="JavaScript">
1.824 bisitz 544: // <![CDATA[
1.468 raeburn 545: var stdeditbrowser;'."\n";
1.876 raeburn 546:
547: $output .= <<"ENDSTDBRW";
1.909 raeburn 548: function opencrsbrowser(formname,uname,udom,desc,extra_element,multflag,type,type_elem) {
1.91 www 549: var url = '/adm/pickcourse?';
1.895 raeburn 550: var formid = getFormIdByName(formname);
1.876 raeburn 551: var domainfilter = getDomainFromSelectbox(formname,udom);
1.128 albertel 552: if (domainfilter != null) {
553: if (domainfilter != '') {
554: url += 'domainfilter='+domainfilter+'&';
555: }
556: }
1.91 www 557: url += 'form=' + formname + '&cnumelement='+uname+
1.187 albertel 558: '&cdomelement='+udom+
559: '&cnameelement='+desc;
1.468 raeburn 560: if (extra_element !=null && extra_element != '') {
1.594 raeburn 561: if (formname == 'rolechoice' || formname == 'studentform') {
1.468 raeburn 562: url += '&roleelement='+extra_element;
563: if (domainfilter == null || domainfilter == '') {
564: url += '&domainfilter='+extra_element;
565: }
1.234 raeburn 566: }
1.468 raeburn 567: else {
568: if (formname == 'portform') {
569: url += '&setroles='+extra_element;
1.800 raeburn 570: } else {
571: if (formname == 'rules') {
572: url += '&fixeddom='+extra_element;
573: }
1.468 raeburn 574: }
575: }
1.230 raeburn 576: }
1.909 raeburn 577: if (type != null && type != '') {
578: url += '&type='+type;
579: }
580: if (type_elem != null && type_elem != '') {
581: url += '&typeelement='+type_elem;
582: }
1.872 raeburn 583: if (formname == 'ccrs') {
584: var ownername = document.forms[formid].ccuname.value;
585: var ownerdom = document.forms[formid].ccdomain.options[document.forms[formid].ccdomain.selectedIndex].value;
586: url += '&cloner='+ownername+':'+ownerdom;
587: }
1.293 raeburn 588: if (multflag !=null && multflag != '') {
589: url += '&multiple='+multflag;
590: }
1.909 raeburn 591: var title = '$wintitle';
1.91 www 592: var options = 'scrollbars=1,resizable=1,menubar=0';
593: options += ',width=700,height=600';
594: stdeditbrowser = open(url,title,options,'1');
595: stdeditbrowser.focus();
596: }
1.876 raeburn 597: $id_functions
598: ENDSTDBRW
1.1075.2.31 raeburn 599: if (($sec_element ne '') || ($role_element ne '') || ($credits_element ne '')) {
600: $output .= &setsec_javascript($sec_element,$formname,$role_element,
601: $credits_element);
1.876 raeburn 602: }
603: $output .= '
604: // ]]>
605: </script>';
606: return $output;
607: }
608:
609: sub javascript_index_functions {
610: return <<"ENDJS";
611:
612: function getFormIdByName(formname) {
613: for (var i=0;i<document.forms.length;i++) {
614: if (document.forms[i].name == formname) {
615: return i;
616: }
617: }
618: return -1;
619: }
620:
621: function getIndexByName(formid,item) {
622: for (var i=0;i<document.forms[formid].elements.length;i++) {
623: if (document.forms[formid].elements[i].name == item) {
624: return i;
625: }
626: }
627: return -1;
628: }
1.468 raeburn 629:
1.876 raeburn 630: function getDomainFromSelectbox(formname,udom) {
631: var userdom;
632: var formid = getFormIdByName(formname);
633: if (formid > -1) {
634: var domid = getIndexByName(formid,udom);
635: if (domid > -1) {
636: if (document.forms[formid].elements[domid].type == 'select-one') {
637: userdom=document.forms[formid].elements[domid].options[document.forms[formid].elements[domid].selectedIndex].value;
638: }
639: if (document.forms[formid].elements[domid].type == 'hidden') {
640: userdom=document.forms[formid].elements[domid].value;
1.468 raeburn 641: }
642: }
643: }
1.876 raeburn 644: return userdom;
645: }
646:
647: ENDJS
1.468 raeburn 648:
1.876 raeburn 649: }
650:
1.1017 raeburn 651: sub javascript_array_indexof {
1.1018 raeburn 652: return <<ENDJS;
1.1017 raeburn 653: <script type="text/javascript" language="JavaScript">
654: // <![CDATA[
655:
656: if (!Array.prototype.indexOf) {
657: Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
658: "use strict";
659: if (this === void 0 || this === null) {
660: throw new TypeError();
661: }
662: var t = Object(this);
663: var len = t.length >>> 0;
664: if (len === 0) {
665: return -1;
666: }
667: var n = 0;
668: if (arguments.length > 0) {
669: n = Number(arguments[1]);
670: if (n !== n) { // shortcut for verifying if it's NaN
671: n = 0;
672: } else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0)) {
673: n = (n > 0 || -1) * Math.floor(Math.abs(n));
674: }
675: }
676: if (n >= len) {
677: return -1;
678: }
679: var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
680: for (; k < len; k++) {
681: if (k in t && t[k] === searchElement) {
682: return k;
683: }
684: }
685: return -1;
686: }
687: }
688:
689: // ]]>
690: </script>
691:
692: ENDJS
693:
694: }
695:
1.876 raeburn 696: sub userbrowser_javascript {
697: my $id_functions = &javascript_index_functions();
698: return <<"ENDUSERBRW";
699:
1.888 raeburn 700: function openuserbrowser(formname,uname,udom,ulast,ufirst,uemail,hideudom,crsdom,caller) {
1.876 raeburn 701: var url = '/adm/pickuser?';
702: var userdom = getDomainFromSelectbox(formname,udom);
703: if (userdom != null) {
704: if (userdom != '') {
705: url += 'srchdom='+userdom+'&';
706: }
707: }
708: url += 'form=' + formname + '&unameelement='+uname+
709: '&udomelement='+udom+
710: '&ulastelement='+ulast+
711: '&ufirstelement='+ufirst+
712: '&uemailelement='+uemail+
1.881 raeburn 713: '&hideudomelement='+hideudom+
714: '&coursedom='+crsdom;
1.888 raeburn 715: if ((caller != null) && (caller != undefined)) {
716: url += '&caller='+caller;
717: }
1.876 raeburn 718: var title = 'User_Browser';
719: var options = 'scrollbars=1,resizable=1,menubar=0';
720: options += ',width=700,height=600';
721: var stdeditbrowser = open(url,title,options,'1');
722: stdeditbrowser.focus();
723: }
724:
1.888 raeburn 725: function fix_domain (formname,udom,origdom,uname) {
1.876 raeburn 726: var formid = getFormIdByName(formname);
727: if (formid > -1) {
1.888 raeburn 728: var unameid = getIndexByName(formid,uname);
1.876 raeburn 729: var domid = getIndexByName(formid,udom);
730: var hidedomid = getIndexByName(formid,origdom);
731: if (hidedomid > -1) {
732: var fixeddom = document.forms[formid].elements[hidedomid].value;
1.888 raeburn 733: var unameval = document.forms[formid].elements[unameid].value;
734: if ((fixeddom != '') && (fixeddom != undefined) && (fixeddom != null) && (unameval != '') && (unameval != undefined) && (unameval != null)) {
735: if (domid > -1) {
736: var slct = document.forms[formid].elements[domid];
737: if (slct.type == 'select-one') {
738: var i;
739: for (i=0;i<slct.length;i++) {
740: if (slct.options[i].value==fixeddom) { slct.selectedIndex=i; }
741: }
742: }
743: if (slct.type == 'hidden') {
744: slct.value = fixeddom;
1.876 raeburn 745: }
746: }
1.468 raeburn 747: }
748: }
749: }
1.876 raeburn 750: return;
751: }
752:
753: $id_functions
754: ENDUSERBRW
1.468 raeburn 755: }
756:
757: sub setsec_javascript {
1.1075.2.31 raeburn 758: my ($sec_element,$formname,$role_element,$credits_element) = @_;
1.905 raeburn 759: my (@courserolenames,@communityrolenames,$rolestr,$courserolestr,
760: $communityrolestr);
761: if ($role_element ne '') {
762: my @allroles = ('st','ta','ep','in','ad');
763: foreach my $crstype ('Course','Community') {
764: if ($crstype eq 'Community') {
765: foreach my $role (@allroles) {
766: push(@communityrolenames,&Apache::lonnet::plaintext($role,$crstype));
767: }
768: push(@communityrolenames,&Apache::lonnet::plaintext('co'));
769: } else {
770: foreach my $role (@allroles) {
771: push(@courserolenames,&Apache::lonnet::plaintext($role,$crstype));
772: }
773: push(@courserolenames,&Apache::lonnet::plaintext('cc'));
774: }
775: }
776: $rolestr = '"'.join('","',@allroles).'"';
777: $courserolestr = '"'.join('","',@courserolenames).'"';
778: $communityrolestr = '"'.join('","',@communityrolenames).'"';
779: }
1.468 raeburn 780: my $setsections = qq|
781: function setSect(sectionlist) {
1.629 raeburn 782: var sectionsArray = new Array();
783: if ((sectionlist != '') && (typeof sectionlist != "undefined")) {
784: sectionsArray = sectionlist.split(",");
785: }
1.468 raeburn 786: var numSections = sectionsArray.length;
787: document.$formname.$sec_element.length = 0;
788: if (numSections == 0) {
789: document.$formname.$sec_element.multiple=false;
790: document.$formname.$sec_element.size=1;
791: document.$formname.$sec_element.options[0] = new Option('No existing sections','',false,false)
792: } else {
793: if (numSections == 1) {
794: document.$formname.$sec_element.multiple=false;
795: document.$formname.$sec_element.size=1;
796: document.$formname.$sec_element.options[0] = new Option('Select','',true,true);
797: document.$formname.$sec_element.options[1] = new Option('No section','',false,false)
798: document.$formname.$sec_element.options[2] = new Option(sectionsArray[0],sectionsArray[0],false,false);
799: } else {
800: for (var i=0; i<numSections; i++) {
801: document.$formname.$sec_element.options[i] = new Option(sectionsArray[i],sectionsArray[i],false,false)
802: }
803: document.$formname.$sec_element.multiple=true
804: if (numSections < 3) {
805: document.$formname.$sec_element.size=numSections;
806: } else {
807: document.$formname.$sec_element.size=3;
808: }
809: document.$formname.$sec_element.options[0].selected = false
810: }
811: }
1.91 www 812: }
1.905 raeburn 813:
814: function setRole(crstype) {
1.468 raeburn 815: |;
1.905 raeburn 816: if ($role_element eq '') {
817: $setsections .= ' return;
818: }
819: ';
820: } else {
821: $setsections .= qq|
822: var elementLength = document.$formname.$role_element.length;
823: var allroles = Array($rolestr);
824: var courserolenames = Array($courserolestr);
825: var communityrolenames = Array($communityrolestr);
826: if (elementLength != undefined) {
827: if (document.$formname.$role_element.options[5].value == 'cc') {
828: if (crstype == 'Course') {
829: return;
830: } else {
831: allroles[5] = 'co';
832: for (var i=0; i<6; i++) {
833: document.$formname.$role_element.options[i].value = allroles[i];
834: document.$formname.$role_element.options[i].text = communityrolenames[i];
835: }
836: }
837: } else {
838: if (crstype == 'Community') {
839: return;
840: } else {
841: allroles[5] = 'cc';
842: for (var i=0; i<6; i++) {
843: document.$formname.$role_element.options[i].value = allroles[i];
844: document.$formname.$role_element.options[i].text = courserolenames[i];
845: }
846: }
847: }
848: }
849: return;
850: }
851: |;
852: }
1.1075.2.31 raeburn 853: if ($credits_element) {
854: $setsections .= qq|
855: function setCredits(defaultcredits) {
856: document.$formname.$credits_element.value = defaultcredits;
857: return;
858: }
859: |;
860: }
1.468 raeburn 861: return $setsections;
862: }
863:
1.91 www 864: sub selectcourse_link {
1.909 raeburn 865: my ($form,$unameele,$udomele,$desc,$extra_element,$multflag,$selecttype,
866: $typeelement) = @_;
867: my $type = $selecttype;
1.871 raeburn 868: my $linktext = &mt('Select Course');
869: if ($selecttype eq 'Community') {
1.909 raeburn 870: $linktext = &mt('Select Community');
1.906 raeburn 871: } elsif ($selecttype eq 'Course/Community') {
872: $linktext = &mt('Select Course/Community');
1.909 raeburn 873: $type = '';
1.1019 raeburn 874: } elsif ($selecttype eq 'Select') {
875: $linktext = &mt('Select');
876: $type = '';
1.871 raeburn 877: }
1.787 bisitz 878: return '<span class="LC_nobreak">'
879: ."<a href='"
880: .'javascript:opencrsbrowser("'.$form.'","'.$unameele
881: .'","'.$udomele.'","'.$desc.'","'.$extra_element
1.909 raeburn 882: .'","'.$multflag.'","'.$type.'","'.$typeelement.'");'
1.871 raeburn 883: ."'>".$linktext.'</a>'
1.787 bisitz 884: .'</span>';
1.74 www 885: }
1.42 matthew 886:
1.653 raeburn 887: sub selectauthor_link {
888: my ($form,$udom)=@_;
889: return '<a href="javascript:openauthorbrowser('."'$form','$udom'".');">'.
890: &mt('Select Author').'</a>';
891: }
892:
1.876 raeburn 893: sub selectuser_link {
1.881 raeburn 894: my ($form,$unameelem,$domelem,$lastelem,$firstelem,$emailelem,$hdomelem,
1.888 raeburn 895: $coursedom,$linktext,$caller) = @_;
1.876 raeburn 896: return '<a href="javascript:openuserbrowser('."'$form','$unameelem','$domelem',".
1.888 raeburn 897: "'$lastelem','$firstelem','$emailelem','$hdomelem','$coursedom','$caller'".
1.881 raeburn 898: ');">'.$linktext.'</a>';
1.876 raeburn 899: }
900:
1.273 raeburn 901: sub check_uncheck_jscript {
902: my $jscript = <<"ENDSCRT";
903: function checkAll(field) {
904: if (field.length > 0) {
905: for (i = 0; i < field.length; i++) {
1.1075.2.14 raeburn 906: if (!field[i].disabled) {
907: field[i].checked = true;
908: }
1.273 raeburn 909: }
910: } else {
1.1075.2.14 raeburn 911: if (!field.disabled) {
912: field.checked = true;
913: }
1.273 raeburn 914: }
915: }
916:
917: function uncheckAll(field) {
918: if (field.length > 0) {
919: for (i = 0; i < field.length; i++) {
920: field[i].checked = false ;
1.543 albertel 921: }
922: } else {
1.273 raeburn 923: field.checked = false ;
924: }
925: }
926: ENDSCRT
927: return $jscript;
928: }
929:
1.656 www 930: sub select_timezone {
1.659 raeburn 931: my ($name,$selected,$onchange,$includeempty)=@_;
932: my $output='<select name="'.$name.'" '.$onchange.'>'."\n";
933: if ($includeempty) {
934: $output .= '<option value=""';
935: if (($selected eq '') || ($selected eq 'local')) {
936: $output .= ' selected="selected" ';
937: }
938: $output .= '> </option>';
939: }
1.657 raeburn 940: my @timezones = DateTime::TimeZone->all_names;
941: foreach my $tzone (@timezones) {
942: $output.= '<option value="'.$tzone.'"';
943: if ($tzone eq $selected) {
944: $output.=' selected="selected"';
945: }
946: $output.=">$tzone</option>\n";
1.656 www 947: }
948: $output.="</select>";
949: return $output;
950: }
1.273 raeburn 951:
1.687 raeburn 952: sub select_datelocale {
953: my ($name,$selected,$onchange,$includeempty)=@_;
954: my $output='<select name="'.$name.'" '.$onchange.'>'."\n";
955: if ($includeempty) {
956: $output .= '<option value=""';
957: if ($selected eq '') {
958: $output .= ' selected="selected" ';
959: }
960: $output .= '> </option>';
961: }
962: my (@possibles,%locale_names);
963: my @locales = DateTime::Locale::Catalog::Locales;
964: foreach my $locale (@locales) {
965: if (ref($locale) eq 'HASH') {
966: my $id = $locale->{'id'};
967: if ($id ne '') {
968: my $en_terr = $locale->{'en_territory'};
969: my $native_terr = $locale->{'native_territory'};
1.695 raeburn 970: my @languages = &Apache::lonlocal::preferred_languages();
1.687 raeburn 971: if (grep(/^en$/,@languages) || !@languages) {
972: if ($en_terr ne '') {
973: $locale_names{$id} = '('.$en_terr.')';
974: } elsif ($native_terr ne '') {
975: $locale_names{$id} = $native_terr;
976: }
977: } else {
978: if ($native_terr ne '') {
979: $locale_names{$id} = $native_terr.' ';
980: } elsif ($en_terr ne '') {
981: $locale_names{$id} = '('.$en_terr.')';
982: }
983: }
1.1075.2.94! raeburn 984: $locale_names{$id} = Encode::encode('UTF-8',$locale_names{$id});
1.687 raeburn 985: push (@possibles,$id);
986: }
987: }
988: }
989: foreach my $item (sort(@possibles)) {
990: $output.= '<option value="'.$item.'"';
991: if ($item eq $selected) {
992: $output.=' selected="selected"';
993: }
994: $output.=">$item";
995: if ($locale_names{$item} ne '') {
1.1075.2.94! raeburn 996: $output.=' '.$locale_names{$item};
1.687 raeburn 997: }
998: $output.="</option>\n";
999: }
1000: $output.="</select>";
1001: return $output;
1002: }
1003:
1.792 raeburn 1004: sub select_language {
1005: my ($name,$selected,$includeempty) = @_;
1006: my %langchoices;
1007: if ($includeempty) {
1.1075.2.32 raeburn 1008: %langchoices = ('' => 'No language preference');
1.792 raeburn 1009: }
1010: foreach my $id (&languageids()) {
1011: my $code = &supportedlanguagecode($id);
1012: if ($code) {
1013: $langchoices{$code} = &plainlanguagedescription($id);
1014: }
1015: }
1.1075.2.32 raeburn 1016: %langchoices = &Apache::lonlocal::texthash(%langchoices);
1.970 raeburn 1017: return &select_form($selected,$name,\%langchoices);
1.792 raeburn 1018: }
1019:
1.42 matthew 1020: =pod
1.36 matthew 1021:
1.648 raeburn 1022: =item * &linked_select_forms(...)
1.36 matthew 1023:
1024: linked_select_forms returns a string containing a <script></script> block
1025: and html for two <select> menus. The select menus will be linked in that
1026: changing the value of the first menu will result in new values being placed
1027: in the second menu. The values in the select menu will appear in alphabetical
1.609 raeburn 1028: order unless a defined order is provided.
1.36 matthew 1029:
1030: linked_select_forms takes the following ordered inputs:
1031:
1032: =over 4
1033:
1.112 bowersj2 1034: =item * $formname, the name of the <form> tag
1.36 matthew 1035:
1.112 bowersj2 1036: =item * $middletext, the text which appears between the <select> tags
1.36 matthew 1037:
1.112 bowersj2 1038: =item * $firstdefault, the default value for the first menu
1.36 matthew 1039:
1.112 bowersj2 1040: =item * $firstselectname, the name of the first <select> tag
1.36 matthew 1041:
1.112 bowersj2 1042: =item * $secondselectname, the name of the second <select> tag
1.36 matthew 1043:
1.112 bowersj2 1044: =item * $hashref, a reference to a hash containing the data for the menus.
1.36 matthew 1045:
1.609 raeburn 1046: =item * $menuorder, the order of values in the first menu
1047:
1.1075.2.31 raeburn 1048: =item * $onchangefirst, additional javascript call to execute for an onchange
1049: event for the first <select> tag
1050:
1051: =item * $onchangesecond, additional javascript call to execute for an onchange
1052: event for the second <select> tag
1053:
1.41 ng 1054: =back
1055:
1.36 matthew 1056: Below is an example of such a hash. Only the 'text', 'default', and
1057: 'select2' keys must appear as stated. keys(%menu) are the possible
1058: values for the first select menu. The text that coincides with the
1.41 ng 1059: first menu value is given in $menu{$choice1}->{'text'}. The values
1.36 matthew 1060: and text for the second menu are given in the hash pointed to by
1061: $menu{$choice1}->{'select2'}.
1062:
1.112 bowersj2 1063: my %menu = ( A1 => { text =>"Choice A1" ,
1064: default => "B3",
1065: select2 => {
1066: B1 => "Choice B1",
1067: B2 => "Choice B2",
1068: B3 => "Choice B3",
1069: B4 => "Choice B4"
1.609 raeburn 1070: },
1071: order => ['B4','B3','B1','B2'],
1.112 bowersj2 1072: },
1073: A2 => { text =>"Choice A2" ,
1074: default => "C2",
1075: select2 => {
1076: C1 => "Choice C1",
1077: C2 => "Choice C2",
1078: C3 => "Choice C3"
1.609 raeburn 1079: },
1080: order => ['C2','C1','C3'],
1.112 bowersj2 1081: },
1082: A3 => { text =>"Choice A3" ,
1083: default => "D6",
1084: select2 => {
1085: D1 => "Choice D1",
1086: D2 => "Choice D2",
1087: D3 => "Choice D3",
1088: D4 => "Choice D4",
1089: D5 => "Choice D5",
1090: D6 => "Choice D6",
1091: D7 => "Choice D7"
1.609 raeburn 1092: },
1093: order => ['D4','D3','D2','D1','D7','D6','D5'],
1.112 bowersj2 1094: }
1095: );
1.36 matthew 1096:
1097: =cut
1098:
1099: sub linked_select_forms {
1100: my ($formname,
1101: $middletext,
1102: $firstdefault,
1103: $firstselectname,
1104: $secondselectname,
1.609 raeburn 1105: $hashref,
1106: $menuorder,
1.1075.2.31 raeburn 1107: $onchangefirst,
1108: $onchangesecond
1.36 matthew 1109: ) = @_;
1110: my $second = "document.$formname.$secondselectname";
1111: my $first = "document.$formname.$firstselectname";
1112: # output the javascript to do the changing
1113: my $result = '';
1.776 bisitz 1114: $result.='<script type="text/javascript" language="JavaScript">'."\n";
1.824 bisitz 1115: $result.="// <![CDATA[\n";
1.36 matthew 1116: $result.="var select2data = new Object();\n";
1117: $" = '","';
1118: my $debug = '';
1119: foreach my $s1 (sort(keys(%$hashref))) {
1120: $result.="select2data.d_$s1 = new Object();\n";
1121: $result.="select2data.d_$s1.def = new String('".
1122: $hashref->{$s1}->{'default'}."');\n";
1.609 raeburn 1123: $result.="select2data.d_$s1.values = new Array(";
1.36 matthew 1124: my @s2values = sort(keys( %{ $hashref->{$s1}->{'select2'} } ));
1.609 raeburn 1125: if (ref($hashref->{$s1}->{'order'}) eq 'ARRAY') {
1126: @s2values = @{$hashref->{$s1}->{'order'}};
1127: }
1.36 matthew 1128: $result.="\"@s2values\");\n";
1129: $result.="select2data.d_$s1.texts = new Array(";
1130: my @s2texts;
1131: foreach my $value (@s2values) {
1132: push @s2texts, $hashref->{$s1}->{'select2'}->{$value};
1133: }
1134: $result.="\"@s2texts\");\n";
1135: }
1136: $"=' ';
1137: $result.= <<"END";
1138:
1139: function select1_changed() {
1140: // Determine new choice
1141: var newvalue = "d_" + $first.value;
1142: // update select2
1143: var values = select2data[newvalue].values;
1144: var texts = select2data[newvalue].texts;
1145: var select2def = select2data[newvalue].def;
1146: var i;
1147: // out with the old
1148: for (i = 0; i < $second.options.length; i++) {
1149: $second.options[i] = null;
1150: }
1151: // in with the nuclear
1152: for (i=0;i<values.length; i++) {
1153: $second.options[i] = new Option(values[i]);
1.143 matthew 1154: $second.options[i].value = values[i];
1.36 matthew 1155: $second.options[i].text = texts[i];
1156: if (values[i] == select2def) {
1157: $second.options[i].selected = true;
1158: }
1159: }
1160: }
1.824 bisitz 1161: // ]]>
1.36 matthew 1162: </script>
1163: END
1164: # output the initial values for the selection lists
1.1075.2.31 raeburn 1165: $result .= "<select size=\"1\" name=\"$firstselectname\" onchange=\"select1_changed();$onchangefirst\">\n";
1.609 raeburn 1166: my @order = sort(keys(%{$hashref}));
1167: if (ref($menuorder) eq 'ARRAY') {
1168: @order = @{$menuorder};
1169: }
1170: foreach my $value (@order) {
1.36 matthew 1171: $result.=" <option value=\"$value\" ";
1.253 albertel 1172: $result.=" selected=\"selected\" " if ($value eq $firstdefault);
1.119 www 1173: $result.=">".&mt($hashref->{$value}->{'text'})."</option>\n";
1.36 matthew 1174: }
1175: $result .= "</select>\n";
1176: my %select2 = %{$hashref->{$firstdefault}->{'select2'}};
1177: $result .= $middletext;
1.1075.2.31 raeburn 1178: $result .= "<select size=\"1\" name=\"$secondselectname\"";
1179: if ($onchangesecond) {
1180: $result .= ' onchange="'.$onchangesecond.'"';
1181: }
1182: $result .= ">\n";
1.36 matthew 1183: my $seconddefault = $hashref->{$firstdefault}->{'default'};
1.609 raeburn 1184:
1185: my @secondorder = sort(keys(%select2));
1186: if (ref($hashref->{$firstdefault}->{'order'}) eq 'ARRAY') {
1187: @secondorder = @{$hashref->{$firstdefault}->{'order'}};
1188: }
1189: foreach my $value (@secondorder) {
1.36 matthew 1190: $result.=" <option value=\"$value\" ";
1.253 albertel 1191: $result.=" selected=\"selected\" " if ($value eq $seconddefault);
1.119 www 1192: $result.=">".&mt($select2{$value})."</option>\n";
1.36 matthew 1193: }
1194: $result .= "</select>\n";
1195: # return $debug;
1196: return $result;
1197: } # end of sub linked_select_forms {
1198:
1.45 matthew 1199: =pod
1.44 bowersj2 1200:
1.973 raeburn 1201: =item * &help_open_topic($topic,$text,$stayOnPage,$width,$height,$imgid)
1.44 bowersj2 1202:
1.112 bowersj2 1203: Returns a string corresponding to an HTML link to the given help
1204: $topic, where $topic corresponds to the name of a .tex file in
1205: /home/httpd/html/adm/help/tex, with underscores replaced by
1206: spaces.
1207:
1208: $text will optionally be linked to the same topic, allowing you to
1209: link text in addition to the graphic. If you do not want to link
1210: text, but wish to specify one of the later parameters, pass an
1211: empty string.
1212:
1213: $stayOnPage is a value that will be interpreted as a boolean. If true,
1214: the link will not open a new window. If false, the link will open
1215: a new window using Javascript. (Default is false.)
1216:
1217: $width and $height are optional numerical parameters that will
1218: override the width and height of the popped up window, which may
1.973 raeburn 1219: be useful for certain help topics with big pictures included.
1220:
1221: $imgid is the id of the img tag used for the help icon. This may be
1222: used in a javascript call to switch the image src. See
1223: lonhtmlcommon::htmlareaselectactive() for an example.
1.44 bowersj2 1224:
1225: =cut
1226:
1227: sub help_open_topic {
1.973 raeburn 1228: my ($topic, $text, $stayOnPage, $width, $height, $imgid) = @_;
1.48 bowersj2 1229: $text = "" if (not defined $text);
1.44 bowersj2 1230: $stayOnPage = 0 if (not defined $stayOnPage);
1.1033 www 1231: $width = 500 if (not defined $width);
1.44 bowersj2 1232: $height = 400 if (not defined $height);
1233: my $filename = $topic;
1234: $filename =~ s/ /_/g;
1235:
1.48 bowersj2 1236: my $template = "";
1237: my $link;
1.572 banghart 1238:
1.159 www 1239: $topic=~s/\W/\_/g;
1.44 bowersj2 1240:
1.572 banghart 1241: if (!$stayOnPage) {
1.1075.2.50 raeburn 1242: if ($env{'browser.mobile'}) {
1243: $link = "javascript:openMyModal('/adm/help/${filename}.hlp',$width,$height,'yes');";
1244: } else {
1245: $link = "javascript:void(open('/adm/help/${filename}.hlp', 'Help_for_$topic', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))";
1246: }
1.1037 www 1247: } elsif ($stayOnPage eq 'popup') {
1248: $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 1249: } else {
1.48 bowersj2 1250: $link = "/adm/help/${filename}.hlp";
1251: }
1252:
1253: # Add the text
1.755 neumanie 1254: if ($text ne "") {
1.763 bisitz 1255: $template.='<span class="LC_help_open_topic">'
1256: .'<a target="_top" href="'.$link.'">'
1257: .$text.'</a>';
1.48 bowersj2 1258: }
1259:
1.763 bisitz 1260: # (Always) Add the graphic
1.179 matthew 1261: my $title = &mt('Online Help');
1.667 raeburn 1262: my $helpicon=&lonhttpdurl("/adm/help/help.png");
1.973 raeburn 1263: if ($imgid ne '') {
1264: $imgid = ' id="'.$imgid.'"';
1265: }
1.763 bisitz 1266: $template.=' <a target="_top" href="'.$link.'" title="'.$title.'">'
1267: .'<img src="'.$helpicon.'" border="0"'
1268: .' alt="'.&mt('Help: [_1]',$topic).'"'
1.973 raeburn 1269: .' title="'.$title.'" style="vertical-align:middle;"'.$imgid
1.763 bisitz 1270: .' /></a>';
1271: if ($text ne "") {
1272: $template.='</span>';
1273: }
1.44 bowersj2 1274: return $template;
1275:
1.106 bowersj2 1276: }
1277:
1278: # This is a quicky function for Latex cheatsheet editing, since it
1279: # appears in at least four places
1280: sub helpLatexCheatsheet {
1.1037 www 1281: my ($topic,$text,$not_author,$stayOnPage) = @_;
1.732 raeburn 1282: my $out;
1.106 bowersj2 1283: my $addOther = '';
1.732 raeburn 1284: if ($topic) {
1.1037 www 1285: $addOther = '<span>'.&help_open_topic($topic,&mt($text),$stayOnPage, undef, 600).'</span> ';
1.763 bisitz 1286: }
1287: $out = '<span>' # Start cheatsheet
1288: .$addOther
1289: .'<span>'
1.1037 www 1290: .&help_open_topic('Greek_Symbols',&mt('Greek Symbols'),$stayOnPage,undef,600)
1.763 bisitz 1291: .'</span> <span>'
1.1037 www 1292: .&help_open_topic('Other_Symbols',&mt('Other Symbols'),$stayOnPage,undef,600)
1.763 bisitz 1293: .'</span>';
1.732 raeburn 1294: unless ($not_author) {
1.763 bisitz 1295: $out .= ' <span>'
1.1037 www 1296: .&help_open_topic('Authoring_Output_Tags',&mt('Output Tags'),$stayOnPage,undef,600)
1.1075.2.71 raeburn 1297: .'</span> <span>'
1.1075.2.78 raeburn 1298: .&help_open_topic('Authoring_Multilingual_Problems',&mt('Languages'),$stayOnPage,undef,600)
1.1075.2.71 raeburn 1299: .'</span>';
1.732 raeburn 1300: }
1.763 bisitz 1301: $out .= '</span>'; # End cheatsheet
1.732 raeburn 1302: return $out;
1.172 www 1303: }
1304:
1.430 albertel 1305: sub general_help {
1306: my $helptopic='Student_Intro';
1307: if ($env{'request.role'}=~/^(ca|au)/) {
1308: $helptopic='Authoring_Intro';
1.907 raeburn 1309: } elsif ($env{'request.role'}=~/^(cc|co)/) {
1.430 albertel 1310: $helptopic='Course_Coordination_Intro';
1.672 raeburn 1311: } elsif ($env{'request.role'}=~/^dc/) {
1312: $helptopic='Domain_Coordination_Intro';
1.430 albertel 1313: }
1314: return $helptopic;
1315: }
1316:
1317: sub update_help_link {
1318: my ($topic,$component_help,$faq,$bug,$stayOnPage) = @_;
1319: my $origurl = $ENV{'REQUEST_URI'};
1320: $origurl=~s|^/~|/priv/|;
1321: my $timestamp = time;
1322: foreach my $datum (\$topic,\$component_help,\$faq,\$bug,\$origurl) {
1323: $$datum = &escape($$datum);
1324: }
1325:
1326: my $banner_link = "/adm/helpmenu?page=banner&topic=$topic&component_help=$component_help&faq=$faq&bug=$bug&origurl=$origurl&stamp=$timestamp&stayonpage=$stayOnPage";
1327: my $output .= <<"ENDOUTPUT";
1328: <script type="text/javascript">
1.824 bisitz 1329: // <![CDATA[
1.430 albertel 1330: banner_link = '$banner_link';
1.824 bisitz 1331: // ]]>
1.430 albertel 1332: </script>
1333: ENDOUTPUT
1334: return $output;
1335: }
1336:
1337: # now just updates the help link and generates a blue icon
1.193 raeburn 1338: sub help_open_menu {
1.430 albertel 1339: my ($topic,$component_help,$faq,$bug,$stayOnPage,$width,$height,$text)
1.552 banghart 1340: = @_;
1.949 droeschl 1341: $stayOnPage = 1;
1.430 albertel 1342: my $output;
1343: if ($component_help) {
1344: if (!$text) {
1345: $output=&help_open_topic($component_help,undef,$stayOnPage,
1346: $width,$height);
1347: } else {
1348: my $help_text;
1349: $help_text=&unescape($topic);
1350: $output='<table><tr><td>'.
1351: &help_open_topic($component_help,$help_text,$stayOnPage,
1352: $width,$height).'</td></tr></table>';
1353: }
1354: }
1355: my $banner_link = &update_help_link($topic,$component_help,$faq,$bug,$stayOnPage);
1356: return $output.$banner_link;
1357: }
1358:
1359: sub top_nav_help {
1360: my ($text) = @_;
1.436 albertel 1361: $text = &mt($text);
1.1075.2.60 raeburn 1362: my $stay_on_page;
1363: unless ($env{'environment.remote'} eq 'on') {
1364: $stay_on_page = 1;
1365: }
1.1075.2.61 raeburn 1366: my ($link,$banner_link);
1367: unless ($env{'request.noversionuri'} =~ m{^/adm/helpmenu}) {
1368: $link = ($stay_on_page) ? "javascript:helpMenu('display')"
1369: : "javascript:helpMenu('open')";
1370: $banner_link = &update_help_link(undef,undef,undef,undef,$stay_on_page);
1371: }
1.201 raeburn 1372: my $title = &mt('Get help');
1.1075.2.61 raeburn 1373: if ($link) {
1374: return <<"END";
1.436 albertel 1375: $banner_link
1.1075.2.56 raeburn 1376: <a href="$link" title="$title">$text</a>
1.436 albertel 1377: END
1.1075.2.61 raeburn 1378: } else {
1379: return ' '.$text.' ';
1380: }
1.436 albertel 1381: }
1382:
1383: sub help_menu_js {
1.1075.2.52 raeburn 1384: my ($httphost) = @_;
1.949 droeschl 1385: my $stayOnPage = 1;
1.436 albertel 1386: my $width = 620;
1387: my $height = 600;
1.430 albertel 1388: my $helptopic=&general_help();
1.1075.2.52 raeburn 1389: my $details_link = $httphost.'/adm/help/'.$helptopic.'.hlp';
1.261 albertel 1390: my $nothing=&Apache::lonhtmlcommon::javascript_nothing();
1.331 albertel 1391: my $start_page =
1392: &Apache::loncommon::start_page('Help Menu', undef,
1393: {'frameset' => 1,
1394: 'js_ready' => 1,
1.1075.2.52 raeburn 1395: 'use_absolute' => $httphost,
1.331 albertel 1396: 'add_entries' => {
1397: 'border' => '0',
1.579 raeburn 1398: 'rows' => "110,*",},});
1.331 albertel 1399: my $end_page =
1400: &Apache::loncommon::end_page({'frameset' => 1,
1401: 'js_ready' => 1,});
1402:
1.436 albertel 1403: my $template .= <<"ENDTEMPLATE";
1404: <script type="text/javascript">
1.877 bisitz 1405: // <![CDATA[
1.253 albertel 1406: // <!-- BEGIN LON-CAPA Internal
1.430 albertel 1407: var banner_link = '';
1.243 raeburn 1408: function helpMenu(target) {
1409: var caller = this;
1410: if (target == 'open') {
1411: var newWindow = null;
1412: try {
1.262 albertel 1413: newWindow = window.open($nothing,"helpmenu","HEIGHT=$height,WIDTH=$width,resizable=yes,scrollbars=yes" )
1.243 raeburn 1414: }
1415: catch(error) {
1416: writeHelp(caller);
1417: return;
1418: }
1419: if (newWindow) {
1420: caller = newWindow;
1421: }
1.193 raeburn 1422: }
1.243 raeburn 1423: writeHelp(caller);
1424: return;
1425: }
1426: function writeHelp(caller) {
1.1075.2.61 raeburn 1427: caller.document.writeln('$start_page\\n<frame name="bannerframe" src="'+banner_link+'" marginwidth="0" marginheight="0" frameborder="0">\\n');
1428: caller.document.writeln('<frame name="bodyframe" src="$details_link" marginwidth="0" marginheight="0" frameborder="0">\\n$end_page');
1429: caller.document.close();
1430: caller.focus();
1.193 raeburn 1431: }
1.877 bisitz 1432: // END LON-CAPA Internal -->
1.253 albertel 1433: // ]]>
1.436 albertel 1434: </script>
1.193 raeburn 1435: ENDTEMPLATE
1436: return $template;
1437: }
1438:
1.172 www 1439: sub help_open_bug {
1440: my ($topic, $text, $stayOnPage, $width, $height) = @_;
1.258 albertel 1441: unless ($env{'user.adv'}) { return ''; }
1.172 www 1442: unless ($Apache::lonnet::perlvar{'BugzillaHost'}) { return ''; }
1443: $text = "" if (not defined $text);
1444: $stayOnPage=1;
1.184 albertel 1445: $width = 600 if (not defined $width);
1446: $height = 600 if (not defined $height);
1.172 www 1447:
1448: $topic=~s/\W+/\+/g;
1449: my $link='';
1450: my $template='';
1.379 albertel 1451: my $url=$Apache::lonnet::perlvar{'BugzillaHost'}.'enter_bug.cgi?product=LON-CAPA&bug_file_loc='.
1452: &escape($ENV{'REQUEST_URI'}).'&component='.$topic;
1.172 www 1453: if (!$stayOnPage)
1454: {
1455: $link = "javascript:void(open('$url', 'Bugzilla', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))";
1456: }
1457: else
1458: {
1459: $link = $url;
1460: }
1461: # Add the text
1462: if ($text ne "")
1463: {
1464: $template .=
1465: "<table bgcolor='#AA3333' cellspacing='1' cellpadding='1' border='0'><tr>".
1.705 tempelho 1466: "<td bgcolor='#FF5555'><a target=\"_top\" href=\"$link\"><span style=\"color:#FFFFFF;font-size:10pt;\">$text</span></a>";
1.172 www 1467: }
1468:
1469: # Add the graphic
1.179 matthew 1470: my $title = &mt('Report a Bug');
1.215 albertel 1471: my $bugicon=&lonhttpdurl("/adm/lonMisc/smallBug.gif");
1.172 www 1472: $template .= <<"ENDTEMPLATE";
1.436 albertel 1473: <a target="_top" href="$link" title="$title"><img src="$bugicon" border="0" alt="(Bug: $topic)" /></a>
1.172 www 1474: ENDTEMPLATE
1475: if ($text ne '') { $template.='</td></tr></table>' };
1476: return $template;
1477:
1478: }
1479:
1480: sub help_open_faq {
1481: my ($topic, $text, $stayOnPage, $width, $height) = @_;
1.258 albertel 1482: unless ($env{'user.adv'}) { return ''; }
1.172 www 1483: unless ($Apache::lonnet::perlvar{'FAQHost'}) { return ''; }
1484: $text = "" if (not defined $text);
1485: $stayOnPage=1;
1486: $width = 350 if (not defined $width);
1487: $height = 400 if (not defined $height);
1488:
1489: $topic=~s/\W+/\+/g;
1490: my $link='';
1491: my $template='';
1492: my $url=$Apache::lonnet::perlvar{'FAQHost'}.'/fom/cache/'.$topic.'.html';
1493: if (!$stayOnPage)
1494: {
1495: $link = "javascript:void(open('$url', 'FAQ-O-Matic', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))";
1496: }
1497: else
1498: {
1499: $link = $url;
1500: }
1501:
1502: # Add the text
1503: if ($text ne "")
1504: {
1505: $template .=
1.173 www 1506: "<table bgcolor='#337733' cellspacing='1' cellpadding='1' border='0'><tr>".
1.705 tempelho 1507: "<td bgcolor='#448844'><a target=\"_top\" href=\"$link\"><span style=\"color:#FFFFFF; font-size:10pt;\">$text</span></a>";
1.172 www 1508: }
1509:
1510: # Add the graphic
1.179 matthew 1511: my $title = &mt('View the FAQ');
1.215 albertel 1512: my $faqicon=&lonhttpdurl("/adm/lonMisc/smallFAQ.gif");
1.172 www 1513: $template .= <<"ENDTEMPLATE";
1.436 albertel 1514: <a target="_top" href="$link" title="$title"><img src="$faqicon" border="0" alt="(FAQ: $topic)" /></a>
1.172 www 1515: ENDTEMPLATE
1516: if ($text ne '') { $template.='</td></tr></table>' };
1517: return $template;
1518:
1.44 bowersj2 1519: }
1.37 matthew 1520:
1.180 matthew 1521: ###############################################################
1522: ###############################################################
1523:
1.45 matthew 1524: =pod
1525:
1.648 raeburn 1526: =item * &change_content_javascript():
1.256 matthew 1527:
1528: This and the next function allow you to create small sections of an
1529: otherwise static HTML page that you can update on the fly with
1530: Javascript, even in Netscape 4.
1531:
1532: The Javascript fragment returned by this function (no E<lt>scriptE<gt> tag)
1533: must be written to the HTML page once. It will prove the Javascript
1534: function "change(name, content)". Calling the change function with the
1535: name of the section
1536: you want to update, matching the name passed to C<changable_area>, and
1537: the new content you want to put in there, will put the content into
1538: that area.
1539:
1540: B<Note>: Netscape 4 only reserves enough space for the changable area
1541: to contain room for the original contents. You need to "make space"
1542: for whatever changes you wish to make, and be B<sure> to check your
1543: code in Netscape 4. This feature in Netscape 4 is B<not> powerful;
1544: it's adequate for updating a one-line status display, but little more.
1545: This script will set the space to 100% width, so you only need to
1546: worry about height in Netscape 4.
1547:
1548: Modern browsers are much less limiting, and if you can commit to the
1549: user not using Netscape 4, this feature may be used freely with
1550: pretty much any HTML.
1551:
1552: =cut
1553:
1554: sub change_content_javascript {
1555: # If we're on Netscape 4, we need to use Layer-based code
1.258 albertel 1556: if ($env{'browser.type'} eq 'netscape' &&
1557: $env{'browser.version'} =~ /^4\./) {
1.256 matthew 1558: return (<<NETSCAPE4);
1559: function change(name, content) {
1560: doc = document.layers[name+"___escape"].layers[0].document;
1561: doc.open();
1562: doc.write(content);
1563: doc.close();
1564: }
1565: NETSCAPE4
1566: } else {
1567: # Otherwise, we need to use semi-standards-compliant code
1568: # (technically, "innerHTML" isn't standard but the equivalent
1569: # is really scary, and every useful browser supports it
1570: return (<<DOMBASED);
1571: function change(name, content) {
1572: element = document.getElementById(name);
1573: element.innerHTML = content;
1574: }
1575: DOMBASED
1576: }
1577: }
1578:
1579: =pod
1580:
1.648 raeburn 1581: =item * &changable_area($name,$origContent):
1.256 matthew 1582:
1583: This provides a "changable area" that can be modified on the fly via
1584: the Javascript code provided in C<change_content_javascript>. $name is
1585: the name you will use to reference the area later; do not repeat the
1586: same name on a given HTML page more then once. $origContent is what
1587: the area will originally contain, which can be left blank.
1588:
1589: =cut
1590:
1591: sub changable_area {
1592: my ($name, $origContent) = @_;
1593:
1.258 albertel 1594: if ($env{'browser.type'} eq 'netscape' &&
1595: $env{'browser.version'} =~ /^4\./) {
1.256 matthew 1596: # If this is netscape 4, we need to use the Layer tag
1597: return "<ilayer width='100%' id='${name}___escape' overflow='none'><layer width='100%' id='$name' overflow='none'>$origContent</layer></ilayer>";
1598: } else {
1599: return "<span id='$name'>$origContent</span>";
1600: }
1601: }
1602:
1603: =pod
1604:
1.648 raeburn 1605: =item * &viewport_geometry_js
1.590 raeburn 1606:
1607: Provides javascript object (Geometry) which can provide information about the viewport geometry for the client browser.
1608:
1609: =cut
1610:
1611:
1612: sub viewport_geometry_js {
1613: return <<"GEOMETRY";
1614: var Geometry = {};
1615: function init_geometry() {
1616: if (Geometry.init) { return };
1617: Geometry.init=1;
1618: if (window.innerHeight) {
1619: Geometry.getViewportHeight = function() { return window.innerHeight; };
1620: Geometry.getViewportWidth = function() { return window.innerWidth; };
1621: Geometry.getHorizontalScroll = function() { return window.pageXOffset; };
1622: Geometry.getVerticalScroll = function() { return window.pageYOffset; };
1623: }
1624: else if (document.documentElement && document.documentElement.clientHeight) {
1625: Geometry.getViewportHeight =
1626: function() { return document.documentElement.clientHeight; };
1627: Geometry.getViewportWidth =
1628: function() { return document.documentElement.clientWidth; };
1629:
1630: Geometry.getHorizontalScroll =
1631: function() { return document.documentElement.scrollLeft; };
1632: Geometry.getVerticalScroll =
1633: function() { return document.documentElement.scrollTop; };
1634: }
1635: else if (document.body.clientHeight) {
1636: Geometry.getViewportHeight =
1637: function() { return document.body.clientHeight; };
1638: Geometry.getViewportWidth =
1639: function() { return document.body.clientWidth; };
1640: Geometry.getHorizontalScroll =
1641: function() { return document.body.scrollLeft; };
1642: Geometry.getVerticalScroll =
1643: function() { return document.body.scrollTop; };
1644: }
1645: }
1646:
1647: GEOMETRY
1648: }
1649:
1650: =pod
1651:
1.648 raeburn 1652: =item * &viewport_size_js()
1.590 raeburn 1653:
1654: 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.
1655:
1656: =cut
1657:
1658: sub viewport_size_js {
1659: my $geometry = &viewport_geometry_js();
1660: return <<"DIMS";
1661:
1662: $geometry
1663:
1664: function getViewportDims(width,height) {
1665: init_geometry();
1666: width.value = Geometry.getViewportWidth();
1667: height.value = Geometry.getViewportHeight();
1668: return;
1669: }
1670:
1671: DIMS
1672: }
1673:
1674: =pod
1675:
1.648 raeburn 1676: =item * &resize_textarea_js()
1.565 albertel 1677:
1678: emits the needed javascript to resize a textarea to be as big as possible
1679:
1680: creates a function resize_textrea that takes two IDs first should be
1681: the id of the element to resize, second should be the id of a div that
1682: surrounds everything that comes after the textarea, this routine needs
1683: to be attached to the <body> for the onload and onresize events.
1684:
1.648 raeburn 1685: =back
1.565 albertel 1686:
1687: =cut
1688:
1689: sub resize_textarea_js {
1.590 raeburn 1690: my $geometry = &viewport_geometry_js();
1.565 albertel 1691: return <<"RESIZE";
1692: <script type="text/javascript">
1.824 bisitz 1693: // <![CDATA[
1.590 raeburn 1694: $geometry
1.565 albertel 1695:
1.588 albertel 1696: function getX(element) {
1697: var x = 0;
1698: while (element) {
1699: x += element.offsetLeft;
1700: element = element.offsetParent;
1701: }
1702: return x;
1703: }
1704: function getY(element) {
1705: var y = 0;
1706: while (element) {
1707: y += element.offsetTop;
1708: element = element.offsetParent;
1709: }
1710: return y;
1711: }
1712:
1713:
1.565 albertel 1714: function resize_textarea(textarea_id,bottom_id) {
1715: init_geometry();
1716: var textarea = document.getElementById(textarea_id);
1717: //alert(textarea);
1718:
1.588 albertel 1719: var textarea_top = getY(textarea);
1.565 albertel 1720: var textarea_height = textarea.offsetHeight;
1721: var bottom = document.getElementById(bottom_id);
1.588 albertel 1722: var bottom_top = getY(bottom);
1.565 albertel 1723: var bottom_height = bottom.offsetHeight;
1724: var window_height = Geometry.getViewportHeight();
1.588 albertel 1725: var fudge = 23;
1.565 albertel 1726: var new_height = window_height-fudge-textarea_top-bottom_height;
1727: if (new_height < 300) {
1728: new_height = 300;
1729: }
1730: textarea.style.height=new_height+'px';
1731: }
1.824 bisitz 1732: // ]]>
1.565 albertel 1733: </script>
1734: RESIZE
1735:
1736: }
1737:
1738: =pod
1739:
1.256 matthew 1740: =head1 Excel and CSV file utility routines
1741:
1742: =cut
1743:
1744: ###############################################################
1745: ###############################################################
1746:
1747: =pod
1748:
1.1075.2.56 raeburn 1749: =over 4
1750:
1.648 raeburn 1751: =item * &csv_translate($text)
1.37 matthew 1752:
1.185 www 1753: Translate $text to allow it to be output as a 'comma separated values'
1.37 matthew 1754: format.
1755:
1756: =cut
1757:
1.180 matthew 1758: ###############################################################
1759: ###############################################################
1.37 matthew 1760: sub csv_translate {
1761: my $text = shift;
1762: $text =~ s/\"/\"\"/g;
1.209 albertel 1763: $text =~ s/\n/ /g;
1.37 matthew 1764: return $text;
1765: }
1.180 matthew 1766:
1767: ###############################################################
1768: ###############################################################
1769:
1770: =pod
1771:
1.648 raeburn 1772: =item * &define_excel_formats()
1.180 matthew 1773:
1774: Define some commonly used Excel cell formats.
1775:
1776: Currently supported formats:
1777:
1778: =over 4
1779:
1780: =item header
1781:
1782: =item bold
1783:
1784: =item h1
1785:
1786: =item h2
1787:
1788: =item h3
1789:
1.256 matthew 1790: =item h4
1791:
1792: =item i
1793:
1.180 matthew 1794: =item date
1795:
1796: =back
1797:
1798: Inputs: $workbook
1799:
1800: Returns: $format, a hash reference.
1801:
1.1057 foxr 1802:
1.180 matthew 1803: =cut
1804:
1805: ###############################################################
1806: ###############################################################
1807: sub define_excel_formats {
1808: my ($workbook) = @_;
1809: my $format;
1810: $format->{'header'} = $workbook->add_format(bold => 1,
1811: bottom => 1,
1812: align => 'center');
1813: $format->{'bold'} = $workbook->add_format(bold=>1);
1814: $format->{'h1'} = $workbook->add_format(bold=>1, size=>18);
1815: $format->{'h2'} = $workbook->add_format(bold=>1, size=>16);
1816: $format->{'h3'} = $workbook->add_format(bold=>1, size=>14);
1.255 matthew 1817: $format->{'h4'} = $workbook->add_format(bold=>1, size=>12);
1.246 matthew 1818: $format->{'i'} = $workbook->add_format(italic=>1);
1.180 matthew 1819: $format->{'date'} = $workbook->add_format(num_format=>
1.207 matthew 1820: 'mm/dd/yyyy hh:mm:ss');
1.180 matthew 1821: return $format;
1822: }
1823:
1824: ###############################################################
1825: ###############################################################
1.113 bowersj2 1826:
1827: =pod
1828:
1.648 raeburn 1829: =item * &create_workbook()
1.255 matthew 1830:
1831: Create an Excel worksheet. If it fails, output message on the
1832: request object and return undefs.
1833:
1834: Inputs: Apache request object
1835:
1836: Returns (undef) on failure,
1837: Excel worksheet object, scalar with filename, and formats
1838: from &Apache::loncommon::define_excel_formats on success
1839:
1840: =cut
1841:
1842: ###############################################################
1843: ###############################################################
1844: sub create_workbook {
1845: my ($r) = @_;
1846: #
1847: # Create the excel spreadsheet
1848: my $filename = '/prtspool/'.
1.258 albertel 1849: $env{'user.name'}.'_'.$env{'user.domain'}.'_'.
1.255 matthew 1850: time.'_'.rand(1000000000).'.xls';
1851: my $workbook = Spreadsheet::WriteExcel->new('/home/httpd'.$filename);
1852: if (! defined($workbook)) {
1853: $r->log_error("Error creating excel spreadsheet $filename: $!");
1.928 bisitz 1854: $r->print(
1855: '<p class="LC_error">'
1856: .&mt('Problems occurred in creating the new Excel file.')
1857: .' '.&mt('This error has been logged.')
1858: .' '.&mt('Please alert your LON-CAPA administrator.')
1859: .'</p>'
1860: );
1.255 matthew 1861: return (undef);
1862: }
1863: #
1.1014 foxr 1864: $workbook->set_tempdir(LONCAPA::tempdir());
1.255 matthew 1865: #
1866: my $format = &Apache::loncommon::define_excel_formats($workbook);
1867: return ($workbook,$filename,$format);
1868: }
1869:
1870: ###############################################################
1871: ###############################################################
1872:
1873: =pod
1874:
1.648 raeburn 1875: =item * &create_text_file()
1.113 bowersj2 1876:
1.542 raeburn 1877: Create a file to write to and eventually make available to the user.
1.256 matthew 1878: If file creation fails, outputs an error message on the request object and
1879: return undefs.
1.113 bowersj2 1880:
1.256 matthew 1881: Inputs: Apache request object, and file suffix
1.113 bowersj2 1882:
1.256 matthew 1883: Returns (undef) on failure,
1884: Filehandle and filename on success.
1.113 bowersj2 1885:
1886: =cut
1887:
1.256 matthew 1888: ###############################################################
1889: ###############################################################
1890: sub create_text_file {
1891: my ($r,$suffix) = @_;
1892: if (! defined($suffix)) { $suffix = 'txt'; };
1893: my $fh;
1894: my $filename = '/prtspool/'.
1.258 albertel 1895: $env{'user.name'}.'_'.$env{'user.domain'}.'_'.
1.256 matthew 1896: time.'_'.rand(1000000000).'.'.$suffix;
1897: $fh = Apache::File->new('>/home/httpd'.$filename);
1898: if (! defined($fh)) {
1899: $r->log_error("Couldn't open $filename for output $!");
1.928 bisitz 1900: $r->print(
1901: '<p class="LC_error">'
1902: .&mt('Problems occurred in creating the output file.')
1903: .' '.&mt('This error has been logged.')
1904: .' '.&mt('Please alert your LON-CAPA administrator.')
1905: .'</p>'
1906: );
1.113 bowersj2 1907: }
1.256 matthew 1908: return ($fh,$filename)
1.113 bowersj2 1909: }
1910:
1911:
1.256 matthew 1912: =pod
1.113 bowersj2 1913:
1914: =back
1915:
1916: =cut
1.37 matthew 1917:
1918: ###############################################################
1.33 matthew 1919: ## Home server <option> list generating code ##
1920: ###############################################################
1.35 matthew 1921:
1.169 www 1922: # ------------------------------------------
1923:
1924: sub domain_select {
1925: my ($name,$value,$multiple)=@_;
1926: my %domains=map {
1.514 albertel 1927: $_ => $_.' '. &Apache::lonnet::domain($_,'description')
1.512 albertel 1928: } &Apache::lonnet::all_domains();
1.169 www 1929: if ($multiple) {
1930: $domains{''}=&mt('Any domain');
1.550 albertel 1931: $domains{'select_form_order'} = [sort {lc($a) cmp lc($b) } (keys(%domains))];
1.287 albertel 1932: return &multiple_select_form($name,$value,4,\%domains);
1.169 www 1933: } else {
1.550 albertel 1934: $domains{'select_form_order'} = [sort {lc($a) cmp lc($b) } (keys(%domains))];
1.970 raeburn 1935: return &select_form($name,$value,\%domains);
1.169 www 1936: }
1937: }
1938:
1.282 albertel 1939: #-------------------------------------------
1940:
1941: =pod
1942:
1.519 raeburn 1943: =head1 Routines for form select boxes
1944:
1945: =over 4
1946:
1.648 raeburn 1947: =item * &multiple_select_form($name,$value,$size,$hash,$order)
1.282 albertel 1948:
1949: Returns a string containing a <select> element int multiple mode
1950:
1951:
1952: Args:
1953: $name - name of the <select> element
1.506 raeburn 1954: $value - scalar or array ref of values that should already be selected
1.282 albertel 1955: $size - number of rows long the select element is
1.283 albertel 1956: $hash - the elements should be 'option' => 'shown text'
1.282 albertel 1957: (shown text should already have been &mt())
1.506 raeburn 1958: $order - (optional) array ref of the order to show the elements in
1.283 albertel 1959:
1.282 albertel 1960: =cut
1961:
1962: #-------------------------------------------
1.169 www 1963: sub multiple_select_form {
1.284 albertel 1964: my ($name,$value,$size,$hash,$order)=@_;
1.169 www 1965: my %selected = map { $_ => 1 } ref($value)?@{$value}:($value);
1966: my $output='';
1.191 matthew 1967: if (! defined($size)) {
1968: $size = 4;
1.283 albertel 1969: if (scalar(keys(%$hash))<4) {
1970: $size = scalar(keys(%$hash));
1.191 matthew 1971: }
1972: }
1.734 bisitz 1973: $output.="\n".'<select name="'.$name.'" size="'.$size.'" multiple="multiple">';
1.501 banghart 1974: my @order;
1.506 raeburn 1975: if (ref($order) eq 'ARRAY') {
1976: @order = @{$order};
1977: } else {
1978: @order = sort(keys(%$hash));
1.501 banghart 1979: }
1980: if (exists($$hash{'select_form_order'})) {
1981: @order = @{$$hash{'select_form_order'}};
1982: }
1983:
1.284 albertel 1984: foreach my $key (@order) {
1.356 albertel 1985: $output.='<option value="'.&HTML::Entities::encode($key,'"<>&').'" ';
1.284 albertel 1986: $output.='selected="selected" ' if ($selected{$key});
1987: $output.='>'.$hash->{$key}."</option>\n";
1.169 www 1988: }
1989: $output.="</select>\n";
1990: return $output;
1991: }
1992:
1.88 www 1993: #-------------------------------------------
1994:
1995: =pod
1996:
1.970 raeburn 1997: =item * &select_form($defdom,$name,$hashref,$onchange)
1.88 www 1998:
1999: Returns a string containing a <select name='$name' size='1'> form to
1.970 raeburn 2000: allow a user to select options from a ref to a hash containing:
2001: option_name => displayed text. An optional $onchange can include
2002: a javascript onchange item, e.g., onchange="this.form.submit();"
2003:
1.88 www 2004: See lonrights.pm for an example invocation and use.
2005:
2006: =cut
2007:
2008: #-------------------------------------------
2009: sub select_form {
1.970 raeburn 2010: my ($def,$name,$hashref,$onchange) = @_;
2011: return unless (ref($hashref) eq 'HASH');
2012: if ($onchange) {
2013: $onchange = ' onchange="'.$onchange.'"';
2014: }
2015: my $selectform = "<select name=\"$name\" size=\"1\"$onchange>\n";
1.128 albertel 2016: my @keys;
1.970 raeburn 2017: if (exists($hashref->{'select_form_order'})) {
2018: @keys=@{$hashref->{'select_form_order'}};
1.128 albertel 2019: } else {
1.970 raeburn 2020: @keys=sort(keys(%{$hashref}));
1.128 albertel 2021: }
1.356 albertel 2022: foreach my $key (@keys) {
2023: $selectform.=
2024: '<option value="'.&HTML::Entities::encode($key,'"<>&').'" '.
2025: ($key eq $def ? 'selected="selected" ' : '').
1.970 raeburn 2026: ">".$hashref->{$key}."</option>\n";
1.88 www 2027: }
2028: $selectform.="</select>";
2029: return $selectform;
2030: }
2031:
1.475 www 2032: # For display filters
2033:
2034: sub display_filter {
1.1074 raeburn 2035: my ($context) = @_;
1.475 www 2036: if (!$env{'form.show'}) { $env{'form.show'}=10; }
1.477 www 2037: if (!$env{'form.displayfilter'}) { $env{'form.displayfilter'}='currentfolder'; }
1.1074 raeburn 2038: my $phraseinput = 'hidden';
2039: my $includeinput = 'hidden';
2040: my ($checked,$includetypestext);
2041: if ($env{'form.displayfilter'} eq 'containing') {
2042: $phraseinput = 'text';
2043: if ($context eq 'parmslog') {
2044: $includeinput = 'checkbox';
2045: if ($env{'form.includetypes'}) {
2046: $checked = ' checked="checked"';
2047: }
2048: $includetypestext = &mt('Include parameter types');
2049: }
2050: } else {
2051: $includetypestext = ' ';
2052: }
2053: my ($additional,$secondid,$thirdid);
2054: if ($context eq 'parmslog') {
2055: $additional =
2056: '<label><input type="'.$includeinput.'" name="includetypes"'.
2057: $checked.' name="includetypes" value="1" id="includetypes" />'.
2058: ' <span id="includetypestext">'.$includetypestext.'</span>'.
2059: '</label>';
2060: $secondid = 'includetypes';
2061: $thirdid = 'includetypestext';
2062: }
2063: my $onchange = "javascript:toggleHistoryOptions(this,'containingphrase','$context',
2064: '$secondid','$thirdid')";
2065: return '<span class="LC_nobreak"><label>'.&mt('Records: [_1]',
1.475 www 2066: &Apache::lonmeta::selectbox('show',$env{'form.show'},undef,
2067: (&mt('all'),10,20,50,100,1000,10000))).
1.714 bisitz 2068: '</label></span> <span class="LC_nobreak">'.
1.1074 raeburn 2069: &mt('Filter: [_1]',
1.477 www 2070: &select_form($env{'form.displayfilter'},
2071: 'displayfilter',
1.970 raeburn 2072: {'currentfolder' => 'Current folder/page',
1.477 www 2073: 'containing' => 'Containing phrase',
1.1074 raeburn 2074: 'none' => 'None'},$onchange)).' '.
2075: '<input type="'.$phraseinput.'" name="containingphrase" id="containingphrase" size="30" value="'.
2076: &HTML::Entities::encode($env{'form.containingphrase'}).
2077: '" />'.$additional;
2078: }
2079:
2080: sub display_filter_js {
2081: my $includetext = &mt('Include parameter types');
2082: return <<"ENDJS";
2083:
2084: function toggleHistoryOptions(setter,firstid,context,secondid,thirdid) {
2085: var firstType = 'hidden';
2086: if (setter.options[setter.selectedIndex].value == 'containing') {
2087: firstType = 'text';
2088: }
2089: firstObject = document.getElementById(firstid);
2090: if (typeof(firstObject) == 'object') {
2091: if (firstObject.type != firstType) {
2092: changeInputType(firstObject,firstType);
2093: }
2094: }
2095: if (context == 'parmslog') {
2096: var secondType = 'hidden';
2097: if (firstType == 'text') {
2098: secondType = 'checkbox';
2099: }
2100: secondObject = document.getElementById(secondid);
2101: if (typeof(secondObject) == 'object') {
2102: if (secondObject.type != secondType) {
2103: changeInputType(secondObject,secondType);
2104: }
2105: }
2106: var textItem = document.getElementById(thirdid);
2107: var currtext = textItem.innerHTML;
2108: var newtext;
2109: if (firstType == 'text') {
2110: newtext = '$includetext';
2111: } else {
2112: newtext = ' ';
2113: }
2114: if (currtext != newtext) {
2115: textItem.innerHTML = newtext;
2116: }
2117: }
2118: return;
2119: }
2120:
2121: function changeInputType(oldObject,newType) {
2122: var newObject = document.createElement('input');
2123: newObject.type = newType;
2124: if (oldObject.size) {
2125: newObject.size = oldObject.size;
2126: }
2127: if (oldObject.value) {
2128: newObject.value = oldObject.value;
2129: }
2130: if (oldObject.name) {
2131: newObject.name = oldObject.name;
2132: }
2133: if (oldObject.id) {
2134: newObject.id = oldObject.id;
2135: }
2136: oldObject.parentNode.replaceChild(newObject,oldObject);
2137: return;
2138: }
2139:
2140: ENDJS
1.475 www 2141: }
2142:
1.167 www 2143: sub gradeleveldescription {
2144: my $gradelevel=shift;
2145: my %gradelevels=(0 => 'Not specified',
2146: 1 => 'Grade 1',
2147: 2 => 'Grade 2',
2148: 3 => 'Grade 3',
2149: 4 => 'Grade 4',
2150: 5 => 'Grade 5',
2151: 6 => 'Grade 6',
2152: 7 => 'Grade 7',
2153: 8 => 'Grade 8',
2154: 9 => 'Grade 9',
2155: 10 => 'Grade 10',
2156: 11 => 'Grade 11',
2157: 12 => 'Grade 12',
2158: 13 => 'Grade 13',
2159: 14 => '100 Level',
2160: 15 => '200 Level',
2161: 16 => '300 Level',
2162: 17 => '400 Level',
2163: 18 => 'Graduate Level');
2164: return &mt($gradelevels{$gradelevel});
2165: }
2166:
1.163 www 2167: sub select_level_form {
2168: my ($deflevel,$name)=@_;
2169: unless ($deflevel) { $deflevel=0; }
1.167 www 2170: my $selectform = "<select name=\"$name\" size=\"1\">\n";
2171: for (my $i=0; $i<=18; $i++) {
2172: $selectform.="<option value=\"$i\" ".
1.253 albertel 2173: ($i==$deflevel ? 'selected="selected" ' : '').
1.167 www 2174: ">".&gradeleveldescription($i)."</option>\n";
2175: }
2176: $selectform.="</select>";
2177: return $selectform;
1.163 www 2178: }
1.167 www 2179:
1.35 matthew 2180: #-------------------------------------------
2181:
1.45 matthew 2182: =pod
2183:
1.1075.2.42 raeburn 2184: =item * &select_dom_form($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms,$excdoms)
1.35 matthew 2185:
2186: Returns a string containing a <select name='$name' size='1'> form to
2187: allow a user to select the domain to preform an operation in.
2188: See loncreateuser.pm for an example invocation and use.
2189:
1.90 www 2190: If the $includeempty flag is set, it also includes an empty choice ("no domain
2191: selected");
2192:
1.743 raeburn 2193: If the $showdomdesc flag is set, the domain name is followed by the domain description.
2194:
1.910 raeburn 2195: The optional $onchange argument specifies what should occur if the domain selector is changed, e.g., 'this.form.submit()' if the form is to be automatically submitted.
2196:
1.1075.2.36 raeburn 2197: The optional $incdoms is a reference to an array of domains which will be the only available options.
2198:
2199: The optional $excdoms is a reference to an array of domains which will be excluded from the available options.
1.563 raeburn 2200:
1.35 matthew 2201: =cut
2202:
2203: #-------------------------------------------
1.34 matthew 2204: sub select_dom_form {
1.1075.2.36 raeburn 2205: my ($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms,$excdoms) = @_;
1.872 raeburn 2206: if ($onchange) {
1.874 raeburn 2207: $onchange = ' onchange="'.$onchange.'"';
1.743 raeburn 2208: }
1.1075.2.36 raeburn 2209: my (@domains,%exclude);
1.910 raeburn 2210: if (ref($incdoms) eq 'ARRAY') {
2211: @domains = sort {lc($a) cmp lc($b)} (@{$incdoms});
2212: } else {
2213: @domains = sort {lc($a) cmp lc($b)} (&Apache::lonnet::all_domains());
2214: }
1.90 www 2215: if ($includeempty) { @domains=('',@domains); }
1.1075.2.36 raeburn 2216: if (ref($excdoms) eq 'ARRAY') {
2217: map { $exclude{$_} = 1; } @{$excdoms};
2218: }
1.743 raeburn 2219: my $selectdomain = "<select name=\"$name\" size=\"1\"$onchange>\n";
1.356 albertel 2220: foreach my $dom (@domains) {
1.1075.2.36 raeburn 2221: next if ($exclude{$dom});
1.356 albertel 2222: $selectdomain.="<option value=\"$dom\" ".
1.563 raeburn 2223: ($dom eq $defdom ? 'selected="selected" ' : '').'>'.$dom;
2224: if ($showdomdesc) {
2225: if ($dom ne '') {
2226: my $domdesc = &Apache::lonnet::domain($dom,'description');
2227: if ($domdesc ne '') {
2228: $selectdomain .= ' ('.$domdesc.')';
2229: }
2230: }
2231: }
2232: $selectdomain .= "</option>\n";
1.34 matthew 2233: }
2234: $selectdomain.="</select>";
2235: return $selectdomain;
2236: }
2237:
1.35 matthew 2238: #-------------------------------------------
2239:
1.45 matthew 2240: =pod
2241:
1.648 raeburn 2242: =item * &home_server_form_item($domain,$name,$defaultflag)
1.35 matthew 2243:
1.586 raeburn 2244: input: 4 arguments (two required, two optional) -
2245: $domain - domain of new user
2246: $name - name of form element
2247: $default - Value of 'default' causes a default item to be first
2248: option, and selected by default.
2249: $hide - Value of 'hide' causes hiding of the name of the server,
2250: if 1 server found, or default, if 0 found.
1.594 raeburn 2251: output: returns 2 items:
1.586 raeburn 2252: (a) form element which contains either:
2253: (i) <select name="$name">
2254: <option value="$hostid1">$hostid $servers{$hostid}</option>
2255: <option value="$hostid2">$hostid $servers{$hostid}</option>
2256: </select>
2257: form item if there are multiple library servers in $domain, or
2258: (ii) an <input type="hidden" name="$name" value="$hostid" /> form item
2259: if there is only one library server in $domain.
2260:
2261: (b) number of library servers found.
2262:
2263: See loncreateuser.pm for example of use.
1.35 matthew 2264:
2265: =cut
2266:
2267: #-------------------------------------------
1.586 raeburn 2268: sub home_server_form_item {
2269: my ($domain,$name,$default,$hide) = @_;
1.513 albertel 2270: my %servers = &Apache::lonnet::get_servers($domain,'library');
1.586 raeburn 2271: my $result;
2272: my $numlib = keys(%servers);
2273: if ($numlib > 1) {
2274: $result .= '<select name="'.$name.'" />'."\n";
2275: if ($default) {
1.804 bisitz 2276: $result .= '<option value="default" selected="selected">'.&mt('default').
1.586 raeburn 2277: '</option>'."\n";
2278: }
2279: foreach my $hostid (sort(keys(%servers))) {
2280: $result.= '<option value="'.$hostid.'">'.
2281: $hostid.' '.$servers{$hostid}."</option>\n";
2282: }
2283: $result .= '</select>'."\n";
2284: } elsif ($numlib == 1) {
2285: my $hostid;
2286: foreach my $item (keys(%servers)) {
2287: $hostid = $item;
2288: }
2289: $result .= '<input type="hidden" name="'.$name.'" value="'.
2290: $hostid.'" />';
2291: if (!$hide) {
2292: $result .= $hostid.' '.$servers{$hostid};
2293: }
2294: $result .= "\n";
2295: } elsif ($default) {
2296: $result .= '<input type="hidden" name="'.$name.
2297: '" value="default" />';
2298: if (!$hide) {
2299: $result .= &mt('default');
2300: }
2301: $result .= "\n";
1.33 matthew 2302: }
1.586 raeburn 2303: return ($result,$numlib);
1.33 matthew 2304: }
1.112 bowersj2 2305:
2306: =pod
2307:
1.534 albertel 2308: =back
2309:
1.112 bowersj2 2310: =cut
1.87 matthew 2311:
2312: ###############################################################
1.112 bowersj2 2313: ## Decoding User Agent ##
1.87 matthew 2314: ###############################################################
2315:
2316: =pod
2317:
1.112 bowersj2 2318: =head1 Decoding the User Agent
2319:
2320: =over 4
2321:
2322: =item * &decode_user_agent()
1.87 matthew 2323:
2324: Inputs: $r
2325:
2326: Outputs:
2327:
2328: =over 4
2329:
1.112 bowersj2 2330: =item * $httpbrowser
1.87 matthew 2331:
1.112 bowersj2 2332: =item * $clientbrowser
1.87 matthew 2333:
1.112 bowersj2 2334: =item * $clientversion
1.87 matthew 2335:
1.112 bowersj2 2336: =item * $clientmathml
1.87 matthew 2337:
1.112 bowersj2 2338: =item * $clientunicode
1.87 matthew 2339:
1.112 bowersj2 2340: =item * $clientos
1.87 matthew 2341:
1.1075.2.42 raeburn 2342: =item * $clientmobile
2343:
2344: =item * $clientinfo
2345:
1.1075.2.77 raeburn 2346: =item * $clientosversion
2347:
1.87 matthew 2348: =back
2349:
1.157 matthew 2350: =back
2351:
1.87 matthew 2352: =cut
2353:
2354: ###############################################################
2355: ###############################################################
2356: sub decode_user_agent {
1.247 albertel 2357: my ($r)=@_;
1.87 matthew 2358: my @browsertype=split(/\&/,$Apache::lonnet::perlvar{"lonBrowsDet"});
2359: my %mathcap=split(/\&/,$$Apache::lonnet::perlvar{"lonMathML"});
2360: my $httpbrowser=$ENV{"HTTP_USER_AGENT"};
1.247 albertel 2361: if (!$httpbrowser && $r) { $httpbrowser=$r->header_in('User-Agent'); }
1.87 matthew 2362: my $clientbrowser='unknown';
2363: my $clientversion='0';
2364: my $clientmathml='';
2365: my $clientunicode='0';
1.1075.2.42 raeburn 2366: my $clientmobile=0;
1.1075.2.77 raeburn 2367: my $clientosversion='';
1.87 matthew 2368: for (my $i=0;$i<=$#browsertype;$i++) {
1.1075.2.76 raeburn 2369: my ($bname,$match,$notmatch,$vreg,$minv,$univ)=split(/\%/,$browsertype[$i]);
1.87 matthew 2370: if (($httpbrowser=~/$match/i) && ($httpbrowser!~/$notmatch/i)) {
2371: $clientbrowser=$bname;
2372: $httpbrowser=~/$vreg/i;
2373: $clientversion=$1;
2374: $clientmathml=($clientversion>=$minv);
2375: $clientunicode=($clientversion>=$univ);
2376: }
2377: }
2378: my $clientos='unknown';
1.1075.2.42 raeburn 2379: my $clientinfo;
1.87 matthew 2380: if (($httpbrowser=~/linux/i) ||
2381: ($httpbrowser=~/unix/i) ||
2382: ($httpbrowser=~/ux/i) ||
2383: ($httpbrowser=~/solaris/i)) { $clientos='unix'; }
2384: if (($httpbrowser=~/vax/i) ||
2385: ($httpbrowser=~/vms/i)) { $clientos='vms'; }
2386: if ($httpbrowser=~/next/i) { $clientos='next'; }
2387: if (($httpbrowser=~/mac/i) ||
2388: ($httpbrowser=~/powerpc/i)) { $clientos='mac'; }
1.1075.2.77 raeburn 2389: if ($httpbrowser=~/win/i) {
2390: $clientos='win';
2391: if ($httpbrowser =~/Windows\s+NT\s+(\d+\.\d+)/i) {
2392: $clientosversion = $1;
2393: }
2394: }
1.87 matthew 2395: if ($httpbrowser=~/embed/i) { $clientos='pda'; }
1.1075.2.42 raeburn 2396: if ($httpbrowser=~/(Android|iPod|iPad|iPhone|webOS|Blackberry|Windows Phone|Opera m(?:ob|in)|Fennec)/i) {
2397: $clientmobile=lc($1);
2398: }
2399: if ($httpbrowser=~ m{Firefox/(\d+\.\d+)}) {
2400: $clientinfo = 'firefox-'.$1;
2401: } elsif ($httpbrowser=~ m{chromeframe/(\d+\.\d+)\.}) {
2402: $clientinfo = 'chromeframe-'.$1;
2403: }
1.87 matthew 2404: return ($httpbrowser,$clientbrowser,$clientversion,$clientmathml,
1.1075.2.77 raeburn 2405: $clientunicode,$clientos,$clientmobile,$clientinfo,
2406: $clientosversion);
1.87 matthew 2407: }
2408:
1.32 matthew 2409: ###############################################################
2410: ## Authentication changing form generation subroutines ##
2411: ###############################################################
2412: ##
2413: ## All of the authform_xxxxxxx subroutines take their inputs in a
2414: ## hash, and have reasonable default values.
2415: ##
2416: ## formname = the name given in the <form> tag.
1.35 matthew 2417: #-------------------------------------------
2418:
1.45 matthew 2419: =pod
2420:
1.112 bowersj2 2421: =head1 Authentication Routines
2422:
2423: =over 4
2424:
1.648 raeburn 2425: =item * &authform_xxxxxx()
1.35 matthew 2426:
2427: The authform_xxxxxx subroutines provide javascript and html forms which
2428: handle some of the conveniences required for authentication forms.
2429: This is not an optimal method, but it works.
2430:
2431: =over 4
2432:
1.112 bowersj2 2433: =item * authform_header
1.35 matthew 2434:
1.112 bowersj2 2435: =item * authform_authorwarning
1.35 matthew 2436:
1.112 bowersj2 2437: =item * authform_nochange
1.35 matthew 2438:
1.112 bowersj2 2439: =item * authform_kerberos
1.35 matthew 2440:
1.112 bowersj2 2441: =item * authform_internal
1.35 matthew 2442:
1.112 bowersj2 2443: =item * authform_filesystem
1.35 matthew 2444:
2445: =back
2446:
1.648 raeburn 2447: See loncreateuser.pm for invocation and use examples.
1.157 matthew 2448:
1.35 matthew 2449: =cut
2450:
2451: #-------------------------------------------
1.32 matthew 2452: sub authform_header{
2453: my %in = (
2454: formname => 'cu',
1.80 albertel 2455: kerb_def_dom => '',
1.32 matthew 2456: @_,
2457: );
2458: $in{'formname'} = 'document.' . $in{'formname'};
2459: my $result='';
1.80 albertel 2460:
2461: #---------------------------------------------- Code for upper case translation
2462: my $Javascript_toUpperCase;
2463: unless ($in{kerb_def_dom}) {
2464: $Javascript_toUpperCase =<<"END";
2465: switch (choice) {
2466: case 'krb': currentform.elements[choicearg].value =
2467: currentform.elements[choicearg].value.toUpperCase();
2468: break;
2469: default:
2470: }
2471: END
2472: } else {
2473: $Javascript_toUpperCase = "";
2474: }
2475:
1.165 raeburn 2476: my $radioval = "'nochange'";
1.591 raeburn 2477: if (defined($in{'curr_authtype'})) {
2478: if ($in{'curr_authtype'} ne '') {
2479: $radioval = "'".$in{'curr_authtype'}."arg'";
2480: }
1.174 matthew 2481: }
1.165 raeburn 2482: my $argfield = 'null';
1.591 raeburn 2483: if (defined($in{'mode'})) {
1.165 raeburn 2484: if ($in{'mode'} eq 'modifycourse') {
1.591 raeburn 2485: if (defined($in{'curr_autharg'})) {
2486: if ($in{'curr_autharg'} ne '') {
1.165 raeburn 2487: $argfield = "'$in{'curr_autharg'}'";
2488: }
2489: }
2490: }
2491: }
2492:
1.32 matthew 2493: $result.=<<"END";
2494: var current = new Object();
1.165 raeburn 2495: current.radiovalue = $radioval;
2496: current.argfield = $argfield;
1.32 matthew 2497:
2498: function changed_radio(choice,currentform) {
2499: var choicearg = choice + 'arg';
2500: // If a radio button in changed, we need to change the argfield
2501: if (current.radiovalue != choice) {
2502: current.radiovalue = choice;
2503: if (current.argfield != null) {
2504: currentform.elements[current.argfield].value = '';
2505: }
2506: if (choice == 'nochange') {
2507: current.argfield = null;
2508: } else {
2509: current.argfield = choicearg;
2510: switch(choice) {
2511: case 'krb':
2512: currentform.elements[current.argfield].value =
2513: "$in{'kerb_def_dom'}";
2514: break;
2515: default:
2516: break;
2517: }
2518: }
2519: }
2520: return;
2521: }
1.22 www 2522:
1.32 matthew 2523: function changed_text(choice,currentform) {
2524: var choicearg = choice + 'arg';
2525: if (currentform.elements[choicearg].value !='') {
1.80 albertel 2526: $Javascript_toUpperCase
1.32 matthew 2527: // clear old field
2528: if ((current.argfield != choicearg) && (current.argfield != null)) {
2529: currentform.elements[current.argfield].value = '';
2530: }
2531: current.argfield = choicearg;
2532: }
2533: set_auth_radio_buttons(choice,currentform);
2534: return;
1.20 www 2535: }
1.32 matthew 2536:
2537: function set_auth_radio_buttons(newvalue,currentform) {
1.986 raeburn 2538: var numauthchoices = currentform.login.length;
2539: if (typeof numauthchoices == "undefined") {
2540: return;
2541: }
1.32 matthew 2542: var i=0;
1.986 raeburn 2543: while (i < numauthchoices) {
1.32 matthew 2544: if (currentform.login[i].value == newvalue) { break; }
2545: i++;
2546: }
1.986 raeburn 2547: if (i == numauthchoices) {
1.32 matthew 2548: return;
2549: }
2550: current.radiovalue = newvalue;
2551: currentform.login[i].checked = true;
2552: return;
2553: }
2554: END
2555: return $result;
2556: }
2557:
1.1075.2.20 raeburn 2558: sub authform_authorwarning {
1.32 matthew 2559: my $result='';
1.144 matthew 2560: $result='<i>'.
2561: &mt('As a general rule, only authors or co-authors should be '.
2562: 'filesystem authenticated '.
2563: '(which allows access to the server filesystem).')."</i>\n";
1.32 matthew 2564: return $result;
2565: }
2566:
1.1075.2.20 raeburn 2567: sub authform_nochange {
1.32 matthew 2568: my %in = (
2569: formname => 'document.cu',
2570: kerb_def_dom => 'MSU.EDU',
2571: @_,
2572: );
1.1075.2.20 raeburn 2573: my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
1.586 raeburn 2574: my $result;
1.1075.2.20 raeburn 2575: if (!$authnum) {
2576: $result = &mt('Under your current role you are not permitted to change login settings for this user');
1.586 raeburn 2577: } else {
2578: $result = '<label>'.&mt('[_1] Do not change login data',
2579: '<input type="radio" name="login" value="nochange" '.
2580: 'checked="checked" onclick="'.
1.281 albertel 2581: "javascript:changed_radio('nochange',$in{'formname'});".'" />').
2582: '</label>';
1.586 raeburn 2583: }
1.32 matthew 2584: return $result;
2585: }
2586:
1.591 raeburn 2587: sub authform_kerberos {
1.32 matthew 2588: my %in = (
2589: formname => 'document.cu',
2590: kerb_def_dom => 'MSU.EDU',
1.80 albertel 2591: kerb_def_auth => 'krb4',
1.32 matthew 2592: @_,
2593: );
1.586 raeburn 2594: my ($check4,$check5,$krbcheck,$krbarg,$krbver,$result,$authtype,
2595: $autharg,$jscall);
1.1075.2.20 raeburn 2596: my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
1.80 albertel 2597: if ($in{'kerb_def_auth'} eq 'krb5') {
1.772 bisitz 2598: $check5 = ' checked="checked"';
1.80 albertel 2599: } else {
1.772 bisitz 2600: $check4 = ' checked="checked"';
1.80 albertel 2601: }
1.165 raeburn 2602: $krbarg = $in{'kerb_def_dom'};
1.591 raeburn 2603: if (defined($in{'curr_authtype'})) {
2604: if ($in{'curr_authtype'} eq 'krb') {
1.772 bisitz 2605: $krbcheck = ' checked="checked"';
1.623 raeburn 2606: if (defined($in{'mode'})) {
2607: if ($in{'mode'} eq 'modifyuser') {
2608: $krbcheck = '';
2609: }
2610: }
1.591 raeburn 2611: if (defined($in{'curr_kerb_ver'})) {
2612: if ($in{'curr_krb_ver'} eq '5') {
1.772 bisitz 2613: $check5 = ' checked="checked"';
1.591 raeburn 2614: $check4 = '';
2615: } else {
1.772 bisitz 2616: $check4 = ' checked="checked"';
1.591 raeburn 2617: $check5 = '';
2618: }
1.586 raeburn 2619: }
1.591 raeburn 2620: if (defined($in{'curr_autharg'})) {
1.165 raeburn 2621: $krbarg = $in{'curr_autharg'};
2622: }
1.586 raeburn 2623: if (!$can_assign{'krb4'} && !$can_assign{'krb5'}) {
1.591 raeburn 2624: if (defined($in{'curr_autharg'})) {
1.586 raeburn 2625: $result =
2626: &mt('Currently Kerberos authenticated with domain [_1] Version [_2].',
2627: $in{'curr_autharg'},$krbver);
2628: } else {
2629: $result =
2630: &mt('Currently Kerberos authenticated, Version [_1].',$krbver);
2631: }
2632: return $result;
2633: }
2634: }
2635: } else {
2636: if ($authnum == 1) {
1.784 bisitz 2637: $authtype = '<input type="hidden" name="login" value="krb" />';
1.165 raeburn 2638: }
2639: }
1.586 raeburn 2640: if (!$can_assign{'krb4'} && !$can_assign{'krb5'}) {
2641: return;
1.587 raeburn 2642: } elsif ($authtype eq '') {
1.591 raeburn 2643: if (defined($in{'mode'})) {
1.587 raeburn 2644: if ($in{'mode'} eq 'modifycourse') {
2645: if ($authnum == 1) {
1.1075.2.20 raeburn 2646: $authtype = '<input type="radio" name="login" value="krb" />';
1.587 raeburn 2647: }
2648: }
2649: }
1.586 raeburn 2650: }
2651: $jscall = "javascript:changed_radio('krb',$in{'formname'});";
2652: if ($authtype eq '') {
2653: $authtype = '<input type="radio" name="login" value="krb" '.
2654: 'onclick="'.$jscall.'" onchange="'.$jscall.'"'.
2655: $krbcheck.' />';
2656: }
2657: if (($can_assign{'krb4'} && $can_assign{'krb5'}) ||
1.1075.2.20 raeburn 2658: ($can_assign{'krb4'} && !$can_assign{'krb5'} &&
1.586 raeburn 2659: $in{'curr_authtype'} eq 'krb5') ||
1.1075.2.20 raeburn 2660: (!$can_assign{'krb4'} && $can_assign{'krb5'} &&
1.586 raeburn 2661: $in{'curr_authtype'} eq 'krb4')) {
2662: $result .= &mt
1.144 matthew 2663: ('[_1] Kerberos authenticated with domain [_2] '.
1.281 albertel 2664: '[_3] Version 4 [_4] Version 5 [_5]',
1.586 raeburn 2665: '<label>'.$authtype,
1.281 albertel 2666: '</label><input type="text" size="10" name="krbarg" '.
1.165 raeburn 2667: 'value="'.$krbarg.'" '.
1.144 matthew 2668: 'onchange="'.$jscall.'" />',
1.281 albertel 2669: '<label><input type="radio" name="krbver" value="4" '.$check4.' />',
2670: '</label><label><input type="radio" name="krbver" value="5" '.$check5.' />',
2671: '</label>');
1.586 raeburn 2672: } elsif ($can_assign{'krb4'}) {
2673: $result .= &mt
2674: ('[_1] Kerberos authenticated with domain [_2] '.
2675: '[_3] Version 4 [_4]',
2676: '<label>'.$authtype,
2677: '</label><input type="text" size="10" name="krbarg" '.
2678: 'value="'.$krbarg.'" '.
2679: 'onchange="'.$jscall.'" />',
2680: '<label><input type="hidden" name="krbver" value="4" />',
2681: '</label>');
2682: } elsif ($can_assign{'krb5'}) {
2683: $result .= &mt
2684: ('[_1] Kerberos authenticated with domain [_2] '.
2685: '[_3] Version 5 [_4]',
2686: '<label>'.$authtype,
2687: '</label><input type="text" size="10" name="krbarg" '.
2688: 'value="'.$krbarg.'" '.
2689: 'onchange="'.$jscall.'" />',
2690: '<label><input type="hidden" name="krbver" value="5" />',
2691: '</label>');
2692: }
1.32 matthew 2693: return $result;
2694: }
2695:
1.1075.2.20 raeburn 2696: sub authform_internal {
1.586 raeburn 2697: my %in = (
1.32 matthew 2698: formname => 'document.cu',
2699: kerb_def_dom => 'MSU.EDU',
2700: @_,
2701: );
1.586 raeburn 2702: my ($intcheck,$intarg,$result,$authtype,$autharg,$jscall);
1.1075.2.20 raeburn 2703: my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
1.591 raeburn 2704: if (defined($in{'curr_authtype'})) {
2705: if ($in{'curr_authtype'} eq 'int') {
1.586 raeburn 2706: if ($can_assign{'int'}) {
1.772 bisitz 2707: $intcheck = 'checked="checked" ';
1.623 raeburn 2708: if (defined($in{'mode'})) {
2709: if ($in{'mode'} eq 'modifyuser') {
2710: $intcheck = '';
2711: }
2712: }
1.591 raeburn 2713: if (defined($in{'curr_autharg'})) {
1.586 raeburn 2714: $intarg = $in{'curr_autharg'};
2715: }
2716: } else {
2717: $result = &mt('Currently internally authenticated.');
2718: return $result;
1.165 raeburn 2719: }
2720: }
1.586 raeburn 2721: } else {
2722: if ($authnum == 1) {
1.784 bisitz 2723: $authtype = '<input type="hidden" name="login" value="int" />';
1.586 raeburn 2724: }
2725: }
2726: if (!$can_assign{'int'}) {
2727: return;
1.587 raeburn 2728: } elsif ($authtype eq '') {
1.591 raeburn 2729: if (defined($in{'mode'})) {
1.587 raeburn 2730: if ($in{'mode'} eq 'modifycourse') {
2731: if ($authnum == 1) {
1.1075.2.20 raeburn 2732: $authtype = '<input type="radio" name="login" value="int" />';
1.587 raeburn 2733: }
2734: }
2735: }
1.165 raeburn 2736: }
1.586 raeburn 2737: $jscall = "javascript:changed_radio('int',$in{'formname'});";
2738: if ($authtype eq '') {
2739: $authtype = '<input type="radio" name="login" value="int" '.$intcheck.
2740: ' onchange="'.$jscall.'" onclick="'.$jscall.'" />';
2741: }
1.605 bisitz 2742: $autharg = '<input type="password" size="10" name="intarg" value="'.
1.586 raeburn 2743: $intarg.'" onchange="'.$jscall.'" />';
2744: $result = &mt
1.144 matthew 2745: ('[_1] Internally authenticated (with initial password [_2])',
1.586 raeburn 2746: '<label>'.$authtype,'</label>'.$autharg);
1.824 bisitz 2747: $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 2748: return $result;
2749: }
2750:
1.1075.2.20 raeburn 2751: sub authform_local {
1.32 matthew 2752: my %in = (
2753: formname => 'document.cu',
2754: kerb_def_dom => 'MSU.EDU',
2755: @_,
2756: );
1.586 raeburn 2757: my ($loccheck,$locarg,$result,$authtype,$autharg,$jscall);
1.1075.2.20 raeburn 2758: my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
1.591 raeburn 2759: if (defined($in{'curr_authtype'})) {
2760: if ($in{'curr_authtype'} eq 'loc') {
1.586 raeburn 2761: if ($can_assign{'loc'}) {
1.772 bisitz 2762: $loccheck = 'checked="checked" ';
1.623 raeburn 2763: if (defined($in{'mode'})) {
2764: if ($in{'mode'} eq 'modifyuser') {
2765: $loccheck = '';
2766: }
2767: }
1.591 raeburn 2768: if (defined($in{'curr_autharg'})) {
1.586 raeburn 2769: $locarg = $in{'curr_autharg'};
2770: }
2771: } else {
2772: $result = &mt('Currently using local (institutional) authentication.');
2773: return $result;
1.165 raeburn 2774: }
2775: }
1.586 raeburn 2776: } else {
2777: if ($authnum == 1) {
1.784 bisitz 2778: $authtype = '<input type="hidden" name="login" value="loc" />';
1.586 raeburn 2779: }
2780: }
2781: if (!$can_assign{'loc'}) {
2782: return;
1.587 raeburn 2783: } elsif ($authtype eq '') {
1.591 raeburn 2784: if (defined($in{'mode'})) {
1.587 raeburn 2785: if ($in{'mode'} eq 'modifycourse') {
2786: if ($authnum == 1) {
1.1075.2.20 raeburn 2787: $authtype = '<input type="radio" name="login" value="loc" />';
1.587 raeburn 2788: }
2789: }
2790: }
1.165 raeburn 2791: }
1.586 raeburn 2792: $jscall = "javascript:changed_radio('loc',$in{'formname'});";
2793: if ($authtype eq '') {
2794: $authtype = '<input type="radio" name="login" value="loc" '.
2795: $loccheck.' onchange="'.$jscall.'" onclick="'.
2796: $jscall.'" />';
2797: }
2798: $autharg = '<input type="text" size="10" name="locarg" value="'.
2799: $locarg.'" onchange="'.$jscall.'" />';
2800: $result = &mt('[_1] Local Authentication with argument [_2]',
2801: '<label>'.$authtype,'</label>'.$autharg);
1.32 matthew 2802: return $result;
2803: }
2804:
1.1075.2.20 raeburn 2805: sub authform_filesystem {
1.32 matthew 2806: my %in = (
2807: formname => 'document.cu',
2808: kerb_def_dom => 'MSU.EDU',
2809: @_,
2810: );
1.586 raeburn 2811: my ($fsyscheck,$result,$authtype,$autharg,$jscall);
1.1075.2.20 raeburn 2812: my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
1.591 raeburn 2813: if (defined($in{'curr_authtype'})) {
2814: if ($in{'curr_authtype'} eq 'fsys') {
1.586 raeburn 2815: if ($can_assign{'fsys'}) {
1.772 bisitz 2816: $fsyscheck = 'checked="checked" ';
1.623 raeburn 2817: if (defined($in{'mode'})) {
2818: if ($in{'mode'} eq 'modifyuser') {
2819: $fsyscheck = '';
2820: }
2821: }
1.586 raeburn 2822: } else {
2823: $result = &mt('Currently Filesystem Authenticated.');
2824: return $result;
2825: }
2826: }
2827: } else {
2828: if ($authnum == 1) {
1.784 bisitz 2829: $authtype = '<input type="hidden" name="login" value="fsys" />';
1.586 raeburn 2830: }
2831: }
2832: if (!$can_assign{'fsys'}) {
2833: return;
1.587 raeburn 2834: } elsif ($authtype eq '') {
1.591 raeburn 2835: if (defined($in{'mode'})) {
1.587 raeburn 2836: if ($in{'mode'} eq 'modifycourse') {
2837: if ($authnum == 1) {
1.1075.2.20 raeburn 2838: $authtype = '<input type="radio" name="login" value="fsys" />';
1.587 raeburn 2839: }
2840: }
2841: }
1.586 raeburn 2842: }
2843: $jscall = "javascript:changed_radio('fsys',$in{'formname'});";
2844: if ($authtype eq '') {
2845: $authtype = '<input type="radio" name="login" value="fsys" '.
2846: $fsyscheck.' onchange="'.$jscall.'" onclick="'.
2847: $jscall.'" />';
2848: }
2849: $autharg = '<input type="text" size="10" name="fsysarg" value=""'.
2850: ' onchange="'.$jscall.'" />';
2851: $result = &mt
1.144 matthew 2852: ('[_1] Filesystem Authenticated (with initial password [_2])',
1.281 albertel 2853: '<label><input type="radio" name="login" value="fsys" '.
1.586 raeburn 2854: $fsyscheck.'onchange="'.$jscall.'" onclick="'.$jscall.'" />',
1.605 bisitz 2855: '</label><input type="password" size="10" name="fsysarg" value="" '.
1.144 matthew 2856: 'onchange="'.$jscall.'" />');
1.32 matthew 2857: return $result;
2858: }
2859:
1.586 raeburn 2860: sub get_assignable_auth {
2861: my ($dom) = @_;
2862: if ($dom eq '') {
2863: $dom = $env{'request.role.domain'};
2864: }
2865: my %can_assign = (
2866: krb4 => 1,
2867: krb5 => 1,
2868: int => 1,
2869: loc => 1,
2870: );
2871: my %domconfig = &Apache::lonnet::get_dom('configuration',['usercreation'],$dom);
2872: if (ref($domconfig{'usercreation'}) eq 'HASH') {
2873: if (ref($domconfig{'usercreation'}{'authtypes'}) eq 'HASH') {
2874: my $authhash = $domconfig{'usercreation'}{'authtypes'};
2875: my $context;
2876: if ($env{'request.role'} =~ /^au/) {
2877: $context = 'author';
2878: } elsif ($env{'request.role'} =~ /^dc/) {
2879: $context = 'domain';
2880: } elsif ($env{'request.course.id'}) {
2881: $context = 'course';
2882: }
2883: if ($context) {
2884: if (ref($authhash->{$context}) eq 'HASH') {
2885: %can_assign = %{$authhash->{$context}};
2886: }
2887: }
2888: }
2889: }
2890: my $authnum = 0;
2891: foreach my $key (keys(%can_assign)) {
2892: if ($can_assign{$key}) {
2893: $authnum ++;
2894: }
2895: }
2896: if ($can_assign{'krb4'} && $can_assign{'krb5'}) {
2897: $authnum --;
2898: }
2899: return ($authnum,%can_assign);
2900: }
2901:
1.80 albertel 2902: ###############################################################
2903: ## Get Kerberos Defaults for Domain ##
2904: ###############################################################
2905: ##
2906: ## Returns default kerberos version and an associated argument
2907: ## as listed in file domain.tab. If not listed, provides
2908: ## appropriate default domain and kerberos version.
2909: ##
2910: #-------------------------------------------
2911:
2912: =pod
2913:
1.648 raeburn 2914: =item * &get_kerberos_defaults()
1.80 albertel 2915:
2916: get_kerberos_defaults($target_domain) returns the default kerberos
1.641 raeburn 2917: version and domain. If not found, it defaults to version 4 and the
2918: domain of the server.
1.80 albertel 2919:
1.648 raeburn 2920: =over 4
2921:
1.80 albertel 2922: ($def_version, $def_krb_domain) = &get_kerberos_defaults($target_domain);
2923:
1.648 raeburn 2924: =back
2925:
2926: =back
2927:
1.80 albertel 2928: =cut
2929:
2930: #-------------------------------------------
2931: sub get_kerberos_defaults {
2932: my $domain=shift;
1.641 raeburn 2933: my ($krbdef,$krbdefdom);
2934: my %domdefaults = &Apache::lonnet::get_domain_defaults($domain);
2935: if (($domdefaults{'auth_def'} =~/^krb(4|5)$/) && ($domdefaults{'auth_arg_def'} ne '')) {
2936: $krbdef = $domdefaults{'auth_def'};
2937: $krbdefdom = $domdefaults{'auth_arg_def'};
2938: } else {
1.80 albertel 2939: $ENV{'SERVER_NAME'}=~/(\w+\.\w+)$/;
2940: my $krbdefdom=$1;
2941: $krbdefdom=~tr/a-z/A-Z/;
2942: $krbdef = "krb4";
2943: }
2944: return ($krbdef,$krbdefdom);
2945: }
1.112 bowersj2 2946:
1.32 matthew 2947:
1.46 matthew 2948: ###############################################################
2949: ## Thesaurus Functions ##
2950: ###############################################################
1.20 www 2951:
1.46 matthew 2952: =pod
1.20 www 2953:
1.112 bowersj2 2954: =head1 Thesaurus Functions
2955:
2956: =over 4
2957:
1.648 raeburn 2958: =item * &initialize_keywords()
1.46 matthew 2959:
2960: Initializes the package variable %Keywords if it is empty. Uses the
2961: package variable $thesaurus_db_file.
2962:
2963: =cut
2964:
2965: ###################################################
2966:
2967: sub initialize_keywords {
2968: return 1 if (scalar keys(%Keywords));
2969: # If we are here, %Keywords is empty, so fill it up
2970: # Make sure the file we need exists...
2971: if (! -e $thesaurus_db_file) {
2972: &Apache::lonnet::logthis("Attempt to access $thesaurus_db_file".
2973: " failed because it does not exist");
2974: return 0;
2975: }
2976: # Set up the hash as a database
2977: my %thesaurus_db;
2978: if (! tie(%thesaurus_db,'GDBM_File',
1.53 albertel 2979: $thesaurus_db_file,&GDBM_READER(),0640)){
1.46 matthew 2980: &Apache::lonnet::logthis("Could not tie \%thesaurus_db to ".
2981: $thesaurus_db_file);
2982: return 0;
2983: }
2984: # Get the average number of appearances of a word.
2985: my $avecount = $thesaurus_db{'average.count'};
2986: # Put keywords (those that appear > average) into %Keywords
2987: while (my ($word,$data)=each (%thesaurus_db)) {
2988: my ($count,undef) = split /:/,$data;
2989: $Keywords{$word}++ if ($count > $avecount);
2990: }
2991: untie %thesaurus_db;
2992: # Remove special values from %Keywords.
1.356 albertel 2993: foreach my $value ('total.count','average.count') {
2994: delete($Keywords{$value}) if (exists($Keywords{$value}));
1.586 raeburn 2995: }
1.46 matthew 2996: return 1;
2997: }
2998:
2999: ###################################################
3000:
3001: =pod
3002:
1.648 raeburn 3003: =item * &keyword($word)
1.46 matthew 3004:
3005: Returns true if $word is a keyword. A keyword is a word that appears more
3006: than the average number of times in the thesaurus database. Calls
3007: &initialize_keywords
3008:
3009: =cut
3010:
3011: ###################################################
1.20 www 3012:
3013: sub keyword {
1.46 matthew 3014: return if (!&initialize_keywords());
3015: my $word=lc(shift());
3016: $word=~s/\W//g;
3017: return exists($Keywords{$word});
1.20 www 3018: }
1.46 matthew 3019:
3020: ###############################################################
3021:
3022: =pod
1.20 www 3023:
1.648 raeburn 3024: =item * &get_related_words()
1.46 matthew 3025:
1.160 matthew 3026: Look up a word in the thesaurus. Takes a scalar argument and returns
1.46 matthew 3027: an array of words. If the keyword is not in the thesaurus, an empty array
3028: will be returned. The order of the words returned is determined by the
3029: database which holds them.
3030:
3031: Uses global $thesaurus_db_file.
3032:
1.1057 foxr 3033:
1.46 matthew 3034: =cut
3035:
3036: ###############################################################
3037: sub get_related_words {
3038: my $keyword = shift;
3039: my %thesaurus_db;
3040: if (! -e $thesaurus_db_file) {
3041: &Apache::lonnet::logthis("Attempt to access $thesaurus_db_file ".
3042: "failed because the file does not exist");
3043: return ();
3044: }
3045: if (! tie(%thesaurus_db,'GDBM_File',
1.53 albertel 3046: $thesaurus_db_file,&GDBM_READER(),0640)){
1.46 matthew 3047: return ();
3048: }
3049: my @Words=();
1.429 www 3050: my $count=0;
1.46 matthew 3051: if (exists($thesaurus_db{$keyword})) {
1.356 albertel 3052: # The first element is the number of times
3053: # the word appears. We do not need it now.
1.429 www 3054: my (undef,@RelatedWords) = (split(/:/,$thesaurus_db{$keyword}));
3055: my (undef,$mostfrequentcount)=split(/\,/,$RelatedWords[0]);
3056: my $threshold=$mostfrequentcount/10;
3057: foreach my $possibleword (@RelatedWords) {
3058: my ($word,$wordcount)=split(/\,/,$possibleword);
3059: if ($wordcount>$threshold) {
3060: push(@Words,$word);
3061: $count++;
3062: if ($count>10) { last; }
3063: }
1.20 www 3064: }
3065: }
1.46 matthew 3066: untie %thesaurus_db;
3067: return @Words;
1.14 harris41 3068: }
1.46 matthew 3069:
1.112 bowersj2 3070: =pod
3071:
3072: =back
3073:
3074: =cut
1.61 www 3075:
3076: # -------------------------------------------------------------- Plaintext name
1.81 albertel 3077: =pod
3078:
1.112 bowersj2 3079: =head1 User Name Functions
3080:
3081: =over 4
3082:
1.648 raeburn 3083: =item * &plainname($uname,$udom,$first)
1.81 albertel 3084:
1.112 bowersj2 3085: Takes a users logon name and returns it as a string in
1.226 albertel 3086: "first middle last generation" form
3087: if $first is set to 'lastname' then it returns it as
3088: 'lastname generation, firstname middlename' if their is a lastname
1.81 albertel 3089:
3090: =cut
1.61 www 3091:
1.295 www 3092:
1.81 albertel 3093: ###############################################################
1.61 www 3094: sub plainname {
1.226 albertel 3095: my ($uname,$udom,$first)=@_;
1.537 albertel 3096: return if (!defined($uname) || !defined($udom));
1.295 www 3097: my %names=&getnames($uname,$udom);
1.226 albertel 3098: my $name=&Apache::lonnet::format_name($names{'firstname'},
3099: $names{'middlename'},
3100: $names{'lastname'},
3101: $names{'generation'},$first);
3102: $name=~s/^\s+//;
1.62 www 3103: $name=~s/\s+$//;
3104: $name=~s/\s+/ /g;
1.353 albertel 3105: if ($name !~ /\S/) { $name=$uname.':'.$udom; }
1.62 www 3106: return $name;
1.61 www 3107: }
1.66 www 3108:
3109: # -------------------------------------------------------------------- Nickname
1.81 albertel 3110: =pod
3111:
1.648 raeburn 3112: =item * &nickname($uname,$udom)
1.81 albertel 3113:
3114: Gets a users name and returns it as a string as
3115:
3116: ""nickname""
1.66 www 3117:
1.81 albertel 3118: if the user has a nickname or
3119:
3120: "first middle last generation"
3121:
3122: if the user does not
3123:
3124: =cut
1.66 www 3125:
3126: sub nickname {
3127: my ($uname,$udom)=@_;
1.537 albertel 3128: return if (!defined($uname) || !defined($udom));
1.295 www 3129: my %names=&getnames($uname,$udom);
1.68 albertel 3130: my $name=$names{'nickname'};
1.66 www 3131: if ($name) {
3132: $name='"'.$name.'"';
3133: } else {
3134: $name=$names{'firstname'}.' '.$names{'middlename'}.' '.
3135: $names{'lastname'}.' '.$names{'generation'};
3136: $name=~s/\s+$//;
3137: $name=~s/\s+/ /g;
3138: }
3139: return $name;
3140: }
3141:
1.295 www 3142: sub getnames {
3143: my ($uname,$udom)=@_;
1.537 albertel 3144: return if (!defined($uname) || !defined($udom));
1.433 albertel 3145: if ($udom eq 'public' && $uname eq 'public') {
3146: return ('lastname' => &mt('Public'));
3147: }
1.295 www 3148: my $id=$uname.':'.$udom;
3149: my ($names,$cached)=&Apache::lonnet::is_cached_new('namescache',$id);
3150: if ($cached) {
3151: return %{$names};
3152: } else {
3153: my %loadnames=&Apache::lonnet::get('environment',
3154: ['firstname','middlename','lastname','generation','nickname'],
3155: $udom,$uname);
3156: &Apache::lonnet::do_cache_new('namescache',$id,\%loadnames);
3157: return %loadnames;
3158: }
3159: }
1.61 www 3160:
1.542 raeburn 3161: # -------------------------------------------------------------------- getemails
1.648 raeburn 3162:
1.542 raeburn 3163: =pod
3164:
1.648 raeburn 3165: =item * &getemails($uname,$udom)
1.542 raeburn 3166:
3167: Gets a user's email information and returns it as a hash with keys:
3168: notification, critnotification, permanentemail
3169:
3170: For notification and critnotification, values are comma-separated lists
1.648 raeburn 3171: of e-mail addresses; for permanentemail, value is a single e-mail address.
1.542 raeburn 3172:
1.648 raeburn 3173:
1.542 raeburn 3174: =cut
3175:
1.648 raeburn 3176:
1.466 albertel 3177: sub getemails {
3178: my ($uname,$udom)=@_;
3179: if ($udom eq 'public' && $uname eq 'public') {
3180: return;
3181: }
1.467 www 3182: if (!$udom) { $udom=$env{'user.domain'}; }
3183: if (!$uname) { $uname=$env{'user.name'}; }
1.466 albertel 3184: my $id=$uname.':'.$udom;
3185: my ($names,$cached)=&Apache::lonnet::is_cached_new('emailscache',$id);
3186: if ($cached) {
3187: return %{$names};
3188: } else {
3189: my %loadnames=&Apache::lonnet::get('environment',
3190: ['notification','critnotification',
3191: 'permanentemail'],
3192: $udom,$uname);
3193: &Apache::lonnet::do_cache_new('emailscache',$id,\%loadnames);
3194: return %loadnames;
3195: }
3196: }
3197:
1.551 albertel 3198: sub flush_email_cache {
3199: my ($uname,$udom)=@_;
3200: if (!$udom) { $udom =$env{'user.domain'}; }
3201: if (!$uname) { $uname=$env{'user.name'}; }
3202: return if ($udom eq 'public' && $uname eq 'public');
3203: my $id=$uname.':'.$udom;
3204: &Apache::lonnet::devalidate_cache_new('emailscache',$id);
3205: }
3206:
1.728 raeburn 3207: # -------------------------------------------------------------------- getlangs
3208:
3209: =pod
3210:
3211: =item * &getlangs($uname,$udom)
3212:
3213: Gets a user's language preference and returns it as a hash with key:
3214: language.
3215:
3216: =cut
3217:
3218:
3219: sub getlangs {
3220: my ($uname,$udom) = @_;
3221: if (!$udom) { $udom =$env{'user.domain'}; }
3222: if (!$uname) { $uname=$env{'user.name'}; }
3223: my $id=$uname.':'.$udom;
3224: my ($langs,$cached)=&Apache::lonnet::is_cached_new('userlangs',$id);
3225: if ($cached) {
3226: return %{$langs};
3227: } else {
3228: my %loadlangs=&Apache::lonnet::get('environment',['languages'],
3229: $udom,$uname);
3230: &Apache::lonnet::do_cache_new('userlangs',$id,\%loadlangs);
3231: return %loadlangs;
3232: }
3233: }
3234:
3235: sub flush_langs_cache {
3236: my ($uname,$udom)=@_;
3237: if (!$udom) { $udom =$env{'user.domain'}; }
3238: if (!$uname) { $uname=$env{'user.name'}; }
3239: return if ($udom eq 'public' && $uname eq 'public');
3240: my $id=$uname.':'.$udom;
3241: &Apache::lonnet::devalidate_cache_new('userlangs',$id);
3242: }
3243:
1.61 www 3244: # ------------------------------------------------------------------ Screenname
1.81 albertel 3245:
3246: =pod
3247:
1.648 raeburn 3248: =item * &screenname($uname,$udom)
1.81 albertel 3249:
3250: Gets a users screenname and returns it as a string
3251:
3252: =cut
1.61 www 3253:
3254: sub screenname {
3255: my ($uname,$udom)=@_;
1.258 albertel 3256: if ($uname eq $env{'user.name'} &&
3257: $udom eq $env{'user.domain'}) {return $env{'environment.screenname'};}
1.212 albertel 3258: my %names=&Apache::lonnet::get('environment',['screenname'],$udom,$uname);
1.68 albertel 3259: return $names{'screenname'};
1.62 www 3260: }
3261:
1.212 albertel 3262:
1.802 bisitz 3263: # ------------------------------------------------------------- Confirm Wrapper
3264: =pod
3265:
1.1075.2.42 raeburn 3266: =item * &confirmwrapper($message)
1.802 bisitz 3267:
3268: Wrap messages about completion of operation in box
3269:
3270: =cut
3271:
3272: sub confirmwrapper {
3273: my ($message)=@_;
3274: if ($message) {
3275: return "\n".'<div class="LC_confirm_box">'."\n"
3276: .$message."\n"
3277: .'</div>'."\n";
3278: } else {
3279: return $message;
3280: }
3281: }
3282:
1.62 www 3283: # ------------------------------------------------------------- Message Wrapper
3284:
3285: sub messagewrapper {
1.369 www 3286: my ($link,$username,$domain,$subject,$text)=@_;
1.62 www 3287: return
1.441 albertel 3288: '<a href="/adm/email?compose=individual&'.
3289: 'recname='.$username.'&recdom='.$domain.
3290: '&subject='.&escape($subject).'&text='.&escape($text).'" '.
1.200 matthew 3291: 'title="'.&mt('Send message').'">'.$link.'</a>';
1.74 www 3292: }
1.802 bisitz 3293:
1.74 www 3294: # --------------------------------------------------------------- Notes Wrapper
3295:
3296: sub noteswrapper {
3297: my ($link,$un,$do)=@_;
3298: return
1.896 amueller 3299: "<a href='/adm/email?recordftf=retrieve&recname=$un&recdom=$do'>$link</a>";
1.62 www 3300: }
1.802 bisitz 3301:
1.62 www 3302: # ------------------------------------------------------------- Aboutme Wrapper
3303:
3304: sub aboutmewrapper {
1.1070 raeburn 3305: my ($link,$username,$domain,$target,$class)=@_;
1.447 raeburn 3306: if (!defined($username) && !defined($domain)) {
3307: return;
3308: }
1.1075.2.15 raeburn 3309: return '<a href="/adm/'.$domain.'/'.$username.'/aboutme"'.
1.1070 raeburn 3310: ($target?' target="'.$target.'"':'').($class?' class="'.$class.'"':'').' title="'.&mt("View this user's personal information page").'">'.$link.'</a>';
1.62 www 3311: }
3312:
3313: # ------------------------------------------------------------ Syllabus Wrapper
3314:
3315: sub syllabuswrapper {
1.707 bisitz 3316: my ($linktext,$coursedir,$domain)=@_;
1.208 matthew 3317: return qq{<a href="/public/$domain/$coursedir/syllabus">$linktext</a>};
1.61 www 3318: }
1.14 harris41 3319:
1.802 bisitz 3320: # -----------------------------------------------------------------------------
3321:
1.208 matthew 3322: sub track_student_link {
1.887 raeburn 3323: my ($linktext,$sname,$sdom,$target,$start,$only_body) = @_;
1.268 albertel 3324: my $link ="/adm/trackstudent?";
1.208 matthew 3325: my $title = 'View recent activity';
3326: if (defined($sname) && $sname !~ /^\s*$/ &&
3327: defined($sdom) && $sdom !~ /^\s*$/) {
1.268 albertel 3328: $link .= "selected_student=$sname:$sdom";
1.208 matthew 3329: $title .= ' of this student';
1.268 albertel 3330: }
1.208 matthew 3331: if (defined($target) && $target !~ /^\s*$/) {
3332: $target = qq{target="$target"};
3333: } else {
3334: $target = '';
3335: }
1.268 albertel 3336: if ($start) { $link.='&start='.$start; }
1.887 raeburn 3337: if ($only_body) { $link .= '&only_body=1'; }
1.554 albertel 3338: $title = &mt($title);
3339: $linktext = &mt($linktext);
1.448 albertel 3340: return qq{<a href="$link" title="$title" $target>$linktext</a>}.
3341: &help_open_topic('View_recent_activity');
1.208 matthew 3342: }
3343:
1.781 raeburn 3344: sub slot_reservations_link {
3345: my ($linktext,$sname,$sdom,$target) = @_;
3346: my $link ="/adm/slotrequest?command=showresv&origin=aboutme";
3347: my $title = 'View slot reservation history';
3348: if (defined($sname) && $sname !~ /^\s*$/ &&
3349: defined($sdom) && $sdom !~ /^\s*$/) {
3350: $link .= "&uname=$sname&udom=$sdom";
3351: $title .= ' of this student';
3352: }
3353: if (defined($target) && $target !~ /^\s*$/) {
3354: $target = qq{target="$target"};
3355: } else {
3356: $target = '';
3357: }
3358: $title = &mt($title);
3359: $linktext = &mt($linktext);
3360: return qq{<a href="$link" title="$title" $target>$linktext</a>};
3361: # FIXME uncomment when help item created: &help_open_topic('Slot_Reservation_History');
3362:
3363: }
3364:
1.508 www 3365: # ===================================================== Display a student photo
3366:
3367:
1.509 albertel 3368: sub student_image_tag {
1.508 www 3369: my ($domain,$user)=@_;
3370: my $imgsrc=&Apache::lonnet::studentphoto($domain,$user,'jpg');
3371: if (($imgsrc) && ($imgsrc ne '/adm/lonKaputt/lonlogo_broken.gif')) {
3372: return '<img src="'.$imgsrc.'" align="right" />';
3373: } else {
3374: return '';
3375: }
3376: }
3377:
1.112 bowersj2 3378: =pod
3379:
3380: =back
3381:
3382: =head1 Access .tab File Data
3383:
3384: =over 4
3385:
1.648 raeburn 3386: =item * &languageids()
1.112 bowersj2 3387:
3388: returns list of all language ids
3389:
3390: =cut
3391:
1.14 harris41 3392: sub languageids {
1.16 harris41 3393: return sort(keys(%language));
1.14 harris41 3394: }
3395:
1.112 bowersj2 3396: =pod
3397:
1.648 raeburn 3398: =item * &languagedescription()
1.112 bowersj2 3399:
3400: returns description of a specified language id
3401:
3402: =cut
3403:
1.14 harris41 3404: sub languagedescription {
1.125 www 3405: my $code=shift;
3406: return ($supported_language{$code}?'* ':'').
3407: $language{$code}.
1.126 www 3408: ($supported_language{$code}?' ('.&mt('interface available').')':'');
1.145 www 3409: }
3410:
1.1048 foxr 3411: =pod
3412:
3413: =item * &plainlanguagedescription
3414:
3415: Returns both the plain language description (e.g. 'Creoles and Pidgins, English-based (Other)')
3416: and the language character encoding (e.g. ISO) separated by a ' - ' string.
3417:
3418: =cut
3419:
1.145 www 3420: sub plainlanguagedescription {
3421: my $code=shift;
3422: return $language{$code};
3423: }
3424:
1.1048 foxr 3425: =pod
3426:
3427: =item * &supportedlanguagecode
3428:
3429: Returns the supported language code (e.g. sptutf maps to pt) given a language
3430: code.
3431:
3432: =cut
3433:
1.145 www 3434: sub supportedlanguagecode {
3435: my $code=shift;
3436: return $supported_language{$code};
1.97 www 3437: }
3438:
1.112 bowersj2 3439: =pod
3440:
1.1048 foxr 3441: =item * &latexlanguage()
3442:
3443: Given a language key code returns the correspondnig language to use
3444: to select the correct hyphenation on LaTeX printouts. This is undef if there
3445: is no supported hyphenation for the language code.
3446:
3447: =cut
3448:
3449: sub latexlanguage {
3450: my $code = shift;
3451: return $latex_language{$code};
3452: }
3453:
3454: =pod
3455:
3456: =item * &latexhyphenation()
3457:
3458: Same as above but what's supplied is the language as it might be stored
3459: in the metadata.
3460:
3461: =cut
3462:
3463: sub latexhyphenation {
3464: my $key = shift;
3465: return $latex_language_bykey{$key};
3466: }
3467:
3468: =pod
3469:
1.648 raeburn 3470: =item * ©rightids()
1.112 bowersj2 3471:
3472: returns list of all copyrights
3473:
3474: =cut
3475:
3476: sub copyrightids {
3477: return sort(keys(%cprtag));
3478: }
3479:
3480: =pod
3481:
1.648 raeburn 3482: =item * ©rightdescription()
1.112 bowersj2 3483:
3484: returns description of a specified copyright id
3485:
3486: =cut
3487:
3488: sub copyrightdescription {
1.166 www 3489: return &mt($cprtag{shift(@_)});
1.112 bowersj2 3490: }
1.197 matthew 3491:
3492: =pod
3493:
1.648 raeburn 3494: =item * &source_copyrightids()
1.192 taceyjo1 3495:
3496: returns list of all source copyrights
3497:
3498: =cut
3499:
3500: sub source_copyrightids {
3501: return sort(keys(%scprtag));
3502: }
3503:
3504: =pod
3505:
1.648 raeburn 3506: =item * &source_copyrightdescription()
1.192 taceyjo1 3507:
3508: returns description of a specified source copyright id
3509:
3510: =cut
3511:
3512: sub source_copyrightdescription {
3513: return &mt($scprtag{shift(@_)});
3514: }
1.112 bowersj2 3515:
3516: =pod
3517:
1.648 raeburn 3518: =item * &filecategories()
1.112 bowersj2 3519:
3520: returns list of all file categories
3521:
3522: =cut
3523:
3524: sub filecategories {
3525: return sort(keys(%category_extensions));
3526: }
3527:
3528: =pod
3529:
1.648 raeburn 3530: =item * &filecategorytypes()
1.112 bowersj2 3531:
3532: returns list of file types belonging to a given file
3533: category
3534:
3535: =cut
3536:
3537: sub filecategorytypes {
1.356 albertel 3538: my ($cat) = @_;
3539: return @{$category_extensions{lc($cat)}};
1.112 bowersj2 3540: }
3541:
3542: =pod
3543:
1.648 raeburn 3544: =item * &fileembstyle()
1.112 bowersj2 3545:
3546: returns embedding style for a specified file type
3547:
3548: =cut
3549:
3550: sub fileembstyle {
3551: return $fe{lc(shift(@_))};
1.169 www 3552: }
3553:
1.351 www 3554: sub filemimetype {
3555: return $fm{lc(shift(@_))};
3556: }
3557:
1.169 www 3558:
3559: sub filecategoryselect {
3560: my ($name,$value)=@_;
1.189 matthew 3561: return &select_form($value,$name,
1.970 raeburn 3562: {'' => &mt('Any category'), map { $_,$_ } sort(keys(%category_extensions))});
1.112 bowersj2 3563: }
3564:
3565: =pod
3566:
1.648 raeburn 3567: =item * &filedescription()
1.112 bowersj2 3568:
3569: returns description for a specified file type
3570:
3571: =cut
3572:
3573: sub filedescription {
1.188 matthew 3574: my $file_description = $fd{lc(shift())};
3575: $file_description =~ s:([\[\]]):~$1:g;
3576: return &mt($file_description);
1.112 bowersj2 3577: }
3578:
3579: =pod
3580:
1.648 raeburn 3581: =item * &filedescriptionex()
1.112 bowersj2 3582:
3583: returns description for a specified file type with
3584: extra formatting
3585:
3586: =cut
3587:
3588: sub filedescriptionex {
3589: my $ex=shift;
1.188 matthew 3590: my $file_description = $fd{lc($ex)};
3591: $file_description =~ s:([\[\]]):~$1:g;
3592: return '.'.$ex.' '.&mt($file_description);
1.112 bowersj2 3593: }
3594:
3595: # End of .tab access
3596: =pod
3597:
3598: =back
3599:
3600: =cut
3601:
3602: # ------------------------------------------------------------------ File Types
3603: sub fileextensions {
3604: return sort(keys(%fe));
3605: }
3606:
1.97 www 3607: # ----------------------------------------------------------- Display Languages
3608: # returns a hash with all desired display languages
3609: #
3610:
3611: sub display_languages {
3612: my %languages=();
1.695 raeburn 3613: foreach my $lang (&Apache::lonlocal::preferred_languages()) {
1.356 albertel 3614: $languages{$lang}=1;
1.97 www 3615: }
3616: &get_unprocessed_cgi($ENV{'QUERY_STRING'},['displaylanguage']);
1.258 albertel 3617: if ($env{'form.displaylanguage'}) {
1.356 albertel 3618: foreach my $lang (split(/\s*(\,|\;|\:)\s*/,$env{'form.displaylanguage'})) {
3619: $languages{$lang}=1;
1.97 www 3620: }
3621: }
3622: return %languages;
1.14 harris41 3623: }
3624:
1.582 albertel 3625: sub languages {
3626: my ($possible_langs) = @_;
1.695 raeburn 3627: my @preferred_langs = &Apache::lonlocal::preferred_languages();
1.582 albertel 3628: if (!ref($possible_langs)) {
3629: if( wantarray ) {
3630: return @preferred_langs;
3631: } else {
3632: return $preferred_langs[0];
3633: }
3634: }
3635: my %possibilities = map { $_ => 1 } (@$possible_langs);
3636: my @preferred_possibilities;
3637: foreach my $preferred_lang (@preferred_langs) {
3638: if (exists($possibilities{$preferred_lang})) {
3639: push(@preferred_possibilities, $preferred_lang);
3640: }
3641: }
3642: if( wantarray ) {
3643: return @preferred_possibilities;
3644: }
3645: return $preferred_possibilities[0];
3646: }
3647:
1.742 raeburn 3648: sub user_lang {
3649: my ($touname,$toudom,$fromcid) = @_;
3650: my @userlangs;
3651: if (($fromcid ne '') && ($env{'course.'.$fromcid.'.languages'} ne '')) {
3652: @userlangs=(@userlangs,split(/\s*(\,|\;|\:)\s*/,
3653: $env{'course.'.$fromcid.'.languages'}));
3654: } else {
3655: my %langhash = &getlangs($touname,$toudom);
3656: if ($langhash{'languages'} ne '') {
3657: @userlangs = split(/\s*(\,|\;|\:)\s*/,$langhash{'languages'});
3658: } else {
3659: my %domdefs = &Apache::lonnet::get_domain_defaults($toudom);
3660: if ($domdefs{'lang_def'} ne '') {
3661: @userlangs = ($domdefs{'lang_def'});
3662: }
3663: }
3664: }
3665: my @languages=&Apache::lonlocal::get_genlanguages(@userlangs);
3666: my $user_lh = Apache::localize->get_handle(@languages);
3667: return $user_lh;
3668: }
3669:
3670:
1.112 bowersj2 3671: ###############################################################
3672: ## Student Answer Attempts ##
3673: ###############################################################
3674:
3675: =pod
3676:
3677: =head1 Alternate Problem Views
3678:
3679: =over 4
3680:
1.648 raeburn 3681: =item * &get_previous_attempt($symb, $username, $domain, $course,
1.1075.2.86 raeburn 3682: $getattempt, $regexp, $gradesub, $usec, $identifier)
1.112 bowersj2 3683:
3684: Return string with previous attempt on problem. Arguments:
3685:
3686: =over 4
3687:
3688: =item * $symb: Problem, including path
3689:
3690: =item * $username: username of the desired student
3691:
3692: =item * $domain: domain of the desired student
1.14 harris41 3693:
1.112 bowersj2 3694: =item * $course: Course ID
1.14 harris41 3695:
1.112 bowersj2 3696: =item * $getattempt: Leave blank for all attempts, otherwise put
3697: something
1.14 harris41 3698:
1.112 bowersj2 3699: =item * $regexp: if string matches this regexp, the string will be
3700: sent to $gradesub
1.14 harris41 3701:
1.112 bowersj2 3702: =item * $gradesub: routine that processes the string if it matches $regexp
1.14 harris41 3703:
1.1075.2.86 raeburn 3704: =item * $usec: section of the desired student
3705:
3706: =item * $identifier: counter for student (multiple students one problem) or
3707: problem (one student; whole sequence).
3708:
1.112 bowersj2 3709: =back
1.14 harris41 3710:
1.112 bowersj2 3711: The output string is a table containing all desired attempts, if any.
1.16 harris41 3712:
1.112 bowersj2 3713: =cut
1.1 albertel 3714:
3715: sub get_previous_attempt {
1.1075.2.86 raeburn 3716: my ($symb,$username,$domain,$course,$getattempt,$regexp,$gradesub,$usec,$identifier)=@_;
1.1 albertel 3717: my $prevattempts='';
1.43 ng 3718: no strict 'refs';
1.1 albertel 3719: if ($symb) {
1.3 albertel 3720: my (%returnhash)=
3721: &Apache::lonnet::restore($symb,$course,$domain,$username);
1.1 albertel 3722: if ($returnhash{'version'}) {
3723: my %lasthash=();
3724: my $version;
3725: for ($version=1;$version<=$returnhash{'version'};$version++) {
1.1075.2.91 raeburn 3726: foreach my $key (reverse(sort(split(/\:/,$returnhash{$version.':keys'})))) {
3727: if ($key =~ /\.rawrndseed$/) {
3728: my ($id) = ($key =~ /^(.+)\.rawrndseed$/);
3729: $lasthash{$id.'.rndseed'} = $returnhash{$version.':'.$key};
3730: } else {
3731: $lasthash{$key}=$returnhash{$version.':'.$key};
3732: }
1.19 harris41 3733: }
1.1 albertel 3734: }
1.596 albertel 3735: $prevattempts=&start_data_table().&start_data_table_header_row();
3736: $prevattempts.='<th>'.&mt('History').'</th>';
1.1075.2.86 raeburn 3737: my (%typeparts,%lasthidden,%regraded,%hidestatus);
1.945 raeburn 3738: my $showsurv=&Apache::lonnet::allowed('vas',$env{'request.course.id'});
1.356 albertel 3739: foreach my $key (sort(keys(%lasthash))) {
3740: my ($ign,@parts) = split(/\./,$key);
1.41 ng 3741: if ($#parts > 0) {
1.31 albertel 3742: my $data=$parts[-1];
1.989 raeburn 3743: next if ($data eq 'foilorder');
1.31 albertel 3744: pop(@parts);
1.1010 www 3745: $prevattempts.='<th>'.&mt('Part ').join('.',@parts).'<br />'.$data.' </th>';
1.945 raeburn 3746: if ($data eq 'type') {
3747: unless ($showsurv) {
3748: my $id = join(',',@parts);
3749: $typeparts{$ign.'.'.$id} = $lasthash{$key};
1.978 raeburn 3750: if (($lasthash{$key} eq 'anonsurvey') || ($lasthash{$key} eq 'anonsurveycred')) {
3751: $lasthidden{$ign.'.'.$id} = 1;
3752: }
1.945 raeburn 3753: }
1.1075.2.86 raeburn 3754: if ($identifier ne '') {
3755: my $id = join(',',@parts);
3756: if (&Apache::lonnet::EXT("resource.$id.problemstatus",$symb,
3757: $domain,$username,$usec,undef,$course) =~ /^no/) {
3758: $hidestatus{$ign.'.'.$id} = 1;
3759: }
3760: }
3761: } elsif ($data eq 'regrader') {
3762: if (($identifier ne '') && (@parts)) {
3763: my $id = join(',',@parts);
3764: $regraded{$ign.'.'.$id} = 1;
3765: }
1.1010 www 3766: }
1.31 albertel 3767: } else {
1.41 ng 3768: if ($#parts == 0) {
3769: $prevattempts.='<th>'.$parts[0].'</th>';
3770: } else {
3771: $prevattempts.='<th>'.$ign.'</th>';
3772: }
1.31 albertel 3773: }
1.16 harris41 3774: }
1.596 albertel 3775: $prevattempts.=&end_data_table_header_row();
1.40 ng 3776: if ($getattempt eq '') {
1.1075.2.86 raeburn 3777: my (%solved,%resets,%probstatus);
3778: if (($identifier ne '') && (keys(%regraded) > 0)) {
3779: for ($version=1;$version<=$returnhash{'version'};$version++) {
3780: foreach my $id (keys(%regraded)) {
3781: if (($returnhash{$version.':'.$id.'.regrader'}) &&
3782: ($returnhash{$version.':'.$id.'.tries'} eq '') &&
3783: ($returnhash{$version.':'.$id.'.award'} eq '')) {
3784: push(@{$resets{$id}},$version);
3785: }
3786: }
3787: }
3788: }
1.40 ng 3789: for ($version=1;$version<=$returnhash{'version'};$version++) {
1.1075.2.86 raeburn 3790: my (@hidden,@unsolved);
1.945 raeburn 3791: if (%typeparts) {
3792: foreach my $id (keys(%typeparts)) {
1.1075.2.86 raeburn 3793: if (($returnhash{$version.':'.$id.'.type'} eq 'anonsurvey') ||
3794: ($returnhash{$version.':'.$id.'.type'} eq 'anonsurveycred')) {
1.945 raeburn 3795: push(@hidden,$id);
1.1075.2.86 raeburn 3796: } elsif ($identifier ne '') {
3797: unless (($returnhash{$version.':'.$id.'.type'} eq 'survey') ||
3798: ($returnhash{$version.':'.$id.'.type'} eq 'surveycred') ||
3799: ($hidestatus{$id})) {
3800: next if ((ref($resets{$id}) eq 'ARRAY') && grep(/^\Q$version\E$/,@{$resets{$id}}));
3801: if ($returnhash{$version.':'.$id.'.solved'} eq 'correct_by_student') {
3802: push(@{$solved{$id}},$version);
3803: } elsif (($returnhash{$version.':'.$id.'.solved'} ne '') &&
3804: (ref($solved{$id}) eq 'ARRAY')) {
3805: my $skip;
3806: if (ref($resets{$id}) eq 'ARRAY') {
3807: foreach my $reset (@{$resets{$id}}) {
3808: if ($reset > $solved{$id}[-1]) {
3809: $skip=1;
3810: last;
3811: }
3812: }
3813: }
3814: unless ($skip) {
3815: my ($ign,$partslist) = split(/\./,$id,2);
3816: push(@unsolved,$partslist);
3817: }
3818: }
3819: }
1.945 raeburn 3820: }
3821: }
3822: }
3823: $prevattempts.=&start_data_table_row().
1.1075.2.86 raeburn 3824: '<td>'.&mt('Transaction [_1]',$version);
3825: if (@unsolved) {
3826: $prevattempts .= '<span class="LC_nobreak"><label>'.
3827: '<input type="checkbox" name="HIDE'.$identifier.'" value="'.$version.':'.join('_',@unsolved).'" />'.
3828: &mt('Hide').'</label></span>';
3829: }
3830: $prevattempts .= '</td>';
1.945 raeburn 3831: if (@hidden) {
3832: foreach my $key (sort(keys(%lasthash))) {
1.989 raeburn 3833: next if ($key =~ /\.foilorder$/);
1.945 raeburn 3834: my $hide;
3835: foreach my $id (@hidden) {
3836: if ($key =~ /^\Q$id\E/) {
3837: $hide = 1;
3838: last;
3839: }
3840: }
3841: if ($hide) {
3842: my ($id,$data) = ($key =~ /^(.+)\.([^.]+)$/);
3843: if (($data eq 'award') || ($data eq 'awarddetail')) {
3844: my $value = &format_previous_attempt_value($key,
3845: $returnhash{$version.':'.$key});
3846: $prevattempts.='<td>'.$value.' </td>';
3847: } else {
3848: $prevattempts.='<td> </td>';
3849: }
3850: } else {
3851: if ($key =~ /\./) {
1.1075.2.91 raeburn 3852: my $value = $returnhash{$version.':'.$key};
3853: if ($key =~ /\.rndseed$/) {
3854: my ($id) = ($key =~ /^(.+)\.rndseed$/);
3855: if (exists($returnhash{$version.':'.$id.'.rawrndseed'})) {
3856: $value = $returnhash{$version.':'.$id.'.rawrndseed'};
3857: }
3858: }
3859: $prevattempts.='<td>'.&format_previous_attempt_value($key,$value).
3860: ' </td>';
1.945 raeburn 3861: } else {
3862: $prevattempts.='<td> </td>';
3863: }
3864: }
3865: }
3866: } else {
3867: foreach my $key (sort(keys(%lasthash))) {
1.989 raeburn 3868: next if ($key =~ /\.foilorder$/);
1.1075.2.91 raeburn 3869: my $value = $returnhash{$version.':'.$key};
3870: if ($key =~ /\.rndseed$/) {
3871: my ($id) = ($key =~ /^(.+)\.rndseed$/);
3872: if (exists($returnhash{$version.':'.$id.'.rawrndseed'})) {
3873: $value = $returnhash{$version.':'.$id.'.rawrndseed'};
3874: }
3875: }
3876: $prevattempts.='<td>'.&format_previous_attempt_value($key,$value).
3877: ' </td>';
1.945 raeburn 3878: }
3879: }
3880: $prevattempts.=&end_data_table_row();
1.40 ng 3881: }
1.1 albertel 3882: }
1.945 raeburn 3883: my @currhidden = keys(%lasthidden);
1.596 albertel 3884: $prevattempts.=&start_data_table_row().'<td>'.&mt('Current').'</td>';
1.356 albertel 3885: foreach my $key (sort(keys(%lasthash))) {
1.989 raeburn 3886: next if ($key =~ /\.foilorder$/);
1.945 raeburn 3887: if (%typeparts) {
3888: my $hidden;
3889: foreach my $id (@currhidden) {
3890: if ($key =~ /^\Q$id\E/) {
3891: $hidden = 1;
3892: last;
3893: }
3894: }
3895: if ($hidden) {
3896: my ($id,$data) = ($key =~ /^(.+)\.([^.]+)$/);
3897: if (($data eq 'award') || ($data eq 'awarddetail')) {
3898: my $value = &format_previous_attempt_value($key,$lasthash{$key});
3899: if ($key =~/$regexp$/ && (defined &$gradesub)) {
3900: $value = &$gradesub($value);
3901: }
3902: $prevattempts.='<td>'.$value.' </td>';
3903: } else {
3904: $prevattempts.='<td> </td>';
3905: }
3906: } else {
3907: my $value = &format_previous_attempt_value($key,$lasthash{$key});
3908: if ($key =~/$regexp$/ && (defined &$gradesub)) {
3909: $value = &$gradesub($value);
3910: }
3911: $prevattempts.='<td>'.$value.' </td>';
3912: }
3913: } else {
3914: my $value = &format_previous_attempt_value($key,$lasthash{$key});
3915: if ($key =~/$regexp$/ && (defined &$gradesub)) {
3916: $value = &$gradesub($value);
3917: }
3918: $prevattempts.='<td>'.$value.' </td>';
3919: }
1.16 harris41 3920: }
1.596 albertel 3921: $prevattempts.= &end_data_table_row().&end_data_table();
1.1 albertel 3922: } else {
1.596 albertel 3923: $prevattempts=
3924: &start_data_table().&start_data_table_row().
3925: '<td>'.&mt('Nothing submitted - no attempts.').'</td>'.
3926: &end_data_table_row().&end_data_table();
1.1 albertel 3927: }
3928: } else {
1.596 albertel 3929: $prevattempts=
3930: &start_data_table().&start_data_table_row().
3931: '<td>'.&mt('No data.').'</td>'.
3932: &end_data_table_row().&end_data_table();
1.1 albertel 3933: }
1.10 albertel 3934: }
3935:
1.581 albertel 3936: sub format_previous_attempt_value {
3937: my ($key,$value) = @_;
1.1011 www 3938: if (($key =~ /timestamp/) || ($key=~/duedate/)) {
1.581 albertel 3939: $value = &Apache::lonlocal::locallocaltime($value);
3940: } elsif (ref($value) eq 'ARRAY') {
3941: $value = '('.join(', ', @{ $value }).')';
1.988 raeburn 3942: } elsif ($key =~ /answerstring$/) {
3943: my %answers = &Apache::lonnet::str2hash($value);
3944: my @anskeys = sort(keys(%answers));
3945: if (@anskeys == 1) {
3946: my $answer = $answers{$anskeys[0]};
1.1001 raeburn 3947: if ($answer =~ m{\0}) {
3948: $answer =~ s{\0}{,}g;
1.988 raeburn 3949: }
3950: my $tag_internal_answer_name = 'INTERNAL';
3951: if ($anskeys[0] eq $tag_internal_answer_name) {
3952: $value = $answer;
3953: } else {
3954: $value = $anskeys[0].'='.$answer;
3955: }
3956: } else {
3957: foreach my $ans (@anskeys) {
3958: my $answer = $answers{$ans};
1.1001 raeburn 3959: if ($answer =~ m{\0}) {
3960: $answer =~ s{\0}{,}g;
1.988 raeburn 3961: }
3962: $value .= $ans.'='.$answer.'<br />';;
3963: }
3964: }
1.581 albertel 3965: } else {
3966: $value = &unescape($value);
3967: }
3968: return $value;
3969: }
3970:
3971:
1.107 albertel 3972: sub relative_to_absolute {
3973: my ($url,$output)=@_;
3974: my $parser=HTML::TokeParser->new(\$output);
3975: my $token;
3976: my $thisdir=$url;
3977: my @rlinks=();
3978: while ($token=$parser->get_token) {
3979: if ($token->[0] eq 'S') {
3980: if ($token->[1] eq 'a') {
3981: if ($token->[2]->{'href'}) {
3982: $rlinks[$#rlinks+1]=$token->[2]->{'href'};
3983: }
3984: } elsif ($token->[1] eq 'img' || $token->[1] eq 'embed' ) {
3985: $rlinks[$#rlinks+1]=$token->[2]->{'src'};
3986: } elsif ($token->[1] eq 'base') {
3987: $thisdir=$token->[2]->{'href'};
3988: }
3989: }
3990: }
3991: $thisdir=~s-/[^/]*$--;
1.356 albertel 3992: foreach my $link (@rlinks) {
1.726 raeburn 3993: unless (($link=~/^https?\:\/\//i) ||
1.356 albertel 3994: ($link=~/^\//) ||
3995: ($link=~/^javascript:/i) ||
3996: ($link=~/^mailto:/i) ||
3997: ($link=~/^\#/)) {
3998: my $newlocation=&Apache::lonnet::hreflocation($thisdir,$link);
3999: $output=~s/(\"|\'|\=\s*)\Q$link\E(\"|\'|\s|\>)/$1$newlocation$2/;
1.107 albertel 4000: }
4001: }
4002: # -------------------------------------------------- Deal with Applet codebases
4003: $output=~s/(\<applet[^\>]+)(codebase\=[^\S\>]+)*([^\>]*)\>/$1.($2?$2:' codebase="'.$thisdir.'"').$3.'>'/gei;
4004: return $output;
4005: }
4006:
1.112 bowersj2 4007: =pod
4008:
1.648 raeburn 4009: =item * &get_student_view()
1.112 bowersj2 4010:
4011: show a snapshot of what student was looking at
4012:
4013: =cut
4014:
1.10 albertel 4015: sub get_student_view {
1.186 albertel 4016: my ($symb,$username,$domain,$courseid,$target,$moreenv) = @_;
1.114 www 4017: my ($map,$id,$feedurl) = &Apache::lonnet::decode_symb($symb);
1.186 albertel 4018: my (%form);
1.10 albertel 4019: my @elements=('symb','courseid','domain','username');
4020: foreach my $element (@elements) {
1.186 albertel 4021: $form{'grade_'.$element}=eval '$'.$element #'
1.10 albertel 4022: }
1.186 albertel 4023: if (defined($moreenv)) {
4024: %form=(%form,%{$moreenv});
4025: }
1.236 albertel 4026: if (defined($target)) { $form{'grade_target'} = $target; }
1.107 albertel 4027: $feedurl=&Apache::lonnet::clutter($feedurl);
1.650 www 4028: my ($userview,$response)=&Apache::lonnet::ssi_body($feedurl,%form);
1.11 albertel 4029: $userview=~s/\<body[^\>]*\>//gi;
4030: $userview=~s/\<\/body\>//gi;
4031: $userview=~s/\<html\>//gi;
4032: $userview=~s/\<\/html\>//gi;
4033: $userview=~s/\<head\>//gi;
4034: $userview=~s/\<\/head\>//gi;
4035: $userview=~s/action\s*\=/would_be_action\=/gi;
1.107 albertel 4036: $userview=&relative_to_absolute($feedurl,$userview);
1.650 www 4037: if (wantarray) {
4038: return ($userview,$response);
4039: } else {
4040: return $userview;
4041: }
4042: }
4043:
4044: sub get_student_view_with_retries {
4045: my ($symb,$retries,$username,$domain,$courseid,$target,$moreenv) = @_;
4046:
4047: my $ok = 0; # True if we got a good response.
4048: my $content;
4049: my $response;
4050:
4051: # Try to get the student_view done. within the retries count:
4052:
4053: do {
4054: ($content, $response) = &get_student_view($symb,$username,$domain,$courseid,$target,$moreenv);
4055: $ok = $response->is_success;
4056: if (!$ok) {
4057: &Apache::lonnet::logthis("Failed get_student_view_with_retries on $symb: ".$response->is_success.', '.$response->code.', '.$response->message);
4058: }
4059: $retries--;
4060: } while (!$ok && ($retries > 0));
4061:
4062: if (!$ok) {
4063: $content = ''; # On error return an empty content.
4064: }
1.651 www 4065: if (wantarray) {
4066: return ($content, $response);
4067: } else {
4068: return $content;
4069: }
1.11 albertel 4070: }
4071:
1.112 bowersj2 4072: =pod
4073:
1.648 raeburn 4074: =item * &get_student_answers()
1.112 bowersj2 4075:
4076: show a snapshot of how student was answering problem
4077:
4078: =cut
4079:
1.11 albertel 4080: sub get_student_answers {
1.100 sakharuk 4081: my ($symb,$username,$domain,$courseid,%form) = @_;
1.114 www 4082: my ($map,$id,$feedurl) = &Apache::lonnet::decode_symb($symb);
1.186 albertel 4083: my (%moreenv);
1.11 albertel 4084: my @elements=('symb','courseid','domain','username');
4085: foreach my $element (@elements) {
1.186 albertel 4086: $moreenv{'grade_'.$element}=eval '$'.$element #'
1.10 albertel 4087: }
1.186 albertel 4088: $moreenv{'grade_target'}='answer';
4089: %moreenv=(%form,%moreenv);
1.497 raeburn 4090: $feedurl = &Apache::lonnet::clutter($feedurl);
4091: my $userview=&Apache::lonnet::ssi($feedurl,%moreenv);
1.10 albertel 4092: return $userview;
1.1 albertel 4093: }
1.116 albertel 4094:
4095: =pod
4096:
4097: =item * &submlink()
4098:
1.242 albertel 4099: Inputs: $text $uname $udom $symb $target
1.116 albertel 4100:
4101: Returns: A link to grades.pm such as to see the SUBM view of a student
4102:
4103: =cut
4104:
4105: ###############################################
4106: sub submlink {
1.242 albertel 4107: my ($text,$uname,$udom,$symb,$target)=@_;
1.116 albertel 4108: if (!($uname && $udom)) {
4109: (my $cursymb, my $courseid,$udom,$uname)=
1.463 albertel 4110: &Apache::lonnet::whichuser($symb);
1.116 albertel 4111: if (!$symb) { $symb=$cursymb; }
4112: }
1.254 matthew 4113: if (!$symb) { $symb=&Apache::lonnet::symbread(); }
1.369 www 4114: $symb=&escape($symb);
1.960 bisitz 4115: if ($target) { $target=" target=\"$target\""; }
4116: return
4117: '<a href="/adm/grades?command=submission'.
4118: '&symb='.$symb.
4119: '&student='.$uname.
4120: '&userdom='.$udom.'"'.
4121: $target.'>'.$text.'</a>';
1.242 albertel 4122: }
4123: ##############################################
4124:
4125: =pod
4126:
4127: =item * &pgrdlink()
4128:
4129: Inputs: $text $uname $udom $symb $target
4130:
4131: Returns: A link to grades.pm such as to see the PGRD view of a student
4132:
4133: =cut
4134:
4135: ###############################################
4136: sub pgrdlink {
4137: my $link=&submlink(@_);
4138: $link=~s/(&command=submission)/$1&showgrading=yes/;
4139: return $link;
4140: }
4141: ##############################################
4142:
4143: =pod
4144:
4145: =item * &pprmlink()
4146:
4147: Inputs: $text $uname $udom $symb $target
4148:
4149: Returns: A link to parmset.pm such as to see the PPRM view of a
1.283 albertel 4150: student and a specific resource
1.242 albertel 4151:
4152: =cut
4153:
4154: ###############################################
4155: sub pprmlink {
4156: my ($text,$uname,$udom,$symb,$target)=@_;
4157: if (!($uname && $udom)) {
4158: (my $cursymb, my $courseid,$udom,$uname)=
1.463 albertel 4159: &Apache::lonnet::whichuser($symb);
1.242 albertel 4160: if (!$symb) { $symb=$cursymb; }
4161: }
1.254 matthew 4162: if (!$symb) { $symb=&Apache::lonnet::symbread(); }
1.369 www 4163: $symb=&escape($symb);
1.242 albertel 4164: if ($target) { $target="target=\"$target\""; }
1.595 albertel 4165: return '<a href="/adm/parmset?command=set&'.
4166: 'symb='.$symb.'&uname='.$uname.
4167: '&udom='.$udom.'" '.$target.'>'.$text.'</a>';
1.116 albertel 4168: }
4169: ##############################################
1.37 matthew 4170:
1.112 bowersj2 4171: =pod
4172:
4173: =back
4174:
4175: =cut
4176:
1.37 matthew 4177: ###############################################
1.51 www 4178:
4179:
4180: sub timehash {
1.687 raeburn 4181: my ($thistime) = @_;
4182: my $timezone = &Apache::lonlocal::gettimezone();
4183: my $dt = DateTime->from_epoch(epoch => $thistime)
4184: ->set_time_zone($timezone);
4185: my $wday = $dt->day_of_week();
4186: if ($wday == 7) { $wday = 0; }
4187: return ( 'second' => $dt->second(),
4188: 'minute' => $dt->minute(),
4189: 'hour' => $dt->hour(),
4190: 'day' => $dt->day_of_month(),
4191: 'month' => $dt->month(),
4192: 'year' => $dt->year(),
4193: 'weekday' => $wday,
4194: 'dayyear' => $dt->day_of_year(),
4195: 'dlsav' => $dt->is_dst() );
1.51 www 4196: }
4197:
1.370 www 4198: sub utc_string {
4199: my ($date)=@_;
1.371 www 4200: return strftime("%Y%m%dT%H%M%SZ",gmtime($date));
1.370 www 4201: }
4202:
1.51 www 4203: sub maketime {
4204: my %th=@_;
1.687 raeburn 4205: my ($epoch_time,$timezone,$dt);
4206: $timezone = &Apache::lonlocal::gettimezone();
4207: eval {
4208: $dt = DateTime->new( year => $th{'year'},
4209: month => $th{'month'},
4210: day => $th{'day'},
4211: hour => $th{'hour'},
4212: minute => $th{'minute'},
4213: second => $th{'second'},
4214: time_zone => $timezone,
4215: );
4216: };
4217: if (!$@) {
4218: $epoch_time = $dt->epoch;
4219: if ($epoch_time) {
4220: return $epoch_time;
4221: }
4222: }
1.51 www 4223: return POSIX::mktime(
4224: ($th{'seconds'},$th{'minutes'},$th{'hours'},
1.210 www 4225: $th{'day'},$th{'month'}-1,$th{'year'}-1900,0,0,-1));
1.70 www 4226: }
4227:
4228: #########################################
1.51 www 4229:
4230: sub findallcourses {
1.482 raeburn 4231: my ($roles,$uname,$udom) = @_;
1.355 albertel 4232: my %roles;
4233: if (ref($roles)) { %roles = map { $_ => 1 } @{$roles}; }
1.348 albertel 4234: my %courses;
1.51 www 4235: my $now=time;
1.482 raeburn 4236: if (!defined($uname)) {
4237: $uname = $env{'user.name'};
4238: }
4239: if (!defined($udom)) {
4240: $udom = $env{'user.domain'};
4241: }
4242: if (($uname ne $env{'user.name'}) || ($udom ne $env{'user.domain'})) {
1.1073 raeburn 4243: my %roleshash = &Apache::lonnet::dump('roles',$udom,$uname);
1.482 raeburn 4244: if (!%roles) {
4245: %roles = (
4246: cc => 1,
1.907 raeburn 4247: co => 1,
1.482 raeburn 4248: in => 1,
4249: ep => 1,
4250: ta => 1,
4251: cr => 1,
4252: st => 1,
4253: );
4254: }
4255: foreach my $entry (keys(%roleshash)) {
4256: my ($trole,$tend,$tstart) = split(/_/,$roleshash{$entry});
4257: if ($trole =~ /^cr/) {
4258: next if (!exists($roles{$trole}) && !exists($roles{'cr'}));
4259: } else {
4260: next if (!exists($roles{$trole}));
4261: }
4262: if ($tend) {
4263: next if ($tend < $now);
4264: }
4265: if ($tstart) {
4266: next if ($tstart > $now);
4267: }
1.1058 raeburn 4268: my ($cdom,$cnum,$sec,$cnumpart,$secpart,$role);
1.482 raeburn 4269: (undef,$cdom,$cnumpart,$secpart) = split(/\//,$entry);
1.1058 raeburn 4270: my $value = $trole.'/'.$cdom.'/';
1.482 raeburn 4271: if ($secpart eq '') {
4272: ($cnum,$role) = split(/_/,$cnumpart);
4273: $sec = 'none';
1.1058 raeburn 4274: $value .= $cnum.'/';
1.482 raeburn 4275: } else {
4276: $cnum = $cnumpart;
4277: ($sec,$role) = split(/_/,$secpart);
1.1058 raeburn 4278: $value .= $cnum.'/'.$sec;
4279: }
4280: if (ref($courses{$cdom.'_'.$cnum}{$sec}) eq 'ARRAY') {
4281: unless (grep(/^\Q$value\E$/,@{$courses{$cdom.'_'.$cnum}{$sec}})) {
4282: push(@{$courses{$cdom.'_'.$cnum}{$sec}},$value);
4283: }
4284: } else {
4285: @{$courses{$cdom.'_'.$cnum}{$sec}} = ($value);
1.490 raeburn 4286: }
1.482 raeburn 4287: }
4288: } else {
4289: foreach my $key (keys(%env)) {
1.483 albertel 4290: if ( $key=~m{^user\.role\.(\w+)\./($match_domain)/($match_courseid)/?(\w*)$} ||
4291: $key=~m{^user\.role\.(cr/$match_domain/$match_username/\w+)\./($match_domain)/($match_courseid)/?(\w*)$}) {
1.482 raeburn 4292: my ($role,$cdom,$cnum,$sec) = ($1,$2,$3,$4);
4293: next if ($role eq 'ca' || $role eq 'aa');
4294: next if (%roles && !exists($roles{$role}));
4295: my ($starttime,$endtime)=split(/\./,$env{$key});
4296: my $active=1;
4297: if ($starttime) {
4298: if ($now<$starttime) { $active=0; }
4299: }
4300: if ($endtime) {
4301: if ($now>$endtime) { $active=0; }
4302: }
4303: if ($active) {
1.1058 raeburn 4304: my $value = $role.'/'.$cdom.'/'.$cnum.'/';
1.482 raeburn 4305: if ($sec eq '') {
4306: $sec = 'none';
1.1058 raeburn 4307: } else {
4308: $value .= $sec;
4309: }
4310: if (ref($courses{$cdom.'_'.$cnum}{$sec}) eq 'ARRAY') {
4311: unless (grep(/^\Q$value\E$/,@{$courses{$cdom.'_'.$cnum}{$sec}})) {
4312: push(@{$courses{$cdom.'_'.$cnum}{$sec}},$value);
4313: }
4314: } else {
4315: @{$courses{$cdom.'_'.$cnum}{$sec}} = ($value);
1.482 raeburn 4316: }
1.474 raeburn 4317: }
4318: }
1.51 www 4319: }
4320: }
1.474 raeburn 4321: return %courses;
1.51 www 4322: }
1.37 matthew 4323:
1.54 www 4324: ###############################################
1.474 raeburn 4325:
4326: sub blockcheck {
1.1075.2.73 raeburn 4327: my ($setters,$activity,$uname,$udom,$url,$is_course) = @_;
1.490 raeburn 4328:
1.1075.2.73 raeburn 4329: if (defined($udom) && defined($uname)) {
4330: # If uname and udom are for a course, check for blocks in the course.
4331: if (($is_course) || (&Apache::lonnet::is_course($udom,$uname))) {
4332: my ($startblock,$endblock,$triggerblock) =
4333: &get_blocks($setters,$activity,$udom,$uname,$url);
4334: return ($startblock,$endblock,$triggerblock);
4335: }
4336: } else {
1.490 raeburn 4337: $udom = $env{'user.domain'};
4338: $uname = $env{'user.name'};
4339: }
4340:
1.502 raeburn 4341: my $startblock = 0;
4342: my $endblock = 0;
1.1062 raeburn 4343: my $triggerblock = '';
1.482 raeburn 4344: my %live_courses = &findallcourses(undef,$uname,$udom);
1.474 raeburn 4345:
1.490 raeburn 4346: # If uname is for a user, and activity is course-specific, i.e.,
4347: # boards, chat or groups, check for blocking in current course only.
1.474 raeburn 4348:
1.490 raeburn 4349: if (($activity eq 'boards' || $activity eq 'chat' ||
1.1075.2.73 raeburn 4350: $activity eq 'groups' || $activity eq 'printout') &&
4351: ($env{'request.course.id'})) {
1.490 raeburn 4352: foreach my $key (keys(%live_courses)) {
4353: if ($key ne $env{'request.course.id'}) {
4354: delete($live_courses{$key});
4355: }
4356: }
4357: }
4358:
4359: my $otheruser = 0;
4360: my %own_courses;
4361: if ((($uname ne $env{'user.name'})) || ($udom ne $env{'user.domain'})) {
4362: # Resource belongs to user other than current user.
4363: $otheruser = 1;
4364: # Gather courses for current user
4365: %own_courses =
4366: &findallcourses(undef,$env{'user.name'},$env{'user.domain'});
4367: }
4368:
4369: # Gather active course roles - course coordinator, instructor,
4370: # exam proctor, ta, student, or custom role.
1.474 raeburn 4371:
4372: foreach my $course (keys(%live_courses)) {
1.482 raeburn 4373: my ($cdom,$cnum);
4374: if ((defined($env{'course.'.$course.'.domain'})) && (defined($env{'course.'.$course.'.num'}))) {
4375: $cdom = $env{'course.'.$course.'.domain'};
4376: $cnum = $env{'course.'.$course.'.num'};
4377: } else {
1.490 raeburn 4378: ($cdom,$cnum) = split(/_/,$course);
1.482 raeburn 4379: }
4380: my $no_ownblock = 0;
4381: my $no_userblock = 0;
1.533 raeburn 4382: if ($otheruser && $activity ne 'com') {
1.490 raeburn 4383: # Check if current user has 'evb' priv for this
4384: if (defined($own_courses{$course})) {
4385: foreach my $sec (keys(%{$own_courses{$course}})) {
4386: my $checkrole = 'cm./'.$cdom.'/'.$cnum;
4387: if ($sec ne 'none') {
4388: $checkrole .= '/'.$sec;
4389: }
4390: if (&Apache::lonnet::allowed('evb',undef,undef,$checkrole)) {
4391: $no_ownblock = 1;
4392: last;
4393: }
4394: }
4395: }
4396: # if they have 'evb' priv and are currently not playing student
4397: next if (($no_ownblock) &&
4398: ($env{'request.role'} !~ m{^st\./$cdom/$cnum}));
4399: }
1.474 raeburn 4400: foreach my $sec (keys(%{$live_courses{$course}})) {
1.482 raeburn 4401: my $checkrole = 'cm./'.$cdom.'/'.$cnum;
1.474 raeburn 4402: if ($sec ne 'none') {
1.482 raeburn 4403: $checkrole .= '/'.$sec;
1.474 raeburn 4404: }
1.490 raeburn 4405: if ($otheruser) {
4406: # Resource belongs to user other than current user.
4407: # Assemble privs for that user, and check for 'evb' priv.
1.1058 raeburn 4408: my (%allroles,%userroles);
4409: if (ref($live_courses{$course}{$sec}) eq 'ARRAY') {
4410: foreach my $entry (@{$live_courses{$course}{$sec}}) {
4411: my ($trole,$tdom,$tnum,$tsec);
4412: if ($entry =~ /^cr/) {
4413: ($trole,$tdom,$tnum,$tsec) =
4414: ($entry =~ m|^(cr/$match_domain/$match_username/\w+)\./($match_domain)/($match_username)/?(\w*)$|);
4415: } else {
4416: ($trole,$tdom,$tnum,$tsec) = split(/\//,$entry);
4417: }
4418: my ($spec,$area,$trest);
4419: $area = '/'.$tdom.'/'.$tnum;
4420: $trest = $tnum;
4421: if ($tsec ne '') {
4422: $area .= '/'.$tsec;
4423: $trest .= '/'.$tsec;
4424: }
4425: $spec = $trole.'.'.$area;
4426: if ($trole =~ /^cr/) {
4427: &Apache::lonnet::custom_roleprivs(\%allroles,$trole,
4428: $tdom,$spec,$trest,$area);
4429: } else {
4430: &Apache::lonnet::standard_roleprivs(\%allroles,$trole,
4431: $tdom,$spec,$trest,$area);
4432: }
4433: }
4434: my ($author,$adv) = &Apache::lonnet::set_userprivs(\%userroles,\%allroles);
4435: if ($userroles{'user.priv.'.$checkrole} =~ /evb\&([^\:]*)/) {
4436: if ($1) {
4437: $no_userblock = 1;
4438: last;
4439: }
1.486 raeburn 4440: }
4441: }
1.490 raeburn 4442: } else {
4443: # Resource belongs to current user
4444: # Check for 'evb' priv via lonnet::allowed().
1.482 raeburn 4445: if (&Apache::lonnet::allowed('evb',undef,undef,$checkrole)) {
4446: $no_ownblock = 1;
4447: last;
4448: }
1.474 raeburn 4449: }
4450: }
4451: # if they have the evb priv and are currently not playing student
1.482 raeburn 4452: next if (($no_ownblock) &&
1.491 albertel 4453: ($env{'request.role'} !~ m{^st\./\Q$cdom\E/\Q$cnum\E}));
1.482 raeburn 4454: next if ($no_userblock);
1.474 raeburn 4455:
1.866 kalberla 4456: # Retrieve blocking times and identity of locker for course
1.490 raeburn 4457: # of specified user, unless user has 'evb' privilege.
1.502 raeburn 4458:
1.1062 raeburn 4459: my ($start,$end,$trigger) =
4460: &get_blocks($setters,$activity,$cdom,$cnum,$url);
1.502 raeburn 4461: if (($start != 0) &&
4462: (($startblock == 0) || ($startblock > $start))) {
4463: $startblock = $start;
1.1062 raeburn 4464: if ($trigger ne '') {
4465: $triggerblock = $trigger;
4466: }
1.502 raeburn 4467: }
4468: if (($end != 0) &&
4469: (($endblock == 0) || ($endblock < $end))) {
4470: $endblock = $end;
1.1062 raeburn 4471: if ($trigger ne '') {
4472: $triggerblock = $trigger;
4473: }
1.502 raeburn 4474: }
1.490 raeburn 4475: }
1.1062 raeburn 4476: return ($startblock,$endblock,$triggerblock);
1.490 raeburn 4477: }
4478:
4479: sub get_blocks {
1.1062 raeburn 4480: my ($setters,$activity,$cdom,$cnum,$url) = @_;
1.490 raeburn 4481: my $startblock = 0;
4482: my $endblock = 0;
1.1062 raeburn 4483: my $triggerblock = '';
1.490 raeburn 4484: my $course = $cdom.'_'.$cnum;
4485: $setters->{$course} = {};
4486: $setters->{$course}{'staff'} = [];
4487: $setters->{$course}{'times'} = [];
1.1062 raeburn 4488: $setters->{$course}{'triggers'} = [];
4489: my (@blockers,%triggered);
4490: my $now = time;
4491: my %commblocks = &Apache::lonnet::get_comm_blocks($cdom,$cnum);
4492: if ($activity eq 'docs') {
4493: @blockers = &Apache::lonnet::has_comm_blocking('bre',undef,$url,\%commblocks);
4494: foreach my $block (@blockers) {
4495: if ($block =~ /^firstaccess____(.+)$/) {
4496: my $item = $1;
4497: my $type = 'map';
4498: my $timersymb = $item;
4499: if ($item eq 'course') {
4500: $type = 'course';
4501: } elsif ($item =~ /___\d+___/) {
4502: $type = 'resource';
4503: } else {
4504: $timersymb = &Apache::lonnet::symbread($item);
4505: }
4506: my $start = $env{'course.'.$cdom.'_'.$cnum.'.firstaccess.'.$timersymb};
4507: my $end = $start + $env{'course.'.$cdom.'_'.$cnum.'.timerinterval.'.$timersymb};
4508: $triggered{$block} = {
4509: start => $start,
4510: end => $end,
4511: type => $type,
4512: };
4513: }
4514: }
4515: } else {
4516: foreach my $block (keys(%commblocks)) {
4517: if ($block =~ m/^(\d+)____(\d+)$/) {
4518: my ($start,$end) = ($1,$2);
4519: if ($start <= time && $end >= time) {
4520: if (ref($commblocks{$block}) eq 'HASH') {
4521: if (ref($commblocks{$block}{'blocks'}) eq 'HASH') {
4522: if ($commblocks{$block}{'blocks'}{$activity} eq 'on') {
4523: unless(grep(/^\Q$block\E$/,@blockers)) {
4524: push(@blockers,$block);
4525: }
4526: }
4527: }
4528: }
4529: }
4530: } elsif ($block =~ /^firstaccess____(.+)$/) {
4531: my $item = $1;
4532: my $timersymb = $item;
4533: my $type = 'map';
4534: if ($item eq 'course') {
4535: $type = 'course';
4536: } elsif ($item =~ /___\d+___/) {
4537: $type = 'resource';
4538: } else {
4539: $timersymb = &Apache::lonnet::symbread($item);
4540: }
4541: my $start = $env{'course.'.$cdom.'_'.$cnum.'.firstaccess.'.$timersymb};
4542: my $end = $start + $env{'course.'.$cdom.'_'.$cnum.'.timerinterval.'.$timersymb};
4543: if ($start && $end) {
4544: if (($start <= time) && ($end >= time)) {
4545: unless (grep(/^\Q$block\E$/,@blockers)) {
4546: push(@blockers,$block);
4547: $triggered{$block} = {
4548: start => $start,
4549: end => $end,
4550: type => $type,
4551: };
4552: }
4553: }
1.490 raeburn 4554: }
1.1062 raeburn 4555: }
4556: }
4557: }
4558: foreach my $blocker (@blockers) {
4559: my ($staff_name,$staff_dom,$title,$blocks) =
4560: &parse_block_record($commblocks{$blocker});
4561: push(@{$$setters{$course}{'staff'}},[$staff_name,$staff_dom]);
4562: my ($start,$end,$triggertype);
4563: if ($blocker =~ m/^(\d+)____(\d+)$/) {
4564: ($start,$end) = ($1,$2);
4565: } elsif (ref($triggered{$blocker}) eq 'HASH') {
4566: $start = $triggered{$blocker}{'start'};
4567: $end = $triggered{$blocker}{'end'};
4568: $triggertype = $triggered{$blocker}{'type'};
4569: }
4570: if ($start) {
4571: push(@{$$setters{$course}{'times'}}, [$start,$end]);
4572: if ($triggertype) {
4573: push(@{$$setters{$course}{'triggers'}},$triggertype);
4574: } else {
4575: push(@{$$setters{$course}{'triggers'}},0);
4576: }
4577: if ( ($startblock == 0) || ($startblock > $start) ) {
4578: $startblock = $start;
4579: if ($triggertype) {
4580: $triggerblock = $blocker;
1.474 raeburn 4581: }
4582: }
1.1062 raeburn 4583: if ( ($endblock == 0) || ($endblock < $end) ) {
4584: $endblock = $end;
4585: if ($triggertype) {
4586: $triggerblock = $blocker;
4587: }
4588: }
1.474 raeburn 4589: }
4590: }
1.1062 raeburn 4591: return ($startblock,$endblock,$triggerblock);
1.474 raeburn 4592: }
4593:
4594: sub parse_block_record {
4595: my ($record) = @_;
4596: my ($setuname,$setudom,$title,$blocks);
4597: if (ref($record) eq 'HASH') {
4598: ($setuname,$setudom) = split(/:/,$record->{'setter'});
4599: $title = &unescape($record->{'event'});
4600: $blocks = $record->{'blocks'};
4601: } else {
4602: my @data = split(/:/,$record,3);
4603: if (scalar(@data) eq 2) {
4604: $title = $data[1];
4605: ($setuname,$setudom) = split(/@/,$data[0]);
4606: } else {
4607: ($setuname,$setudom,$title) = @data;
4608: }
4609: $blocks = { 'com' => 'on' };
4610: }
4611: return ($setuname,$setudom,$title,$blocks);
4612: }
4613:
1.854 kalberla 4614: sub blocking_status {
1.1075.2.73 raeburn 4615: my ($activity,$uname,$udom,$url,$is_course) = @_;
1.1061 raeburn 4616: my %setters;
1.890 droeschl 4617:
1.1061 raeburn 4618: # check for active blocking
1.1062 raeburn 4619: my ($startblock,$endblock,$triggerblock) =
1.1075.2.73 raeburn 4620: &blockcheck(\%setters,$activity,$uname,$udom,$url,$is_course);
1.1062 raeburn 4621: my $blocked = 0;
4622: if ($startblock && $endblock) {
4623: $blocked = 1;
4624: }
1.890 droeschl 4625:
1.1061 raeburn 4626: # caller just wants to know whether a block is active
4627: if (!wantarray) { return $blocked; }
4628:
4629: # build a link to a popup window containing the details
4630: my $querystring = "?activity=$activity";
4631: # $uname and $udom decide whose portfolio the user is trying to look at
1.1062 raeburn 4632: if ($activity eq 'port') {
4633: $querystring .= "&udom=$udom" if $udom;
4634: $querystring .= "&uname=$uname" if $uname;
4635: } elsif ($activity eq 'docs') {
4636: $querystring .= '&url='.&HTML::Entities::encode($url,'&"');
4637: }
1.1061 raeburn 4638:
4639: my $output .= <<'END_MYBLOCK';
4640: function openWindow(url, wdwName, w, h, toolbar,scrollbar) {
4641: var options = "width=" + w + ",height=" + h + ",";
4642: options += "resizable=yes,scrollbars="+scrollbar+",status=no,";
4643: options += "menubar=no,toolbar="+toolbar+",location=no,directories=no";
4644: var newWin = window.open(url, wdwName, options);
4645: newWin.focus();
4646: }
1.890 droeschl 4647: END_MYBLOCK
1.854 kalberla 4648:
1.1061 raeburn 4649: $output = Apache::lonhtmlcommon::scripttag($output);
1.890 droeschl 4650:
1.1061 raeburn 4651: my $popupUrl = "/adm/blockingstatus/$querystring";
1.1062 raeburn 4652: my $text = &mt('Communication Blocked');
1.1075.2.93 raeburn 4653: my $class = 'LC_comblock';
1.1062 raeburn 4654: if ($activity eq 'docs') {
4655: $text = &mt('Content Access Blocked');
1.1075.2.93 raeburn 4656: $class = '';
1.1063 raeburn 4657: } elsif ($activity eq 'printout') {
4658: $text = &mt('Printing Blocked');
1.1062 raeburn 4659: }
1.1061 raeburn 4660: $output .= <<"END_BLOCK";
1.1075.2.93 raeburn 4661: <div class='$class'>
1.869 kalberla 4662: <a onclick='openWindow("$popupUrl","Blocking Table",600,300,"no","no");return false;' href='/adm/blockingstatus/$querystring'
1.890 droeschl 4663: title='$text'>
4664: <img class='LC_noBorder LC_middle' title='$text' src='/res/adm/pages/comblock.png' alt='$text'/></a>
1.869 kalberla 4665: <a onclick='openWindow("$popupUrl","Blocking Table",600,300,"no","no");return false;' href='/adm/blockingstatus/$querystring'
1.890 droeschl 4666: title='$text'>$text</a>
1.867 kalberla 4667: </div>
4668:
4669: END_BLOCK
1.474 raeburn 4670:
1.1061 raeburn 4671: return ($blocked, $output);
1.854 kalberla 4672: }
1.490 raeburn 4673:
1.60 matthew 4674: ###############################################
4675:
1.682 raeburn 4676: sub check_ip_acc {
4677: my ($acc)=@_;
4678: &Apache::lonxml::debug("acc is $acc");
4679: if (!defined($acc) || $acc =~ /^\s*$/ || $acc =~/^\s*no\s*$/i) {
4680: return 1;
4681: }
4682: my $allowed=0;
4683: my $ip=$env{'request.host'} || $ENV{'REMOTE_ADDR'};
4684:
4685: my $name;
4686: foreach my $pattern (split(',',$acc)) {
4687: $pattern =~ s/^\s*//;
4688: $pattern =~ s/\s*$//;
4689: if ($pattern =~ /\*$/) {
4690: #35.8.*
4691: $pattern=~s/\*//;
4692: if ($ip =~ /^\Q$pattern\E/) { $allowed=1; }
4693: } elsif ($pattern =~ /(\d+\.\d+\.\d+)\.\[(\d+)-(\d+)\]$/) {
4694: #35.8.3.[34-56]
4695: my $low=$2;
4696: my $high=$3;
4697: $pattern=$1;
4698: if ($ip =~ /^\Q$pattern\E/) {
4699: my $last=(split(/\./,$ip))[3];
4700: if ($last <=$high && $last >=$low) { $allowed=1; }
4701: }
4702: } elsif ($pattern =~ /^\*/) {
4703: #*.msu.edu
4704: $pattern=~s/\*//;
4705: if (!defined($name)) {
4706: use Socket;
4707: my $netaddr=inet_aton($ip);
4708: ($name)=gethostbyaddr($netaddr,AF_INET);
4709: }
4710: if ($name =~ /\Q$pattern\E$/i) { $allowed=1; }
4711: } elsif ($pattern =~ /\d+\.\d+\.\d+\.\d+/) {
4712: #127.0.0.1
4713: if ($ip =~ /^\Q$pattern\E/) { $allowed=1; }
4714: } else {
4715: #some.name.com
4716: if (!defined($name)) {
4717: use Socket;
4718: my $netaddr=inet_aton($ip);
4719: ($name)=gethostbyaddr($netaddr,AF_INET);
4720: }
4721: if ($name =~ /\Q$pattern\E$/i) { $allowed=1; }
4722: }
4723: if ($allowed) { last; }
4724: }
4725: return $allowed;
4726: }
4727:
4728: ###############################################
4729:
1.60 matthew 4730: =pod
4731:
1.112 bowersj2 4732: =head1 Domain Template Functions
4733:
4734: =over 4
4735:
4736: =item * &determinedomain()
1.60 matthew 4737:
4738: Inputs: $domain (usually will be undef)
4739:
1.63 www 4740: Returns: Determines which domain should be used for designs
1.60 matthew 4741:
4742: =cut
1.54 www 4743:
1.60 matthew 4744: ###############################################
1.63 www 4745: sub determinedomain {
4746: my $domain=shift;
1.531 albertel 4747: if (! $domain) {
1.60 matthew 4748: # Determine domain if we have not been given one
1.893 raeburn 4749: $domain = &Apache::lonnet::default_login_domain();
1.258 albertel 4750: if ($env{'user.domain'}) { $domain=$env{'user.domain'}; }
4751: if ($env{'request.role.domain'}) {
4752: $domain=$env{'request.role.domain'};
1.60 matthew 4753: }
4754: }
1.63 www 4755: return $domain;
4756: }
4757: ###############################################
1.517 raeburn 4758:
1.518 albertel 4759: sub devalidate_domconfig_cache {
4760: my ($udom)=@_;
4761: &Apache::lonnet::devalidate_cache_new('domainconfig',$udom);
4762: }
4763:
4764: # ---------------------- Get domain configuration for a domain
4765: sub get_domainconf {
4766: my ($udom) = @_;
4767: my $cachetime=1800;
4768: my ($result,$cached)=&Apache::lonnet::is_cached_new('domainconfig',$udom);
4769: if (defined($cached)) { return %{$result}; }
4770:
4771: my %domconfig = &Apache::lonnet::get_dom('configuration',
1.948 raeburn 4772: ['login','rolecolors','autoenroll'],$udom);
1.632 raeburn 4773: my (%designhash,%legacy);
1.518 albertel 4774: if (keys(%domconfig) > 0) {
4775: if (ref($domconfig{'login'}) eq 'HASH') {
1.632 raeburn 4776: if (keys(%{$domconfig{'login'}})) {
4777: foreach my $key (keys(%{$domconfig{'login'}})) {
1.699 raeburn 4778: if (ref($domconfig{'login'}{$key}) eq 'HASH') {
1.1075.2.87 raeburn 4779: if (($key eq 'loginvia') || ($key eq 'headtag')) {
4780: if (ref($domconfig{'login'}{$key}) eq 'HASH') {
4781: foreach my $hostname (keys(%{$domconfig{'login'}{$key}})) {
4782: if (ref($domconfig{'login'}{$key}{$hostname}) eq 'HASH') {
4783: if ($key eq 'loginvia') {
4784: if ($domconfig{'login'}{'loginvia'}{$hostname}{'server'}) {
4785: my $server = $domconfig{'login'}{'loginvia'}{$hostname}{'server'};
4786: $designhash{$udom.'.login.loginvia'} = $server;
4787: if ($domconfig{'login'}{'loginvia'}{$hostname}{'serverpath'} eq 'custom') {
4788: $designhash{$udom.'.login.loginvia_'.$hostname} = $server.':'.$domconfig{'login'}{'loginvia'}{$hostname}{'custompath'};
4789: } else {
4790: $designhash{$udom.'.login.loginvia_'.$hostname} = $server.':'.$domconfig{'login'}{'loginvia'}{$hostname}{'serverpath'};
4791: }
1.948 raeburn 4792: }
1.1075.2.87 raeburn 4793: } elsif ($key eq 'headtag') {
4794: if ($domconfig{'login'}{'headtag'}{$hostname}{'url'}) {
4795: $designhash{$udom.'.login.headtag_'.$hostname} = $domconfig{'login'}{'headtag'}{$hostname}{'url'};
1.948 raeburn 4796: }
1.946 raeburn 4797: }
1.1075.2.87 raeburn 4798: if ($domconfig{'login'}{$key}{$hostname}{'exempt'}) {
4799: $designhash{$udom.'.login.'.$key.'_exempt_'.$hostname} = $domconfig{'login'}{$key}{$hostname}{'exempt'};
4800: }
1.946 raeburn 4801: }
4802: }
4803: }
4804: } else {
4805: foreach my $img (keys(%{$domconfig{'login'}{$key}})) {
4806: $designhash{$udom.'.login.'.$key.'_'.$img} =
4807: $domconfig{'login'}{$key}{$img};
4808: }
1.699 raeburn 4809: }
4810: } else {
4811: $designhash{$udom.'.login.'.$key}=$domconfig{'login'}{$key};
4812: }
1.632 raeburn 4813: }
4814: } else {
4815: $legacy{'login'} = 1;
1.518 albertel 4816: }
1.632 raeburn 4817: } else {
4818: $legacy{'login'} = 1;
1.518 albertel 4819: }
4820: if (ref($domconfig{'rolecolors'}) eq 'HASH') {
1.632 raeburn 4821: if (keys(%{$domconfig{'rolecolors'}})) {
4822: foreach my $role (keys(%{$domconfig{'rolecolors'}})) {
4823: if (ref($domconfig{'rolecolors'}{$role}) eq 'HASH') {
4824: foreach my $item (keys(%{$domconfig{'rolecolors'}{$role}})) {
4825: $designhash{$udom.'.'.$role.'.'.$item}=$domconfig{'rolecolors'}{$role}{$item};
4826: }
1.518 albertel 4827: }
4828: }
1.632 raeburn 4829: } else {
4830: $legacy{'rolecolors'} = 1;
1.518 albertel 4831: }
1.632 raeburn 4832: } else {
4833: $legacy{'rolecolors'} = 1;
1.518 albertel 4834: }
1.948 raeburn 4835: if (ref($domconfig{'autoenroll'}) eq 'HASH') {
4836: if ($domconfig{'autoenroll'}{'co-owners'}) {
4837: $designhash{$udom.'.autoassign.co-owners'}=$domconfig{'autoenroll'}{'co-owners'};
4838: }
4839: }
1.632 raeburn 4840: if (keys(%legacy) > 0) {
4841: my %legacyhash = &get_legacy_domconf($udom);
4842: foreach my $item (keys(%legacyhash)) {
4843: if ($item =~ /^\Q$udom\E\.login/) {
4844: if ($legacy{'login'}) {
4845: $designhash{$item} = $legacyhash{$item};
4846: }
4847: } else {
4848: if ($legacy{'rolecolors'}) {
4849: $designhash{$item} = $legacyhash{$item};
4850: }
1.518 albertel 4851: }
4852: }
4853: }
1.632 raeburn 4854: } else {
4855: %designhash = &get_legacy_domconf($udom);
1.518 albertel 4856: }
4857: &Apache::lonnet::do_cache_new('domainconfig',$udom,\%designhash,
4858: $cachetime);
4859: return %designhash;
4860: }
4861:
1.632 raeburn 4862: sub get_legacy_domconf {
4863: my ($udom) = @_;
4864: my %legacyhash;
4865: my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors';
4866: my $designfile = $designdir.'/'.$udom.'.tab';
4867: if (-e $designfile) {
4868: if ( open (my $fh,"<$designfile") ) {
4869: while (my $line = <$fh>) {
4870: next if ($line =~ /^\#/);
4871: chomp($line);
4872: my ($key,$val)=(split(/\=/,$line));
4873: if ($val) { $legacyhash{$udom.'.'.$key}=$val; }
4874: }
4875: close($fh);
4876: }
4877: }
1.1026 raeburn 4878: if (-e $Apache::lonnet::perlvar{'lonDocRoot'}.'/adm/lonDomLogos/'.$udom.'.gif') {
1.632 raeburn 4879: $legacyhash{$udom.'.login.domlogo'} = "/adm/lonDomLogos/$udom.gif";
4880: }
4881: return %legacyhash;
4882: }
4883:
1.63 www 4884: =pod
4885:
1.112 bowersj2 4886: =item * &domainlogo()
1.63 www 4887:
4888: Inputs: $domain (usually will be undef)
4889:
4890: Returns: A link to a domain logo, if the domain logo exists.
4891: If the domain logo does not exist, a description of the domain.
4892:
4893: =cut
1.112 bowersj2 4894:
1.63 www 4895: ###############################################
4896: sub domainlogo {
1.517 raeburn 4897: my $domain = &determinedomain(shift);
1.518 albertel 4898: my %designhash = &get_domainconf($domain);
1.517 raeburn 4899: # See if there is a logo
4900: if ($designhash{$domain.'.login.domlogo'} ne '') {
1.519 raeburn 4901: my $imgsrc = $designhash{$domain.'.login.domlogo'};
1.538 albertel 4902: if ($imgsrc =~ m{^/(adm|res)/}) {
4903: if ($imgsrc =~ m{^/res/}) {
4904: my $local_name = &Apache::lonnet::filelocation('',$imgsrc);
4905: &Apache::lonnet::repcopy($local_name);
4906: }
4907: $imgsrc = &lonhttpdurl($imgsrc);
1.519 raeburn 4908: }
4909: return '<img src="'.$imgsrc.'" alt="'.$domain.'" />';
1.514 albertel 4910: } elsif (defined(&Apache::lonnet::domain($domain,'description'))) {
4911: return &Apache::lonnet::domain($domain,'description');
1.59 www 4912: } else {
1.60 matthew 4913: return '';
1.59 www 4914: }
4915: }
1.63 www 4916: ##############################################
4917:
4918: =pod
4919:
1.112 bowersj2 4920: =item * &designparm()
1.63 www 4921:
4922: Inputs: $which parameter; $domain (usually will be undef)
4923:
4924: Returns: value of designparamter $which
4925:
4926: =cut
1.112 bowersj2 4927:
1.397 albertel 4928:
1.400 albertel 4929: ##############################################
1.397 albertel 4930: sub designparm {
4931: my ($which,$domain)=@_;
4932: if (exists($env{'environment.color.'.$which})) {
1.817 bisitz 4933: return $env{'environment.color.'.$which};
1.96 www 4934: }
1.63 www 4935: $domain=&determinedomain($domain);
1.1016 raeburn 4936: my %domdesign;
4937: unless ($domain eq 'public') {
4938: %domdesign = &get_domainconf($domain);
4939: }
1.520 raeburn 4940: my $output;
1.517 raeburn 4941: if ($domdesign{$domain.'.'.$which} ne '') {
1.817 bisitz 4942: $output = $domdesign{$domain.'.'.$which};
1.63 www 4943: } else {
1.520 raeburn 4944: $output = $defaultdesign{$which};
4945: }
4946: if (($which =~ /^(student|coordinator|author|admin)\.img$/) ||
1.635 raeburn 4947: ($which =~ /login\.(img|logo|domlogo|login)/)) {
1.538 albertel 4948: if ($output =~ m{^/(adm|res)/}) {
1.817 bisitz 4949: if ($output =~ m{^/res/}) {
4950: my $local_name = &Apache::lonnet::filelocation('',$output);
4951: &Apache::lonnet::repcopy($local_name);
4952: }
1.520 raeburn 4953: $output = &lonhttpdurl($output);
4954: }
1.63 www 4955: }
1.520 raeburn 4956: return $output;
1.63 www 4957: }
1.59 www 4958:
1.822 bisitz 4959: ##############################################
4960: =pod
4961:
1.832 bisitz 4962: =item * &authorspace()
4963:
1.1028 raeburn 4964: Inputs: $url (usually will be undef).
1.832 bisitz 4965:
1.1075.2.40 raeburn 4966: Returns: Path to Authoring Space containing the resource or
1.1028 raeburn 4967: directory being viewed (or for which action is being taken).
4968: If $url is provided, and begins /priv/<domain>/<uname>
4969: the path will be that portion of the $context argument.
4970: Otherwise the path will be for the author space of the current
4971: user when the current role is author, or for that of the
4972: co-author/assistant co-author space when the current role
4973: is co-author or assistant co-author.
1.832 bisitz 4974:
4975: =cut
4976:
4977: sub authorspace {
1.1028 raeburn 4978: my ($url) = @_;
4979: if ($url ne '') {
4980: if ($url =~ m{^(/priv/$match_domain/$match_username/)}) {
4981: return $1;
4982: }
4983: }
1.832 bisitz 4984: my $caname = '';
1.1024 www 4985: my $cadom = '';
1.1028 raeburn 4986: if ($env{'request.role'} =~ /^(?:ca|aa)/) {
1.1024 www 4987: ($cadom,$caname) =
1.832 bisitz 4988: ($env{'request.role'}=~/($match_domain)\/($match_username)$/);
1.1028 raeburn 4989: } elsif ($env{'request.role'} =~ m{^au\./($match_domain)/}) {
1.832 bisitz 4990: $caname = $env{'user.name'};
1.1024 www 4991: $cadom = $env{'user.domain'};
1.832 bisitz 4992: }
1.1028 raeburn 4993: if (($caname ne '') && ($cadom ne '')) {
4994: return "/priv/$cadom/$caname/";
4995: }
4996: return;
1.832 bisitz 4997: }
4998:
4999: ##############################################
5000: =pod
5001:
1.822 bisitz 5002: =item * &head_subbox()
5003:
5004: Inputs: $content (contains HTML code with page functions, etc.)
5005:
5006: Returns: HTML div with $content
5007: To be included in page header
5008:
5009: =cut
5010:
5011: sub head_subbox {
5012: my ($content)=@_;
5013: my $output =
1.993 raeburn 5014: '<div class="LC_head_subbox">'
1.822 bisitz 5015: .$content
5016: .'</div>'
5017: }
5018:
5019: ##############################################
5020: =pod
5021:
5022: =item * &CSTR_pageheader()
5023:
1.1026 raeburn 5024: Input: (optional) filename from which breadcrumb trail is built.
5025: In most cases no input as needed, as $env{'request.filename'}
5026: is appropriate for use in building the breadcrumb trail.
1.822 bisitz 5027:
5028: Returns: HTML div with CSTR path and recent box
1.1075.2.40 raeburn 5029: To be included on Authoring Space pages
1.822 bisitz 5030:
5031: =cut
5032:
5033: sub CSTR_pageheader {
1.1026 raeburn 5034: my ($trailfile) = @_;
5035: if ($trailfile eq '') {
5036: $trailfile = $env{'request.filename'};
5037: }
5038:
5039: # this is for resources; directories have customtitle, and crumbs
5040: # and select recent are created in lonpubdir.pm
5041:
5042: my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'};
1.1022 www 5043: my ($udom,$uname,$thisdisfn)=
1.1075.2.29 raeburn 5044: ($trailfile =~ m{^\Q$londocroot\E/priv/([^/]+)/([^/]+)(?:|/(.*))$});
1.1026 raeburn 5045: my $formaction = "/priv/$udom/$uname/$thisdisfn";
5046: $formaction =~ s{/+}{/}g;
1.822 bisitz 5047:
5048: my $parentpath = '';
5049: my $lastitem = '';
5050: if ($thisdisfn =~ m-(.+/)([^/]*)$-) {
5051: $parentpath = $1;
5052: $lastitem = $2;
5053: } else {
5054: $lastitem = $thisdisfn;
5055: }
1.921 bisitz 5056:
5057: my $output =
1.822 bisitz 5058: '<div>'
5059: .&Apache::loncommon::help_open_menu('','',3,'Authoring') #FIXME: Broken? Where is it?
1.1075.2.40 raeburn 5060: .'<b>'.&mt('Authoring Space:').'</b> '
1.822 bisitz 5061: .'<form name="dirs" method="post" action="'.$formaction
1.921 bisitz 5062: .'" target="_top">' #FIXME lonpubdir: target="_parent"
1.1024 www 5063: .&Apache::lonhtmlcommon::crumbs($uname.'/'.$parentpath,'_top','/priv/'.$udom,undef,undef);
1.921 bisitz 5064:
5065: if ($lastitem) {
5066: $output .=
5067: '<span class="LC_filename">'
5068: .$lastitem
5069: .'</span>';
5070: }
5071: $output .=
5072: '<br />'
1.822 bisitz 5073: #FIXME lonpubdir: &Apache::lonhtmlcommon::crumbs($uname.$thisdisfn.'/','_top','/priv','','+1',1)."</b></tt><br />"
5074: .&Apache::lonhtmlcommon::select_recent('construct','recent','this.form.action=this.form.recent.value;this.form.submit()')
5075: .'</form>'
5076: .&Apache::lonmenu::constspaceform()
5077: .'</div>';
1.921 bisitz 5078:
5079: return $output;
1.822 bisitz 5080: }
5081:
1.60 matthew 5082: ###############################################
5083: ###############################################
5084:
5085: =pod
5086:
1.112 bowersj2 5087: =back
5088:
1.549 albertel 5089: =head1 HTML Helpers
1.112 bowersj2 5090:
5091: =over 4
5092:
5093: =item * &bodytag()
1.60 matthew 5094:
5095: Returns a uniform header for LON-CAPA web pages.
5096:
5097: Inputs:
5098:
1.112 bowersj2 5099: =over 4
5100:
5101: =item * $title, A title to be displayed on the page.
5102:
5103: =item * $function, the current role (can be undef).
5104:
5105: =item * $addentries, extra parameters for the <body> tag.
5106:
5107: =item * $bodyonly, if defined, only return the <body> tag.
5108:
5109: =item * $domain, if defined, force a given domain.
5110:
5111: =item * $forcereg, if page should register as content page (relevant for
1.86 www 5112: text interface only)
1.60 matthew 5113:
1.814 bisitz 5114: =item * $no_nav_bar, if true, keep the 'what is this' info but remove the
5115: navigational links
1.317 albertel 5116:
1.338 albertel 5117: =item * $bgcolor, used to override the bgcolor on a webpage to a specific value
5118:
1.1075.2.12 raeburn 5119: =item * $no_inline_link, if true and in remote mode, don't show the
5120: 'Switch To Inline Menu' link
5121:
1.460 albertel 5122: =item * $args, optional argument valid values are
5123: no_auto_mt_title -> prevents &mt()ing the title arg
1.562 albertel 5124: inherit_jsmath -> when creating popup window in a page,
5125: should it have jsmath forced on by the
5126: current page
1.460 albertel 5127:
1.1075.2.15 raeburn 5128: =item * $advtoolsref, optional argument, ref to an array containing
5129: inlineremote items to be added in "Functions" menu below
5130: breadcrumbs.
5131:
1.112 bowersj2 5132: =back
5133:
1.60 matthew 5134: Returns: A uniform header for LON-CAPA web pages.
5135: If $bodyonly is nonzero, a string containing a <body> tag will be returned.
5136: If $bodyonly is undef or zero, an html string containing a <body> tag and
5137: other decorations will be returned.
5138:
5139: =cut
5140:
1.54 www 5141: sub bodytag {
1.831 bisitz 5142: my ($title,$function,$addentries,$bodyonly,$domain,$forcereg,
1.1075.2.15 raeburn 5143: $no_nav_bar,$bgcolor,$no_inline_link,$args,$advtoolsref)=@_;
1.339 albertel 5144:
1.954 raeburn 5145: my $public;
5146: if ((($env{'user.name'} eq 'public') && ($env{'user.domain'} eq 'public'))
5147: || ($env{'user.name'} eq '') && ($env{'user.domain'} eq '')) {
5148: $public = 1;
5149: }
1.460 albertel 5150: if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); }
1.1075.2.52 raeburn 5151: my $httphost = $args->{'use_absolute'};
1.339 albertel 5152:
1.183 matthew 5153: $function = &get_users_function() if (!$function);
1.339 albertel 5154: my $img = &designparm($function.'.img',$domain);
5155: my $font = &designparm($function.'.font',$domain);
5156: my $pgbg = $bgcolor || &designparm($function.'.pgbg',$domain);
5157:
1.803 bisitz 5158: my %design = ( 'style' => 'margin-top: 0',
1.535 albertel 5159: 'bgcolor' => $pgbg,
1.339 albertel 5160: 'text' => $font,
5161: 'alink' => &designparm($function.'.alink',$domain),
5162: 'vlink' => &designparm($function.'.vlink',$domain),
5163: 'link' => &designparm($function.'.link',$domain),);
1.438 albertel 5164: @design{keys(%$addentries)} = @$addentries{keys(%$addentries)};
1.339 albertel 5165:
1.63 www 5166: # role and realm
1.1075.2.68 raeburn 5167: my ($role,$realm) = split(m{\./},$env{'request.role'},2);
5168: if ($realm) {
5169: $realm = '/'.$realm;
5170: }
1.378 raeburn 5171: if ($role eq 'ca') {
1.479 albertel 5172: my ($rdom,$rname) = ($realm =~ m{^/($match_domain)/($match_username)$});
1.500 albertel 5173: $realm = &plainname($rname,$rdom);
1.378 raeburn 5174: }
1.55 www 5175: # realm
1.258 albertel 5176: if ($env{'request.course.id'}) {
1.378 raeburn 5177: if ($env{'request.role'} !~ /^cr/) {
5178: $role = &Apache::lonnet::plaintext($role,&course_type());
5179: }
1.898 raeburn 5180: if ($env{'request.course.sec'}) {
5181: $role .= (' 'x2).'- '.&mt('section:').' '.$env{'request.course.sec'};
5182: }
1.359 albertel 5183: $realm = $env{'course.'.$env{'request.course.id'}.'.description'};
1.378 raeburn 5184: } else {
5185: $role = &Apache::lonnet::plaintext($role);
1.54 www 5186: }
1.433 albertel 5187:
1.359 albertel 5188: if (!$realm) { $realm=' '; }
1.330 albertel 5189:
1.438 albertel 5190: my $extra_body_attr = &make_attr_string($forcereg,\%design);
1.329 albertel 5191:
1.101 www 5192: # construct main body tag
1.359 albertel 5193: my $bodytag = "<body $extra_body_attr>".
1.562 albertel 5194: &Apache::lontexconvert::init_math_support($args->{'inherit_jsmath'});
1.252 albertel 5195:
1.1075.2.38 raeburn 5196: &get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['inhibitmenu']);
5197:
5198: if (($bodyonly) || ($no_nav_bar) || ($env{'form.inhibitmenu'} eq 'yes')) {
1.60 matthew 5199: return $bodytag;
1.1075.2.38 raeburn 5200: }
1.359 albertel 5201:
1.954 raeburn 5202: if ($public) {
1.433 albertel 5203: undef($role);
5204: }
1.359 albertel 5205:
1.762 bisitz 5206: my $titleinfo = '<h1>'.$title.'</h1>';
1.359 albertel 5207: #
5208: # Extra info if you are the DC
5209: my $dc_info = '';
5210: if ($env{'user.adv'} && exists($env{'user.role.dc./'.
5211: $env{'course.'.$env{'request.course.id'}.
5212: '.domain'}.'/'})) {
5213: my $cid = $env{'request.course.id'};
1.917 raeburn 5214: $dc_info = $cid.' '.$env{'course.'.$cid.'.internal.coursecode'};
1.380 www 5215: $dc_info =~ s/\s+$//;
1.359 albertel 5216: }
5217:
1.898 raeburn 5218: $role = '<span class="LC_nobreak">('.$role.')</span>' if $role;
1.903 droeschl 5219:
1.1075.2.13 raeburn 5220: if ($env{'request.state'} eq 'construct') { $forcereg=1; }
5221:
1.1075.2.38 raeburn 5222:
5223:
1.1075.2.21 raeburn 5224: my $funclist;
5225: if (($env{'environment.remote'} eq 'on') && ($env{'request.state'} ne 'construct')) {
1.1075.2.52 raeburn 5226: $bodytag .= Apache::lonhtmlcommon::scripttag(Apache::lonmenu::utilityfunctions($httphost), 'start')."\n".
1.1075.2.21 raeburn 5227: Apache::lonmenu::serverform();
5228: my $forbodytag;
5229: &Apache::lonmenu::prepare_functions($env{'request.noversionuri'},
5230: $forcereg,$args->{'group'},
5231: $args->{'bread_crumbs'},
5232: $advtoolsref,'',\$forbodytag);
5233: unless (ref($args->{'bread_crumbs'}) eq 'ARRAY') {
5234: $funclist = $forbodytag;
5235: }
5236: } else {
1.903 droeschl 5237:
5238: # if ($env{'request.state'} eq 'construct') {
5239: # $titleinfo = &CSTR_pageheader(); #FIXME: Will be removed once all scripts have their own calls
5240: # }
5241:
1.1075.2.38 raeburn 5242: $bodytag .= Apache::lonhtmlcommon::scripttag(
1.1075.2.52 raeburn 5243: Apache::lonmenu::utilityfunctions($httphost), 'start');
1.359 albertel 5244:
1.1075.2.38 raeburn 5245: my ($left,$right) = Apache::lonmenu::primary_menu();
1.1075.2.2 raeburn 5246:
1.916 droeschl 5247: if ($env{'request.noversionuri'} =~ m{^/res/adm/pages/}) {
1.1075.2.22 raeburn 5248: if ($dc_info) {
5249: $dc_info = qq|<span class="LC_cusr_subheading">$dc_info</span>|;
1.1075.2.1 raeburn 5250: }
1.1075.2.38 raeburn 5251: $bodytag .= qq|<div id="LC_nav_bar">$left $role<br />
1.1075.2.22 raeburn 5252: <em>$realm</em> $dc_info</div>|;
1.903 droeschl 5253: return $bodytag;
5254: }
1.894 droeschl 5255:
1.927 raeburn 5256: unless ($env{'request.symb'} =~ m/\.page___\d+___/) {
1.1075.2.38 raeburn 5257: $bodytag .= qq|<div id="LC_nav_bar">$left $role</div>|;
1.927 raeburn 5258: }
1.916 droeschl 5259:
1.1075.2.38 raeburn 5260: $bodytag .= $right;
1.852 droeschl 5261:
1.917 raeburn 5262: if ($dc_info) {
5263: $dc_info = &dc_courseid_toggle($dc_info);
5264: }
5265: $bodytag .= qq|<div id="LC_realm">$realm $dc_info</div>|;
1.916 droeschl 5266:
1.1075.2.61 raeburn 5267: #if directed to not display the secondary menu, don't.
5268: if ($args->{'no_secondary_menu'}) {
5269: return $bodytag;
5270: }
1.903 droeschl 5271: #don't show menus for public users
1.954 raeburn 5272: if (!$public){
1.1075.2.52 raeburn 5273: $bodytag .= Apache::lonmenu::secondary_menu($httphost);
1.903 droeschl 5274: $bodytag .= Apache::lonmenu::serverform();
1.920 raeburn 5275: $bodytag .= Apache::lonhtmlcommon::scripttag('', 'end');
5276: if ($env{'request.state'} eq 'construct') {
1.962 droeschl 5277: $bodytag .= &Apache::lonmenu::innerregister($forcereg,
1.920 raeburn 5278: $args->{'bread_crumbs'});
5279: } elsif ($forcereg) {
1.1075.2.22 raeburn 5280: $bodytag .= &Apache::lonmenu::innerregister($forcereg,undef,
5281: $args->{'group'});
1.1075.2.15 raeburn 5282: } else {
1.1075.2.21 raeburn 5283: my $forbodytag;
5284: &Apache::lonmenu::prepare_functions($env{'request.noversionuri'},
5285: $forcereg,$args->{'group'},
5286: $args->{'bread_crumbs'},
5287: $advtoolsref,'',\$forbodytag);
5288: unless (ref($args->{'bread_crumbs'}) eq 'ARRAY') {
5289: $bodytag .= $forbodytag;
5290: }
1.920 raeburn 5291: }
1.903 droeschl 5292: }else{
5293: # this is to seperate menu from content when there's no secondary
5294: # menu. Especially needed for public accessible ressources.
5295: $bodytag .= '<hr style="clear:both" />';
5296: $bodytag .= Apache::lonhtmlcommon::scripttag('', 'end');
1.235 raeburn 5297: }
1.903 droeschl 5298:
1.235 raeburn 5299: return $bodytag;
1.1075.2.12 raeburn 5300: }
5301:
5302: #
5303: # Top frame rendering, Remote is up
5304: #
5305:
5306: my $imgsrc = $img;
5307: if ($img =~ /^\/adm/) {
5308: $imgsrc = &lonhttpdurl($img);
5309: }
5310: my $upperleft='<img src="'.$imgsrc.'" alt="'.$function.'" />';
5311:
1.1075.2.60 raeburn 5312: my $help=($no_inline_link?''
5313: :&Apache::loncommon::top_nav_help('Help'));
5314:
1.1075.2.12 raeburn 5315: # Explicit link to get inline menu
5316: my $menu= ($no_inline_link?''
5317: :'<a href="/adm/remote?action=collapse" target="_top">'.&mt('Switch to Inline Menu Mode').'</a>');
5318:
5319: if ($dc_info) {
5320: $dc_info = qq|<span class="LC_cusr_subheading">($dc_info)</span>|;
5321: }
5322:
1.1075.2.38 raeburn 5323: my $name = &plainname($env{'user.name'},$env{'user.domain'});
5324: unless ($public) {
5325: $name = &aboutmewrapper($name,$env{'user.name'},$env{'user.domain'},
5326: undef,'LC_menubuttons_link');
5327: }
5328:
1.1075.2.12 raeburn 5329: unless ($env{'form.inhibitmenu'}) {
5330: $bodytag .= qq|<div id="LC_nav_bar">$name $role</div>
1.1075.2.38 raeburn 5331: <ol class="LC_primary_menu LC_floatright LC_right">
1.1075.2.60 raeburn 5332: <li>$help</li>
1.1075.2.12 raeburn 5333: <li>$menu</li>
5334: </ol><div id="LC_realm"> $realm $dc_info</div>|;
5335: }
1.1075.2.13 raeburn 5336: if ($env{'request.state'} eq 'construct') {
5337: if (!$public){
5338: if ($env{'request.state'} eq 'construct') {
5339: $funclist = &Apache::lonhtmlcommon::scripttag(
1.1075.2.52 raeburn 5340: &Apache::lonmenu::utilityfunctions($httphost), 'start').
1.1075.2.13 raeburn 5341: &Apache::lonhtmlcommon::scripttag('','end').
5342: &Apache::lonmenu::innerregister($forcereg,
5343: $args->{'bread_crumbs'});
5344: }
5345: }
5346: }
1.1075.2.21 raeburn 5347: return $bodytag."\n".$funclist;
1.182 matthew 5348: }
5349:
1.917 raeburn 5350: sub dc_courseid_toggle {
5351: my ($dc_info) = @_;
1.980 raeburn 5352: return ' <span id="dccidtext" class="LC_cusr_subheading LC_nobreak">'.
1.1069 raeburn 5353: '<a href="javascript:showCourseID();" class="LC_menubuttons_link">'.
1.917 raeburn 5354: &mt('(More ...)').'</a></span>'.
5355: '<div id="dccid" class="LC_dccid">'.$dc_info.'</div>';
5356: }
5357:
1.330 albertel 5358: sub make_attr_string {
5359: my ($register,$attr_ref) = @_;
5360:
5361: if ($attr_ref && !ref($attr_ref)) {
5362: die("addentries Must be a hash ref ".
5363: join(':',caller(1))." ".
5364: join(':',caller(0))." ");
5365: }
5366:
5367: if ($register) {
1.339 albertel 5368: my ($on_load,$on_unload);
5369: foreach my $key (keys(%{$attr_ref})) {
5370: if (lc($key) eq 'onload') {
5371: $on_load.=$attr_ref->{$key}.';';
5372: delete($attr_ref->{$key});
5373:
5374: } elsif (lc($key) eq 'onunload') {
5375: $on_unload.=$attr_ref->{$key}.';';
5376: delete($attr_ref->{$key});
5377: }
5378: }
1.1075.2.12 raeburn 5379: if ($env{'environment.remote'} eq 'on') {
5380: $attr_ref->{'onload'} =
5381: &Apache::lonmenu::loadevents(). $on_load;
5382: $attr_ref->{'onunload'}=
5383: &Apache::lonmenu::unloadevents().$on_unload;
5384: } else {
5385: $attr_ref->{'onload'} = $on_load;
5386: $attr_ref->{'onunload'}= $on_unload;
5387: }
1.330 albertel 5388: }
1.339 albertel 5389:
1.330 albertel 5390: my $attr_string;
1.1075.2.56 raeburn 5391: foreach my $attr (sort(keys(%$attr_ref))) {
1.330 albertel 5392: $attr_string .= " $attr=\"".$attr_ref->{$attr}.'" ';
5393: }
5394: return $attr_string;
5395: }
5396:
5397:
1.182 matthew 5398: ###############################################
1.251 albertel 5399: ###############################################
5400:
5401: =pod
5402:
5403: =item * &endbodytag()
5404:
5405: Returns a uniform footer for LON-CAPA web pages.
5406:
1.635 raeburn 5407: Inputs: 1 - optional reference to an args hash
5408: If in the hash, key for noredirectlink has a value which evaluates to true,
5409: a 'Continue' link is not displayed if the page contains an
5410: internal redirect in the <head></head> section,
5411: i.e., $env{'internal.head.redirect'} exists
1.251 albertel 5412:
5413: =cut
5414:
5415: sub endbodytag {
1.635 raeburn 5416: my ($args) = @_;
1.1075.2.6 raeburn 5417: my $endbodytag;
5418: unless ((ref($args) eq 'HASH') && ($args->{'notbody'})) {
5419: $endbodytag='</body>';
5420: }
1.269 albertel 5421: $endbodytag=&Apache::lontexconvert::jsMath_process()."\n".$endbodytag;
1.315 albertel 5422: if ( exists( $env{'internal.head.redirect'} ) ) {
1.635 raeburn 5423: if (!(ref($args) eq 'HASH' && $args->{'noredirectlink'})) {
5424: $endbodytag=
5425: "<br /><a href=\"$env{'internal.head.redirect'}\">".
5426: &mt('Continue').'</a>'.
5427: $endbodytag;
5428: }
1.315 albertel 5429: }
1.251 albertel 5430: return $endbodytag;
5431: }
5432:
1.352 albertel 5433: =pod
5434:
5435: =item * &standard_css()
5436:
5437: Returns a style sheet
5438:
5439: Inputs: (all optional)
5440: domain -> force to color decorate a page for a specific
5441: domain
5442: function -> force usage of a specific rolish color scheme
5443: bgcolor -> override the default page bgcolor
5444:
5445: =cut
5446:
1.343 albertel 5447: sub standard_css {
1.345 albertel 5448: my ($function,$domain,$bgcolor) = @_;
1.352 albertel 5449: $function = &get_users_function() if (!$function);
5450: my $img = &designparm($function.'.img', $domain);
5451: my $tabbg = &designparm($function.'.tabbg', $domain);
5452: my $font = &designparm($function.'.font', $domain);
1.801 tempelho 5453: my $fontmenu = &designparm($function.'.fontmenu', $domain);
1.791 tempelho 5454: #second colour for later usage
1.345 albertel 5455: my $sidebg = &designparm($function.'.sidebg',$domain);
1.382 albertel 5456: my $pgbg_or_bgcolor =
5457: $bgcolor ||
1.352 albertel 5458: &designparm($function.'.pgbg', $domain);
1.382 albertel 5459: my $pgbg = &designparm($function.'.pgbg', $domain);
1.352 albertel 5460: my $alink = &designparm($function.'.alink', $domain);
5461: my $vlink = &designparm($function.'.vlink', $domain);
5462: my $link = &designparm($function.'.link', $domain);
5463:
1.602 albertel 5464: my $sans = 'Verdana,Arial,Helvetica,sans-serif';
1.395 albertel 5465: my $mono = 'monospace';
1.850 bisitz 5466: my $data_table_head = $sidebg;
5467: my $data_table_light = '#FAFAFA';
1.1060 bisitz 5468: my $data_table_dark = '#E0E0E0';
1.470 banghart 5469: my $data_table_darker = '#CCCCCC';
1.349 albertel 5470: my $data_table_highlight = '#FFFF00';
1.352 albertel 5471: my $mail_new = '#FFBB77';
5472: my $mail_new_hover = '#DD9955';
5473: my $mail_read = '#BBBB77';
5474: my $mail_read_hover = '#999944';
5475: my $mail_replied = '#AAAA88';
5476: my $mail_replied_hover = '#888855';
5477: my $mail_other = '#99BBBB';
5478: my $mail_other_hover = '#669999';
1.391 albertel 5479: my $table_header = '#DDDDDD';
1.489 raeburn 5480: my $feedback_link_bg = '#BBBBBB';
1.911 bisitz 5481: my $lg_border_color = '#C8C8C8';
1.952 onken 5482: my $button_hover = '#BF2317';
1.392 albertel 5483:
1.608 albertel 5484: my $border = ($env{'browser.type'} eq 'explorer' ||
1.911 bisitz 5485: $env{'browser.type'} eq 'safari' ) ? '0 2px 0 2px'
5486: : '0 3px 0 4px';
1.448 albertel 5487:
1.523 albertel 5488:
1.343 albertel 5489: return <<END;
1.947 droeschl 5490:
5491: /* needed for iframe to allow 100% height in FF */
5492: body, html {
5493: margin: 0;
5494: padding: 0 0.5%;
5495: height: 99%; /* to avoid scrollbars */
5496: }
5497:
1.795 www 5498: body {
1.911 bisitz 5499: font-family: $sans;
5500: line-height:130%;
5501: font-size:0.83em;
5502: color:$font;
1.795 www 5503: }
5504:
1.959 onken 5505: a:focus,
5506: a:focus img {
1.795 www 5507: color: red;
5508: }
1.698 harmsja 5509:
1.911 bisitz 5510: form, .inline {
5511: display: inline;
1.795 www 5512: }
1.721 harmsja 5513:
1.795 www 5514: .LC_right {
1.911 bisitz 5515: text-align:right;
1.795 www 5516: }
5517:
5518: .LC_middle {
1.911 bisitz 5519: vertical-align:middle;
1.795 www 5520: }
1.721 harmsja 5521:
1.1075.2.38 raeburn 5522: .LC_floatleft {
5523: float: left;
5524: }
5525:
5526: .LC_floatright {
5527: float: right;
5528: }
5529:
1.911 bisitz 5530: .LC_400Box {
5531: width:400px;
5532: }
1.721 harmsja 5533:
1.947 droeschl 5534: .LC_iframecontainer {
5535: width: 98%;
5536: margin: 0;
5537: position: fixed;
5538: top: 8.5em;
5539: bottom: 0;
5540: }
5541:
5542: .LC_iframecontainer iframe{
5543: border: none;
5544: width: 100%;
5545: height: 100%;
5546: }
5547:
1.778 bisitz 5548: .LC_filename {
5549: font-family: $mono;
5550: white-space:pre;
1.921 bisitz 5551: font-size: 120%;
1.778 bisitz 5552: }
5553:
5554: .LC_fileicon {
5555: border: none;
5556: height: 1.3em;
5557: vertical-align: text-bottom;
5558: margin-right: 0.3em;
5559: text-decoration:none;
5560: }
5561:
1.1008 www 5562: .LC_setting {
5563: text-decoration:underline;
5564: }
5565:
1.350 albertel 5566: .LC_error {
5567: color: red;
5568: }
1.795 www 5569:
1.1075.2.15 raeburn 5570: .LC_warning {
5571: color: darkorange;
5572: }
5573:
1.457 albertel 5574: .LC_diff_removed {
1.733 bisitz 5575: color: red;
1.394 albertel 5576: }
1.532 albertel 5577:
5578: .LC_info,
1.457 albertel 5579: .LC_success,
5580: .LC_diff_added {
1.350 albertel 5581: color: green;
5582: }
1.795 www 5583:
1.802 bisitz 5584: div.LC_confirm_box {
5585: background-color: #FAFAFA;
5586: border: 1px solid $lg_border_color;
5587: margin-right: 0;
5588: padding: 5px;
5589: }
5590:
5591: div.LC_confirm_box .LC_error img,
5592: div.LC_confirm_box .LC_success img {
5593: vertical-align: middle;
5594: }
5595:
1.440 albertel 5596: .LC_icon {
1.771 droeschl 5597: border: none;
1.790 droeschl 5598: vertical-align: middle;
1.771 droeschl 5599: }
5600:
1.543 albertel 5601: .LC_docs_spacer {
5602: width: 25px;
5603: height: 1px;
1.771 droeschl 5604: border: none;
1.543 albertel 5605: }
1.346 albertel 5606:
1.532 albertel 5607: .LC_internal_info {
1.735 bisitz 5608: color: #999999;
1.532 albertel 5609: }
5610:
1.794 www 5611: .LC_discussion {
1.1050 www 5612: background: $data_table_dark;
1.911 bisitz 5613: border: 1px solid black;
5614: margin: 2px;
1.794 www 5615: }
5616:
5617: .LC_disc_action_left {
1.1050 www 5618: background: $sidebg;
1.911 bisitz 5619: text-align: left;
1.1050 www 5620: padding: 4px;
5621: margin: 2px;
1.794 www 5622: }
5623:
5624: .LC_disc_action_right {
1.1050 www 5625: background: $sidebg;
1.911 bisitz 5626: text-align: right;
1.1050 www 5627: padding: 4px;
5628: margin: 2px;
1.794 www 5629: }
5630:
5631: .LC_disc_new_item {
1.911 bisitz 5632: background: white;
5633: border: 2px solid red;
1.1050 www 5634: margin: 4px;
5635: padding: 4px;
1.794 www 5636: }
5637:
5638: .LC_disc_old_item {
1.911 bisitz 5639: background: white;
1.1050 www 5640: margin: 4px;
5641: padding: 4px;
1.794 www 5642: }
5643:
1.458 albertel 5644: table.LC_pastsubmission {
5645: border: 1px solid black;
5646: margin: 2px;
5647: }
5648:
1.924 bisitz 5649: table#LC_menubuttons {
1.345 albertel 5650: width: 100%;
5651: background: $pgbg;
1.392 albertel 5652: border: 2px;
1.402 albertel 5653: border-collapse: separate;
1.803 bisitz 5654: padding: 0;
1.345 albertel 5655: }
1.392 albertel 5656:
1.801 tempelho 5657: table#LC_title_bar a {
5658: color: $fontmenu;
5659: }
1.836 bisitz 5660:
1.807 droeschl 5661: table#LC_title_bar {
1.819 tempelho 5662: clear: both;
1.836 bisitz 5663: display: none;
1.807 droeschl 5664: }
5665:
1.795 www 5666: table#LC_title_bar,
1.933 droeschl 5667: table.LC_breadcrumbs, /* obsolete? */
1.393 albertel 5668: table#LC_title_bar.LC_with_remote {
1.359 albertel 5669: width: 100%;
1.392 albertel 5670: border-color: $pgbg;
5671: border-style: solid;
5672: border-width: $border;
1.379 albertel 5673: background: $pgbg;
1.801 tempelho 5674: color: $fontmenu;
1.392 albertel 5675: border-collapse: collapse;
1.803 bisitz 5676: padding: 0;
1.819 tempelho 5677: margin: 0;
1.359 albertel 5678: }
1.795 www 5679:
1.933 droeschl 5680: ul.LC_breadcrumb_tools_outerlist {
1.913 droeschl 5681: margin: 0;
5682: padding: 0;
1.933 droeschl 5683: position: relative;
5684: list-style: none;
1.913 droeschl 5685: }
1.933 droeschl 5686: ul.LC_breadcrumb_tools_outerlist li {
1.913 droeschl 5687: display: inline;
5688: }
1.933 droeschl 5689:
5690: .LC_breadcrumb_tools_navigation {
1.913 droeschl 5691: padding: 0;
1.933 droeschl 5692: margin: 0;
5693: float: left;
1.913 droeschl 5694: }
1.933 droeschl 5695: .LC_breadcrumb_tools_tools {
5696: padding: 0;
5697: margin: 0;
1.913 droeschl 5698: float: right;
5699: }
5700:
1.359 albertel 5701: table#LC_title_bar td {
5702: background: $tabbg;
5703: }
1.795 www 5704:
1.911 bisitz 5705: table#LC_menubuttons img {
1.803 bisitz 5706: border: none;
1.346 albertel 5707: }
1.795 www 5708:
1.842 droeschl 5709: .LC_breadcrumbs_component {
1.911 bisitz 5710: float: right;
5711: margin: 0 1em;
1.357 albertel 5712: }
1.842 droeschl 5713: .LC_breadcrumbs_component img {
1.911 bisitz 5714: vertical-align: middle;
1.777 tempelho 5715: }
1.795 www 5716:
1.383 albertel 5717: td.LC_table_cell_checkbox {
5718: text-align: center;
5719: }
1.795 www 5720:
5721: .LC_fontsize_small {
1.911 bisitz 5722: font-size: 70%;
1.705 tempelho 5723: }
5724:
1.844 bisitz 5725: #LC_breadcrumbs {
1.911 bisitz 5726: clear:both;
5727: background: $sidebg;
5728: border-bottom: 1px solid $lg_border_color;
5729: line-height: 2.5em;
1.933 droeschl 5730: overflow: hidden;
1.911 bisitz 5731: margin: 0;
5732: padding: 0;
1.995 raeburn 5733: text-align: left;
1.819 tempelho 5734: }
1.862 bisitz 5735:
1.1075.2.16 raeburn 5736: .LC_head_subbox, .LC_actionbox {
1.911 bisitz 5737: clear:both;
5738: background: #F8F8F8; /* $sidebg; */
1.915 droeschl 5739: border: 1px solid $sidebg;
1.1075.2.16 raeburn 5740: margin: 0 0 10px 0;
1.966 bisitz 5741: padding: 3px;
1.995 raeburn 5742: text-align: left;
1.822 bisitz 5743: }
5744:
1.795 www 5745: .LC_fontsize_medium {
1.911 bisitz 5746: font-size: 85%;
1.705 tempelho 5747: }
5748:
1.795 www 5749: .LC_fontsize_large {
1.911 bisitz 5750: font-size: 120%;
1.705 tempelho 5751: }
5752:
1.346 albertel 5753: .LC_menubuttons_inline_text {
5754: color: $font;
1.698 harmsja 5755: font-size: 90%;
1.701 harmsja 5756: padding-left:3px;
1.346 albertel 5757: }
5758:
1.934 droeschl 5759: .LC_menubuttons_inline_text img{
5760: vertical-align: middle;
5761: }
5762:
1.1051 www 5763: li.LC_menubuttons_inline_text img {
1.951 onken 5764: cursor:pointer;
1.1002 droeschl 5765: text-decoration: none;
1.951 onken 5766: }
5767:
1.526 www 5768: .LC_menubuttons_link {
5769: text-decoration: none;
5770: }
1.795 www 5771:
1.522 albertel 5772: .LC_menubuttons_category {
1.521 www 5773: color: $font;
1.526 www 5774: background: $pgbg;
1.521 www 5775: font-size: larger;
5776: font-weight: bold;
5777: }
5778:
1.346 albertel 5779: td.LC_menubuttons_text {
1.911 bisitz 5780: color: $font;
1.346 albertel 5781: }
1.706 harmsja 5782:
1.346 albertel 5783: .LC_current_location {
5784: background: $tabbg;
5785: }
1.795 www 5786:
1.938 bisitz 5787: table.LC_data_table {
1.347 albertel 5788: border: 1px solid #000000;
1.402 albertel 5789: border-collapse: separate;
1.426 albertel 5790: border-spacing: 1px;
1.610 albertel 5791: background: $pgbg;
1.347 albertel 5792: }
1.795 www 5793:
1.422 albertel 5794: .LC_data_table_dense {
5795: font-size: small;
5796: }
1.795 www 5797:
1.507 raeburn 5798: table.LC_nested_outer {
5799: border: 1px solid #000000;
1.589 raeburn 5800: border-collapse: collapse;
1.803 bisitz 5801: border-spacing: 0;
1.507 raeburn 5802: width: 100%;
5803: }
1.795 www 5804:
1.879 raeburn 5805: table.LC_innerpickbox,
1.507 raeburn 5806: table.LC_nested {
1.803 bisitz 5807: border: none;
1.589 raeburn 5808: border-collapse: collapse;
1.803 bisitz 5809: border-spacing: 0;
1.507 raeburn 5810: width: 100%;
5811: }
1.795 www 5812:
1.911 bisitz 5813: table.LC_data_table tr th,
5814: table.LC_calendar tr th,
1.879 raeburn 5815: table.LC_prior_tries tr th,
5816: table.LC_innerpickbox tr th {
1.349 albertel 5817: font-weight: bold;
5818: background-color: $data_table_head;
1.801 tempelho 5819: color:$fontmenu;
1.701 harmsja 5820: font-size:90%;
1.347 albertel 5821: }
1.795 www 5822:
1.879 raeburn 5823: table.LC_innerpickbox tr th,
5824: table.LC_innerpickbox tr td {
5825: vertical-align: top;
5826: }
5827:
1.711 raeburn 5828: table.LC_data_table tr.LC_info_row > td {
1.735 bisitz 5829: background-color: #CCCCCC;
1.711 raeburn 5830: font-weight: bold;
5831: text-align: left;
5832: }
1.795 www 5833:
1.912 bisitz 5834: table.LC_data_table tr.LC_odd_row > td {
5835: background-color: $data_table_light;
5836: padding: 2px;
5837: vertical-align: top;
5838: }
5839:
1.809 bisitz 5840: table.LC_pick_box tr > td.LC_odd_row {
1.349 albertel 5841: background-color: $data_table_light;
1.912 bisitz 5842: vertical-align: top;
5843: }
5844:
5845: table.LC_data_table tr.LC_even_row > td {
5846: background-color: $data_table_dark;
1.425 albertel 5847: padding: 2px;
1.900 bisitz 5848: vertical-align: top;
1.347 albertel 5849: }
1.795 www 5850:
1.809 bisitz 5851: table.LC_pick_box tr > td.LC_even_row {
1.349 albertel 5852: background-color: $data_table_dark;
1.900 bisitz 5853: vertical-align: top;
1.347 albertel 5854: }
1.795 www 5855:
1.425 albertel 5856: table.LC_data_table tr.LC_data_table_highlight td {
5857: background-color: $data_table_darker;
5858: }
1.795 www 5859:
1.639 raeburn 5860: table.LC_data_table tr td.LC_leftcol_header {
5861: background-color: $data_table_head;
5862: font-weight: bold;
5863: }
1.795 www 5864:
1.451 albertel 5865: table.LC_data_table tr.LC_empty_row td,
1.507 raeburn 5866: table.LC_nested tr.LC_empty_row td {
1.421 albertel 5867: font-weight: bold;
5868: font-style: italic;
5869: text-align: center;
5870: padding: 8px;
1.347 albertel 5871: }
1.795 www 5872:
1.1075.2.30 raeburn 5873: table.LC_data_table tr.LC_empty_row td,
5874: table.LC_data_table tr.LC_footer_row td {
1.940 bisitz 5875: background-color: $sidebg;
5876: }
5877:
5878: table.LC_nested tr.LC_empty_row td {
5879: background-color: #FFFFFF;
5880: }
5881:
1.890 droeschl 5882: table.LC_caption {
5883: }
5884:
1.507 raeburn 5885: table.LC_nested tr.LC_empty_row td {
1.465 albertel 5886: padding: 4ex
5887: }
1.795 www 5888:
1.507 raeburn 5889: table.LC_nested_outer tr th {
5890: font-weight: bold;
1.801 tempelho 5891: color:$fontmenu;
1.507 raeburn 5892: background-color: $data_table_head;
1.701 harmsja 5893: font-size: small;
1.507 raeburn 5894: border-bottom: 1px solid #000000;
5895: }
1.795 www 5896:
1.507 raeburn 5897: table.LC_nested_outer tr td.LC_subheader {
5898: background-color: $data_table_head;
5899: font-weight: bold;
5900: font-size: small;
5901: border-bottom: 1px solid #000000;
5902: text-align: right;
1.451 albertel 5903: }
1.795 www 5904:
1.507 raeburn 5905: table.LC_nested tr.LC_info_row td {
1.735 bisitz 5906: background-color: #CCCCCC;
1.451 albertel 5907: font-weight: bold;
5908: font-size: small;
1.507 raeburn 5909: text-align: center;
5910: }
1.795 www 5911:
1.589 raeburn 5912: table.LC_nested tr.LC_info_row td.LC_left_item,
5913: table.LC_nested_outer tr th.LC_left_item {
1.507 raeburn 5914: text-align: left;
1.451 albertel 5915: }
1.795 www 5916:
1.507 raeburn 5917: table.LC_nested td {
1.735 bisitz 5918: background-color: #FFFFFF;
1.451 albertel 5919: font-size: small;
1.507 raeburn 5920: }
1.795 www 5921:
1.507 raeburn 5922: table.LC_nested_outer tr th.LC_right_item,
5923: table.LC_nested tr.LC_info_row td.LC_right_item,
5924: table.LC_nested tr.LC_odd_row td.LC_right_item,
5925: table.LC_nested tr td.LC_right_item {
1.451 albertel 5926: text-align: right;
5927: }
5928:
1.507 raeburn 5929: table.LC_nested tr.LC_odd_row td {
1.735 bisitz 5930: background-color: #EEEEEE;
1.451 albertel 5931: }
5932:
1.473 raeburn 5933: table.LC_createuser {
5934: }
5935:
5936: table.LC_createuser tr.LC_section_row td {
1.701 harmsja 5937: font-size: small;
1.473 raeburn 5938: }
5939:
5940: table.LC_createuser tr.LC_info_row td {
1.735 bisitz 5941: background-color: #CCCCCC;
1.473 raeburn 5942: font-weight: bold;
5943: text-align: center;
5944: }
5945:
1.349 albertel 5946: table.LC_calendar {
5947: border: 1px solid #000000;
5948: border-collapse: collapse;
1.917 raeburn 5949: width: 98%;
1.349 albertel 5950: }
1.795 www 5951:
1.349 albertel 5952: table.LC_calendar_pickdate {
5953: font-size: xx-small;
5954: }
1.795 www 5955:
1.349 albertel 5956: table.LC_calendar tr td {
5957: border: 1px solid #000000;
5958: vertical-align: top;
1.917 raeburn 5959: width: 14%;
1.349 albertel 5960: }
1.795 www 5961:
1.349 albertel 5962: table.LC_calendar tr td.LC_calendar_day_empty {
5963: background-color: $data_table_dark;
5964: }
1.795 www 5965:
1.779 bisitz 5966: table.LC_calendar tr td.LC_calendar_day_current {
5967: background-color: $data_table_highlight;
1.777 tempelho 5968: }
1.795 www 5969:
1.938 bisitz 5970: table.LC_data_table tr td.LC_mail_new {
1.349 albertel 5971: background-color: $mail_new;
5972: }
1.795 www 5973:
1.938 bisitz 5974: table.LC_data_table tr.LC_mail_new:hover {
1.349 albertel 5975: background-color: $mail_new_hover;
5976: }
1.795 www 5977:
1.938 bisitz 5978: table.LC_data_table tr td.LC_mail_read {
1.349 albertel 5979: background-color: $mail_read;
5980: }
1.795 www 5981:
1.938 bisitz 5982: /*
5983: table.LC_data_table tr.LC_mail_read:hover {
1.349 albertel 5984: background-color: $mail_read_hover;
5985: }
1.938 bisitz 5986: */
1.795 www 5987:
1.938 bisitz 5988: table.LC_data_table tr td.LC_mail_replied {
1.349 albertel 5989: background-color: $mail_replied;
5990: }
1.795 www 5991:
1.938 bisitz 5992: /*
5993: table.LC_data_table tr.LC_mail_replied:hover {
1.349 albertel 5994: background-color: $mail_replied_hover;
5995: }
1.938 bisitz 5996: */
1.795 www 5997:
1.938 bisitz 5998: table.LC_data_table tr td.LC_mail_other {
1.349 albertel 5999: background-color: $mail_other;
6000: }
1.795 www 6001:
1.938 bisitz 6002: /*
6003: table.LC_data_table tr.LC_mail_other:hover {
1.349 albertel 6004: background-color: $mail_other_hover;
6005: }
1.938 bisitz 6006: */
1.494 raeburn 6007:
1.777 tempelho 6008: table.LC_data_table tr > td.LC_browser_file,
6009: table.LC_data_table tr > td.LC_browser_file_published {
1.899 bisitz 6010: background: #AAEE77;
1.389 albertel 6011: }
1.795 www 6012:
1.777 tempelho 6013: table.LC_data_table tr > td.LC_browser_file_locked,
6014: table.LC_data_table tr > td.LC_browser_file_unpublished {
1.389 albertel 6015: background: #FFAA99;
1.387 albertel 6016: }
1.795 www 6017:
1.777 tempelho 6018: table.LC_data_table tr > td.LC_browser_file_obsolete {
1.899 bisitz 6019: background: #888888;
1.779 bisitz 6020: }
1.795 www 6021:
1.777 tempelho 6022: table.LC_data_table tr > td.LC_browser_file_modified,
1.779 bisitz 6023: table.LC_data_table tr > td.LC_browser_file_metamodified {
1.899 bisitz 6024: background: #F8F866;
1.777 tempelho 6025: }
1.795 www 6026:
1.696 bisitz 6027: table.LC_data_table tr.LC_browser_folder > td {
1.899 bisitz 6028: background: #E0E8FF;
1.387 albertel 6029: }
1.696 bisitz 6030:
1.707 bisitz 6031: table.LC_data_table tr > td.LC_roles_is {
1.911 bisitz 6032: /* background: #77FF77; */
1.707 bisitz 6033: }
1.795 www 6034:
1.707 bisitz 6035: table.LC_data_table tr > td.LC_roles_future {
1.939 bisitz 6036: border-right: 8px solid #FFFF77;
1.707 bisitz 6037: }
1.795 www 6038:
1.707 bisitz 6039: table.LC_data_table tr > td.LC_roles_will {
1.939 bisitz 6040: border-right: 8px solid #FFAA77;
1.707 bisitz 6041: }
1.795 www 6042:
1.707 bisitz 6043: table.LC_data_table tr > td.LC_roles_expired {
1.939 bisitz 6044: border-right: 8px solid #FF7777;
1.707 bisitz 6045: }
1.795 www 6046:
1.707 bisitz 6047: table.LC_data_table tr > td.LC_roles_will_not {
1.939 bisitz 6048: border-right: 8px solid #AAFF77;
1.707 bisitz 6049: }
1.795 www 6050:
1.707 bisitz 6051: table.LC_data_table tr > td.LC_roles_selected {
1.939 bisitz 6052: border-right: 8px solid #11CC55;
1.707 bisitz 6053: }
6054:
1.388 albertel 6055: span.LC_current_location {
1.701 harmsja 6056: font-size:larger;
1.388 albertel 6057: background: $pgbg;
6058: }
1.387 albertel 6059:
1.1029 www 6060: span.LC_current_nav_location {
6061: font-weight:bold;
6062: background: $sidebg;
6063: }
6064:
1.395 albertel 6065: span.LC_parm_menu_item {
6066: font-size: larger;
6067: }
1.795 www 6068:
1.395 albertel 6069: span.LC_parm_scope_all {
6070: color: red;
6071: }
1.795 www 6072:
1.395 albertel 6073: span.LC_parm_scope_folder {
6074: color: green;
6075: }
1.795 www 6076:
1.395 albertel 6077: span.LC_parm_scope_resource {
6078: color: orange;
6079: }
1.795 www 6080:
1.395 albertel 6081: span.LC_parm_part {
6082: color: blue;
6083: }
1.795 www 6084:
1.911 bisitz 6085: span.LC_parm_folder,
6086: span.LC_parm_symb {
1.395 albertel 6087: font-size: x-small;
6088: font-family: $mono;
6089: color: #AAAAAA;
6090: }
6091:
1.977 bisitz 6092: ul.LC_parm_parmlist li {
6093: display: inline-block;
6094: padding: 0.3em 0.8em;
6095: vertical-align: top;
6096: width: 150px;
6097: border-top:1px solid $lg_border_color;
6098: }
6099:
1.795 www 6100: td.LC_parm_overview_level_menu,
6101: td.LC_parm_overview_map_menu,
6102: td.LC_parm_overview_parm_selectors,
6103: td.LC_parm_overview_restrictions {
1.396 albertel 6104: border: 1px solid black;
6105: border-collapse: collapse;
6106: }
1.795 www 6107:
1.396 albertel 6108: table.LC_parm_overview_restrictions td {
6109: border-width: 1px 4px 1px 4px;
6110: border-style: solid;
6111: border-color: $pgbg;
6112: text-align: center;
6113: }
1.795 www 6114:
1.396 albertel 6115: table.LC_parm_overview_restrictions th {
6116: background: $tabbg;
6117: border-width: 1px 4px 1px 4px;
6118: border-style: solid;
6119: border-color: $pgbg;
6120: }
1.795 www 6121:
1.398 albertel 6122: table#LC_helpmenu {
1.803 bisitz 6123: border: none;
1.398 albertel 6124: height: 55px;
1.803 bisitz 6125: border-spacing: 0;
1.398 albertel 6126: }
6127:
6128: table#LC_helpmenu fieldset legend {
6129: font-size: larger;
6130: }
1.795 www 6131:
1.397 albertel 6132: table#LC_helpmenu_links {
6133: width: 100%;
6134: border: 1px solid black;
6135: background: $pgbg;
1.803 bisitz 6136: padding: 0;
1.397 albertel 6137: border-spacing: 1px;
6138: }
1.795 www 6139:
1.397 albertel 6140: table#LC_helpmenu_links tr td {
6141: padding: 1px;
6142: background: $tabbg;
1.399 albertel 6143: text-align: center;
6144: font-weight: bold;
1.397 albertel 6145: }
1.396 albertel 6146:
1.795 www 6147: table#LC_helpmenu_links a:link,
6148: table#LC_helpmenu_links a:visited,
1.397 albertel 6149: table#LC_helpmenu_links a:active {
6150: text-decoration: none;
6151: color: $font;
6152: }
1.795 www 6153:
1.397 albertel 6154: table#LC_helpmenu_links a:hover {
6155: text-decoration: underline;
6156: color: $vlink;
6157: }
1.396 albertel 6158:
1.417 albertel 6159: .LC_chrt_popup_exists {
6160: border: 1px solid #339933;
6161: margin: -1px;
6162: }
1.795 www 6163:
1.417 albertel 6164: .LC_chrt_popup_up {
6165: border: 1px solid yellow;
6166: margin: -1px;
6167: }
1.795 www 6168:
1.417 albertel 6169: .LC_chrt_popup {
6170: border: 1px solid #8888FF;
6171: background: #CCCCFF;
6172: }
1.795 www 6173:
1.421 albertel 6174: table.LC_pick_box {
6175: border-collapse: separate;
6176: background: white;
6177: border: 1px solid black;
6178: border-spacing: 1px;
6179: }
1.795 www 6180:
1.421 albertel 6181: table.LC_pick_box td.LC_pick_box_title {
1.850 bisitz 6182: background: $sidebg;
1.421 albertel 6183: font-weight: bold;
1.900 bisitz 6184: text-align: left;
1.740 bisitz 6185: vertical-align: top;
1.421 albertel 6186: width: 184px;
6187: padding: 8px;
6188: }
1.795 www 6189:
1.579 raeburn 6190: table.LC_pick_box td.LC_pick_box_value {
6191: text-align: left;
6192: padding: 8px;
6193: }
1.795 www 6194:
1.579 raeburn 6195: table.LC_pick_box td.LC_pick_box_select {
6196: text-align: left;
6197: padding: 8px;
6198: }
1.795 www 6199:
1.424 albertel 6200: table.LC_pick_box td.LC_pick_box_separator {
1.803 bisitz 6201: padding: 0;
1.421 albertel 6202: height: 1px;
6203: background: black;
6204: }
1.795 www 6205:
1.421 albertel 6206: table.LC_pick_box td.LC_pick_box_submit {
6207: text-align: right;
6208: }
1.795 www 6209:
1.579 raeburn 6210: table.LC_pick_box td.LC_evenrow_value {
6211: text-align: left;
6212: padding: 8px;
6213: background-color: $data_table_light;
6214: }
1.795 www 6215:
1.579 raeburn 6216: table.LC_pick_box td.LC_oddrow_value {
6217: text-align: left;
6218: padding: 8px;
6219: background-color: $data_table_light;
6220: }
1.795 www 6221:
1.579 raeburn 6222: span.LC_helpform_receipt_cat {
6223: font-weight: bold;
6224: }
1.795 www 6225:
1.424 albertel 6226: table.LC_group_priv_box {
6227: background: white;
6228: border: 1px solid black;
6229: border-spacing: 1px;
6230: }
1.795 www 6231:
1.424 albertel 6232: table.LC_group_priv_box td.LC_pick_box_title {
6233: background: $tabbg;
6234: font-weight: bold;
6235: text-align: right;
6236: width: 184px;
6237: }
1.795 www 6238:
1.424 albertel 6239: table.LC_group_priv_box td.LC_groups_fixed {
6240: background: $data_table_light;
6241: text-align: center;
6242: }
1.795 www 6243:
1.424 albertel 6244: table.LC_group_priv_box td.LC_groups_optional {
6245: background: $data_table_dark;
6246: text-align: center;
6247: }
1.795 www 6248:
1.424 albertel 6249: table.LC_group_priv_box td.LC_groups_functionality {
6250: background: $data_table_darker;
6251: text-align: center;
6252: font-weight: bold;
6253: }
1.795 www 6254:
1.424 albertel 6255: table.LC_group_priv td {
6256: text-align: left;
1.803 bisitz 6257: padding: 0;
1.424 albertel 6258: }
6259:
6260: .LC_navbuttons {
6261: margin: 2ex 0ex 2ex 0ex;
6262: }
1.795 www 6263:
1.423 albertel 6264: .LC_topic_bar {
6265: font-weight: bold;
6266: background: $tabbg;
1.918 wenzelju 6267: margin: 1em 0em 1em 2em;
1.805 bisitz 6268: padding: 3px;
1.918 wenzelju 6269: font-size: 1.2em;
1.423 albertel 6270: }
1.795 www 6271:
1.423 albertel 6272: .LC_topic_bar span {
1.918 wenzelju 6273: left: 0.5em;
6274: position: absolute;
1.423 albertel 6275: vertical-align: middle;
1.918 wenzelju 6276: font-size: 1.2em;
1.423 albertel 6277: }
1.795 www 6278:
1.423 albertel 6279: table.LC_course_group_status {
6280: margin: 20px;
6281: }
1.795 www 6282:
1.423 albertel 6283: table.LC_status_selector td {
6284: vertical-align: top;
6285: text-align: center;
1.424 albertel 6286: padding: 4px;
6287: }
1.795 www 6288:
1.599 albertel 6289: div.LC_feedback_link {
1.616 albertel 6290: clear: both;
1.829 kalberla 6291: background: $sidebg;
1.779 bisitz 6292: width: 100%;
1.829 kalberla 6293: padding-bottom: 10px;
6294: border: 1px $tabbg solid;
1.833 kalberla 6295: height: 22px;
6296: line-height: 22px;
6297: padding-top: 5px;
6298: }
6299:
6300: div.LC_feedback_link img {
6301: height: 22px;
1.867 kalberla 6302: vertical-align:middle;
1.829 kalberla 6303: }
6304:
1.911 bisitz 6305: div.LC_feedback_link a {
1.829 kalberla 6306: text-decoration: none;
1.489 raeburn 6307: }
1.795 www 6308:
1.867 kalberla 6309: div.LC_comblock {
1.911 bisitz 6310: display:inline;
1.867 kalberla 6311: color:$font;
6312: font-size:90%;
6313: }
6314:
6315: div.LC_feedback_link div.LC_comblock {
6316: padding-left:5px;
6317: }
6318:
6319: div.LC_feedback_link div.LC_comblock a {
6320: color:$font;
6321: }
6322:
1.489 raeburn 6323: span.LC_feedback_link {
1.858 bisitz 6324: /* background: $feedback_link_bg; */
1.599 albertel 6325: font-size: larger;
6326: }
1.795 www 6327:
1.599 albertel 6328: span.LC_message_link {
1.858 bisitz 6329: /* background: $feedback_link_bg; */
1.599 albertel 6330: font-size: larger;
6331: position: absolute;
6332: right: 1em;
1.489 raeburn 6333: }
1.421 albertel 6334:
1.515 albertel 6335: table.LC_prior_tries {
1.524 albertel 6336: border: 1px solid #000000;
6337: border-collapse: separate;
6338: border-spacing: 1px;
1.515 albertel 6339: }
1.523 albertel 6340:
1.515 albertel 6341: table.LC_prior_tries td {
1.524 albertel 6342: padding: 2px;
1.515 albertel 6343: }
1.523 albertel 6344:
6345: .LC_answer_correct {
1.795 www 6346: background: lightgreen;
6347: color: darkgreen;
6348: padding: 6px;
1.523 albertel 6349: }
1.795 www 6350:
1.523 albertel 6351: .LC_answer_charged_try {
1.797 www 6352: background: #FFAAAA;
1.795 www 6353: color: darkred;
6354: padding: 6px;
1.523 albertel 6355: }
1.795 www 6356:
1.779 bisitz 6357: .LC_answer_not_charged_try,
1.523 albertel 6358: .LC_answer_no_grade,
6359: .LC_answer_late {
1.795 www 6360: background: lightyellow;
1.523 albertel 6361: color: black;
1.795 www 6362: padding: 6px;
1.523 albertel 6363: }
1.795 www 6364:
1.523 albertel 6365: .LC_answer_previous {
1.795 www 6366: background: lightblue;
6367: color: darkblue;
6368: padding: 6px;
1.523 albertel 6369: }
1.795 www 6370:
1.779 bisitz 6371: .LC_answer_no_message {
1.777 tempelho 6372: background: #FFFFFF;
6373: color: black;
1.795 www 6374: padding: 6px;
1.779 bisitz 6375: }
1.795 www 6376:
1.779 bisitz 6377: .LC_answer_unknown {
6378: background: orange;
6379: color: black;
1.795 www 6380: padding: 6px;
1.777 tempelho 6381: }
1.795 www 6382:
1.529 albertel 6383: span.LC_prior_numerical,
6384: span.LC_prior_string,
6385: span.LC_prior_custom,
6386: span.LC_prior_reaction,
6387: span.LC_prior_math {
1.925 bisitz 6388: font-family: $mono;
1.523 albertel 6389: white-space: pre;
6390: }
6391:
1.525 albertel 6392: span.LC_prior_string {
1.925 bisitz 6393: font-family: $mono;
1.525 albertel 6394: white-space: pre;
6395: }
6396:
1.523 albertel 6397: table.LC_prior_option {
6398: width: 100%;
6399: border-collapse: collapse;
6400: }
1.795 www 6401:
1.911 bisitz 6402: table.LC_prior_rank,
1.795 www 6403: table.LC_prior_match {
1.528 albertel 6404: border-collapse: collapse;
6405: }
1.795 www 6406:
1.528 albertel 6407: table.LC_prior_option tr td,
6408: table.LC_prior_rank tr td,
6409: table.LC_prior_match tr td {
1.524 albertel 6410: border: 1px solid #000000;
1.515 albertel 6411: }
6412:
1.855 bisitz 6413: .LC_nobreak {
1.544 albertel 6414: white-space: nowrap;
1.519 raeburn 6415: }
6416:
1.576 raeburn 6417: span.LC_cusr_emph {
6418: font-style: italic;
6419: }
6420:
1.633 raeburn 6421: span.LC_cusr_subheading {
6422: font-weight: normal;
6423: font-size: 85%;
6424: }
6425:
1.861 bisitz 6426: div.LC_docs_entry_move {
1.859 bisitz 6427: border: 1px solid #BBBBBB;
1.545 albertel 6428: background: #DDDDDD;
1.861 bisitz 6429: width: 22px;
1.859 bisitz 6430: padding: 1px;
6431: margin: 0;
1.545 albertel 6432: }
6433:
1.861 bisitz 6434: table.LC_data_table tr > td.LC_docs_entry_commands,
6435: table.LC_data_table tr > td.LC_docs_entry_parameter {
1.545 albertel 6436: font-size: x-small;
6437: }
1.795 www 6438:
1.861 bisitz 6439: .LC_docs_entry_parameter {
6440: white-space: nowrap;
6441: }
6442:
1.544 albertel 6443: .LC_docs_copy {
1.545 albertel 6444: color: #000099;
1.544 albertel 6445: }
1.795 www 6446:
1.544 albertel 6447: .LC_docs_cut {
1.545 albertel 6448: color: #550044;
1.544 albertel 6449: }
1.795 www 6450:
1.544 albertel 6451: .LC_docs_rename {
1.545 albertel 6452: color: #009900;
1.544 albertel 6453: }
1.795 www 6454:
1.544 albertel 6455: .LC_docs_remove {
1.545 albertel 6456: color: #990000;
6457: }
6458:
1.547 albertel 6459: .LC_docs_reinit_warn,
6460: .LC_docs_ext_edit {
6461: font-size: x-small;
6462: }
6463:
1.545 albertel 6464: table.LC_docs_adddocs td,
6465: table.LC_docs_adddocs th {
6466: border: 1px solid #BBBBBB;
6467: padding: 4px;
6468: background: #DDDDDD;
1.543 albertel 6469: }
6470:
1.584 albertel 6471: table.LC_sty_begin {
6472: background: #BBFFBB;
6473: }
1.795 www 6474:
1.584 albertel 6475: table.LC_sty_end {
6476: background: #FFBBBB;
6477: }
6478:
1.589 raeburn 6479: table.LC_double_column {
1.803 bisitz 6480: border-width: 0;
1.589 raeburn 6481: border-collapse: collapse;
6482: width: 100%;
6483: padding: 2px;
6484: }
6485:
6486: table.LC_double_column tr td.LC_left_col {
1.590 raeburn 6487: top: 2px;
1.589 raeburn 6488: left: 2px;
6489: width: 47%;
6490: vertical-align: top;
6491: }
6492:
6493: table.LC_double_column tr td.LC_right_col {
6494: top: 2px;
1.779 bisitz 6495: right: 2px;
1.589 raeburn 6496: width: 47%;
6497: vertical-align: top;
6498: }
6499:
1.591 raeburn 6500: div.LC_left_float {
6501: float: left;
6502: padding-right: 5%;
1.597 albertel 6503: padding-bottom: 4px;
1.591 raeburn 6504: }
6505:
6506: div.LC_clear_float_header {
1.597 albertel 6507: padding-bottom: 2px;
1.591 raeburn 6508: }
6509:
6510: div.LC_clear_float_footer {
1.597 albertel 6511: padding-top: 10px;
1.591 raeburn 6512: clear: both;
6513: }
6514:
1.597 albertel 6515: div.LC_grade_show_user {
1.941 bisitz 6516: /* border-left: 5px solid $sidebg; */
6517: border-top: 5px solid #000000;
6518: margin: 50px 0 0 0;
1.936 bisitz 6519: padding: 15px 0 5px 10px;
1.597 albertel 6520: }
1.795 www 6521:
1.936 bisitz 6522: div.LC_grade_show_user_odd_row {
1.941 bisitz 6523: /* border-left: 5px solid #000000; */
6524: }
6525:
6526: div.LC_grade_show_user div.LC_Box {
6527: margin-right: 50px;
1.597 albertel 6528: }
6529:
6530: div.LC_grade_submissions,
6531: div.LC_grade_message_center,
1.936 bisitz 6532: div.LC_grade_info_links {
1.597 albertel 6533: margin: 5px;
6534: width: 99%;
6535: background: #FFFFFF;
6536: }
1.795 www 6537:
1.597 albertel 6538: div.LC_grade_submissions_header,
1.936 bisitz 6539: div.LC_grade_message_center_header {
1.705 tempelho 6540: font-weight: bold;
6541: font-size: large;
1.597 albertel 6542: }
1.795 www 6543:
1.597 albertel 6544: div.LC_grade_submissions_body,
1.936 bisitz 6545: div.LC_grade_message_center_body {
1.597 albertel 6546: border: 1px solid black;
6547: width: 99%;
6548: background: #FFFFFF;
6549: }
1.795 www 6550:
1.613 albertel 6551: table.LC_scantron_action {
6552: width: 100%;
6553: }
1.795 www 6554:
1.613 albertel 6555: table.LC_scantron_action tr th {
1.698 harmsja 6556: font-weight:bold;
6557: font-style:normal;
1.613 albertel 6558: }
1.795 www 6559:
1.779 bisitz 6560: .LC_edit_problem_header,
1.614 albertel 6561: div.LC_edit_problem_footer {
1.705 tempelho 6562: font-weight: normal;
6563: font-size: medium;
1.602 albertel 6564: margin: 2px;
1.1060 bisitz 6565: background-color: $sidebg;
1.600 albertel 6566: }
1.795 www 6567:
1.600 albertel 6568: div.LC_edit_problem_header,
1.602 albertel 6569: div.LC_edit_problem_header div,
1.614 albertel 6570: div.LC_edit_problem_footer,
6571: div.LC_edit_problem_footer div,
1.602 albertel 6572: div.LC_edit_problem_editxml_header,
6573: div.LC_edit_problem_editxml_header div {
1.600 albertel 6574: margin-top: 5px;
6575: }
1.795 www 6576:
1.600 albertel 6577: div.LC_edit_problem_header_title {
1.705 tempelho 6578: font-weight: bold;
6579: font-size: larger;
1.602 albertel 6580: background: $tabbg;
6581: padding: 3px;
1.1060 bisitz 6582: margin: 0 0 5px 0;
1.602 albertel 6583: }
1.795 www 6584:
1.602 albertel 6585: table.LC_edit_problem_header_title {
6586: width: 100%;
1.600 albertel 6587: background: $tabbg;
1.602 albertel 6588: }
6589:
6590: div.LC_edit_problem_discards {
6591: float: left;
6592: padding-bottom: 5px;
6593: }
1.795 www 6594:
1.602 albertel 6595: div.LC_edit_problem_saves {
6596: float: right;
6597: padding-bottom: 5px;
1.600 albertel 6598: }
1.795 www 6599:
1.1075.2.34 raeburn 6600: .LC_edit_opt {
6601: padding-left: 1em;
6602: white-space: nowrap;
6603: }
6604:
1.1075.2.57 raeburn 6605: .LC_edit_problem_latexhelper{
6606: text-align: right;
6607: }
6608:
6609: #LC_edit_problem_colorful div{
6610: margin-left: 40px;
6611: }
6612:
1.911 bisitz 6613: img.stift {
1.803 bisitz 6614: border-width: 0;
6615: vertical-align: middle;
1.677 riegler 6616: }
1.680 riegler 6617:
1.923 bisitz 6618: table td.LC_mainmenu_col_fieldset {
1.680 riegler 6619: vertical-align: top;
1.777 tempelho 6620: }
1.795 www 6621:
1.716 raeburn 6622: div.LC_createcourse {
1.911 bisitz 6623: margin: 10px 10px 10px 10px;
1.716 raeburn 6624: }
6625:
1.917 raeburn 6626: .LC_dccid {
1.1075.2.38 raeburn 6627: float: right;
1.917 raeburn 6628: margin: 0.2em 0 0 0;
6629: padding: 0;
6630: font-size: 90%;
6631: display:none;
6632: }
6633:
1.897 wenzelju 6634: ol.LC_primary_menu a:hover,
1.721 harmsja 6635: ol#LC_MenuBreadcrumbs a:hover,
6636: ol#LC_PathBreadcrumbs a:hover,
1.897 wenzelju 6637: ul#LC_secondary_menu a:hover,
1.721 harmsja 6638: .LC_FormSectionClearButton input:hover
1.795 www 6639: ul.LC_TabContent li:hover a {
1.952 onken 6640: color:$button_hover;
1.911 bisitz 6641: text-decoration:none;
1.693 droeschl 6642: }
6643:
1.779 bisitz 6644: h1 {
1.911 bisitz 6645: padding: 0;
6646: line-height:130%;
1.693 droeschl 6647: }
1.698 harmsja 6648:
1.911 bisitz 6649: h2,
6650: h3,
6651: h4,
6652: h5,
6653: h6 {
6654: margin: 5px 0 5px 0;
6655: padding: 0;
6656: line-height:130%;
1.693 droeschl 6657: }
1.795 www 6658:
6659: .LC_hcell {
1.911 bisitz 6660: padding:3px 15px 3px 15px;
6661: margin: 0;
6662: background-color:$tabbg;
6663: color:$fontmenu;
6664: border-bottom:solid 1px $lg_border_color;
1.693 droeschl 6665: }
1.795 www 6666:
1.840 bisitz 6667: .LC_Box > .LC_hcell {
1.911 bisitz 6668: margin: 0 -10px 10px -10px;
1.835 bisitz 6669: }
6670:
1.721 harmsja 6671: .LC_noBorder {
1.911 bisitz 6672: border: 0;
1.698 harmsja 6673: }
1.693 droeschl 6674:
1.721 harmsja 6675: .LC_FormSectionClearButton input {
1.911 bisitz 6676: background-color:transparent;
6677: border: none;
6678: cursor:pointer;
6679: text-decoration:underline;
1.693 droeschl 6680: }
1.763 bisitz 6681:
6682: .LC_help_open_topic {
1.911 bisitz 6683: color: #FFFFFF;
6684: background-color: #EEEEFF;
6685: margin: 1px;
6686: padding: 4px;
6687: border: 1px solid #000033;
6688: white-space: nowrap;
6689: /* vertical-align: middle; */
1.759 neumanie 6690: }
1.693 droeschl 6691:
1.911 bisitz 6692: dl,
6693: ul,
6694: div,
6695: fieldset {
6696: margin: 10px 10px 10px 0;
6697: /* overflow: hidden; */
1.693 droeschl 6698: }
1.795 www 6699:
1.1075.2.90 raeburn 6700: article.geogebraweb div {
6701: margin: 0;
6702: }
6703:
1.838 bisitz 6704: fieldset > legend {
1.911 bisitz 6705: font-weight: bold;
6706: padding: 0 5px 0 5px;
1.838 bisitz 6707: }
6708:
1.813 bisitz 6709: #LC_nav_bar {
1.911 bisitz 6710: float: left;
1.995 raeburn 6711: background-color: $pgbg_or_bgcolor;
1.966 bisitz 6712: margin: 0 0 2px 0;
1.807 droeschl 6713: }
6714:
1.916 droeschl 6715: #LC_realm {
6716: margin: 0.2em 0 0 0;
6717: padding: 0;
6718: font-weight: bold;
6719: text-align: center;
1.995 raeburn 6720: background-color: $pgbg_or_bgcolor;
1.916 droeschl 6721: }
6722:
1.911 bisitz 6723: #LC_nav_bar em {
6724: font-weight: bold;
6725: font-style: normal;
1.807 droeschl 6726: }
6727:
1.897 wenzelju 6728: ol.LC_primary_menu {
1.934 droeschl 6729: margin: 0;
1.1075.2.2 raeburn 6730: padding: 0;
1.995 raeburn 6731: background-color: $pgbg_or_bgcolor;
1.807 droeschl 6732: }
6733:
1.852 droeschl 6734: ol#LC_PathBreadcrumbs {
1.911 bisitz 6735: margin: 0;
1.693 droeschl 6736: }
6737:
1.897 wenzelju 6738: ol.LC_primary_menu li {
1.1075.2.2 raeburn 6739: color: RGB(80, 80, 80);
6740: vertical-align: middle;
6741: text-align: left;
6742: list-style: none;
6743: float: left;
6744: }
6745:
6746: ol.LC_primary_menu li a {
6747: display: block;
6748: margin: 0;
6749: padding: 0 5px 0 10px;
6750: text-decoration: none;
6751: }
6752:
6753: ol.LC_primary_menu li ul {
6754: display: none;
6755: width: 10em;
6756: background-color: $data_table_light;
6757: }
6758:
6759: ol.LC_primary_menu li:hover ul, ol.LC_primary_menu li.hover ul {
6760: display: block;
6761: position: absolute;
6762: margin: 0;
6763: padding: 0;
1.1075.2.5 raeburn 6764: z-index: 2;
1.1075.2.2 raeburn 6765: }
6766:
6767: ol.LC_primary_menu li:hover li, ol.LC_primary_menu li.hover li {
6768: font-size: 90%;
1.911 bisitz 6769: vertical-align: top;
1.1075.2.2 raeburn 6770: float: none;
1.1075.2.5 raeburn 6771: border-left: 1px solid black;
6772: border-right: 1px solid black;
1.1075.2.2 raeburn 6773: }
6774:
6775: ol.LC_primary_menu li:hover li a, ol.LC_primary_menu li.hover li a {
1.1075.2.5 raeburn 6776: background-color:$data_table_light;
1.1075.2.2 raeburn 6777: }
6778:
6779: ol.LC_primary_menu li li a:hover {
6780: color:$button_hover;
6781: background-color:$data_table_dark;
1.693 droeschl 6782: }
6783:
1.897 wenzelju 6784: ol.LC_primary_menu li img {
1.911 bisitz 6785: vertical-align: bottom;
1.934 droeschl 6786: height: 1.1em;
1.1075.2.3 raeburn 6787: margin: 0.2em 0 0 0;
1.693 droeschl 6788: }
6789:
1.897 wenzelju 6790: ol.LC_primary_menu a {
1.911 bisitz 6791: color: RGB(80, 80, 80);
6792: text-decoration: none;
1.693 droeschl 6793: }
1.795 www 6794:
1.949 droeschl 6795: ol.LC_primary_menu a.LC_new_message {
6796: font-weight:bold;
6797: color: darkred;
6798: }
6799:
1.975 raeburn 6800: ol.LC_docs_parameters {
6801: margin-left: 0;
6802: padding: 0;
6803: list-style: none;
6804: }
6805:
6806: ol.LC_docs_parameters li {
6807: margin: 0;
6808: padding-right: 20px;
6809: display: inline;
6810: }
6811:
1.976 raeburn 6812: ol.LC_docs_parameters li:before {
6813: content: "\\002022 \\0020";
6814: }
6815:
6816: li.LC_docs_parameters_title {
6817: font-weight: bold;
6818: }
6819:
6820: ol.LC_docs_parameters li.LC_docs_parameters_title:before {
6821: content: "";
6822: }
6823:
1.897 wenzelju 6824: ul#LC_secondary_menu {
1.1075.2.23 raeburn 6825: clear: right;
1.911 bisitz 6826: color: $fontmenu;
6827: background: $tabbg;
6828: list-style: none;
6829: padding: 0;
6830: margin: 0;
6831: width: 100%;
1.995 raeburn 6832: text-align: left;
1.1075.2.4 raeburn 6833: float: left;
1.808 droeschl 6834: }
6835:
1.897 wenzelju 6836: ul#LC_secondary_menu li {
1.911 bisitz 6837: font-weight: bold;
6838: line-height: 1.8em;
6839: border-right: 1px solid black;
6840: vertical-align: middle;
1.1075.2.4 raeburn 6841: float: left;
6842: }
6843:
6844: ul#LC_secondary_menu li.LC_hoverable:hover, ul#LC_secondary_menu li.hover {
6845: background-color: $data_table_light;
6846: }
6847:
6848: ul#LC_secondary_menu li a {
6849: padding: 0 0.8em;
6850: }
6851:
6852: ul#LC_secondary_menu li ul {
6853: display: none;
6854: }
6855:
6856: ul#LC_secondary_menu li:hover ul, ul#LC_secondary_menu li.hover ul {
6857: display: block;
6858: position: absolute;
6859: margin: 0;
6860: padding: 0;
6861: list-style:none;
6862: float: none;
6863: background-color: $data_table_light;
1.1075.2.5 raeburn 6864: z-index: 2;
1.1075.2.10 raeburn 6865: margin-left: -1px;
1.1075.2.4 raeburn 6866: }
6867:
6868: ul#LC_secondary_menu li ul li {
6869: font-size: 90%;
6870: vertical-align: top;
6871: border-left: 1px solid black;
6872: border-right: 1px solid black;
1.1075.2.33 raeburn 6873: background-color: $data_table_light;
1.1075.2.4 raeburn 6874: list-style:none;
6875: float: none;
6876: }
6877:
6878: ul#LC_secondary_menu li ul li:hover, ul#LC_secondary_menu li ul li.hover {
6879: background-color: $data_table_dark;
1.807 droeschl 6880: }
6881:
1.847 tempelho 6882: ul.LC_TabContent {
1.911 bisitz 6883: display:block;
6884: background: $sidebg;
6885: border-bottom: solid 1px $lg_border_color;
6886: list-style:none;
1.1020 raeburn 6887: margin: -1px -10px 0 -10px;
1.911 bisitz 6888: padding: 0;
1.693 droeschl 6889: }
6890:
1.795 www 6891: ul.LC_TabContent li,
6892: ul.LC_TabContentBigger li {
1.911 bisitz 6893: float:left;
1.741 harmsja 6894: }
1.795 www 6895:
1.897 wenzelju 6896: ul#LC_secondary_menu li a {
1.911 bisitz 6897: color: $fontmenu;
6898: text-decoration: none;
1.693 droeschl 6899: }
1.795 www 6900:
1.721 harmsja 6901: ul.LC_TabContent {
1.952 onken 6902: min-height:20px;
1.721 harmsja 6903: }
1.795 www 6904:
6905: ul.LC_TabContent li {
1.911 bisitz 6906: vertical-align:middle;
1.959 onken 6907: padding: 0 16px 0 10px;
1.911 bisitz 6908: background-color:$tabbg;
6909: border-bottom:solid 1px $lg_border_color;
1.1020 raeburn 6910: border-left: solid 1px $font;
1.721 harmsja 6911: }
1.795 www 6912:
1.847 tempelho 6913: ul.LC_TabContent .right {
1.911 bisitz 6914: float:right;
1.847 tempelho 6915: }
6916:
1.911 bisitz 6917: ul.LC_TabContent li a,
6918: ul.LC_TabContent li {
6919: color:rgb(47,47,47);
6920: text-decoration:none;
6921: font-size:95%;
6922: font-weight:bold;
1.952 onken 6923: min-height:20px;
6924: }
6925:
1.959 onken 6926: ul.LC_TabContent li a:hover,
6927: ul.LC_TabContent li a:focus {
1.952 onken 6928: color: $button_hover;
1.959 onken 6929: background:none;
6930: outline:none;
1.952 onken 6931: }
6932:
6933: ul.LC_TabContent li:hover {
6934: color: $button_hover;
6935: cursor:pointer;
1.721 harmsja 6936: }
1.795 www 6937:
1.911 bisitz 6938: ul.LC_TabContent li.active {
1.952 onken 6939: color: $font;
1.911 bisitz 6940: background:#FFFFFF url(/adm/lonIcons/open.gif) no-repeat scroll right center;
1.952 onken 6941: border-bottom:solid 1px #FFFFFF;
6942: cursor: default;
1.744 ehlerst 6943: }
1.795 www 6944:
1.959 onken 6945: ul.LC_TabContent li.active a {
6946: color:$font;
6947: background:#FFFFFF;
6948: outline: none;
6949: }
1.1047 raeburn 6950:
6951: ul.LC_TabContent li.goback {
6952: float: left;
6953: border-left: none;
6954: }
6955:
1.870 tempelho 6956: #maincoursedoc {
1.911 bisitz 6957: clear:both;
1.870 tempelho 6958: }
6959:
6960: ul.LC_TabContentBigger {
1.911 bisitz 6961: display:block;
6962: list-style:none;
6963: padding: 0;
1.870 tempelho 6964: }
6965:
1.795 www 6966: ul.LC_TabContentBigger li {
1.911 bisitz 6967: vertical-align:bottom;
6968: height: 30px;
6969: font-size:110%;
6970: font-weight:bold;
6971: color: #737373;
1.841 tempelho 6972: }
6973:
1.957 onken 6974: ul.LC_TabContentBigger li.active {
6975: position: relative;
6976: top: 1px;
6977: }
6978:
1.870 tempelho 6979: ul.LC_TabContentBigger li a {
1.911 bisitz 6980: background:url('/adm/lonIcons/tabbgleft.gif') left bottom no-repeat;
6981: height: 30px;
6982: line-height: 30px;
6983: text-align: center;
6984: display: block;
6985: text-decoration: none;
1.958 onken 6986: outline: none;
1.741 harmsja 6987: }
1.795 www 6988:
1.870 tempelho 6989: ul.LC_TabContentBigger li.active a {
1.911 bisitz 6990: background:url('/adm/lonIcons/tabbgleft.gif') left top no-repeat;
6991: color:$font;
1.744 ehlerst 6992: }
1.795 www 6993:
1.870 tempelho 6994: ul.LC_TabContentBigger li b {
1.911 bisitz 6995: background: url('/adm/lonIcons/tabbgright.gif') no-repeat right bottom;
6996: display: block;
6997: float: left;
6998: padding: 0 30px;
1.957 onken 6999: border-bottom: 1px solid $lg_border_color;
1.870 tempelho 7000: }
7001:
1.956 onken 7002: ul.LC_TabContentBigger li:hover b {
7003: color:$button_hover;
7004: }
7005:
1.870 tempelho 7006: ul.LC_TabContentBigger li.active b {
1.911 bisitz 7007: background:url('/adm/lonIcons/tabbgright.gif') right top no-repeat;
7008: color:$font;
1.957 onken 7009: border: 0;
1.741 harmsja 7010: }
1.693 droeschl 7011:
1.870 tempelho 7012:
1.862 bisitz 7013: ul.LC_CourseBreadcrumbs {
7014: background: $sidebg;
1.1020 raeburn 7015: height: 2em;
1.862 bisitz 7016: padding-left: 10px;
1.1020 raeburn 7017: margin: 0;
1.862 bisitz 7018: list-style-position: inside;
7019: }
7020:
1.911 bisitz 7021: ol#LC_MenuBreadcrumbs,
1.862 bisitz 7022: ol#LC_PathBreadcrumbs {
1.911 bisitz 7023: padding-left: 10px;
7024: margin: 0;
1.933 droeschl 7025: height: 2.5em; /* equal to #LC_breadcrumbs line-height */
1.693 droeschl 7026: }
7027:
1.911 bisitz 7028: ol#LC_MenuBreadcrumbs li,
7029: ol#LC_PathBreadcrumbs li,
1.862 bisitz 7030: ul.LC_CourseBreadcrumbs li {
1.911 bisitz 7031: display: inline;
1.933 droeschl 7032: white-space: normal;
1.693 droeschl 7033: }
7034:
1.823 bisitz 7035: ol#LC_MenuBreadcrumbs li a,
1.862 bisitz 7036: ul.LC_CourseBreadcrumbs li a {
1.911 bisitz 7037: text-decoration: none;
7038: font-size:90%;
1.693 droeschl 7039: }
1.795 www 7040:
1.969 droeschl 7041: ol#LC_MenuBreadcrumbs h1 {
7042: display: inline;
7043: font-size: 90%;
7044: line-height: 2.5em;
7045: margin: 0;
7046: padding: 0;
7047: }
7048:
1.795 www 7049: ol#LC_PathBreadcrumbs li a {
1.911 bisitz 7050: text-decoration:none;
7051: font-size:100%;
7052: font-weight:bold;
1.693 droeschl 7053: }
1.795 www 7054:
1.840 bisitz 7055: .LC_Box {
1.911 bisitz 7056: border: solid 1px $lg_border_color;
7057: padding: 0 10px 10px 10px;
1.746 neumanie 7058: }
1.795 www 7059:
1.1020 raeburn 7060: .LC_DocsBox {
7061: border: solid 1px $lg_border_color;
7062: padding: 0 0 10px 10px;
7063: }
7064:
1.795 www 7065: .LC_AboutMe_Image {
1.911 bisitz 7066: float:left;
7067: margin-right:10px;
1.747 neumanie 7068: }
1.795 www 7069:
7070: .LC_Clear_AboutMe_Image {
1.911 bisitz 7071: clear:left;
1.747 neumanie 7072: }
1.795 www 7073:
1.721 harmsja 7074: dl.LC_ListStyleClean dt {
1.911 bisitz 7075: padding-right: 5px;
7076: display: table-header-group;
1.693 droeschl 7077: }
7078:
1.721 harmsja 7079: dl.LC_ListStyleClean dd {
1.911 bisitz 7080: display: table-row;
1.693 droeschl 7081: }
7082:
1.721 harmsja 7083: .LC_ListStyleClean,
7084: .LC_ListStyleSimple,
7085: .LC_ListStyleNormal,
1.795 www 7086: .LC_ListStyleSpecial {
1.911 bisitz 7087: /* display:block; */
7088: list-style-position: inside;
7089: list-style-type: none;
7090: overflow: hidden;
7091: padding: 0;
1.693 droeschl 7092: }
7093:
1.721 harmsja 7094: .LC_ListStyleSimple li,
7095: .LC_ListStyleSimple dd,
7096: .LC_ListStyleNormal li,
7097: .LC_ListStyleNormal dd,
7098: .LC_ListStyleSpecial li,
1.795 www 7099: .LC_ListStyleSpecial dd {
1.911 bisitz 7100: margin: 0;
7101: padding: 5px 5px 5px 10px;
7102: clear: both;
1.693 droeschl 7103: }
7104:
1.721 harmsja 7105: .LC_ListStyleClean li,
7106: .LC_ListStyleClean dd {
1.911 bisitz 7107: padding-top: 0;
7108: padding-bottom: 0;
1.693 droeschl 7109: }
7110:
1.721 harmsja 7111: .LC_ListStyleSimple dd,
1.795 www 7112: .LC_ListStyleSimple li {
1.911 bisitz 7113: border-bottom: solid 1px $lg_border_color;
1.693 droeschl 7114: }
7115:
1.721 harmsja 7116: .LC_ListStyleSpecial li,
7117: .LC_ListStyleSpecial dd {
1.911 bisitz 7118: list-style-type: none;
7119: background-color: RGB(220, 220, 220);
7120: margin-bottom: 4px;
1.693 droeschl 7121: }
7122:
1.721 harmsja 7123: table.LC_SimpleTable {
1.911 bisitz 7124: margin:5px;
7125: border:solid 1px $lg_border_color;
1.795 www 7126: }
1.693 droeschl 7127:
1.721 harmsja 7128: table.LC_SimpleTable tr {
1.911 bisitz 7129: padding: 0;
7130: border:solid 1px $lg_border_color;
1.693 droeschl 7131: }
1.795 www 7132:
7133: table.LC_SimpleTable thead {
1.911 bisitz 7134: background:rgb(220,220,220);
1.693 droeschl 7135: }
7136:
1.721 harmsja 7137: div.LC_columnSection {
1.911 bisitz 7138: display: block;
7139: clear: both;
7140: overflow: hidden;
7141: margin: 0;
1.693 droeschl 7142: }
7143:
1.721 harmsja 7144: div.LC_columnSection>* {
1.911 bisitz 7145: float: left;
7146: margin: 10px 20px 10px 0;
7147: overflow:hidden;
1.693 droeschl 7148: }
1.721 harmsja 7149:
1.795 www 7150: table em {
1.911 bisitz 7151: font-weight: bold;
7152: font-style: normal;
1.748 schulted 7153: }
1.795 www 7154:
1.779 bisitz 7155: table.LC_tableBrowseRes,
1.795 www 7156: table.LC_tableOfContent {
1.911 bisitz 7157: border:none;
7158: border-spacing: 1px;
7159: padding: 3px;
7160: background-color: #FFFFFF;
7161: font-size: 90%;
1.753 droeschl 7162: }
1.789 droeschl 7163:
1.911 bisitz 7164: table.LC_tableOfContent {
7165: border-collapse: collapse;
1.789 droeschl 7166: }
7167:
1.771 droeschl 7168: table.LC_tableBrowseRes a,
1.768 schulted 7169: table.LC_tableOfContent a {
1.911 bisitz 7170: background-color: transparent;
7171: text-decoration: none;
1.753 droeschl 7172: }
7173:
1.795 www 7174: table.LC_tableOfContent img {
1.911 bisitz 7175: border: none;
7176: height: 1.3em;
7177: vertical-align: text-bottom;
7178: margin-right: 0.3em;
1.753 droeschl 7179: }
1.757 schulted 7180:
1.795 www 7181: a#LC_content_toolbar_firsthomework {
1.911 bisitz 7182: background-image:url(/res/adm/pages/open-first-problem.gif);
1.774 ehlerst 7183: }
7184:
1.795 www 7185: a#LC_content_toolbar_everything {
1.911 bisitz 7186: background-image:url(/res/adm/pages/show-all.gif);
1.774 ehlerst 7187: }
7188:
1.795 www 7189: a#LC_content_toolbar_uncompleted {
1.911 bisitz 7190: background-image:url(/res/adm/pages/show-incomplete-problems.gif);
1.774 ehlerst 7191: }
7192:
1.795 www 7193: #LC_content_toolbar_clearbubbles {
1.911 bisitz 7194: background-image:url(/res/adm/pages/mark-discussionentries-read.gif);
1.774 ehlerst 7195: }
7196:
1.795 www 7197: a#LC_content_toolbar_changefolder {
1.911 bisitz 7198: background : url(/res/adm/pages/close-all-folders.gif) top center ;
1.757 schulted 7199: }
7200:
1.795 www 7201: a#LC_content_toolbar_changefolder_toggled {
1.911 bisitz 7202: background-image:url(/res/adm/pages/open-all-folders.gif);
1.757 schulted 7203: }
7204:
1.1043 raeburn 7205: a#LC_content_toolbar_edittoplevel {
7206: background-image:url(/res/adm/pages/edittoplevel.gif);
7207: }
7208:
1.795 www 7209: ul#LC_toolbar li a:hover {
1.911 bisitz 7210: background-position: bottom center;
1.757 schulted 7211: }
7212:
1.795 www 7213: ul#LC_toolbar {
1.911 bisitz 7214: padding: 0;
7215: margin: 2px;
7216: list-style:none;
7217: position:relative;
7218: background-color:white;
1.1075.2.9 raeburn 7219: overflow: auto;
1.757 schulted 7220: }
7221:
1.795 www 7222: ul#LC_toolbar li {
1.911 bisitz 7223: border:1px solid white;
7224: padding: 0;
7225: margin: 0;
7226: float: left;
7227: display:inline;
7228: vertical-align:middle;
1.1075.2.9 raeburn 7229: white-space: nowrap;
1.911 bisitz 7230: }
1.757 schulted 7231:
1.783 amueller 7232:
1.795 www 7233: a.LC_toolbarItem {
1.911 bisitz 7234: display:block;
7235: padding: 0;
7236: margin: 0;
7237: height: 32px;
7238: width: 32px;
7239: color:white;
7240: border: none;
7241: background-repeat:no-repeat;
7242: background-color:transparent;
1.757 schulted 7243: }
7244:
1.915 droeschl 7245: ul.LC_funclist {
7246: margin: 0;
7247: padding: 0.5em 1em 0.5em 0;
7248: }
7249:
1.933 droeschl 7250: ul.LC_funclist > li:first-child {
7251: font-weight:bold;
7252: margin-left:0.8em;
7253: }
7254:
1.915 droeschl 7255: ul.LC_funclist + ul.LC_funclist {
7256: /*
7257: left border as a seperator if we have more than
7258: one list
7259: */
7260: border-left: 1px solid $sidebg;
7261: /*
7262: this hides the left border behind the border of the
7263: outer box if element is wrapped to the next 'line'
7264: */
7265: margin-left: -1px;
7266: }
7267:
1.843 bisitz 7268: ul.LC_funclist li {
1.915 droeschl 7269: display: inline;
1.782 bisitz 7270: white-space: nowrap;
1.915 droeschl 7271: margin: 0 0 0 25px;
7272: line-height: 150%;
1.782 bisitz 7273: }
7274:
1.974 wenzelju 7275: .LC_hidden {
7276: display: none;
7277: }
7278:
1.1030 www 7279: .LCmodal-overlay {
7280: position:fixed;
7281: top:0;
7282: right:0;
7283: bottom:0;
7284: left:0;
7285: height:100%;
7286: width:100%;
7287: margin:0;
7288: padding:0;
7289: background:#999;
7290: opacity:.75;
7291: filter: alpha(opacity=75);
7292: -moz-opacity: 0.75;
7293: z-index:101;
7294: }
7295:
7296: * html .LCmodal-overlay {
7297: position: absolute;
7298: height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px');
7299: }
7300:
7301: .LCmodal-window {
7302: position:fixed;
7303: top:50%;
7304: left:50%;
7305: margin:0;
7306: padding:0;
7307: z-index:102;
7308: }
7309:
7310: * html .LCmodal-window {
7311: position:absolute;
7312: }
7313:
7314: .LCclose-window {
7315: position:absolute;
7316: width:32px;
7317: height:32px;
7318: right:8px;
7319: top:8px;
7320: background:transparent url('/res/adm/pages/process-stop.png') no-repeat scroll right top;
7321: text-indent:-99999px;
7322: overflow:hidden;
7323: cursor:pointer;
7324: }
7325:
1.1075.2.17 raeburn 7326: /*
7327: styles used by TTH when "Default set of options to pass to tth/m
7328: when converting TeX" in course settings has been set
7329:
7330: option passed: -t
7331:
7332: */
7333:
7334: td div.comp { margin-top: -0.6ex; margin-bottom: -1ex;}
7335: td div.comb { margin-top: -0.6ex; margin-bottom: -.6ex;}
7336: td div.hrcomp { line-height: 0.9; margin-top: -0.8ex; margin-bottom: -1ex;}
7337: td div.norm {line-height:normal;}
7338:
7339: /*
7340: option passed -y3
7341: */
7342:
7343: span.roman {font-family: serif; font-style: normal; font-weight: normal;}
7344: span.overacc2 {position: relative; left: .8em; top: -1.2ex;}
7345: span.overacc1 {position: relative; left: .6em; top: -1.2ex;}
7346:
1.343 albertel 7347: END
7348: }
7349:
1.306 albertel 7350: =pod
7351:
7352: =item * &headtag()
7353:
7354: Returns a uniform footer for LON-CAPA web pages.
7355:
1.307 albertel 7356: Inputs: $title - optional title for the head
7357: $head_extra - optional extra HTML to put inside the <head>
1.315 albertel 7358: $args - optional arguments
1.319 albertel 7359: force_register - if is true call registerurl so the remote is
7360: informed
1.415 albertel 7361: redirect -> array ref of
7362: 1- seconds before redirect occurs
7363: 2- url to redirect to
7364: 3- whether the side effect should occur
1.315 albertel 7365: (side effect of setting
7366: $env{'internal.head.redirect'} to the url
7367: redirected too)
1.352 albertel 7368: domain -> force to color decorate a page for a specific
7369: domain
7370: function -> force usage of a specific rolish color scheme
7371: bgcolor -> override the default page bgcolor
1.460 albertel 7372: no_auto_mt_title
7373: -> prevent &mt()ing the title arg
1.464 albertel 7374:
1.306 albertel 7375: =cut
7376:
7377: sub headtag {
1.313 albertel 7378: my ($title,$head_extra,$args) = @_;
1.306 albertel 7379:
1.363 albertel 7380: my $function = $args->{'function'} || &get_users_function();
7381: my $domain = $args->{'domain'} || &determinedomain();
7382: my $bgcolor = $args->{'bgcolor'} || &designparm($function.'.pgbg',$domain);
1.1075.2.52 raeburn 7383: my $httphost = $args->{'use_absolute'};
1.418 albertel 7384: my $url = join(':',$env{'user.name'},$env{'user.domain'},
1.458 albertel 7385: $Apache::lonnet::perlvar{'lonVersion'},
1.531 albertel 7386: #time(),
1.418 albertel 7387: $env{'environment.color.timestamp'},
1.363 albertel 7388: $function,$domain,$bgcolor);
7389:
1.369 www 7390: $url = '/adm/css/'.&escape($url).'.css';
1.363 albertel 7391:
1.308 albertel 7392: my $result =
7393: '<head>'.
1.1075.2.56 raeburn 7394: &font_settings($args);
1.319 albertel 7395:
1.1075.2.72 raeburn 7396: my $inhibitprint;
7397: if ($args->{'print_suppress'}) {
7398: $inhibitprint = &print_suppression();
7399: }
1.1064 raeburn 7400:
1.461 albertel 7401: if (!$args->{'frameset'}) {
7402: $result .= &Apache::lonhtmlcommon::htmlareaheaders();
7403: }
1.1075.2.12 raeburn 7404: if ($args->{'force_register'}) {
7405: $result .= &Apache::lonmenu::registerurl(1);
1.319 albertel 7406: }
1.436 albertel 7407: if (!$args->{'no_nav_bar'}
7408: && !$args->{'only_body'}
7409: && !$args->{'frameset'}) {
1.1075.2.52 raeburn 7410: $result .= &help_menu_js($httphost);
1.1032 www 7411: $result.=&modal_window();
1.1038 www 7412: $result.=&togglebox_script();
1.1034 www 7413: $result.=&wishlist_window();
1.1041 www 7414: $result.=&LCprogressbarUpdate_script();
1.1034 www 7415: } else {
7416: if ($args->{'add_modal'}) {
7417: $result.=&modal_window();
7418: }
7419: if ($args->{'add_wishlist'}) {
7420: $result.=&wishlist_window();
7421: }
1.1038 www 7422: if ($args->{'add_togglebox'}) {
7423: $result.=&togglebox_script();
7424: }
1.1041 www 7425: if ($args->{'add_progressbar'}) {
7426: $result.=&LCprogressbarUpdate_script();
7427: }
1.436 albertel 7428: }
1.314 albertel 7429: if (ref($args->{'redirect'})) {
1.414 albertel 7430: my ($time,$url,$inhibit_continue) = @{$args->{'redirect'}};
1.315 albertel 7431: $url = &Apache::lonenc::check_encrypt($url);
1.414 albertel 7432: if (!$inhibit_continue) {
7433: $env{'internal.head.redirect'} = $url;
7434: }
1.313 albertel 7435: $result.=<<ADDMETA
7436: <meta http-equiv="pragma" content="no-cache" />
1.344 albertel 7437: <meta http-equiv="Refresh" content="$time; url=$url" />
1.313 albertel 7438: ADDMETA
1.1075.2.89 raeburn 7439: } else {
7440: unless (($args->{'frameset'}) || ($args->{'js_ready'}) || ($args->{'only_body'}) || ($args->{'no_nav_bar'})) {
7441: my $requrl = $env{'request.uri'};
7442: if ($requrl eq '') {
7443: $requrl = $ENV{'REQUEST_URI'};
7444: $requrl =~ s/\?.+$//;
7445: }
7446: unless (($requrl =~ m{^/adm/(?:switchserver|login|authenticate|logout|groupsort|cleanup|helper|slotrequest|grades)(\?|$)}) ||
7447: (($requrl =~ m{^/res/}) && (($env{'form.submitted'} eq 'scantron') ||
7448: ($env{'form.grade_symb'}) || ($Apache::lonhomework::scantronmode)))) {
7449: my $dom_in_use = $Apache::lonnet::perlvar{'lonDefDomain'};
7450: unless (&Apache::lonnet::allowed('mau',$dom_in_use)) {
7451: my %domdefs = &Apache::lonnet::get_domain_defaults($dom_in_use);
7452: if (ref($domdefs{'offloadnow'}) eq 'HASH') {
7453: my $lonhost = $Apache::lonnet::perlvar{'lonHostID'};
7454: if ($domdefs{'offloadnow'}{$lonhost}) {
7455: my $newserver = &Apache::lonnet::spareserver(30000,undef,1,$dom_in_use);
7456: if (($newserver) && ($newserver ne $lonhost)) {
7457: my $numsec = 5;
7458: my $timeout = $numsec * 1000;
7459: my ($newurl,$locknum,%locks,$msg);
7460: if ($env{'request.role.adv'}) {
7461: ($locknum,%locks) = &Apache::lonnet::get_locks();
7462: }
7463: my $disable_submit = 0;
7464: if ($requrl =~ /$LONCAPA::assess_re/) {
7465: $disable_submit = 1;
7466: }
7467: if ($locknum) {
7468: my @lockinfo = sort(values(%locks));
7469: $msg = &mt('Once the following tasks are complete: ')."\\n".
7470: join(", ",sort(values(%locks)))."\\n".
7471: &mt('your session will be transferred to a different server, after you click "Roles".');
7472: } else {
7473: if (($requrl =~ m{^/res/}) && ($env{'form.submitted'} =~ /^part_/)) {
7474: $msg = &mt('Your LON-CAPA submission has been recorded')."\\n";
7475: }
7476: $msg .= &mt('Your current LON-CAPA session will be transferred to a different server in [quant,_1,second].',$numsec);
7477: $newurl = '/adm/switchserver?otherserver='.$newserver;
7478: if (($env{'request.role'}) && ($env{'request.role'} ne 'cm')) {
7479: $newurl .= '&role='.$env{'request.role'};
7480: }
7481: if ($env{'request.symb'}) {
7482: $newurl .= '&symb='.$env{'request.symb'};
7483: } else {
7484: $newurl .= '&origurl='.$requrl;
7485: }
7486: }
7487: $result.=<<OFFLOAD
7488: <meta http-equiv="pragma" content="no-cache" />
7489: <script type="text/javascript">
1.1075.2.92 raeburn 7490: // <![CDATA[
1.1075.2.89 raeburn 7491: function LC_Offload_Now() {
7492: var dest = "$newurl";
7493: if (dest != '') {
7494: window.location.href="$newurl";
7495: }
7496: }
1.1075.2.92 raeburn 7497: \$(document).ready(function () {
7498: window.alert('$msg');
7499: if ($disable_submit) {
1.1075.2.89 raeburn 7500: \$(".LC_hwk_submit").prop("disabled", true);
7501: \$( ".LC_textline" ).prop( "readonly", "readonly");
1.1075.2.92 raeburn 7502: }
7503: setTimeout('LC_Offload_Now()', $timeout);
7504: });
7505: // ]]>
1.1075.2.89 raeburn 7506: </script>
7507: OFFLOAD
7508: }
7509: }
7510: }
7511: }
7512: }
7513: }
1.313 albertel 7514: }
1.306 albertel 7515: if (!defined($title)) {
7516: $title = 'The LearningOnline Network with CAPA';
7517: }
1.460 albertel 7518: if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); }
7519: $result .= '<title> LON-CAPA '.$title.'</title>'
1.1075.2.61 raeburn 7520: .'<link rel="stylesheet" type="text/css" href="'.$url.'"';
7521: if (!$args->{'frameset'}) {
7522: $result .= ' /';
7523: }
7524: $result .= '>'
1.1064 raeburn 7525: .$inhibitprint
1.414 albertel 7526: .$head_extra;
1.1075.2.42 raeburn 7527: if ($env{'browser.mobile'}) {
7528: $result .= '
7529: <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0">
7530: <meta name="apple-mobile-web-app-capable" content="yes" />';
7531: }
1.962 droeschl 7532: return $result.'</head>';
1.306 albertel 7533: }
7534:
7535: =pod
7536:
1.340 albertel 7537: =item * &font_settings()
7538:
7539: Returns neccessary <meta> to set the proper encoding
7540:
1.1075.2.56 raeburn 7541: Inputs: optional reference to HASH -- $args passed to &headtag()
1.340 albertel 7542:
7543: =cut
7544:
7545: sub font_settings {
1.1075.2.56 raeburn 7546: my ($args) = @_;
1.340 albertel 7547: my $headerstring='';
1.1075.2.56 raeburn 7548: if ((!$env{'browser.mathml'} && $env{'browser.unicode'}) ||
7549: ((ref($args) eq 'HASH') && ($args->{'browser.unicode'}))) {
1.340 albertel 7550: $headerstring.=
1.1075.2.61 raeburn 7551: '<meta http-equiv="Content-Type" content="text/html; charset=utf-8"';
7552: if (!$args->{'frameset'}) {
7553: $headerstring.= ' /';
7554: }
7555: $headerstring .= '>'."\n";
1.340 albertel 7556: }
7557: return $headerstring;
7558: }
7559:
1.341 albertel 7560: =pod
7561:
1.1064 raeburn 7562: =item * &print_suppression()
7563:
7564: In course context returns css which causes the body to be blank when media="print",
7565: if printout generation is unavailable for the current resource.
7566:
7567: This could be because:
7568:
7569: (a) printstartdate is in the future
7570:
7571: (b) printenddate is in the past
7572:
7573: (c) there is an active exam block with "printout"
7574: functionality blocked
7575:
7576: Users with pav, pfo or evb privileges are exempt.
7577:
7578: Inputs: none
7579:
7580: =cut
7581:
7582:
7583: sub print_suppression {
7584: my $noprint;
7585: if ($env{'request.course.id'}) {
7586: my $scope = $env{'request.course.id'};
7587: if ((&Apache::lonnet::allowed('pav',$scope)) ||
7588: (&Apache::lonnet::allowed('pfo',$scope))) {
7589: return;
7590: }
7591: if ($env{'request.course.sec'} ne '') {
7592: $scope .= "/$env{'request.course.sec'}";
7593: if ((&Apache::lonnet::allowed('pav',$scope)) ||
7594: (&Apache::lonnet::allowed('pfo',$scope))) {
1.1065 raeburn 7595: return;
1.1064 raeburn 7596: }
7597: }
7598: my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
7599: my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
1.1075.2.73 raeburn 7600: my $blocked = &blocking_status('printout',$cnum,$cdom,undef,1);
1.1064 raeburn 7601: if ($blocked) {
7602: my $checkrole = "cm./$cdom/$cnum";
7603: if ($env{'request.course.sec'} ne '') {
7604: $checkrole .= "/$env{'request.course.sec'}";
7605: }
7606: unless ((&Apache::lonnet::allowed('evb',undef,undef,$checkrole)) &&
7607: ($env{'request.role'} !~ m{^st\./$cdom/$cnum})) {
7608: $noprint = 1;
7609: }
7610: }
7611: unless ($noprint) {
7612: my $symb = &Apache::lonnet::symbread();
7613: if ($symb ne '') {
7614: my $navmap = Apache::lonnavmaps::navmap->new();
7615: if (ref($navmap)) {
7616: my $res = $navmap->getBySymb($symb);
7617: if (ref($res)) {
7618: if (!$res->resprintable()) {
7619: $noprint = 1;
7620: }
7621: }
7622: }
7623: }
7624: }
7625: if ($noprint) {
7626: return <<"ENDSTYLE";
7627: <style type="text/css" media="print">
7628: body { display:none }
7629: </style>
7630: ENDSTYLE
7631: }
7632: }
7633: return;
7634: }
7635:
7636: =pod
7637:
1.341 albertel 7638: =item * &xml_begin()
7639:
7640: Returns the needed doctype and <html>
7641:
7642: Inputs: none
7643:
7644: =cut
7645:
7646: sub xml_begin {
1.1075.2.61 raeburn 7647: my ($is_frameset) = @_;
1.341 albertel 7648: my $output='';
7649:
7650: if ($env{'browser.mathml'}) {
7651: $output='<?xml version="1.0"?>'
7652: #.'<?xml-stylesheet type="text/css" href="/adm/MathML/mathml.css"?>'."\n"
7653: # .'<!DOCTYPE html SYSTEM "/adm/MathML/mathml.dtd" '
7654:
7655: # .'<!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">] >'
7656: .'<!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">'
7657: .'<html xmlns:math="http://www.w3.org/1998/Math/MathML" '
7658: .'xmlns="http://www.w3.org/1999/xhtml">';
1.1075.2.61 raeburn 7659: } elsif ($is_frameset) {
7660: $output='<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">'."\n".
7661: '<html>'."\n";
1.341 albertel 7662: } else {
1.1075.2.61 raeburn 7663: $output='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'."\n".
7664: '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">'."\n";
1.341 albertel 7665: }
7666: return $output;
7667: }
1.340 albertel 7668:
7669: =pod
7670:
1.306 albertel 7671: =item * &start_page()
7672:
7673: Returns a complete <html> .. <body> section for LON-CAPA web pages.
7674:
1.648 raeburn 7675: Inputs:
7676:
7677: =over 4
7678:
7679: $title - optional title for the page
7680:
7681: $head_extra - optional extra HTML to incude inside the <head>
7682:
7683: $args - additional optional args supported are:
7684:
7685: =over 8
7686:
7687: only_body -> is true will set &bodytag() onlybodytag
1.317 albertel 7688: arg on
1.814 bisitz 7689: no_nav_bar -> is true will set &bodytag() no_nav_bar arg on
1.648 raeburn 7690: add_entries -> additional attributes to add to the <body>
7691: domain -> force to color decorate a page for a
1.317 albertel 7692: specific domain
1.648 raeburn 7693: function -> force usage of a specific rolish color
1.317 albertel 7694: scheme
1.648 raeburn 7695: redirect -> see &headtag()
7696: bgcolor -> override the default page bg color
7697: js_ready -> return a string ready for being used in
1.317 albertel 7698: a javascript writeln
1.648 raeburn 7699: html_encode -> return a string ready for being used in
1.320 albertel 7700: a html attribute
1.648 raeburn 7701: force_register -> if is true will turn on the &bodytag()
1.317 albertel 7702: $forcereg arg
1.648 raeburn 7703: frameset -> if true will start with a <frameset>
1.330 albertel 7704: rather than <body>
1.648 raeburn 7705: skip_phases -> hash ref of
1.338 albertel 7706: head -> skip the <html><head> generation
7707: body -> skip all <body> generation
1.1075.2.12 raeburn 7708: no_inline_link -> if true and in remote mode, don't show the
7709: 'Switch To Inline Menu' link
1.648 raeburn 7710: no_auto_mt_title -> prevent &mt()ing the title arg
7711: inherit_jsmath -> when creating popup window in a page,
7712: should it have jsmath forced on by the
7713: current page
1.867 kalberla 7714: bread_crumbs -> Array containing breadcrumbs
1.983 raeburn 7715: bread_crumbs_component -> if exists show it as headline else show only the breadcrumbs
1.1075.2.15 raeburn 7716: group -> includes the current group, if page is for a
7717: specific group
1.361 albertel 7718:
1.648 raeburn 7719: =back
1.460 albertel 7720:
1.648 raeburn 7721: =back
1.562 albertel 7722:
1.306 albertel 7723: =cut
7724:
7725: sub start_page {
1.309 albertel 7726: my ($title,$head_extra,$args) = @_;
1.318 albertel 7727: #&Apache::lonnet::logthis("start_page ".join(':',caller(0)));
1.319 albertel 7728:
1.315 albertel 7729: $env{'internal.start_page'}++;
1.1075.2.15 raeburn 7730: my ($result,@advtools);
1.964 droeschl 7731:
1.338 albertel 7732: if (! exists($args->{'skip_phases'}{'head'}) ) {
1.1075.2.62 raeburn 7733: $result .= &xml_begin($args->{'frameset'}) . &headtag($title, $head_extra, $args);
1.338 albertel 7734: }
7735:
7736: if (! exists($args->{'skip_phases'}{'body'}) ) {
7737: if ($args->{'frameset'}) {
7738: my $attr_string = &make_attr_string($args->{'force_register'},
7739: $args->{'add_entries'});
7740: $result .= "\n<frameset $attr_string>\n";
1.831 bisitz 7741: } else {
7742: $result .=
7743: &bodytag($title,
7744: $args->{'function'}, $args->{'add_entries'},
7745: $args->{'only_body'}, $args->{'domain'},
7746: $args->{'force_register'}, $args->{'no_nav_bar'},
1.1075.2.12 raeburn 7747: $args->{'bgcolor'}, $args->{'no_inline_link'},
1.1075.2.15 raeburn 7748: $args, \@advtools);
1.831 bisitz 7749: }
1.330 albertel 7750: }
1.338 albertel 7751:
1.315 albertel 7752: if ($args->{'js_ready'}) {
1.713 kaisler 7753: $result = &js_ready($result);
1.315 albertel 7754: }
1.320 albertel 7755: if ($args->{'html_encode'}) {
1.713 kaisler 7756: $result = &html_encode($result);
7757: }
7758:
1.813 bisitz 7759: # Preparation for new and consistent functionlist at top of screen
7760: # if ($args->{'functionlist'}) {
7761: # $result .= &build_functionlist();
7762: #}
7763:
1.964 droeschl 7764: # Don't add anything more if only_body wanted or in const space
7765: return $result if $args->{'only_body'}
7766: || $env{'request.state'} eq 'construct';
1.813 bisitz 7767:
7768: #Breadcrumbs
1.758 kaisler 7769: if (exists($args->{'bread_crumbs'}) or exists($args->{'bread_crumbs_component'})) {
7770: &Apache::lonhtmlcommon::clear_breadcrumbs();
7771: #if any br links exists, add them to the breadcrumbs
7772: if (exists($args->{'bread_crumbs'}) and ref($args->{'bread_crumbs'}) eq 'ARRAY') {
7773: foreach my $crumb (@{$args->{'bread_crumbs'}}){
7774: &Apache::lonhtmlcommon::add_breadcrumb($crumb);
7775: }
7776: }
1.1075.2.19 raeburn 7777: # if @advtools array contains items add then to the breadcrumbs
7778: if (@advtools > 0) {
7779: &Apache::lonmenu::advtools_crumbs(@advtools);
7780: }
1.758 kaisler 7781:
7782: #if bread_crumbs_component exists show it as headline else show only the breadcrumbs
7783: if(exists($args->{'bread_crumbs_component'})){
7784: $result .= &Apache::lonhtmlcommon::breadcrumbs($args->{'bread_crumbs_component'});
7785: }else{
7786: $result .= &Apache::lonhtmlcommon::breadcrumbs();
7787: }
1.1075.2.24 raeburn 7788: } elsif (($env{'environment.remote'} eq 'on') &&
7789: ($env{'form.inhibitmenu'} ne 'yes') &&
7790: ($env{'request.noversionuri'} =~ m{^/res/}) &&
7791: ($env{'request.noversionuri'} !~ m{^/res/adm/pages/})) {
1.1075.2.21 raeburn 7792: $result .= '<div style="padding:0;margin:0;clear:both"><hr /></div>';
1.320 albertel 7793: }
1.315 albertel 7794: return $result;
1.306 albertel 7795: }
7796:
7797: sub end_page {
1.315 albertel 7798: my ($args) = @_;
7799: $env{'internal.end_page'}++;
1.330 albertel 7800: my $result;
1.335 albertel 7801: if ($args->{'discussion'}) {
7802: my ($target,$parser);
7803: if (ref($args->{'discussion'})) {
7804: ($target,$parser) =($args->{'discussion'}{'target'},
7805: $args->{'discussion'}{'parser'});
7806: }
7807: $result .= &Apache::lonxml::xmlend($target,$parser);
7808: }
1.330 albertel 7809: if ($args->{'frameset'}) {
7810: $result .= '</frameset>';
7811: } else {
1.635 raeburn 7812: $result .= &endbodytag($args);
1.330 albertel 7813: }
1.1075.2.6 raeburn 7814: unless ($args->{'notbody'}) {
7815: $result .= "\n</html>";
7816: }
1.330 albertel 7817:
1.315 albertel 7818: if ($args->{'js_ready'}) {
1.317 albertel 7819: $result = &js_ready($result);
1.315 albertel 7820: }
1.335 albertel 7821:
1.320 albertel 7822: if ($args->{'html_encode'}) {
7823: $result = &html_encode($result);
7824: }
1.335 albertel 7825:
1.315 albertel 7826: return $result;
7827: }
7828:
1.1034 www 7829: sub wishlist_window {
7830: return(<<'ENDWISHLIST');
1.1046 raeburn 7831: <script type="text/javascript">
1.1034 www 7832: // <![CDATA[
7833: // <!-- BEGIN LON-CAPA Internal
7834: function set_wishlistlink(title, path) {
7835: if (!title) {
7836: title = document.title;
7837: title = title.replace(/^LON-CAPA /,'');
7838: }
1.1075.2.65 raeburn 7839: title = encodeURIComponent(title);
1.1075.2.83 raeburn 7840: title = title.replace("'","\\\'");
1.1034 www 7841: if (!path) {
7842: path = location.pathname;
7843: }
1.1075.2.65 raeburn 7844: path = encodeURIComponent(path);
1.1075.2.83 raeburn 7845: path = path.replace("'","\\\'");
1.1034 www 7846: Win = window.open('/adm/wishlist?mode=newLink&setTitle='+title+'&setPath='+path,
7847: 'wishlistNewLink','width=560,height=350,scrollbars=0');
7848: }
7849: // END LON-CAPA Internal -->
7850: // ]]>
7851: </script>
7852: ENDWISHLIST
7853: }
7854:
1.1030 www 7855: sub modal_window {
7856: return(<<'ENDMODAL');
1.1046 raeburn 7857: <script type="text/javascript">
1.1030 www 7858: // <![CDATA[
7859: // <!-- BEGIN LON-CAPA Internal
7860: var modalWindow = {
7861: parent:"body",
7862: windowId:null,
7863: content:null,
7864: width:null,
7865: height:null,
7866: close:function()
7867: {
7868: $(".LCmodal-window").remove();
7869: $(".LCmodal-overlay").remove();
7870: },
7871: open:function()
7872: {
7873: var modal = "";
7874: modal += "<div class=\"LCmodal-overlay\"></div>";
7875: modal += "<div id=\"" + this.windowId + "\" class=\"LCmodal-window\" style=\"width:" + this.width + "px; height:" + this.height + "px; margin-top:-" + (this.height / 2) + "px; margin-left:-" + (this.width / 2) + "px;\">";
7876: modal += this.content;
7877: modal += "</div>";
7878:
7879: $(this.parent).append(modal);
7880:
7881: $(".LCmodal-window").append("<a class=\"LCclose-window\"></a>");
7882: $(".LCclose-window").click(function(){modalWindow.close();});
7883: $(".LCmodal-overlay").click(function(){modalWindow.close();});
7884: }
7885: };
1.1075.2.42 raeburn 7886: var openMyModal = function(source,width,height,scrolling,transparency,style)
1.1030 www 7887: {
1.1075.2.83 raeburn 7888: source = source.replace("'","'");
1.1030 www 7889: modalWindow.windowId = "myModal";
7890: modalWindow.width = width;
7891: modalWindow.height = height;
1.1075.2.80 raeburn 7892: modalWindow.content = "<iframe width='"+width+"' height='"+height+"' frameborder='0' scrolling='"+scrolling+"' allowtransparency='"+transparency+"' src='" + source + "' style='"+style+"'></iframe>";
1.1030 www 7893: modalWindow.open();
1.1075.2.87 raeburn 7894: };
1.1030 www 7895: // END LON-CAPA Internal -->
7896: // ]]>
7897: </script>
7898: ENDMODAL
7899: }
7900:
7901: sub modal_link {
1.1075.2.42 raeburn 7902: my ($link,$linktext,$width,$height,$target,$scrolling,$title,$transparency,$style)=@_;
1.1030 www 7903: unless ($width) { $width=480; }
7904: unless ($height) { $height=400; }
1.1031 www 7905: unless ($scrolling) { $scrolling='yes'; }
1.1075.2.42 raeburn 7906: unless ($transparency) { $transparency='true'; }
7907:
1.1074 raeburn 7908: my $target_attr;
7909: if (defined($target)) {
7910: $target_attr = 'target="'.$target.'"';
7911: }
7912: return <<"ENDLINK";
1.1075.2.42 raeburn 7913: <a href="$link" $target_attr title="$title" onclick="javascript:openMyModal('$link',$width,$height,'$scrolling','$transparency','$style'); return false;">
1.1074 raeburn 7914: $linktext</a>
7915: ENDLINK
1.1030 www 7916: }
7917:
1.1032 www 7918: sub modal_adhoc_script {
7919: my ($funcname,$width,$height,$content)=@_;
7920: return (<<ENDADHOC);
1.1046 raeburn 7921: <script type="text/javascript">
1.1032 www 7922: // <![CDATA[
7923: var $funcname = function()
7924: {
7925: modalWindow.windowId = "myModal";
7926: modalWindow.width = $width;
7927: modalWindow.height = $height;
7928: modalWindow.content = '$content';
7929: modalWindow.open();
7930: };
7931: // ]]>
7932: </script>
7933: ENDADHOC
7934: }
7935:
1.1041 www 7936: sub modal_adhoc_inner {
7937: my ($funcname,$width,$height,$content)=@_;
7938: my $innerwidth=$width-20;
7939: $content=&js_ready(
1.1042 www 7940: &start_page('Dialog',undef,{'only_body'=>1,'bgcolor'=>'#FFFFFF'}).
1.1075.2.42 raeburn 7941: &start_scrollbox($width.'px',$innerwidth.'px',$height.'px','myModal','#FFFFFF',undef,1).
7942: $content.
1.1041 www 7943: &end_scrollbox().
1.1075.2.42 raeburn 7944: &end_page()
1.1041 www 7945: );
7946: return &modal_adhoc_script($funcname,$width,$height,$content);
7947: }
7948:
7949: sub modal_adhoc_window {
7950: my ($funcname,$width,$height,$content,$linktext)=@_;
7951: return &modal_adhoc_inner($funcname,$width,$height,$content).
7952: "<a href=\"javascript:$funcname();void(0);\">".$linktext."</a>";
7953: }
7954:
7955: sub modal_adhoc_launch {
7956: my ($funcname,$width,$height,$content)=@_;
7957: return &modal_adhoc_inner($funcname,$width,$height,$content).(<<ENDLAUNCH);
7958: <script type="text/javascript">
7959: // <![CDATA[
7960: $funcname();
7961: // ]]>
7962: </script>
7963: ENDLAUNCH
7964: }
7965:
7966: sub modal_adhoc_close {
7967: return (<<ENDCLOSE);
7968: <script type="text/javascript">
7969: // <![CDATA[
7970: modalWindow.close();
7971: // ]]>
7972: </script>
7973: ENDCLOSE
7974: }
7975:
1.1038 www 7976: sub togglebox_script {
7977: return(<<ENDTOGGLE);
7978: <script type="text/javascript">
7979: // <![CDATA[
7980: function LCtoggleDisplay(id,hidetext,showtext) {
7981: link = document.getElementById(id + "link").childNodes[0];
7982: with (document.getElementById(id).style) {
7983: if (display == "none" ) {
7984: display = "inline";
7985: link.nodeValue = hidetext;
7986: } else {
7987: display = "none";
7988: link.nodeValue = showtext;
7989: }
7990: }
7991: }
7992: // ]]>
7993: </script>
7994: ENDTOGGLE
7995: }
7996:
1.1039 www 7997: sub start_togglebox {
7998: my ($id,$heading,$headerbg,$hidetext,$showtext)=@_;
7999: unless ($heading) { $heading=''; } else { $heading.=' '; }
8000: unless ($showtext) { $showtext=&mt('show'); }
8001: unless ($hidetext) { $hidetext=&mt('hide'); }
8002: unless ($headerbg) { $headerbg='#FFFFFF'; }
8003: return &start_data_table().
8004: &start_data_table_header_row().
8005: '<td bgcolor="'.$headerbg.'">'.$heading.
8006: '[<a id="'.$id.'link" href="javascript:LCtoggleDisplay(\''.$id.'\',\''.$hidetext.'\',\''.
8007: $showtext.'\')">'.$showtext.'</a>]</td>'.
8008: &end_data_table_header_row().
8009: '<tr id="'.$id.'" style="display:none""><td>';
8010: }
8011:
8012: sub end_togglebox {
8013: return '</td></tr>'.&end_data_table();
8014: }
8015:
1.1041 www 8016: sub LCprogressbar_script {
1.1045 www 8017: my ($id)=@_;
1.1041 www 8018: return(<<ENDPROGRESS);
8019: <script type="text/javascript">
8020: // <![CDATA[
1.1045 www 8021: \$('#progressbar$id').progressbar({
1.1041 www 8022: value: 0,
8023: change: function(event, ui) {
8024: var newVal = \$(this).progressbar('option', 'value');
8025: \$('.pblabel', this).text(LCprogressTxt);
8026: }
8027: });
8028: // ]]>
8029: </script>
8030: ENDPROGRESS
8031: }
8032:
8033: sub LCprogressbarUpdate_script {
8034: return(<<ENDPROGRESSUPDATE);
8035: <style type="text/css">
8036: .ui-progressbar { position:relative; }
8037: .pblabel { position: absolute; width: 100%; text-align: center; line-height: 1.9em; }
8038: </style>
8039: <script type="text/javascript">
8040: // <![CDATA[
1.1045 www 8041: var LCprogressTxt='---';
8042:
8043: function LCupdateProgress(percent,progresstext,id) {
1.1041 www 8044: LCprogressTxt=progresstext;
1.1045 www 8045: \$('#progressbar'+id).progressbar('value',percent);
1.1041 www 8046: }
8047: // ]]>
8048: </script>
8049: ENDPROGRESSUPDATE
8050: }
8051:
1.1042 www 8052: my $LClastpercent;
1.1045 www 8053: my $LCidcnt;
8054: my $LCcurrentid;
1.1042 www 8055:
1.1041 www 8056: sub LCprogressbar {
1.1042 www 8057: my ($r)=(@_);
8058: $LClastpercent=0;
1.1045 www 8059: $LCidcnt++;
8060: $LCcurrentid=$$.'_'.$LCidcnt;
1.1041 www 8061: my $starting=&mt('Starting');
8062: my $content=(<<ENDPROGBAR);
1.1045 www 8063: <div id="progressbar$LCcurrentid">
1.1041 www 8064: <span class="pblabel">$starting</span>
8065: </div>
8066: ENDPROGBAR
1.1045 www 8067: &r_print($r,$content.&LCprogressbar_script($LCcurrentid));
1.1041 www 8068: }
8069:
8070: sub LCprogressbarUpdate {
1.1042 www 8071: my ($r,$val,$text)=@_;
8072: unless ($val) {
8073: if ($LClastpercent) {
8074: $val=$LClastpercent;
8075: } else {
8076: $val=0;
8077: }
8078: }
1.1041 www 8079: if ($val<0) { $val=0; }
8080: if ($val>100) { $val=0; }
1.1042 www 8081: $LClastpercent=$val;
1.1041 www 8082: unless ($text) { $text=$val.'%'; }
8083: $text=&js_ready($text);
1.1044 www 8084: &r_print($r,<<ENDUPDATE);
1.1041 www 8085: <script type="text/javascript">
8086: // <![CDATA[
1.1045 www 8087: LCupdateProgress($val,'$text','$LCcurrentid');
1.1041 www 8088: // ]]>
8089: </script>
8090: ENDUPDATE
1.1035 www 8091: }
8092:
1.1042 www 8093: sub LCprogressbarClose {
8094: my ($r)=@_;
8095: $LClastpercent=0;
1.1044 www 8096: &r_print($r,<<ENDCLOSE);
1.1042 www 8097: <script type="text/javascript">
8098: // <![CDATA[
1.1045 www 8099: \$("#progressbar$LCcurrentid").hide('slow');
1.1042 www 8100: // ]]>
8101: </script>
8102: ENDCLOSE
1.1044 www 8103: }
8104:
8105: sub r_print {
8106: my ($r,$to_print)=@_;
8107: if ($r) {
8108: $r->print($to_print);
8109: $r->rflush();
8110: } else {
8111: print($to_print);
8112: }
1.1042 www 8113: }
8114:
1.320 albertel 8115: sub html_encode {
8116: my ($result) = @_;
8117:
1.322 albertel 8118: $result = &HTML::Entities::encode($result,'<>&"');
1.320 albertel 8119:
8120: return $result;
8121: }
1.1044 www 8122:
1.317 albertel 8123: sub js_ready {
8124: my ($result) = @_;
8125:
1.323 albertel 8126: $result =~ s/[\n\r]/ /xmsg;
8127: $result =~ s/\\/\\\\/xmsg;
8128: $result =~ s/'/\\'/xmsg;
1.372 albertel 8129: $result =~ s{</}{<\\/}xmsg;
1.317 albertel 8130:
8131: return $result;
8132: }
8133:
1.315 albertel 8134: sub validate_page {
8135: if ( exists($env{'internal.start_page'})
1.316 albertel 8136: && $env{'internal.start_page'} > 1) {
8137: &Apache::lonnet::logthis('start_page called multiple times '.
1.318 albertel 8138: $env{'internal.start_page'}.' '.
1.316 albertel 8139: $ENV{'request.filename'});
1.315 albertel 8140: }
8141: if ( exists($env{'internal.end_page'})
1.316 albertel 8142: && $env{'internal.end_page'} > 1) {
8143: &Apache::lonnet::logthis('end_page called multiple times '.
1.318 albertel 8144: $env{'internal.end_page'}.' '.
1.316 albertel 8145: $env{'request.filename'});
1.315 albertel 8146: }
8147: if ( exists($env{'internal.start_page'})
8148: && ! exists($env{'internal.end_page'})) {
1.316 albertel 8149: &Apache::lonnet::logthis('start_page called without end_page '.
8150: $env{'request.filename'});
1.315 albertel 8151: }
8152: if ( ! exists($env{'internal.start_page'})
8153: && exists($env{'internal.end_page'})) {
1.316 albertel 8154: &Apache::lonnet::logthis('end_page called without start_page'.
8155: $env{'request.filename'});
1.315 albertel 8156: }
1.306 albertel 8157: }
1.315 albertel 8158:
1.996 www 8159:
8160: sub start_scrollbox {
1.1075.2.56 raeburn 8161: my ($outerwidth,$width,$height,$id,$bgcolor,$cursor,$needjsready) = @_;
1.998 raeburn 8162: unless ($outerwidth) { $outerwidth='520px'; }
8163: unless ($width) { $width='500px'; }
8164: unless ($height) { $height='200px'; }
1.1075 raeburn 8165: my ($table_id,$div_id,$tdcol);
1.1018 raeburn 8166: if ($id ne '') {
1.1075.2.42 raeburn 8167: $table_id = ' id="table_'.$id.'"';
8168: $div_id = ' id="div_'.$id.'"';
1.1018 raeburn 8169: }
1.1075 raeburn 8170: if ($bgcolor ne '') {
8171: $tdcol = "background-color: $bgcolor;";
8172: }
1.1075.2.42 raeburn 8173: my $nicescroll_js;
8174: if ($env{'browser.mobile'}) {
8175: $nicescroll_js = &nicescroll_javascript('div_'.$id,$cursor,$needjsready);
8176: }
1.1075 raeburn 8177: return <<"END";
1.1075.2.42 raeburn 8178: $nicescroll_js
8179:
8180: <table style="width: $outerwidth; border: 1px solid none;"$table_id><tr><td style="width: $width;$tdcol">
1.1075.2.56 raeburn 8181: <div style="overflow:auto; width:$width; height:$height;"$div_id>
1.1075 raeburn 8182: END
1.996 www 8183: }
8184:
8185: sub end_scrollbox {
1.1036 www 8186: return '</div></td></tr></table>';
1.996 www 8187: }
8188:
1.1075.2.42 raeburn 8189: sub nicescroll_javascript {
8190: my ($id,$cursor,$needjsready,$framecheck,$location) = @_;
8191: my %options;
8192: if (ref($cursor) eq 'HASH') {
8193: %options = %{$cursor};
8194: }
8195: unless ($options{'railalign'} =~ /^left|right$/) {
8196: $options{'railalign'} = 'left';
8197: }
8198: unless ($options{'cursorcolor'} =~ /^\#\w+$/) {
8199: my $function = &get_users_function();
8200: $options{'cursorcolor'} = &designparm($function.'.sidebg',$env{'request.role.domain'});
8201: unless ($options{'cursorcolor'} =~ /^\#\w+$/) {
8202: $options{'cursorcolor'} = '#00F';
8203: }
8204: }
8205: if ($options{'cursoropacity'} =~ /^[\d.]+$/) {
8206: unless ($options{'cursoropacity'} >= 0.0 && $options{'cursoropacity'} <=1.0) {
8207: $options{'cursoropacity'}='1.0';
8208: }
8209: } else {
8210: $options{'cursoropacity'}='1.0';
8211: }
8212: if ($options{'cursorfixedheight'} eq 'none') {
8213: delete($options{'cursorfixedheight'});
8214: } else {
8215: unless ($options{'cursorfixedheight'} =~ /^\d+$/) { $options{'cursorfixedheight'}='50'; }
8216: }
8217: unless ($options{'railoffset'} =~ /^{[\w\:\d\-,]+}$/) {
8218: delete($options{'railoffset'});
8219: }
8220: my @niceoptions;
8221: while (my($key,$value) = each(%options)) {
8222: if ($value =~ /^\{.+\}$/) {
8223: push(@niceoptions,$key.':'.$value);
8224: } else {
8225: push(@niceoptions,$key.':"'.$value.'"');
8226: }
8227: }
8228: my $nicescroll_js = '
8229: $(document).ready(
8230: function() {
8231: $("#'.$id.'").niceScroll({'.join(',',@niceoptions).'});
8232: }
8233: );
8234: ';
8235: if ($framecheck) {
8236: $nicescroll_js .= '
8237: function expand_div(caller) {
8238: if (top === self) {
8239: document.getElementById("'.$id.'").style.width = "auto";
8240: document.getElementById("'.$id.'").style.height = "auto";
8241: } else {
8242: try {
8243: if (parent.frames) {
8244: if (parent.frames.length > 1) {
8245: var framesrc = parent.frames[1].location.href;
8246: var currsrc = framesrc.replace(/\#.*$/,"");
8247: if ((caller == "search") || (currsrc == "'.$location.'")) {
8248: document.getElementById("'.$id.'").style.width = "auto";
8249: document.getElementById("'.$id.'").style.height = "auto";
8250: }
8251: }
8252: }
8253: } catch (e) {
8254: return;
8255: }
8256: }
8257: return;
8258: }
8259: ';
8260: }
8261: if ($needjsready) {
8262: $nicescroll_js = '
8263: <script type="text/javascript">'."\n".$nicescroll_js."\n</script>\n";
8264: } else {
8265: $nicescroll_js = &Apache::lonhtmlcommon::scripttag($nicescroll_js);
8266: }
8267: return $nicescroll_js;
8268: }
8269:
1.318 albertel 8270: sub simple_error_page {
1.1075.2.49 raeburn 8271: my ($r,$title,$msg,$args) = @_;
8272: if (ref($args) eq 'HASH') {
8273: if (!$args->{'no_auto_mt_msg'}) { $msg = &mt($msg); }
8274: } else {
8275: $msg = &mt($msg);
8276: }
8277:
1.318 albertel 8278: my $page =
8279: &Apache::loncommon::start_page($title).
1.1075.2.49 raeburn 8280: '<p class="LC_error">'.$msg.'</p>'.
1.318 albertel 8281: &Apache::loncommon::end_page();
8282: if (ref($r)) {
8283: $r->print($page);
1.327 albertel 8284: return;
1.318 albertel 8285: }
8286: return $page;
8287: }
1.347 albertel 8288:
8289: {
1.610 albertel 8290: my @row_count;
1.961 onken 8291:
8292: sub start_data_table_count {
8293: unshift(@row_count, 0);
8294: return;
8295: }
8296:
8297: sub end_data_table_count {
8298: shift(@row_count);
8299: return;
8300: }
8301:
1.347 albertel 8302: sub start_data_table {
1.1018 raeburn 8303: my ($add_class,$id) = @_;
1.422 albertel 8304: my $css_class = (join(' ','LC_data_table',$add_class));
1.1018 raeburn 8305: my $table_id;
8306: if (defined($id)) {
8307: $table_id = ' id="'.$id.'"';
8308: }
1.961 onken 8309: &start_data_table_count();
1.1018 raeburn 8310: return '<table class="'.$css_class.'"'.$table_id.'>'."\n";
1.347 albertel 8311: }
8312:
8313: sub end_data_table {
1.961 onken 8314: &end_data_table_count();
1.389 albertel 8315: return '</table>'."\n";;
1.347 albertel 8316: }
8317:
8318: sub start_data_table_row {
1.974 wenzelju 8319: my ($add_class, $id) = @_;
1.610 albertel 8320: $row_count[0]++;
8321: my $css_class = ($row_count[0] % 2)?'LC_odd_row':'LC_even_row';
1.900 bisitz 8322: $css_class = (join(' ',$css_class,$add_class)) unless ($add_class eq '');
1.974 wenzelju 8323: $id = (' id="'.$id.'"') unless ($id eq '');
8324: return '<tr class="'.$css_class.'"'.$id.'>'."\n";
1.347 albertel 8325: }
1.471 banghart 8326:
8327: sub continue_data_table_row {
1.974 wenzelju 8328: my ($add_class, $id) = @_;
1.610 albertel 8329: my $css_class = ($row_count[0] % 2)?'LC_odd_row':'LC_even_row';
1.974 wenzelju 8330: $css_class = (join(' ',$css_class,$add_class)) unless ($add_class eq '');
8331: $id = (' id="'.$id.'"') unless ($id eq '');
8332: return '<tr class="'.$css_class.'"'.$id.'>'."\n";
1.471 banghart 8333: }
1.347 albertel 8334:
8335: sub end_data_table_row {
1.389 albertel 8336: return '</tr>'."\n";;
1.347 albertel 8337: }
1.367 www 8338:
1.421 albertel 8339: sub start_data_table_empty_row {
1.707 bisitz 8340: # $row_count[0]++;
1.421 albertel 8341: return '<tr class="LC_empty_row" >'."\n";;
8342: }
8343:
8344: sub end_data_table_empty_row {
8345: return '</tr>'."\n";;
8346: }
8347:
1.367 www 8348: sub start_data_table_header_row {
1.389 albertel 8349: return '<tr class="LC_header_row">'."\n";;
1.367 www 8350: }
8351:
8352: sub end_data_table_header_row {
1.389 albertel 8353: return '</tr>'."\n";;
1.367 www 8354: }
1.890 droeschl 8355:
8356: sub data_table_caption {
8357: my $caption = shift;
8358: return "<caption class=\"LC_caption\">$caption</caption>";
8359: }
1.347 albertel 8360: }
8361:
1.548 albertel 8362: =pod
8363:
8364: =item * &inhibit_menu_check($arg)
8365:
8366: Checks for a inhibitmenu state and generates output to preserve it
8367:
8368: Inputs: $arg - can be any of
8369: - undef - in which case the return value is a string
8370: to add into arguments list of a uri
8371: - 'input' - in which case the return value is a HTML
8372: <form> <input> field of type hidden to
8373: preserve the value
8374: - a url - in which case the return value is the url with
8375: the neccesary cgi args added to preserve the
8376: inhibitmenu state
8377: - a ref to a url - no return value, but the string is
8378: updated to include the neccessary cgi
8379: args to preserve the inhibitmenu state
8380:
8381: =cut
8382:
8383: sub inhibit_menu_check {
8384: my ($arg) = @_;
8385: &get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['inhibitmenu']);
8386: if ($arg eq 'input') {
8387: if ($env{'form.inhibitmenu'}) {
8388: return '<input type="hidden" name="inhibitmenu" value="'.$env{'form.inhibitmenu'}.'" />';
8389: } else {
8390: return
8391: }
8392: }
8393: if ($env{'form.inhibitmenu'}) {
8394: if (ref($arg)) {
8395: $$arg .= '?inhibitmenu='.$env{'form.inhibitmenu'};
8396: } elsif ($arg eq '') {
8397: $arg .= 'inhibitmenu='.$env{'form.inhibitmenu'};
8398: } else {
8399: $arg .= '?inhibitmenu='.$env{'form.inhibitmenu'};
8400: }
8401: }
8402: if (!ref($arg)) {
8403: return $arg;
8404: }
8405: }
8406:
1.251 albertel 8407: ###############################################
1.182 matthew 8408:
8409: =pod
8410:
1.549 albertel 8411: =back
8412:
8413: =head1 User Information Routines
8414:
8415: =over 4
8416:
1.405 albertel 8417: =item * &get_users_function()
1.182 matthew 8418:
8419: Used by &bodytag to determine the current users primary role.
8420: Returns either 'student','coordinator','admin', or 'author'.
8421:
8422: =cut
8423:
8424: ###############################################
8425: sub get_users_function {
1.815 tempelho 8426: my $function = 'norole';
1.818 tempelho 8427: if ($env{'request.role'}=~/^(st)/) {
8428: $function='student';
8429: }
1.907 raeburn 8430: if ($env{'request.role'}=~/^(cc|co|in|ta|ep)/) {
1.182 matthew 8431: $function='coordinator';
8432: }
1.258 albertel 8433: if ($env{'request.role'}=~/^(su|dc|ad|li)/) {
1.182 matthew 8434: $function='admin';
8435: }
1.826 bisitz 8436: if (($env{'request.role'}=~/^(au|ca|aa)/) ||
1.1025 raeburn 8437: ($ENV{'REQUEST_URI'}=~ m{/^(/priv)})) {
1.182 matthew 8438: $function='author';
8439: }
8440: return $function;
1.54 www 8441: }
1.99 www 8442:
8443: ###############################################
8444:
1.233 raeburn 8445: =pod
8446:
1.821 raeburn 8447: =item * &show_course()
8448:
8449: Used by lonmenu.pm and lonroles.pm to determine whether to use the word
8450: 'Courses' or 'Roles' in inline navigation and on screen displaying user's roles.
8451:
8452: Inputs:
8453: None
8454:
8455: Outputs:
8456: Scalar: 1 if 'Course' to be used, 0 otherwise.
8457:
8458: =cut
8459:
8460: ###############################################
8461: sub show_course {
8462: my $course = !$env{'user.adv'};
8463: if (!$env{'user.adv'}) {
8464: foreach my $env (keys(%env)) {
8465: next if ($env !~ m/^user\.priv\./);
8466: if ($env !~ m/^user\.priv\.(?:st|cm)/) {
8467: $course = 0;
8468: last;
8469: }
8470: }
8471: }
8472: return $course;
8473: }
8474:
8475: ###############################################
8476:
8477: =pod
8478:
1.542 raeburn 8479: =item * &check_user_status()
1.274 raeburn 8480:
8481: Determines current status of supplied role for a
8482: specific user. Roles can be active, previous or future.
8483:
8484: Inputs:
8485: user's domain, user's username, course's domain,
1.375 raeburn 8486: course's number, optional section ID.
1.274 raeburn 8487:
8488: Outputs:
8489: role status: active, previous or future.
8490:
8491: =cut
8492:
8493: sub check_user_status {
1.412 raeburn 8494: my ($udom,$uname,$cdom,$crs,$role,$sec) = @_;
1.1073 raeburn 8495: my %userinfo = &Apache::lonnet::dump('roles',$udom,$uname);
1.1075.2.85 raeburn 8496: my @uroles = keys(%userinfo);
1.274 raeburn 8497: my $srchstr;
8498: my $active_chk = 'none';
1.412 raeburn 8499: my $now = time;
1.274 raeburn 8500: if (@uroles > 0) {
1.908 raeburn 8501: if (($role eq 'cc') || ($role eq 'co') || ($sec eq '') || (!defined($sec))) {
1.274 raeburn 8502: $srchstr = '/'.$cdom.'/'.$crs.'_'.$role;
8503: } else {
1.412 raeburn 8504: $srchstr = '/'.$cdom.'/'.$crs.'/'.$sec.'_'.$role;
8505: }
8506: if (grep/^\Q$srchstr\E$/,@uroles) {
1.274 raeburn 8507: my $role_end = 0;
8508: my $role_start = 0;
8509: $active_chk = 'active';
1.412 raeburn 8510: if ($userinfo{$srchstr} =~ m/^\Q$role\E_(\d+)/) {
8511: $role_end = $1;
8512: if ($userinfo{$srchstr} =~ m/^\Q$role\E_\Q$role_end\E_(\d+)$/) {
8513: $role_start = $1;
1.274 raeburn 8514: }
8515: }
8516: if ($role_start > 0) {
1.412 raeburn 8517: if ($now < $role_start) {
1.274 raeburn 8518: $active_chk = 'future';
8519: }
8520: }
8521: if ($role_end > 0) {
1.412 raeburn 8522: if ($now > $role_end) {
1.274 raeburn 8523: $active_chk = 'previous';
8524: }
8525: }
8526: }
8527: }
8528: return $active_chk;
8529: }
8530:
8531: ###############################################
8532:
8533: =pod
8534:
1.405 albertel 8535: =item * &get_sections()
1.233 raeburn 8536:
8537: Determines all the sections for a course including
8538: sections with students and sections containing other roles.
1.419 raeburn 8539: Incoming parameters:
8540:
8541: 1. domain
8542: 2. course number
8543: 3. reference to array containing roles for which sections should
8544: be gathered (optional).
8545: 4. reference to array containing status types for which sections
8546: should be gathered (optional).
8547:
8548: If the third argument is undefined, sections are gathered for any role.
8549: If the fourth argument is undefined, sections are gathered for any status.
8550: Permissible values are 'active' or 'future' or 'previous'.
1.233 raeburn 8551:
1.374 raeburn 8552: Returns section hash (keys are section IDs, values are
8553: number of users in each section), subject to the
1.419 raeburn 8554: optional roles filter, optional status filter
1.233 raeburn 8555:
8556: =cut
8557:
8558: ###############################################
8559: sub get_sections {
1.419 raeburn 8560: my ($cdom,$cnum,$possible_roles,$possible_status) = @_;
1.366 albertel 8561: if (!defined($cdom) || !defined($cnum)) {
8562: my $cid = $env{'request.course.id'};
8563:
8564: return if (!defined($cid));
8565:
8566: $cdom = $env{'course.'.$cid.'.domain'};
8567: $cnum = $env{'course.'.$cid.'.num'};
8568: }
8569:
8570: my %sectioncount;
1.419 raeburn 8571: my $now = time;
1.240 albertel 8572:
1.1075.2.33 raeburn 8573: my $check_students = 1;
8574: my $only_students = 0;
8575: if (ref($possible_roles) eq 'ARRAY') {
8576: if (grep(/^st$/,@{$possible_roles})) {
8577: if (@{$possible_roles} == 1) {
8578: $only_students = 1;
8579: }
8580: } else {
8581: $check_students = 0;
8582: }
8583: }
8584:
8585: if ($check_students) {
1.276 albertel 8586: my ($classlist) = &Apache::loncoursedata::get_classlist($cdom,$cnum);
1.240 albertel 8587: my $sec_index = &Apache::loncoursedata::CL_SECTION();
8588: my $status_index = &Apache::loncoursedata::CL_STATUS();
1.419 raeburn 8589: my $start_index = &Apache::loncoursedata::CL_START();
8590: my $end_index = &Apache::loncoursedata::CL_END();
8591: my $status;
1.366 albertel 8592: while (my ($student,$data) = each(%$classlist)) {
1.419 raeburn 8593: my ($section,$stu_status,$start,$end) = ($data->[$sec_index],
8594: $data->[$status_index],
8595: $data->[$start_index],
8596: $data->[$end_index]);
8597: if ($stu_status eq 'Active') {
8598: $status = 'active';
8599: } elsif ($end < $now) {
8600: $status = 'previous';
8601: } elsif ($start > $now) {
8602: $status = 'future';
8603: }
8604: if ($section ne '-1' && $section !~ /^\s*$/) {
8605: if ((!defined($possible_status)) || (($status ne '') &&
8606: (grep/^\Q$status\E$/,@{$possible_status}))) {
8607: $sectioncount{$section}++;
8608: }
1.240 albertel 8609: }
8610: }
8611: }
1.1075.2.33 raeburn 8612: if ($only_students) {
8613: return %sectioncount;
8614: }
1.240 albertel 8615: my %courseroles = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
8616: foreach my $user (sort(keys(%courseroles))) {
8617: if ($user !~ /^(\w{2})/) { next; }
8618: my ($role) = ($user =~ /^(\w{2})/);
8619: if ($possible_roles && !(grep(/^$role$/,@$possible_roles))) { next; }
1.419 raeburn 8620: my ($section,$status);
1.240 albertel 8621: if ($role eq 'cr' &&
8622: $user =~ m-^$role/[^/]*/[^/]*/[^/]*:[^:]*:[^:]*:(\w+)-) {
8623: $section=$1;
8624: }
8625: if ($user =~ /^$role:[^:]*:[^:]*:(\w+)/) { $section=$1; }
8626: if (!defined($section) || $section eq '-1') { next; }
1.419 raeburn 8627: my ($end,$start) = ($courseroles{$user} =~ /^([^:]*):([^:]*)$/);
8628: if ($end == -1 && $start == -1) {
8629: next; #deleted role
8630: }
8631: if (!defined($possible_status)) {
8632: $sectioncount{$section}++;
8633: } else {
8634: if ((!$end || $end >= $now) && (!$start || $start <= $now)) {
8635: $status = 'active';
8636: } elsif ($end < $now) {
8637: $status = 'future';
8638: } elsif ($start > $now) {
8639: $status = 'previous';
8640: }
8641: if (($status ne '') && (grep/^\Q$status\E$/,@{$possible_status})) {
8642: $sectioncount{$section}++;
8643: }
8644: }
1.233 raeburn 8645: }
1.366 albertel 8646: return %sectioncount;
1.233 raeburn 8647: }
8648:
1.274 raeburn 8649: ###############################################
1.294 raeburn 8650:
8651: =pod
1.405 albertel 8652:
8653: =item * &get_course_users()
8654:
1.275 raeburn 8655: Retrieves usernames:domains for users in the specified course
8656: with specific role(s), and access status.
8657:
8658: Incoming parameters:
1.277 albertel 8659: 1. course domain
8660: 2. course number
8661: 3. access status: users must have - either active,
1.275 raeburn 8662: previous, future, or all.
1.277 albertel 8663: 4. reference to array of permissible roles
1.288 raeburn 8664: 5. reference to array of section restrictions (optional)
8665: 6. reference to results object (hash of hashes).
8666: 7. reference to optional userdata hash
1.609 raeburn 8667: 8. reference to optional statushash
1.630 raeburn 8668: 9. flag if privileged users (except those set to unhide in
8669: course settings) should be excluded
1.609 raeburn 8670: Keys of top level results hash are roles.
1.275 raeburn 8671: Keys of inner hashes are username:domain, with
8672: values set to access type.
1.288 raeburn 8673: Optional userdata hash returns an array with arguments in the
8674: same order as loncoursedata::get_classlist() for student data.
8675:
1.609 raeburn 8676: Optional statushash returns
8677:
1.288 raeburn 8678: Entries for end, start, section and status are blank because
8679: of the possibility of multiple values for non-student roles.
8680:
1.275 raeburn 8681: =cut
1.405 albertel 8682:
1.275 raeburn 8683: ###############################################
1.405 albertel 8684:
1.275 raeburn 8685: sub get_course_users {
1.630 raeburn 8686: my ($cdom,$cnum,$types,$roles,$sections,$users,$userdata,$statushash,$hidepriv) = @_;
1.288 raeburn 8687: my %idx = ();
1.419 raeburn 8688: my %seclists;
1.288 raeburn 8689:
8690: $idx{udom} = &Apache::loncoursedata::CL_SDOM();
8691: $idx{uname} = &Apache::loncoursedata::CL_SNAME();
8692: $idx{end} = &Apache::loncoursedata::CL_END();
8693: $idx{start} = &Apache::loncoursedata::CL_START();
8694: $idx{id} = &Apache::loncoursedata::CL_ID();
8695: $idx{section} = &Apache::loncoursedata::CL_SECTION();
8696: $idx{fullname} = &Apache::loncoursedata::CL_FULLNAME();
8697: $idx{status} = &Apache::loncoursedata::CL_STATUS();
8698:
1.290 albertel 8699: if (grep(/^st$/,@{$roles})) {
1.276 albertel 8700: my ($classlist,$keylist)=&Apache::loncoursedata::get_classlist($cdom,$cnum);
1.278 raeburn 8701: my $now = time;
1.277 albertel 8702: foreach my $student (keys(%{$classlist})) {
1.288 raeburn 8703: my $match = 0;
1.412 raeburn 8704: my $secmatch = 0;
1.419 raeburn 8705: my $section = $$classlist{$student}[$idx{section}];
1.609 raeburn 8706: my $status = $$classlist{$student}[$idx{status}];
1.419 raeburn 8707: if ($section eq '') {
8708: $section = 'none';
8709: }
1.291 albertel 8710: if ((ref($sections) eq 'ARRAY') && (@{$sections} > 0)) {
1.420 albertel 8711: if (grep(/^all$/,@{$sections})) {
1.412 raeburn 8712: $secmatch = 1;
8713: } elsif ($$classlist{$student}[$idx{section}] eq '') {
1.420 albertel 8714: if (grep(/^none$/,@{$sections})) {
1.412 raeburn 8715: $secmatch = 1;
8716: }
8717: } else {
1.419 raeburn 8718: if (grep(/^\Q$section\E$/,@{$sections})) {
1.412 raeburn 8719: $secmatch = 1;
8720: }
1.290 albertel 8721: }
1.412 raeburn 8722: if (!$secmatch) {
8723: next;
8724: }
1.419 raeburn 8725: }
1.275 raeburn 8726: if (defined($$types{'active'})) {
1.288 raeburn 8727: if ($$classlist{$student}[$idx{status}] eq 'Active') {
1.275 raeburn 8728: push(@{$$users{st}{$student}},'active');
1.288 raeburn 8729: $match = 1;
1.275 raeburn 8730: }
8731: }
8732: if (defined($$types{'previous'})) {
1.609 raeburn 8733: if ($$classlist{$student}[$idx{status}] eq 'Expired') {
1.275 raeburn 8734: push(@{$$users{st}{$student}},'previous');
1.288 raeburn 8735: $match = 1;
1.275 raeburn 8736: }
8737: }
8738: if (defined($$types{'future'})) {
1.609 raeburn 8739: if ($$classlist{$student}[$idx{status}] eq 'Future') {
1.275 raeburn 8740: push(@{$$users{st}{$student}},'future');
1.288 raeburn 8741: $match = 1;
1.275 raeburn 8742: }
8743: }
1.609 raeburn 8744: if ($match) {
8745: push(@{$seclists{$student}},$section);
8746: if (ref($userdata) eq 'HASH') {
8747: $$userdata{$student} = $$classlist{$student};
8748: }
8749: if (ref($statushash) eq 'HASH') {
8750: $statushash->{$student}{'st'}{$section} = $status;
8751: }
1.288 raeburn 8752: }
1.275 raeburn 8753: }
8754: }
1.412 raeburn 8755: if ((@{$roles} > 1) || ((@{$roles} == 1) && ($$roles[0] ne "st"))) {
1.439 raeburn 8756: my %coursepersonnel = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
8757: my $now = time;
1.609 raeburn 8758: my %displaystatus = ( previous => 'Expired',
8759: active => 'Active',
8760: future => 'Future',
8761: );
1.1075.2.36 raeburn 8762: my (%nothide,@possdoms);
1.630 raeburn 8763: if ($hidepriv) {
8764: my %coursehash=&Apache::lonnet::coursedescription($cdom.'_'.$cnum);
8765: foreach my $user (split(/\s*\,\s*/,$coursehash{'nothideprivileged'})) {
8766: if ($user !~ /:/) {
8767: $nothide{join(':',split(/[\@]/,$user))}=1;
8768: } else {
8769: $nothide{$user} = 1;
8770: }
8771: }
1.1075.2.36 raeburn 8772: my @possdoms = ($cdom);
8773: if ($coursehash{'checkforpriv'}) {
8774: push(@possdoms,split(/,/,$coursehash{'checkforpriv'}));
8775: }
1.630 raeburn 8776: }
1.439 raeburn 8777: foreach my $person (sort(keys(%coursepersonnel))) {
1.288 raeburn 8778: my $match = 0;
1.412 raeburn 8779: my $secmatch = 0;
1.439 raeburn 8780: my $status;
1.412 raeburn 8781: my ($role,$user,$usec) = ($person =~ /^([^:]*):([^:]+:[^:]+):([^:]*)/);
1.275 raeburn 8782: $user =~ s/:$//;
1.439 raeburn 8783: my ($end,$start) = split(/:/,$coursepersonnel{$person});
8784: if ($end == -1 || $start == -1) {
8785: next;
8786: }
8787: if (($role) && ((grep(/^\Q$role\E$/,@{$roles})) ||
8788: (grep(/^cr$/,@{$roles}) && $role =~ /^cr\//))) {
1.412 raeburn 8789: my ($uname,$udom) = split(/:/,$user);
8790: if ((ref($sections) eq 'ARRAY') && (@{$sections} > 0)) {
1.420 albertel 8791: if (grep(/^all$/,@{$sections})) {
1.412 raeburn 8792: $secmatch = 1;
8793: } elsif ($usec eq '') {
1.420 albertel 8794: if (grep(/^none$/,@{$sections})) {
1.412 raeburn 8795: $secmatch = 1;
8796: }
8797: } else {
8798: if (grep(/^\Q$usec\E$/,@{$sections})) {
8799: $secmatch = 1;
8800: }
8801: }
8802: if (!$secmatch) {
8803: next;
8804: }
1.288 raeburn 8805: }
1.419 raeburn 8806: if ($usec eq '') {
8807: $usec = 'none';
8808: }
1.275 raeburn 8809: if ($uname ne '' && $udom ne '') {
1.630 raeburn 8810: if ($hidepriv) {
1.1075.2.36 raeburn 8811: if ((&Apache::lonnet::privileged($uname,$udom,\@possdoms)) &&
1.630 raeburn 8812: (!$nothide{$uname.':'.$udom})) {
8813: next;
8814: }
8815: }
1.503 raeburn 8816: if ($end > 0 && $end < $now) {
1.439 raeburn 8817: $status = 'previous';
8818: } elsif ($start > $now) {
8819: $status = 'future';
8820: } else {
8821: $status = 'active';
8822: }
1.277 albertel 8823: foreach my $type (keys(%{$types})) {
1.275 raeburn 8824: if ($status eq $type) {
1.420 albertel 8825: if (!grep(/^\Q$type\E$/,@{$$users{$role}{$user}})) {
1.419 raeburn 8826: push(@{$$users{$role}{$user}},$type);
8827: }
1.288 raeburn 8828: $match = 1;
8829: }
8830: }
1.419 raeburn 8831: if (($match) && (ref($userdata) eq 'HASH')) {
8832: if (!exists($$userdata{$uname.':'.$udom})) {
8833: &get_user_info($udom,$uname,\%idx,$userdata);
8834: }
1.420 albertel 8835: if (!grep(/^\Q$usec\E$/,@{$seclists{$uname.':'.$udom}})) {
1.419 raeburn 8836: push(@{$seclists{$uname.':'.$udom}},$usec);
8837: }
1.609 raeburn 8838: if (ref($statushash) eq 'HASH') {
8839: $statushash->{$uname.':'.$udom}{$role}{$usec} = $displaystatus{$status};
8840: }
1.275 raeburn 8841: }
8842: }
8843: }
8844: }
1.290 albertel 8845: if (grep(/^ow$/,@{$roles})) {
1.279 raeburn 8846: if ((defined($cdom)) && (defined($cnum))) {
8847: my %csettings = &Apache::lonnet::get('environment',['internal.courseowner'],$cdom,$cnum);
8848: if ( defined($csettings{'internal.courseowner'}) ) {
8849: my $owner = $csettings{'internal.courseowner'};
1.609 raeburn 8850: next if ($owner eq '');
8851: my ($ownername,$ownerdom);
8852: if ($owner =~ /^([^:]+):([^:]+)$/) {
8853: $ownername = $1;
8854: $ownerdom = $2;
8855: } else {
8856: $ownername = $owner;
8857: $ownerdom = $cdom;
8858: $owner = $ownername.':'.$ownerdom;
1.439 raeburn 8859: }
8860: @{$$users{'ow'}{$owner}} = 'any';
1.290 albertel 8861: if (defined($userdata) &&
1.609 raeburn 8862: !exists($$userdata{$owner})) {
8863: &get_user_info($ownerdom,$ownername,\%idx,$userdata);
8864: if (!grep(/^none$/,@{$seclists{$owner}})) {
8865: push(@{$seclists{$owner}},'none');
8866: }
8867: if (ref($statushash) eq 'HASH') {
8868: $statushash->{$owner}{'ow'}{'none'} = 'Any';
1.419 raeburn 8869: }
1.290 albertel 8870: }
1.279 raeburn 8871: }
8872: }
8873: }
1.419 raeburn 8874: foreach my $user (keys(%seclists)) {
8875: @{$seclists{$user}} = (sort {$a <=> $b} @{$seclists{$user}});
8876: $$userdata{$user}[$idx{section}] = join(',',@{$seclists{$user}});
8877: }
1.275 raeburn 8878: }
8879: return;
8880: }
8881:
1.288 raeburn 8882: sub get_user_info {
8883: my ($udom,$uname,$idx,$userdata) = @_;
1.289 albertel 8884: $$userdata{$uname.':'.$udom}[$$idx{fullname}] =
8885: &plainname($uname,$udom,'lastname');
1.291 albertel 8886: $$userdata{$uname.':'.$udom}[$$idx{uname}] = $uname;
1.297 raeburn 8887: $$userdata{$uname.':'.$udom}[$$idx{udom}] = $udom;
1.609 raeburn 8888: my %idhash = &Apache::lonnet::idrget($udom,($uname));
8889: $$userdata{$uname.':'.$udom}[$$idx{id}] = $idhash{$uname};
1.288 raeburn 8890: return;
8891: }
1.275 raeburn 8892:
1.472 raeburn 8893: ###############################################
8894:
8895: =pod
8896:
8897: =item * &get_user_quota()
8898:
1.1075.2.41 raeburn 8899: Retrieves quota assigned for storage of user files.
8900: Default is to report quota for portfolio files.
1.472 raeburn 8901:
8902: Incoming parameters:
8903: 1. user's username
8904: 2. user's domain
1.1075.2.41 raeburn 8905: 3. quota name - portfolio, author, or course
8906: (if no quota name provided, defaults to portfolio).
1.1075.2.59 raeburn 8907: 4. crstype - official, unofficial, textbook or community, if quota name is
1.1075.2.42 raeburn 8908: course
1.472 raeburn 8909:
8910: Returns:
1.1075.2.58 raeburn 8911: 1. Disk quota (in MB) assigned to student.
1.536 raeburn 8912: 2. (Optional) Type of setting: custom or default
8913: (individually assigned or default for user's
8914: institutional status).
8915: 3. (Optional) - User's institutional status (e.g., faculty, staff
8916: or student - types as defined in localenroll::inst_usertypes
8917: for user's domain, which determines default quota for user.
8918: 4. (Optional) - Default quota which would apply to the user.
1.472 raeburn 8919:
8920: If a value has been stored in the user's environment,
1.536 raeburn 8921: it will return that, otherwise it returns the maximal default
1.1075.2.41 raeburn 8922: defined for the user's institutional status(es) in the domain.
1.472 raeburn 8923:
8924: =cut
8925:
8926: ###############################################
8927:
8928:
8929: sub get_user_quota {
1.1075.2.42 raeburn 8930: my ($uname,$udom,$quotaname,$crstype) = @_;
1.536 raeburn 8931: my ($quota,$quotatype,$settingstatus,$defquota);
1.472 raeburn 8932: if (!defined($udom)) {
8933: $udom = $env{'user.domain'};
8934: }
8935: if (!defined($uname)) {
8936: $uname = $env{'user.name'};
8937: }
8938: if (($udom eq '' || $uname eq '') ||
8939: ($udom eq 'public') && ($uname eq 'public')) {
8940: $quota = 0;
1.536 raeburn 8941: $quotatype = 'default';
8942: $defquota = 0;
1.472 raeburn 8943: } else {
1.536 raeburn 8944: my $inststatus;
1.1075.2.41 raeburn 8945: if ($quotaname eq 'course') {
8946: if (($env{'course.'.$udom.'_'.$uname.'.num'} eq $uname) &&
8947: ($env{'course.'.$udom.'_'.$uname.'.domain'} eq $udom)) {
8948: $quota = $env{'course.'.$udom.'_'.$uname.'.internal.uploadquota'};
8949: } else {
8950: my %cenv = &Apache::lonnet::coursedescription("$udom/$uname");
8951: $quota = $cenv{'internal.uploadquota'};
8952: }
1.536 raeburn 8953: } else {
1.1075.2.41 raeburn 8954: if ($udom eq $env{'user.domain'} && $uname eq $env{'user.name'}) {
8955: if ($quotaname eq 'author') {
8956: $quota = $env{'environment.authorquota'};
8957: } else {
8958: $quota = $env{'environment.portfolioquota'};
8959: }
8960: $inststatus = $env{'environment.inststatus'};
8961: } else {
8962: my %userenv =
8963: &Apache::lonnet::get('environment',['portfolioquota',
8964: 'authorquota','inststatus'],$udom,$uname);
8965: my ($tmp) = keys(%userenv);
8966: if ($tmp !~ /^(con_lost|error|no_such_host)/i) {
8967: if ($quotaname eq 'author') {
8968: $quota = $userenv{'authorquota'};
8969: } else {
8970: $quota = $userenv{'portfolioquota'};
8971: }
8972: $inststatus = $userenv{'inststatus'};
8973: } else {
8974: undef(%userenv);
8975: }
8976: }
8977: }
8978: if ($quota eq '' || wantarray) {
8979: if ($quotaname eq 'course') {
8980: my %domdefs = &Apache::lonnet::get_domain_defaults($udom);
1.1075.2.59 raeburn 8981: if (($crstype eq 'official') || ($crstype eq 'unofficial') ||
8982: ($crstype eq 'community') || ($crstype eq 'textbook')) {
1.1075.2.42 raeburn 8983: $defquota = $domdefs{$crstype.'quota'};
8984: }
8985: if ($defquota eq '') {
8986: $defquota = 500;
8987: }
1.1075.2.41 raeburn 8988: } else {
8989: ($defquota,$settingstatus) = &default_quota($udom,$inststatus,$quotaname);
8990: }
8991: if ($quota eq '') {
8992: $quota = $defquota;
8993: $quotatype = 'default';
8994: } else {
8995: $quotatype = 'custom';
8996: }
1.472 raeburn 8997: }
8998: }
1.536 raeburn 8999: if (wantarray) {
9000: return ($quota,$quotatype,$settingstatus,$defquota);
9001: } else {
9002: return $quota;
9003: }
1.472 raeburn 9004: }
9005:
9006: ###############################################
9007:
9008: =pod
9009:
9010: =item * &default_quota()
9011:
1.536 raeburn 9012: Retrieves default quota assigned for storage of user portfolio files,
9013: given an (optional) user's institutional status.
1.472 raeburn 9014:
9015: Incoming parameters:
1.1075.2.42 raeburn 9016:
1.472 raeburn 9017: 1. domain
1.536 raeburn 9018: 2. (Optional) institutional status(es). This is a : separated list of
9019: status types (e.g., faculty, staff, student etc.)
9020: which apply to the user for whom the default is being retrieved.
9021: If the institutional status string in undefined, the domain
1.1075.2.41 raeburn 9022: default quota will be returned.
9023: 3. quota name - portfolio, author, or course
9024: (if no quota name provided, defaults to portfolio).
1.472 raeburn 9025:
9026: Returns:
1.1075.2.42 raeburn 9027:
1.1075.2.58 raeburn 9028: 1. Default disk quota (in MB) for user portfolios in the domain.
1.536 raeburn 9029: 2. (Optional) institutional type which determined the value of the
9030: default quota.
1.472 raeburn 9031:
9032: If a value has been stored in the domain's configuration db,
9033: it will return that, otherwise it returns 20 (for backwards
9034: compatibility with domains which have not set up a configuration
1.1075.2.58 raeburn 9035: db file; the original statically defined portfolio quota was 20 MB).
1.472 raeburn 9036:
1.536 raeburn 9037: If the user's status includes multiple types (e.g., staff and student),
9038: the largest default quota which applies to the user determines the
9039: default quota returned.
9040:
1.472 raeburn 9041: =cut
9042:
9043: ###############################################
9044:
9045:
9046: sub default_quota {
1.1075.2.41 raeburn 9047: my ($udom,$inststatus,$quotaname) = @_;
1.536 raeburn 9048: my ($defquota,$settingstatus);
9049: my %quotahash = &Apache::lonnet::get_dom('configuration',
1.622 raeburn 9050: ['quotas'],$udom);
1.1075.2.41 raeburn 9051: my $key = 'defaultquota';
9052: if ($quotaname eq 'author') {
9053: $key = 'authorquota';
9054: }
1.622 raeburn 9055: if (ref($quotahash{'quotas'}) eq 'HASH') {
1.536 raeburn 9056: if ($inststatus ne '') {
1.765 raeburn 9057: my @statuses = map { &unescape($_); } split(/:/,$inststatus);
1.536 raeburn 9058: foreach my $item (@statuses) {
1.1075.2.41 raeburn 9059: if (ref($quotahash{'quotas'}{$key}) eq 'HASH') {
9060: if ($quotahash{'quotas'}{$key}{$item} ne '') {
1.711 raeburn 9061: if ($defquota eq '') {
1.1075.2.41 raeburn 9062: $defquota = $quotahash{'quotas'}{$key}{$item};
1.711 raeburn 9063: $settingstatus = $item;
1.1075.2.41 raeburn 9064: } elsif ($quotahash{'quotas'}{$key}{$item} > $defquota) {
9065: $defquota = $quotahash{'quotas'}{$key}{$item};
1.711 raeburn 9066: $settingstatus = $item;
9067: }
9068: }
1.1075.2.41 raeburn 9069: } elsif ($key eq 'defaultquota') {
1.711 raeburn 9070: if ($quotahash{'quotas'}{$item} ne '') {
9071: if ($defquota eq '') {
9072: $defquota = $quotahash{'quotas'}{$item};
9073: $settingstatus = $item;
9074: } elsif ($quotahash{'quotas'}{$item} > $defquota) {
9075: $defquota = $quotahash{'quotas'}{$item};
9076: $settingstatus = $item;
9077: }
1.536 raeburn 9078: }
9079: }
9080: }
9081: }
9082: if ($defquota eq '') {
1.1075.2.41 raeburn 9083: if (ref($quotahash{'quotas'}{$key}) eq 'HASH') {
9084: $defquota = $quotahash{'quotas'}{$key}{'default'};
9085: } elsif ($key eq 'defaultquota') {
1.711 raeburn 9086: $defquota = $quotahash{'quotas'}{'default'};
9087: }
1.536 raeburn 9088: $settingstatus = 'default';
1.1075.2.42 raeburn 9089: if ($defquota eq '') {
9090: if ($quotaname eq 'author') {
9091: $defquota = 500;
9092: }
9093: }
1.536 raeburn 9094: }
9095: } else {
9096: $settingstatus = 'default';
1.1075.2.41 raeburn 9097: if ($quotaname eq 'author') {
9098: $defquota = 500;
9099: } else {
9100: $defquota = 20;
9101: }
1.536 raeburn 9102: }
9103: if (wantarray) {
9104: return ($defquota,$settingstatus);
1.472 raeburn 9105: } else {
1.536 raeburn 9106: return $defquota;
1.472 raeburn 9107: }
9108: }
9109:
1.1075.2.41 raeburn 9110: ###############################################
9111:
9112: =pod
9113:
1.1075.2.42 raeburn 9114: =item * &excess_filesize_warning()
1.1075.2.41 raeburn 9115:
9116: Returns warning message if upload of file to authoring space, or copying
1.1075.2.42 raeburn 9117: of existing file within authoring space will cause quota for the authoring
9118: space to be exceeded.
9119:
9120: Same, if upload of a file directly to a course/community via Course Editor
9121: will cause quota for uploaded content for the course to be exceeded.
1.1075.2.41 raeburn 9122:
1.1075.2.61 raeburn 9123: Inputs: 7
1.1075.2.42 raeburn 9124: 1. username or coursenum
1.1075.2.41 raeburn 9125: 2. domain
1.1075.2.42 raeburn 9126: 3. context ('author' or 'course')
1.1075.2.41 raeburn 9127: 4. filename of file for which action is being requested
9128: 5. filesize (kB) of file
9129: 6. action being taken: copy or upload.
1.1075.2.59 raeburn 9130: 7. quotatype (in course context -- official, unofficial, community or textbook).
1.1075.2.41 raeburn 9131:
9132: Returns: 1 scalar: HTML to display containing warning if quota would be exceeded,
9133: otherwise return null.
9134:
1.1075.2.42 raeburn 9135: =back
9136:
1.1075.2.41 raeburn 9137: =cut
9138:
1.1075.2.42 raeburn 9139: sub excess_filesize_warning {
1.1075.2.59 raeburn 9140: my ($uname,$udom,$context,$filename,$filesize,$action,$quotatype) = @_;
1.1075.2.42 raeburn 9141: my $current_disk_usage = 0;
1.1075.2.59 raeburn 9142: my $disk_quota = &get_user_quota($uname,$udom,$context,$quotatype); #expressed in MB
1.1075.2.42 raeburn 9143: if ($context eq 'author') {
9144: my $authorspace = $Apache::lonnet::perlvar{'lonDocRoot'}."/priv/$udom/$uname";
9145: $current_disk_usage = &Apache::lonnet::diskusage($udom,$uname,$authorspace);
9146: } else {
9147: foreach my $subdir ('docs','supplemental') {
9148: $current_disk_usage += &Apache::lonnet::diskusage($udom,$uname,"userfiles/$subdir",1);
9149: }
9150: }
1.1075.2.41 raeburn 9151: $disk_quota = int($disk_quota * 1000);
9152: if (($current_disk_usage + $filesize) > $disk_quota) {
1.1075.2.69 raeburn 9153: return '<p class="LC_warning">'.
1.1075.2.41 raeburn 9154: &mt("Unable to $action [_1]. (size = [_2] kilobytes). Disk quota will be exceeded.",
1.1075.2.69 raeburn 9155: '<span class="LC_filename">'.$filename.'</span>',$filesize).'</p>'.
9156: '<p>'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.',
1.1075.2.41 raeburn 9157: $disk_quota,$current_disk_usage).
9158: '</p>';
9159: }
9160: return;
9161: }
9162:
9163: ###############################################
9164:
9165:
1.384 raeburn 9166: sub get_secgrprole_info {
9167: my ($cdom,$cnum,$needroles,$type) = @_;
9168: my %sections_count = &get_sections($cdom,$cnum);
9169: my @sections = (sort {$a <=> $b} keys(%sections_count));
9170: my %curr_groups = &Apache::longroup::coursegroups($cdom,$cnum);
9171: my @groups = sort(keys(%curr_groups));
9172: my $allroles = [];
9173: my $rolehash;
9174: my $accesshash = {
9175: active => 'Currently has access',
9176: future => 'Will have future access',
9177: previous => 'Previously had access',
9178: };
9179: if ($needroles) {
9180: $rolehash = {'all' => 'all'};
1.385 albertel 9181: my %user_roles = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
9182: if (&Apache::lonnet::error(%user_roles)) {
9183: undef(%user_roles);
9184: }
9185: foreach my $item (keys(%user_roles)) {
1.384 raeburn 9186: my ($role)=split(/\:/,$item,2);
9187: if ($role eq 'cr') { next; }
9188: if ($role =~ /^cr/) {
9189: $$rolehash{$role} = (split('/',$role))[3];
9190: } else {
9191: $$rolehash{$role} = &Apache::lonnet::plaintext($role,$type);
9192: }
9193: }
9194: foreach my $key (sort(keys(%{$rolehash}))) {
9195: push(@{$allroles},$key);
9196: }
9197: push (@{$allroles},'st');
9198: $$rolehash{'st'} = &Apache::lonnet::plaintext('st',$type);
9199: }
9200: return (\@sections,\@groups,$allroles,$rolehash,$accesshash);
9201: }
9202:
1.555 raeburn 9203: sub user_picker {
1.994 raeburn 9204: my ($dom,$srch,$forcenewuser,$caller,$cancreate,$usertype,$context) = @_;
1.555 raeburn 9205: my $currdom = $dom;
9206: my %curr_selected = (
9207: srchin => 'dom',
1.580 raeburn 9208: srchby => 'lastname',
1.555 raeburn 9209: );
9210: my $srchterm;
1.625 raeburn 9211: if ((ref($srch) eq 'HASH') && ($env{'form.origform'} ne 'crtusername')) {
1.555 raeburn 9212: if ($srch->{'srchby'} ne '') {
9213: $curr_selected{'srchby'} = $srch->{'srchby'};
9214: }
9215: if ($srch->{'srchin'} ne '') {
9216: $curr_selected{'srchin'} = $srch->{'srchin'};
9217: }
9218: if ($srch->{'srchtype'} ne '') {
9219: $curr_selected{'srchtype'} = $srch->{'srchtype'};
9220: }
9221: if ($srch->{'srchdomain'} ne '') {
9222: $currdom = $srch->{'srchdomain'};
9223: }
9224: $srchterm = $srch->{'srchterm'};
9225: }
9226: my %lt=&Apache::lonlocal::texthash(
1.573 raeburn 9227: 'usr' => 'Search criteria',
1.563 raeburn 9228: 'doma' => 'Domain/institution to search',
1.558 albertel 9229: 'uname' => 'username',
9230: 'lastname' => 'last name',
1.555 raeburn 9231: 'lastfirst' => 'last name, first name',
1.558 albertel 9232: 'crs' => 'in this course',
1.576 raeburn 9233: 'dom' => 'in selected LON-CAPA domain',
1.558 albertel 9234: 'alc' => 'all LON-CAPA',
1.573 raeburn 9235: 'instd' => 'in institutional directory for selected domain',
1.558 albertel 9236: 'exact' => 'is',
9237: 'contains' => 'contains',
1.569 raeburn 9238: 'begins' => 'begins with',
1.571 raeburn 9239: 'youm' => "You must include some text to search for.",
9240: 'thte' => "The text you are searching for must contain at least two characters when using a 'begins' type search.",
9241: 'thet' => "The text you are searching for must contain at least three characters when using a 'contains' type search.",
9242: 'yomc' => "You must choose a domain when using an institutional directory search.",
9243: 'ymcd' => "You must choose a domain when using a domain search.",
9244: 'whus' => "When using searching by last,first you must include a comma as separator between last name and first name.",
9245: 'whse' => "When searching by last,first you must include at least one character in the first name.",
9246: 'thfo' => "The following need to be corrected before the search can be run:",
1.555 raeburn 9247: );
1.563 raeburn 9248: my $domform = &select_dom_form($currdom,'srchdomain',1,1);
9249: my $srchinsel = ' <select name="srchin">';
1.555 raeburn 9250:
9251: my @srchins = ('crs','dom','alc','instd');
9252:
9253: foreach my $option (@srchins) {
9254: # FIXME 'alc' option unavailable until
9255: # loncreateuser::print_user_query_page()
9256: # has been completed.
9257: next if ($option eq 'alc');
1.880 raeburn 9258: next if (($option eq 'crs') && ($env{'form.form'} eq 'requestcrs'));
1.555 raeburn 9259: next if ($option eq 'crs' && !$env{'request.course.id'});
1.563 raeburn 9260: if ($curr_selected{'srchin'} eq $option) {
9261: $srchinsel .= '
9262: <option value="'.$option.'" selected="selected">'.$lt{$option}.'</option>';
9263: } else {
9264: $srchinsel .= '
9265: <option value="'.$option.'">'.$lt{$option}.'</option>';
9266: }
1.555 raeburn 9267: }
1.563 raeburn 9268: $srchinsel .= "\n </select>\n";
1.555 raeburn 9269:
9270: my $srchbysel = ' <select name="srchby">';
1.580 raeburn 9271: foreach my $option ('lastname','lastfirst','uname') {
1.555 raeburn 9272: if ($curr_selected{'srchby'} eq $option) {
9273: $srchbysel .= '
9274: <option value="'.$option.'" selected="selected">'.$lt{$option}.'</option>';
9275: } else {
9276: $srchbysel .= '
9277: <option value="'.$option.'">'.$lt{$option}.'</option>';
9278: }
9279: }
9280: $srchbysel .= "\n </select>\n";
9281:
9282: my $srchtypesel = ' <select name="srchtype">';
1.580 raeburn 9283: foreach my $option ('begins','contains','exact') {
1.555 raeburn 9284: if ($curr_selected{'srchtype'} eq $option) {
9285: $srchtypesel .= '
9286: <option value="'.$option.'" selected="selected">'.$lt{$option}.'</option>';
9287: } else {
9288: $srchtypesel .= '
9289: <option value="'.$option.'">'.$lt{$option}.'</option>';
9290: }
9291: }
9292: $srchtypesel .= "\n </select>\n";
9293:
1.558 albertel 9294: my ($newuserscript,$new_user_create);
1.994 raeburn 9295: my $context_dom = $env{'request.role.domain'};
9296: if ($context eq 'requestcrs') {
9297: if ($env{'form.coursedom'} ne '') {
9298: $context_dom = $env{'form.coursedom'};
9299: }
9300: }
1.556 raeburn 9301: if ($forcenewuser) {
1.576 raeburn 9302: if (ref($srch) eq 'HASH') {
1.994 raeburn 9303: if ($srch->{'srchby'} eq 'uname' && $srch->{'srchtype'} eq 'exact' && $srch->{'srchin'} eq 'dom' && $srch->{'srchdomain'} eq $context_dom) {
1.627 raeburn 9304: if ($cancreate) {
9305: $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>';
9306: } else {
1.799 bisitz 9307: my $helplink = 'javascript:helpMenu('."'display'".')';
1.627 raeburn 9308: my %usertypetext = (
9309: official => 'institutional',
9310: unofficial => 'non-institutional',
9311: );
1.799 bisitz 9312: $new_user_create = '<p class="LC_warning">'
9313: .&mt("You are not authorized to create new $usertypetext{$usertype} users in this domain.")
9314: .' '
9315: .&mt('Please contact the [_1]helpdesk[_2] for assistance.'
9316: ,'<a href="'.$helplink.'">','</a>')
9317: .'</p><br />';
1.627 raeburn 9318: }
1.576 raeburn 9319: }
9320: }
9321:
1.556 raeburn 9322: $newuserscript = <<"ENDSCRIPT";
9323:
1.570 raeburn 9324: function setSearch(createnew,callingForm) {
1.556 raeburn 9325: if (createnew == 1) {
1.570 raeburn 9326: for (var i=0; i<callingForm.srchby.length; i++) {
9327: if (callingForm.srchby.options[i].value == 'uname') {
9328: callingForm.srchby.selectedIndex = i;
1.556 raeburn 9329: }
9330: }
1.570 raeburn 9331: for (var i=0; i<callingForm.srchin.length; i++) {
9332: if ( callingForm.srchin.options[i].value == 'dom') {
9333: callingForm.srchin.selectedIndex = i;
1.556 raeburn 9334: }
9335: }
1.570 raeburn 9336: for (var i=0; i<callingForm.srchtype.length; i++) {
9337: if (callingForm.srchtype.options[i].value == 'exact') {
9338: callingForm.srchtype.selectedIndex = i;
1.556 raeburn 9339: }
9340: }
1.570 raeburn 9341: for (var i=0; i<callingForm.srchdomain.length; i++) {
1.994 raeburn 9342: if (callingForm.srchdomain.options[i].value == '$context_dom') {
1.570 raeburn 9343: callingForm.srchdomain.selectedIndex = i;
1.556 raeburn 9344: }
9345: }
9346: }
9347: }
9348: ENDSCRIPT
1.558 albertel 9349:
1.556 raeburn 9350: }
9351:
1.555 raeburn 9352: my $output = <<"END_BLOCK";
1.556 raeburn 9353: <script type="text/javascript">
1.824 bisitz 9354: // <![CDATA[
1.570 raeburn 9355: function validateEntry(callingForm) {
1.558 albertel 9356:
1.556 raeburn 9357: var checkok = 1;
1.558 albertel 9358: var srchin;
1.570 raeburn 9359: for (var i=0; i<callingForm.srchin.length; i++) {
9360: if ( callingForm.srchin[i].checked ) {
9361: srchin = callingForm.srchin[i].value;
1.558 albertel 9362: }
9363: }
9364:
1.570 raeburn 9365: var srchtype = callingForm.srchtype.options[callingForm.srchtype.selectedIndex].value;
9366: var srchby = callingForm.srchby.options[callingForm.srchby.selectedIndex].value;
9367: var srchdomain = callingForm.srchdomain.options[callingForm.srchdomain.selectedIndex].value;
9368: var srchterm = callingForm.srchterm.value;
9369: var srchin = callingForm.srchin.options[callingForm.srchin.selectedIndex].value;
1.556 raeburn 9370: var msg = "";
9371:
9372: if (srchterm == "") {
9373: checkok = 0;
1.571 raeburn 9374: msg += "$lt{'youm'}\\n";
1.556 raeburn 9375: }
9376:
1.569 raeburn 9377: if (srchtype== 'begins') {
9378: if (srchterm.length < 2) {
9379: checkok = 0;
1.571 raeburn 9380: msg += "$lt{'thte'}\\n";
1.569 raeburn 9381: }
9382: }
9383:
1.556 raeburn 9384: if (srchtype== 'contains') {
9385: if (srchterm.length < 3) {
9386: checkok = 0;
1.571 raeburn 9387: msg += "$lt{'thet'}\\n";
1.556 raeburn 9388: }
9389: }
9390: if (srchin == 'instd') {
9391: if (srchdomain == '') {
9392: checkok = 0;
1.571 raeburn 9393: msg += "$lt{'yomc'}\\n";
1.556 raeburn 9394: }
9395: }
9396: if (srchin == 'dom') {
9397: if (srchdomain == '') {
9398: checkok = 0;
1.571 raeburn 9399: msg += "$lt{'ymcd'}\\n";
1.556 raeburn 9400: }
9401: }
9402: if (srchby == 'lastfirst') {
9403: if (srchterm.indexOf(",") == -1) {
9404: checkok = 0;
1.571 raeburn 9405: msg += "$lt{'whus'}\\n";
1.556 raeburn 9406: }
9407: if (srchterm.indexOf(",") == srchterm.length -1) {
9408: checkok = 0;
1.571 raeburn 9409: msg += "$lt{'whse'}\\n";
1.556 raeburn 9410: }
9411: }
9412: if (checkok == 0) {
1.571 raeburn 9413: alert("$lt{'thfo'}\\n"+msg);
1.556 raeburn 9414: return;
9415: }
9416: if (checkok == 1) {
1.570 raeburn 9417: callingForm.submit();
1.556 raeburn 9418: }
9419: }
9420:
9421: $newuserscript
9422:
1.824 bisitz 9423: // ]]>
1.556 raeburn 9424: </script>
1.558 albertel 9425:
9426: $new_user_create
9427:
1.555 raeburn 9428: END_BLOCK
1.558 albertel 9429:
1.876 raeburn 9430: $output .= &Apache::lonhtmlcommon::start_pick_box().
9431: &Apache::lonhtmlcommon::row_title($lt{'doma'}).
9432: $domform.
9433: &Apache::lonhtmlcommon::row_closure().
9434: &Apache::lonhtmlcommon::row_title($lt{'usr'}).
9435: $srchbysel.
9436: $srchtypesel.
9437: '<input type="text" size="15" name="srchterm" value="'.$srchterm.'" />'.
9438: $srchinsel.
9439: &Apache::lonhtmlcommon::row_closure(1).
9440: &Apache::lonhtmlcommon::end_pick_box().
9441: '<br />';
1.555 raeburn 9442: return $output;
9443: }
9444:
1.612 raeburn 9445: sub user_rule_check {
1.615 raeburn 9446: my ($usershash,$checks,$alerts,$rulematch,$inst_results,$curr_rules,$got_rules) = @_;
1.612 raeburn 9447: my $response;
9448: if (ref($usershash) eq 'HASH') {
9449: foreach my $user (keys(%{$usershash})) {
9450: my ($uname,$udom) = split(/:/,$user);
9451: next if ($udom eq '' || $uname eq '');
1.615 raeburn 9452: my ($id,$newuser);
1.612 raeburn 9453: if (ref($usershash->{$user}) eq 'HASH') {
1.615 raeburn 9454: $newuser = $usershash->{$user}->{'newuser'};
1.612 raeburn 9455: $id = $usershash->{$user}->{'id'};
9456: }
9457: my $inst_response;
9458: if (ref($checks) eq 'HASH') {
9459: if (defined($checks->{'username'})) {
1.615 raeburn 9460: ($inst_response,%{$inst_results->{$user}}) =
1.612 raeburn 9461: &Apache::lonnet::get_instuser($udom,$uname);
9462: } elsif (defined($checks->{'id'})) {
1.615 raeburn 9463: ($inst_response,%{$inst_results->{$user}}) =
1.612 raeburn 9464: &Apache::lonnet::get_instuser($udom,undef,$id);
9465: }
1.615 raeburn 9466: } else {
9467: ($inst_response,%{$inst_results->{$user}}) =
9468: &Apache::lonnet::get_instuser($udom,$uname);
9469: return;
1.612 raeburn 9470: }
1.615 raeburn 9471: if (!$got_rules->{$udom}) {
1.612 raeburn 9472: my %domconfig = &Apache::lonnet::get_dom('configuration',
9473: ['usercreation'],$udom);
9474: if (ref($domconfig{'usercreation'}) eq 'HASH') {
1.615 raeburn 9475: foreach my $item ('username','id') {
1.612 raeburn 9476: if (ref($domconfig{'usercreation'}{$item.'_rule'}) eq 'ARRAY') {
9477: $$curr_rules{$udom}{$item} =
9478: $domconfig{'usercreation'}{$item.'_rule'};
1.585 raeburn 9479: }
9480: }
9481: }
1.615 raeburn 9482: $got_rules->{$udom} = 1;
1.585 raeburn 9483: }
1.612 raeburn 9484: foreach my $item (keys(%{$checks})) {
9485: if (ref($$curr_rules{$udom}) eq 'HASH') {
9486: if (ref($$curr_rules{$udom}{$item}) eq 'ARRAY') {
9487: if (@{$$curr_rules{$udom}{$item}} > 0) {
9488: my %rule_check = &Apache::lonnet::inst_rulecheck($udom,$uname,$id,$item,$$curr_rules{$udom}{$item});
9489: foreach my $rule (@{$$curr_rules{$udom}{$item}}) {
9490: if ($rule_check{$rule}) {
9491: $$rulematch{$user}{$item} = $rule;
9492: if ($inst_response eq 'ok') {
1.615 raeburn 9493: if (ref($inst_results) eq 'HASH') {
9494: if (ref($inst_results->{$user}) eq 'HASH') {
9495: if (keys(%{$inst_results->{$user}}) == 0) {
9496: $$alerts{$item}{$udom}{$uname} = 1;
9497: }
1.612 raeburn 9498: }
9499: }
1.615 raeburn 9500: }
9501: last;
1.585 raeburn 9502: }
9503: }
9504: }
9505: }
9506: }
9507: }
9508: }
9509: }
1.612 raeburn 9510: return;
9511: }
9512:
9513: sub user_rule_formats {
9514: my ($domain,$domdesc,$curr_rules,$check) = @_;
9515: my %text = (
9516: 'username' => 'Usernames',
9517: 'id' => 'IDs',
9518: );
9519: my $output;
9520: my ($rules,$ruleorder) = &Apache::lonnet::inst_userrules($domain,$check);
9521: if ((ref($rules) eq 'HASH') && (ref($ruleorder) eq 'ARRAY')) {
9522: if (@{$ruleorder} > 0) {
1.1075.2.20 raeburn 9523: $output = '<br />'.
9524: &mt($text{$check}.' with the following format(s) may [_1]only[_2] be used for verified users at [_3]:',
9525: '<span class="LC_cusr_emph">','</span>',$domdesc).
9526: ' <ul>';
1.612 raeburn 9527: foreach my $rule (@{$ruleorder}) {
9528: if (ref($curr_rules) eq 'ARRAY') {
9529: if (grep(/^\Q$rule\E$/,@{$curr_rules})) {
9530: if (ref($rules->{$rule}) eq 'HASH') {
9531: $output .= '<li>'.$rules->{$rule}{'name'}.': '.
9532: $rules->{$rule}{'desc'}.'</li>';
9533: }
9534: }
9535: }
9536: }
9537: $output .= '</ul>';
9538: }
9539: }
9540: return $output;
9541: }
9542:
9543: sub instrule_disallow_msg {
1.615 raeburn 9544: my ($checkitem,$domdesc,$count,$mode) = @_;
1.612 raeburn 9545: my $response;
9546: my %text = (
9547: item => 'username',
9548: items => 'usernames',
9549: match => 'matches',
9550: do => 'does',
9551: action => 'a username',
9552: one => 'one',
9553: );
9554: if ($count > 1) {
9555: $text{'item'} = 'usernames';
9556: $text{'match'} ='match';
9557: $text{'do'} = 'do';
9558: $text{'action'} = 'usernames',
9559: $text{'one'} = 'ones';
9560: }
9561: if ($checkitem eq 'id') {
9562: $text{'items'} = 'IDs';
9563: $text{'item'} = 'ID';
9564: $text{'action'} = 'an ID';
1.615 raeburn 9565: if ($count > 1) {
9566: $text{'item'} = 'IDs';
9567: $text{'action'} = 'IDs';
9568: }
1.612 raeburn 9569: }
1.674 bisitz 9570: $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 9571: if ($mode eq 'upload') {
9572: if ($checkitem eq 'username') {
9573: $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'}.");
9574: } elsif ($checkitem eq 'id') {
1.674 bisitz 9575: $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 9576: }
1.669 raeburn 9577: } elsif ($mode eq 'selfcreate') {
9578: if ($checkitem eq 'id') {
9579: $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.");
9580: }
1.615 raeburn 9581: } else {
9582: if ($checkitem eq 'username') {
9583: $response .= &mt("You must choose $text{'action'} with a different format -- $text{'one'} that will not conflict with 'official' institutional $text{'items'}.");
9584: } elsif ($checkitem eq 'id') {
9585: $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.");
9586: }
1.612 raeburn 9587: }
9588: return $response;
1.585 raeburn 9589: }
9590:
1.624 raeburn 9591: sub personal_data_fieldtitles {
9592: my %fieldtitles = &Apache::lonlocal::texthash (
9593: id => 'Student/Employee ID',
9594: permanentemail => 'E-mail address',
9595: lastname => 'Last Name',
9596: firstname => 'First Name',
9597: middlename => 'Middle Name',
9598: generation => 'Generation',
9599: gen => 'Generation',
1.765 raeburn 9600: inststatus => 'Affiliation',
1.624 raeburn 9601: );
9602: return %fieldtitles;
9603: }
9604:
1.642 raeburn 9605: sub sorted_inst_types {
9606: my ($dom) = @_;
1.1075.2.70 raeburn 9607: my ($usertypes,$order);
9608: my %domdefaults = &Apache::lonnet::get_domain_defaults($dom);
9609: if (ref($domdefaults{'inststatus'}) eq 'HASH') {
9610: $usertypes = $domdefaults{'inststatus'}{'inststatustypes'};
9611: $order = $domdefaults{'inststatus'}{'inststatusorder'};
9612: } else {
9613: ($usertypes,$order) = &Apache::lonnet::retrieve_inst_usertypes($dom);
9614: }
1.642 raeburn 9615: my $othertitle = &mt('All users');
9616: if ($env{'request.course.id'}) {
1.668 raeburn 9617: $othertitle = &mt('Any users');
1.642 raeburn 9618: }
9619: my @types;
9620: if (ref($order) eq 'ARRAY') {
9621: @types = @{$order};
9622: }
9623: if (@types == 0) {
9624: if (ref($usertypes) eq 'HASH') {
9625: @types = sort(keys(%{$usertypes}));
9626: }
9627: }
9628: if (keys(%{$usertypes}) > 0) {
9629: $othertitle = &mt('Other users');
9630: }
9631: return ($othertitle,$usertypes,\@types);
9632: }
9633:
1.645 raeburn 9634: sub get_institutional_codes {
9635: my ($settings,$allcourses,$LC_code) = @_;
9636: # Get complete list of course sections to update
9637: my @currsections = ();
9638: my @currxlists = ();
9639: my $coursecode = $$settings{'internal.coursecode'};
9640:
9641: if ($$settings{'internal.sectionnums'} ne '') {
9642: @currsections = split(/,/,$$settings{'internal.sectionnums'});
9643: }
9644:
9645: if ($$settings{'internal.crosslistings'} ne '') {
9646: @currxlists = split(/,/,$$settings{'internal.crosslistings'});
9647: }
9648:
9649: if (@currxlists > 0) {
9650: foreach (@currxlists) {
9651: if (m/^([^:]+):(\w*)$/) {
9652: unless (grep/^$1$/,@{$allcourses}) {
9653: push @{$allcourses},$1;
9654: $$LC_code{$1} = $2;
9655: }
9656: }
9657: }
9658: }
9659:
9660: if (@currsections > 0) {
9661: foreach (@currsections) {
9662: if (m/^(\w+):(\w*)$/) {
9663: my $sec = $coursecode.$1;
9664: my $lc_sec = $2;
9665: unless (grep/^$sec$/,@{$allcourses}) {
9666: push @{$allcourses},$sec;
9667: $$LC_code{$sec} = $lc_sec;
9668: }
9669: }
9670: }
9671: }
9672: return;
9673: }
9674:
1.971 raeburn 9675: sub get_standard_codeitems {
9676: return ('Year','Semester','Department','Number','Section');
9677: }
9678:
1.112 bowersj2 9679: =pod
9680:
1.780 raeburn 9681: =head1 Slot Helpers
9682:
9683: =over 4
9684:
9685: =item * sorted_slots()
9686:
1.1040 raeburn 9687: Sorts an array of slot names in order of an optional sort key,
9688: default sort is by slot start time (earliest first).
1.780 raeburn 9689:
9690: Inputs:
9691:
9692: =over 4
9693:
9694: slotsarr - Reference to array of unsorted slot names.
9695:
9696: slots - Reference to hash of hash, where outer hash keys are slot names.
9697:
1.1040 raeburn 9698: sortkey - Name of key in inner hash to be sorted on (e.g., starttime).
9699:
1.549 albertel 9700: =back
9701:
1.780 raeburn 9702: Returns:
9703:
9704: =over 4
9705:
1.1040 raeburn 9706: sorted - An array of slot names sorted by a specified sort key
9707: (default sort key is start time of the slot).
1.780 raeburn 9708:
9709: =back
9710:
9711: =cut
9712:
9713:
9714: sub sorted_slots {
1.1040 raeburn 9715: my ($slotsarr,$slots,$sortkey) = @_;
9716: if ($sortkey eq '') {
9717: $sortkey = 'starttime';
9718: }
1.780 raeburn 9719: my @sorted;
9720: if ((ref($slotsarr) eq 'ARRAY') && (ref($slots) eq 'HASH')) {
9721: @sorted =
9722: sort {
9723: if (ref($slots->{$a}) && ref($slots->{$b})) {
1.1040 raeburn 9724: return $slots->{$a}{$sortkey} <=> $slots->{$b}{$sortkey}
1.780 raeburn 9725: }
9726: if (ref($slots->{$a})) { return -1;}
9727: if (ref($slots->{$b})) { return 1;}
9728: return 0;
9729: } @{$slotsarr};
9730: }
9731: return @sorted;
9732: }
9733:
1.1040 raeburn 9734: =pod
9735:
9736: =item * get_future_slots()
9737:
9738: Inputs:
9739:
9740: =over 4
9741:
9742: cnum - course number
9743:
9744: cdom - course domain
9745:
9746: now - current UNIX time
9747:
9748: symb - optional symb
9749:
9750: =back
9751:
9752: Returns:
9753:
9754: =over 4
9755:
9756: sorted_reservable - ref to array of student_schedulable slots currently
9757: reservable, ordered by end date of reservation period.
9758:
9759: reservable_now - ref to hash of student_schedulable slots currently
9760: reservable.
9761:
9762: Keys in inner hash are:
9763: (a) symb: either blank or symb to which slot use is restricted.
9764: (b) endreserve: end date of reservation period.
9765:
9766: sorted_future - ref to array of student_schedulable slots reservable in
9767: the future, ordered by start date of reservation period.
9768:
9769: future_reservable - ref to hash of student_schedulable slots reservable
9770: in the future.
9771:
9772: Keys in inner hash are:
9773: (a) symb: either blank or symb to which slot use is restricted.
9774: (b) startreserve: start date of reservation period.
9775:
9776: =back
9777:
9778: =cut
9779:
9780: sub get_future_slots {
9781: my ($cnum,$cdom,$now,$symb) = @_;
9782: my (%reservable_now,%future_reservable,@sorted_reservable,@sorted_future);
9783: my %slots = &Apache::lonnet::get_course_slots($cnum,$cdom);
9784: foreach my $slot (keys(%slots)) {
9785: next unless($slots{$slot}->{'type'} eq 'schedulable_student');
9786: if ($symb) {
9787: next if (($slots{$slot}->{'symb'} ne '') &&
9788: ($slots{$slot}->{'symb'} ne $symb));
9789: }
9790: if (($slots{$slot}->{'starttime'} > $now) &&
9791: ($slots{$slot}->{'endtime'} > $now)) {
9792: if (($slots{$slot}->{'allowedsections'}) || ($slots{$slot}->{'allowedusers'})) {
9793: my $userallowed = 0;
9794: if ($slots{$slot}->{'allowedsections'}) {
9795: my @allowed_sec = split(',',$slots{$slot}->{'allowedsections'});
9796: if (!defined($env{'request.role.sec'})
9797: && grep(/^No section assigned$/,@allowed_sec)) {
9798: $userallowed=1;
9799: } else {
9800: if (grep(/^\Q$env{'request.role.sec'}\E$/,@allowed_sec)) {
9801: $userallowed=1;
9802: }
9803: }
9804: unless ($userallowed) {
9805: if (defined($env{'request.course.groups'})) {
9806: my @groups = split(/:/,$env{'request.course.groups'});
9807: foreach my $group (@groups) {
9808: if (grep(/^\Q$group\E$/,@allowed_sec)) {
9809: $userallowed=1;
9810: last;
9811: }
9812: }
9813: }
9814: }
9815: }
9816: if ($slots{$slot}->{'allowedusers'}) {
9817: my @allowed_users = split(',',$slots{$slot}->{'allowedusers'});
9818: my $user = $env{'user.name'}.':'.$env{'user.domain'};
9819: if (grep(/^\Q$user\E$/,@allowed_users)) {
9820: $userallowed = 1;
9821: }
9822: }
9823: next unless($userallowed);
9824: }
9825: my $startreserve = $slots{$slot}->{'startreserve'};
9826: my $endreserve = $slots{$slot}->{'endreserve'};
9827: my $symb = $slots{$slot}->{'symb'};
9828: if (($startreserve < $now) &&
9829: (!$endreserve || $endreserve > $now)) {
9830: my $lastres = $endreserve;
9831: if (!$lastres) {
9832: $lastres = $slots{$slot}->{'starttime'};
9833: }
9834: $reservable_now{$slot} = {
9835: symb => $symb,
9836: endreserve => $lastres
9837: };
9838: } elsif (($startreserve > $now) &&
9839: (!$endreserve || $endreserve > $startreserve)) {
9840: $future_reservable{$slot} = {
9841: symb => $symb,
9842: startreserve => $startreserve
9843: };
9844: }
9845: }
9846: }
9847: my @unsorted_reservable = keys(%reservable_now);
9848: if (@unsorted_reservable > 0) {
9849: @sorted_reservable =
9850: &sorted_slots(\@unsorted_reservable,\%reservable_now,'endreserve');
9851: }
9852: my @unsorted_future = keys(%future_reservable);
9853: if (@unsorted_future > 0) {
9854: @sorted_future =
9855: &sorted_slots(\@unsorted_future,\%future_reservable,'startreserve');
9856: }
9857: return (\@sorted_reservable,\%reservable_now,\@sorted_future,\%future_reservable);
9858: }
1.780 raeburn 9859:
9860: =pod
9861:
1.1057 foxr 9862: =back
9863:
1.549 albertel 9864: =head1 HTTP Helpers
9865:
9866: =over 4
9867:
1.648 raeburn 9868: =item * &get_unprocessed_cgi($query,$possible_names)
1.112 bowersj2 9869:
1.258 albertel 9870: Modify the %env hash to contain unprocessed CGI form parameters held in
1.112 bowersj2 9871: $query. The parameters listed in $possible_names (an array reference),
1.258 albertel 9872: will be set in $env{'form.name'} if they do not already exist.
1.112 bowersj2 9873:
9874: Typically called with $ENV{'QUERY_STRING'} as the first parameter.
9875: $possible_names is an ref to an array of form element names. As an example:
9876: get_unprocessed_cgi($ENV{'QUERY_STRING'},['uname','udom']);
1.258 albertel 9877: will result in $env{'form.uname'} and $env{'form.udom'} being set.
1.112 bowersj2 9878:
9879: =cut
1.1 albertel 9880:
1.6 albertel 9881: sub get_unprocessed_cgi {
1.25 albertel 9882: my ($query,$possible_names)= @_;
1.26 matthew 9883: # $Apache::lonxml::debug=1;
1.356 albertel 9884: foreach my $pair (split(/&/,$query)) {
9885: my ($name, $value) = split(/=/,$pair);
1.369 www 9886: $name = &unescape($name);
1.25 albertel 9887: if (!defined($possible_names) || (grep {$_ eq $name} @$possible_names)) {
9888: $value =~ tr/+/ /;
9889: $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
1.258 albertel 9890: unless (defined($env{'form.'.$name})) { &add_to_env('form.'.$name,$value) };
1.25 albertel 9891: }
1.16 harris41 9892: }
1.6 albertel 9893: }
9894:
1.112 bowersj2 9895: =pod
9896:
1.648 raeburn 9897: =item * &cacheheader()
1.112 bowersj2 9898:
9899: returns cache-controlling header code
9900:
9901: =cut
9902:
1.7 albertel 9903: sub cacheheader {
1.258 albertel 9904: unless ($env{'request.method'} eq 'GET') { return ''; }
1.216 albertel 9905: my $date=strftime("%a, %d %b %Y %H:%M:%S GMT",gmtime);
9906: my $output .='<meta HTTP-EQUIV="Expires" CONTENT="'.$date.'" />
1.7 albertel 9907: <meta HTTP-EQUIV="Cache-control" CONTENT="no-cache" />
9908: <meta HTTP-EQUIV="Pragma" CONTENT="no-cache" />';
1.216 albertel 9909: return $output;
1.7 albertel 9910: }
9911:
1.112 bowersj2 9912: =pod
9913:
1.648 raeburn 9914: =item * &no_cache($r)
1.112 bowersj2 9915:
9916: specifies header code to not have cache
9917:
9918: =cut
9919:
1.9 albertel 9920: sub no_cache {
1.216 albertel 9921: my ($r) = @_;
9922: if ($ENV{'REQUEST_METHOD'} ne 'GET' &&
1.258 albertel 9923: $env{'request.method'} ne 'GET') { return ''; }
1.216 albertel 9924: my $date=strftime("%a, %d %b %Y %H:%M:%S GMT",gmtime(time));
9925: $r->no_cache(1);
9926: $r->header_out("Expires" => $date);
9927: $r->header_out("Pragma" => "no-cache");
1.123 www 9928: }
9929:
9930: sub content_type {
1.181 albertel 9931: my ($r,$type,$charset) = @_;
1.299 foxr 9932: if ($r) {
9933: # Note that printout.pl calls this with undef for $r.
9934: &no_cache($r);
9935: }
1.258 albertel 9936: if ($env{'browser.mathml'} && $type eq 'text/html') { $type='text/xml'; }
1.181 albertel 9937: unless ($charset) {
9938: $charset=&Apache::lonlocal::current_encoding;
9939: }
9940: if ($charset) { $type.='; charset='.$charset; }
9941: if ($r) {
9942: $r->content_type($type);
9943: } else {
9944: print("Content-type: $type\n\n");
9945: }
1.9 albertel 9946: }
1.25 albertel 9947:
1.112 bowersj2 9948: =pod
9949:
1.648 raeburn 9950: =item * &add_to_env($name,$value)
1.112 bowersj2 9951:
1.258 albertel 9952: adds $name to the %env hash with value
1.112 bowersj2 9953: $value, if $name already exists, the entry is converted to an array
9954: reference and $value is added to the array.
9955:
9956: =cut
9957:
1.25 albertel 9958: sub add_to_env {
9959: my ($name,$value)=@_;
1.258 albertel 9960: if (defined($env{$name})) {
9961: if (ref($env{$name})) {
1.25 albertel 9962: #already have multiple values
1.258 albertel 9963: push(@{ $env{$name} },$value);
1.25 albertel 9964: } else {
9965: #first time seeing multiple values, convert hash entry to an arrayref
1.258 albertel 9966: my $first=$env{$name};
9967: undef($env{$name});
9968: push(@{ $env{$name} },$first,$value);
1.25 albertel 9969: }
9970: } else {
1.258 albertel 9971: $env{$name}=$value;
1.25 albertel 9972: }
1.31 albertel 9973: }
1.149 albertel 9974:
9975: =pod
9976:
1.648 raeburn 9977: =item * &get_env_multiple($name)
1.149 albertel 9978:
1.258 albertel 9979: gets $name from the %env hash, it seemlessly handles the cases where multiple
1.149 albertel 9980: values may be defined and end up as an array ref.
9981:
9982: returns an array of values
9983:
9984: =cut
9985:
9986: sub get_env_multiple {
9987: my ($name) = @_;
9988: my @values;
1.258 albertel 9989: if (defined($env{$name})) {
1.149 albertel 9990: # exists is it an array
1.258 albertel 9991: if (ref($env{$name})) {
9992: @values=@{ $env{$name} };
1.149 albertel 9993: } else {
1.258 albertel 9994: $values[0]=$env{$name};
1.149 albertel 9995: }
9996: }
9997: return(@values);
9998: }
9999:
1.660 raeburn 10000: sub ask_for_embedded_content {
10001: my ($actionurl,$state,$allfiles,$codebase,$args)=@_;
1.1071 raeburn 10002: my (%subdependencies,%dependencies,%mapping,%existing,%newfiles,%pathchanges,
1.1075.2.11 raeburn 10003: %currsubfile,%unused,$rem);
1.1071 raeburn 10004: my $counter = 0;
10005: my $numnew = 0;
1.987 raeburn 10006: my $numremref = 0;
10007: my $numinvalid = 0;
10008: my $numpathchg = 0;
10009: my $numexisting = 0;
1.1071 raeburn 10010: my $numunused = 0;
10011: my ($output,$upload_output,$toplevel,$url,$udom,$uname,$getpropath,$cdom,$cnum,
1.1075.2.53 raeburn 10012: $fileloc,$filename,$delete_output,$modify_output,$title,$symb,$path,$navmap);
1.1071 raeburn 10013: my $heading = &mt('Upload embedded files');
10014: my $buttontext = &mt('Upload');
10015:
1.1075.2.11 raeburn 10016: if ($env{'request.course.id'}) {
1.1075.2.35 raeburn 10017: if ($actionurl eq '/adm/dependencies') {
10018: $navmap = Apache::lonnavmaps::navmap->new();
10019: }
10020: $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
10021: $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
1.1075.2.11 raeburn 10022: }
1.1075.2.35 raeburn 10023: if (($actionurl eq '/adm/portfolio') ||
10024: ($actionurl eq '/adm/coursegrp_portfolio')) {
1.984 raeburn 10025: my $current_path='/';
10026: if ($env{'form.currentpath'}) {
10027: $current_path = $env{'form.currentpath'};
10028: }
10029: if ($actionurl eq '/adm/coursegrp_portfolio') {
1.1075.2.35 raeburn 10030: $udom = $cdom;
10031: $uname = $cnum;
1.984 raeburn 10032: $url = '/userfiles/groups/'.$env{'form.group'}.'/portfolio';
10033: } else {
10034: $udom = $env{'user.domain'};
10035: $uname = $env{'user.name'};
10036: $url = '/userfiles/portfolio';
10037: }
1.987 raeburn 10038: $toplevel = $url.'/';
1.984 raeburn 10039: $url .= $current_path;
10040: $getpropath = 1;
1.987 raeburn 10041: } elsif (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank') ||
10042: ($actionurl eq '/adm/imsimport')) {
1.1022 www 10043: my ($udom,$uname,$rest) = ($args->{'current_path'} =~ m{/priv/($match_domain)/($match_username)/?(.*)$});
1.1026 raeburn 10044: $url = $Apache::lonnet::perlvar{'lonDocRoot'}."/priv/$udom/$uname/";
1.987 raeburn 10045: $toplevel = $url;
1.984 raeburn 10046: if ($rest ne '') {
1.987 raeburn 10047: $url .= $rest;
10048: }
10049: } elsif ($actionurl eq '/adm/coursedocs') {
10050: if (ref($args) eq 'HASH') {
1.1071 raeburn 10051: $url = $args->{'docs_url'};
10052: $toplevel = $url;
1.1075.2.11 raeburn 10053: if ($args->{'context'} eq 'paste') {
10054: ($cdom,$cnum) = ($url =~ m{^\Q/uploaded/\E($match_domain)/($match_courseid)/});
10055: ($path) =
10056: ($toplevel =~ m{^(\Q/uploaded/$cdom/$cnum/\E(?:docs|supplemental)/(?:default|\d+)/\d+)/});
10057: $fileloc = &Apache::lonnet::filelocation('',$toplevel);
10058: $fileloc =~ s{^/}{};
10059: }
1.1071 raeburn 10060: }
10061: } elsif ($actionurl eq '/adm/dependencies') {
10062: if ($env{'request.course.id'} ne '') {
10063: if (ref($args) eq 'HASH') {
10064: $url = $args->{'docs_url'};
10065: $title = $args->{'docs_title'};
1.1075.2.35 raeburn 10066: $toplevel = $url;
10067: unless ($toplevel =~ m{^/}) {
10068: $toplevel = "/$url";
10069: }
1.1075.2.11 raeburn 10070: ($rem) = ($toplevel =~ m{^(.+/)[^/]+$});
1.1075.2.35 raeburn 10071: if ($toplevel =~ m{^(\Q/uploaded/$cdom/$cnum/portfolio/syllabus\E)}) {
10072: $path = $1;
10073: } else {
10074: ($path) =
10075: ($toplevel =~ m{^(\Q/uploaded/$cdom/$cnum/\E(?:docs|supplemental)/(?:default|\d+)/\d+)/});
10076: }
1.1075.2.79 raeburn 10077: if ($toplevel=~/^\/*(uploaded|editupload)/) {
10078: $fileloc = $toplevel;
10079: $fileloc=~ s/^\s*(\S+)\s*$/$1/;
10080: my ($udom,$uname,$fname) =
10081: ($fileloc=~ m{^/+(?:uploaded|editupload)/+($match_domain)/+($match_name)/+(.*)$});
10082: $fileloc = propath($udom,$uname).'/userfiles/'.$fname;
10083: } else {
10084: $fileloc = &Apache::lonnet::filelocation('',$toplevel);
10085: }
1.1071 raeburn 10086: $fileloc =~ s{^/}{};
10087: ($filename) = ($fileloc =~ m{.+/([^/]+)$});
10088: $heading = &mt('Status of dependencies in [_1]',"$title ($filename)");
10089: }
1.987 raeburn 10090: }
1.1075.2.35 raeburn 10091: } elsif ($actionurl eq "/public/$cdom/$cnum/syllabus") {
10092: $udom = $cdom;
10093: $uname = $cnum;
10094: $url = "/uploaded/$cdom/$cnum/portfolio/syllabus";
10095: $toplevel = $url;
10096: $path = $url;
10097: $fileloc = &Apache::lonnet::filelocation('',$toplevel).'/';
10098: $fileloc =~ s{^/}{};
10099: }
10100: foreach my $file (keys(%{$allfiles})) {
10101: my $embed_file;
10102: if (($path eq "/uploaded/$cdom/$cnum/portfolio/syllabus") && ($file =~ m{^\Q$path/\E(.+)$})) {
10103: $embed_file = $1;
10104: } else {
10105: $embed_file = $file;
10106: }
1.1075.2.55 raeburn 10107: my ($absolutepath,$cleaned_file);
10108: if ($embed_file =~ m{^\w+://}) {
10109: $cleaned_file = $embed_file;
1.1075.2.47 raeburn 10110: $newfiles{$cleaned_file} = 1;
10111: $mapping{$cleaned_file} = $embed_file;
1.987 raeburn 10112: } else {
1.1075.2.55 raeburn 10113: $cleaned_file = &clean_path($embed_file);
1.987 raeburn 10114: if ($embed_file =~ m{^/}) {
10115: $absolutepath = $embed_file;
10116: }
1.1075.2.47 raeburn 10117: if ($cleaned_file =~ m{/}) {
10118: my ($path,$fname) = ($cleaned_file =~ m{^(.+)/([^/]*)$});
1.987 raeburn 10119: $path = &check_for_traversal($path,$url,$toplevel);
10120: my $item = $fname;
10121: if ($path ne '') {
10122: $item = $path.'/'.$fname;
10123: $subdependencies{$path}{$fname} = 1;
10124: } else {
10125: $dependencies{$item} = 1;
10126: }
10127: if ($absolutepath) {
10128: $mapping{$item} = $absolutepath;
10129: } else {
10130: $mapping{$item} = $embed_file;
10131: }
10132: } else {
10133: $dependencies{$embed_file} = 1;
10134: if ($absolutepath) {
1.1075.2.47 raeburn 10135: $mapping{$cleaned_file} = $absolutepath;
1.987 raeburn 10136: } else {
1.1075.2.47 raeburn 10137: $mapping{$cleaned_file} = $embed_file;
1.987 raeburn 10138: }
10139: }
1.984 raeburn 10140: }
10141: }
1.1071 raeburn 10142: my $dirptr = 16384;
1.984 raeburn 10143: foreach my $path (keys(%subdependencies)) {
1.1071 raeburn 10144: $currsubfile{$path} = {};
1.1075.2.35 raeburn 10145: if (($actionurl eq '/adm/portfolio') ||
10146: ($actionurl eq '/adm/coursegrp_portfolio')) {
1.1021 raeburn 10147: my ($sublistref,$listerror) =
10148: &Apache::lonnet::dirlist($url.$path,$udom,$uname,$getpropath);
10149: if (ref($sublistref) eq 'ARRAY') {
10150: foreach my $line (@{$sublistref}) {
10151: my ($file_name,$rest) = split(/\&/,$line,2);
1.1071 raeburn 10152: $currsubfile{$path}{$file_name} = 1;
1.1021 raeburn 10153: }
1.984 raeburn 10154: }
1.987 raeburn 10155: } elsif (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank')) {
1.984 raeburn 10156: if (opendir(my $dir,$url.'/'.$path)) {
10157: my @subdir_list = grep(!/^\./,readdir($dir));
1.1071 raeburn 10158: map {$currsubfile{$path}{$_} = 1;} @subdir_list;
10159: }
1.1075.2.11 raeburn 10160: } elsif (($actionurl eq '/adm/dependencies') ||
10161: (($actionurl eq '/adm/coursedocs') && (ref($args) eq 'HASH') &&
1.1075.2.35 raeburn 10162: ($args->{'context'} eq 'paste')) ||
10163: ($actionurl eq "/public/$cdom/$cnum/syllabus")) {
1.1071 raeburn 10164: if ($env{'request.course.id'} ne '') {
1.1075.2.35 raeburn 10165: my $dir;
10166: if ($actionurl eq "/public/$cdom/$cnum/syllabus") {
10167: $dir = $fileloc;
10168: } else {
10169: ($dir) = ($fileloc =~ m{^(.+/)[^/]+$});
10170: }
1.1071 raeburn 10171: if ($dir ne '') {
10172: my ($sublistref,$listerror) =
10173: &Apache::lonnet::dirlist($dir.$path,$cdom,$cnum,$getpropath,undef,'/');
10174: if (ref($sublistref) eq 'ARRAY') {
10175: foreach my $line (@{$sublistref}) {
10176: my ($file_name,$dom,undef,$testdir,undef,undef,undef,undef,$size,
10177: undef,$mtime)=split(/\&/,$line,12);
10178: unless (($testdir&$dirptr) ||
10179: ($file_name =~ /^\.\.?$/)) {
10180: $currsubfile{$path}{$file_name} = [$size,$mtime];
10181: }
10182: }
10183: }
10184: }
1.984 raeburn 10185: }
10186: }
10187: foreach my $file (keys(%{$subdependencies{$path}})) {
1.1071 raeburn 10188: if (exists($currsubfile{$path}{$file})) {
1.987 raeburn 10189: my $item = $path.'/'.$file;
10190: unless ($mapping{$item} eq $item) {
10191: $pathchanges{$item} = 1;
10192: }
10193: $existing{$item} = 1;
10194: $numexisting ++;
10195: } else {
10196: $newfiles{$path.'/'.$file} = 1;
1.984 raeburn 10197: }
10198: }
1.1071 raeburn 10199: if ($actionurl eq '/adm/dependencies') {
10200: foreach my $path (keys(%currsubfile)) {
10201: if (ref($currsubfile{$path}) eq 'HASH') {
10202: foreach my $file (keys(%{$currsubfile{$path}})) {
10203: unless ($subdependencies{$path}{$file}) {
1.1075.2.11 raeburn 10204: next if (($rem ne '') &&
10205: (($env{"httpref.$rem"."$path/$file"} ne '') ||
10206: (ref($navmap) &&
10207: (($navmap->getResourceByUrl($rem."$path/$file") ne '') ||
10208: (($file =~ /^(.*\.s?html?)\.bak$/i) &&
10209: ($navmap->getResourceByUrl($rem."$path/$1")))))));
1.1071 raeburn 10210: $unused{$path.'/'.$file} = 1;
10211: }
10212: }
10213: }
10214: }
10215: }
1.984 raeburn 10216: }
1.987 raeburn 10217: my %currfile;
1.1075.2.35 raeburn 10218: if (($actionurl eq '/adm/portfolio') ||
10219: ($actionurl eq '/adm/coursegrp_portfolio')) {
1.1021 raeburn 10220: my ($dirlistref,$listerror) =
10221: &Apache::lonnet::dirlist($url,$udom,$uname,$getpropath);
10222: if (ref($dirlistref) eq 'ARRAY') {
10223: foreach my $line (@{$dirlistref}) {
10224: my ($file_name,$rest) = split(/\&/,$line,2);
10225: $currfile{$file_name} = 1;
10226: }
1.984 raeburn 10227: }
1.987 raeburn 10228: } elsif (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank')) {
1.984 raeburn 10229: if (opendir(my $dir,$url)) {
1.987 raeburn 10230: my @dir_list = grep(!/^\./,readdir($dir));
1.984 raeburn 10231: map {$currfile{$_} = 1;} @dir_list;
10232: }
1.1075.2.11 raeburn 10233: } elsif (($actionurl eq '/adm/dependencies') ||
10234: (($actionurl eq '/adm/coursedocs') && (ref($args) eq 'HASH') &&
1.1075.2.35 raeburn 10235: ($args->{'context'} eq 'paste')) ||
10236: ($actionurl eq "/public/$cdom/$cnum/syllabus")) {
1.1071 raeburn 10237: if ($env{'request.course.id'} ne '') {
10238: my ($dir) = ($fileloc =~ m{^(.+/)[^/]+$});
10239: if ($dir ne '') {
10240: my ($dirlistref,$listerror) =
10241: &Apache::lonnet::dirlist($dir,$cdom,$cnum,$getpropath,undef,'/');
10242: if (ref($dirlistref) eq 'ARRAY') {
10243: foreach my $line (@{$dirlistref}) {
10244: my ($file_name,$dom,undef,$testdir,undef,undef,undef,undef,
10245: $size,undef,$mtime)=split(/\&/,$line,12);
10246: unless (($testdir&$dirptr) ||
10247: ($file_name =~ /^\.\.?$/)) {
10248: $currfile{$file_name} = [$size,$mtime];
10249: }
10250: }
10251: }
10252: }
10253: }
1.984 raeburn 10254: }
10255: foreach my $file (keys(%dependencies)) {
1.1071 raeburn 10256: if (exists($currfile{$file})) {
1.987 raeburn 10257: unless ($mapping{$file} eq $file) {
10258: $pathchanges{$file} = 1;
10259: }
10260: $existing{$file} = 1;
10261: $numexisting ++;
10262: } else {
1.984 raeburn 10263: $newfiles{$file} = 1;
10264: }
10265: }
1.1071 raeburn 10266: foreach my $file (keys(%currfile)) {
10267: unless (($file eq $filename) ||
10268: ($file eq $filename.'.bak') ||
10269: ($dependencies{$file})) {
1.1075.2.11 raeburn 10270: if ($actionurl eq '/adm/dependencies') {
1.1075.2.35 raeburn 10271: unless ($toplevel =~ m{^\Q/uploaded/$cdom/$cnum/portfolio/syllabus\E}) {
10272: next if (($rem ne '') &&
10273: (($env{"httpref.$rem".$file} ne '') ||
10274: (ref($navmap) &&
10275: (($navmap->getResourceByUrl($rem.$file) ne '') ||
10276: (($file =~ /^(.*\.s?html?)\.bak$/i) &&
10277: ($navmap->getResourceByUrl($rem.$1)))))));
10278: }
1.1075.2.11 raeburn 10279: }
1.1071 raeburn 10280: $unused{$file} = 1;
10281: }
10282: }
1.1075.2.11 raeburn 10283: if (($actionurl eq '/adm/coursedocs') && (ref($args) eq 'HASH') &&
10284: ($args->{'context'} eq 'paste')) {
10285: $counter = scalar(keys(%existing));
10286: $numpathchg = scalar(keys(%pathchanges));
10287: return ($output,$counter,$numpathchg,\%existing);
1.1075.2.35 raeburn 10288: } elsif (($actionurl eq "/public/$cdom/$cnum/syllabus") &&
10289: (ref($args) eq 'HASH') && ($args->{'context'} eq 'rewrites')) {
10290: $counter = scalar(keys(%existing));
10291: $numpathchg = scalar(keys(%pathchanges));
10292: return ($output,$counter,$numpathchg,\%existing,\%mapping);
1.1075.2.11 raeburn 10293: }
1.984 raeburn 10294: foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%newfiles)) {
1.1071 raeburn 10295: if ($actionurl eq '/adm/dependencies') {
10296: next if ($embed_file =~ m{^\w+://});
10297: }
1.660 raeburn 10298: $upload_output .= &start_data_table_row().
1.1075.2.35 raeburn 10299: '<td valign="top"><img src="'.&icon($embed_file).'" /> '.
1.1071 raeburn 10300: '<span class="LC_filename">'.$embed_file.'</span>';
1.987 raeburn 10301: unless ($mapping{$embed_file} eq $embed_file) {
1.1075.2.35 raeburn 10302: $upload_output .= '<br /><span class="LC_info" style="font-size:smaller;">'.
10303: &mt('changed from: [_1]',$mapping{$embed_file}).'</span>';
1.987 raeburn 10304: }
1.1075.2.35 raeburn 10305: $upload_output .= '</td>';
1.1071 raeburn 10306: if ($args->{'ignore_remote_references'} && $embed_file =~ m{^\w+://}) {
1.1075.2.35 raeburn 10307: $upload_output.='<td align="right">'.
10308: '<span class="LC_info LC_fontsize_medium">'.
10309: &mt("URL points to web address").'</span>';
1.987 raeburn 10310: $numremref++;
1.660 raeburn 10311: } elsif ($args->{'error_on_invalid_names'}
10312: && $embed_file ne &Apache::lonnet::clean_filename($embed_file,{'keep_path' => 1,})) {
1.1075.2.35 raeburn 10313: $upload_output.='<td align="right"><span class="LC_warning">'.
10314: &mt('Invalid characters').'</span>';
1.987 raeburn 10315: $numinvalid++;
1.660 raeburn 10316: } else {
1.1075.2.35 raeburn 10317: $upload_output .= '<td>'.
10318: &embedded_file_element('upload_embedded',$counter,
1.987 raeburn 10319: $embed_file,\%mapping,
1.1071 raeburn 10320: $allfiles,$codebase,'upload');
10321: $counter ++;
10322: $numnew ++;
1.987 raeburn 10323: }
10324: $upload_output .= '</td>'.&Apache::loncommon::end_data_table_row()."\n";
10325: }
10326: foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%existing)) {
1.1071 raeburn 10327: if ($actionurl eq '/adm/dependencies') {
10328: my ($size,$mtime) = &get_dependency_details(\%currfile,\%currsubfile,$embed_file);
10329: $modify_output .= &start_data_table_row().
10330: '<td><a href="'.$path.'/'.$embed_file.'" style="text-decoration:none;">'.
10331: '<img src="'.&icon($embed_file).'" border="0" />'.
10332: ' <span class="LC_filename">'.$embed_file.'</span></a></td>'.
10333: '<td>'.$size.'</td>'.
10334: '<td>'.$mtime.'</td>'.
10335: '<td><label><input type="checkbox" name="mod_upload_dep" '.
10336: 'onclick="toggleBrowse('."'$counter'".')" id="mod_upload_dep_'.
10337: $counter.'" value="'.$counter.'" />'.&mt('Yes').'</label>'.
10338: '<div id="moduploaddep_'.$counter.'" style="display:none;">'.
10339: &embedded_file_element('upload_embedded',$counter,
10340: $embed_file,\%mapping,
10341: $allfiles,$codebase,'modify').
10342: '</div></td>'.
10343: &end_data_table_row()."\n";
10344: $counter ++;
10345: } else {
10346: $upload_output .= &start_data_table_row().
1.1075.2.35 raeburn 10347: '<td valign="top"><img src="'.&icon($embed_file).'" /> '.
10348: '<span class="LC_filename">'.$embed_file.'</span></td>'.
10349: '<td align="right"><span class="LC_info LC_fontsize_medium">'.&mt('Already exists').'</span></td>'.
1.1071 raeburn 10350: &Apache::loncommon::end_data_table_row()."\n";
10351: }
10352: }
10353: my $delidx = $counter;
10354: foreach my $oldfile (sort {lc($a) cmp lc($b)} keys(%unused)) {
10355: my ($size,$mtime) = &get_dependency_details(\%currfile,\%currsubfile,$oldfile);
10356: $delete_output .= &start_data_table_row().
10357: '<td><img src="'.&icon($oldfile).'" />'.
10358: ' <span class="LC_filename">'.$oldfile.'</span></td>'.
10359: '<td>'.$size.'</td>'.
10360: '<td>'.$mtime.'</td>'.
10361: '<td><label><input type="checkbox" name="del_upload_dep" '.
10362: ' value="'.$delidx.'" />'.&mt('Yes').'</label>'.
10363: &embedded_file_element('upload_embedded',$delidx,
10364: $oldfile,\%mapping,$allfiles,
10365: $codebase,'delete').'</td>'.
10366: &end_data_table_row()."\n";
10367: $numunused ++;
10368: $delidx ++;
1.987 raeburn 10369: }
10370: if ($upload_output) {
10371: $upload_output = &start_data_table().
10372: $upload_output.
10373: &end_data_table()."\n";
10374: }
1.1071 raeburn 10375: if ($modify_output) {
10376: $modify_output = &start_data_table().
10377: &start_data_table_header_row().
10378: '<th>'.&mt('File').'</th>'.
10379: '<th>'.&mt('Size (KB)').'</th>'.
10380: '<th>'.&mt('Modified').'</th>'.
10381: '<th>'.&mt('Upload replacement?').'</th>'.
10382: &end_data_table_header_row().
10383: $modify_output.
10384: &end_data_table()."\n";
10385: }
10386: if ($delete_output) {
10387: $delete_output = &start_data_table().
10388: &start_data_table_header_row().
10389: '<th>'.&mt('File').'</th>'.
10390: '<th>'.&mt('Size (KB)').'</th>'.
10391: '<th>'.&mt('Modified').'</th>'.
10392: '<th>'.&mt('Delete?').'</th>'.
10393: &end_data_table_header_row().
10394: $delete_output.
10395: &end_data_table()."\n";
10396: }
1.987 raeburn 10397: my $applies = 0;
10398: if ($numremref) {
10399: $applies ++;
10400: }
10401: if ($numinvalid) {
10402: $applies ++;
10403: }
10404: if ($numexisting) {
10405: $applies ++;
10406: }
1.1071 raeburn 10407: if ($counter || $numunused) {
1.987 raeburn 10408: $output = '<form name="upload_embedded" action="'.$actionurl.'"'.
10409: ' method="post" enctype="multipart/form-data">'."\n".
1.1071 raeburn 10410: $state.'<h3>'.$heading.'</h3>';
10411: if ($actionurl eq '/adm/dependencies') {
10412: if ($numnew) {
10413: $output .= '<h4>'.&mt('Missing dependencies').'</h4>'.
10414: '<p>'.&mt('The following files need to be uploaded.').'</p>'."\n".
10415: $upload_output.'<br />'."\n";
10416: }
10417: if ($numexisting) {
10418: $output .= '<h4>'.&mt('Uploaded dependencies (in use)').'</h4>'.
10419: '<p>'.&mt('Upload a new file to replace the one currently in use.').'</p>'."\n".
10420: $modify_output.'<br />'."\n";
10421: $buttontext = &mt('Save changes');
10422: }
10423: if ($numunused) {
10424: $output .= '<h4>'.&mt('Unused files').'</h4>'.
10425: '<p>'.&mt('The following uploaded files are no longer used.').'</p>'."\n".
10426: $delete_output.'<br />'."\n";
10427: $buttontext = &mt('Save changes');
10428: }
10429: } else {
10430: $output .= $upload_output.'<br />'."\n";
10431: }
10432: $output .= '<input type ="hidden" name="number_embedded_items" value="'.
10433: $counter.'" />'."\n";
10434: if ($actionurl eq '/adm/dependencies') {
10435: $output .= '<input type ="hidden" name="number_newemb_items" value="'.
10436: $numnew.'" />'."\n";
10437: } elsif ($actionurl eq '') {
1.987 raeburn 10438: $output .= '<input type="hidden" name="phase" value="three" />';
10439: }
10440: } elsif ($applies) {
10441: $output = '<b>'.&mt('Referenced files').'</b>:<br />';
10442: if ($applies > 1) {
10443: $output .=
1.1075.2.35 raeburn 10444: &mt('No dependencies need to be uploaded, as one of the following applies to each reference:').'<ul>';
1.987 raeburn 10445: if ($numremref) {
10446: $output .= '<li>'.&mt('reference is to a URL which points to another server').'</li>'."\n";
10447: }
10448: if ($numinvalid) {
10449: $output .= '<li>'.&mt('reference is to file with a name containing invalid characters').'</li>'."\n";
10450: }
10451: if ($numexisting) {
10452: $output .= '<li>'.&mt('reference is to an existing file at the specified location').'</li>'."\n";
10453: }
10454: $output .= '</ul><br />';
10455: } elsif ($numremref) {
10456: $output .= '<p>'.&mt('None to upload, as all references are to URLs pointing to another server.').'</p>';
10457: } elsif ($numinvalid) {
10458: $output .= '<p>'.&mt('None to upload, as all references are to files with names containing invalid characters.').'</p>';
10459: } elsif ($numexisting) {
10460: $output .= '<p>'.&mt('None to upload, as all references are to existing files.').'</p>';
10461: }
10462: $output .= $upload_output.'<br />';
10463: }
10464: my ($pathchange_output,$chgcount);
1.1071 raeburn 10465: $chgcount = $counter;
1.987 raeburn 10466: if (keys(%pathchanges) > 0) {
10467: foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%pathchanges)) {
1.1071 raeburn 10468: if ($counter) {
1.987 raeburn 10469: $output .= &embedded_file_element('pathchange',$chgcount,
10470: $embed_file,\%mapping,
1.1071 raeburn 10471: $allfiles,$codebase,'change');
1.987 raeburn 10472: } else {
10473: $pathchange_output .=
10474: &start_data_table_row().
10475: '<td><input type ="checkbox" name="namechange" value="'.
10476: $chgcount.'" checked="checked" /></td>'.
10477: '<td>'.$mapping{$embed_file}.'</td>'.
10478: '<td>'.$embed_file.
10479: &embedded_file_element('pathchange',$numpathchg,$embed_file,
1.1071 raeburn 10480: \%mapping,$allfiles,$codebase,'change').
1.987 raeburn 10481: '</td>'.&end_data_table_row();
1.660 raeburn 10482: }
1.987 raeburn 10483: $numpathchg ++;
10484: $chgcount ++;
1.660 raeburn 10485: }
10486: }
1.1075.2.35 raeburn 10487: if (($counter) || ($numunused)) {
1.987 raeburn 10488: if ($numpathchg) {
10489: $output .= '<input type ="hidden" name="number_pathchange_items" value="'.
10490: $numpathchg.'" />'."\n";
10491: }
10492: if (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank') ||
10493: ($actionurl eq '/adm/imsimport')) {
10494: $output .= '<input type="hidden" name="phase" value="three" />'."\n";
10495: } elsif ($actionurl eq '/adm/portfolio' || $actionurl eq '/adm/coursegrp_portfolio') {
10496: $output .= '<input type="hidden" name="action" value="upload_embedded" />';
1.1071 raeburn 10497: } elsif ($actionurl eq '/adm/dependencies') {
10498: $output .= '<input type="hidden" name="action" value="process_changes" />';
1.987 raeburn 10499: }
1.1075.2.35 raeburn 10500: $output .= '<input type ="submit" value="'.$buttontext.'" />'."\n".'</form>'."\n";
1.987 raeburn 10501: } elsif ($numpathchg) {
10502: my %pathchange = ();
10503: $output .= &modify_html_form('pathchange',$actionurl,$state,\%pathchange,$pathchange_output);
10504: if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) {
10505: $output .= '<p>'.&mt('or').'</p>';
1.1075.2.35 raeburn 10506: }
1.987 raeburn 10507: }
1.1071 raeburn 10508: return ($output,$counter,$numpathchg);
1.987 raeburn 10509: }
10510:
1.1075.2.47 raeburn 10511: =pod
10512:
10513: =item * clean_path($name)
10514:
10515: Performs clean-up of directories, subdirectories and filename in an
10516: embedded object, referenced in an HTML file which is being uploaded
10517: to a course or portfolio, where
10518: "Upload embedded images/multimedia files if HTML file" checkbox was
10519: checked.
10520:
10521: Clean-up is similar to replacements in lonnet::clean_filename()
10522: except each / between sub-directory and next level is preserved.
10523:
10524: =cut
10525:
10526: sub clean_path {
10527: my ($embed_file) = @_;
10528: $embed_file =~s{^/+}{};
10529: my @contents;
10530: if ($embed_file =~ m{/}) {
10531: @contents = split(/\//,$embed_file);
10532: } else {
10533: @contents = ($embed_file);
10534: }
10535: my $lastidx = scalar(@contents)-1;
10536: for (my $i=0; $i<=$lastidx; $i++) {
10537: $contents[$i]=~s{\\}{/}g;
10538: $contents[$i]=~s/\s+/\_/g;
10539: $contents[$i]=~s{[^/\w\.\-]}{}g;
10540: if ($i == $lastidx) {
10541: $contents[$i]=~s/\.(\d+)(?=\.)/_$1/g;
10542: }
10543: }
10544: if ($lastidx > 0) {
10545: return join('/',@contents);
10546: } else {
10547: return $contents[0];
10548: }
10549: }
10550:
1.987 raeburn 10551: sub embedded_file_element {
1.1071 raeburn 10552: my ($context,$num,$embed_file,$mapping,$allfiles,$codebase,$type) = @_;
1.987 raeburn 10553: return unless ((ref($mapping) eq 'HASH') && (ref($allfiles) eq 'HASH') &&
10554: (ref($codebase) eq 'HASH'));
10555: my $output;
1.1071 raeburn 10556: if (($context eq 'upload_embedded') && ($type ne 'delete')) {
1.987 raeburn 10557: $output = '<input name="embedded_item_'.$num.'" type="file" value="" />'."\n";
10558: }
10559: $output .= '<input name="embedded_orig_'.$num.'" type="hidden" value="'.
10560: &escape($embed_file).'" />';
10561: unless (($context eq 'upload_embedded') &&
10562: ($mapping->{$embed_file} eq $embed_file)) {
10563: $output .='
10564: <input name="embedded_ref_'.$num.'" type="hidden" value="'.&escape($mapping->{$embed_file}).'" />';
10565: }
10566: my $attrib;
10567: if (ref($allfiles->{$mapping->{$embed_file}}) eq 'ARRAY') {
10568: $attrib = &escape(join(':',@{$allfiles->{$mapping->{$embed_file}}}));
10569: }
10570: $output .=
10571: "\n\t\t".
10572: '<input name="embedded_attrib_'.$num.'" type="hidden" value="'.
10573: $attrib.'" />';
10574: if (exists($codebase->{$mapping->{$embed_file}})) {
10575: $output .=
10576: "\n\t\t".
10577: '<input name="codebase_'.$num.'" type="hidden" value="'.
10578: &escape($codebase->{$mapping->{$embed_file}}).'" />';
1.984 raeburn 10579: }
1.987 raeburn 10580: return $output;
1.660 raeburn 10581: }
10582:
1.1071 raeburn 10583: sub get_dependency_details {
10584: my ($currfile,$currsubfile,$embed_file) = @_;
10585: my ($size,$mtime,$showsize,$showmtime);
10586: if ((ref($currfile) eq 'HASH') && (ref($currsubfile))) {
10587: if ($embed_file =~ m{/}) {
10588: my ($path,$fname) = split(/\//,$embed_file);
10589: if (ref($currsubfile->{$path}{$fname}) eq 'ARRAY') {
10590: ($size,$mtime) = @{$currsubfile->{$path}{$fname}};
10591: }
10592: } else {
10593: if (ref($currfile->{$embed_file}) eq 'ARRAY') {
10594: ($size,$mtime) = @{$currfile->{$embed_file}};
10595: }
10596: }
10597: $showsize = $size/1024.0;
10598: $showsize = sprintf("%.1f",$showsize);
10599: if ($mtime > 0) {
10600: $showmtime = &Apache::lonlocal::locallocaltime($mtime);
10601: }
10602: }
10603: return ($showsize,$showmtime);
10604: }
10605:
10606: sub ask_embedded_js {
10607: return <<"END";
10608: <script type="text/javascript"">
10609: // <![CDATA[
10610: function toggleBrowse(counter) {
10611: var chkboxid = document.getElementById('mod_upload_dep_'+counter);
10612: var fileid = document.getElementById('embedded_item_'+counter);
10613: var uploaddivid = document.getElementById('moduploaddep_'+counter);
10614: if (chkboxid.checked == true) {
10615: uploaddivid.style.display='block';
10616: } else {
10617: uploaddivid.style.display='none';
10618: fileid.value = '';
10619: }
10620: }
10621: // ]]>
10622: </script>
10623:
10624: END
10625: }
10626:
1.661 raeburn 10627: sub upload_embedded {
10628: my ($context,$dirpath,$uname,$udom,$dir_root,$url_root,$group,$disk_quota,
1.987 raeburn 10629: $current_disk_usage,$hiddenstate,$actionurl) = @_;
10630: my (%pathchange,$output,$modifyform,$footer,$returnflag);
1.661 raeburn 10631: for (my $i=0; $i<$env{'form.number_embedded_items'}; $i++) {
10632: next if (!exists($env{'form.embedded_item_'.$i.'.filename'}));
10633: my $orig_uploaded_filename =
10634: $env{'form.embedded_item_'.$i.'.filename'};
1.987 raeburn 10635: foreach my $type ('orig','ref','attrib','codebase') {
10636: if ($env{'form.embedded_'.$type.'_'.$i} ne '') {
10637: $env{'form.embedded_'.$type.'_'.$i} =
10638: &unescape($env{'form.embedded_'.$type.'_'.$i});
10639: }
10640: }
1.661 raeburn 10641: my ($path,$fname) =
10642: ($env{'form.embedded_orig_'.$i} =~ m{(.*/)([^/]*)});
10643: # no path, whole string is fname
10644: if (!$fname) { $fname = $env{'form.embedded_orig_'.$i} };
10645: $fname = &Apache::lonnet::clean_filename($fname);
10646: # See if there is anything left
10647: next if ($fname eq '');
10648:
10649: # Check if file already exists as a file or directory.
10650: my ($state,$msg);
10651: if ($context eq 'portfolio') {
10652: my $port_path = $dirpath;
10653: if ($group ne '') {
10654: $port_path = "groups/$group/$port_path";
10655: }
1.987 raeburn 10656: ($state,$msg) = &check_for_upload($env{'form.currentpath'}.$path,
10657: $fname,$group,'embedded_item_'.$i,
1.661 raeburn 10658: $dir_root,$port_path,$disk_quota,
10659: $current_disk_usage,$uname,$udom);
10660: if ($state eq 'will_exceed_quota'
1.984 raeburn 10661: || $state eq 'file_locked') {
1.661 raeburn 10662: $output .= $msg;
10663: next;
10664: }
10665: } elsif (($context eq 'author') || ($context eq 'testbank')) {
10666: ($state,$msg) = &check_for_existing($path,$fname,'embedded_item_'.$i);
10667: if ($state eq 'exists') {
10668: $output .= $msg;
10669: next;
10670: }
10671: }
10672: # Check if extension is valid
10673: if (($fname =~ /\.(\w+)$/) &&
10674: (&Apache::loncommon::fileembstyle($1) eq 'hdn')) {
1.1075.2.53 raeburn 10675: $output .= &mt('Invalid file extension ([_1]) - reserved for internal use.',$1)
10676: .' '.&mt('Rename the file with a different extension and re-upload.').'<br />';
1.661 raeburn 10677: next;
10678: } elsif (($fname =~ /\.(\w+)$/) &&
10679: (!defined(&Apache::loncommon::fileembstyle($1)))) {
1.987 raeburn 10680: $output .= &mt('Unrecognized file extension ([_1]) - rename the file with a proper extension and re-upload.',$1).'<br />';
1.661 raeburn 10681: next;
10682: } elsif ($fname=~/\.(\d+)\.(\w+)$/) {
1.1075.2.34 raeburn 10683: $output .= &mt('Filename not allowed - rename the file to remove the number immediately before the file extension([_1]) and re-upload.',$2).'<br />';
1.661 raeburn 10684: next;
10685: }
10686: $env{'form.embedded_item_'.$i.'.filename'}=$fname;
1.1075.2.35 raeburn 10687: my $subdir = $path;
10688: $subdir =~ s{/+$}{};
1.661 raeburn 10689: if ($context eq 'portfolio') {
1.984 raeburn 10690: my $result;
10691: if ($state eq 'existingfile') {
10692: $result=
10693: &Apache::lonnet::userfileupload('embedded_item_'.$i,'existingfile',
1.1075.2.35 raeburn 10694: $dirpath.$env{'form.currentpath'}.$subdir);
1.661 raeburn 10695: } else {
1.984 raeburn 10696: $result=
10697: &Apache::lonnet::userfileupload('embedded_item_'.$i,'',
1.987 raeburn 10698: $dirpath.
1.1075.2.35 raeburn 10699: $env{'form.currentpath'}.$subdir);
1.984 raeburn 10700: if ($result !~ m|^/uploaded/|) {
10701: $output .= '<span class="LC_error">'
10702: .&mt('An error occurred ([_1]) while trying to upload [_2] for embedded element [_3].'
10703: ,$result,$orig_uploaded_filename,$env{'form.embedded_orig_'.$i})
10704: .'</span><br />';
10705: next;
10706: } else {
1.987 raeburn 10707: $output .= &mt('Uploaded [_1]','<span class="LC_filename">'.
10708: $path.$fname.'</span>').'<br />';
1.984 raeburn 10709: }
1.661 raeburn 10710: }
1.1075.2.35 raeburn 10711: } elsif (($context eq 'coursedoc') || ($context eq 'syllabus')) {
10712: my $extendedsubdir = $dirpath.'/'.$subdir;
10713: $extendedsubdir =~ s{/+$}{};
1.987 raeburn 10714: my $result =
1.1075.2.35 raeburn 10715: &Apache::lonnet::userfileupload('embedded_item_'.$i,$context,$extendedsubdir);
1.987 raeburn 10716: if ($result !~ m|^/uploaded/|) {
10717: $output .= '<span class="LC_error">'
10718: .&mt('An error occurred ([_1]) while trying to upload [_2] for embedded element [_3].'
10719: ,$result,$orig_uploaded_filename,$env{'form.embedded_orig_'.$i})
10720: .'</span><br />';
10721: next;
10722: } else {
10723: $output .= &mt('Uploaded [_1]','<span class="LC_filename">'.
10724: $path.$fname.'</span>').'<br />';
1.1075.2.35 raeburn 10725: if ($context eq 'syllabus') {
10726: &Apache::lonnet::make_public_indefinitely($result);
10727: }
1.987 raeburn 10728: }
1.661 raeburn 10729: } else {
10730: # Save the file
10731: my $target = $env{'form.embedded_item_'.$i};
10732: my $fullpath = $dir_root.$dirpath.'/'.$path;
10733: my $dest = $fullpath.$fname;
10734: my $url = $url_root.$dirpath.'/'.$path.$fname;
1.1027 raeburn 10735: my @parts=split(/\//,"$dirpath/$path");
1.661 raeburn 10736: my $count;
10737: my $filepath = $dir_root;
1.1027 raeburn 10738: foreach my $subdir (@parts) {
10739: $filepath .= "/$subdir";
10740: if (!-e $filepath) {
1.661 raeburn 10741: mkdir($filepath,0770);
10742: }
10743: }
10744: my $fh;
10745: if (!open($fh,'>'.$dest)) {
10746: &Apache::lonnet::logthis('Failed to create '.$dest);
10747: $output .= '<span class="LC_error">'.
1.1071 raeburn 10748: &mt('An error occurred while trying to upload [_1] for embedded element [_2].',
10749: $orig_uploaded_filename,$env{'form.embedded_orig_'.$i}).
1.661 raeburn 10750: '</span><br />';
10751: } else {
10752: if (!print $fh $env{'form.embedded_item_'.$i}) {
10753: &Apache::lonnet::logthis('Failed to write to '.$dest);
10754: $output .= '<span class="LC_error">'.
1.1071 raeburn 10755: &mt('An error occurred while writing the file [_1] for embedded element [_2].',
10756: $orig_uploaded_filename,$env{'form.embedded_orig_'.$i}).
1.661 raeburn 10757: '</span><br />';
10758: } else {
1.987 raeburn 10759: $output .= &mt('Uploaded [_1]','<span class="LC_filename">'.
10760: $url.'</span>').'<br />';
10761: unless ($context eq 'testbank') {
10762: $footer .= &mt('View embedded file: [_1]',
10763: '<a href="'.$url.'">'.$fname.'</a>').'<br />';
10764: }
10765: }
10766: close($fh);
10767: }
10768: }
10769: if ($env{'form.embedded_ref_'.$i}) {
10770: $pathchange{$i} = 1;
10771: }
10772: }
10773: if ($output) {
10774: $output = '<p>'.$output.'</p>';
10775: }
10776: $output .= &modify_html_form('upload_embedded',$actionurl,$hiddenstate,\%pathchange);
10777: $returnflag = 'ok';
1.1071 raeburn 10778: my $numpathchgs = scalar(keys(%pathchange));
10779: if ($numpathchgs > 0) {
1.987 raeburn 10780: if ($context eq 'portfolio') {
10781: $output .= '<p>'.&mt('or').'</p>';
10782: } elsif ($context eq 'testbank') {
1.1071 raeburn 10783: $output .= '<p>'.&mt('Or [_1]continue[_2] the testbank import without modifying the reference(s).',
10784: '<a href="javascript:document.testbankForm.submit();">','</a>').'</p>';
1.987 raeburn 10785: $returnflag = 'modify_orightml';
10786: }
10787: }
1.1071 raeburn 10788: return ($output.$footer,$returnflag,$numpathchgs);
1.987 raeburn 10789: }
10790:
10791: sub modify_html_form {
10792: my ($context,$actionurl,$hiddenstate,$pathchange,$pathchgtable) = @_;
10793: my $end = 0;
10794: my $modifyform;
10795: if ($context eq 'upload_embedded') {
10796: return unless (ref($pathchange) eq 'HASH');
10797: if ($env{'form.number_embedded_items'}) {
10798: $end += $env{'form.number_embedded_items'};
10799: }
10800: if ($env{'form.number_pathchange_items'}) {
10801: $end += $env{'form.number_pathchange_items'};
10802: }
10803: if ($end) {
10804: for (my $i=0; $i<$end; $i++) {
10805: if ($i < $env{'form.number_embedded_items'}) {
10806: next unless($pathchange->{$i});
10807: }
10808: $modifyform .=
10809: &start_data_table_row().
10810: '<td><input type ="checkbox" name="namechange" value="'.$i.'" '.
10811: 'checked="checked" /></td>'.
10812: '<td>'.$env{'form.embedded_ref_'.$i}.
10813: '<input type="hidden" name="embedded_ref_'.$i.'" value="'.
10814: &escape($env{'form.embedded_ref_'.$i}).'" />'.
10815: '<input type="hidden" name="embedded_codebase_'.$i.'" value="'.
10816: &escape($env{'form.embedded_codebase_'.$i}).'" />'.
10817: '<input type="hidden" name="embedded_attrib_'.$i.'" value="'.
10818: &escape($env{'form.embedded_attrib_'.$i}).'" /></td>'.
10819: '<td>'.$env{'form.embedded_orig_'.$i}.
10820: '<input type="hidden" name="embedded_orig_'.$i.'" value="'.
10821: &escape($env{'form.embedded_orig_'.$i}).'" /></td>'.
10822: &end_data_table_row();
1.1071 raeburn 10823: }
1.987 raeburn 10824: }
10825: } else {
10826: $modifyform = $pathchgtable;
10827: if (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank')) {
10828: $hiddenstate .= '<input type="hidden" name="phase" value="four" />';
10829: } elsif (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) {
10830: $hiddenstate .= '<input type="hidden" name="action" value="modify_orightml" />';
10831: }
10832: }
10833: if ($modifyform) {
1.1071 raeburn 10834: if ($actionurl eq '/adm/dependencies') {
10835: $hiddenstate .= '<input type="hidden" name="action" value="modifyhrefs" />';
10836: }
1.987 raeburn 10837: return '<h3>'.&mt('Changes in content of HTML file required').'</h3>'."\n".
10838: '<p>'.&mt('Changes need to be made to the reference(s) used for one or more of the dependencies, if your HTML file is to work correctly:').'<ol>'."\n".
10839: '<li>'.&mt('For consistency between the reference(s) and the location of the corresponding stored file within LON-CAPA.').'</li>'."\n".
10840: '<li>'.&mt('To change absolute paths to relative paths, or replace directory traversal via "../" within the original reference.').'</li>'."\n".
10841: '</ol></p>'."\n".'<p>'.
10842: &mt('LON-CAPA can make the required changes to your HTML file.').'</p>'."\n".
10843: '<form method="post" name="refchanger" action="'.$actionurl.'">'.
10844: &start_data_table()."\n".
10845: &start_data_table_header_row().
10846: '<th>'.&mt('Change?').'</th>'.
10847: '<th>'.&mt('Current reference').'</th>'.
10848: '<th>'.&mt('Required reference').'</th>'.
10849: &end_data_table_header_row()."\n".
10850: $modifyform.
10851: &end_data_table().'<br />'."\n".$hiddenstate.
10852: '<input type="submit" name="pathchanges" value="'.&mt('Modify HTML file').'" />'.
10853: '</form>'."\n";
10854: }
10855: return;
10856: }
10857:
10858: sub modify_html_refs {
1.1075.2.35 raeburn 10859: my ($context,$dirpath,$uname,$udom,$dir_root,$url) = @_;
1.987 raeburn 10860: my $container;
10861: if ($context eq 'portfolio') {
10862: $container = $env{'form.container'};
10863: } elsif ($context eq 'coursedoc') {
10864: $container = $env{'form.primaryurl'};
1.1071 raeburn 10865: } elsif ($context eq 'manage_dependencies') {
10866: (undef,undef,$container) = &Apache::lonnet::decode_symb($env{'form.symb'});
10867: $container = "/$container";
1.1075.2.35 raeburn 10868: } elsif ($context eq 'syllabus') {
10869: $container = $url;
1.987 raeburn 10870: } else {
1.1027 raeburn 10871: $container = $Apache::lonnet::perlvar{'lonDocRoot'}.$env{'form.filename'};
1.987 raeburn 10872: }
10873: my (%allfiles,%codebase,$output,$content);
10874: my @changes = &get_env_multiple('form.namechange');
1.1075.2.35 raeburn 10875: unless ((@changes > 0) || ($context eq 'syllabus')) {
1.1071 raeburn 10876: if (wantarray) {
10877: return ('',0,0);
10878: } else {
10879: return;
10880: }
10881: }
10882: if (($context eq 'portfolio') || ($context eq 'coursedoc') ||
1.1075.2.35 raeburn 10883: ($context eq 'manage_dependencies') || ($context eq 'syllabus')) {
1.1071 raeburn 10884: unless ($container =~ m{^/uploaded/\Q$udom\E/\Q$uname\E/}) {
10885: if (wantarray) {
10886: return ('',0,0);
10887: } else {
10888: return;
10889: }
10890: }
1.987 raeburn 10891: $content = &Apache::lonnet::getfile($container);
1.1071 raeburn 10892: if ($content eq '-1') {
10893: if (wantarray) {
10894: return ('',0,0);
10895: } else {
10896: return;
10897: }
10898: }
1.987 raeburn 10899: } else {
1.1071 raeburn 10900: unless ($container =~ /^\Q$dir_root\E/) {
10901: if (wantarray) {
10902: return ('',0,0);
10903: } else {
10904: return;
10905: }
10906: }
1.987 raeburn 10907: if (open(my $fh,"<$container")) {
10908: $content = join('', <$fh>);
10909: close($fh);
10910: } else {
1.1071 raeburn 10911: if (wantarray) {
10912: return ('',0,0);
10913: } else {
10914: return;
10915: }
1.987 raeburn 10916: }
10917: }
10918: my ($count,$codebasecount) = (0,0);
10919: my $mm = new File::MMagic;
10920: my $mime_type = $mm->checktype_contents($content);
10921: if ($mime_type eq 'text/html') {
10922: my $parse_result =
10923: &Apache::lonnet::extract_embedded_items($container,\%allfiles,
10924: \%codebase,\$content);
10925: if ($parse_result eq 'ok') {
10926: foreach my $i (@changes) {
10927: my $orig = &unescape($env{'form.embedded_orig_'.$i});
10928: my $ref = &unescape($env{'form.embedded_ref_'.$i});
10929: if ($allfiles{$ref}) {
10930: my $newname = $orig;
10931: my ($attrib_regexp,$codebase);
1.1006 raeburn 10932: $attrib_regexp = &unescape($env{'form.embedded_attrib_'.$i});
1.987 raeburn 10933: if ($attrib_regexp =~ /:/) {
10934: $attrib_regexp =~ s/\:/|/g;
10935: }
10936: if ($content =~ m{($attrib_regexp\s*=\s*['"]?)\Q$ref\E(['"]?)}) {
10937: my $numchg = ($content =~ s{($attrib_regexp\s*=\s*['"]?)\Q$ref\E(['"]?)}{$1$newname$2}gi);
10938: $count += $numchg;
1.1075.2.35 raeburn 10939: $allfiles{$newname} = $allfiles{$ref};
1.1075.2.48 raeburn 10940: delete($allfiles{$ref});
1.987 raeburn 10941: }
10942: if ($env{'form.embedded_codebase_'.$i} ne '') {
1.1006 raeburn 10943: $codebase = &unescape($env{'form.embedded_codebase_'.$i});
1.987 raeburn 10944: my $numchg = ($content =~ s/(codebase\s*=\s*["']?)\Q$codebase\E(["']?)/$1.$2/i); #' stupid emacs
10945: $codebasecount ++;
10946: }
10947: }
10948: }
1.1075.2.35 raeburn 10949: my $skiprewrites;
1.987 raeburn 10950: if ($count || $codebasecount) {
10951: my $saveresult;
1.1071 raeburn 10952: if (($context eq 'portfolio') || ($context eq 'coursedoc') ||
1.1075.2.35 raeburn 10953: ($context eq 'manage_dependencies') || ($context eq 'syllabus')) {
1.987 raeburn 10954: my $url = &Apache::lonnet::store_edited_file($container,$content,$udom,$uname,\$saveresult);
10955: if ($url eq $container) {
10956: my ($fname) = ($container =~ m{/([^/]+)$});
10957: $output = '<p>'.&mt('Updated [quant,_1,reference] in [_2].',
10958: $count,'<span class="LC_filename">'.
1.1071 raeburn 10959: $fname.'</span>').'</p>';
1.987 raeburn 10960: } else {
10961: $output = '<p class="LC_error">'.
10962: &mt('Error: update failed for: [_1].',
10963: '<span class="LC_filename">'.
10964: $container.'</span>').'</p>';
10965: }
1.1075.2.35 raeburn 10966: if ($context eq 'syllabus') {
10967: unless ($saveresult eq 'ok') {
10968: $skiprewrites = 1;
10969: }
10970: }
1.987 raeburn 10971: } else {
10972: if (open(my $fh,">$container")) {
10973: print $fh $content;
10974: close($fh);
10975: $output = '<p>'.&mt('Updated [quant,_1,reference] in [_2].',
10976: $count,'<span class="LC_filename">'.
10977: $container.'</span>').'</p>';
1.661 raeburn 10978: } else {
1.987 raeburn 10979: $output = '<p class="LC_error">'.
10980: &mt('Error: could not update [_1].',
10981: '<span class="LC_filename">'.
10982: $container.'</span>').'</p>';
1.661 raeburn 10983: }
10984: }
10985: }
1.1075.2.35 raeburn 10986: if (($context eq 'syllabus') && (!$skiprewrites)) {
10987: my ($actionurl,$state);
10988: $actionurl = "/public/$udom/$uname/syllabus";
10989: my ($ignore,$num,$numpathchanges,$existing,$mapping) =
10990: &ask_for_embedded_content($actionurl,$state,\%allfiles,
10991: \%codebase,
10992: {'context' => 'rewrites',
10993: 'ignore_remote_references' => 1,});
10994: if (ref($mapping) eq 'HASH') {
10995: my $rewrites = 0;
10996: foreach my $key (keys(%{$mapping})) {
10997: next if ($key =~ m{^https?://});
10998: my $ref = $mapping->{$key};
10999: my $newname = "/uploaded/$udom/$uname/portfolio/syllabus/$key";
11000: my $attrib;
11001: if (ref($allfiles{$mapping->{$key}}) eq 'ARRAY') {
11002: $attrib = join('|',@{$allfiles{$mapping->{$key}}});
11003: }
11004: if ($content =~ m{($attrib\s*=\s*['"]?)\Q$ref\E(['"]?)}) {
11005: my $numchg = ($content =~ s{($attrib\s*=\s*['"]?)\Q$ref\E(['"]?)}{$1$newname$2}gi);
11006: $rewrites += $numchg;
11007: }
11008: }
11009: if ($rewrites) {
11010: my $saveresult;
11011: my $url = &Apache::lonnet::store_edited_file($container,$content,$udom,$uname,\$saveresult);
11012: if ($url eq $container) {
11013: my ($fname) = ($container =~ m{/([^/]+)$});
11014: $output .= '<p>'.&mt('Rewrote [quant,_1,link] as [quant,_1,absolute link] in [_2].',
11015: $count,'<span class="LC_filename">'.
11016: $fname.'</span>').'</p>';
11017: } else {
11018: $output .= '<p class="LC_error">'.
11019: &mt('Error: could not update links in [_1].',
11020: '<span class="LC_filename">'.
11021: $container.'</span>').'</p>';
11022:
11023: }
11024: }
11025: }
11026: }
1.987 raeburn 11027: } else {
11028: &logthis('Failed to parse '.$container.
11029: ' to modify references: '.$parse_result);
1.661 raeburn 11030: }
11031: }
1.1071 raeburn 11032: if (wantarray) {
11033: return ($output,$count,$codebasecount);
11034: } else {
11035: return $output;
11036: }
1.661 raeburn 11037: }
11038:
11039: sub check_for_existing {
11040: my ($path,$fname,$element) = @_;
11041: my ($state,$msg);
11042: if (-d $path.'/'.$fname) {
11043: $state = 'exists';
11044: $msg = &mt('Unable to upload [_1]. A directory by that name was found in [_2].','<span class="LC_filename">'.$fname.'</span>',$path);
11045: } elsif (-e $path.'/'.$fname) {
11046: $state = 'exists';
11047: $msg = &mt('Unable to upload [_1]. A file by that name was found in [_2].','<span class="LC_filename">'.$fname.'</span>',$path);
11048: }
11049: if ($state eq 'exists') {
11050: $msg = '<span class="LC_error">'.$msg.'</span><br />';
11051: }
11052: return ($state,$msg);
11053: }
11054:
11055: sub check_for_upload {
11056: my ($path,$fname,$group,$element,$portfolio_root,$port_path,
11057: $disk_quota,$current_disk_usage,$uname,$udom) = @_;
1.985 raeburn 11058: my $filesize = length($env{'form.'.$element});
11059: if (!$filesize) {
11060: my $msg = '<span class="LC_error">'.
11061: &mt('Unable to upload [_1]. (size = [_2] bytes)',
11062: '<span class="LC_filename">'.$fname.'</span>',
11063: $filesize).'<br />'.
1.1007 raeburn 11064: &mt('Either the file you attempted to upload was empty, or your web browser was unable to read its contents.').'<br />'.
1.985 raeburn 11065: '</span>';
11066: return ('zero_bytes',$msg);
11067: }
11068: $filesize = $filesize/1000; #express in k (1024?)
1.661 raeburn 11069: my $getpropath = 1;
1.1021 raeburn 11070: my ($dirlistref,$listerror) =
11071: &Apache::lonnet::dirlist($portfolio_root.$path,$udom,$uname,$getpropath);
1.661 raeburn 11072: my $found_file = 0;
11073: my $locked_file = 0;
1.991 raeburn 11074: my @lockers;
11075: my $navmap;
11076: if ($env{'request.course.id'}) {
11077: $navmap = Apache::lonnavmaps::navmap->new();
11078: }
1.1021 raeburn 11079: if (ref($dirlistref) eq 'ARRAY') {
11080: foreach my $line (@{$dirlistref}) {
11081: my ($file_name,$rest)=split(/\&/,$line,2);
11082: if ($file_name eq $fname){
11083: $file_name = $path.$file_name;
11084: if ($group ne '') {
11085: $file_name = $group.$file_name;
11086: }
11087: $found_file = 1;
11088: if (&Apache::lonnet::is_locked($file_name,$udom,$uname,\@lockers) eq 'true') {
11089: foreach my $lock (@lockers) {
11090: if (ref($lock) eq 'ARRAY') {
11091: my ($symb,$crsid) = @{$lock};
11092: if ($crsid eq $env{'request.course.id'}) {
11093: if (ref($navmap)) {
11094: my $res = $navmap->getBySymb($symb);
11095: foreach my $part (@{$res->parts()}) {
11096: my ($slot_status,$slot_time,$slot_name)=$res->check_for_slot($part);
11097: unless (($slot_status == $res->RESERVED) ||
11098: ($slot_status == $res->RESERVED_LOCATION)) {
11099: $locked_file = 1;
11100: }
1.991 raeburn 11101: }
1.1021 raeburn 11102: } else {
11103: $locked_file = 1;
1.991 raeburn 11104: }
11105: } else {
11106: $locked_file = 1;
11107: }
11108: }
1.1021 raeburn 11109: }
11110: } else {
11111: my @info = split(/\&/,$rest);
11112: my $currsize = $info[6]/1000;
11113: if ($currsize < $filesize) {
11114: my $extra = $filesize - $currsize;
11115: if (($current_disk_usage + $extra) > $disk_quota) {
1.1075.2.69 raeburn 11116: my $msg = '<p class="LC_warning">'.
1.1021 raeburn 11117: &mt('Unable to upload [_1]. (size = [_2] kilobytes). Disk quota will be exceeded if existing (smaller) file with same name (size = [_3] kilobytes) is replaced.',
1.1075.2.69 raeburn 11118: '<span class="LC_filename">'.$fname.'</span>',$filesize,$currsize).'</p>'.
11119: '<p>'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.',
11120: $disk_quota,$current_disk_usage).'</p>';
1.1021 raeburn 11121: return ('will_exceed_quota',$msg);
11122: }
1.984 raeburn 11123: }
11124: }
1.661 raeburn 11125: }
11126: }
11127: }
11128: if (($current_disk_usage + $filesize) > $disk_quota){
1.1075.2.69 raeburn 11129: my $msg = '<p class="LC_warning">'.
11130: &mt('Unable to upload [_1]. (size = [_2] kilobytes). Disk quota will be exceeded.','<span class="LC_filename">'.$fname.'</span>',$filesize).'</p>'.
11131: '<p>'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.',$disk_quota,$current_disk_usage).'</p>';
1.661 raeburn 11132: return ('will_exceed_quota',$msg);
11133: } elsif ($found_file) {
11134: if ($locked_file) {
1.1075.2.69 raeburn 11135: my $msg = '<p class="LC_warning">';
1.661 raeburn 11136: $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>');
1.1075.2.69 raeburn 11137: $msg .= '</p>';
1.661 raeburn 11138: $msg .= &mt('You will be able to rename or delete existing [_1] after a grade has been assigned.','<span class="LC_filename">'.$fname.'</span>');
11139: return ('file_locked',$msg);
11140: } else {
1.1075.2.69 raeburn 11141: my $msg = '<p class="LC_error">';
1.984 raeburn 11142: $msg .= &mt(' A file by that name: [_1] was found in [_2].','<span class="LC_filename">'.$fname.'</span>',$port_path.$env{'form.currentpath'});
1.1075.2.69 raeburn 11143: $msg .= '</p>';
1.984 raeburn 11144: return ('existingfile',$msg);
1.661 raeburn 11145: }
11146: }
11147: }
11148:
1.987 raeburn 11149: sub check_for_traversal {
11150: my ($path,$url,$toplevel) = @_;
11151: my @parts=split(/\//,$path);
11152: my $cleanpath;
11153: my $fullpath = $url;
11154: for (my $i=0;$i<@parts;$i++) {
11155: next if ($parts[$i] eq '.');
11156: if ($parts[$i] eq '..') {
11157: $fullpath =~ s{([^/]+/)$}{};
11158: } else {
11159: $fullpath .= $parts[$i].'/';
11160: }
11161: }
11162: if ($fullpath =~ /^\Q$url\E(.*)$/) {
11163: $cleanpath = $1;
11164: } elsif ($fullpath =~ /^\Q$toplevel\E(.*)$/) {
11165: my $curr_toprel = $1;
11166: my @parts = split(/\//,$curr_toprel);
11167: my ($url_toprel) = ($url =~ /^\Q$toplevel\E(.*)$/);
11168: my @urlparts = split(/\//,$url_toprel);
11169: my $doubledots;
11170: my $startdiff = -1;
11171: for (my $i=0; $i<@urlparts; $i++) {
11172: if ($startdiff == -1) {
11173: unless ($urlparts[$i] eq $parts[$i]) {
11174: $startdiff = $i;
11175: $doubledots .= '../';
11176: }
11177: } else {
11178: $doubledots .= '../';
11179: }
11180: }
11181: if ($startdiff > -1) {
11182: $cleanpath = $doubledots;
11183: for (my $i=$startdiff; $i<@parts; $i++) {
11184: $cleanpath .= $parts[$i].'/';
11185: }
11186: }
11187: }
11188: $cleanpath =~ s{(/)$}{};
11189: return $cleanpath;
11190: }
1.31 albertel 11191:
1.1053 raeburn 11192: sub is_archive_file {
11193: my ($mimetype) = @_;
11194: if (($mimetype eq 'application/octet-stream') ||
11195: ($mimetype eq 'application/x-stuffit') ||
11196: ($mimetype =~ m{^application/(x\-)?(compressed|tar|zip|tgz|gz|gtar|gzip|gunzip|bz|bz2|bzip2)})) {
11197: return 1;
11198: }
11199: return;
11200: }
11201:
11202: sub decompress_form {
1.1065 raeburn 11203: my ($mimetype,$archiveurl,$action,$noextract,$hiddenelements,$dirlist) = @_;
1.1053 raeburn 11204: my %lt = &Apache::lonlocal::texthash (
11205: this => 'This file is an archive file.',
1.1067 raeburn 11206: camt => 'This file is a Camtasia archive file.',
1.1065 raeburn 11207: itsc => 'Its contents are as follows:',
1.1053 raeburn 11208: youm => 'You may wish to extract its contents.',
11209: extr => 'Extract contents',
1.1067 raeburn 11210: auto => 'LON-CAPA can process the files automatically, or you can decide how each should be handled.',
11211: proa => 'Process automatically?',
1.1053 raeburn 11212: yes => 'Yes',
11213: no => 'No',
1.1067 raeburn 11214: fold => 'Title for folder containing movie',
11215: movi => 'Title for page containing embedded movie',
1.1053 raeburn 11216: );
1.1065 raeburn 11217: my $fileloc = &Apache::lonnet::filelocation(undef,$archiveurl);
1.1067 raeburn 11218: my ($is_camtasia,$topdir,%toplevel,@paths);
1.1065 raeburn 11219: my $info = &list_archive_contents($fileloc,\@paths);
11220: if (@paths) {
11221: foreach my $path (@paths) {
11222: $path =~ s{^/}{};
1.1067 raeburn 11223: if ($path =~ m{^([^/]+)/$}) {
11224: $topdir = $1;
11225: }
1.1065 raeburn 11226: if ($path =~ m{^([^/]+)/}) {
11227: $toplevel{$1} = $path;
11228: } else {
11229: $toplevel{$path} = $path;
11230: }
11231: }
11232: }
1.1067 raeburn 11233: if ($mimetype =~ m{^application/(x\-)?(compressed|zip)}) {
1.1075.2.59 raeburn 11234: my @camtasia6 = ("$topdir/","$topdir/index.html",
1.1067 raeburn 11235: "$topdir/media/",
11236: "$topdir/media/$topdir.mp4",
11237: "$topdir/media/FirstFrame.png",
11238: "$topdir/media/player.swf",
11239: "$topdir/media/swfobject.js",
11240: "$topdir/media/expressInstall.swf");
1.1075.2.81 raeburn 11241: my @camtasia8_1 = ("$topdir/","$topdir/$topdir.html",
1.1075.2.59 raeburn 11242: "$topdir/$topdir.mp4",
11243: "$topdir/$topdir\_config.xml",
11244: "$topdir/$topdir\_controller.swf",
11245: "$topdir/$topdir\_embed.css",
11246: "$topdir/$topdir\_First_Frame.png",
11247: "$topdir/$topdir\_player.html",
11248: "$topdir/$topdir\_Thumbnails.png",
11249: "$topdir/playerProductInstall.swf",
11250: "$topdir/scripts/",
11251: "$topdir/scripts/config_xml.js",
11252: "$topdir/scripts/handlebars.js",
11253: "$topdir/scripts/jquery-1.7.1.min.js",
11254: "$topdir/scripts/jquery-ui-1.8.15.custom.min.js",
11255: "$topdir/scripts/modernizr.js",
11256: "$topdir/scripts/player-min.js",
11257: "$topdir/scripts/swfobject.js",
11258: "$topdir/skins/",
11259: "$topdir/skins/configuration_express.xml",
11260: "$topdir/skins/express_show/",
11261: "$topdir/skins/express_show/player-min.css",
11262: "$topdir/skins/express_show/spritesheet.png");
1.1075.2.81 raeburn 11263: my @camtasia8_4 = ("$topdir/","$topdir/$topdir.html",
11264: "$topdir/$topdir.mp4",
11265: "$topdir/$topdir\_config.xml",
11266: "$topdir/$topdir\_controller.swf",
11267: "$topdir/$topdir\_embed.css",
11268: "$topdir/$topdir\_First_Frame.png",
11269: "$topdir/$topdir\_player.html",
11270: "$topdir/$topdir\_Thumbnails.png",
11271: "$topdir/playerProductInstall.swf",
11272: "$topdir/scripts/",
11273: "$topdir/scripts/config_xml.js",
11274: "$topdir/scripts/techsmith-smart-player.min.js",
11275: "$topdir/skins/",
11276: "$topdir/skins/configuration_express.xml",
11277: "$topdir/skins/express_show/",
11278: "$topdir/skins/express_show/spritesheet.min.css",
11279: "$topdir/skins/express_show/spritesheet.png",
11280: "$topdir/skins/express_show/techsmith-smart-player.min.css");
1.1075.2.59 raeburn 11281: my @diffs = &compare_arrays(\@paths,\@camtasia6);
1.1067 raeburn 11282: if (@diffs == 0) {
1.1075.2.59 raeburn 11283: $is_camtasia = 6;
11284: } else {
1.1075.2.81 raeburn 11285: @diffs = &compare_arrays(\@paths,\@camtasia8_1);
1.1075.2.59 raeburn 11286: if (@diffs == 0) {
11287: $is_camtasia = 8;
1.1075.2.81 raeburn 11288: } else {
11289: @diffs = &compare_arrays(\@paths,\@camtasia8_4);
11290: if (@diffs == 0) {
11291: $is_camtasia = 8;
11292: }
1.1075.2.59 raeburn 11293: }
1.1067 raeburn 11294: }
11295: }
11296: my $output;
11297: if ($is_camtasia) {
11298: $output = <<"ENDCAM";
11299: <script type="text/javascript" language="Javascript">
11300: // <![CDATA[
11301:
11302: function camtasiaToggle() {
11303: for (var i=0; i<document.uploaded_decompress.autoextract_camtasia.length; i++) {
11304: if (document.uploaded_decompress.autoextract_camtasia[i].checked) {
1.1075.2.59 raeburn 11305: if (document.uploaded_decompress.autoextract_camtasia[i].value == $is_camtasia) {
1.1067 raeburn 11306: document.getElementById('camtasia_titles').style.display='block';
11307: } else {
11308: document.getElementById('camtasia_titles').style.display='none';
11309: }
11310: }
11311: }
11312: return;
11313: }
11314:
11315: // ]]>
11316: </script>
11317: <p>$lt{'camt'}</p>
11318: ENDCAM
1.1065 raeburn 11319: } else {
1.1067 raeburn 11320: $output = '<p>'.$lt{'this'};
11321: if ($info eq '') {
11322: $output .= ' '.$lt{'youm'}.'</p>'."\n";
11323: } else {
11324: $output .= ' '.$lt{'itsc'}.'</p>'."\n".
11325: '<div><pre>'.$info.'</pre></div>';
11326: }
1.1065 raeburn 11327: }
1.1067 raeburn 11328: $output .= '<form name="uploaded_decompress" action="'.$action.'" method="post">'."\n";
1.1065 raeburn 11329: my $duplicates;
11330: my $num = 0;
11331: if (ref($dirlist) eq 'ARRAY') {
11332: foreach my $item (@{$dirlist}) {
11333: if (ref($item) eq 'ARRAY') {
11334: if (exists($toplevel{$item->[0]})) {
11335: $duplicates .=
11336: &start_data_table_row().
11337: '<td><label><input type="radio" name="archive_overwrite_'.$num.'" '.
11338: 'value="0" checked="checked" />'.&mt('No').'</label>'.
11339: ' <label><input type="radio" name="archive_overwrite_'.$num.'" '.
11340: 'value="1" />'.&mt('Yes').'</label>'.
11341: '<input type="hidden" name="archive_overwrite_name_'.$num.'" value="'.$item->[0].'" /></td>'."\n".
11342: '<td>'.$item->[0].'</td>';
11343: if ($item->[2]) {
11344: $duplicates .= '<td>'.&mt('Directory').'</td>';
11345: } else {
11346: $duplicates .= '<td>'.&mt('File').'</td>';
11347: }
11348: $duplicates .= '<td>'.$item->[3].'</td>'.
11349: '<td>'.
11350: &Apache::lonlocal::locallocaltime($item->[4]).
11351: '</td>'.
11352: &end_data_table_row();
11353: $num ++;
11354: }
11355: }
11356: }
11357: }
11358: my $itemcount;
11359: if (@paths > 0) {
11360: $itemcount = scalar(@paths);
11361: } else {
11362: $itemcount = 1;
11363: }
1.1067 raeburn 11364: if ($is_camtasia) {
11365: $output .= $lt{'auto'}.'<br />'.
11366: '<span class="LC_nobreak">'.$lt{'proa'}.'<label>'.
1.1075.2.59 raeburn 11367: '<input type="radio" name="autoextract_camtasia" value="'.$is_camtasia.'" onclick="javascript:camtasiaToggle();" checked="checked" />'.
1.1067 raeburn 11368: $lt{'yes'}.'</label> <label>'.
11369: '<input type="radio" name="autoextract_camtasia" value="0" onclick="javascript:camtasiaToggle();" />'.
11370: $lt{'no'}.'</label></span><br />'.
11371: '<div id="camtasia_titles" style="display:block">'.
11372: &Apache::lonhtmlcommon::start_pick_box().
11373: &Apache::lonhtmlcommon::row_title($lt{'fold'}).
11374: '<input type="textbox" name="camtasia_foldername" value="'.$env{'form.comment'}.'" />'."\n".
11375: &Apache::lonhtmlcommon::row_closure().
11376: &Apache::lonhtmlcommon::row_title($lt{'movi'}).
11377: '<input type="textbox" name="camtasia_moviename" value="" />'."\n".
11378: &Apache::lonhtmlcommon::row_closure(1).
11379: &Apache::lonhtmlcommon::end_pick_box().
11380: '</div>';
11381: }
1.1065 raeburn 11382: $output .=
11383: '<input type="hidden" name="archive_overwrite_total" value="'.$num.'" />'.
1.1067 raeburn 11384: '<input type="hidden" name="archive_itemcount" value="'.$itemcount.'" />'.
11385: "\n";
1.1065 raeburn 11386: if ($duplicates ne '') {
11387: $output .= '<p><span class="LC_warning">'.
11388: &mt('Warning: decompression of the archive will overwrite the following items which already exist:').'</span><br />'.
11389: &start_data_table().
11390: &start_data_table_header_row().
11391: '<th>'.&mt('Overwrite?').'</th>'.
11392: '<th>'.&mt('Name').'</th>'.
11393: '<th>'.&mt('Type').'</th>'.
11394: '<th>'.&mt('Size').'</th>'.
11395: '<th>'.&mt('Last modified').'</th>'.
11396: &end_data_table_header_row().
11397: $duplicates.
11398: &end_data_table().
11399: '</p>';
11400: }
1.1067 raeburn 11401: $output .= '<input type="hidden" name="archiveurl" value="'.$archiveurl.'" />'."\n";
1.1053 raeburn 11402: if (ref($hiddenelements) eq 'HASH') {
11403: foreach my $hidden (sort(keys(%{$hiddenelements}))) {
11404: $output .= '<input type="hidden" name="'.$hidden.'" value="'.$hiddenelements->{$hidden}.'" />'."\n";
11405: }
11406: }
11407: $output .= <<"END";
1.1067 raeburn 11408: <br />
1.1053 raeburn 11409: <input type="submit" name="decompress" value="$lt{'extr'}" />
11410: </form>
11411: $noextract
11412: END
11413: return $output;
11414: }
11415:
1.1065 raeburn 11416: sub decompression_utility {
11417: my ($program) = @_;
11418: my @utilities = ('tar','gunzip','bunzip2','unzip');
11419: my $location;
11420: if (grep(/^\Q$program\E$/,@utilities)) {
11421: foreach my $dir ('/bin/','/usr/bin/','/usr/local/bin/','/sbin/',
11422: '/usr/sbin/') {
11423: if (-x $dir.$program) {
11424: $location = $dir.$program;
11425: last;
11426: }
11427: }
11428: }
11429: return $location;
11430: }
11431:
11432: sub list_archive_contents {
11433: my ($file,$pathsref) = @_;
11434: my (@cmd,$output);
11435: my $needsregexp;
11436: if ($file =~ /\.zip$/) {
11437: @cmd = (&decompression_utility('unzip'),"-l");
11438: $needsregexp = 1;
11439: } elsif (($file =~ m/\.tar\.gz$/) ||
11440: ($file =~ /\.tgz$/)) {
11441: @cmd = (&decompression_utility('tar'),"-ztf");
11442: } elsif ($file =~ /\.tar\.bz2$/) {
11443: @cmd = (&decompression_utility('tar'),"-jtf");
11444: } elsif ($file =~ m|\.tar$|) {
11445: @cmd = (&decompression_utility('tar'),"-tf");
11446: }
11447: if (@cmd) {
11448: undef($!);
11449: undef($@);
11450: if (open(my $fh,"-|", @cmd, $file)) {
11451: while (my $line = <$fh>) {
11452: $output .= $line;
11453: chomp($line);
11454: my $item;
11455: if ($needsregexp) {
11456: ($item) = ($line =~ /^\s*\d+\s+[\d\-]+\s+[\d:]+\s*(.+)$/);
11457: } else {
11458: $item = $line;
11459: }
11460: if ($item ne '') {
11461: unless (grep(/^\Q$item\E$/,@{$pathsref})) {
11462: push(@{$pathsref},$item);
11463: }
11464: }
11465: }
11466: close($fh);
11467: }
11468: }
11469: return $output;
11470: }
11471:
1.1053 raeburn 11472: sub decompress_uploaded_file {
11473: my ($file,$dir) = @_;
11474: &Apache::lonnet::appenv({'cgi.file' => $file});
11475: &Apache::lonnet::appenv({'cgi.dir' => $dir});
11476: my $result = &Apache::lonnet::ssi_body('/cgi-bin/decompress.pl');
11477: my ($handle) = ($env{'user.environment'} =~m{/([^/]+)\.id$});
11478: my $lonidsdir = $Apache::lonnet::perlvar{'lonIDsDir'};
11479: &Apache::lonnet::transfer_profile_to_env($lonidsdir,$handle,1);
11480: my $decompressed = $env{'cgi.decompressed'};
11481: &Apache::lonnet::delenv('cgi.file');
11482: &Apache::lonnet::delenv('cgi.dir');
11483: &Apache::lonnet::delenv('cgi.decompressed');
11484: return ($decompressed,$result);
11485: }
11486:
1.1055 raeburn 11487: sub process_decompression {
11488: my ($docudom,$docuname,$file,$destination,$dir_root,$hiddenelem) = @_;
11489: my ($dir,$error,$warning,$output);
1.1075.2.69 raeburn 11490: if ($file !~ /\.(zip|tar|bz2|gz|tar.gz|tar.bz2|tgz)$/i) {
1.1075.2.34 raeburn 11491: $error = &mt('Filename not a supported archive file type.').
11492: '<br />'.&mt('Filename should end with one of: [_1].',
1.1055 raeburn 11493: '.zip, .tar, .bz2, .gz, .tar.gz, .tar.bz2, .tgz');
11494: } else {
11495: my $docuhome = &Apache::lonnet::homeserver($docuname,$docudom);
11496: if ($docuhome eq 'no_host') {
11497: $error = &mt('Could not determine home server for course.');
11498: } else {
11499: my @ids=&Apache::lonnet::current_machine_ids();
11500: my $currdir = "$dir_root/$destination";
11501: if (grep(/^\Q$docuhome\E$/,@ids)) {
11502: $dir = &LONCAPA::propath($docudom,$docuname).
11503: "$dir_root/$destination";
11504: } else {
11505: $dir = $Apache::lonnet::perlvar{'lonDocRoot'}.
11506: "$dir_root/$docudom/$docuname/$destination";
11507: unless (&Apache::lonnet::repcopy_userfile("$dir/$file") eq 'ok') {
11508: $error = &mt('Archive file not found.');
11509: }
11510: }
1.1065 raeburn 11511: my (@to_overwrite,@to_skip);
11512: if ($env{'form.archive_overwrite_total'} > 0) {
11513: my $total = $env{'form.archive_overwrite_total'};
11514: for (my $i=0; $i<$total; $i++) {
11515: if ($env{'form.archive_overwrite_'.$i} == 1) {
11516: push(@to_overwrite,$env{'form.archive_overwrite_name_'.$i});
11517: } elsif ($env{'form.archive_overwrite_'.$i} == 0) {
11518: push(@to_skip,$env{'form.archive_overwrite_name_'.$i});
11519: }
11520: }
11521: }
11522: my $numskip = scalar(@to_skip);
11523: if (($numskip > 0) &&
11524: ($numskip == $env{'form.archive_itemcount'})) {
11525: $warning = &mt('All items in the archive file already exist, and no overwriting of existing files has been requested.');
11526: } elsif ($dir eq '') {
1.1055 raeburn 11527: $error = &mt('Directory containing archive file unavailable.');
11528: } elsif (!$error) {
1.1065 raeburn 11529: my ($decompressed,$display);
11530: if ($numskip > 0) {
11531: my $tempdir = time.'_'.$$.int(rand(10000));
11532: mkdir("$dir/$tempdir",0755);
11533: system("mv $dir/$file $dir/$tempdir/$file");
11534: ($decompressed,$display) =
11535: &decompress_uploaded_file($file,"$dir/$tempdir");
11536: foreach my $item (@to_skip) {
11537: if (($item ne '') && ($item !~ /\.\./)) {
11538: if (-f "$dir/$tempdir/$item") {
11539: unlink("$dir/$tempdir/$item");
11540: } elsif (-d "$dir/$tempdir/$item") {
11541: system("rm -rf $dir/$tempdir/$item");
11542: }
11543: }
11544: }
11545: system("mv $dir/$tempdir/* $dir");
11546: rmdir("$dir/$tempdir");
11547: } else {
11548: ($decompressed,$display) =
11549: &decompress_uploaded_file($file,$dir);
11550: }
1.1055 raeburn 11551: if ($decompressed eq 'ok') {
1.1065 raeburn 11552: $output = '<p class="LC_info">'.
11553: &mt('Files extracted successfully from archive.').
11554: '</p>'."\n";
1.1055 raeburn 11555: my ($warning,$result,@contents);
11556: my ($newdirlistref,$newlisterror) =
11557: &Apache::lonnet::dirlist($currdir,$docudom,
11558: $docuname,1);
11559: my (%is_dir,%changes,@newitems);
11560: my $dirptr = 16384;
1.1065 raeburn 11561: if (ref($newdirlistref) eq 'ARRAY') {
1.1055 raeburn 11562: foreach my $dir_line (@{$newdirlistref}) {
11563: my ($item,undef,undef,$testdir)=split(/\&/,$dir_line,5);
1.1065 raeburn 11564: unless (($item =~ /^\.+$/) || ($item eq $file) ||
11565: ((@to_skip > 0) && (grep(/^\Q$item\E$/,@to_skip)))) {
1.1055 raeburn 11566: push(@newitems,$item);
11567: if ($dirptr&$testdir) {
11568: $is_dir{$item} = 1;
11569: }
11570: $changes{$item} = 1;
11571: }
11572: }
11573: }
11574: if (keys(%changes) > 0) {
11575: foreach my $item (sort(@newitems)) {
11576: if ($changes{$item}) {
11577: push(@contents,$item);
11578: }
11579: }
11580: }
11581: if (@contents > 0) {
1.1067 raeburn 11582: my $wantform;
11583: unless ($env{'form.autoextract_camtasia'}) {
11584: $wantform = 1;
11585: }
1.1056 raeburn 11586: my (%children,%parent,%dirorder,%titles);
1.1055 raeburn 11587: my ($count,$datatable) = &get_extracted($docudom,$docuname,
11588: $currdir,\%is_dir,
11589: \%children,\%parent,
1.1056 raeburn 11590: \@contents,\%dirorder,
11591: \%titles,$wantform);
1.1055 raeburn 11592: if ($datatable ne '') {
11593: $output .= &archive_options_form('decompressed',$datatable,
11594: $count,$hiddenelem);
1.1065 raeburn 11595: my $startcount = 6;
1.1055 raeburn 11596: $output .= &archive_javascript($startcount,$count,
1.1056 raeburn 11597: \%titles,\%children);
1.1055 raeburn 11598: }
1.1067 raeburn 11599: if ($env{'form.autoextract_camtasia'}) {
1.1075.2.59 raeburn 11600: my $version = $env{'form.autoextract_camtasia'};
1.1067 raeburn 11601: my %displayed;
11602: my $total = 1;
11603: $env{'form.archive_directory'} = [];
11604: foreach my $i (sort { $a <=> $b } keys(%dirorder)) {
11605: my $path = join('/',map { $titles{$_}; } @{$dirorder{$i}});
11606: $path =~ s{/$}{};
11607: my $item;
11608: if ($path ne '') {
11609: $item = "$path/$titles{$i}";
11610: } else {
11611: $item = $titles{$i};
11612: }
11613: $env{'form.archive_content_'.$i} = "$dir_root/$destination/$item";
11614: if ($item eq $contents[0]) {
11615: push(@{$env{'form.archive_directory'}},$i);
11616: $env{'form.archive_'.$i} = 'display';
11617: $env{'form.archive_title_'.$i} = $env{'form.camtasia_foldername'};
11618: $displayed{'folder'} = $i;
1.1075.2.59 raeburn 11619: } elsif ((($item eq "$contents[0]/index.html") && ($version == 6)) ||
11620: (($item eq "$contents[0]/$contents[0]".'.html') && ($version == 8))) {
1.1067 raeburn 11621: $env{'form.archive_'.$i} = 'display';
11622: $env{'form.archive_title_'.$i} = $env{'form.camtasia_moviename'};
11623: $displayed{'web'} = $i;
11624: } else {
1.1075.2.59 raeburn 11625: if ((($item eq "$contents[0]/media") && ($version == 6)) ||
11626: ((($item eq "$contents[0]/scripts") || ($item eq "$contents[0]/skins") ||
11627: ($item eq "$contents[0]/skins/express_show")) && ($version == 8))) {
1.1067 raeburn 11628: push(@{$env{'form.archive_directory'}},$i);
11629: }
11630: $env{'form.archive_'.$i} = 'dependency';
11631: }
11632: $total ++;
11633: }
11634: for (my $i=1; $i<$total; $i++) {
11635: next if ($i == $displayed{'web'});
11636: next if ($i == $displayed{'folder'});
11637: $env{'form.archive_dependent_on_'.$i} = $displayed{'web'};
11638: }
11639: $env{'form.phase'} = 'decompress_cleanup';
11640: $env{'form.archivedelete'} = 1;
11641: $env{'form.archive_count'} = $total-1;
11642: $output .=
11643: &process_extracted_files('coursedocs',$docudom,
11644: $docuname,$destination,
11645: $dir_root,$hiddenelem);
11646: }
1.1055 raeburn 11647: } else {
11648: $warning = &mt('No new items extracted from archive file.');
11649: }
11650: } else {
11651: $output = $display;
11652: $error = &mt('An error occurred during extraction from the archive file.');
11653: }
11654: }
11655: }
11656: }
11657: if ($error) {
11658: $output .= '<p class="LC_error">'.&mt('Not extracted.').'<br />'.
11659: $error.'</p>'."\n";
11660: }
11661: if ($warning) {
11662: $output .= '<p class="LC_warning">'.$warning.'</p>'."\n";
11663: }
11664: return $output;
11665: }
11666:
11667: sub get_extracted {
1.1056 raeburn 11668: my ($docudom,$docuname,$currdir,$is_dir,$children,$parent,$contents,$dirorder,
11669: $titles,$wantform) = @_;
1.1055 raeburn 11670: my $count = 0;
11671: my $depth = 0;
11672: my $datatable;
1.1056 raeburn 11673: my @hierarchy;
1.1055 raeburn 11674: return unless ((ref($is_dir) eq 'HASH') && (ref($children) eq 'HASH') &&
1.1056 raeburn 11675: (ref($parent) eq 'HASH') && (ref($contents) eq 'ARRAY') &&
11676: (ref($dirorder) eq 'HASH') && (ref($titles) eq 'HASH'));
1.1055 raeburn 11677: foreach my $item (@{$contents}) {
11678: $count ++;
1.1056 raeburn 11679: @{$dirorder->{$count}} = @hierarchy;
11680: $titles->{$count} = $item;
1.1055 raeburn 11681: &archive_hierarchy($depth,$count,$parent,$children);
11682: if ($wantform) {
11683: $datatable .= &archive_row($is_dir->{$item},$item,
11684: $currdir,$depth,$count);
11685: }
11686: if ($is_dir->{$item}) {
11687: $depth ++;
1.1056 raeburn 11688: push(@hierarchy,$count);
11689: $parent->{$depth} = $count;
1.1055 raeburn 11690: $datatable .=
11691: &recurse_extracted_archive("$currdir/$item",$docudom,$docuname,
1.1056 raeburn 11692: \$depth,\$count,\@hierarchy,$dirorder,
11693: $children,$parent,$titles,$wantform);
1.1055 raeburn 11694: $depth --;
1.1056 raeburn 11695: pop(@hierarchy);
1.1055 raeburn 11696: }
11697: }
11698: return ($count,$datatable);
11699: }
11700:
11701: sub recurse_extracted_archive {
1.1056 raeburn 11702: my ($currdir,$docudom,$docuname,$depth,$count,$hierarchy,$dirorder,
11703: $children,$parent,$titles,$wantform) = @_;
1.1055 raeburn 11704: my $result='';
1.1056 raeburn 11705: unless ((ref($depth)) && (ref($count)) && (ref($hierarchy) eq 'ARRAY') &&
11706: (ref($children) eq 'HASH') && (ref($parent) eq 'HASH') &&
11707: (ref($dirorder) eq 'HASH')) {
1.1055 raeburn 11708: return $result;
11709: }
11710: my $dirptr = 16384;
11711: my ($newdirlistref,$newlisterror) =
11712: &Apache::lonnet::dirlist($currdir,$docudom,$docuname,1);
11713: if (ref($newdirlistref) eq 'ARRAY') {
11714: foreach my $dir_line (@{$newdirlistref}) {
11715: my ($item,undef,undef,$testdir)=split(/\&/,$dir_line,5);
11716: unless ($item =~ /^\.+$/) {
11717: $$count ++;
1.1056 raeburn 11718: @{$dirorder->{$$count}} = @{$hierarchy};
11719: $titles->{$$count} = $item;
1.1055 raeburn 11720: &archive_hierarchy($$depth,$$count,$parent,$children);
1.1056 raeburn 11721:
1.1055 raeburn 11722: my $is_dir;
11723: if ($dirptr&$testdir) {
11724: $is_dir = 1;
11725: }
11726: if ($wantform) {
11727: $result .= &archive_row($is_dir,$item,$currdir,$$depth,$$count);
11728: }
11729: if ($is_dir) {
11730: $$depth ++;
1.1056 raeburn 11731: push(@{$hierarchy},$$count);
11732: $parent->{$$depth} = $$count;
1.1055 raeburn 11733: $result .=
11734: &recurse_extracted_archive("$currdir/$item",$docudom,
11735: $docuname,$depth,$count,
1.1056 raeburn 11736: $hierarchy,$dirorder,$children,
11737: $parent,$titles,$wantform);
1.1055 raeburn 11738: $$depth --;
1.1056 raeburn 11739: pop(@{$hierarchy});
1.1055 raeburn 11740: }
11741: }
11742: }
11743: }
11744: return $result;
11745: }
11746:
11747: sub archive_hierarchy {
11748: my ($depth,$count,$parent,$children) =@_;
11749: if ((ref($parent) eq 'HASH') && (ref($children) eq 'HASH')) {
11750: if (exists($parent->{$depth})) {
11751: $children->{$parent->{$depth}} .= $count.':';
11752: }
11753: }
11754: return;
11755: }
11756:
11757: sub archive_row {
11758: my ($is_dir,$item,$currdir,$depth,$count) = @_;
11759: my ($name) = ($item =~ m{([^/]+)$});
11760: my %choices = &Apache::lonlocal::texthash (
1.1059 raeburn 11761: 'display' => 'Add as file',
1.1055 raeburn 11762: 'dependency' => 'Include as dependency',
11763: 'discard' => 'Discard',
11764: );
11765: if ($is_dir) {
1.1059 raeburn 11766: $choices{'display'} = &mt('Add as folder');
1.1055 raeburn 11767: }
1.1056 raeburn 11768: my $output = &start_data_table_row().'<td align="right">'.$count.'</td>'."\n";
11769: my $offset = 0;
1.1055 raeburn 11770: foreach my $action ('display','dependency','discard') {
1.1056 raeburn 11771: $offset ++;
1.1065 raeburn 11772: if ($action ne 'display') {
11773: $offset ++;
11774: }
1.1055 raeburn 11775: $output .= '<td><span class="LC_nobreak">'.
11776: '<label><input type="radio" name="archive_'.$count.
11777: '" id="archive_'.$action.'_'.$count.'" value="'.$action.'"';
11778: my $text = $choices{$action};
11779: if ($is_dir) {
11780: $output .= ' onclick="javascript:propagateCheck(this.form,'."'$count'".');"';
11781: if ($action eq 'display') {
1.1059 raeburn 11782: $text = &mt('Add as folder');
1.1055 raeburn 11783: }
1.1056 raeburn 11784: } else {
11785: $output .= ' onclick="javascript:dependencyCheck(this.form,'."$count,$offset".');"';
11786:
11787: }
11788: $output .= ' /> '.$choices{$action}.'</label></span>';
11789: if ($action eq 'dependency') {
11790: $output .= '<div id="arc_depon_'.$count.'" style="display:none;">'."\n".
11791: &mt('Used by:').' <select name="archive_dependent_on_'.$count.'" '.
11792: 'onchange="propagateSelect(this.form,'."$count,$offset".')">'."\n".
11793: '<option value=""></option>'."\n".
11794: '</select>'."\n".
11795: '</div>';
1.1059 raeburn 11796: } elsif ($action eq 'display') {
11797: $output .= '<div id="arc_title_'.$count.'" style="display:none;">'."\n".
11798: &mt('Title:').' <input type="text" name="archive_title_'.$count.'" id="archive_title_'.$count.'" />'."\n".
11799: '</div>';
1.1055 raeburn 11800: }
1.1056 raeburn 11801: $output .= '</td>';
1.1055 raeburn 11802: }
11803: $output .= '<td><input type="hidden" name="archive_content_'.$count.'" value="'.
11804: &HTML::Entities::encode("$currdir/$item",'"<>&').'" />'.(' ' x 2);
11805: for (my $i=0; $i<$depth; $i++) {
11806: $output .= ('<img src="/adm/lonIcons/whitespace1.gif" class="LC_docs_spacer" alt="" />' x2)."\n";
11807: }
11808: if ($is_dir) {
11809: $output .= '<img src="/adm/lonIcons/navmap.folder.open.gif" alt="" /> '."\n".
11810: '<input type="hidden" name="archive_directory" value="'.$count.'" />'."\n";
11811: } else {
11812: $output .= '<input type="hidden" name="archive_file" value="'.$count.'" />'."\n";
11813: }
11814: $output .= ' '.$name.'</td>'."\n".
11815: &end_data_table_row();
11816: return $output;
11817: }
11818:
11819: sub archive_options_form {
1.1065 raeburn 11820: my ($form,$display,$count,$hiddenelem) = @_;
11821: my %lt = &Apache::lonlocal::texthash(
11822: perm => 'Permanently remove archive file?',
11823: hows => 'How should each extracted item be incorporated in the course?',
11824: cont => 'Content actions for all',
11825: addf => 'Add as folder/file',
11826: incd => 'Include as dependency for a displayed file',
11827: disc => 'Discard',
11828: no => 'No',
11829: yes => 'Yes',
11830: save => 'Save',
11831: );
11832: my $output = <<"END";
11833: <form name="$form" method="post" action="">
11834: <p><span class="LC_nobreak">$lt{'perm'}
11835: <label>
11836: <input type="radio" name="archivedelete" value="0" checked="checked" />$lt{'no'}
11837: </label>
11838:
11839: <label>
11840: <input type="radio" name="archivedelete" value="1" />$lt{'yes'}</label>
11841: </span>
11842: </p>
11843: <input type="hidden" name="phase" value="decompress_cleanup" />
11844: <br />$lt{'hows'}
11845: <div class="LC_columnSection">
11846: <fieldset>
11847: <legend>$lt{'cont'}</legend>
11848: <input type="button" value="$lt{'addf'}" onclick="javascript:checkAll(document.$form,'display');" />
11849: <input type="button" value="$lt{'incd'}" onclick="javascript:checkAll(document.$form,'dependency');" />
11850: <input type="button" value="$lt{'disc'}" onclick="javascript:checkAll(document.$form,'discard');" />
11851: </fieldset>
11852: </div>
11853: END
11854: return $output.
1.1055 raeburn 11855: &start_data_table()."\n".
1.1065 raeburn 11856: $display."\n".
1.1055 raeburn 11857: &end_data_table()."\n".
11858: '<input type="hidden" name="archive_count" value="'.$count.'" />'.
11859: $hiddenelem.
1.1065 raeburn 11860: '<br /><input type="submit" name="archive_submit" value="'.$lt{'save'}.'" />'.
1.1055 raeburn 11861: '</form>';
11862: }
11863:
11864: sub archive_javascript {
1.1056 raeburn 11865: my ($startcount,$numitems,$titles,$children) = @_;
11866: return unless ((ref($titles) eq 'HASH') && (ref($children) eq 'HASH'));
1.1059 raeburn 11867: my $maintitle = $env{'form.comment'};
1.1055 raeburn 11868: my $scripttag = <<START;
11869: <script type="text/javascript">
11870: // <![CDATA[
11871:
11872: function checkAll(form,prefix) {
11873: var idstr = new RegExp("^archive_"+prefix+"_\\\\d+\$");
11874: for (var i=0; i < form.elements.length; i++) {
11875: var id = form.elements[i].id;
11876: if ((id != '') && (id != undefined)) {
11877: if (idstr.test(id)) {
11878: if (form.elements[i].type == 'radio') {
11879: form.elements[i].checked = true;
1.1056 raeburn 11880: var nostart = i-$startcount;
1.1059 raeburn 11881: var offset = nostart%7;
11882: var count = (nostart-offset)/7;
1.1056 raeburn 11883: dependencyCheck(form,count,offset);
1.1055 raeburn 11884: }
11885: }
11886: }
11887: }
11888: }
11889:
11890: function propagateCheck(form,count) {
11891: if (count > 0) {
1.1059 raeburn 11892: var startelement = $startcount + ((count-1) * 7);
11893: for (var j=1; j<6; j++) {
11894: if ((j != 2) && (j != 4)) {
1.1056 raeburn 11895: var item = startelement + j;
11896: if (form.elements[item].type == 'radio') {
11897: if (form.elements[item].checked) {
11898: containerCheck(form,count,j);
11899: break;
11900: }
1.1055 raeburn 11901: }
11902: }
11903: }
11904: }
11905: }
11906:
11907: numitems = $numitems
1.1056 raeburn 11908: var titles = new Array(numitems);
11909: var parents = new Array(numitems);
1.1055 raeburn 11910: for (var i=0; i<numitems; i++) {
1.1056 raeburn 11911: parents[i] = new Array;
1.1055 raeburn 11912: }
1.1059 raeburn 11913: var maintitle = '$maintitle';
1.1055 raeburn 11914:
11915: START
11916:
1.1056 raeburn 11917: foreach my $container (sort { $a <=> $b } (keys(%{$children}))) {
11918: my @contents = split(/:/,$children->{$container});
1.1055 raeburn 11919: for (my $i=0; $i<@contents; $i ++) {
11920: $scripttag .= 'parents['.$container.']['.$i.'] = '.$contents[$i]."\n";
11921: }
11922: }
11923:
1.1056 raeburn 11924: foreach my $key (sort { $a <=> $b } (keys(%{$titles}))) {
11925: $scripttag .= "titles[$key] = '".$titles->{$key}."';\n";
11926: }
11927:
1.1055 raeburn 11928: $scripttag .= <<END;
11929:
11930: function containerCheck(form,count,offset) {
11931: if (count > 0) {
1.1056 raeburn 11932: dependencyCheck(form,count,offset);
1.1059 raeburn 11933: var item = (offset+$startcount)+7*(count-1);
1.1055 raeburn 11934: form.elements[item].checked = true;
11935: if(Object.prototype.toString.call(parents[count]) === '[object Array]') {
11936: if (parents[count].length > 0) {
11937: for (var j=0; j<parents[count].length; j++) {
1.1056 raeburn 11938: containerCheck(form,parents[count][j],offset);
11939: }
11940: }
11941: }
11942: }
11943: }
11944:
11945: function dependencyCheck(form,count,offset) {
11946: if (count > 0) {
1.1059 raeburn 11947: var chosen = (offset+$startcount)+7*(count-1);
11948: var depitem = $startcount + ((count-1) * 7) + 4;
1.1056 raeburn 11949: var currtype = form.elements[depitem].type;
11950: if (form.elements[chosen].value == 'dependency') {
11951: document.getElementById('arc_depon_'+count).style.display='block';
11952: form.elements[depitem].options.length = 0;
11953: form.elements[depitem].options[0] = new Option('Select','',true,true);
1.1075.2.11 raeburn 11954: for (var i=1; i<=numitems; i++) {
11955: if (i == count) {
11956: continue;
11957: }
1.1059 raeburn 11958: var startelement = $startcount + (i-1) * 7;
11959: for (var j=1; j<6; j++) {
11960: if ((j != 2) && (j!= 4)) {
1.1056 raeburn 11961: var item = startelement + j;
11962: if (form.elements[item].type == 'radio') {
11963: if (form.elements[item].checked) {
11964: if (form.elements[item].value == 'display') {
11965: var n = form.elements[depitem].options.length;
11966: form.elements[depitem].options[n] = new Option(titles[i],i,false,false);
11967: }
11968: }
11969: }
11970: }
11971: }
11972: }
11973: } else {
11974: document.getElementById('arc_depon_'+count).style.display='none';
11975: form.elements[depitem].options.length = 0;
11976: form.elements[depitem].options[0] = new Option('Select','',true,true);
11977: }
1.1059 raeburn 11978: titleCheck(form,count,offset);
1.1056 raeburn 11979: }
11980: }
11981:
11982: function propagateSelect(form,count,offset) {
11983: if (count > 0) {
1.1065 raeburn 11984: var item = (1+offset+$startcount)+7*(count-1);
1.1056 raeburn 11985: var picked = form.elements[item].options[form.elements[item].selectedIndex].value;
11986: if (Object.prototype.toString.call(parents[count]) === '[object Array]') {
11987: if (parents[count].length > 0) {
11988: for (var j=0; j<parents[count].length; j++) {
11989: containerSelect(form,parents[count][j],offset,picked);
1.1055 raeburn 11990: }
11991: }
11992: }
11993: }
11994: }
1.1056 raeburn 11995:
11996: function containerSelect(form,count,offset,picked) {
11997: if (count > 0) {
1.1065 raeburn 11998: var item = (offset+$startcount)+7*(count-1);
1.1056 raeburn 11999: if (form.elements[item].type == 'radio') {
12000: if (form.elements[item].value == 'dependency') {
12001: if (form.elements[item+1].type == 'select-one') {
12002: for (var i=0; i<form.elements[item+1].options.length; i++) {
12003: if (form.elements[item+1].options[i].value == picked) {
12004: form.elements[item+1].selectedIndex = i;
12005: break;
12006: }
12007: }
12008: }
12009: if (Object.prototype.toString.call(parents[count]) === '[object Array]') {
12010: if (parents[count].length > 0) {
12011: for (var j=0; j<parents[count].length; j++) {
12012: containerSelect(form,parents[count][j],offset,picked);
12013: }
12014: }
12015: }
12016: }
12017: }
12018: }
12019: }
12020:
1.1059 raeburn 12021: function titleCheck(form,count,offset) {
12022: if (count > 0) {
12023: var chosen = (offset+$startcount)+7*(count-1);
12024: var depitem = $startcount + ((count-1) * 7) + 2;
12025: var currtype = form.elements[depitem].type;
12026: if (form.elements[chosen].value == 'display') {
12027: document.getElementById('arc_title_'+count).style.display='block';
12028: if ((count==1) && ((parents[count].length > 0) || (numitems == 1))) {
12029: document.getElementById('archive_title_'+count).value=maintitle;
12030: }
12031: } else {
12032: document.getElementById('arc_title_'+count).style.display='none';
12033: if (currtype == 'text') {
12034: document.getElementById('archive_title_'+count).value='';
12035: }
12036: }
12037: }
12038: return;
12039: }
12040:
1.1055 raeburn 12041: // ]]>
12042: </script>
12043: END
12044: return $scripttag;
12045: }
12046:
12047: sub process_extracted_files {
1.1067 raeburn 12048: my ($context,$docudom,$docuname,$destination,$dir_root,$hiddenelem) = @_;
1.1055 raeburn 12049: my $numitems = $env{'form.archive_count'};
12050: return unless ($numitems);
12051: my @ids=&Apache::lonnet::current_machine_ids();
12052: my ($prefix,$pathtocheck,$dir,$ishome,$error,$warning,%toplevelitems,%is_dir,
1.1067 raeburn 12053: %folders,%containers,%mapinner,%prompttofetch);
1.1055 raeburn 12054: my $docuhome = &Apache::lonnet::homeserver($docuname,$docudom);
12055: if (grep(/^\Q$docuhome\E$/,@ids)) {
12056: $prefix = &LONCAPA::propath($docudom,$docuname);
12057: $pathtocheck = "$dir_root/$destination";
12058: $dir = $dir_root;
12059: $ishome = 1;
12060: } else {
12061: $prefix = $Apache::lonnet::perlvar{'lonDocRoot'};
12062: $pathtocheck = "$dir_root/$docudom/$docuname/$destination";
12063: $dir = "$dir_root/$docudom/$docuname";
12064: }
12065: my $currdir = "$dir_root/$destination";
12066: (my $docstype,$mapinner{'0'}) = ($destination =~ m{^(docs|supplemental)/(\w+)/});
12067: if ($env{'form.folderpath'}) {
12068: my @items = split('&',$env{'form.folderpath'});
12069: $folders{'0'} = $items[-2];
1.1075.2.17 raeburn 12070: if ($env{'form.folderpath'} =~ /\:1$/) {
12071: $containers{'0'}='page';
12072: } else {
12073: $containers{'0'}='sequence';
12074: }
1.1055 raeburn 12075: }
12076: my @archdirs = &get_env_multiple('form.archive_directory');
12077: if ($numitems) {
12078: for (my $i=1; $i<=$numitems; $i++) {
12079: my $path = $env{'form.archive_content_'.$i};
12080: if ($path =~ m{^\Q$pathtocheck\E/([^/]+)$}) {
12081: my $item = $1;
12082: $toplevelitems{$item} = $i;
12083: if (grep(/^\Q$i\E$/,@archdirs)) {
12084: $is_dir{$item} = 1;
12085: }
12086: }
12087: }
12088: }
1.1067 raeburn 12089: my ($output,%children,%parent,%titles,%dirorder,$result);
1.1055 raeburn 12090: if (keys(%toplevelitems) > 0) {
12091: my @contents = sort(keys(%toplevelitems));
1.1056 raeburn 12092: (my $count,undef) = &get_extracted($docudom,$docuname,$currdir,\%is_dir,\%children,
12093: \%parent,\@contents,\%dirorder,\%titles);
1.1055 raeburn 12094: }
1.1066 raeburn 12095: my (%referrer,%orphaned,%todelete,%todeletedir,%newdest,%newseqid);
1.1055 raeburn 12096: if ($numitems) {
12097: for (my $i=1; $i<=$numitems; $i++) {
1.1075.2.11 raeburn 12098: next if ($env{'form.archive_'.$i} eq 'dependency');
1.1055 raeburn 12099: my $path = $env{'form.archive_content_'.$i};
12100: if ($path =~ /^\Q$pathtocheck\E/) {
12101: if ($env{'form.archive_'.$i} eq 'discard') {
12102: if ($prefix ne '' && $path ne '') {
12103: if (-e $prefix.$path) {
1.1066 raeburn 12104: if ((@archdirs > 0) &&
12105: (grep(/^\Q$i\E$/,@archdirs))) {
12106: $todeletedir{$prefix.$path} = 1;
12107: } else {
12108: $todelete{$prefix.$path} = 1;
12109: }
1.1055 raeburn 12110: }
12111: }
12112: } elsif ($env{'form.archive_'.$i} eq 'display') {
1.1059 raeburn 12113: my ($docstitle,$title,$url,$outer);
1.1055 raeburn 12114: ($title) = ($path =~ m{/([^/]+)$});
1.1059 raeburn 12115: $docstitle = $env{'form.archive_title_'.$i};
12116: if ($docstitle eq '') {
12117: $docstitle = $title;
12118: }
1.1055 raeburn 12119: $outer = 0;
1.1056 raeburn 12120: if (ref($dirorder{$i}) eq 'ARRAY') {
12121: if (@{$dirorder{$i}} > 0) {
12122: foreach my $item (reverse(@{$dirorder{$i}})) {
1.1055 raeburn 12123: if ($env{'form.archive_'.$item} eq 'display') {
12124: $outer = $item;
12125: last;
12126: }
12127: }
12128: }
12129: }
12130: my ($errtext,$fatal) =
12131: &LONCAPA::map::mapread('/uploaded/'.$docudom.'/'.$docuname.
12132: '/'.$folders{$outer}.'.'.
12133: $containers{$outer});
12134: next if ($fatal);
12135: if ((@archdirs > 0) && (grep(/^\Q$i\E$/,@archdirs))) {
12136: if ($context eq 'coursedocs') {
1.1056 raeburn 12137: $mapinner{$i} = time;
1.1055 raeburn 12138: $folders{$i} = 'default_'.$mapinner{$i};
12139: $containers{$i} = 'sequence';
12140: my $url = '/uploaded/'.$docudom.'/'.$docuname.'/'.
12141: $folders{$i}.'.'.$containers{$i};
12142: my $newidx = &LONCAPA::map::getresidx();
12143: $LONCAPA::map::resources[$newidx]=
1.1059 raeburn 12144: $docstitle.':'.$url.':false:normal:res';
1.1055 raeburn 12145: push(@LONCAPA::map::order,$newidx);
12146: my ($outtext,$errtext) =
12147: &LONCAPA::map::storemap('/uploaded/'.$docudom.'/'.
12148: $docuname.'/'.$folders{$outer}.
1.1075.2.11 raeburn 12149: '.'.$containers{$outer},1,1);
1.1056 raeburn 12150: $newseqid{$i} = $newidx;
1.1067 raeburn 12151: unless ($errtext) {
12152: $result .= '<li>'.&mt('Folder: [_1] added to course',$docstitle).'</li>'."\n";
12153: }
1.1055 raeburn 12154: }
12155: } else {
12156: if ($context eq 'coursedocs') {
12157: my $newidx=&LONCAPA::map::getresidx();
12158: my $url = '/uploaded/'.$docudom.'/'.$docuname.'/'.
12159: $docstype.'/'.$mapinner{$outer}.'/'.$newidx.'/'.
12160: $title;
12161: if (!-e "$prefix$dir/$docstype/$mapinner{$outer}") {
12162: mkdir("$prefix$dir/$docstype/$mapinner{$outer}",0755);
12163: }
12164: if (!-e "$prefix$dir/$docstype/$mapinner{$outer}/$newidx") {
12165: mkdir("$prefix$dir/$docstype/$mapinner{$outer}/$newidx");
12166: }
12167: if (-e "$prefix$dir/$docstype/$mapinner{$outer}/$newidx") {
12168: system("mv $prefix$path $prefix$dir/$docstype/$mapinner{$outer}/$newidx/$title");
1.1056 raeburn 12169: $newdest{$i} = "$prefix$dir/$docstype/$mapinner{$outer}/$newidx";
1.1067 raeburn 12170: unless ($ishome) {
12171: my $fetch = "$newdest{$i}/$title";
12172: $fetch =~ s/^\Q$prefix$dir\E//;
12173: $prompttofetch{$fetch} = 1;
12174: }
1.1055 raeburn 12175: }
12176: $LONCAPA::map::resources[$newidx]=
1.1059 raeburn 12177: $docstitle.':'.$url.':false:normal:res';
1.1055 raeburn 12178: push(@LONCAPA::map::order, $newidx);
12179: my ($outtext,$errtext)=
12180: &LONCAPA::map::storemap('/uploaded/'.$docudom.'/'.
12181: $docuname.'/'.$folders{$outer}.
1.1075.2.11 raeburn 12182: '.'.$containers{$outer},1,1);
1.1067 raeburn 12183: unless ($errtext) {
12184: if (-e "$prefix$dir/$docstype/$mapinner{$outer}/$newidx/$title") {
12185: $result .= '<li>'.&mt('File: [_1] added to course',$docstitle).'</li>'."\n";
12186: }
12187: }
1.1055 raeburn 12188: }
12189: }
1.1075.2.11 raeburn 12190: }
12191: } else {
12192: $warning .= &mt('Item extracted from archive: [_1] has unexpected path.',$path).'<br />';
12193: }
12194: }
12195: for (my $i=1; $i<=$numitems; $i++) {
12196: next unless ($env{'form.archive_'.$i} eq 'dependency');
12197: my $path = $env{'form.archive_content_'.$i};
12198: if ($path =~ /^\Q$pathtocheck\E/) {
12199: my ($title) = ($path =~ m{/([^/]+)$});
12200: $referrer{$i} = $env{'form.archive_dependent_on_'.$i};
12201: if ($env{'form.archive_'.$referrer{$i}} eq 'display') {
12202: if (ref($dirorder{$i}) eq 'ARRAY') {
12203: my ($itemidx,$fullpath,$relpath);
12204: if (ref($dirorder{$referrer{$i}}) eq 'ARRAY') {
12205: my $container = $dirorder{$referrer{$i}}->[-1];
1.1056 raeburn 12206: for (my $j=0; $j<@{$dirorder{$i}}; $j++) {
1.1075.2.11 raeburn 12207: if ($dirorder{$i}->[$j] eq $container) {
12208: $itemidx = $j;
1.1056 raeburn 12209: }
12210: }
1.1075.2.11 raeburn 12211: }
12212: if ($itemidx eq '') {
12213: $itemidx = 0;
12214: }
12215: if (grep(/^\Q$referrer{$i}\E$/,@archdirs)) {
12216: if ($mapinner{$referrer{$i}}) {
12217: $fullpath = "$prefix$dir/$docstype/$mapinner{$referrer{$i}}";
12218: for (my $j=$itemidx; $j<@{$dirorder{$i}}; $j++) {
12219: if (grep(/^\Q$dirorder{$i}->[$j]\E$/,@archdirs)) {
12220: unless (defined($newseqid{$dirorder{$i}->[$j]})) {
12221: $fullpath .= '/'.$titles{$dirorder{$i}->[$j]};
12222: $relpath .= '/'.$titles{$dirorder{$i}->[$j]};
12223: if (!-e $fullpath) {
12224: mkdir($fullpath,0755);
1.1056 raeburn 12225: }
12226: }
1.1075.2.11 raeburn 12227: } else {
12228: last;
1.1056 raeburn 12229: }
1.1075.2.11 raeburn 12230: }
12231: }
12232: } elsif ($newdest{$referrer{$i}}) {
12233: $fullpath = $newdest{$referrer{$i}};
12234: for (my $j=$itemidx; $j<@{$dirorder{$i}}; $j++) {
12235: if ($env{'form.archive_'.$dirorder{$i}->[$j]} eq 'discard') {
12236: $orphaned{$i} = $env{'form.archive_'.$dirorder{$i}->[$j]};
12237: last;
12238: } elsif (grep(/^\Q$dirorder{$i}->[$j]\E$/,@archdirs)) {
12239: unless (defined($newseqid{$dirorder{$i}->[$j]})) {
12240: $fullpath .= '/'.$titles{$dirorder{$i}->[$j]};
12241: $relpath .= '/'.$titles{$dirorder{$i}->[$j]};
12242: if (!-e $fullpath) {
12243: mkdir($fullpath,0755);
1.1056 raeburn 12244: }
12245: }
1.1075.2.11 raeburn 12246: } else {
12247: last;
1.1056 raeburn 12248: }
1.1075.2.11 raeburn 12249: }
12250: }
12251: if ($fullpath ne '') {
12252: if (-e "$prefix$path") {
12253: system("mv $prefix$path $fullpath/$title");
12254: }
12255: if (-e "$fullpath/$title") {
12256: my $showpath;
12257: if ($relpath ne '') {
12258: $showpath = "$relpath/$title";
12259: } else {
12260: $showpath = "/$title";
1.1056 raeburn 12261: }
1.1075.2.11 raeburn 12262: $result .= '<li>'.&mt('[_1] included as a dependency',$showpath).'</li>'."\n";
12263: }
12264: unless ($ishome) {
12265: my $fetch = "$fullpath/$title";
12266: $fetch =~ s/^\Q$prefix$dir\E//;
12267: $prompttofetch{$fetch} = 1;
1.1055 raeburn 12268: }
12269: }
12270: }
1.1075.2.11 raeburn 12271: } elsif ($env{'form.archive_'.$referrer{$i}} eq 'discard') {
12272: $warning .= &mt('[_1] is a dependency of [_2], which was discarded.',
12273: $path,$env{'form.archive_content_'.$referrer{$i}}).'<br />';
1.1055 raeburn 12274: }
12275: } else {
1.1075.2.11 raeburn 12276: $warning .= &mt('Item extracted from archive: [_1] has unexpected path.',$path).'<br />';
1.1055 raeburn 12277: }
12278: }
12279: if (keys(%todelete)) {
12280: foreach my $key (keys(%todelete)) {
12281: unlink($key);
1.1066 raeburn 12282: }
12283: }
12284: if (keys(%todeletedir)) {
12285: foreach my $key (keys(%todeletedir)) {
12286: rmdir($key);
12287: }
12288: }
12289: foreach my $dir (sort(keys(%is_dir))) {
12290: if (($pathtocheck ne '') && ($dir ne '')) {
12291: &cleanup_empty_dirs($prefix."$pathtocheck/$dir");
1.1055 raeburn 12292: }
12293: }
1.1067 raeburn 12294: if ($result ne '') {
12295: $output .= '<ul>'."\n".
12296: $result."\n".
12297: '</ul>';
12298: }
12299: unless ($ishome) {
12300: my $replicationfail;
12301: foreach my $item (keys(%prompttofetch)) {
12302: my $fetchresult= &Apache::lonnet::reply('fetchuserfile:'.$item,$docuhome);
12303: unless ($fetchresult eq 'ok') {
12304: $replicationfail .= '<li>'.$item.'</li>'."\n";
12305: }
12306: }
12307: if ($replicationfail) {
12308: $output .= '<p class="LC_error">'.
12309: &mt('Course home server failed to retrieve:').'<ul>'.
12310: $replicationfail.
12311: '</ul></p>';
12312: }
12313: }
1.1055 raeburn 12314: } else {
12315: $warning = &mt('No items found in archive.');
12316: }
12317: if ($error) {
12318: $output .= '<p class="LC_error">'.&mt('Not extracted.').'<br />'.
12319: $error.'</p>'."\n";
12320: }
12321: if ($warning) {
12322: $output .= '<p class="LC_warning">'.$warning.'</p>'."\n";
12323: }
12324: return $output;
12325: }
12326:
1.1066 raeburn 12327: sub cleanup_empty_dirs {
12328: my ($path) = @_;
12329: if (($path ne '') && (-d $path)) {
12330: if (opendir(my $dirh,$path)) {
12331: my @dircontents = grep(!/^\./,readdir($dirh));
12332: my $numitems = 0;
12333: foreach my $item (@dircontents) {
12334: if (-d "$path/$item") {
1.1075.2.28 raeburn 12335: &cleanup_empty_dirs("$path/$item");
1.1066 raeburn 12336: if (-e "$path/$item") {
12337: $numitems ++;
12338: }
12339: } else {
12340: $numitems ++;
12341: }
12342: }
12343: if ($numitems == 0) {
12344: rmdir($path);
12345: }
12346: closedir($dirh);
12347: }
12348: }
12349: return;
12350: }
12351:
1.41 ng 12352: =pod
1.45 matthew 12353:
1.1075.2.56 raeburn 12354: =item * &get_folder_hierarchy()
1.1068 raeburn 12355:
12356: Provides hierarchy of names of folders/sub-folders containing the current
12357: item,
12358:
12359: Inputs: 3
12360: - $navmap - navmaps object
12361:
12362: - $map - url for map (either the trigger itself, or map containing
12363: the resource, which is the trigger).
12364:
12365: - $showitem - 1 => show title for map itself; 0 => do not show.
12366:
12367: Outputs: 1 @pathitems - array of folder/subfolder names.
12368:
12369: =cut
12370:
12371: sub get_folder_hierarchy {
12372: my ($navmap,$map,$showitem) = @_;
12373: my @pathitems;
12374: if (ref($navmap)) {
12375: my $mapres = $navmap->getResourceByUrl($map);
12376: if (ref($mapres)) {
12377: my $pcslist = $mapres->map_hierarchy();
12378: if ($pcslist ne '') {
12379: my @pcs = split(/,/,$pcslist);
12380: foreach my $pc (@pcs) {
12381: if ($pc == 1) {
1.1075.2.38 raeburn 12382: push(@pathitems,&mt('Main Content'));
1.1068 raeburn 12383: } else {
12384: my $res = $navmap->getByMapPc($pc);
12385: if (ref($res)) {
12386: my $title = $res->compTitle();
12387: $title =~ s/\W+/_/g;
12388: if ($title ne '') {
12389: push(@pathitems,$title);
12390: }
12391: }
12392: }
12393: }
12394: }
1.1071 raeburn 12395: if ($showitem) {
12396: if ($mapres->{ID} eq '0.0') {
1.1075.2.38 raeburn 12397: push(@pathitems,&mt('Main Content'));
1.1071 raeburn 12398: } else {
12399: my $maptitle = $mapres->compTitle();
12400: $maptitle =~ s/\W+/_/g;
12401: if ($maptitle ne '') {
12402: push(@pathitems,$maptitle);
12403: }
1.1068 raeburn 12404: }
12405: }
12406: }
12407: }
12408: return @pathitems;
12409: }
12410:
12411: =pod
12412:
1.1015 raeburn 12413: =item * &get_turnedin_filepath()
12414:
12415: Determines path in a user's portfolio file for storage of files uploaded
12416: to a specific essayresponse or dropbox item.
12417:
12418: Inputs: 3 required + 1 optional.
12419: $symb is symb for resource, $uname and $udom are for current user (required).
12420: $caller is optional (can be "submission", if routine is called when storing
12421: an upoaded file when "Submit Answer" button was pressed).
12422:
12423: Returns array containing $path and $multiresp.
12424: $path is path in portfolio. $multiresp is 1 if this resource contains more
12425: than one file upload item. Callers of routine should append partid as a
12426: subdirectory to $path in cases where $multiresp is 1.
12427:
12428: Called by: homework/essayresponse.pm and homework/structuretags.pm
12429:
12430: =cut
12431:
12432: sub get_turnedin_filepath {
12433: my ($symb,$uname,$udom,$caller) = @_;
12434: my ($map,$resid,$resurl)=&Apache::lonnet::decode_symb($symb);
12435: my $turnindir;
12436: my %userhash = &Apache::lonnet::userenvironment($udom,$uname,'turnindir');
12437: $turnindir = $userhash{'turnindir'};
12438: my ($path,$multiresp);
12439: if ($turnindir eq '') {
12440: if ($caller eq 'submission') {
12441: $turnindir = &mt('turned in');
12442: $turnindir =~ s/\W+/_/g;
12443: my %newhash = (
12444: 'turnindir' => $turnindir,
12445: );
12446: &Apache::lonnet::put('environment',\%newhash,$udom,$uname);
12447: }
12448: }
12449: if ($turnindir ne '') {
12450: $path = '/'.$turnindir.'/';
12451: my ($multipart,$turnin,@pathitems);
12452: my $navmap = Apache::lonnavmaps::navmap->new();
12453: if (defined($navmap)) {
12454: my $mapres = $navmap->getResourceByUrl($map);
12455: if (ref($mapres)) {
12456: my $pcslist = $mapres->map_hierarchy();
12457: if ($pcslist ne '') {
12458: foreach my $pc (split(/,/,$pcslist)) {
12459: my $res = $navmap->getByMapPc($pc);
12460: if (ref($res)) {
12461: my $title = $res->compTitle();
12462: $title =~ s/\W+/_/g;
12463: if ($title ne '') {
1.1075.2.48 raeburn 12464: if (($pc > 1) && (length($title) > 12)) {
12465: $title = substr($title,0,12);
12466: }
1.1015 raeburn 12467: push(@pathitems,$title);
12468: }
12469: }
12470: }
12471: }
12472: my $maptitle = $mapres->compTitle();
12473: $maptitle =~ s/\W+/_/g;
12474: if ($maptitle ne '') {
1.1075.2.48 raeburn 12475: if (length($maptitle) > 12) {
12476: $maptitle = substr($maptitle,0,12);
12477: }
1.1015 raeburn 12478: push(@pathitems,$maptitle);
12479: }
12480: unless ($env{'request.state'} eq 'construct') {
12481: my $res = $navmap->getBySymb($symb);
12482: if (ref($res)) {
12483: my $partlist = $res->parts();
12484: my $totaluploads = 0;
12485: if (ref($partlist) eq 'ARRAY') {
12486: foreach my $part (@{$partlist}) {
12487: my @types = $res->responseType($part);
12488: my @ids = $res->responseIds($part);
12489: for (my $i=0; $i < scalar(@ids); $i++) {
12490: if ($types[$i] eq 'essay') {
12491: my $partid = $part.'_'.$ids[$i];
12492: if (&Apache::lonnet::EXT("resource.$partid.uploadedfiletypes") ne '') {
12493: $totaluploads ++;
12494: }
12495: }
12496: }
12497: }
12498: if ($totaluploads > 1) {
12499: $multiresp = 1;
12500: }
12501: }
12502: }
12503: }
12504: } else {
12505: return;
12506: }
12507: } else {
12508: return;
12509: }
12510: my $restitle=&Apache::lonnet::gettitle($symb);
12511: $restitle =~ s/\W+/_/g;
12512: if ($restitle eq '') {
12513: $restitle = ($resurl =~ m{/[^/]+$});
12514: if ($restitle eq '') {
12515: $restitle = time;
12516: }
12517: }
1.1075.2.48 raeburn 12518: if (length($restitle) > 12) {
12519: $restitle = substr($restitle,0,12);
12520: }
1.1015 raeburn 12521: push(@pathitems,$restitle);
12522: $path .= join('/',@pathitems);
12523: }
12524: return ($path,$multiresp);
12525: }
12526:
12527: =pod
12528:
1.464 albertel 12529: =back
1.41 ng 12530:
1.112 bowersj2 12531: =head1 CSV Upload/Handling functions
1.38 albertel 12532:
1.41 ng 12533: =over 4
12534:
1.648 raeburn 12535: =item * &upfile_store($r)
1.41 ng 12536:
12537: Store uploaded file, $r should be the HTTP Request object,
1.258 albertel 12538: needs $env{'form.upfile'}
1.41 ng 12539: returns $datatoken to be put into hidden field
12540:
12541: =cut
1.31 albertel 12542:
12543: sub upfile_store {
12544: my $r=shift;
1.258 albertel 12545: $env{'form.upfile'}=~s/\r/\n/gs;
12546: $env{'form.upfile'}=~s/\f/\n/gs;
12547: $env{'form.upfile'}=~s/\n+/\n/gs;
12548: $env{'form.upfile'}=~s/\n+$//gs;
1.31 albertel 12549:
1.258 albertel 12550: my $datatoken=$env{'user.name'}.'_'.$env{'user.domain'}.
12551: '_enroll_'.$env{'request.course.id'}.'_'.time.'_'.$$;
1.31 albertel 12552: {
1.158 raeburn 12553: my $datafile = $r->dir_config('lonDaemons').
12554: '/tmp/'.$datatoken.'.tmp';
12555: if ( open(my $fh,">$datafile") ) {
1.258 albertel 12556: print $fh $env{'form.upfile'};
1.158 raeburn 12557: close($fh);
12558: }
1.31 albertel 12559: }
12560: return $datatoken;
12561: }
12562:
1.56 matthew 12563: =pod
12564:
1.648 raeburn 12565: =item * &load_tmp_file($r)
1.41 ng 12566:
12567: Load uploaded file from tmp, $r should be the HTTP Request object,
1.258 albertel 12568: needs $env{'form.datatoken'},
12569: sets $env{'form.upfile'} to the contents of the file
1.41 ng 12570:
12571: =cut
1.31 albertel 12572:
12573: sub load_tmp_file {
12574: my $r=shift;
12575: my @studentdata=();
12576: {
1.158 raeburn 12577: my $studentfile = $r->dir_config('lonDaemons').
1.258 albertel 12578: '/tmp/'.$env{'form.datatoken'}.'.tmp';
1.158 raeburn 12579: if ( open(my $fh,"<$studentfile") ) {
12580: @studentdata=<$fh>;
12581: close($fh);
12582: }
1.31 albertel 12583: }
1.258 albertel 12584: $env{'form.upfile'}=join('',@studentdata);
1.31 albertel 12585: }
12586:
1.56 matthew 12587: =pod
12588:
1.648 raeburn 12589: =item * &upfile_record_sep()
1.41 ng 12590:
12591: Separate uploaded file into records
12592: returns array of records,
1.258 albertel 12593: needs $env{'form.upfile'} and $env{'form.upfiletype'}
1.41 ng 12594:
12595: =cut
1.31 albertel 12596:
12597: sub upfile_record_sep {
1.258 albertel 12598: if ($env{'form.upfiletype'} eq 'xml') {
1.31 albertel 12599: } else {
1.248 albertel 12600: my @records;
1.258 albertel 12601: foreach my $line (split(/\n/,$env{'form.upfile'})) {
1.248 albertel 12602: if ($line=~/^\s*$/) { next; }
12603: push(@records,$line);
12604: }
12605: return @records;
1.31 albertel 12606: }
12607: }
12608:
1.56 matthew 12609: =pod
12610:
1.648 raeburn 12611: =item * &record_sep($record)
1.41 ng 12612:
1.258 albertel 12613: Separate a record into fields $record should be an item from the upfile_record_sep(), needs $env{'form.upfiletype'}
1.41 ng 12614:
12615: =cut
12616:
1.263 www 12617: sub takeleft {
12618: my $index=shift;
12619: return substr('0000'.$index,-4,4);
12620: }
12621:
1.31 albertel 12622: sub record_sep {
12623: my $record=shift;
12624: my %components=();
1.258 albertel 12625: if ($env{'form.upfiletype'} eq 'xml') {
12626: } elsif ($env{'form.upfiletype'} eq 'space') {
1.31 albertel 12627: my $i=0;
1.356 albertel 12628: foreach my $field (split(/\s+/,$record)) {
1.31 albertel 12629: $field=~s/^(\"|\')//;
12630: $field=~s/(\"|\')$//;
1.263 www 12631: $components{&takeleft($i)}=$field;
1.31 albertel 12632: $i++;
12633: }
1.258 albertel 12634: } elsif ($env{'form.upfiletype'} eq 'tab') {
1.31 albertel 12635: my $i=0;
1.356 albertel 12636: foreach my $field (split(/\t/,$record)) {
1.31 albertel 12637: $field=~s/^(\"|\')//;
12638: $field=~s/(\"|\')$//;
1.263 www 12639: $components{&takeleft($i)}=$field;
1.31 albertel 12640: $i++;
12641: }
12642: } else {
1.561 www 12643: my $separator=',';
1.480 banghart 12644: if ($env{'form.upfiletype'} eq 'semisv') {
1.561 www 12645: $separator=';';
1.480 banghart 12646: }
1.31 albertel 12647: my $i=0;
1.561 www 12648: # the character we are looking for to indicate the end of a quote or a record
12649: my $looking_for=$separator;
12650: # do not add the characters to the fields
12651: my $ignore=0;
12652: # we just encountered a separator (or the beginning of the record)
12653: my $just_found_separator=1;
12654: # store the field we are working on here
12655: my $field='';
12656: # work our way through all characters in record
12657: foreach my $character ($record=~/(.)/g) {
12658: if ($character eq $looking_for) {
12659: if ($character ne $separator) {
12660: # Found the end of a quote, again looking for separator
12661: $looking_for=$separator;
12662: $ignore=1;
12663: } else {
12664: # Found a separator, store away what we got
12665: $components{&takeleft($i)}=$field;
12666: $i++;
12667: $just_found_separator=1;
12668: $ignore=0;
12669: $field='';
12670: }
12671: next;
12672: }
12673: # single or double quotation marks after a separator indicate beginning of a quote
12674: # we are now looking for the end of the quote and need to ignore separators
12675: if ((($character eq '"') || ($character eq "'")) && ($just_found_separator)) {
12676: $looking_for=$character;
12677: next;
12678: }
12679: # ignore would be true after we reached the end of a quote
12680: if ($ignore) { next; }
12681: if (($just_found_separator) && ($character=~/\s/)) { next; }
12682: $field.=$character;
12683: $just_found_separator=0;
1.31 albertel 12684: }
1.561 www 12685: # catch the very last entry, since we never encountered the separator
12686: $components{&takeleft($i)}=$field;
1.31 albertel 12687: }
12688: return %components;
12689: }
12690:
1.144 matthew 12691: ######################################################
12692: ######################################################
12693:
1.56 matthew 12694: =pod
12695:
1.648 raeburn 12696: =item * &upfile_select_html()
1.41 ng 12697:
1.144 matthew 12698: Return HTML code to select a file from the users machine and specify
12699: the file type.
1.41 ng 12700:
12701: =cut
12702:
1.144 matthew 12703: ######################################################
12704: ######################################################
1.31 albertel 12705: sub upfile_select_html {
1.144 matthew 12706: my %Types = (
12707: csv => &mt('CSV (comma separated values, spreadsheet)'),
1.480 banghart 12708: semisv => &mt('Semicolon separated values'),
1.144 matthew 12709: space => &mt('Space separated'),
12710: tab => &mt('Tabulator separated'),
12711: # xml => &mt('HTML/XML'),
12712: );
12713: my $Str = '<input type="file" name="upfile" size="50" />'.
1.727 riegler 12714: '<br />'.&mt('Type').': <select name="upfiletype">';
1.144 matthew 12715: foreach my $type (sort(keys(%Types))) {
12716: $Str .= '<option value="'.$type.'" >'.$Types{$type}."</option>\n";
12717: }
12718: $Str .= "</select>\n";
12719: return $Str;
1.31 albertel 12720: }
12721:
1.301 albertel 12722: sub get_samples {
12723: my ($records,$toget) = @_;
12724: my @samples=({});
12725: my $got=0;
12726: foreach my $rec (@$records) {
12727: my %temp = &record_sep($rec);
12728: if (! grep(/\S/, values(%temp))) { next; }
12729: if (%temp) {
12730: $samples[$got]=\%temp;
12731: $got++;
12732: if ($got == $toget) { last; }
12733: }
12734: }
12735: return \@samples;
12736: }
12737:
1.144 matthew 12738: ######################################################
12739: ######################################################
12740:
1.56 matthew 12741: =pod
12742:
1.648 raeburn 12743: =item * &csv_print_samples($r,$records)
1.41 ng 12744:
12745: Prints a table of sample values from each column uploaded $r is an
12746: Apache Request ref, $records is an arrayref from
12747: &Apache::loncommon::upfile_record_sep
12748:
12749: =cut
12750:
1.144 matthew 12751: ######################################################
12752: ######################################################
1.31 albertel 12753: sub csv_print_samples {
12754: my ($r,$records) = @_;
1.662 bisitz 12755: my $samples = &get_samples($records,5);
1.301 albertel 12756:
1.594 raeburn 12757: $r->print(&mt('Samples').'<br />'.&start_data_table().
12758: &start_data_table_header_row());
1.356 albertel 12759: foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) {
1.845 bisitz 12760: $r->print('<th>'.&mt('Column [_1]',($sample+1)).'</th>'); }
1.594 raeburn 12761: $r->print(&end_data_table_header_row());
1.301 albertel 12762: foreach my $hash (@$samples) {
1.594 raeburn 12763: $r->print(&start_data_table_row());
1.356 albertel 12764: foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) {
1.31 albertel 12765: $r->print('<td>');
1.356 albertel 12766: if (defined($$hash{$sample})) { $r->print($$hash{$sample}); }
1.31 albertel 12767: $r->print('</td>');
12768: }
1.594 raeburn 12769: $r->print(&end_data_table_row());
1.31 albertel 12770: }
1.594 raeburn 12771: $r->print(&end_data_table().'<br />'."\n");
1.31 albertel 12772: }
12773:
1.144 matthew 12774: ######################################################
12775: ######################################################
12776:
1.56 matthew 12777: =pod
12778:
1.648 raeburn 12779: =item * &csv_print_select_table($r,$records,$d)
1.41 ng 12780:
12781: Prints a table to create associations between values and table columns.
1.144 matthew 12782:
1.41 ng 12783: $r is an Apache Request ref,
12784: $records is an arrayref from &Apache::loncommon::upfile_record_sep,
1.174 matthew 12785: $d is an array of 2 element arrays (internal name, displayed name,defaultcol)
1.41 ng 12786:
12787: =cut
12788:
1.144 matthew 12789: ######################################################
12790: ######################################################
1.31 albertel 12791: sub csv_print_select_table {
12792: my ($r,$records,$d) = @_;
1.301 albertel 12793: my $i=0;
12794: my $samples = &get_samples($records,1);
1.144 matthew 12795: $r->print(&mt('Associate columns with student attributes.')."\n".
1.594 raeburn 12796: &start_data_table().&start_data_table_header_row().
1.144 matthew 12797: '<th>'.&mt('Attribute').'</th>'.
1.594 raeburn 12798: '<th>'.&mt('Column').'</th>'.
12799: &end_data_table_header_row()."\n");
1.356 albertel 12800: foreach my $array_ref (@$d) {
12801: my ($value,$display,$defaultcol)=@{ $array_ref };
1.729 raeburn 12802: $r->print(&start_data_table_row().'<td>'.$display.'</td>');
1.31 albertel 12803:
1.875 bisitz 12804: $r->print('<td><select name="f'.$i.'"'.
1.32 matthew 12805: ' onchange="javascript:flip(this.form,'.$i.');">');
1.31 albertel 12806: $r->print('<option value="none"></option>');
1.356 albertel 12807: foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) {
12808: $r->print('<option value="'.$sample.'"'.
12809: ($sample eq $defaultcol ? ' selected="selected" ' : '').
1.662 bisitz 12810: '>'.&mt('Column [_1]',($sample+1)).'</option>');
1.31 albertel 12811: }
1.594 raeburn 12812: $r->print('</select></td>'.&end_data_table_row()."\n");
1.31 albertel 12813: $i++;
12814: }
1.594 raeburn 12815: $r->print(&end_data_table());
1.31 albertel 12816: $i--;
12817: return $i;
12818: }
1.56 matthew 12819:
1.144 matthew 12820: ######################################################
12821: ######################################################
12822:
1.56 matthew 12823: =pod
1.31 albertel 12824:
1.648 raeburn 12825: =item * &csv_samples_select_table($r,$records,$d)
1.41 ng 12826:
12827: Prints a table of sample values from the upload and can make associate samples to internal names.
12828:
12829: $r is an Apache Request ref,
12830: $records is an arrayref from &Apache::loncommon::upfile_record_sep,
12831: $d is an array of 2 element arrays (internal name, displayed name)
12832:
12833: =cut
12834:
1.144 matthew 12835: ######################################################
12836: ######################################################
1.31 albertel 12837: sub csv_samples_select_table {
12838: my ($r,$records,$d) = @_;
12839: my $i=0;
1.144 matthew 12840: #
1.662 bisitz 12841: my $max_samples = 5;
12842: my $samples = &get_samples($records,$max_samples);
1.594 raeburn 12843: $r->print(&start_data_table().
12844: &start_data_table_header_row().'<th>'.
12845: &mt('Field').'</th><th>'.&mt('Samples').'</th>'.
12846: &end_data_table_header_row());
1.301 albertel 12847:
12848: foreach my $key (sort(keys(%{ $samples->[0] }))) {
1.594 raeburn 12849: $r->print(&start_data_table_row().'<td><select name="f'.$i.'"'.
1.32 matthew 12850: ' onchange="javascript:flip(this.form,'.$i.');">');
1.301 albertel 12851: foreach my $option (@$d) {
12852: my ($value,$display,$defaultcol)=@{ $option };
1.174 matthew 12853: $r->print('<option value="'.$value.'"'.
1.253 albertel 12854: ($i eq $defaultcol ? ' selected="selected" ':'').'>'.
1.174 matthew 12855: $display.'</option>');
1.31 albertel 12856: }
12857: $r->print('</select></td><td>');
1.662 bisitz 12858: foreach my $line (0..($max_samples-1)) {
1.301 albertel 12859: if (defined($samples->[$line]{$key})) {
12860: $r->print($samples->[$line]{$key}."<br />\n");
12861: }
12862: }
1.594 raeburn 12863: $r->print('</td>'.&end_data_table_row());
1.31 albertel 12864: $i++;
12865: }
1.594 raeburn 12866: $r->print(&end_data_table());
1.31 albertel 12867: $i--;
12868: return($i);
1.115 matthew 12869: }
12870:
1.144 matthew 12871: ######################################################
12872: ######################################################
12873:
1.115 matthew 12874: =pod
12875:
1.648 raeburn 12876: =item * &clean_excel_name($name)
1.115 matthew 12877:
12878: Returns a replacement for $name which does not contain any illegal characters.
12879:
12880: =cut
12881:
1.144 matthew 12882: ######################################################
12883: ######################################################
1.115 matthew 12884: sub clean_excel_name {
12885: my ($name) = @_;
12886: $name =~ s/[:\*\?\/\\]//g;
12887: if (length($name) > 31) {
12888: $name = substr($name,0,31);
12889: }
12890: return $name;
1.25 albertel 12891: }
1.84 albertel 12892:
1.85 albertel 12893: =pod
12894:
1.648 raeburn 12895: =item * &check_if_partid_hidden($id,$symb,$udom,$uname)
1.85 albertel 12896:
12897: Returns either 1 or undef
12898:
12899: 1 if the part is to be hidden, undef if it is to be shown
12900:
12901: Arguments are:
12902:
12903: $id the id of the part to be checked
12904: $symb, optional the symb of the resource to check
12905: $udom, optional the domain of the user to check for
12906: $uname, optional the username of the user to check for
12907:
12908: =cut
1.84 albertel 12909:
12910: sub check_if_partid_hidden {
12911: my ($id,$symb,$udom,$uname) = @_;
1.133 albertel 12912: my $hiddenparts=&Apache::lonnet::EXT('resource.0.hiddenparts',
1.84 albertel 12913: $symb,$udom,$uname);
1.141 albertel 12914: my $truth=1;
12915: #if the string starts with !, then the list is the list to show not hide
12916: if ($hiddenparts=~s/^\s*!//) { $truth=undef; }
1.84 albertel 12917: my @hiddenlist=split(/,/,$hiddenparts);
12918: foreach my $checkid (@hiddenlist) {
1.141 albertel 12919: if ($checkid =~ /^\s*\Q$id\E\s*$/) { return $truth; }
1.84 albertel 12920: }
1.141 albertel 12921: return !$truth;
1.84 albertel 12922: }
1.127 matthew 12923:
1.138 matthew 12924:
12925: ############################################################
12926: ############################################################
12927:
12928: =pod
12929:
1.157 matthew 12930: =back
12931:
1.138 matthew 12932: =head1 cgi-bin script and graphing routines
12933:
1.157 matthew 12934: =over 4
12935:
1.648 raeburn 12936: =item * &get_cgi_id()
1.138 matthew 12937:
12938: Inputs: none
12939:
12940: Returns an id which can be used to pass environment variables
12941: to various cgi-bin scripts. These environment variables will
12942: be removed from the users environment after a given time by
12943: the routine &Apache::lonnet::transfer_profile_to_env.
12944:
12945: =cut
12946:
12947: ############################################################
12948: ############################################################
1.152 albertel 12949: my $uniq=0;
1.136 matthew 12950: sub get_cgi_id {
1.154 albertel 12951: $uniq=($uniq+1)%100000;
1.280 albertel 12952: return (time.'_'.$$.'_'.$uniq);
1.136 matthew 12953: }
12954:
1.127 matthew 12955: ############################################################
12956: ############################################################
12957:
12958: =pod
12959:
1.648 raeburn 12960: =item * &DrawBarGraph()
1.127 matthew 12961:
1.138 matthew 12962: Facilitates the plotting of data in a (stacked) bar graph.
12963: Puts plot definition data into the users environment in order for
12964: graph.png to plot it. Returns an <img> tag for the plot.
12965: The bars on the plot are labeled '1','2',...,'n'.
12966:
12967: Inputs:
12968:
12969: =over 4
12970:
12971: =item $Title: string, the title of the plot
12972:
12973: =item $xlabel: string, text describing the X-axis of the plot
12974:
12975: =item $ylabel: string, text describing the Y-axis of the plot
12976:
12977: =item $Max: scalar, the maximum Y value to use in the plot
12978: If $Max is < any data point, the graph will not be rendered.
12979:
1.140 matthew 12980: =item $colors: array ref holding the colors to be used for the data sets when
1.138 matthew 12981: they are plotted. If undefined, default values will be used.
12982:
1.178 matthew 12983: =item $labels: array ref holding the labels to use on the x-axis for the bars.
12984:
1.138 matthew 12985: =item @Values: An array of array references. Each array reference holds data
12986: to be plotted in a stacked bar chart.
12987:
1.239 matthew 12988: =item If the final element of @Values is a hash reference the key/value
12989: pairs will be added to the graph definition.
12990:
1.138 matthew 12991: =back
12992:
12993: Returns:
12994:
12995: An <img> tag which references graph.png and the appropriate identifying
12996: information for the plot.
12997:
1.127 matthew 12998: =cut
12999:
13000: ############################################################
13001: ############################################################
1.134 matthew 13002: sub DrawBarGraph {
1.178 matthew 13003: my ($Title,$xlabel,$ylabel,$Max,$colors,$labels,@Values)=@_;
1.134 matthew 13004: #
13005: if (! defined($colors)) {
13006: $colors = ['#33ff00',
13007: '#0033cc', '#990000', '#aaaa66', '#663399', '#ff9933',
13008: '#66ccff', '#ff9999', '#cccc33', '#660000', '#33cc66',
13009: ];
13010: }
1.228 matthew 13011: my $extra_settings = {};
13012: if (ref($Values[-1]) eq 'HASH') {
13013: $extra_settings = pop(@Values);
13014: }
1.127 matthew 13015: #
1.136 matthew 13016: my $identifier = &get_cgi_id();
13017: my $id = 'cgi.'.$identifier;
1.129 matthew 13018: if (! @Values || ref($Values[0]) ne 'ARRAY') {
1.127 matthew 13019: return '';
13020: }
1.225 matthew 13021: #
13022: my @Labels;
13023: if (defined($labels)) {
13024: @Labels = @$labels;
13025: } else {
13026: for (my $i=0;$i<@{$Values[0]};$i++) {
13027: push (@Labels,$i+1);
13028: }
13029: }
13030: #
1.129 matthew 13031: my $NumBars = scalar(@{$Values[0]});
1.225 matthew 13032: if ($NumBars < scalar(@Labels)) { $NumBars = scalar(@Labels); }
1.129 matthew 13033: my %ValuesHash;
13034: my $NumSets=1;
13035: foreach my $array (@Values) {
13036: next if (! ref($array));
1.136 matthew 13037: $ValuesHash{$id.'.data.'.$NumSets++} =
1.132 matthew 13038: join(',',@$array);
1.129 matthew 13039: }
1.127 matthew 13040: #
1.136 matthew 13041: my ($height,$width,$xskip,$bar_width) = (200,120,1,15);
1.225 matthew 13042: if ($NumBars < 3) {
13043: $width = 120+$NumBars*32;
1.220 matthew 13044: $xskip = 1;
1.225 matthew 13045: $bar_width = 30;
13046: } elsif ($NumBars < 5) {
13047: $width = 120+$NumBars*20;
13048: $xskip = 1;
13049: $bar_width = 20;
1.220 matthew 13050: } elsif ($NumBars < 10) {
1.136 matthew 13051: $width = 120+$NumBars*15;
13052: $xskip = 1;
13053: $bar_width = 15;
13054: } elsif ($NumBars <= 25) {
13055: $width = 120+$NumBars*11;
13056: $xskip = 5;
13057: $bar_width = 8;
13058: } elsif ($NumBars <= 50) {
13059: $width = 120+$NumBars*8;
13060: $xskip = 5;
13061: $bar_width = 4;
13062: } else {
13063: $width = 120+$NumBars*8;
13064: $xskip = 5;
13065: $bar_width = 4;
13066: }
13067: #
1.137 matthew 13068: $Max = 1 if ($Max < 1);
13069: if ( int($Max) < $Max ) {
13070: $Max++;
13071: $Max = int($Max);
13072: }
1.127 matthew 13073: $Title = '' if (! defined($Title));
13074: $xlabel = '' if (! defined($xlabel));
13075: $ylabel = '' if (! defined($ylabel));
1.369 www 13076: $ValuesHash{$id.'.title'} = &escape($Title);
13077: $ValuesHash{$id.'.xlabel'} = &escape($xlabel);
13078: $ValuesHash{$id.'.ylabel'} = &escape($ylabel);
1.137 matthew 13079: $ValuesHash{$id.'.y_max_value'} = $Max;
1.136 matthew 13080: $ValuesHash{$id.'.NumBars'} = $NumBars;
13081: $ValuesHash{$id.'.NumSets'} = $NumSets;
13082: $ValuesHash{$id.'.PlotType'} = 'bar';
13083: $ValuesHash{$id.'.Colors'} = join(',',@{$colors});
13084: $ValuesHash{$id.'.height'} = $height;
13085: $ValuesHash{$id.'.width'} = $width;
13086: $ValuesHash{$id.'.xskip'} = $xskip;
13087: $ValuesHash{$id.'.bar_width'} = $bar_width;
13088: $ValuesHash{$id.'.labels'} = join(',',@Labels);
1.127 matthew 13089: #
1.228 matthew 13090: # Deal with other parameters
13091: while (my ($key,$value) = each(%$extra_settings)) {
13092: $ValuesHash{$id.'.'.$key} = $value;
13093: }
13094: #
1.646 raeburn 13095: &Apache::lonnet::appenv(\%ValuesHash);
1.137 matthew 13096: return '<img src="/cgi-bin/graph.png?'.$identifier.'" border="1" />';
13097: }
13098:
13099: ############################################################
13100: ############################################################
13101:
13102: =pod
13103:
1.648 raeburn 13104: =item * &DrawXYGraph()
1.137 matthew 13105:
1.138 matthew 13106: Facilitates the plotting of data in an XY graph.
13107: Puts plot definition data into the users environment in order for
13108: graph.png to plot it. Returns an <img> tag for the plot.
13109:
13110: Inputs:
13111:
13112: =over 4
13113:
13114: =item $Title: string, the title of the plot
13115:
13116: =item $xlabel: string, text describing the X-axis of the plot
13117:
13118: =item $ylabel: string, text describing the Y-axis of the plot
13119:
13120: =item $Max: scalar, the maximum Y value to use in the plot
13121: If $Max is < any data point, the graph will not be rendered.
13122:
13123: =item $colors: Array ref containing the hex color codes for the data to be
13124: plotted in. If undefined, default values will be used.
13125:
13126: =item $Xlabels: Array ref containing the labels to be used for the X-axis.
13127:
13128: =item $Ydata: Array ref containing Array refs.
1.185 www 13129: Each of the contained arrays will be plotted as a separate curve.
1.138 matthew 13130:
13131: =item %Values: hash indicating or overriding any default values which are
13132: passed to graph.png.
13133: Possible values are: width, xskip, x_ticks, x_tick_offset, among others.
13134:
13135: =back
13136:
13137: Returns:
13138:
13139: An <img> tag which references graph.png and the appropriate identifying
13140: information for the plot.
13141:
1.137 matthew 13142: =cut
13143:
13144: ############################################################
13145: ############################################################
13146: sub DrawXYGraph {
13147: my ($Title,$xlabel,$ylabel,$Max,$colors,$Xlabels,$Ydata,%Values)=@_;
13148: #
13149: # Create the identifier for the graph
13150: my $identifier = &get_cgi_id();
13151: my $id = 'cgi.'.$identifier;
13152: #
13153: $Title = '' if (! defined($Title));
13154: $xlabel = '' if (! defined($xlabel));
13155: $ylabel = '' if (! defined($ylabel));
13156: my %ValuesHash =
13157: (
1.369 www 13158: $id.'.title' => &escape($Title),
13159: $id.'.xlabel' => &escape($xlabel),
13160: $id.'.ylabel' => &escape($ylabel),
1.137 matthew 13161: $id.'.y_max_value'=> $Max,
13162: $id.'.labels' => join(',',@$Xlabels),
13163: $id.'.PlotType' => 'XY',
13164: );
13165: #
13166: if (defined($colors) && ref($colors) eq 'ARRAY') {
13167: $ValuesHash{$id.'.Colors'} = join(',',@{$colors});
13168: }
13169: #
13170: if (! ref($Ydata) || ref($Ydata) ne 'ARRAY') {
13171: return '';
13172: }
13173: my $NumSets=1;
1.138 matthew 13174: foreach my $array (@{$Ydata}){
1.137 matthew 13175: next if (! ref($array));
13176: $ValuesHash{$id.'.data.'.$NumSets++} = join(',',@$array);
13177: }
1.138 matthew 13178: $ValuesHash{$id.'.NumSets'} = $NumSets-1;
1.137 matthew 13179: #
13180: # Deal with other parameters
13181: while (my ($key,$value) = each(%Values)) {
13182: $ValuesHash{$id.'.'.$key} = $value;
1.127 matthew 13183: }
13184: #
1.646 raeburn 13185: &Apache::lonnet::appenv(\%ValuesHash);
1.136 matthew 13186: return '<img src="/cgi-bin/graph.png?'.$identifier.'" border="1" />';
13187: }
13188:
13189: ############################################################
13190: ############################################################
13191:
13192: =pod
13193:
1.648 raeburn 13194: =item * &DrawXYYGraph()
1.138 matthew 13195:
13196: Facilitates the plotting of data in an XY graph with two Y axes.
13197: Puts plot definition data into the users environment in order for
13198: graph.png to plot it. Returns an <img> tag for the plot.
13199:
13200: Inputs:
13201:
13202: =over 4
13203:
13204: =item $Title: string, the title of the plot
13205:
13206: =item $xlabel: string, text describing the X-axis of the plot
13207:
13208: =item $ylabel: string, text describing the Y-axis of the plot
13209:
13210: =item $colors: Array ref containing the hex color codes for the data to be
13211: plotted in. If undefined, default values will be used.
13212:
13213: =item $Xlabels: Array ref containing the labels to be used for the X-axis.
13214:
13215: =item $Ydata1: The first data set
13216:
13217: =item $Min1: The minimum value of the left Y-axis
13218:
13219: =item $Max1: The maximum value of the left Y-axis
13220:
13221: =item $Ydata2: The second data set
13222:
13223: =item $Min2: The minimum value of the right Y-axis
13224:
13225: =item $Max2: The maximum value of the left Y-axis
13226:
13227: =item %Values: hash indicating or overriding any default values which are
13228: passed to graph.png.
13229: Possible values are: width, xskip, x_ticks, x_tick_offset, among others.
13230:
13231: =back
13232:
13233: Returns:
13234:
13235: An <img> tag which references graph.png and the appropriate identifying
13236: information for the plot.
1.136 matthew 13237:
13238: =cut
13239:
13240: ############################################################
13241: ############################################################
1.137 matthew 13242: sub DrawXYYGraph {
13243: my ($Title,$xlabel,$ylabel,$colors,$Xlabels,$Ydata1,$Min1,$Max1,
13244: $Ydata2,$Min2,$Max2,%Values)=@_;
1.136 matthew 13245: #
13246: # Create the identifier for the graph
13247: my $identifier = &get_cgi_id();
13248: my $id = 'cgi.'.$identifier;
13249: #
13250: $Title = '' if (! defined($Title));
13251: $xlabel = '' if (! defined($xlabel));
13252: $ylabel = '' if (! defined($ylabel));
13253: my %ValuesHash =
13254: (
1.369 www 13255: $id.'.title' => &escape($Title),
13256: $id.'.xlabel' => &escape($xlabel),
13257: $id.'.ylabel' => &escape($ylabel),
1.136 matthew 13258: $id.'.labels' => join(',',@$Xlabels),
13259: $id.'.PlotType' => 'XY',
13260: $id.'.NumSets' => 2,
1.137 matthew 13261: $id.'.two_axes' => 1,
13262: $id.'.y1_max_value' => $Max1,
13263: $id.'.y1_min_value' => $Min1,
13264: $id.'.y2_max_value' => $Max2,
13265: $id.'.y2_min_value' => $Min2,
1.136 matthew 13266: );
13267: #
1.137 matthew 13268: if (defined($colors) && ref($colors) eq 'ARRAY') {
13269: $ValuesHash{$id.'.Colors'} = join(',',@{$colors});
13270: }
13271: #
13272: if (! ref($Ydata1) || ref($Ydata1) ne 'ARRAY' ||
13273: ! ref($Ydata2) || ref($Ydata2) ne 'ARRAY'){
1.136 matthew 13274: return '';
13275: }
13276: my $NumSets=1;
1.137 matthew 13277: foreach my $array ($Ydata1,$Ydata2){
1.136 matthew 13278: next if (! ref($array));
13279: $ValuesHash{$id.'.data.'.$NumSets++} = join(',',@$array);
1.137 matthew 13280: }
13281: #
13282: # Deal with other parameters
13283: while (my ($key,$value) = each(%Values)) {
13284: $ValuesHash{$id.'.'.$key} = $value;
1.136 matthew 13285: }
13286: #
1.646 raeburn 13287: &Apache::lonnet::appenv(\%ValuesHash);
1.130 albertel 13288: return '<img src="/cgi-bin/graph.png?'.$identifier.'" border="1" />';
1.139 matthew 13289: }
13290:
13291: ############################################################
13292: ############################################################
13293:
13294: =pod
13295:
1.157 matthew 13296: =back
13297:
1.139 matthew 13298: =head1 Statistics helper routines?
13299:
13300: Bad place for them but what the hell.
13301:
1.157 matthew 13302: =over 4
13303:
1.648 raeburn 13304: =item * &chartlink()
1.139 matthew 13305:
13306: Returns a link to the chart for a specific student.
13307:
13308: Inputs:
13309:
13310: =over 4
13311:
13312: =item $linktext: The text of the link
13313:
13314: =item $sname: The students username
13315:
13316: =item $sdomain: The students domain
13317:
13318: =back
13319:
1.157 matthew 13320: =back
13321:
1.139 matthew 13322: =cut
13323:
13324: ############################################################
13325: ############################################################
13326: sub chartlink {
13327: my ($linktext, $sname, $sdomain) = @_;
13328: my $link = '<a href="/adm/statistics?reportSelected=student_assessment'.
1.369 www 13329: '&SelectedStudent='.&escape($sname.':'.$sdomain).
1.219 albertel 13330: '&chartoutputmode='.HTML::Entities::encode('html, with all links').
1.139 matthew 13331: '">'.$linktext.'</a>';
1.153 matthew 13332: }
13333:
13334: #######################################################
13335: #######################################################
13336:
13337: =pod
13338:
13339: =head1 Course Environment Routines
1.157 matthew 13340:
13341: =over 4
1.153 matthew 13342:
1.648 raeburn 13343: =item * &restore_course_settings()
1.153 matthew 13344:
1.648 raeburn 13345: =item * &store_course_settings()
1.153 matthew 13346:
13347: Restores/Store indicated form parameters from the course environment.
13348: Will not overwrite existing values of the form parameters.
13349:
13350: Inputs:
13351: a scalar describing the data (e.g. 'chart', 'problem_analysis')
13352:
13353: a hash ref describing the data to be stored. For example:
13354:
13355: %Save_Parameters = ('Status' => 'scalar',
13356: 'chartoutputmode' => 'scalar',
13357: 'chartoutputdata' => 'scalar',
13358: 'Section' => 'array',
1.373 raeburn 13359: 'Group' => 'array',
1.153 matthew 13360: 'StudentData' => 'array',
13361: 'Maps' => 'array');
13362:
13363: Returns: both routines return nothing
13364:
1.631 raeburn 13365: =back
13366:
1.153 matthew 13367: =cut
13368:
13369: #######################################################
13370: #######################################################
13371: sub store_course_settings {
1.496 albertel 13372: return &store_settings($env{'request.course.id'},@_);
13373: }
13374:
13375: sub store_settings {
1.153 matthew 13376: # save to the environment
13377: # appenv the same items, just to be safe
1.300 albertel 13378: my $udom = $env{'user.domain'};
13379: my $uname = $env{'user.name'};
1.496 albertel 13380: my ($context,$prefix,$Settings) = @_;
1.153 matthew 13381: my %SaveHash;
13382: my %AppHash;
13383: while (my ($setting,$type) = each(%$Settings)) {
1.496 albertel 13384: my $basename = join('.','internal',$context,$prefix,$setting);
1.300 albertel 13385: my $envname = 'environment.'.$basename;
1.258 albertel 13386: if (exists($env{'form.'.$setting})) {
1.153 matthew 13387: # Save this value away
13388: if ($type eq 'scalar' &&
1.258 albertel 13389: (! exists($env{$envname}) ||
13390: $env{$envname} ne $env{'form.'.$setting})) {
13391: $SaveHash{$basename} = $env{'form.'.$setting};
13392: $AppHash{$envname} = $env{'form.'.$setting};
1.153 matthew 13393: } elsif ($type eq 'array') {
13394: my $stored_form;
1.258 albertel 13395: if (ref($env{'form.'.$setting})) {
1.153 matthew 13396: $stored_form = join(',',
13397: map {
1.369 www 13398: &escape($_);
1.258 albertel 13399: } sort(@{$env{'form.'.$setting}}));
1.153 matthew 13400: } else {
13401: $stored_form =
1.369 www 13402: &escape($env{'form.'.$setting});
1.153 matthew 13403: }
13404: # Determine if the array contents are the same.
1.258 albertel 13405: if ($stored_form ne $env{$envname}) {
1.153 matthew 13406: $SaveHash{$basename} = $stored_form;
13407: $AppHash{$envname} = $stored_form;
13408: }
13409: }
13410: }
13411: }
13412: my $put_result = &Apache::lonnet::put('environment',\%SaveHash,
1.300 albertel 13413: $udom,$uname);
1.153 matthew 13414: if ($put_result !~ /^(ok|delayed)/) {
13415: &Apache::lonnet::logthis('unable to save form parameters, '.
13416: 'got error:'.$put_result);
13417: }
13418: # Make sure these settings stick around in this session, too
1.646 raeburn 13419: &Apache::lonnet::appenv(\%AppHash);
1.153 matthew 13420: return;
13421: }
13422:
13423: sub restore_course_settings {
1.499 albertel 13424: return &restore_settings($env{'request.course.id'},@_);
1.496 albertel 13425: }
13426:
13427: sub restore_settings {
13428: my ($context,$prefix,$Settings) = @_;
1.153 matthew 13429: while (my ($setting,$type) = each(%$Settings)) {
1.258 albertel 13430: next if (exists($env{'form.'.$setting}));
1.496 albertel 13431: my $envname = 'environment.internal.'.$context.'.'.$prefix.
1.153 matthew 13432: '.'.$setting;
1.258 albertel 13433: if (exists($env{$envname})) {
1.153 matthew 13434: if ($type eq 'scalar') {
1.258 albertel 13435: $env{'form.'.$setting} = $env{$envname};
1.153 matthew 13436: } elsif ($type eq 'array') {
1.258 albertel 13437: $env{'form.'.$setting} = [
1.153 matthew 13438: map {
1.369 www 13439: &unescape($_);
1.258 albertel 13440: } split(',',$env{$envname})
1.153 matthew 13441: ];
13442: }
13443: }
13444: }
1.127 matthew 13445: }
13446:
1.618 raeburn 13447: #######################################################
13448: #######################################################
13449:
13450: =pod
13451:
13452: =head1 Domain E-mail Routines
13453:
13454: =over 4
13455:
1.648 raeburn 13456: =item * &build_recipient_list()
1.618 raeburn 13457:
1.1075.2.44 raeburn 13458: Build recipient lists for following types of e-mail:
1.766 raeburn 13459: (a) Error Reports, (b) Package Updates, (c) lonstatus warnings/errors
1.1075.2.44 raeburn 13460: (d) Help requests, (e) Course requests needing approval, (f) loncapa
13461: module change checking, student/employee ID conflict checks, as
13462: generated by lonerrorhandler.pm, CHECKRPMS, loncron,
13463: lonsupportreq.pm, loncoursequeueadmin.pm, searchcat.pl respectively.
1.618 raeburn 13464:
13465: Inputs:
1.1075.2.44 raeburn 13466: defmail (scalar - email address of default recipient),
13467: mailing type (scalar: errormail, packagesmail, helpdeskmail,
13468: requestsmail, updatesmail, or idconflictsmail).
13469:
1.619 raeburn 13470: defdom (domain for which to retrieve configuration settings),
1.1075.2.44 raeburn 13471:
13472: origmail (scalar - email address of recipient from loncapa.conf,
13473: i.e., predates configuration by DC via domainprefs.pm
1.618 raeburn 13474:
1.655 raeburn 13475: Returns: comma separated list of addresses to which to send e-mail.
13476:
13477: =back
1.618 raeburn 13478:
13479: =cut
13480:
13481: ############################################################
13482: ############################################################
13483: sub build_recipient_list {
1.619 raeburn 13484: my ($defmail,$mailing,$defdom,$origmail) = @_;
1.618 raeburn 13485: my @recipients;
13486: my $otheremails;
13487: my %domconfig =
13488: &Apache::lonnet::get_dom('configuration',['contacts'],$defdom);
13489: if (ref($domconfig{'contacts'}) eq 'HASH') {
1.766 raeburn 13490: if (exists($domconfig{'contacts'}{$mailing})) {
13491: if (ref($domconfig{'contacts'}{$mailing}) eq 'HASH') {
13492: my @contacts = ('adminemail','supportemail');
13493: foreach my $item (@contacts) {
13494: if ($domconfig{'contacts'}{$mailing}{$item}) {
13495: my $addr = $domconfig{'contacts'}{$item};
13496: if (!grep(/^\Q$addr\E$/,@recipients)) {
13497: push(@recipients,$addr);
13498: }
1.619 raeburn 13499: }
1.766 raeburn 13500: $otheremails = $domconfig{'contacts'}{$mailing}{'others'};
1.618 raeburn 13501: }
13502: }
1.766 raeburn 13503: } elsif ($origmail ne '') {
13504: push(@recipients,$origmail);
1.618 raeburn 13505: }
1.619 raeburn 13506: } elsif ($origmail ne '') {
13507: push(@recipients,$origmail);
1.618 raeburn 13508: }
1.688 raeburn 13509: if (defined($defmail)) {
13510: if ($defmail ne '') {
13511: push(@recipients,$defmail);
13512: }
1.618 raeburn 13513: }
13514: if ($otheremails) {
1.619 raeburn 13515: my @others;
13516: if ($otheremails =~ /,/) {
13517: @others = split(/,/,$otheremails);
1.618 raeburn 13518: } else {
1.619 raeburn 13519: push(@others,$otheremails);
13520: }
13521: foreach my $addr (@others) {
13522: if (!grep(/^\Q$addr\E$/,@recipients)) {
13523: push(@recipients,$addr);
13524: }
1.618 raeburn 13525: }
13526: }
1.619 raeburn 13527: my $recipientlist = join(',',@recipients);
1.618 raeburn 13528: return $recipientlist;
13529: }
13530:
1.127 matthew 13531: ############################################################
13532: ############################################################
1.154 albertel 13533:
1.655 raeburn 13534: =pod
13535:
13536: =head1 Course Catalog Routines
13537:
13538: =over 4
13539:
13540: =item * &gather_categories()
13541:
13542: Converts category definitions - keys of categories hash stored in
13543: coursecategories in configuration.db on the primary library server in a
13544: domain - to an array. Also generates javascript and idx hash used to
13545: generate Domain Coordinator interface for editing Course Categories.
13546:
13547: Inputs:
1.663 raeburn 13548:
1.655 raeburn 13549: categories (reference to hash of category definitions).
1.663 raeburn 13550:
1.655 raeburn 13551: cats (reference to array of arrays/hashes which encapsulates hierarchy of
13552: categories and subcategories).
1.663 raeburn 13553:
1.655 raeburn 13554: idx (reference to hash of counters used in Domain Coordinator interface for
13555: editing Course Categories).
1.663 raeburn 13556:
1.655 raeburn 13557: jsarray (reference to array of categories used to create Javascript arrays for
13558: Domain Coordinator interface for editing Course Categories).
13559:
13560: Returns: nothing
13561:
13562: Side effects: populates cats, idx and jsarray.
13563:
13564: =cut
13565:
13566: sub gather_categories {
13567: my ($categories,$cats,$idx,$jsarray) = @_;
13568: my %counters;
13569: my $num = 0;
13570: foreach my $item (keys(%{$categories})) {
13571: my ($cat,$container,$depth) = map { &unescape($_); } split(/:/,$item);
13572: if ($container eq '' && $depth == 0) {
13573: $cats->[$depth][$categories->{$item}] = $cat;
13574: } else {
13575: $cats->[$depth]{$container}[$categories->{$item}] = $cat;
13576: }
13577: my ($escitem,$tail) = split(/:/,$item,2);
13578: if ($counters{$tail} eq '') {
13579: $counters{$tail} = $num;
13580: $num ++;
13581: }
13582: if (ref($idx) eq 'HASH') {
13583: $idx->{$item} = $counters{$tail};
13584: }
13585: if (ref($jsarray) eq 'ARRAY') {
13586: push(@{$jsarray->[$counters{$tail}]},$item);
13587: }
13588: }
13589: return;
13590: }
13591:
13592: =pod
13593:
13594: =item * &extract_categories()
13595:
13596: Used to generate breadcrumb trails for course categories.
13597:
13598: Inputs:
1.663 raeburn 13599:
1.655 raeburn 13600: categories (reference to hash of category definitions).
1.663 raeburn 13601:
1.655 raeburn 13602: cats (reference to array of arrays/hashes which encapsulates hierarchy of
13603: categories and subcategories).
1.663 raeburn 13604:
1.655 raeburn 13605: trails (reference to array of breacrumb trails for each category).
1.663 raeburn 13606:
1.655 raeburn 13607: allitems (reference to hash - key is category key
13608: (format: escaped(name):escaped(parent category):depth in hierarchy).
1.663 raeburn 13609:
1.655 raeburn 13610: idx (reference to hash of counters used in Domain Coordinator interface for
13611: editing Course Categories).
1.663 raeburn 13612:
1.655 raeburn 13613: jsarray (reference to array of categories used to create Javascript arrays for
13614: Domain Coordinator interface for editing Course Categories).
13615:
1.665 raeburn 13616: subcats (reference to hash of arrays containing all subcategories within each
13617: category, -recursive)
13618:
1.655 raeburn 13619: Returns: nothing
13620:
13621: Side effects: populates trails and allitems hash references.
13622:
13623: =cut
13624:
13625: sub extract_categories {
1.665 raeburn 13626: my ($categories,$cats,$trails,$allitems,$idx,$jsarray,$subcats) = @_;
1.655 raeburn 13627: if (ref($categories) eq 'HASH') {
13628: &gather_categories($categories,$cats,$idx,$jsarray);
13629: if (ref($cats->[0]) eq 'ARRAY') {
13630: for (my $i=0; $i<@{$cats->[0]}; $i++) {
13631: my $name = $cats->[0][$i];
13632: my $item = &escape($name).'::0';
13633: my $trailstr;
13634: if ($name eq 'instcode') {
13635: $trailstr = &mt('Official courses (with institutional codes)');
1.919 raeburn 13636: } elsif ($name eq 'communities') {
13637: $trailstr = &mt('Communities');
1.655 raeburn 13638: } else {
13639: $trailstr = $name;
13640: }
13641: if ($allitems->{$item} eq '') {
13642: push(@{$trails},$trailstr);
13643: $allitems->{$item} = scalar(@{$trails})-1;
13644: }
13645: my @parents = ($name);
13646: if (ref($cats->[1]{$name}) eq 'ARRAY') {
13647: for (my $j=0; $j<@{$cats->[1]{$name}}; $j++) {
13648: my $category = $cats->[1]{$name}[$j];
1.665 raeburn 13649: if (ref($subcats) eq 'HASH') {
13650: push(@{$subcats->{$item}},&escape($category).':'.&escape($name).':1');
13651: }
13652: &recurse_categories($cats,2,$category,$trails,$allitems,\@parents,$subcats);
13653: }
13654: } else {
13655: if (ref($subcats) eq 'HASH') {
13656: $subcats->{$item} = [];
1.655 raeburn 13657: }
13658: }
13659: }
13660: }
13661: }
13662: return;
13663: }
13664:
13665: =pod
13666:
1.1075.2.56 raeburn 13667: =item * &recurse_categories()
1.655 raeburn 13668:
13669: Recursively used to generate breadcrumb trails for course categories.
13670:
13671: Inputs:
1.663 raeburn 13672:
1.655 raeburn 13673: cats (reference to array of arrays/hashes which encapsulates hierarchy of
13674: categories and subcategories).
1.663 raeburn 13675:
1.655 raeburn 13676: depth (current depth in hierarchy of categories and sub-categories - 0 indexed).
1.663 raeburn 13677:
13678: category (current course category, for which breadcrumb trail is being generated).
13679:
13680: trails (reference to array of breadcrumb trails for each category).
13681:
1.655 raeburn 13682: allitems (reference to hash - key is category key
13683: (format: escaped(name):escaped(parent category):depth in hierarchy).
1.663 raeburn 13684:
1.655 raeburn 13685: parents (array containing containers directories for current category,
13686: back to top level).
13687:
13688: Returns: nothing
13689:
13690: Side effects: populates trails and allitems hash references
13691:
13692: =cut
13693:
13694: sub recurse_categories {
1.665 raeburn 13695: my ($cats,$depth,$category,$trails,$allitems,$parents,$subcats) = @_;
1.655 raeburn 13696: my $shallower = $depth - 1;
13697: if (ref($cats->[$depth]{$category}) eq 'ARRAY') {
13698: for (my $k=0; $k<@{$cats->[$depth]{$category}}; $k++) {
13699: my $name = $cats->[$depth]{$category}[$k];
13700: my $item = &escape($category).':'.&escape($parents->[-1]).':'.$shallower;
13701: my $trailstr = join(' -> ',(@{$parents},$category));
13702: if ($allitems->{$item} eq '') {
13703: push(@{$trails},$trailstr);
13704: $allitems->{$item} = scalar(@{$trails})-1;
13705: }
13706: my $deeper = $depth+1;
13707: push(@{$parents},$category);
1.665 raeburn 13708: if (ref($subcats) eq 'HASH') {
13709: my $subcat = &escape($name).':'.$category.':'.$depth;
13710: for (my $j=@{$parents}; $j>=0; $j--) {
13711: my $higher;
13712: if ($j > 0) {
13713: $higher = &escape($parents->[$j]).':'.
13714: &escape($parents->[$j-1]).':'.$j;
13715: } else {
13716: $higher = &escape($parents->[$j]).'::'.$j;
13717: }
13718: push(@{$subcats->{$higher}},$subcat);
13719: }
13720: }
13721: &recurse_categories($cats,$deeper,$name,$trails,$allitems,$parents,
13722: $subcats);
1.655 raeburn 13723: pop(@{$parents});
13724: }
13725: } else {
13726: my $item = &escape($category).':'.&escape($parents->[-1]).':'.$shallower;
13727: my $trailstr = join(' -> ',(@{$parents},$category));
13728: if ($allitems->{$item} eq '') {
13729: push(@{$trails},$trailstr);
13730: $allitems->{$item} = scalar(@{$trails})-1;
13731: }
13732: }
13733: return;
13734: }
13735:
1.663 raeburn 13736: =pod
13737:
1.1075.2.56 raeburn 13738: =item * &assign_categories_table()
1.663 raeburn 13739:
13740: Create a datatable for display of hierarchical categories in a domain,
13741: with checkboxes to allow a course to be categorized.
13742:
13743: Inputs:
13744:
13745: cathash - reference to hash of categories defined for the domain (from
13746: configuration.db)
13747:
13748: currcat - scalar with an & separated list of categories assigned to a course.
13749:
1.919 raeburn 13750: type - scalar contains course type (Course or Community).
13751:
1.663 raeburn 13752: Returns: $output (markup to be displayed)
13753:
13754: =cut
13755:
13756: sub assign_categories_table {
1.919 raeburn 13757: my ($cathash,$currcat,$type) = @_;
1.663 raeburn 13758: my $output;
13759: if (ref($cathash) eq 'HASH') {
13760: my (@cats,@trails,%allitems,%idx,@jsarray,@path,$maxdepth);
13761: &extract_categories($cathash,\@cats,\@trails,\%allitems,\%idx,\@jsarray);
13762: $maxdepth = scalar(@cats);
13763: if (@cats > 0) {
13764: my $itemcount = 0;
13765: if (ref($cats[0]) eq 'ARRAY') {
13766: my @currcategories;
13767: if ($currcat ne '') {
13768: @currcategories = split('&',$currcat);
13769: }
1.919 raeburn 13770: my $table;
1.663 raeburn 13771: for (my $i=0; $i<@{$cats[0]}; $i++) {
13772: my $parent = $cats[0][$i];
1.919 raeburn 13773: next if ($parent eq 'instcode');
13774: if ($type eq 'Community') {
13775: next unless ($parent eq 'communities');
13776: } else {
13777: next if ($parent eq 'communities');
13778: }
1.663 raeburn 13779: my $css_class = $itemcount%2?' class="LC_odd_row"':'';
13780: my $item = &escape($parent).'::0';
13781: my $checked = '';
13782: if (@currcategories > 0) {
13783: if (grep(/^\Q$item\E$/,@currcategories)) {
1.772 bisitz 13784: $checked = ' checked="checked"';
1.663 raeburn 13785: }
13786: }
1.919 raeburn 13787: my $parent_title = $parent;
13788: if ($parent eq 'communities') {
13789: $parent_title = &mt('Communities');
13790: }
13791: $table .= '<tr '.$css_class.'><td><span class="LC_nobreak">'.
13792: '<input type="checkbox" name="usecategory" value="'.
13793: $item.'"'.$checked.' />'.$parent_title.'</span>'.
13794: '<input type="hidden" name="catname" value="'.$parent.'" /></td>';
1.663 raeburn 13795: my $depth = 1;
13796: push(@path,$parent);
1.919 raeburn 13797: $table .= &assign_category_rows($itemcount,\@cats,$depth,$parent,\@path,\@currcategories);
1.663 raeburn 13798: pop(@path);
1.919 raeburn 13799: $table .= '</tr><tr><td colspan="'.$maxdepth.'" class="LC_row_separator"></td></tr>';
1.663 raeburn 13800: $itemcount ++;
13801: }
1.919 raeburn 13802: if ($itemcount) {
13803: $output = &Apache::loncommon::start_data_table().
13804: $table.
13805: &Apache::loncommon::end_data_table();
13806: }
1.663 raeburn 13807: }
13808: }
13809: }
13810: return $output;
13811: }
13812:
13813: =pod
13814:
1.1075.2.56 raeburn 13815: =item * &assign_category_rows()
1.663 raeburn 13816:
13817: Create a datatable row for display of nested categories in a domain,
13818: with checkboxes to allow a course to be categorized,called recursively.
13819:
13820: Inputs:
13821:
13822: itemcount - track row number for alternating colors
13823:
13824: cats - reference to array of arrays/hashes which encapsulates hierarchy of
13825: categories and subcategories.
13826:
13827: depth - current depth in hierarchy of categories and sub-categories - 0 indexed.
13828:
13829: parent - parent of current category item
13830:
13831: path - Array containing all categories back up through the hierarchy from the
13832: current category to the top level.
13833:
13834: currcategories - reference to array of current categories assigned to the course
13835:
13836: Returns: $output (markup to be displayed).
13837:
13838: =cut
13839:
13840: sub assign_category_rows {
13841: my ($itemcount,$cats,$depth,$parent,$path,$currcategories) = @_;
13842: my ($text,$name,$item,$chgstr);
13843: if (ref($cats) eq 'ARRAY') {
13844: my $maxdepth = scalar(@{$cats});
13845: if (ref($cats->[$depth]) eq 'HASH') {
13846: if (ref($cats->[$depth]{$parent}) eq 'ARRAY') {
13847: my $numchildren = @{$cats->[$depth]{$parent}};
13848: my $css_class = $itemcount%2?' class="LC_odd_row"':'';
1.1075.2.45 raeburn 13849: $text .= '<td><table class="LC_data_table">';
1.663 raeburn 13850: for (my $j=0; $j<$numchildren; $j++) {
13851: $name = $cats->[$depth]{$parent}[$j];
13852: $item = &escape($name).':'.&escape($parent).':'.$depth;
13853: my $deeper = $depth+1;
13854: my $checked = '';
13855: if (ref($currcategories) eq 'ARRAY') {
13856: if (@{$currcategories} > 0) {
13857: if (grep(/^\Q$item\E$/,@{$currcategories})) {
1.772 bisitz 13858: $checked = ' checked="checked"';
1.663 raeburn 13859: }
13860: }
13861: }
1.664 raeburn 13862: $text .= '<tr><td><span class="LC_nobreak"><label>'.
13863: '<input type="checkbox" name="usecategory" value="'.
1.675 raeburn 13864: $item.'"'.$checked.' />'.$name.'</label></span>'.
13865: '<input type="hidden" name="catname" value="'.$name.'" />'.
13866: '</td><td>';
1.663 raeburn 13867: if (ref($path) eq 'ARRAY') {
13868: push(@{$path},$name);
13869: $text .= &assign_category_rows($itemcount,$cats,$deeper,$name,$path,$currcategories);
13870: pop(@{$path});
13871: }
13872: $text .= '</td></tr>';
13873: }
13874: $text .= '</table></td>';
13875: }
13876: }
13877: }
13878: return $text;
13879: }
13880:
1.1075.2.69 raeburn 13881: =pod
13882:
13883: =back
13884:
13885: =cut
13886:
1.655 raeburn 13887: ############################################################
13888: ############################################################
13889:
13890:
1.443 albertel 13891: sub commit_customrole {
1.664 raeburn 13892: my ($udom,$uname,$url,$three,$four,$five,$start,$end,$context) = @_;
1.630 raeburn 13893: my $output = &mt('Assigning custom role').' "'.$five.'" by '.$four.':'.$three.' in '.$url.
1.443 albertel 13894: ($start?', '.&mt('starting').' '.localtime($start):'').
13895: ($end?', ending '.localtime($end):'').': <b>'.
13896: &Apache::lonnet::assigncustomrole(
1.664 raeburn 13897: $udom,$uname,$url,$three,$four,$five,$end,$start,undef,undef,$context).
1.443 albertel 13898: '</b><br />';
13899: return $output;
13900: }
13901:
13902: sub commit_standardrole {
1.1075.2.31 raeburn 13903: my ($udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context,$credits) = @_;
1.541 raeburn 13904: my ($output,$logmsg,$linefeed);
13905: if ($context eq 'auto') {
13906: $linefeed = "\n";
13907: } else {
13908: $linefeed = "<br />\n";
13909: }
1.443 albertel 13910: if ($three eq 'st') {
1.541 raeburn 13911: my $result = &commit_studentrole(\$logmsg,$udom,$uname,$url,$three,$start,$end,
1.1075.2.31 raeburn 13912: $one,$two,$sec,$context,$credits);
1.541 raeburn 13913: if (($result =~ /^error/) || ($result eq 'not_in_class') ||
1.626 raeburn 13914: ($result eq 'unknown_course') || ($result eq 'refused')) {
13915: $output = $logmsg.' '.&mt('Error: ').$result."\n";
1.443 albertel 13916: } else {
1.541 raeburn 13917: $output = $logmsg.$linefeed.&mt('Assigning').' '.$three.' in '.$url.
1.443 albertel 13918: ($start?', '.&mt('starting').' '.localtime($start):'').
1.541 raeburn 13919: ($end?', '.&mt('ending').' '.localtime($end):'').': ';
13920: if ($context eq 'auto') {
13921: $output .= $result.$linefeed.&mt('Add to classlist').': ok';
13922: } else {
13923: $output .= '<b>'.$result.'</b>'.$linefeed.
13924: &mt('Add to classlist').': <b>ok</b>';
13925: }
13926: $output .= $linefeed;
1.443 albertel 13927: }
13928: } else {
13929: $output = &mt('Assigning').' '.$three.' in '.$url.
13930: ($start?', '.&mt('starting').' '.localtime($start):'').
1.541 raeburn 13931: ($end?', '.&mt('ending').' '.localtime($end):'').': ';
1.652 raeburn 13932: my $result = &Apache::lonnet::assignrole($udom,$uname,$url,$three,$end,$start,'','',$context);
1.541 raeburn 13933: if ($context eq 'auto') {
13934: $output .= $result.$linefeed;
13935: } else {
13936: $output .= '<b>'.$result.'</b>'.$linefeed;
13937: }
1.443 albertel 13938: }
13939: return $output;
13940: }
13941:
13942: sub commit_studentrole {
1.1075.2.31 raeburn 13943: my ($logmsg,$udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context,
13944: $credits) = @_;
1.626 raeburn 13945: my ($result,$linefeed,$oldsecurl,$newsecurl);
1.541 raeburn 13946: if ($context eq 'auto') {
13947: $linefeed = "\n";
13948: } else {
13949: $linefeed = '<br />'."\n";
13950: }
1.443 albertel 13951: if (defined($one) && defined($two)) {
13952: my $cid=$one.'_'.$two;
13953: my $oldsec=&Apache::lonnet::getsection($udom,$uname,$cid);
13954: my $secchange = 0;
13955: my $expire_role_result;
13956: my $modify_section_result;
1.628 raeburn 13957: if ($oldsec ne '-1') {
13958: if ($oldsec ne $sec) {
1.443 albertel 13959: $secchange = 1;
1.628 raeburn 13960: my $now = time;
1.443 albertel 13961: my $uurl='/'.$cid;
13962: $uurl=~s/\_/\//g;
13963: if ($oldsec) {
13964: $uurl.='/'.$oldsec;
13965: }
1.626 raeburn 13966: $oldsecurl = $uurl;
1.628 raeburn 13967: $expire_role_result =
1.652 raeburn 13968: &Apache::lonnet::assignrole($udom,$uname,$uurl,'st',$now,'','',$context);
1.628 raeburn 13969: if ($env{'request.course.sec'} ne '') {
13970: if ($expire_role_result eq 'refused') {
13971: my @roles = ('st');
13972: my @statuses = ('previous');
13973: my @roledoms = ($one);
13974: my $withsec = 1;
13975: my %roleshash =
13976: &Apache::lonnet::get_my_roles($uname,$udom,'userroles',
13977: \@statuses,\@roles,\@roledoms,$withsec);
13978: if (defined ($roleshash{$two.':'.$one.':st:'.$oldsec})) {
13979: my ($oldstart,$oldend) =
13980: split(':',$roleshash{$two.':'.$one.':st:'.$oldsec});
13981: if ($oldend > 0 && $oldend <= $now) {
13982: $expire_role_result = 'ok';
13983: }
13984: }
13985: }
13986: }
1.443 albertel 13987: $result = $expire_role_result;
13988: }
13989: }
13990: if (($expire_role_result eq 'ok') || ($secchange == 0)) {
1.1075.2.31 raeburn 13991: $modify_section_result =
13992: &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,
13993: undef,undef,undef,$sec,
13994: $end,$start,'','',$cid,
13995: '',$context,$credits);
1.443 albertel 13996: if ($modify_section_result =~ /^ok/) {
13997: if ($secchange == 1) {
1.628 raeburn 13998: if ($sec eq '') {
13999: $$logmsg .= &mt('Section for [_1] switched from (possibly expired) old section: [_2] to student role without a section.',$uname,$oldsec).$linefeed;
14000: } else {
14001: $$logmsg .= &mt('Section for [_1] switched from (possibly expired) old section: [_2] to new section: [_3].',$uname,$oldsec,$sec).$linefeed;
14002: }
1.443 albertel 14003: } elsif ($oldsec eq '-1') {
1.628 raeburn 14004: if ($sec eq '') {
14005: $$logmsg .= &mt('New student role without a section for [_1] in course [_2].',$uname,$cid).$linefeed;
14006: } else {
14007: $$logmsg .= &mt('New student role for [_1] in section [_2] in course [_3].',$uname,$sec,$cid).$linefeed;
14008: }
1.443 albertel 14009: } else {
1.628 raeburn 14010: if ($sec eq '') {
14011: $$logmsg .= &mt('Student [_1] assigned to course [_2] without a section.',$uname,$cid).$linefeed;
14012: } else {
14013: $$logmsg .= &mt('Student [_1] assigned to section [_2] in course [_3].',$uname,$sec,$cid).$linefeed;
14014: }
1.443 albertel 14015: }
14016: } else {
1.628 raeburn 14017: if ($secchange) {
14018: $$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;
14019: } else {
14020: $$logmsg .= &mt('Error when attempting to modify role for [_1] for section: "[_2]" in course [_3] -error:',$uname,$sec,$cid).' '.$modify_section_result.$linefeed;
14021: }
1.443 albertel 14022: }
14023: $result = $modify_section_result;
14024: } elsif ($secchange == 1) {
1.628 raeburn 14025: if ($oldsec eq '') {
1.1075.2.20 raeburn 14026: $$logmsg .= &mt('Error when attempting to expire existing role without a section for [_1] in course [_2] -error: ',$uname,$cid).' '.$expire_role_result.$linefeed;
1.628 raeburn 14027: } else {
14028: $$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;
14029: }
1.626 raeburn 14030: if ($expire_role_result eq 'refused') {
14031: my $newsecurl = '/'.$cid;
14032: $newsecurl =~ s/\_/\//g;
14033: if ($sec ne '') {
14034: $newsecurl.='/'.$sec;
14035: }
14036: if (&Apache::lonnet::allowed('cst',$newsecurl) && !(&Apache::lonnet::allowed('cst',$oldsecurl))) {
14037: if ($sec eq '') {
14038: $$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;
14039: } else {
14040: $$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;
14041: }
14042: }
14043: }
1.443 albertel 14044: }
14045: } else {
1.626 raeburn 14046: $$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 14047: $result = "error: incomplete course id\n";
14048: }
14049: return $result;
14050: }
14051:
1.1075.2.25 raeburn 14052: sub show_role_extent {
14053: my ($scope,$context,$role) = @_;
14054: $scope =~ s{^/}{};
14055: my @courseroles = &Apache::lonuserutils::roles_by_context('course',1);
14056: push(@courseroles,'co');
14057: my @authorroles = &Apache::lonuserutils::roles_by_context('author');
14058: if (($context eq 'course') || (grep(/^\Q$role\E/,@courseroles))) {
14059: $scope =~ s{/}{_};
14060: return '<span class="LC_cusr_emph">'.$env{'course.'.$scope.'.description'}.'</span>';
14061: } elsif (($context eq 'author') || (grep(/^\Q$role\E/,@authorroles))) {
14062: my ($audom,$auname) = split(/\//,$scope);
14063: return &mt('[_1] Author Space','<span class="LC_cusr_emph">'.
14064: &Apache::loncommon::plainname($auname,$audom).'</span>');
14065: } else {
14066: $scope =~ s{/$}{};
14067: return &mt('Domain: [_1]','<span class="LC_cusr_emph">'.
14068: &Apache::lonnet::domain($scope,'description').'</span>');
14069: }
14070: }
14071:
1.443 albertel 14072: ############################################################
14073: ############################################################
14074:
1.566 albertel 14075: sub check_clone {
1.578 raeburn 14076: my ($args,$linefeed) = @_;
1.566 albertel 14077: my $cloneid='/'.$args->{'clonedomain'}.'/'.$args->{'clonecourse'};
14078: my ($clonecrsudom,$clonecrsunum)= &LONCAPA::split_courseid($cloneid);
14079: my $clonehome=&Apache::lonnet::homeserver($clonecrsunum,$clonecrsudom);
14080: my $clonemsg;
14081: my $can_clone = 0;
1.944 raeburn 14082: my $lctype = lc($args->{'crstype'});
1.908 raeburn 14083: if ($lctype ne 'community') {
14084: $lctype = 'course';
14085: }
1.566 albertel 14086: if ($clonehome eq 'no_host') {
1.944 raeburn 14087: if ($args->{'crstype'} eq 'Community') {
1.908 raeburn 14088: $clonemsg = &mt('No new community created.').$linefeed.&mt('A new community could not be cloned from the specified original - [_1] - because it is a non-existent community.',$args->{'clonecourse'}.':'.$args->{'clonedomain'});
14089: } else {
14090: $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'});
14091: }
1.566 albertel 14092: } else {
14093: my %clonedesc = &Apache::lonnet::coursedescription($cloneid,{'one_time' => 1});
1.944 raeburn 14094: if ($args->{'crstype'} eq 'Community') {
1.908 raeburn 14095: if ($clonedesc{'type'} ne 'Community') {
14096: $clonemsg = &mt('No new community created.').$linefeed.&mt('A new community could not be cloned from the specified original - [_1] - because it is a course not a community.',$args->{'clonecourse'}.':'.$args->{'clonedomain'});
14097: return ($can_clone, $clonemsg, $cloneid, $clonehome);
14098: }
14099: }
1.882 raeburn 14100: if (($env{'request.role.domain'} eq $args->{'clonedomain'}) &&
14101: (&Apache::lonnet::allowed('ccc',$env{'request.role.domain'}))) {
1.566 albertel 14102: $can_clone = 1;
14103: } else {
14104: my %clonehash = &Apache::lonnet::get('environment',['cloners'],
14105: $args->{'clonedomain'},$args->{'clonecourse'});
14106: my @cloners = split(/,/,$clonehash{'cloners'});
1.578 raeburn 14107: if (grep(/^\*$/,@cloners)) {
14108: $can_clone = 1;
14109: } elsif (grep(/^\*\:\Q$args->{'ccdomain'}\E$/,@cloners)) {
14110: $can_clone = 1;
14111: } else {
1.908 raeburn 14112: my $ccrole = 'cc';
1.944 raeburn 14113: if ($args->{'crstype'} eq 'Community') {
1.908 raeburn 14114: $ccrole = 'co';
14115: }
1.578 raeburn 14116: my %roleshash =
14117: &Apache::lonnet::get_my_roles($args->{'ccuname'},
14118: $args->{'ccdomain'},
1.908 raeburn 14119: 'userroles',['active'],[$ccrole],
1.578 raeburn 14120: [$args->{'clonedomain'}]);
1.908 raeburn 14121: if (($roleshash{$args->{'clonecourse'}.':'.$args->{'clonedomain'}.':'.$ccrole}) || (grep(/^\Q$args->{'ccuname'}\E:\Q$args->{'ccdomain'}\E$/,@cloners))) {
1.942 raeburn 14122: $can_clone = 1;
14123: } elsif (&Apache::lonnet::is_course_owner($args->{'clonedomain'},$args->{'clonecourse'},$args->{'ccuname'},$args->{'ccdomain'})) {
14124: $can_clone = 1;
14125: } else {
1.944 raeburn 14126: if ($args->{'crstype'} eq 'Community') {
1.908 raeburn 14127: $clonemsg = &mt('No new community created.').$linefeed.&mt('The new community could not be cloned from the existing community because the new community owner ([_1]) does not have cloning rights in the existing community ([_2]).',$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'});
14128: } else {
14129: $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'});
14130: }
1.578 raeburn 14131: }
1.566 albertel 14132: }
1.578 raeburn 14133: }
1.566 albertel 14134: }
14135: return ($can_clone, $clonemsg, $cloneid, $clonehome);
14136: }
14137:
1.444 albertel 14138: sub construct_course {
1.1075.2.59 raeburn 14139: my ($args,$logmsg,$courseid,$crsudom,$crsunum,$udom,$uname,$context,$cnum,$category,$coderef) = @_;
1.444 albertel 14140: my $outcome;
1.541 raeburn 14141: my $linefeed = '<br />'."\n";
14142: if ($context eq 'auto') {
14143: $linefeed = "\n";
14144: }
1.566 albertel 14145:
14146: #
14147: # Are we cloning?
14148: #
14149: my ($can_clone, $clonemsg, $cloneid, $clonehome);
14150: if (($args->{'clonecourse'}) && ($args->{'clonedomain'})) {
1.578 raeburn 14151: ($can_clone, $clonemsg, $cloneid, $clonehome) = &check_clone($args,$linefeed);
1.566 albertel 14152: if ($context ne 'auto') {
1.578 raeburn 14153: if ($clonemsg ne '') {
14154: $clonemsg = '<span class="LC_error">'.$clonemsg.'</span>';
14155: }
1.566 albertel 14156: }
14157: $outcome .= $clonemsg.$linefeed;
14158:
14159: if (!$can_clone) {
14160: return (0,$outcome);
14161: }
14162: }
14163:
1.444 albertel 14164: #
14165: # Open course
14166: #
14167: my $crstype = lc($args->{'crstype'});
14168: my %cenv=();
14169: $$courseid=&Apache::lonnet::createcourse($args->{'course_domain'},
14170: $args->{'cdescr'},
14171: $args->{'curl'},
14172: $args->{'course_home'},
14173: $args->{'nonstandard'},
14174: $args->{'crscode'},
14175: $args->{'ccuname'}.':'.
14176: $args->{'ccdomain'},
1.882 raeburn 14177: $args->{'crstype'},
1.885 raeburn 14178: $cnum,$context,$category);
1.444 albertel 14179:
14180: # Note: The testing routines depend on this being output; see
14181: # Utils::Course. This needs to at least be output as a comment
14182: # if anyone ever decides to not show this, and Utils::Course::new
14183: # will need to be suitably modified.
1.541 raeburn 14184: $outcome .= &mt('New LON-CAPA [_1] ID: [_2]',$crstype,$$courseid).$linefeed;
1.943 raeburn 14185: if ($$courseid =~ /^error:/) {
14186: return (0,$outcome);
14187: }
14188:
1.444 albertel 14189: #
14190: # Check if created correctly
14191: #
1.479 albertel 14192: ($$crsudom,$$crsunum)= &LONCAPA::split_courseid($$courseid);
1.444 albertel 14193: my $crsuhome=&Apache::lonnet::homeserver($$crsunum,$$crsudom);
1.943 raeburn 14194: if ($crsuhome eq 'no_host') {
14195: $outcome .= &mt('Course creation failed, unrecognized course home server.').$linefeed;
14196: return (0,$outcome);
14197: }
1.541 raeburn 14198: $outcome .= &mt('Created on').': '.$crsuhome.$linefeed;
1.566 albertel 14199:
1.444 albertel 14200: #
1.566 albertel 14201: # Do the cloning
14202: #
14203: if ($can_clone && $cloneid) {
14204: $clonemsg = &mt('Cloning [_1] from [_2]',$crstype,$clonehome);
14205: if ($context ne 'auto') {
14206: $clonemsg = '<span class="LC_success">'.$clonemsg.'</span>';
14207: }
14208: $outcome .= $clonemsg.$linefeed;
14209: my %oldcenv=&Apache::lonnet::dump('environment',$$crsudom,$$crsunum);
1.444 albertel 14210: # Copy all files
1.637 www 14211: &Apache::lonclonecourse::copycoursefiles($cloneid,$$courseid,$args->{'datemode'},$args->{'dateshift'});
1.444 albertel 14212: # Restore URL
1.566 albertel 14213: $cenv{'url'}=$oldcenv{'url'};
1.444 albertel 14214: # Restore title
1.566 albertel 14215: $cenv{'description'}=$oldcenv{'description'};
1.955 raeburn 14216: # Restore creation date, creator and creation context.
14217: $cenv{'internal.created'}=$oldcenv{'internal.created'};
14218: $cenv{'internal.creator'}=$oldcenv{'internal.creator'};
14219: $cenv{'internal.creationcontext'}=$oldcenv{'internal.creationcontext'};
1.444 albertel 14220: # Mark as cloned
1.566 albertel 14221: $cenv{'clonedfrom'}=$cloneid;
1.638 www 14222: # Need to clone grading mode
14223: my %newenv=&Apache::lonnet::get('environment',['grading'],$$crsudom,$$crsunum);
14224: $cenv{'grading'}=$newenv{'grading'};
14225: # Do not clone these environment entries
14226: &Apache::lonnet::del('environment',
14227: ['default_enrollment_start_date',
14228: 'default_enrollment_end_date',
14229: 'question.email',
14230: 'policy.email',
14231: 'comment.email',
14232: 'pch.users.denied',
1.725 raeburn 14233: 'plc.users.denied',
14234: 'hidefromcat',
1.1075.2.36 raeburn 14235: 'checkforpriv',
1.1075.2.59 raeburn 14236: 'categories',
14237: 'internal.uniquecode'],
1.638 www 14238: $$crsudom,$$crsunum);
1.1075.2.63 raeburn 14239: if ($args->{'textbook'}) {
14240: $cenv{'internal.textbook'} = $args->{'textbook'};
14241: }
1.444 albertel 14242: }
1.566 albertel 14243:
1.444 albertel 14244: #
14245: # Set environment (will override cloned, if existing)
14246: #
14247: my @sections = ();
14248: my @xlists = ();
14249: if ($args->{'crstype'}) {
14250: $cenv{'type'}=$args->{'crstype'};
14251: }
14252: if ($args->{'crsid'}) {
14253: $cenv{'courseid'}=$args->{'crsid'};
14254: }
14255: if ($args->{'crscode'}) {
14256: $cenv{'internal.coursecode'}=$args->{'crscode'};
14257: }
14258: if ($args->{'crsquota'} ne '') {
14259: $cenv{'internal.coursequota'}=$args->{'crsquota'};
14260: } else {
14261: $cenv{'internal.coursequota'}=$args->{'crsquota'} = 20;
14262: }
14263: if ($args->{'ccuname'}) {
14264: $cenv{'internal.courseowner'} = $args->{'ccuname'}.
14265: ':'.$args->{'ccdomain'};
14266: } else {
14267: $cenv{'internal.courseowner'} = $args->{'curruser'};
14268: }
1.1075.2.31 raeburn 14269: if ($args->{'defaultcredits'}) {
14270: $cenv{'internal.defaultcredits'} = $args->{'defaultcredits'};
14271: }
1.444 albertel 14272: my @badclasses = (); # Used to accumulate sections/crosslistings that did not pass classlist access check for course owner.
14273: if ($args->{'crssections'}) {
14274: $cenv{'internal.sectionnums'} = '';
14275: if ($args->{'crssections'} =~ m/,/) {
14276: @sections = split/,/,$args->{'crssections'};
14277: } else {
14278: $sections[0] = $args->{'crssections'};
14279: }
14280: if (@sections > 0) {
14281: foreach my $item (@sections) {
14282: my ($sec,$gp) = split/:/,$item;
14283: my $class = $args->{'crscode'}.$sec;
14284: my $addcheck = &Apache::lonnet::auto_new_course($$crsunum,$$crsudom,$class,$cenv{'internal.courseowner'});
14285: $cenv{'internal.sectionnums'} .= $item.',';
14286: unless ($addcheck eq 'ok') {
14287: push @badclasses, $class;
14288: }
14289: }
14290: $cenv{'internal.sectionnums'} =~ s/,$//;
14291: }
14292: }
14293: # do not hide course coordinator from staff listing,
14294: # even if privileged
14295: $cenv{'nothideprivileged'}=$args->{'ccuname'}.':'.$args->{'ccdomain'};
1.1075.2.36 raeburn 14296: # add course coordinator's domain to domains to check for privileged users
14297: # if different to course domain
14298: if ($$crsudom ne $args->{'ccdomain'}) {
14299: $cenv{'checkforpriv'} = $args->{'ccdomain'};
14300: }
1.444 albertel 14301: # add crosslistings
14302: if ($args->{'crsxlist'}) {
14303: $cenv{'internal.crosslistings'}='';
14304: if ($args->{'crsxlist'} =~ m/,/) {
14305: @xlists = split/,/,$args->{'crsxlist'};
14306: } else {
14307: $xlists[0] = $args->{'crsxlist'};
14308: }
14309: if (@xlists > 0) {
14310: foreach my $item (@xlists) {
14311: my ($xl,$gp) = split/:/,$item;
14312: my $addcheck = &Apache::lonnet::auto_new_course($$crsunum,$$crsudom,$xl,$cenv{'internal.courseowner'});
14313: $cenv{'internal.crosslistings'} .= $item.',';
14314: unless ($addcheck eq 'ok') {
14315: push @badclasses, $xl;
14316: }
14317: }
14318: $cenv{'internal.crosslistings'} =~ s/,$//;
14319: }
14320: }
14321: if ($args->{'autoadds'}) {
14322: $cenv{'internal.autoadds'}=$args->{'autoadds'};
14323: }
14324: if ($args->{'autodrops'}) {
14325: $cenv{'internal.autodrops'}=$args->{'autodrops'};
14326: }
14327: # check for notification of enrollment changes
14328: my @notified = ();
14329: if ($args->{'notify_owner'}) {
14330: if ($args->{'ccuname'} ne '') {
14331: push(@notified,$args->{'ccuname'}.':'.$args->{'ccdomain'});
14332: }
14333: }
14334: if ($args->{'notify_dc'}) {
14335: if ($uname ne '') {
1.630 raeburn 14336: push(@notified,$uname.':'.$udom);
1.444 albertel 14337: }
14338: }
14339: if (@notified > 0) {
14340: my $notifylist;
14341: if (@notified > 1) {
14342: $notifylist = join(',',@notified);
14343: } else {
14344: $notifylist = $notified[0];
14345: }
14346: $cenv{'internal.notifylist'} = $notifylist;
14347: }
14348: if (@badclasses > 0) {
14349: my %lt=&Apache::lonlocal::texthash(
14350: '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',
14351: 'dnhr' => 'does not have rights to access enrollment in these classes',
14352: 'adby' => 'as determined by the policies of your institution on access to official classlists'
14353: );
1.541 raeburn 14354: my $badclass_msg = $cenv{'internal.courseowner'}.') - '.$lt{'dnhr'}.
14355: ' ('.$lt{'adby'}.')';
14356: if ($context eq 'auto') {
14357: $outcome .= $badclass_msg.$linefeed;
1.566 albertel 14358: $outcome .= '<div class="LC_warning">'.$badclass_msg.$linefeed.'<ul>'."\n";
1.541 raeburn 14359: foreach my $item (@badclasses) {
14360: if ($context eq 'auto') {
14361: $outcome .= " - $item\n";
14362: } else {
14363: $outcome .= "<li>$item</li>\n";
14364: }
14365: }
14366: if ($context eq 'auto') {
14367: $outcome .= $linefeed;
14368: } else {
1.566 albertel 14369: $outcome .= "</ul><br /><br /></div>\n";
1.541 raeburn 14370: }
14371: }
1.444 albertel 14372: }
14373: if ($args->{'no_end_date'}) {
14374: $args->{'endaccess'} = 0;
14375: }
14376: $cenv{'internal.autostart'}=$args->{'enrollstart'};
14377: $cenv{'internal.autoend'}=$args->{'enrollend'};
14378: $cenv{'default_enrollment_start_date'}=$args->{'startaccess'};
14379: $cenv{'default_enrollment_end_date'}=$args->{'endaccess'};
14380: if ($args->{'showphotos'}) {
14381: $cenv{'internal.showphotos'}=$args->{'showphotos'};
14382: }
14383: $cenv{'internal.authtype'} = $args->{'authtype'};
14384: $cenv{'internal.autharg'} = $args->{'autharg'};
14385: if ( ($cenv{'internal.authtype'} =~ /^krb/) && ($cenv{'internal.autoadds'} == 1)) {
14386: if (! defined($cenv{'internal.autharg'}) || $cenv{'internal.autharg'} eq '') {
1.541 raeburn 14387: 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');
14388: if ($context eq 'auto') {
14389: $outcome .= $krb_msg;
14390: } else {
1.566 albertel 14391: $outcome .= '<span class="LC_error">'.$krb_msg.'</span>';
1.541 raeburn 14392: }
14393: $outcome .= $linefeed;
1.444 albertel 14394: }
14395: }
14396: if (($args->{'ccdomain'}) && ($args->{'ccuname'})) {
14397: if ($args->{'setpolicy'}) {
14398: $cenv{'policy.email'}=$args->{'ccuname'}.':'.$args->{'ccdomain'};
14399: }
14400: if ($args->{'setcontent'}) {
14401: $cenv{'question.email'}=$args->{'ccuname'}.':'.$args->{'ccdomain'};
14402: }
14403: }
14404: if ($args->{'reshome'}) {
14405: $cenv{'reshome'}=$args->{'reshome'}.'/';
14406: $cenv{'reshome'}=~s/\/+$/\//;
14407: }
14408: #
14409: # course has keyed access
14410: #
14411: if ($args->{'setkeys'}) {
14412: $cenv{'keyaccess'}='yes';
14413: }
14414: # if specified, key authority is not course, but user
14415: # only active if keyaccess is yes
14416: if ($args->{'keyauth'}) {
1.487 albertel 14417: my ($user,$domain) = split(':',$args->{'keyauth'});
14418: $user = &LONCAPA::clean_username($user);
14419: $domain = &LONCAPA::clean_username($domain);
1.488 foxr 14420: if ($user ne '' && $domain ne '') {
1.487 albertel 14421: $cenv{'keyauth'}=$user.':'.$domain;
1.444 albertel 14422: }
14423: }
14424:
1.1075.2.59 raeburn 14425: #
14426: # generate and store uniquecode (available to course requester), if course should have one.
14427: #
14428: if ($args->{'uniquecode'}) {
14429: my ($code,$error) = &make_unique_code($$crsudom,$$crsunum);
14430: if ($code) {
14431: $cenv{'internal.uniquecode'} = $code;
14432: my %crsinfo =
14433: &Apache::lonnet::courseiddump($$crsudom,'.',1,'.','.',$$crsunum,undef,undef,'.');
14434: if (ref($crsinfo{$$crsudom.'_'.$$crsunum}) eq 'HASH') {
14435: $crsinfo{$$crsudom.'_'.$$crsunum}{'uniquecode'} = $code;
14436: my $putres = &Apache::lonnet::courseidput($$crsudom,\%crsinfo,$crsuhome,'notime');
14437: }
14438: if (ref($coderef)) {
14439: $$coderef = $code;
14440: }
14441: }
14442: }
14443:
1.444 albertel 14444: if ($args->{'disresdis'}) {
14445: $cenv{'pch.roles.denied'}='st';
14446: }
14447: if ($args->{'disablechat'}) {
14448: $cenv{'plc.roles.denied'}='st';
14449: }
14450:
14451: # Record we've not yet viewed the Course Initialization Helper for this
14452: # course
14453: $cenv{'course.helper.not.run'} = 1;
14454: #
14455: # Use new Randomseed
14456: #
14457: $cenv{'rndseed'}=&Apache::lonnet::latest_rnd_algorithm_id();;
14458: $cenv{'receiptalg'}=&Apache::lonnet::latest_receipt_algorithm_id();;
14459: #
14460: # The encryption code and receipt prefix for this course
14461: #
14462: $cenv{'internal.encseed'}=$Apache::lonnet::perlvar{'lonReceipt'}.$$.time.int(rand(9999));
14463: $cenv{'internal.encpref'}=100+int(9*rand(99));
14464: #
14465: # By default, use standard grading
14466: if (!defined($cenv{'grading'})) { $cenv{'grading'} = 'standard'; }
14467:
1.541 raeburn 14468: $outcome .= $linefeed.&mt('Setting environment').': '.
14469: &Apache::lonnet::put('environment',\%cenv,$$crsudom,$$crsunum).$linefeed;
1.444 albertel 14470: #
14471: # Open all assignments
14472: #
14473: if ($args->{'openall'}) {
14474: my $storeunder=$$crsudom.'_'.$$crsunum.'.0.opendate';
14475: my %storecontent = ($storeunder => time,
14476: $storeunder.'.type' => 'date_start');
14477:
14478: $outcome .= &mt('Opening all assignments').': '.&Apache::lonnet::cput
1.541 raeburn 14479: ('resourcedata',\%storecontent,$$crsudom,$$crsunum).$linefeed;
1.444 albertel 14480: }
14481: #
14482: # Set first page
14483: #
14484: unless (($args->{'nonstandard'}) || ($args->{'firstres'} eq 'blank')
14485: || ($cloneid)) {
1.445 albertel 14486: use LONCAPA::map;
1.444 albertel 14487: $outcome .= &mt('Setting first resource').': ';
1.445 albertel 14488:
14489: my $map = '/uploaded/'.$$crsudom.'/'.$$crsunum.'/default.sequence';
14490: my ($errtext,$fatal)=&LONCAPA::map::mapread($map);
14491:
1.444 albertel 14492: $outcome .= ($fatal?$errtext:'read ok').' - ';
14493: my $title; my $url;
14494: if ($args->{'firstres'} eq 'syl') {
1.690 bisitz 14495: $title=&mt('Syllabus');
1.444 albertel 14496: $url='/public/'.$$crsudom.'/'.$$crsunum.'/syllabus';
14497: } else {
1.963 raeburn 14498: $title=&mt('Table of Contents');
1.444 albertel 14499: $url='/adm/navmaps';
14500: }
1.445 albertel 14501:
14502: $LONCAPA::map::resources[1]=$title.':'.$url.':false:start:res';
14503: (my $outtext,$errtext) = &LONCAPA::map::storemap($map,1);
14504:
14505: if ($errtext) { $fatal=2; }
1.541 raeburn 14506: $outcome .= ($fatal?$errtext:'write ok').$linefeed;
1.444 albertel 14507: }
1.566 albertel 14508:
14509: return (1,$outcome);
1.444 albertel 14510: }
14511:
1.1075.2.59 raeburn 14512: sub make_unique_code {
14513: my ($cdom,$cnum) = @_;
14514: # get lock on uniquecodes db
14515: my $lockhash = {
14516: $cnum."\0".'uniquecodes' => $env{'user.name'}.
14517: ':'.$env{'user.domain'},
14518: };
14519: my $tries = 0;
14520: my $gotlock = &Apache::lonnet::newput_dom('uniquecodes',$lockhash,$cdom);
14521: my ($code,$error);
14522:
14523: while (($gotlock ne 'ok') && ($tries<3)) {
14524: $tries ++;
14525: sleep 1;
14526: $gotlock = &Apache::lonnet::newput_dom('uniquecodes',$lockhash,$cdom);
14527: }
14528: if ($gotlock eq 'ok') {
14529: my %currcodes = &Apache::lonnet::dump_dom('uniquecodes',$cdom);
14530: my $gotcode;
14531: my $attempts = 0;
14532: while ((!$gotcode) && ($attempts < 100)) {
14533: $code = &generate_code();
14534: if (!exists($currcodes{$code})) {
14535: $gotcode = 1;
14536: unless (&Apache::lonnet::newput_dom('uniquecodes',{ $code => $cnum },$cdom) eq 'ok') {
14537: $error = 'nostore';
14538: }
14539: }
14540: $attempts ++;
14541: }
14542: my @del_lock = ($cnum."\0".'uniquecodes');
14543: my $dellockoutcome = &Apache::lonnet::del_dom('uniquecodes',\@del_lock,$cdom);
14544: } else {
14545: $error = 'nolock';
14546: }
14547: return ($code,$error);
14548: }
14549:
14550: sub generate_code {
14551: my $code;
14552: my @letts = qw(B C D G H J K M N P Q R S T V W X Z);
14553: for (my $i=0; $i<6; $i++) {
14554: my $lettnum = int (rand 2);
14555: my $item = '';
14556: if ($lettnum) {
14557: $item = $letts[int( rand(18) )];
14558: } else {
14559: $item = 1+int( rand(8) );
14560: }
14561: $code .= $item;
14562: }
14563: return $code;
14564: }
14565:
1.444 albertel 14566: ############################################################
14567: ############################################################
14568:
1.953 droeschl 14569: #SD
14570: # only Community and Course, or anything else?
1.378 raeburn 14571: sub course_type {
14572: my ($cid) = @_;
14573: if (!defined($cid)) {
14574: $cid = $env{'request.course.id'};
14575: }
1.404 albertel 14576: if (defined($env{'course.'.$cid.'.type'})) {
14577: return $env{'course.'.$cid.'.type'};
1.378 raeburn 14578: } else {
14579: return 'Course';
1.377 raeburn 14580: }
14581: }
1.156 albertel 14582:
1.406 raeburn 14583: sub group_term {
14584: my $crstype = &course_type();
14585: my %names = (
14586: 'Course' => 'group',
1.865 raeburn 14587: 'Community' => 'group',
1.406 raeburn 14588: );
14589: return $names{$crstype};
14590: }
14591:
1.902 raeburn 14592: sub course_types {
1.1075.2.59 raeburn 14593: my @types = ('official','unofficial','community','textbook');
1.902 raeburn 14594: my %typename = (
14595: official => 'Official course',
14596: unofficial => 'Unofficial course',
14597: community => 'Community',
1.1075.2.59 raeburn 14598: textbook => 'Textbook course',
1.902 raeburn 14599: );
14600: return (\@types,\%typename);
14601: }
14602:
1.156 albertel 14603: sub icon {
14604: my ($file)=@_;
1.505 albertel 14605: my $curfext = lc((split(/\./,$file))[-1]);
1.168 albertel 14606: my $iconname=$Apache::lonnet::perlvar{'lonIconsURL'}.'/unknown.gif';
1.156 albertel 14607: my $embstyle = &Apache::loncommon::fileembstyle($curfext);
1.168 albertel 14608: if (!(!defined($embstyle) || $embstyle eq 'unk' || $embstyle eq 'hdn')) {
14609: if (-e $Apache::lonnet::perlvar{'lonDocRoot'}.'/'.
14610: $Apache::lonnet::perlvar{'lonIconsURL'}.'/'.
14611: $curfext.".gif") {
14612: $iconname=$Apache::lonnet::perlvar{'lonIconsURL'}.'/'.
14613: $curfext.".gif";
14614: }
14615: }
1.249 albertel 14616: return &lonhttpdurl($iconname);
1.154 albertel 14617: }
1.84 albertel 14618:
1.575 albertel 14619: sub lonhttpdurl {
1.692 www 14620: #
14621: # Had been used for "small fry" static images on separate port 8080.
14622: # Modify here if lightweight http functionality desired again.
14623: # Currently eliminated due to increasing firewall issues.
14624: #
1.575 albertel 14625: my ($url)=@_;
1.692 www 14626: return $url;
1.215 albertel 14627: }
14628:
1.213 albertel 14629: sub connection_aborted {
14630: my ($r)=@_;
14631: $r->print(" ");$r->rflush();
14632: my $c = $r->connection;
14633: return $c->aborted();
14634: }
14635:
1.221 foxr 14636: # Escapes strings that may have embedded 's that will be put into
1.222 foxr 14637: # strings as 'strings'.
14638: sub escape_single {
1.221 foxr 14639: my ($input) = @_;
1.223 albertel 14640: $input =~ s/\\/\\\\/g; # Escape the \'s..(must be first)>
1.221 foxr 14641: $input =~ s/\'/\\\'/g; # Esacpe the 's....
14642: return $input;
14643: }
1.223 albertel 14644:
1.222 foxr 14645: # Same as escape_single, but escape's "'s This
14646: # can be used for "strings"
14647: sub escape_double {
14648: my ($input) = @_;
14649: $input =~ s/\\/\\\\/g; # Escape the /'s..(must be first)>
14650: $input =~ s/\"/\\\"/g; # Esacpe the "s....
14651: return $input;
14652: }
1.223 albertel 14653:
1.222 foxr 14654: # Escapes the last element of a full URL.
14655: sub escape_url {
14656: my ($url) = @_;
1.238 raeburn 14657: my @urlslices = split(/\//, $url,-1);
1.369 www 14658: my $lastitem = &escape(pop(@urlslices));
1.1075.2.83 raeburn 14659: return &HTML::Entities::encode(join('/',@urlslices),"'").'/'.$lastitem;
1.222 foxr 14660: }
1.462 albertel 14661:
1.820 raeburn 14662: sub compare_arrays {
14663: my ($arrayref1,$arrayref2) = @_;
14664: my (@difference,%count);
14665: @difference = ();
14666: %count = ();
14667: if ((ref($arrayref1) eq 'ARRAY') && (ref($arrayref2) eq 'ARRAY')) {
14668: foreach my $element (@{$arrayref1}, @{$arrayref2}) { $count{$element}++; }
14669: foreach my $element (keys(%count)) {
14670: if ($count{$element} == 1) {
14671: push(@difference,$element);
14672: }
14673: }
14674: }
14675: return @difference;
14676: }
14677:
1.817 bisitz 14678: # -------------------------------------------------------- Initialize user login
1.462 albertel 14679: sub init_user_environment {
1.463 albertel 14680: my ($r, $username, $domain, $authhost, $form, $args) = @_;
1.462 albertel 14681: my $lonids=$Apache::lonnet::perlvar{'lonIDsDir'};
14682:
14683: my $public=($username eq 'public' && $domain eq 'public');
14684:
14685: # See if old ID present, if so, remove
14686:
1.1062 raeburn 14687: my ($filename,$cookie,$userroles,$firstaccenv,$timerintenv);
1.462 albertel 14688: my $now=time;
14689:
14690: if ($public) {
14691: my $max_public=100;
14692: my $oldest;
14693: my $oldest_time=0;
14694: for(my $next=1;$next<=$max_public;$next++) {
14695: if (-e $lonids."/publicuser_$next.id") {
14696: my $mtime=(stat($lonids."/publicuser_$next.id"))[9];
14697: if ($mtime<$oldest_time || !$oldest_time) {
14698: $oldest_time=$mtime;
14699: $oldest=$next;
14700: }
14701: } else {
14702: $cookie="publicuser_$next";
14703: last;
14704: }
14705: }
14706: if (!$cookie) { $cookie="publicuser_$oldest"; }
14707: } else {
1.463 albertel 14708: # if this isn't a robot, kill any existing non-robot sessions
14709: if (!$args->{'robot'}) {
14710: opendir(DIR,$lonids);
14711: while ($filename=readdir(DIR)) {
14712: if ($filename=~/^$username\_\d+\_$domain\_$authhost\.id$/) {
14713: unlink($lonids.'/'.$filename);
14714: }
1.462 albertel 14715: }
1.463 albertel 14716: closedir(DIR);
1.1075.2.84 raeburn 14717: # If there is a undeleted lockfile for the user's paste buffer remove it.
14718: my $namespace = 'nohist_courseeditor';
14719: my $lockingkey = 'paste'."\0".'locked_num';
14720: my %lockhash = &Apache::lonnet::get($namespace,[$lockingkey],
14721: $domain,$username);
14722: if (exists($lockhash{$lockingkey})) {
14723: my $delresult = &Apache::lonnet::del($namespace,[$lockingkey],$domain,$username);
14724: unless ($delresult eq 'ok') {
14725: &Apache::lonnet::logthis("Failed to delete paste buffer locking key in $namespace for ".$username.":".$domain." Result was: $delresult");
14726: }
14727: }
1.462 albertel 14728: }
14729: # Give them a new cookie
1.463 albertel 14730: my $id = ($args->{'robot'} ? 'robot'.$args->{'robot'}
1.684 www 14731: : $now.$$.int(rand(10000)));
1.463 albertel 14732: $cookie="$username\_$id\_$domain\_$authhost";
1.462 albertel 14733:
14734: # Initialize roles
14735:
1.1062 raeburn 14736: ($userroles,$firstaccenv,$timerintenv) =
14737: &Apache::lonnet::rolesinit($domain,$username,$authhost);
1.462 albertel 14738: }
14739: # ------------------------------------ Check browser type and MathML capability
14740:
1.1075.2.77 raeburn 14741: my ($httpbrowser,$clientbrowser,$clientversion,$clientmathml,$clientunicode,
14742: $clientos,$clientmobile,$clientinfo,$clientosversion) = &decode_user_agent($r);
1.462 albertel 14743:
14744: # ------------------------------------------------------------- Get environment
14745:
14746: my %userenv = &Apache::lonnet::dump('environment',$domain,$username);
14747: my ($tmp) = keys(%userenv);
14748: if ($tmp !~ /^(con_lost|error|no_such_host)/i) {
14749: } else {
14750: undef(%userenv);
14751: }
14752: if (($userenv{'interface'}) && (!$form->{'interface'})) {
14753: $form->{'interface'}=$userenv{'interface'};
14754: }
14755: if ($userenv{'texengine'} eq 'ttm') { $clientmathml=1; }
14756:
14757: # --------------- Do not trust query string to be put directly into environment
1.817 bisitz 14758: foreach my $option ('interface','localpath','localres') {
14759: $form->{$option}=~s/[\n\r\=]//gs;
1.462 albertel 14760: }
14761: # --------------------------------------------------------- Write first profile
14762:
14763: {
14764: my %initial_env =
14765: ("user.name" => $username,
14766: "user.domain" => $domain,
14767: "user.home" => $authhost,
14768: "browser.type" => $clientbrowser,
14769: "browser.version" => $clientversion,
14770: "browser.mathml" => $clientmathml,
14771: "browser.unicode" => $clientunicode,
14772: "browser.os" => $clientos,
1.1075.2.42 raeburn 14773: "browser.mobile" => $clientmobile,
14774: "browser.info" => $clientinfo,
1.1075.2.77 raeburn 14775: "browser.osversion" => $clientosversion,
1.462 albertel 14776: "server.domain" => $Apache::lonnet::perlvar{'lonDefDomain'},
14777: "request.course.fn" => '',
14778: "request.course.uri" => '',
14779: "request.course.sec" => '',
14780: "request.role" => 'cm',
14781: "request.role.adv" => $env{'user.adv'},
14782: "request.host" => $ENV{'REMOTE_ADDR'},);
14783:
14784: if ($form->{'localpath'}) {
14785: $initial_env{"browser.localpath"} = $form->{'localpath'};
14786: $initial_env{"browser.localres"} = $form->{'localres'};
14787: }
14788:
14789: if ($form->{'interface'}) {
14790: $form->{'interface'}=~s/\W//gs;
14791: $initial_env{"browser.interface"} = $form->{'interface'};
14792: $env{'browser.interface'}=$form->{'interface'};
14793: }
14794:
1.1075.2.54 raeburn 14795: if ($form->{'iptoken'}) {
14796: my $lonhost = $r->dir_config('lonHostID');
14797: $initial_env{"user.noloadbalance"} = $lonhost;
14798: $env{'user.noloadbalance'} = $lonhost;
14799: }
14800:
1.981 raeburn 14801: my %is_adv = ( is_adv => $env{'user.adv'} );
1.1016 raeburn 14802: my %domdef;
14803: unless ($domain eq 'public') {
14804: %domdef = &Apache::lonnet::get_domain_defaults($domain);
14805: }
1.980 raeburn 14806:
1.1075.2.7 raeburn 14807: foreach my $tool ('aboutme','blog','webdav','portfolio') {
1.724 raeburn 14808: $userenv{'availabletools.'.$tool} =
1.980 raeburn 14809: &Apache::lonnet::usertools_access($username,$domain,$tool,'reload',
14810: undef,\%userenv,\%domdef,\%is_adv);
1.724 raeburn 14811: }
14812:
1.1075.2.59 raeburn 14813: foreach my $crstype ('official','unofficial','community','textbook') {
1.765 raeburn 14814: $userenv{'canrequest.'.$crstype} =
14815: &Apache::lonnet::usertools_access($username,$domain,$crstype,
1.980 raeburn 14816: 'reload','requestcourses',
14817: \%userenv,\%domdef,\%is_adv);
1.765 raeburn 14818: }
14819:
1.1075.2.14 raeburn 14820: $userenv{'canrequest.author'} =
14821: &Apache::lonnet::usertools_access($username,$domain,'requestauthor',
14822: 'reload','requestauthor',
14823: \%userenv,\%domdef,\%is_adv);
14824: my %reqauthor = &Apache::lonnet::get('requestauthor',['author_status','author'],
14825: $domain,$username);
14826: my $reqstatus = $reqauthor{'author_status'};
14827: if ($reqstatus eq 'approval' || $reqstatus eq 'approved') {
14828: if (ref($reqauthor{'author'}) eq 'HASH') {
14829: $userenv{'requestauthorqueued'} = $reqstatus.':'.
14830: $reqauthor{'author'}{'timestamp'};
14831: }
14832: }
14833:
1.462 albertel 14834: $env{'user.environment'} = "$lonids/$cookie.id";
1.1062 raeburn 14835:
1.462 albertel 14836: if (tie(my %disk_env,'GDBM_File',"$lonids/$cookie.id",
14837: &GDBM_WRCREAT(),0640)) {
14838: &_add_to_env(\%disk_env,\%initial_env);
14839: &_add_to_env(\%disk_env,\%userenv,'environment.');
14840: &_add_to_env(\%disk_env,$userroles);
1.1062 raeburn 14841: if (ref($firstaccenv) eq 'HASH') {
14842: &_add_to_env(\%disk_env,$firstaccenv);
14843: }
14844: if (ref($timerintenv) eq 'HASH') {
14845: &_add_to_env(\%disk_env,$timerintenv);
14846: }
1.463 albertel 14847: if (ref($args->{'extra_env'})) {
14848: &_add_to_env(\%disk_env,$args->{'extra_env'});
14849: }
1.462 albertel 14850: untie(%disk_env);
14851: } else {
1.705 tempelho 14852: &Apache::lonnet::logthis("<span style=\"color:blue;\">WARNING: ".
14853: 'Could not create environment storage in lonauth: '.$!.'</span>');
1.462 albertel 14854: return 'error: '.$!;
14855: }
14856: }
14857: $env{'request.role'}='cm';
14858: $env{'request.role.adv'}=$env{'user.adv'};
14859: $env{'browser.type'}=$clientbrowser;
14860:
14861: return $cookie;
14862:
14863: }
14864:
14865: sub _add_to_env {
14866: my ($idf,$env_data,$prefix) = @_;
1.676 raeburn 14867: if (ref($env_data) eq 'HASH') {
14868: while (my ($key,$value) = each(%$env_data)) {
14869: $idf->{$prefix.$key} = $value;
14870: $env{$prefix.$key} = $value;
14871: }
1.462 albertel 14872: }
14873: }
14874:
1.685 tempelho 14875: # --- Get the symbolic name of a problem and the url
14876: sub get_symb {
14877: my ($request,$silent) = @_;
1.726 raeburn 14878: (my $url=$env{'form.url'}) =~ s-^https?\://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;
1.685 tempelho 14879: my $symb=($env{'form.symb'} ne '' ? $env{'form.symb'} : (&Apache::lonnet::symbread($url)));
14880: if ($symb eq '') {
14881: if (!$silent) {
1.1071 raeburn 14882: if (ref($request)) {
14883: $request->print("Unable to handle ambiguous references:$url:.");
14884: }
1.685 tempelho 14885: return ();
14886: }
14887: }
14888: &Apache::lonenc::check_decrypt(\$symb);
14889: return ($symb);
14890: }
14891:
14892: # --------------------------------------------------------------Get annotation
14893:
14894: sub get_annotation {
14895: my ($symb,$enc) = @_;
14896:
14897: my $key = $symb;
14898: if (!$enc) {
14899: $key =
14900: &Apache::lonnet::clutter((&Apache::lonnet::decode_symb($symb))[2]);
14901: }
14902: my %annotation=&Apache::lonnet::get('nohist_annotations',[$key]);
14903: return $annotation{$key};
14904: }
14905:
14906: sub clean_symb {
1.731 raeburn 14907: my ($symb,$delete_enc) = @_;
1.685 tempelho 14908:
14909: &Apache::lonenc::check_decrypt(\$symb);
14910: my $enc = $env{'request.enc'};
1.731 raeburn 14911: if ($delete_enc) {
1.730 raeburn 14912: delete($env{'request.enc'});
14913: }
1.685 tempelho 14914:
14915: return ($symb,$enc);
14916: }
1.462 albertel 14917:
1.1075.2.69 raeburn 14918: ############################################################
14919: ############################################################
14920:
14921: =pod
14922:
14923: =head1 Routines for building display used to search for courses
14924:
14925:
14926: =over 4
14927:
14928: =item * &build_filters()
14929:
14930: Create markup for a table used to set filters to use when selecting
14931: courses in a domain. Used by lonpickcourse.pm, lonmodifycourse.pm
14932: and quotacheck.pl
14933:
14934:
14935: Inputs:
14936:
14937: filterlist - anonymous array of fields to include as potential filters
14938:
14939: crstype - course type
14940:
14941: roleelement - fifth arg in selectcourse_link() populates fifth arg in javascript: opencrsbrowser() function, used
14942: to pop-open a course selector (will contain "extra element").
14943:
14944: multelement - if multiple course selections will be allowed, this will be a hidden form element: name: multiple; value: 1
14945:
14946: filter - anonymous hash of criteria and their values
14947:
14948: action - form action
14949:
14950: numfiltersref - ref to scalar (count of number of elements in institutional codes -- e.g., 4 for year, semester, department, and number)
14951:
14952: caller - caller context (e.g., set to 'modifycourse' when routine is called from lonmodifycourse.pm)
14953:
14954: cloneruname - username of owner of new course who wants to clone
14955:
14956: clonerudom - domain of owner of new course who wants to clone
14957:
14958: typeelem - text to use for left column in row containing course type (i.e., Course, Community or Course/Community)
14959:
14960: codetitlesref - reference to array of titles of components in institutional codes (official courses)
14961:
14962: codedom - domain
14963:
14964: formname - value of form element named "form".
14965:
14966: fixeddom - domain, if fixed.
14967:
14968: prevphase - value to assign to form element named "phase" when going back to the previous screen
14969:
14970: cnameelement - name of form element in form on opener page which will receive title of selected course
14971:
14972: cnumelement - name of form element in form on opener page which will receive courseID of selected course
14973:
14974: cdomelement - name of form element in form on opener page which will receive domain of selected course
14975:
14976: setroles - includes access constraint identifier when setting a roles-based condition for acces to a portfolio file
14977:
14978: clonetext - hidden form elements containing list of courses cloneable by intended course owner when DC creates a course
14979:
14980: clonewarning - warning message about missing information for intended course owner when DC creates a course
14981:
14982:
14983: Returns: $output - HTML for display of search criteria, and hidden form elements.
14984:
14985:
14986: Side Effects: None
14987:
14988: =cut
14989:
14990: # ---------------------------------------------- search for courses based on last activity etc.
14991:
14992: sub build_filters {
14993: my ($filterlist,$crstype,$roleelement,$multelement,$filter,$action,
14994: $numtitlesref,$caller,$cloneruname,$clonerudom,$typeelement,
14995: $codetitlesref,$codedom,$formname,$fixeddom,$prevphase,
14996: $cnameelement,$cnumelement,$cdomelement,$setroles,
14997: $clonetext,$clonewarning) = @_;
14998: my ($list,$jscript);
14999: my $onchange = 'javascript:updateFilters(this)';
15000: my ($domainselectform,$sincefilterform,$createdfilterform,
15001: $ownerdomselectform,$persondomselectform,$instcodeform,
15002: $typeselectform,$instcodetitle);
15003: if ($formname eq '') {
15004: $formname = $caller;
15005: }
15006: foreach my $item (@{$filterlist}) {
15007: unless (($item eq 'descriptfilter') || ($item eq 'instcodefilter') ||
15008: ($item eq 'sincefilter') || ($item eq 'createdfilter')) {
15009: if ($item eq 'domainfilter') {
15010: $filter->{$item} = &LONCAPA::clean_domain($filter->{$item});
15011: } elsif ($item eq 'coursefilter') {
15012: $filter->{$item} = &LONCAPA::clean_courseid($filter->{$item});
15013: } elsif ($item eq 'ownerfilter') {
15014: $filter->{$item} = &LONCAPA::clean_username($filter->{$item});
15015: } elsif ($item eq 'ownerdomfilter') {
15016: $filter->{'ownerdomfilter'} =
15017: &LONCAPA::clean_domain($filter->{$item});
15018: $ownerdomselectform = &select_dom_form($filter->{'ownerdomfilter'},
15019: 'ownerdomfilter',1);
15020: } elsif ($item eq 'personfilter') {
15021: $filter->{$item} = &LONCAPA::clean_username($filter->{$item});
15022: } elsif ($item eq 'persondomfilter') {
15023: $persondomselectform = &select_dom_form($filter->{'persondomfilter'},
15024: 'persondomfilter',1);
15025: } else {
15026: $filter->{$item} =~ s/\W//g;
15027: }
15028: if (!$filter->{$item}) {
15029: $filter->{$item} = '';
15030: }
15031: }
15032: if ($item eq 'domainfilter') {
15033: my $allow_blank = 1;
15034: if ($formname eq 'portform') {
15035: $allow_blank=0;
15036: } elsif ($formname eq 'studentform') {
15037: $allow_blank=0;
15038: }
15039: if ($fixeddom) {
15040: $domainselectform = '<input type="hidden" name="domainfilter"'.
15041: ' value="'.$codedom.'" />'.
15042: &Apache::lonnet::domain($codedom,'description');
15043: } else {
15044: $domainselectform = &select_dom_form($filter->{$item},
15045: 'domainfilter',
15046: $allow_blank,'',$onchange);
15047: }
15048: } else {
15049: $list->{$item} = &HTML::Entities::encode($filter->{$item},'<>&"');
15050: }
15051: }
15052:
15053: # last course activity filter and selection
15054: $sincefilterform = &timebased_select_form('sincefilter',$filter);
15055:
15056: # course created filter and selection
15057: if (exists($filter->{'createdfilter'})) {
15058: $createdfilterform = &timebased_select_form('createdfilter',$filter);
15059: }
15060:
15061: my %lt = &Apache::lonlocal::texthash(
15062: 'cac' => "$crstype Activity",
15063: 'ccr' => "$crstype Created",
15064: 'cde' => "$crstype Title",
15065: 'cdo' => "$crstype Domain",
15066: 'ins' => 'Institutional Code',
15067: 'inc' => 'Institutional Categorization',
15068: 'cow' => "$crstype Owner/Co-owner",
15069: 'cop' => "$crstype Personnel Includes",
15070: 'cog' => 'Type',
15071: );
15072:
15073: if (($formname eq 'ccrs') || ($formname eq 'requestcrs')) {
15074: my $typeval = 'Course';
15075: if ($crstype eq 'Community') {
15076: $typeval = 'Community';
15077: }
15078: $typeselectform = '<input type="hidden" name="type" value="'.$typeval.'" />';
15079: } else {
15080: $typeselectform = '<select name="type" size="1"';
15081: if ($onchange) {
15082: $typeselectform .= ' onchange="'.$onchange.'"';
15083: }
15084: $typeselectform .= '>'."\n";
15085: foreach my $posstype ('Course','Community') {
15086: $typeselectform.='<option value="'.$posstype.'"'.
15087: ($posstype eq $crstype ? ' selected="selected" ' : ''). ">".&mt($posstype)."</option>\n";
15088: }
15089: $typeselectform.="</select>";
15090: }
15091:
15092: my ($cloneableonlyform,$cloneabletitle);
15093: if (exists($filter->{'cloneableonly'})) {
15094: my $cloneableon = '';
15095: my $cloneableoff = ' checked="checked"';
15096: if ($filter->{'cloneableonly'}) {
15097: $cloneableon = $cloneableoff;
15098: $cloneableoff = '';
15099: }
15100: $cloneableonlyform = '<span class="LC_nobreak"><label><input type="radio" name="cloneableonly" value="1" '.$cloneableon.'/> '.&mt('Required').'</label>'.(' 'x3).'<label><input type="radio" name="cloneableonly" value="" '.$cloneableoff.' /> '.&mt('No restriction').'</label></span>';
15101: if ($formname eq 'ccrs') {
1.1075.2.71 raeburn 15102: $cloneabletitle = &mt('Cloneable for [_1]',$cloneruname.':'.$clonerudom);
1.1075.2.69 raeburn 15103: } else {
15104: $cloneabletitle = &mt('Cloneable by you');
15105: }
15106: }
15107: my $officialjs;
15108: if ($crstype eq 'Course') {
15109: if (exists($filter->{'instcodefilter'})) {
15110: # if (($fixeddom) || ($formname eq 'requestcrs') ||
15111: # ($formname eq 'modifycourse') || ($formname eq 'filterpicker')) {
15112: if ($codedom) {
15113: $officialjs = 1;
15114: ($instcodeform,$jscript,$$numtitlesref) =
15115: &Apache::courseclassifier::instcode_selectors($codedom,'filterpicker',
15116: $officialjs,$codetitlesref);
15117: if ($jscript) {
15118: $jscript = '<script type="text/javascript">'."\n".
15119: '// <![CDATA['."\n".
15120: $jscript."\n".
15121: '// ]]>'."\n".
15122: '</script>'."\n";
15123: }
15124: }
15125: if ($instcodeform eq '') {
15126: $instcodeform =
15127: '<input type="text" name="instcodefilter" size="10" value="'.
15128: $list->{'instcodefilter'}.'" />';
15129: $instcodetitle = $lt{'ins'};
15130: } else {
15131: $instcodetitle = $lt{'inc'};
15132: }
15133: if ($fixeddom) {
15134: $instcodetitle .= '<br />('.$codedom.')';
15135: }
15136: }
15137: }
15138: my $output = qq|
15139: <form method="post" name="filterpicker" action="$action">
15140: <input type="hidden" name="form" value="$formname" />
15141: |;
15142: if ($formname eq 'modifycourse') {
15143: $output .= '<input type="hidden" name="phase" value="courselist" />'."\n".
15144: '<input type="hidden" name="prevphase" value="'.
15145: $prevphase.'" />'."\n";
1.1075.2.82 raeburn 15146: } elsif ($formname eq 'quotacheck') {
15147: $output .= qq|
15148: <input type="hidden" name="sortby" value="" />
15149: <input type="hidden" name="sortorder" value="" />
15150: |;
15151: } else {
1.1075.2.69 raeburn 15152: my $name_input;
15153: if ($cnameelement ne '') {
15154: $name_input = '<input type="hidden" name="cnameelement" value="'.
15155: $cnameelement.'" />';
15156: }
15157: $output .= qq|
15158: <input type="hidden" name="cnumelement" value="$cnumelement" />
15159: <input type="hidden" name="cdomelement" value="$cdomelement" />
15160: $name_input
15161: $roleelement
15162: $multelement
15163: $typeelement
15164: |;
15165: if ($formname eq 'portform') {
15166: $output .= '<input type="hidden" name="setroles" value="'.$setroles.'" />'."\n";
15167: }
15168: }
15169: if ($fixeddom) {
15170: $output .= '<input type="hidden" name="fixeddom" value="'.$fixeddom.'" />'."\n";
15171: }
15172: $output .= "<br />\n".&Apache::lonhtmlcommon::start_pick_box();
15173: if ($sincefilterform) {
15174: $output .= &Apache::lonhtmlcommon::row_title($lt{'cac'})
15175: .$sincefilterform
15176: .&Apache::lonhtmlcommon::row_closure();
15177: }
15178: if ($createdfilterform) {
15179: $output .= &Apache::lonhtmlcommon::row_title($lt{'ccr'})
15180: .$createdfilterform
15181: .&Apache::lonhtmlcommon::row_closure();
15182: }
15183: if ($domainselectform) {
15184: $output .= &Apache::lonhtmlcommon::row_title($lt{'cdo'})
15185: .$domainselectform
15186: .&Apache::lonhtmlcommon::row_closure();
15187: }
15188: if ($typeselectform) {
15189: if (($formname eq 'ccrs') || ($formname eq 'requestcrs')) {
15190: $output .= $typeselectform;
15191: } else {
15192: $output .= &Apache::lonhtmlcommon::row_title($lt{'cog'})
15193: .$typeselectform
15194: .&Apache::lonhtmlcommon::row_closure();
15195: }
15196: }
15197: if ($instcodeform) {
15198: $output .= &Apache::lonhtmlcommon::row_title($instcodetitle)
15199: .$instcodeform
15200: .&Apache::lonhtmlcommon::row_closure();
15201: }
15202: if (exists($filter->{'ownerfilter'})) {
15203: $output .= &Apache::lonhtmlcommon::row_title($lt{'cow'}).
15204: '<table><tr><td>'.&mt('Username').'<br />'.
15205: '<input type="text" name="ownerfilter" size="20" value="'.
15206: $list->{'ownerfilter'}.'" /></td><td>'.&mt('Domain').'<br />'.
15207: $ownerdomselectform.'</td></tr></table>'.
15208: &Apache::lonhtmlcommon::row_closure();
15209: }
15210: if (exists($filter->{'personfilter'})) {
15211: $output .= &Apache::lonhtmlcommon::row_title($lt{'cop'}).
15212: '<table><tr><td>'.&mt('Username').'<br />'.
15213: '<input type="text" name="personfilter" size="20" value="'.
15214: $list->{'personfilter'}.'" /></td><td>'.&mt('Domain').'<br />'.
15215: $persondomselectform.'</td></tr></table>'.
15216: &Apache::lonhtmlcommon::row_closure();
15217: }
15218: if (exists($filter->{'coursefilter'})) {
15219: $output .= &Apache::lonhtmlcommon::row_title(&mt('LON-CAPA course ID'))
15220: .'<input type="text" name="coursefilter" size="25" value="'
15221: .$list->{'coursefilter'}.'" />'
15222: .&Apache::lonhtmlcommon::row_closure();
15223: }
15224: if ($cloneableonlyform) {
15225: $output .= &Apache::lonhtmlcommon::row_title($cloneabletitle).
15226: $cloneableonlyform.&Apache::lonhtmlcommon::row_closure();
15227: }
15228: if (exists($filter->{'descriptfilter'})) {
15229: $output .= &Apache::lonhtmlcommon::row_title($lt{'cde'})
15230: .'<input type="text" name="descriptfilter" size="40" value="'
15231: .$list->{'descriptfilter'}.'" />'
15232: .&Apache::lonhtmlcommon::row_closure(1);
15233: }
15234: $output .= &Apache::lonhtmlcommon::end_pick_box().'<p>'.$clonetext."\n".
15235: '<input type="hidden" name="updater" value="" />'."\n".
15236: '<input type="submit" name="gosearch" value="'.
15237: &mt('Search').'" /></p>'."\n".'</form>'."\n".'<hr />'."\n";
15238: return $jscript.$clonewarning.$output;
15239: }
15240:
15241: =pod
15242:
15243: =item * &timebased_select_form()
15244:
15245: Create markup for a dropdown list used to select a time-based
15246: filter e.g., Course Activity, Course Created, when searching for courses
15247: or communities
15248:
15249: Inputs:
15250:
15251: item - name of form element (sincefilter or createdfilter)
15252:
15253: filter - anonymous hash of criteria and their values
15254:
15255: Returns: HTML for a select box contained a blank, then six time selections,
15256: with value set in incoming form variables currently selected.
15257:
15258: Side Effects: None
15259:
15260: =cut
15261:
15262: sub timebased_select_form {
15263: my ($item,$filter) = @_;
15264: if (ref($filter) eq 'HASH') {
15265: $filter->{$item} =~ s/[^\d-]//g;
15266: if (!$filter->{$item}) { $filter->{$item}=-1; }
15267: return &select_form(
15268: $filter->{$item},
15269: $item,
15270: { '-1' => '',
15271: '86400' => &mt('today'),
15272: '604800' => &mt('last week'),
15273: '2592000' => &mt('last month'),
15274: '7776000' => &mt('last three months'),
15275: '15552000' => &mt('last six months'),
15276: '31104000' => &mt('last year'),
15277: 'select_form_order' =>
15278: ['-1','86400','604800','2592000','7776000',
15279: '15552000','31104000']});
15280: }
15281: }
15282:
15283: =pod
15284:
15285: =item * &js_changer()
15286:
15287: Create script tag containing Javascript used to submit course search form
15288: when course type or domain is changed, and also to hide 'Searching ...' on
15289: page load completion for page showing search result.
15290:
15291: Inputs: None
15292:
15293: Returns: markup containing updateFilters() and hideSearching() javascript functions.
15294:
15295: Side Effects: None
15296:
15297: =cut
15298:
15299: sub js_changer {
15300: return <<ENDJS;
15301: <script type="text/javascript">
15302: // <![CDATA[
15303: function updateFilters(caller) {
15304: if (typeof(caller) != "undefined") {
15305: document.filterpicker.updater.value = caller.name;
15306: }
15307: document.filterpicker.submit();
15308: }
15309:
15310: function hideSearching() {
15311: if (document.getElementById('searching')) {
15312: document.getElementById('searching').style.display = 'none';
15313: }
15314: return;
15315: }
15316:
15317: // ]]>
15318: </script>
15319:
15320: ENDJS
15321: }
15322:
15323: =pod
15324:
15325: =item * &search_courses()
15326:
15327: Process selected filters form course search form and pass to lonnet::courseiddump
15328: to retrieve a hash for which keys are courseIDs which match the selected filters.
15329:
15330: Inputs:
15331:
15332: dom - domain being searched
15333:
15334: type - course type ('Course' or 'Community' or '.' if any).
15335:
15336: filter - anonymous hash of criteria and their values
15337:
15338: numtitles - for institutional codes - number of categories
15339:
15340: cloneruname - optional username of new course owner
15341:
15342: clonerudom - optional domain of new course owner
15343:
15344: domcloner - Optional "domcloner" flag; has value=1 if user has ccc priv in domain being filtered by,
15345: (used when DC is using course creation form)
15346:
15347: codetitles - reference to array of titles of components in institutional codes (official courses).
15348:
15349:
15350: Returns: %courses - hash of courses satisfying search criteria, keys = course IDs, values are corresponding colon-separated escaped description, institutional code, owner and type.
15351:
15352:
15353: Side Effects: None
15354:
15355: =cut
15356:
15357:
15358: sub search_courses {
15359: my ($dom,$type,$filter,$numtitles,$cloneruname,$clonerudom,$domcloner,$codetitles) = @_;
15360: my (%courses,%showcourses,$cloner);
15361: if (($filter->{'ownerfilter'} ne '') ||
15362: ($filter->{'ownerdomfilter'} ne '')) {
15363: $filter->{'combownerfilter'} = $filter->{'ownerfilter'}.':'.
15364: $filter->{'ownerdomfilter'};
15365: }
15366: foreach my $item ('descriptfilter','coursefilter','combownerfilter') {
15367: if (!$filter->{$item}) {
15368: $filter->{$item}='.';
15369: }
15370: }
15371: my $now = time;
15372: my $timefilter =
15373: ($filter->{'sincefilter'}==-1?1:$now-$filter->{'sincefilter'});
15374: my ($createdbefore,$createdafter);
15375: if (($filter->{'createdfilter'} ne '') && ($filter->{'createdfilter'} !=-1)) {
15376: $createdbefore = $now;
15377: $createdafter = $now-$filter->{'createdfilter'};
15378: }
15379: my ($instcodefilter,$regexpok);
15380: if ($numtitles) {
15381: if ($env{'form.official'} eq 'on') {
15382: $instcodefilter =
15383: &Apache::courseclassifier::instcode_search_str($dom,$numtitles,$codetitles);
15384: $regexpok = 1;
15385: } elsif ($env{'form.official'} eq 'off') {
15386: $instcodefilter = &Apache::courseclassifier::instcode_search_str($dom,$numtitles,$codetitles);
15387: unless ($instcodefilter eq '') {
15388: $regexpok = -1;
15389: }
15390: }
15391: } else {
15392: $instcodefilter = $filter->{'instcodefilter'};
15393: }
15394: if ($instcodefilter eq '') { $instcodefilter = '.'; }
15395: if ($type eq '') { $type = '.'; }
15396:
15397: if (($clonerudom ne '') && ($cloneruname ne '')) {
15398: $cloner = $cloneruname.':'.$clonerudom;
15399: }
15400: %courses = &Apache::lonnet::courseiddump($dom,
15401: $filter->{'descriptfilter'},
15402: $timefilter,
15403: $instcodefilter,
15404: $filter->{'combownerfilter'},
15405: $filter->{'coursefilter'},
15406: undef,undef,$type,$regexpok,undef,undef,
15407: undef,undef,$cloner,$env{'form.cc_clone'},
15408: $filter->{'cloneableonly'},
15409: $createdbefore,$createdafter,undef,
15410: $domcloner);
15411: if (($filter->{'personfilter'} ne '') && ($filter->{'persondomfilter'} ne '')) {
15412: my $ccrole;
15413: if ($type eq 'Community') {
15414: $ccrole = 'co';
15415: } else {
15416: $ccrole = 'cc';
15417: }
15418: my %rolehash = &Apache::lonnet::get_my_roles($filter->{'personfilter'},
15419: $filter->{'persondomfilter'},
15420: 'userroles',undef,
15421: [$ccrole,'in','ad','ep','ta','cr'],
15422: $dom);
15423: foreach my $role (keys(%rolehash)) {
15424: my ($cnum,$cdom,$courserole) = split(':',$role);
15425: my $cid = $cdom.'_'.$cnum;
15426: if (exists($courses{$cid})) {
15427: if (ref($courses{$cid}) eq 'HASH') {
15428: if (ref($courses{$cid}{roles}) eq 'ARRAY') {
15429: if (!grep(/^\Q$courserole\E$/,@{$courses{$cid}{roles}})) {
15430: push (@{$courses{$cid}{roles}},$courserole);
15431: }
15432: } else {
15433: $courses{$cid}{roles} = [$courserole];
15434: }
15435: $showcourses{$cid} = $courses{$cid};
15436: }
15437: }
15438: }
15439: %courses = %showcourses;
15440: }
15441: return %courses;
15442: }
15443:
15444: =pod
15445:
15446: =back
15447:
1.1075.2.88 raeburn 15448: =head1 Routines for version requirements for current course.
15449:
15450: =over 4
15451:
15452: =item * &check_release_required()
15453:
15454: Compares required LON-CAPA version with version on server, and
15455: if required version is newer looks for a server with the required version.
15456:
15457: Looks first at servers in user's owen domain; if none suitable, looks at
15458: servers in course's domain are permitted to host sessions for user's domain.
15459:
15460: Inputs:
15461:
15462: $loncaparev - Version on current server (format: Major.Minor.Subrelease-datestamp)
15463:
15464: $courseid - Course ID of current course
15465:
15466: $rolecode - User's current role in course (for switchserver query string).
15467:
15468: $required - LON-CAPA version needed by course (format: Major.Minor).
15469:
15470:
15471: Returns:
15472:
15473: $switchserver - query string tp append to /adm/switchserver call (if
15474: current server's LON-CAPA version is too old.
15475:
15476: $warning - Message is displayed if no suitable server could be found.
15477:
15478: =cut
15479:
15480: sub check_release_required {
15481: my ($loncaparev,$courseid,$rolecode,$required) = @_;
15482: my ($switchserver,$warning);
15483: if ($required ne '') {
15484: my ($reqdmajor,$reqdminor) = ($required =~ /^(\d+)\.(\d+)$/);
15485: my ($major,$minor) = ($loncaparev =~ /^\'?(\d+)\.(\d+)\.[\w.\-]+\'?$/);
15486: if ($reqdmajor ne '' && $reqdminor ne '') {
15487: my $otherserver;
15488: if (($major eq '' && $minor eq '') ||
15489: (($reqdmajor > $major) || (($reqdmajor == $major) && ($reqdminor > $minor)))) {
15490: my ($userdomserver) = &Apache::lonnet::choose_server($env{'user.domain'},undef,$required,1);
15491: my $switchlcrev =
15492: &Apache::lonnet::get_server_loncaparev($env{'user.domain'},
15493: $userdomserver);
15494: my ($swmajor,$swminor) = ($switchlcrev =~ /^\'?(\d+)\.(\d+)\.[\w.\-]+\'?$/);
15495: if (($swmajor eq '' && $swminor eq '') || ($reqdmajor > $swmajor) ||
15496: (($reqdmajor == $swmajor) && ($reqdminor > $swminor))) {
15497: my $cdom = $env{'course.'.$courseid.'.domain'};
15498: if ($cdom ne $env{'user.domain'}) {
15499: my ($coursedomserver,$coursehostname) = &Apache::lonnet::choose_server($cdom,undef,$required,1);
15500: my $serverhomeID = &Apache::lonnet::get_server_homeID($coursehostname);
15501: my $serverhomedom = &Apache::lonnet::host_domain($serverhomeID);
15502: my %defdomdefaults = &Apache::lonnet::get_domain_defaults($serverhomedom);
15503: my %udomdefaults = &Apache::lonnet::get_domain_defaults($env{'user.domain'});
15504: my $remoterev = &Apache::lonnet::get_server_loncaparev($serverhomedom,$coursedomserver);
15505: my $canhost =
15506: &Apache::lonnet::can_host_session($env{'user.domain'},
15507: $coursedomserver,
15508: $remoterev,
15509: $udomdefaults{'remotesessions'},
15510: $defdomdefaults{'hostedsessions'});
15511:
15512: if ($canhost) {
15513: $otherserver = $coursedomserver;
15514: } else {
15515: $warning = &mt('Requires LON-CAPA version [_1].',$env{'course.'.$courseid.'.internal.releaserequired'}).'<br />'. &mt("No suitable server could be found amongst servers in either your own domain or in the course's domain.");
15516: }
15517: } else {
15518: $warning = &mt('Requires LON-CAPA version [_1].',$env{'course.'.$courseid.'.internal.releaserequired'}).'<br />'.&mt("No suitable server could be found amongst servers in your own domain (which is also the course's domain).");
15519: }
15520: } else {
15521: $otherserver = $userdomserver;
15522: }
15523: }
15524: if ($otherserver ne '') {
15525: $switchserver = 'otherserver='.$otherserver.'&role='.$rolecode;
15526: }
15527: }
15528: }
15529: return ($switchserver,$warning);
15530: }
15531:
15532: =pod
15533:
15534: =item * &check_release_result()
15535:
15536: Inputs:
15537:
15538: $switchwarning - Warning message if no suitable server found to host session.
15539:
15540: $switchserver - query string to append to /adm/switchserver containing lonHostID
15541: and current role.
15542:
15543: Returns: HTML to display with information about requirement to switch server.
15544: Either displaying warning with link to Roles/Courses screen or
15545: display link to switchserver.
15546:
1.1075.2.69 raeburn 15547: =cut
15548:
1.1075.2.88 raeburn 15549: sub check_release_result {
15550: my ($switchwarning,$switchserver) = @_;
15551: my $output = &start_page('Selected course unavailable on this server').
15552: '<p class="LC_warning">';
15553: if ($switchwarning) {
15554: $output .= $switchwarning.'<br /><a href="/adm/roles">';
15555: if (&show_course()) {
15556: $output .= &mt('Display courses');
15557: } else {
15558: $output .= &mt('Display roles');
15559: }
15560: $output .= '</a>';
15561: } elsif ($switchserver) {
15562: $output .= &mt('This course requires a newer version of LON-CAPA than is installed on this server.').
15563: '<br />'.
15564: '<a href="/adm/switchserver?'.$switchserver.'">'.
15565: &mt('Switch Server').
15566: '</a>';
15567: }
15568: $output .= '</p>'.&end_page();
15569: return $output;
15570: }
15571:
15572: =pod
15573:
15574: =item * &needs_coursereinit()
15575:
15576: Determine if course contents stored for user's session needs to be
15577: refreshed, because content has changed since "Big Hash" last tied.
15578:
15579: Check for change is made if time last checked is more than 10 minutes ago
15580: (by default).
15581:
15582: Inputs:
15583:
15584: $loncaparev - Version on current server (format: Major.Minor.Subrelease-datestamp)
15585:
15586: $interval (optional) - Time which may elapse (in s) between last check for content
15587: change in current course. (default: 600 s).
15588:
15589: Returns: an array; first element is:
15590:
15591: =over 4
15592:
15593: 'switch' - if content updates mean user's session
15594: needs to be switched to a server running a newer LON-CAPA version
15595:
15596: 'update' - if course session needs to be refreshed (i.e., Big Hash needs to be reloaded)
15597: on current server hosting user's session
15598:
15599: '' - if no action required.
15600:
15601: =back
15602:
15603: If first item element is 'switch':
15604:
15605: second item is $switchwarning - Warning message if no suitable server found to host session.
15606:
15607: third item is $switchserver - query string to append to /adm/switchserver containing lonHostID
15608: and current role.
15609:
15610: otherwise: no other elements returned.
15611:
15612: =back
15613:
15614: =cut
15615:
15616: sub needs_coursereinit {
15617: my ($loncaparev,$interval) = @_;
15618: return() unless ($env{'request.course.id'} && $env{'request.course.tied'});
15619: my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
15620: my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
15621: my $now = time;
15622: if ($interval eq '') {
15623: $interval = 600;
15624: }
15625: if (($now-$env{'request.course.timechecked'})>$interval) {
15626: my $lastchange = &Apache::lonnet::get_coursechange($cdom,$cnum);
15627: &Apache::lonnet::appenv({'request.course.timechecked'=>$now});
15628: if ($lastchange > $env{'request.course.tied'}) {
15629: my %curr_reqd_hash = &Apache::lonnet::userenvironment($cdom,$cnum,'internal.releaserequired');
15630: if ($curr_reqd_hash{'internal.releaserequired'} ne '') {
15631: my $required = $env{'course.'.$cdom.'_'.$cnum.'.internal.releaserequired'};
15632: if ($curr_reqd_hash{'internal.releaserequired'} ne $required) {
15633: &Apache::lonnet::appenv({'course.'.$cdom.'_'.$cnum.'.internal.releaserequired' =>
15634: $curr_reqd_hash{'internal.releaserequired'}});
15635: my ($switchserver,$switchwarning) =
15636: &check_release_required($loncaparev,$cdom.'_'.$cnum,$env{'request.role'},
15637: $curr_reqd_hash{'internal.releaserequired'});
15638: if ($switchwarning ne '' || $switchserver ne '') {
15639: return ('switch',$switchwarning,$switchserver);
15640: }
15641: }
15642: }
15643: return ('update');
15644: }
15645: }
15646: return ();
15647: }
1.1075.2.69 raeburn 15648:
1.1075.2.11 raeburn 15649: sub update_content_constraints {
15650: my ($cdom,$cnum,$chome,$cid) = @_;
15651: my %curr_reqd_hash = &Apache::lonnet::userenvironment($cdom,$cnum,'internal.releaserequired');
15652: my ($reqdmajor,$reqdminor) = split(/\./,$curr_reqd_hash{'internal.releaserequired'});
15653: my %checkresponsetypes;
15654: foreach my $key (keys(%Apache::lonnet::needsrelease)) {
15655: my ($item,$name,$value) = split(/:/,$key);
15656: if ($item eq 'resourcetag') {
15657: if ($name eq 'responsetype') {
15658: $checkresponsetypes{$value} = $Apache::lonnet::needsrelease{$key}
15659: }
15660: }
15661: }
15662: my $navmap = Apache::lonnavmaps::navmap->new();
15663: if (defined($navmap)) {
15664: my %allresponses;
15665: foreach my $res ($navmap->retrieveResources(undef,sub { $_[0]->is_problem() },1,0)) {
15666: my %responses = $res->responseTypes();
15667: foreach my $key (keys(%responses)) {
15668: next unless(exists($checkresponsetypes{$key}));
15669: $allresponses{$key} += $responses{$key};
15670: }
15671: }
15672: foreach my $key (keys(%allresponses)) {
15673: my ($major,$minor) = split(/\./,$checkresponsetypes{$key});
15674: if (($major > $reqdmajor) || ($major == $reqdmajor && $minor > $reqdminor)) {
15675: ($reqdmajor,$reqdminor) = ($major,$minor);
15676: }
15677: }
15678: undef($navmap);
15679: }
15680: unless (($reqdmajor eq '') && ($reqdminor eq '')) {
15681: &Apache::lonnet::update_released_required($reqdmajor.'.'.$reqdminor,$cdom,$cnum,$chome,$cid);
15682: }
15683: return;
15684: }
15685:
1.1075.2.27 raeburn 15686: sub allmaps_incourse {
15687: my ($cdom,$cnum,$chome,$cid) = @_;
15688: if ($cdom eq '' || $cnum eq '' || $chome eq '' || $cid eq '') {
15689: $cid = $env{'request.course.id'};
15690: $cdom = $env{'course.'.$cid.'.domain'};
15691: $cnum = $env{'course.'.$cid.'.num'};
15692: $chome = $env{'course.'.$cid.'.home'};
15693: }
15694: my %allmaps = ();
15695: my $lastchange =
15696: &Apache::lonnet::get_coursechange($cdom,$cnum);
15697: if ($lastchange > $env{'request.course.tied'}) {
15698: my ($furl,$ferr) = &Apache::lonuserstate::readmap("$cdom/$cnum");
15699: unless ($ferr) {
15700: &update_content_constraints($cdom,$cnum,$chome,$cid);
15701: }
15702: }
15703: my $navmap = Apache::lonnavmaps::navmap->new();
15704: if (defined($navmap)) {
15705: foreach my $res ($navmap->retrieveResources(undef,sub { $_[0]->is_map() },1,0,1)) {
15706: $allmaps{$res->src()} = 1;
15707: }
15708: }
15709: return \%allmaps;
15710: }
15711:
1.1075.2.11 raeburn 15712: sub parse_supplemental_title {
15713: my ($title) = @_;
15714:
15715: my ($foldertitle,$renametitle);
15716: if ($title =~ /&&&/) {
15717: $title = &HTML::Entites::decode($title);
15718: }
15719: if ($title =~ m/^(\d+)___&&&___($match_username)___&&&___($match_domain)___&&&___(.*)$/) {
15720: $renametitle=$4;
15721: my ($time,$uname,$udom) = ($1,$2,$3);
15722: $foldertitle=&Apache::lontexconvert::msgtexconverted($4);
15723: my $name = &plainname($uname,$udom);
15724: $name = &HTML::Entities::encode($name,'"<>&\'');
15725: $renametitle = &HTML::Entities::encode($renametitle,'"<>&\'');
15726: $title='<i>'.&Apache::lonlocal::locallocaltime($time).'</i> '.
15727: $name.': <br />'.$foldertitle;
15728: }
15729: if (wantarray) {
15730: return ($title,$foldertitle,$renametitle);
15731: }
15732: return $title;
15733: }
15734:
1.1075.2.43 raeburn 15735: sub recurse_supplemental {
15736: my ($cnum,$cdom,$suppmap,$numfiles,$errors) = @_;
15737: if ($suppmap) {
15738: my ($errtext,$fatal) = &LONCAPA::map::mapread('/uploaded/'.$cdom.'/'.$cnum.'/'.$suppmap);
15739: if ($fatal) {
15740: $errors ++;
15741: } else {
15742: if ($#LONCAPA::map::resources > 0) {
15743: foreach my $res (@LONCAPA::map::resources) {
15744: my ($title,$src,$ext,$type,$status)=split(/\:/,$res);
15745: if (($src ne '') && ($status eq 'res')) {
1.1075.2.46 raeburn 15746: if ($src =~ m{^\Q/uploaded/$cdom/$cnum/\E(supplemental_\d+\.sequence)$}) {
15747: ($numfiles,$errors) = &recurse_supplemental($cnum,$cdom,$1,$numfiles,$errors);
1.1075.2.43 raeburn 15748: } else {
15749: $numfiles ++;
15750: }
15751: }
15752: }
15753: }
15754: }
15755: }
15756: return ($numfiles,$errors);
15757: }
15758:
1.1075.2.18 raeburn 15759: sub symb_to_docspath {
15760: my ($symb) = @_;
15761: return unless ($symb);
15762: my ($mapurl,$id,$resurl) = &Apache::lonnet::decode_symb($symb);
15763: if ($resurl=~/\.(sequence|page)$/) {
15764: $mapurl=$resurl;
15765: } elsif ($resurl eq 'adm/navmaps') {
15766: $mapurl=$env{'course.'.$env{'request.course.id'}.'.url'};
15767: }
15768: my $mapresobj;
15769: my $navmap = Apache::lonnavmaps::navmap->new();
15770: if (ref($navmap)) {
15771: $mapresobj = $navmap->getResourceByUrl($mapurl);
15772: }
15773: $mapurl=~s{^.*/([^/]+)\.(\w+)$}{$1};
15774: my $type=$2;
15775: my $path;
15776: if (ref($mapresobj)) {
15777: my $pcslist = $mapresobj->map_hierarchy();
15778: if ($pcslist ne '') {
15779: foreach my $pc (split(/,/,$pcslist)) {
15780: next if ($pc <= 1);
15781: my $res = $navmap->getByMapPc($pc);
15782: if (ref($res)) {
15783: my $thisurl = $res->src();
15784: $thisurl=~s{^.*/([^/]+)\.\w+$}{$1};
15785: my $thistitle = $res->title();
15786: $path .= '&'.
15787: &Apache::lonhtmlcommon::entity_encode($thisurl).'&'.
1.1075.2.46 raeburn 15788: &escape($thistitle).
1.1075.2.18 raeburn 15789: ':'.$res->randompick().
15790: ':'.$res->randomout().
15791: ':'.$res->encrypted().
15792: ':'.$res->randomorder().
15793: ':'.$res->is_page();
15794: }
15795: }
15796: }
15797: $path =~ s/^\&//;
15798: my $maptitle = $mapresobj->title();
15799: if ($mapurl eq 'default') {
1.1075.2.38 raeburn 15800: $maptitle = 'Main Content';
1.1075.2.18 raeburn 15801: }
15802: $path .= (($path ne '')? '&' : '').
15803: &Apache::lonhtmlcommon::entity_encode($mapurl).'&'.
1.1075.2.46 raeburn 15804: &escape($maptitle).
1.1075.2.18 raeburn 15805: ':'.$mapresobj->randompick().
15806: ':'.$mapresobj->randomout().
15807: ':'.$mapresobj->encrypted().
15808: ':'.$mapresobj->randomorder().
15809: ':'.$mapresobj->is_page();
15810: } else {
15811: my $maptitle = &Apache::lonnet::gettitle($mapurl);
15812: my $ispage = (($type eq 'page')? 1 : '');
15813: if ($mapurl eq 'default') {
1.1075.2.38 raeburn 15814: $maptitle = 'Main Content';
1.1075.2.18 raeburn 15815: }
15816: $path = &Apache::lonhtmlcommon::entity_encode($mapurl).'&'.
1.1075.2.46 raeburn 15817: &escape($maptitle).':::::'.$ispage;
1.1075.2.18 raeburn 15818: }
15819: unless ($mapurl eq 'default') {
15820: $path = 'default&'.
1.1075.2.46 raeburn 15821: &escape('Main Content').
1.1075.2.18 raeburn 15822: ':::::&'.$path;
15823: }
15824: return $path;
15825: }
15826:
1.1075.2.14 raeburn 15827: sub captcha_display {
15828: my ($context,$lonhost) = @_;
15829: my ($output,$error);
15830: my ($captcha,$pubkey,$privkey) = &get_captcha_config($context,$lonhost);
15831: if ($captcha eq 'original') {
15832: $output = &create_captcha();
15833: unless ($output) {
15834: $error = 'captcha';
15835: }
15836: } elsif ($captcha eq 'recaptcha') {
15837: $output = &create_recaptcha($pubkey);
15838: unless ($output) {
15839: $error = 'recaptcha';
15840: }
15841: }
1.1075.2.66 raeburn 15842: return ($output,$error,$captcha);
1.1075.2.14 raeburn 15843: }
15844:
15845: sub captcha_response {
15846: my ($context,$lonhost) = @_;
15847: my ($captcha_chk,$captcha_error);
15848: my ($captcha,$pubkey,$privkey) = &get_captcha_config($context,$lonhost);
15849: if ($captcha eq 'original') {
15850: ($captcha_chk,$captcha_error) = &check_captcha();
15851: } elsif ($captcha eq 'recaptcha') {
15852: $captcha_chk = &check_recaptcha($privkey);
15853: } else {
15854: $captcha_chk = 1;
15855: }
15856: return ($captcha_chk,$captcha_error);
15857: }
15858:
15859: sub get_captcha_config {
15860: my ($context,$lonhost) = @_;
15861: my ($captcha,$pubkey,$privkey,$hashtocheck);
15862: my $hostname = &Apache::lonnet::hostname($lonhost);
15863: my $serverhomeID = &Apache::lonnet::get_server_homeID($hostname);
15864: my $serverhomedom = &Apache::lonnet::host_domain($serverhomeID);
15865: if ($context eq 'usercreation') {
15866: my %domconfig = &Apache::lonnet::get_dom('configuration',[$context],$serverhomedom);
15867: if (ref($domconfig{$context}) eq 'HASH') {
15868: $hashtocheck = $domconfig{$context}{'cancreate'};
15869: if (ref($hashtocheck) eq 'HASH') {
15870: if ($hashtocheck->{'captcha'} eq 'recaptcha') {
15871: if (ref($hashtocheck->{'recaptchakeys'}) eq 'HASH') {
15872: $pubkey = $hashtocheck->{'recaptchakeys'}{'public'};
15873: $privkey = $hashtocheck->{'recaptchakeys'}{'private'};
15874: }
15875: if ($privkey && $pubkey) {
15876: $captcha = 'recaptcha';
15877: } else {
15878: $captcha = 'original';
15879: }
15880: } elsif ($hashtocheck->{'captcha'} ne 'notused') {
15881: $captcha = 'original';
15882: }
15883: }
15884: } else {
15885: $captcha = 'captcha';
15886: }
15887: } elsif ($context eq 'login') {
15888: my %domconfhash = &Apache::loncommon::get_domainconf($serverhomedom);
15889: if ($domconfhash{$serverhomedom.'.login.captcha'} eq 'recaptcha') {
15890: $pubkey = $domconfhash{$serverhomedom.'.login.recaptchakeys_public'};
15891: $privkey = $domconfhash{$serverhomedom.'.login.recaptchakeys_private'};
15892: if ($privkey && $pubkey) {
15893: $captcha = 'recaptcha';
15894: } else {
15895: $captcha = 'original';
15896: }
15897: } elsif ($domconfhash{$serverhomedom.'.login.captcha'} eq 'original') {
15898: $captcha = 'original';
15899: }
15900: }
15901: return ($captcha,$pubkey,$privkey);
15902: }
15903:
15904: sub create_captcha {
15905: my %captcha_params = &captcha_settings();
15906: my ($output,$maxtries,$tries) = ('',10,0);
15907: while ($tries < $maxtries) {
15908: $tries ++;
15909: my $captcha = Authen::Captcha->new (
15910: output_folder => $captcha_params{'output_dir'},
15911: data_folder => $captcha_params{'db_dir'},
15912: );
15913: my $md5sum = $captcha->generate_code($captcha_params{'numchars'});
15914:
15915: if (-e $Apache::lonnet::perlvar{'lonCaptchaDir'}.'/'.$md5sum.'.png') {
15916: $output = '<input type="hidden" name="crypt" value="'.$md5sum.'" />'."\n".
15917: &mt('Type in the letters/numbers shown below').' '.
1.1075.2.66 raeburn 15918: '<input type="text" size="5" name="code" value="" autocomplete="off" />'.
15919: '<br />'.
15920: '<img src="'.$captcha_params{'www_output_dir'}.'/'.$md5sum.'.png" alt="captcha" />';
1.1075.2.14 raeburn 15921: last;
15922: }
15923: }
15924: return $output;
15925: }
15926:
15927: sub captcha_settings {
15928: my %captcha_params = (
15929: output_dir => $Apache::lonnet::perlvar{'lonCaptchaDir'},
15930: www_output_dir => "/captchaspool",
15931: db_dir => $Apache::lonnet::perlvar{'lonCaptchaDb'},
15932: numchars => '5',
15933: );
15934: return %captcha_params;
15935: }
15936:
15937: sub check_captcha {
15938: my ($captcha_chk,$captcha_error);
15939: my $code = $env{'form.code'};
15940: my $md5sum = $env{'form.crypt'};
15941: my %captcha_params = &captcha_settings();
15942: my $captcha = Authen::Captcha->new(
15943: output_folder => $captcha_params{'output_dir'},
15944: data_folder => $captcha_params{'db_dir'},
15945: );
1.1075.2.26 raeburn 15946: $captcha_chk = $captcha->check_code($code,$md5sum);
1.1075.2.14 raeburn 15947: my %captcha_hash = (
15948: 0 => 'Code not checked (file error)',
15949: -1 => 'Failed: code expired',
15950: -2 => 'Failed: invalid code (not in database)',
15951: -3 => 'Failed: invalid code (code does not match crypt)',
15952: );
15953: if ($captcha_chk != 1) {
15954: $captcha_error = $captcha_hash{$captcha_chk}
15955: }
15956: return ($captcha_chk,$captcha_error);
15957: }
15958:
15959: sub create_recaptcha {
15960: my ($pubkey) = @_;
1.1075.2.51 raeburn 15961: my $use_ssl;
15962: if ($ENV{'SERVER_PORT'} == 443) {
15963: $use_ssl = 1;
15964: }
1.1075.2.14 raeburn 15965: my $captcha = Captcha::reCAPTCHA->new;
15966: return $captcha->get_options_setter({theme => 'white'})."\n".
1.1075.2.51 raeburn 15967: $captcha->get_html($pubkey,undef,$use_ssl).
1.1075.2.92 raeburn 15968: &mt('If the text is hard to read, [_1] will replace them.',
1.1075.2.39 raeburn 15969: '<img src="/res/adm/pages/refresh.gif" alt="reCAPTCHA refresh" />').
1.1075.2.14 raeburn 15970: '<br /><br />';
15971: }
15972:
15973: sub check_recaptcha {
15974: my ($privkey) = @_;
15975: my $captcha_chk;
15976: my $captcha = Captcha::reCAPTCHA->new;
15977: my $captcha_result =
15978: $captcha->check_answer(
15979: $privkey,
15980: $ENV{'REMOTE_ADDR'},
15981: $env{'form.recaptcha_challenge_field'},
15982: $env{'form.recaptcha_response_field'},
15983: );
15984: if ($captcha_result->{is_valid}) {
15985: $captcha_chk = 1;
15986: }
15987: return $captcha_chk;
15988: }
15989:
1.1075.2.64 raeburn 15990: sub emailusername_info {
1.1075.2.67 raeburn 15991: my @fields = ('firstname','lastname','institution','web','location','officialemail');
1.1075.2.64 raeburn 15992: my %titles = &Apache::lonlocal::texthash (
15993: lastname => 'Last Name',
15994: firstname => 'First Name',
15995: institution => 'School/college/university',
15996: location => "School's city, state/province, country",
15997: web => "School's web address",
15998: officialemail => 'E-mail address at institution (if different)',
15999: );
16000: return (\@fields,\%titles);
16001: }
16002:
1.1075.2.56 raeburn 16003: sub cleanup_html {
16004: my ($incoming) = @_;
16005: my $outgoing;
16006: if ($incoming ne '') {
16007: $outgoing = $incoming;
16008: $outgoing =~ s/;/;/g;
16009: $outgoing =~ s/\#/#/g;
16010: $outgoing =~ s/\&/&/g;
16011: $outgoing =~ s/</</g;
16012: $outgoing =~ s/>/>/g;
16013: $outgoing =~ s/\(/(/g;
16014: $outgoing =~ s/\)/)/g;
16015: $outgoing =~ s/"/"/g;
16016: $outgoing =~ s/'/'/g;
16017: $outgoing =~ s/\$/$/g;
16018: $outgoing =~ s{/}{/}g;
16019: $outgoing =~ s/=/=/g;
16020: $outgoing =~ s/\\/\/g
16021: }
16022: return $outgoing;
16023: }
16024:
1.1075.2.74 raeburn 16025: # Checks for critical messages and returns a redirect url if one exists.
16026: # $interval indicates how often to check for messages.
16027: sub critical_redirect {
16028: my ($interval) = @_;
16029: if ((time-$env{'user.criticalcheck.time'})>$interval) {
16030: my @what=&Apache::lonnet::dump('critical', $env{'user.domain'},
16031: $env{'user.name'});
16032: &Apache::lonnet::appenv({'user.criticalcheck.time'=>time});
16033: my $redirecturl;
16034: if ($what[0]) {
16035: if (($what[0] ne 'con_lost') && ($what[0]!~/^error\:/)) {
16036: $redirecturl='/adm/email?critical=display';
16037: my $url=&Apache::lonnet::absolute_url().$redirecturl;
16038: return (1, $url);
16039: }
16040: }
16041: }
16042: return ();
16043: }
16044:
1.1075.2.64 raeburn 16045: # Use:
16046: # my $answer=reply("encrypt:passwd:$udom:$uname:$upass",$tryserver);
16047: #
16048: ##################################################
16049: # password associated functions #
16050: ##################################################
16051: sub des_keys {
16052: # Make a new key for DES encryption.
16053: # Each key has two parts which are returned separately.
16054: # Please note: Each key must be passed through the &hex function
16055: # before it is output to the web browser. The hex versions cannot
16056: # be used to decrypt.
16057: my @hexstr=('0','1','2','3','4','5','6','7',
16058: '8','9','a','b','c','d','e','f');
16059: my $lkey='';
16060: for (0..7) {
16061: $lkey.=$hexstr[rand(15)];
16062: }
16063: my $ukey='';
16064: for (0..7) {
16065: $ukey.=$hexstr[rand(15)];
16066: }
16067: return ($lkey,$ukey);
16068: }
16069:
16070: sub des_decrypt {
16071: my ($key,$cyphertext) = @_;
16072: my $keybin=pack("H16",$key);
16073: my $cypher;
16074: if ($Crypt::DES::VERSION>=2.03) {
16075: $cypher=new Crypt::DES $keybin;
16076: } else {
16077: $cypher=new DES $keybin;
16078: }
16079: my $plaintext=
16080: $cypher->decrypt(unpack("a8",pack("H16",substr($cyphertext,0,16))));
16081: $plaintext.=
16082: $cypher->decrypt(unpack("a8",pack("H16",substr($cyphertext,16,16))));
16083: $plaintext=substr($plaintext,1,ord(substr($plaintext,0,1)) );
16084: return $plaintext;
16085: }
16086:
1.112 bowersj2 16087: 1;
16088: __END__;
1.41 ng 16089:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>