Annotation of loncom/interface/loncommon.pm, revision 1.1075.2.115
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.115! raeburn 4: # $Id: loncommon.pm,v 1.1075.2.114 2016/09/18 20:56:04 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.1075.2.102 raeburn 75: use DateTime::Locale;
1.1075.2.94 raeburn 76: use Encode();
1.1075.2.14 raeburn 77: use Authen::Captcha;
78: use Captcha::reCAPTCHA;
1.1075.2.107 raeburn 79: use JSON::DWIW;
80: use LWP::UserAgent;
1.1075.2.64 raeburn 81: use Crypt::DES;
82: use DynaLoader; # for Crypt::DES version
1.117 www 83:
1.517 raeburn 84: # ---------------------------------------------- Designs
85: use vars qw(%defaultdesign);
86:
1.22 www 87: my $readit;
88:
1.517 raeburn 89:
1.157 matthew 90: ##
91: ## Global Variables
92: ##
1.46 matthew 93:
1.643 foxr 94:
95: # ----------------------------------------------- SSI with retries:
96: #
97:
98: =pod
99:
1.648 raeburn 100: =head1 Server Side include with retries:
1.643 foxr 101:
102: =over 4
103:
1.648 raeburn 104: =item * &ssi_with_retries(resource,retries form)
1.643 foxr 105:
106: Performs an ssi with some number of retries. Retries continue either
107: until the result is ok or until the retry count supplied by the
108: caller is exhausted.
109:
110: Inputs:
1.648 raeburn 111:
112: =over 4
113:
1.643 foxr 114: resource - Identifies the resource to insert.
1.648 raeburn 115:
1.643 foxr 116: retries - Count of the number of retries allowed.
1.648 raeburn 117:
1.643 foxr 118: form - Hash that identifies the rendering options.
119:
1.648 raeburn 120: =back
121:
122: Returns:
123:
124: =over 4
125:
1.643 foxr 126: content - The content of the response. If retries were exhausted this is empty.
1.648 raeburn 127:
1.643 foxr 128: response - The response from the last attempt (which may or may not have been successful.
129:
1.648 raeburn 130: =back
131:
132: =back
133:
1.643 foxr 134: =cut
135:
136: sub ssi_with_retries {
137: my ($resource, $retries, %form) = @_;
138:
139:
140: my $ok = 0; # True if we got a good response.
141: my $content;
142: my $response;
143:
144: # Try to get the ssi done. within the retries count:
145:
146: do {
147: ($content, $response) = &Apache::lonnet::ssi($resource, %form);
148: $ok = $response->is_success;
1.650 www 149: if (!$ok) {
150: &Apache::lonnet::logthis("Failed ssi_with_retries on $resource: ".$response->is_success.', '.$response->code.', '.$response->message);
151: }
1.643 foxr 152: $retries--;
153: } while (!$ok && ($retries > 0));
154:
155: if (!$ok) {
156: $content = ''; # On error return an empty content.
157: }
158: return ($content, $response);
159:
160: }
161:
162:
163:
1.20 www 164: # ----------------------------------------------- Filetypes/Languages/Copyright
1.12 harris41 165: my %language;
1.124 www 166: my %supported_language;
1.1048 foxr 167: my %latex_language; # For choosing hyphenation in <transl..>
168: my %latex_language_bykey; # for choosing hyphenation from metadata
1.12 harris41 169: my %cprtag;
1.192 taceyjo1 170: my %scprtag;
1.351 www 171: my %fe; my %fd; my %fm;
1.41 ng 172: my %category_extensions;
1.12 harris41 173:
1.46 matthew 174: # ---------------------------------------------- Thesaurus variables
1.144 matthew 175: #
176: # %Keywords:
177: # A hash used by &keyword to determine if a word is considered a keyword.
178: # $thesaurus_db_file
179: # Scalar containing the full path to the thesaurus database.
1.46 matthew 180:
181: my %Keywords;
182: my $thesaurus_db_file;
183:
1.144 matthew 184: #
185: # Initialize values from language.tab, copyright.tab, filetypes.tab,
186: # thesaurus.tab, and filecategories.tab.
187: #
1.18 www 188: BEGIN {
1.46 matthew 189: # Variable initialization
190: $thesaurus_db_file = $Apache::lonnet::perlvar{'lonTabDir'}."/thesaurus.db";
191: #
1.22 www 192: unless ($readit) {
1.12 harris41 193: # ------------------------------------------------------------------- languages
194: {
1.158 raeburn 195: my $langtabfile = $Apache::lonnet::perlvar{'lonTabDir'}.
196: '/language.tab';
197: if ( open(my $fh,"<$langtabfile") ) {
1.356 albertel 198: while (my $line = <$fh>) {
199: next if ($line=~/^\#/);
200: chomp($line);
1.1048 foxr 201: my ($key,$two,$country,$three,$enc,$val,$sup,$latex)=(split(/\t/,$line));
1.158 raeburn 202: $language{$key}=$val.' - '.$enc;
203: if ($sup) {
204: $supported_language{$key}=$sup;
205: }
1.1048 foxr 206: if ($latex) {
207: $latex_language_bykey{$key} = $latex;
208: $latex_language{$two} = $latex;
209: }
1.158 raeburn 210: }
211: close($fh);
212: }
1.12 harris41 213: }
214: # ------------------------------------------------------------------ copyrights
215: {
1.158 raeburn 216: my $copyrightfile = $Apache::lonnet::perlvar{'lonIncludes'}.
217: '/copyright.tab';
218: if ( open (my $fh,"<$copyrightfile") ) {
1.356 albertel 219: while (my $line = <$fh>) {
220: next if ($line=~/^\#/);
221: chomp($line);
222: my ($key,$val)=(split(/\s+/,$line,2));
1.158 raeburn 223: $cprtag{$key}=$val;
224: }
225: close($fh);
226: }
1.12 harris41 227: }
1.351 www 228: # ----------------------------------------------------------- source copyrights
1.192 taceyjo1 229: {
230: my $sourcecopyrightfile = $Apache::lonnet::perlvar{'lonIncludes'}.
231: '/source_copyright.tab';
232: if ( open (my $fh,"<$sourcecopyrightfile") ) {
1.356 albertel 233: while (my $line = <$fh>) {
234: next if ($line =~ /^\#/);
235: chomp($line);
236: my ($key,$val)=(split(/\s+/,$line,2));
1.192 taceyjo1 237: $scprtag{$key}=$val;
238: }
239: close($fh);
240: }
241: }
1.63 www 242:
1.517 raeburn 243: # -------------------------------------------------------------- default domain designs
1.63 www 244: my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors';
1.517 raeburn 245: my $designfile = $designdir.'/default.tab';
246: if ( open (my $fh,"<$designfile") ) {
247: while (my $line = <$fh>) {
248: next if ($line =~ /^\#/);
249: chomp($line);
250: my ($key,$val)=(split(/\=/,$line));
251: if ($val) { $defaultdesign{$key}=$val; }
252: }
253: close($fh);
1.63 www 254: }
255:
1.15 harris41 256: # ------------------------------------------------------------- file categories
257: {
1.158 raeburn 258: my $categoryfile = $Apache::lonnet::perlvar{'lonTabDir'}.
259: '/filecategories.tab';
260: if ( open (my $fh,"<$categoryfile") ) {
1.356 albertel 261: while (my $line = <$fh>) {
262: next if ($line =~ /^\#/);
263: chomp($line);
264: my ($extension,$category)=(split(/\s+/,$line,2));
1.158 raeburn 265: push @{$category_extensions{lc($category)}},$extension;
266: }
267: close($fh);
268: }
269:
1.15 harris41 270: }
1.12 harris41 271: # ------------------------------------------------------------------ file types
272: {
1.158 raeburn 273: my $typesfile = $Apache::lonnet::perlvar{'lonTabDir'}.
274: '/filetypes.tab';
275: if ( open (my $fh,"<$typesfile") ) {
1.356 albertel 276: while (my $line = <$fh>) {
277: next if ($line =~ /^\#/);
278: chomp($line);
279: my ($ending,$emb,$mime,$descr)=split(/\s+/,$line,4);
1.158 raeburn 280: if ($descr ne '') {
281: $fe{$ending}=lc($emb);
282: $fd{$ending}=$descr;
1.351 www 283: if ($mime ne 'unk') { $fm{$ending}=$mime; }
1.158 raeburn 284: }
285: }
286: close($fh);
287: }
1.12 harris41 288: }
1.22 www 289: &Apache::lonnet::logthis(
1.705 tempelho 290: "<span style='color:yellow;'>INFO: Read file types</span>");
1.22 www 291: $readit=1;
1.46 matthew 292: } # end of unless($readit)
1.32 matthew 293:
294: }
1.112 bowersj2 295:
1.42 matthew 296: ###############################################################
297: ## HTML and Javascript Helper Functions ##
298: ###############################################################
299:
300: =pod
301:
1.112 bowersj2 302: =head1 HTML and Javascript Functions
1.42 matthew 303:
1.112 bowersj2 304: =over 4
305:
1.648 raeburn 306: =item * &browser_and_searcher_javascript()
1.112 bowersj2 307:
308: X<browsing, javascript>X<searching, javascript>Returns a string
309: containing javascript with two functions, C<openbrowser> and
310: C<opensearcher>. Returned string does not contain E<lt>scriptE<gt>
311: tags.
1.42 matthew 312:
1.648 raeburn 313: =item * &openbrowser(formname,elementname,only,omit) [javascript]
1.42 matthew 314:
315: inputs: formname, elementname, only, omit
316:
317: formname and elementname indicate the name of the html form and name of
318: the element that the results of the browsing selection are to be placed in.
319:
320: Specifying 'only' will restrict the browser to displaying only files
1.185 www 321: with the given extension. Can be a comma separated list.
1.42 matthew 322:
323: Specifying 'omit' will restrict the browser to NOT displaying files
1.185 www 324: with the given extension. Can be a comma separated list.
1.42 matthew 325:
1.648 raeburn 326: =item * &opensearcher(formname,elementname) [javascript]
1.42 matthew 327:
328: Inputs: formname, elementname
329:
330: formname and elementname specify the name of the html form and the name
331: of the element the selection from the search results will be placed in.
1.542 raeburn 332:
1.42 matthew 333: =cut
334:
335: sub browser_and_searcher_javascript {
1.199 albertel 336: my ($mode)=@_;
337: if (!defined($mode)) { $mode='edit'; }
1.453 albertel 338: my $resurl=&escape_single(&lastresurl());
1.42 matthew 339: return <<END;
1.219 albertel 340: // <!-- BEGIN LON-CAPA Internal
1.50 matthew 341: var editbrowser = null;
1.135 albertel 342: function openbrowser(formname,elementname,only,omit,titleelement) {
1.170 www 343: var url = '$resurl/?';
1.42 matthew 344: if (editbrowser == null) {
345: url += 'launch=1&';
346: }
347: url += 'catalogmode=interactive&';
1.199 albertel 348: url += 'mode=$mode&';
1.611 albertel 349: url += 'inhibitmenu=yes&';
1.42 matthew 350: url += 'form=' + formname + '&';
351: if (only != null) {
352: url += 'only=' + only + '&';
1.217 albertel 353: } else {
354: url += 'only=&';
355: }
1.42 matthew 356: if (omit != null) {
357: url += 'omit=' + omit + '&';
1.217 albertel 358: } else {
359: url += 'omit=&';
360: }
1.135 albertel 361: if (titleelement != null) {
362: url += 'titleelement=' + titleelement + '&';
1.217 albertel 363: } else {
364: url += 'titleelement=&';
365: }
1.42 matthew 366: url += 'element=' + elementname + '';
367: var title = 'Browser';
1.435 albertel 368: var options = 'scrollbars=1,resizable=1,menubar=0,toolbar=1,location=1';
1.42 matthew 369: options += ',width=700,height=600';
370: editbrowser = open(url,title,options,'1');
371: editbrowser.focus();
372: }
373: var editsearcher;
1.135 albertel 374: function opensearcher(formname,elementname,titleelement) {
1.42 matthew 375: var url = '/adm/searchcat?';
376: if (editsearcher == null) {
377: url += 'launch=1&';
378: }
379: url += 'catalogmode=interactive&';
1.199 albertel 380: url += 'mode=$mode&';
1.42 matthew 381: url += 'form=' + formname + '&';
1.135 albertel 382: if (titleelement != null) {
383: url += 'titleelement=' + titleelement + '&';
1.217 albertel 384: } else {
385: url += 'titleelement=&';
386: }
1.42 matthew 387: url += 'element=' + elementname + '';
388: var title = 'Search';
1.435 albertel 389: var options = 'scrollbars=1,resizable=1,menubar=0,toolbar=1,location=1';
1.42 matthew 390: options += ',width=700,height=600';
391: editsearcher = open(url,title,options,'1');
392: editsearcher.focus();
393: }
1.219 albertel 394: // END LON-CAPA Internal -->
1.42 matthew 395: END
1.170 www 396: }
397:
398: sub lastresurl {
1.258 albertel 399: if ($env{'environment.lastresurl'}) {
400: return $env{'environment.lastresurl'}
1.170 www 401: } else {
402: return '/res';
403: }
404: }
405:
406: sub storeresurl {
407: my $resurl=&Apache::lonnet::clutter(shift);
408: unless ($resurl=~/^\/res/) { return 0; }
409: $resurl=~s/\/$//;
410: &Apache::lonnet::put('environment',{'lastresurl' => $resurl});
1.646 raeburn 411: &Apache::lonnet::appenv({'environment.lastresurl' => $resurl});
1.170 www 412: return 1;
1.42 matthew 413: }
414:
1.74 www 415: sub studentbrowser_javascript {
1.111 www 416: unless (
1.258 albertel 417: (($env{'request.course.id'}) &&
1.302 albertel 418: (&Apache::lonnet::allowed('srm',$env{'request.course.id'})
419: || &Apache::lonnet::allowed('srm',$env{'request.course.id'}.
420: '/'.$env{'request.course.sec'})
421: ))
1.258 albertel 422: || ($env{'request.role'}=~/^(au|dc|su)/)
1.111 www 423: ) { return ''; }
1.74 www 424: return (<<'ENDSTDBRW');
1.776 bisitz 425: <script type="text/javascript" language="Javascript">
1.824 bisitz 426: // <![CDATA[
1.74 www 427: var stdeditbrowser;
1.999 www 428: function openstdbrowser(formname,uname,udom,clicker,roleflag,ignorefilter,courseadvonly) {
1.74 www 429: var url = '/adm/pickstudent?';
430: var filter;
1.558 albertel 431: if (!ignorefilter) {
432: eval('filter=document.'+formname+'.'+uname+'.value;');
433: }
1.74 www 434: if (filter != null) {
435: if (filter != '') {
436: url += 'filter='+filter+'&';
437: }
438: }
439: url += 'form=' + formname + '&unameelement='+uname+
1.999 www 440: '&udomelement='+udom+
441: '&clicker='+clicker;
1.111 www 442: if (roleflag) { url+="&roles=1"; }
1.793 raeburn 443: if (courseadvonly) { url+="&courseadvonly=1"; }
1.102 www 444: var title = 'Student_Browser';
1.74 www 445: var options = 'scrollbars=1,resizable=1,menubar=0';
446: options += ',width=700,height=600';
447: stdeditbrowser = open(url,title,options,'1');
448: stdeditbrowser.focus();
449: }
1.824 bisitz 450: // ]]>
1.74 www 451: </script>
452: ENDSTDBRW
453: }
1.42 matthew 454:
1.1003 www 455: sub resourcebrowser_javascript {
456: unless ($env{'request.course.id'}) { return ''; }
1.1004 www 457: return (<<'ENDRESBRW');
1.1003 www 458: <script type="text/javascript" language="Javascript">
459: // <![CDATA[
460: var reseditbrowser;
1.1004 www 461: function openresbrowser(formname,reslink) {
1.1005 www 462: var url = '/adm/pickresource?form='+formname+'&reslink='+reslink;
1.1003 www 463: var title = 'Resource_Browser';
464: var options = 'scrollbars=1,resizable=1,menubar=0';
1.1005 www 465: options += ',width=700,height=500';
1.1004 www 466: reseditbrowser = open(url,title,options,'1');
467: reseditbrowser.focus();
1.1003 www 468: }
469: // ]]>
470: </script>
1.1004 www 471: ENDRESBRW
1.1003 www 472: }
473:
1.74 www 474: sub selectstudent_link {
1.999 www 475: my ($form,$unameele,$udomele,$courseadvonly,$clickerid)=@_;
476: my $callargs = "'".&Apache::lonhtmlcommon::entity_encode($form)."','".
477: &Apache::lonhtmlcommon::entity_encode($unameele)."','".
478: &Apache::lonhtmlcommon::entity_encode($udomele)."'";
1.258 albertel 479: if ($env{'request.course.id'}) {
1.302 albertel 480: if (!&Apache::lonnet::allowed('srm',$env{'request.course.id'})
481: && !&Apache::lonnet::allowed('srm',$env{'request.course.id'}.
482: '/'.$env{'request.course.sec'})) {
1.111 www 483: return '';
484: }
1.999 www 485: $callargs.=",'".&Apache::lonhtmlcommon::entity_encode($clickerid)."'";
1.793 raeburn 486: if ($courseadvonly) {
487: $callargs .= ",'',1,1";
488: }
489: return '<span class="LC_nobreak">'.
490: '<a href="javascript:openstdbrowser('.$callargs.');">'.
491: &mt('Select User').'</a></span>';
1.74 www 492: }
1.258 albertel 493: if ($env{'request.role'}=~/^(au|dc|su)/) {
1.1012 www 494: $callargs .= ",'',1";
1.793 raeburn 495: return '<span class="LC_nobreak">'.
496: '<a href="javascript:openstdbrowser('.$callargs.');">'.
497: &mt('Select User').'</a></span>';
1.111 www 498: }
499: return '';
1.91 www 500: }
501:
1.1004 www 502: sub selectresource_link {
503: my ($form,$reslink,$arg)=@_;
504:
505: my $callargs = "'".&Apache::lonhtmlcommon::entity_encode($form)."','".
506: &Apache::lonhtmlcommon::entity_encode($reslink)."'";
507: unless ($env{'request.course.id'}) { return $arg; }
508: return '<span class="LC_nobreak">'.
509: '<a href="javascript:openresbrowser('.$callargs.');">'.
510: $arg.'</a></span>';
511: }
512:
513:
514:
1.653 raeburn 515: sub authorbrowser_javascript {
516: return <<"ENDAUTHORBRW";
1.776 bisitz 517: <script type="text/javascript" language="JavaScript">
1.824 bisitz 518: // <![CDATA[
1.653 raeburn 519: var stdeditbrowser;
520:
521: function openauthorbrowser(formname,udom) {
522: var url = '/adm/pickauthor?';
523: url += 'form='+formname+'&roledom='+udom;
524: var title = 'Author_Browser';
525: var options = 'scrollbars=1,resizable=1,menubar=0';
526: options += ',width=700,height=600';
527: stdeditbrowser = open(url,title,options,'1');
528: stdeditbrowser.focus();
529: }
530:
1.824 bisitz 531: // ]]>
1.653 raeburn 532: </script>
533: ENDAUTHORBRW
534: }
535:
1.91 www 536: sub coursebrowser_javascript {
1.1075.2.31 raeburn 537: my ($domainfilter,$sec_element,$formname,$role_element,$crstype,
1.1075.2.95 raeburn 538: $credits_element,$instcode) = @_;
1.932 raeburn 539: my $wintitle = 'Course_Browser';
1.931 raeburn 540: if ($crstype eq 'Community') {
1.932 raeburn 541: $wintitle = 'Community_Browser';
1.909 raeburn 542: }
1.876 raeburn 543: my $id_functions = &javascript_index_functions();
544: my $output = '
1.776 bisitz 545: <script type="text/javascript" language="JavaScript">
1.824 bisitz 546: // <![CDATA[
1.468 raeburn 547: var stdeditbrowser;'."\n";
1.876 raeburn 548:
549: $output .= <<"ENDSTDBRW";
1.909 raeburn 550: function opencrsbrowser(formname,uname,udom,desc,extra_element,multflag,type,type_elem) {
1.91 www 551: var url = '/adm/pickcourse?';
1.895 raeburn 552: var formid = getFormIdByName(formname);
1.876 raeburn 553: var domainfilter = getDomainFromSelectbox(formname,udom);
1.128 albertel 554: if (domainfilter != null) {
555: if (domainfilter != '') {
556: url += 'domainfilter='+domainfilter+'&';
557: }
558: }
1.91 www 559: url += 'form=' + formname + '&cnumelement='+uname+
1.187 albertel 560: '&cdomelement='+udom+
561: '&cnameelement='+desc;
1.468 raeburn 562: if (extra_element !=null && extra_element != '') {
1.594 raeburn 563: if (formname == 'rolechoice' || formname == 'studentform') {
1.468 raeburn 564: url += '&roleelement='+extra_element;
565: if (domainfilter == null || domainfilter == '') {
566: url += '&domainfilter='+extra_element;
567: }
1.234 raeburn 568: }
1.468 raeburn 569: else {
570: if (formname == 'portform') {
571: url += '&setroles='+extra_element;
1.800 raeburn 572: } else {
573: if (formname == 'rules') {
574: url += '&fixeddom='+extra_element;
575: }
1.468 raeburn 576: }
577: }
1.230 raeburn 578: }
1.909 raeburn 579: if (type != null && type != '') {
580: url += '&type='+type;
581: }
582: if (type_elem != null && type_elem != '') {
583: url += '&typeelement='+type_elem;
584: }
1.872 raeburn 585: if (formname == 'ccrs') {
586: var ownername = document.forms[formid].ccuname.value;
587: var ownerdom = document.forms[formid].ccdomain.options[document.forms[formid].ccdomain.selectedIndex].value;
1.1075.2.101 raeburn 588: url += '&cloner='+ownername+':'+ownerdom;
589: if (type == 'Course') {
590: url += '&crscode='+document.forms[formid].crscode.value;
591: }
1.1075.2.95 raeburn 592: }
593: if (formname == 'requestcrs') {
594: url += '&crsdom=$domainfilter&crscode=$instcode';
1.872 raeburn 595: }
1.293 raeburn 596: if (multflag !=null && multflag != '') {
597: url += '&multiple='+multflag;
598: }
1.909 raeburn 599: var title = '$wintitle';
1.91 www 600: var options = 'scrollbars=1,resizable=1,menubar=0';
601: options += ',width=700,height=600';
602: stdeditbrowser = open(url,title,options,'1');
603: stdeditbrowser.focus();
604: }
1.876 raeburn 605: $id_functions
606: ENDSTDBRW
1.1075.2.31 raeburn 607: if (($sec_element ne '') || ($role_element ne '') || ($credits_element ne '')) {
608: $output .= &setsec_javascript($sec_element,$formname,$role_element,
609: $credits_element);
1.876 raeburn 610: }
611: $output .= '
612: // ]]>
613: </script>';
614: return $output;
615: }
616:
617: sub javascript_index_functions {
618: return <<"ENDJS";
619:
620: function getFormIdByName(formname) {
621: for (var i=0;i<document.forms.length;i++) {
622: if (document.forms[i].name == formname) {
623: return i;
624: }
625: }
626: return -1;
627: }
628:
629: function getIndexByName(formid,item) {
630: for (var i=0;i<document.forms[formid].elements.length;i++) {
631: if (document.forms[formid].elements[i].name == item) {
632: return i;
633: }
634: }
635: return -1;
636: }
1.468 raeburn 637:
1.876 raeburn 638: function getDomainFromSelectbox(formname,udom) {
639: var userdom;
640: var formid = getFormIdByName(formname);
641: if (formid > -1) {
642: var domid = getIndexByName(formid,udom);
643: if (domid > -1) {
644: if (document.forms[formid].elements[domid].type == 'select-one') {
645: userdom=document.forms[formid].elements[domid].options[document.forms[formid].elements[domid].selectedIndex].value;
646: }
647: if (document.forms[formid].elements[domid].type == 'hidden') {
648: userdom=document.forms[formid].elements[domid].value;
1.468 raeburn 649: }
650: }
651: }
1.876 raeburn 652: return userdom;
653: }
654:
655: ENDJS
1.468 raeburn 656:
1.876 raeburn 657: }
658:
1.1017 raeburn 659: sub javascript_array_indexof {
1.1018 raeburn 660: return <<ENDJS;
1.1017 raeburn 661: <script type="text/javascript" language="JavaScript">
662: // <![CDATA[
663:
664: if (!Array.prototype.indexOf) {
665: Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
666: "use strict";
667: if (this === void 0 || this === null) {
668: throw new TypeError();
669: }
670: var t = Object(this);
671: var len = t.length >>> 0;
672: if (len === 0) {
673: return -1;
674: }
675: var n = 0;
676: if (arguments.length > 0) {
677: n = Number(arguments[1]);
678: if (n !== n) { // shortcut for verifying if it's NaN
679: n = 0;
680: } else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0)) {
681: n = (n > 0 || -1) * Math.floor(Math.abs(n));
682: }
683: }
684: if (n >= len) {
685: return -1;
686: }
687: var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
688: for (; k < len; k++) {
689: if (k in t && t[k] === searchElement) {
690: return k;
691: }
692: }
693: return -1;
694: }
695: }
696:
697: // ]]>
698: </script>
699:
700: ENDJS
701:
702: }
703:
1.876 raeburn 704: sub userbrowser_javascript {
705: my $id_functions = &javascript_index_functions();
706: return <<"ENDUSERBRW";
707:
1.888 raeburn 708: function openuserbrowser(formname,uname,udom,ulast,ufirst,uemail,hideudom,crsdom,caller) {
1.876 raeburn 709: var url = '/adm/pickuser?';
710: var userdom = getDomainFromSelectbox(formname,udom);
711: if (userdom != null) {
712: if (userdom != '') {
713: url += 'srchdom='+userdom+'&';
714: }
715: }
716: url += 'form=' + formname + '&unameelement='+uname+
717: '&udomelement='+udom+
718: '&ulastelement='+ulast+
719: '&ufirstelement='+ufirst+
720: '&uemailelement='+uemail+
1.881 raeburn 721: '&hideudomelement='+hideudom+
722: '&coursedom='+crsdom;
1.888 raeburn 723: if ((caller != null) && (caller != undefined)) {
724: url += '&caller='+caller;
725: }
1.876 raeburn 726: var title = 'User_Browser';
727: var options = 'scrollbars=1,resizable=1,menubar=0';
728: options += ',width=700,height=600';
729: var stdeditbrowser = open(url,title,options,'1');
730: stdeditbrowser.focus();
731: }
732:
1.888 raeburn 733: function fix_domain (formname,udom,origdom,uname) {
1.876 raeburn 734: var formid = getFormIdByName(formname);
735: if (formid > -1) {
1.888 raeburn 736: var unameid = getIndexByName(formid,uname);
1.876 raeburn 737: var domid = getIndexByName(formid,udom);
738: var hidedomid = getIndexByName(formid,origdom);
739: if (hidedomid > -1) {
740: var fixeddom = document.forms[formid].elements[hidedomid].value;
1.888 raeburn 741: var unameval = document.forms[formid].elements[unameid].value;
742: if ((fixeddom != '') && (fixeddom != undefined) && (fixeddom != null) && (unameval != '') && (unameval != undefined) && (unameval != null)) {
743: if (domid > -1) {
744: var slct = document.forms[formid].elements[domid];
745: if (slct.type == 'select-one') {
746: var i;
747: for (i=0;i<slct.length;i++) {
748: if (slct.options[i].value==fixeddom) { slct.selectedIndex=i; }
749: }
750: }
751: if (slct.type == 'hidden') {
752: slct.value = fixeddom;
1.876 raeburn 753: }
754: }
1.468 raeburn 755: }
756: }
757: }
1.876 raeburn 758: return;
759: }
760:
761: $id_functions
762: ENDUSERBRW
1.468 raeburn 763: }
764:
765: sub setsec_javascript {
1.1075.2.31 raeburn 766: my ($sec_element,$formname,$role_element,$credits_element) = @_;
1.905 raeburn 767: my (@courserolenames,@communityrolenames,$rolestr,$courserolestr,
768: $communityrolestr);
769: if ($role_element ne '') {
770: my @allroles = ('st','ta','ep','in','ad');
771: foreach my $crstype ('Course','Community') {
772: if ($crstype eq 'Community') {
773: foreach my $role (@allroles) {
774: push(@communityrolenames,&Apache::lonnet::plaintext($role,$crstype));
775: }
776: push(@communityrolenames,&Apache::lonnet::plaintext('co'));
777: } else {
778: foreach my $role (@allroles) {
779: push(@courserolenames,&Apache::lonnet::plaintext($role,$crstype));
780: }
781: push(@courserolenames,&Apache::lonnet::plaintext('cc'));
782: }
783: }
784: $rolestr = '"'.join('","',@allroles).'"';
785: $courserolestr = '"'.join('","',@courserolenames).'"';
786: $communityrolestr = '"'.join('","',@communityrolenames).'"';
787: }
1.468 raeburn 788: my $setsections = qq|
789: function setSect(sectionlist) {
1.629 raeburn 790: var sectionsArray = new Array();
791: if ((sectionlist != '') && (typeof sectionlist != "undefined")) {
792: sectionsArray = sectionlist.split(",");
793: }
1.468 raeburn 794: var numSections = sectionsArray.length;
795: document.$formname.$sec_element.length = 0;
796: if (numSections == 0) {
797: document.$formname.$sec_element.multiple=false;
798: document.$formname.$sec_element.size=1;
799: document.$formname.$sec_element.options[0] = new Option('No existing sections','',false,false)
800: } else {
801: if (numSections == 1) {
802: document.$formname.$sec_element.multiple=false;
803: document.$formname.$sec_element.size=1;
804: document.$formname.$sec_element.options[0] = new Option('Select','',true,true);
805: document.$formname.$sec_element.options[1] = new Option('No section','',false,false)
806: document.$formname.$sec_element.options[2] = new Option(sectionsArray[0],sectionsArray[0],false,false);
807: } else {
808: for (var i=0; i<numSections; i++) {
809: document.$formname.$sec_element.options[i] = new Option(sectionsArray[i],sectionsArray[i],false,false)
810: }
811: document.$formname.$sec_element.multiple=true
812: if (numSections < 3) {
813: document.$formname.$sec_element.size=numSections;
814: } else {
815: document.$formname.$sec_element.size=3;
816: }
817: document.$formname.$sec_element.options[0].selected = false
818: }
819: }
1.91 www 820: }
1.905 raeburn 821:
822: function setRole(crstype) {
1.468 raeburn 823: |;
1.905 raeburn 824: if ($role_element eq '') {
825: $setsections .= ' return;
826: }
827: ';
828: } else {
829: $setsections .= qq|
830: var elementLength = document.$formname.$role_element.length;
831: var allroles = Array($rolestr);
832: var courserolenames = Array($courserolestr);
833: var communityrolenames = Array($communityrolestr);
834: if (elementLength != undefined) {
835: if (document.$formname.$role_element.options[5].value == 'cc') {
836: if (crstype == 'Course') {
837: return;
838: } else {
839: allroles[5] = 'co';
840: for (var i=0; i<6; i++) {
841: document.$formname.$role_element.options[i].value = allroles[i];
842: document.$formname.$role_element.options[i].text = communityrolenames[i];
843: }
844: }
845: } else {
846: if (crstype == 'Community') {
847: return;
848: } else {
849: allroles[5] = 'cc';
850: for (var i=0; i<6; i++) {
851: document.$formname.$role_element.options[i].value = allroles[i];
852: document.$formname.$role_element.options[i].text = courserolenames[i];
853: }
854: }
855: }
856: }
857: return;
858: }
859: |;
860: }
1.1075.2.31 raeburn 861: if ($credits_element) {
862: $setsections .= qq|
863: function setCredits(defaultcredits) {
864: document.$formname.$credits_element.value = defaultcredits;
865: return;
866: }
867: |;
868: }
1.468 raeburn 869: return $setsections;
870: }
871:
1.91 www 872: sub selectcourse_link {
1.909 raeburn 873: my ($form,$unameele,$udomele,$desc,$extra_element,$multflag,$selecttype,
874: $typeelement) = @_;
875: my $type = $selecttype;
1.871 raeburn 876: my $linktext = &mt('Select Course');
877: if ($selecttype eq 'Community') {
1.909 raeburn 878: $linktext = &mt('Select Community');
1.906 raeburn 879: } elsif ($selecttype eq 'Course/Community') {
880: $linktext = &mt('Select Course/Community');
1.909 raeburn 881: $type = '';
1.1019 raeburn 882: } elsif ($selecttype eq 'Select') {
883: $linktext = &mt('Select');
884: $type = '';
1.871 raeburn 885: }
1.787 bisitz 886: return '<span class="LC_nobreak">'
887: ."<a href='"
888: .'javascript:opencrsbrowser("'.$form.'","'.$unameele
889: .'","'.$udomele.'","'.$desc.'","'.$extra_element
1.909 raeburn 890: .'","'.$multflag.'","'.$type.'","'.$typeelement.'");'
1.871 raeburn 891: ."'>".$linktext.'</a>'
1.787 bisitz 892: .'</span>';
1.74 www 893: }
1.42 matthew 894:
1.653 raeburn 895: sub selectauthor_link {
896: my ($form,$udom)=@_;
897: return '<a href="javascript:openauthorbrowser('."'$form','$udom'".');">'.
898: &mt('Select Author').'</a>';
899: }
900:
1.876 raeburn 901: sub selectuser_link {
1.881 raeburn 902: my ($form,$unameelem,$domelem,$lastelem,$firstelem,$emailelem,$hdomelem,
1.888 raeburn 903: $coursedom,$linktext,$caller) = @_;
1.876 raeburn 904: return '<a href="javascript:openuserbrowser('."'$form','$unameelem','$domelem',".
1.888 raeburn 905: "'$lastelem','$firstelem','$emailelem','$hdomelem','$coursedom','$caller'".
1.881 raeburn 906: ');">'.$linktext.'</a>';
1.876 raeburn 907: }
908:
1.273 raeburn 909: sub check_uncheck_jscript {
910: my $jscript = <<"ENDSCRT";
911: function checkAll(field) {
912: if (field.length > 0) {
913: for (i = 0; i < field.length; i++) {
1.1075.2.14 raeburn 914: if (!field[i].disabled) {
915: field[i].checked = true;
916: }
1.273 raeburn 917: }
918: } else {
1.1075.2.14 raeburn 919: if (!field.disabled) {
920: field.checked = true;
921: }
1.273 raeburn 922: }
923: }
924:
925: function uncheckAll(field) {
926: if (field.length > 0) {
927: for (i = 0; i < field.length; i++) {
928: field[i].checked = false ;
1.543 albertel 929: }
930: } else {
1.273 raeburn 931: field.checked = false ;
932: }
933: }
934: ENDSCRT
935: return $jscript;
936: }
937:
1.656 www 938: sub select_timezone {
1.1075.2.115! raeburn 939: my ($name,$selected,$onchange,$includeempty,$disabled)=@_;
! 940: my $output='<select name="'.$name.'" '.$onchange.$disabled.'>'."\n";
1.659 raeburn 941: if ($includeempty) {
942: $output .= '<option value=""';
943: if (($selected eq '') || ($selected eq 'local')) {
944: $output .= ' selected="selected" ';
945: }
946: $output .= '> </option>';
947: }
1.657 raeburn 948: my @timezones = DateTime::TimeZone->all_names;
949: foreach my $tzone (@timezones) {
950: $output.= '<option value="'.$tzone.'"';
951: if ($tzone eq $selected) {
952: $output.=' selected="selected"';
953: }
954: $output.=">$tzone</option>\n";
1.656 www 955: }
956: $output.="</select>";
957: return $output;
958: }
1.273 raeburn 959:
1.687 raeburn 960: sub select_datelocale {
1.1075.2.115! raeburn 961: my ($name,$selected,$onchange,$includeempty,$disabled)=@_;
! 962: my $output='<select name="'.$name.'" '.$onchange.$disabled.'>'."\n";
1.687 raeburn 963: if ($includeempty) {
964: $output .= '<option value=""';
965: if ($selected eq '') {
966: $output .= ' selected="selected" ';
967: }
968: $output .= '> </option>';
969: }
1.1075.2.102 raeburn 970: my @languages = &Apache::lonlocal::preferred_languages();
1.687 raeburn 971: my (@possibles,%locale_names);
1.1075.2.102 raeburn 972: my @locales = DateTime::Locale->ids();
973: foreach my $id (@locales) {
974: if ($id ne '') {
975: my ($en_terr,$native_terr);
976: my $loc = DateTime::Locale->load($id);
977: if (ref($loc)) {
978: $en_terr = $loc->name();
979: $native_terr = $loc->native_name();
1.687 raeburn 980: if (grep(/^en$/,@languages) || !@languages) {
981: if ($en_terr ne '') {
982: $locale_names{$id} = '('.$en_terr.')';
983: } elsif ($native_terr ne '') {
984: $locale_names{$id} = $native_terr;
985: }
986: } else {
987: if ($native_terr ne '') {
988: $locale_names{$id} = $native_terr.' ';
989: } elsif ($en_terr ne '') {
990: $locale_names{$id} = '('.$en_terr.')';
991: }
992: }
1.1075.2.94 raeburn 993: $locale_names{$id} = Encode::encode('UTF-8',$locale_names{$id});
1.1075.2.102 raeburn 994: push(@possibles,$id);
1.687 raeburn 995: }
996: }
997: }
998: foreach my $item (sort(@possibles)) {
999: $output.= '<option value="'.$item.'"';
1000: if ($item eq $selected) {
1001: $output.=' selected="selected"';
1002: }
1003: $output.=">$item";
1004: if ($locale_names{$item} ne '') {
1.1075.2.94 raeburn 1005: $output.=' '.$locale_names{$item};
1.687 raeburn 1006: }
1007: $output.="</option>\n";
1008: }
1009: $output.="</select>";
1010: return $output;
1011: }
1012:
1.792 raeburn 1013: sub select_language {
1.1075.2.115! raeburn 1014: my ($name,$selected,$includeempty,$noedit) = @_;
1.792 raeburn 1015: my %langchoices;
1016: if ($includeempty) {
1.1075.2.32 raeburn 1017: %langchoices = ('' => 'No language preference');
1.792 raeburn 1018: }
1019: foreach my $id (&languageids()) {
1020: my $code = &supportedlanguagecode($id);
1021: if ($code) {
1022: $langchoices{$code} = &plainlanguagedescription($id);
1023: }
1024: }
1.1075.2.32 raeburn 1025: %langchoices = &Apache::lonlocal::texthash(%langchoices);
1.1075.2.115! raeburn 1026: return &select_form($selected,$name,\%langchoices,undef,$noedit);
1.792 raeburn 1027: }
1028:
1.42 matthew 1029: =pod
1.36 matthew 1030:
1.648 raeburn 1031: =item * &linked_select_forms(...)
1.36 matthew 1032:
1033: linked_select_forms returns a string containing a <script></script> block
1034: and html for two <select> menus. The select menus will be linked in that
1035: changing the value of the first menu will result in new values being placed
1036: in the second menu. The values in the select menu will appear in alphabetical
1.609 raeburn 1037: order unless a defined order is provided.
1.36 matthew 1038:
1039: linked_select_forms takes the following ordered inputs:
1040:
1041: =over 4
1042:
1.112 bowersj2 1043: =item * $formname, the name of the <form> tag
1.36 matthew 1044:
1.112 bowersj2 1045: =item * $middletext, the text which appears between the <select> tags
1.36 matthew 1046:
1.112 bowersj2 1047: =item * $firstdefault, the default value for the first menu
1.36 matthew 1048:
1.112 bowersj2 1049: =item * $firstselectname, the name of the first <select> tag
1.36 matthew 1050:
1.112 bowersj2 1051: =item * $secondselectname, the name of the second <select> tag
1.36 matthew 1052:
1.112 bowersj2 1053: =item * $hashref, a reference to a hash containing the data for the menus.
1.36 matthew 1054:
1.609 raeburn 1055: =item * $menuorder, the order of values in the first menu
1056:
1.1075.2.31 raeburn 1057: =item * $onchangefirst, additional javascript call to execute for an onchange
1058: event for the first <select> tag
1059:
1060: =item * $onchangesecond, additional javascript call to execute for an onchange
1061: event for the second <select> tag
1062:
1.41 ng 1063: =back
1064:
1.36 matthew 1065: Below is an example of such a hash. Only the 'text', 'default', and
1066: 'select2' keys must appear as stated. keys(%menu) are the possible
1067: values for the first select menu. The text that coincides with the
1.41 ng 1068: first menu value is given in $menu{$choice1}->{'text'}. The values
1.36 matthew 1069: and text for the second menu are given in the hash pointed to by
1070: $menu{$choice1}->{'select2'}.
1071:
1.112 bowersj2 1072: my %menu = ( A1 => { text =>"Choice A1" ,
1073: default => "B3",
1074: select2 => {
1075: B1 => "Choice B1",
1076: B2 => "Choice B2",
1077: B3 => "Choice B3",
1078: B4 => "Choice B4"
1.609 raeburn 1079: },
1080: order => ['B4','B3','B1','B2'],
1.112 bowersj2 1081: },
1082: A2 => { text =>"Choice A2" ,
1083: default => "C2",
1084: select2 => {
1085: C1 => "Choice C1",
1086: C2 => "Choice C2",
1087: C3 => "Choice C3"
1.609 raeburn 1088: },
1089: order => ['C2','C1','C3'],
1.112 bowersj2 1090: },
1091: A3 => { text =>"Choice A3" ,
1092: default => "D6",
1093: select2 => {
1094: D1 => "Choice D1",
1095: D2 => "Choice D2",
1096: D3 => "Choice D3",
1097: D4 => "Choice D4",
1098: D5 => "Choice D5",
1099: D6 => "Choice D6",
1100: D7 => "Choice D7"
1.609 raeburn 1101: },
1102: order => ['D4','D3','D2','D1','D7','D6','D5'],
1.112 bowersj2 1103: }
1104: );
1.36 matthew 1105:
1106: =cut
1107:
1108: sub linked_select_forms {
1109: my ($formname,
1110: $middletext,
1111: $firstdefault,
1112: $firstselectname,
1113: $secondselectname,
1.609 raeburn 1114: $hashref,
1115: $menuorder,
1.1075.2.31 raeburn 1116: $onchangefirst,
1117: $onchangesecond
1.36 matthew 1118: ) = @_;
1119: my $second = "document.$formname.$secondselectname";
1120: my $first = "document.$formname.$firstselectname";
1121: # output the javascript to do the changing
1122: my $result = '';
1.776 bisitz 1123: $result.='<script type="text/javascript" language="JavaScript">'."\n";
1.824 bisitz 1124: $result.="// <![CDATA[\n";
1.36 matthew 1125: $result.="var select2data = new Object();\n";
1126: $" = '","';
1127: my $debug = '';
1128: foreach my $s1 (sort(keys(%$hashref))) {
1129: $result.="select2data.d_$s1 = new Object();\n";
1130: $result.="select2data.d_$s1.def = new String('".
1131: $hashref->{$s1}->{'default'}."');\n";
1.609 raeburn 1132: $result.="select2data.d_$s1.values = new Array(";
1.36 matthew 1133: my @s2values = sort(keys( %{ $hashref->{$s1}->{'select2'} } ));
1.609 raeburn 1134: if (ref($hashref->{$s1}->{'order'}) eq 'ARRAY') {
1135: @s2values = @{$hashref->{$s1}->{'order'}};
1136: }
1.36 matthew 1137: $result.="\"@s2values\");\n";
1138: $result.="select2data.d_$s1.texts = new Array(";
1139: my @s2texts;
1140: foreach my $value (@s2values) {
1141: push @s2texts, $hashref->{$s1}->{'select2'}->{$value};
1142: }
1143: $result.="\"@s2texts\");\n";
1144: }
1145: $"=' ';
1146: $result.= <<"END";
1147:
1148: function select1_changed() {
1149: // Determine new choice
1150: var newvalue = "d_" + $first.value;
1151: // update select2
1152: var values = select2data[newvalue].values;
1153: var texts = select2data[newvalue].texts;
1154: var select2def = select2data[newvalue].def;
1155: var i;
1156: // out with the old
1157: for (i = 0; i < $second.options.length; i++) {
1158: $second.options[i] = null;
1159: }
1160: // in with the nuclear
1161: for (i=0;i<values.length; i++) {
1162: $second.options[i] = new Option(values[i]);
1.143 matthew 1163: $second.options[i].value = values[i];
1.36 matthew 1164: $second.options[i].text = texts[i];
1165: if (values[i] == select2def) {
1166: $second.options[i].selected = true;
1167: }
1168: }
1169: }
1.824 bisitz 1170: // ]]>
1.36 matthew 1171: </script>
1172: END
1173: # output the initial values for the selection lists
1.1075.2.31 raeburn 1174: $result .= "<select size=\"1\" name=\"$firstselectname\" onchange=\"select1_changed();$onchangefirst\">\n";
1.609 raeburn 1175: my @order = sort(keys(%{$hashref}));
1176: if (ref($menuorder) eq 'ARRAY') {
1177: @order = @{$menuorder};
1178: }
1179: foreach my $value (@order) {
1.36 matthew 1180: $result.=" <option value=\"$value\" ";
1.253 albertel 1181: $result.=" selected=\"selected\" " if ($value eq $firstdefault);
1.119 www 1182: $result.=">".&mt($hashref->{$value}->{'text'})."</option>\n";
1.36 matthew 1183: }
1184: $result .= "</select>\n";
1185: my %select2 = %{$hashref->{$firstdefault}->{'select2'}};
1186: $result .= $middletext;
1.1075.2.31 raeburn 1187: $result .= "<select size=\"1\" name=\"$secondselectname\"";
1188: if ($onchangesecond) {
1189: $result .= ' onchange="'.$onchangesecond.'"';
1190: }
1191: $result .= ">\n";
1.36 matthew 1192: my $seconddefault = $hashref->{$firstdefault}->{'default'};
1.609 raeburn 1193:
1194: my @secondorder = sort(keys(%select2));
1195: if (ref($hashref->{$firstdefault}->{'order'}) eq 'ARRAY') {
1196: @secondorder = @{$hashref->{$firstdefault}->{'order'}};
1197: }
1198: foreach my $value (@secondorder) {
1.36 matthew 1199: $result.=" <option value=\"$value\" ";
1.253 albertel 1200: $result.=" selected=\"selected\" " if ($value eq $seconddefault);
1.119 www 1201: $result.=">".&mt($select2{$value})."</option>\n";
1.36 matthew 1202: }
1203: $result .= "</select>\n";
1204: # return $debug;
1205: return $result;
1206: } # end of sub linked_select_forms {
1207:
1.45 matthew 1208: =pod
1.44 bowersj2 1209:
1.973 raeburn 1210: =item * &help_open_topic($topic,$text,$stayOnPage,$width,$height,$imgid)
1.44 bowersj2 1211:
1.112 bowersj2 1212: Returns a string corresponding to an HTML link to the given help
1213: $topic, where $topic corresponds to the name of a .tex file in
1214: /home/httpd/html/adm/help/tex, with underscores replaced by
1215: spaces.
1216:
1217: $text will optionally be linked to the same topic, allowing you to
1218: link text in addition to the graphic. If you do not want to link
1219: text, but wish to specify one of the later parameters, pass an
1220: empty string.
1221:
1222: $stayOnPage is a value that will be interpreted as a boolean. If true,
1223: the link will not open a new window. If false, the link will open
1224: a new window using Javascript. (Default is false.)
1225:
1226: $width and $height are optional numerical parameters that will
1227: override the width and height of the popped up window, which may
1.973 raeburn 1228: be useful for certain help topics with big pictures included.
1229:
1230: $imgid is the id of the img tag used for the help icon. This may be
1231: used in a javascript call to switch the image src. See
1232: lonhtmlcommon::htmlareaselectactive() for an example.
1.44 bowersj2 1233:
1234: =cut
1235:
1236: sub help_open_topic {
1.973 raeburn 1237: my ($topic, $text, $stayOnPage, $width, $height, $imgid) = @_;
1.48 bowersj2 1238: $text = "" if (not defined $text);
1.44 bowersj2 1239: $stayOnPage = 0 if (not defined $stayOnPage);
1.1033 www 1240: $width = 500 if (not defined $width);
1.44 bowersj2 1241: $height = 400 if (not defined $height);
1242: my $filename = $topic;
1243: $filename =~ s/ /_/g;
1244:
1.48 bowersj2 1245: my $template = "";
1246: my $link;
1.572 banghart 1247:
1.159 www 1248: $topic=~s/\W/\_/g;
1.44 bowersj2 1249:
1.572 banghart 1250: if (!$stayOnPage) {
1.1075.2.50 raeburn 1251: if ($env{'browser.mobile'}) {
1252: $link = "javascript:openMyModal('/adm/help/${filename}.hlp',$width,$height,'yes');";
1253: } else {
1254: $link = "javascript:void(open('/adm/help/${filename}.hlp', 'Help_for_$topic', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))";
1255: }
1.1037 www 1256: } elsif ($stayOnPage eq 'popup') {
1257: $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 1258: } else {
1.48 bowersj2 1259: $link = "/adm/help/${filename}.hlp";
1260: }
1261:
1262: # Add the text
1.755 neumanie 1263: if ($text ne "") {
1.763 bisitz 1264: $template.='<span class="LC_help_open_topic">'
1265: .'<a target="_top" href="'.$link.'">'
1266: .$text.'</a>';
1.48 bowersj2 1267: }
1268:
1.763 bisitz 1269: # (Always) Add the graphic
1.179 matthew 1270: my $title = &mt('Online Help');
1.667 raeburn 1271: my $helpicon=&lonhttpdurl("/adm/help/help.png");
1.973 raeburn 1272: if ($imgid ne '') {
1273: $imgid = ' id="'.$imgid.'"';
1274: }
1.763 bisitz 1275: $template.=' <a target="_top" href="'.$link.'" title="'.$title.'">'
1276: .'<img src="'.$helpicon.'" border="0"'
1277: .' alt="'.&mt('Help: [_1]',$topic).'"'
1.973 raeburn 1278: .' title="'.$title.'" style="vertical-align:middle;"'.$imgid
1.763 bisitz 1279: .' /></a>';
1280: if ($text ne "") {
1281: $template.='</span>';
1282: }
1.44 bowersj2 1283: return $template;
1284:
1.106 bowersj2 1285: }
1286:
1287: # This is a quicky function for Latex cheatsheet editing, since it
1288: # appears in at least four places
1289: sub helpLatexCheatsheet {
1.1037 www 1290: my ($topic,$text,$not_author,$stayOnPage) = @_;
1.732 raeburn 1291: my $out;
1.106 bowersj2 1292: my $addOther = '';
1.732 raeburn 1293: if ($topic) {
1.1037 www 1294: $addOther = '<span>'.&help_open_topic($topic,&mt($text),$stayOnPage, undef, 600).'</span> ';
1.763 bisitz 1295: }
1296: $out = '<span>' # Start cheatsheet
1297: .$addOther
1298: .'<span>'
1.1037 www 1299: .&help_open_topic('Greek_Symbols',&mt('Greek Symbols'),$stayOnPage,undef,600)
1.763 bisitz 1300: .'</span> <span>'
1.1037 www 1301: .&help_open_topic('Other_Symbols',&mt('Other Symbols'),$stayOnPage,undef,600)
1.763 bisitz 1302: .'</span>';
1.732 raeburn 1303: unless ($not_author) {
1.763 bisitz 1304: $out .= ' <span>'
1.1037 www 1305: .&help_open_topic('Authoring_Output_Tags',&mt('Output Tags'),$stayOnPage,undef,600)
1.1075.2.71 raeburn 1306: .'</span> <span>'
1.1075.2.78 raeburn 1307: .&help_open_topic('Authoring_Multilingual_Problems',&mt('Languages'),$stayOnPage,undef,600)
1.1075.2.71 raeburn 1308: .'</span>';
1.732 raeburn 1309: }
1.763 bisitz 1310: $out .= '</span>'; # End cheatsheet
1.732 raeburn 1311: return $out;
1.172 www 1312: }
1313:
1.430 albertel 1314: sub general_help {
1315: my $helptopic='Student_Intro';
1316: if ($env{'request.role'}=~/^(ca|au)/) {
1317: $helptopic='Authoring_Intro';
1.907 raeburn 1318: } elsif ($env{'request.role'}=~/^(cc|co)/) {
1.430 albertel 1319: $helptopic='Course_Coordination_Intro';
1.672 raeburn 1320: } elsif ($env{'request.role'}=~/^dc/) {
1321: $helptopic='Domain_Coordination_Intro';
1.430 albertel 1322: }
1323: return $helptopic;
1324: }
1325:
1326: sub update_help_link {
1327: my ($topic,$component_help,$faq,$bug,$stayOnPage) = @_;
1328: my $origurl = $ENV{'REQUEST_URI'};
1329: $origurl=~s|^/~|/priv/|;
1330: my $timestamp = time;
1331: foreach my $datum (\$topic,\$component_help,\$faq,\$bug,\$origurl) {
1332: $$datum = &escape($$datum);
1333: }
1334:
1335: my $banner_link = "/adm/helpmenu?page=banner&topic=$topic&component_help=$component_help&faq=$faq&bug=$bug&origurl=$origurl&stamp=$timestamp&stayonpage=$stayOnPage";
1336: my $output .= <<"ENDOUTPUT";
1337: <script type="text/javascript">
1.824 bisitz 1338: // <![CDATA[
1.430 albertel 1339: banner_link = '$banner_link';
1.824 bisitz 1340: // ]]>
1.430 albertel 1341: </script>
1342: ENDOUTPUT
1343: return $output;
1344: }
1345:
1346: # now just updates the help link and generates a blue icon
1.193 raeburn 1347: sub help_open_menu {
1.430 albertel 1348: my ($topic,$component_help,$faq,$bug,$stayOnPage,$width,$height,$text)
1.552 banghart 1349: = @_;
1.949 droeschl 1350: $stayOnPage = 1;
1.430 albertel 1351: my $output;
1352: if ($component_help) {
1353: if (!$text) {
1354: $output=&help_open_topic($component_help,undef,$stayOnPage,
1355: $width,$height);
1356: } else {
1357: my $help_text;
1358: $help_text=&unescape($topic);
1359: $output='<table><tr><td>'.
1360: &help_open_topic($component_help,$help_text,$stayOnPage,
1361: $width,$height).'</td></tr></table>';
1362: }
1363: }
1364: my $banner_link = &update_help_link($topic,$component_help,$faq,$bug,$stayOnPage);
1365: return $output.$banner_link;
1366: }
1367:
1368: sub top_nav_help {
1369: my ($text) = @_;
1.436 albertel 1370: $text = &mt($text);
1.1075.2.60 raeburn 1371: my $stay_on_page;
1372: unless ($env{'environment.remote'} eq 'on') {
1373: $stay_on_page = 1;
1374: }
1.1075.2.61 raeburn 1375: my ($link,$banner_link);
1376: unless ($env{'request.noversionuri'} =~ m{^/adm/helpmenu}) {
1377: $link = ($stay_on_page) ? "javascript:helpMenu('display')"
1378: : "javascript:helpMenu('open')";
1379: $banner_link = &update_help_link(undef,undef,undef,undef,$stay_on_page);
1380: }
1.201 raeburn 1381: my $title = &mt('Get help');
1.1075.2.61 raeburn 1382: if ($link) {
1383: return <<"END";
1.436 albertel 1384: $banner_link
1.1075.2.56 raeburn 1385: <a href="$link" title="$title">$text</a>
1.436 albertel 1386: END
1.1075.2.61 raeburn 1387: } else {
1388: return ' '.$text.' ';
1389: }
1.436 albertel 1390: }
1391:
1392: sub help_menu_js {
1.1075.2.52 raeburn 1393: my ($httphost) = @_;
1.949 droeschl 1394: my $stayOnPage = 1;
1.436 albertel 1395: my $width = 620;
1396: my $height = 600;
1.430 albertel 1397: my $helptopic=&general_help();
1.1075.2.52 raeburn 1398: my $details_link = $httphost.'/adm/help/'.$helptopic.'.hlp';
1.261 albertel 1399: my $nothing=&Apache::lonhtmlcommon::javascript_nothing();
1.331 albertel 1400: my $start_page =
1401: &Apache::loncommon::start_page('Help Menu', undef,
1402: {'frameset' => 1,
1403: 'js_ready' => 1,
1.1075.2.52 raeburn 1404: 'use_absolute' => $httphost,
1.331 albertel 1405: 'add_entries' => {
1406: 'border' => '0',
1.579 raeburn 1407: 'rows' => "110,*",},});
1.331 albertel 1408: my $end_page =
1409: &Apache::loncommon::end_page({'frameset' => 1,
1410: 'js_ready' => 1,});
1411:
1.436 albertel 1412: my $template .= <<"ENDTEMPLATE";
1413: <script type="text/javascript">
1.877 bisitz 1414: // <![CDATA[
1.253 albertel 1415: // <!-- BEGIN LON-CAPA Internal
1.430 albertel 1416: var banner_link = '';
1.243 raeburn 1417: function helpMenu(target) {
1418: var caller = this;
1419: if (target == 'open') {
1420: var newWindow = null;
1421: try {
1.262 albertel 1422: newWindow = window.open($nothing,"helpmenu","HEIGHT=$height,WIDTH=$width,resizable=yes,scrollbars=yes" )
1.243 raeburn 1423: }
1424: catch(error) {
1425: writeHelp(caller);
1426: return;
1427: }
1428: if (newWindow) {
1429: caller = newWindow;
1430: }
1.193 raeburn 1431: }
1.243 raeburn 1432: writeHelp(caller);
1433: return;
1434: }
1435: function writeHelp(caller) {
1.1075.2.61 raeburn 1436: caller.document.writeln('$start_page\\n<frame name="bannerframe" src="'+banner_link+'" marginwidth="0" marginheight="0" frameborder="0">\\n');
1437: caller.document.writeln('<frame name="bodyframe" src="$details_link" marginwidth="0" marginheight="0" frameborder="0">\\n$end_page');
1438: caller.document.close();
1439: caller.focus();
1.193 raeburn 1440: }
1.877 bisitz 1441: // END LON-CAPA Internal -->
1.253 albertel 1442: // ]]>
1.436 albertel 1443: </script>
1.193 raeburn 1444: ENDTEMPLATE
1445: return $template;
1446: }
1447:
1.172 www 1448: sub help_open_bug {
1449: my ($topic, $text, $stayOnPage, $width, $height) = @_;
1.258 albertel 1450: unless ($env{'user.adv'}) { return ''; }
1.172 www 1451: unless ($Apache::lonnet::perlvar{'BugzillaHost'}) { return ''; }
1452: $text = "" if (not defined $text);
1453: $stayOnPage=1;
1.184 albertel 1454: $width = 600 if (not defined $width);
1455: $height = 600 if (not defined $height);
1.172 www 1456:
1457: $topic=~s/\W+/\+/g;
1458: my $link='';
1459: my $template='';
1.379 albertel 1460: my $url=$Apache::lonnet::perlvar{'BugzillaHost'}.'enter_bug.cgi?product=LON-CAPA&bug_file_loc='.
1461: &escape($ENV{'REQUEST_URI'}).'&component='.$topic;
1.172 www 1462: if (!$stayOnPage)
1463: {
1464: $link = "javascript:void(open('$url', 'Bugzilla', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))";
1465: }
1466: else
1467: {
1468: $link = $url;
1469: }
1470: # Add the text
1471: if ($text ne "")
1472: {
1473: $template .=
1474: "<table bgcolor='#AA3333' cellspacing='1' cellpadding='1' border='0'><tr>".
1.705 tempelho 1475: "<td bgcolor='#FF5555'><a target=\"_top\" href=\"$link\"><span style=\"color:#FFFFFF;font-size:10pt;\">$text</span></a>";
1.172 www 1476: }
1477:
1478: # Add the graphic
1.179 matthew 1479: my $title = &mt('Report a Bug');
1.215 albertel 1480: my $bugicon=&lonhttpdurl("/adm/lonMisc/smallBug.gif");
1.172 www 1481: $template .= <<"ENDTEMPLATE";
1.436 albertel 1482: <a target="_top" href="$link" title="$title"><img src="$bugicon" border="0" alt="(Bug: $topic)" /></a>
1.172 www 1483: ENDTEMPLATE
1484: if ($text ne '') { $template.='</td></tr></table>' };
1485: return $template;
1486:
1487: }
1488:
1489: sub help_open_faq {
1490: my ($topic, $text, $stayOnPage, $width, $height) = @_;
1.258 albertel 1491: unless ($env{'user.adv'}) { return ''; }
1.172 www 1492: unless ($Apache::lonnet::perlvar{'FAQHost'}) { return ''; }
1493: $text = "" if (not defined $text);
1494: $stayOnPage=1;
1495: $width = 350 if (not defined $width);
1496: $height = 400 if (not defined $height);
1497:
1498: $topic=~s/\W+/\+/g;
1499: my $link='';
1500: my $template='';
1501: my $url=$Apache::lonnet::perlvar{'FAQHost'}.'/fom/cache/'.$topic.'.html';
1502: if (!$stayOnPage)
1503: {
1504: $link = "javascript:void(open('$url', 'FAQ-O-Matic', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))";
1505: }
1506: else
1507: {
1508: $link = $url;
1509: }
1510:
1511: # Add the text
1512: if ($text ne "")
1513: {
1514: $template .=
1.173 www 1515: "<table bgcolor='#337733' cellspacing='1' cellpadding='1' border='0'><tr>".
1.705 tempelho 1516: "<td bgcolor='#448844'><a target=\"_top\" href=\"$link\"><span style=\"color:#FFFFFF; font-size:10pt;\">$text</span></a>";
1.172 www 1517: }
1518:
1519: # Add the graphic
1.179 matthew 1520: my $title = &mt('View the FAQ');
1.215 albertel 1521: my $faqicon=&lonhttpdurl("/adm/lonMisc/smallFAQ.gif");
1.172 www 1522: $template .= <<"ENDTEMPLATE";
1.436 albertel 1523: <a target="_top" href="$link" title="$title"><img src="$faqicon" border="0" alt="(FAQ: $topic)" /></a>
1.172 www 1524: ENDTEMPLATE
1525: if ($text ne '') { $template.='</td></tr></table>' };
1526: return $template;
1527:
1.44 bowersj2 1528: }
1.37 matthew 1529:
1.180 matthew 1530: ###############################################################
1531: ###############################################################
1532:
1.45 matthew 1533: =pod
1534:
1.648 raeburn 1535: =item * &change_content_javascript():
1.256 matthew 1536:
1537: This and the next function allow you to create small sections of an
1538: otherwise static HTML page that you can update on the fly with
1539: Javascript, even in Netscape 4.
1540:
1541: The Javascript fragment returned by this function (no E<lt>scriptE<gt> tag)
1542: must be written to the HTML page once. It will prove the Javascript
1543: function "change(name, content)". Calling the change function with the
1544: name of the section
1545: you want to update, matching the name passed to C<changable_area>, and
1546: the new content you want to put in there, will put the content into
1547: that area.
1548:
1549: B<Note>: Netscape 4 only reserves enough space for the changable area
1550: to contain room for the original contents. You need to "make space"
1551: for whatever changes you wish to make, and be B<sure> to check your
1552: code in Netscape 4. This feature in Netscape 4 is B<not> powerful;
1553: it's adequate for updating a one-line status display, but little more.
1554: This script will set the space to 100% width, so you only need to
1555: worry about height in Netscape 4.
1556:
1557: Modern browsers are much less limiting, and if you can commit to the
1558: user not using Netscape 4, this feature may be used freely with
1559: pretty much any HTML.
1560:
1561: =cut
1562:
1563: sub change_content_javascript {
1564: # If we're on Netscape 4, we need to use Layer-based code
1.258 albertel 1565: if ($env{'browser.type'} eq 'netscape' &&
1566: $env{'browser.version'} =~ /^4\./) {
1.256 matthew 1567: return (<<NETSCAPE4);
1568: function change(name, content) {
1569: doc = document.layers[name+"___escape"].layers[0].document;
1570: doc.open();
1571: doc.write(content);
1572: doc.close();
1573: }
1574: NETSCAPE4
1575: } else {
1576: # Otherwise, we need to use semi-standards-compliant code
1577: # (technically, "innerHTML" isn't standard but the equivalent
1578: # is really scary, and every useful browser supports it
1579: return (<<DOMBASED);
1580: function change(name, content) {
1581: element = document.getElementById(name);
1582: element.innerHTML = content;
1583: }
1584: DOMBASED
1585: }
1586: }
1587:
1588: =pod
1589:
1.648 raeburn 1590: =item * &changable_area($name,$origContent):
1.256 matthew 1591:
1592: This provides a "changable area" that can be modified on the fly via
1593: the Javascript code provided in C<change_content_javascript>. $name is
1594: the name you will use to reference the area later; do not repeat the
1595: same name on a given HTML page more then once. $origContent is what
1596: the area will originally contain, which can be left blank.
1597:
1598: =cut
1599:
1600: sub changable_area {
1601: my ($name, $origContent) = @_;
1602:
1.258 albertel 1603: if ($env{'browser.type'} eq 'netscape' &&
1604: $env{'browser.version'} =~ /^4\./) {
1.256 matthew 1605: # If this is netscape 4, we need to use the Layer tag
1606: return "<ilayer width='100%' id='${name}___escape' overflow='none'><layer width='100%' id='$name' overflow='none'>$origContent</layer></ilayer>";
1607: } else {
1608: return "<span id='$name'>$origContent</span>";
1609: }
1610: }
1611:
1612: =pod
1613:
1.648 raeburn 1614: =item * &viewport_geometry_js
1.590 raeburn 1615:
1616: Provides javascript object (Geometry) which can provide information about the viewport geometry for the client browser.
1617:
1618: =cut
1619:
1620:
1621: sub viewport_geometry_js {
1622: return <<"GEOMETRY";
1623: var Geometry = {};
1624: function init_geometry() {
1625: if (Geometry.init) { return };
1626: Geometry.init=1;
1627: if (window.innerHeight) {
1628: Geometry.getViewportHeight = function() { return window.innerHeight; };
1629: Geometry.getViewportWidth = function() { return window.innerWidth; };
1630: Geometry.getHorizontalScroll = function() { return window.pageXOffset; };
1631: Geometry.getVerticalScroll = function() { return window.pageYOffset; };
1632: }
1633: else if (document.documentElement && document.documentElement.clientHeight) {
1634: Geometry.getViewportHeight =
1635: function() { return document.documentElement.clientHeight; };
1636: Geometry.getViewportWidth =
1637: function() { return document.documentElement.clientWidth; };
1638:
1639: Geometry.getHorizontalScroll =
1640: function() { return document.documentElement.scrollLeft; };
1641: Geometry.getVerticalScroll =
1642: function() { return document.documentElement.scrollTop; };
1643: }
1644: else if (document.body.clientHeight) {
1645: Geometry.getViewportHeight =
1646: function() { return document.body.clientHeight; };
1647: Geometry.getViewportWidth =
1648: function() { return document.body.clientWidth; };
1649: Geometry.getHorizontalScroll =
1650: function() { return document.body.scrollLeft; };
1651: Geometry.getVerticalScroll =
1652: function() { return document.body.scrollTop; };
1653: }
1654: }
1655:
1656: GEOMETRY
1657: }
1658:
1659: =pod
1660:
1.648 raeburn 1661: =item * &viewport_size_js()
1.590 raeburn 1662:
1663: 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.
1664:
1665: =cut
1666:
1667: sub viewport_size_js {
1668: my $geometry = &viewport_geometry_js();
1669: return <<"DIMS";
1670:
1671: $geometry
1672:
1673: function getViewportDims(width,height) {
1674: init_geometry();
1675: width.value = Geometry.getViewportWidth();
1676: height.value = Geometry.getViewportHeight();
1677: return;
1678: }
1679:
1680: DIMS
1681: }
1682:
1683: =pod
1684:
1.648 raeburn 1685: =item * &resize_textarea_js()
1.565 albertel 1686:
1687: emits the needed javascript to resize a textarea to be as big as possible
1688:
1689: creates a function resize_textrea that takes two IDs first should be
1690: the id of the element to resize, second should be the id of a div that
1691: surrounds everything that comes after the textarea, this routine needs
1692: to be attached to the <body> for the onload and onresize events.
1693:
1.648 raeburn 1694: =back
1.565 albertel 1695:
1696: =cut
1697:
1698: sub resize_textarea_js {
1.590 raeburn 1699: my $geometry = &viewport_geometry_js();
1.565 albertel 1700: return <<"RESIZE";
1701: <script type="text/javascript">
1.824 bisitz 1702: // <![CDATA[
1.590 raeburn 1703: $geometry
1.565 albertel 1704:
1.588 albertel 1705: function getX(element) {
1706: var x = 0;
1707: while (element) {
1708: x += element.offsetLeft;
1709: element = element.offsetParent;
1710: }
1711: return x;
1712: }
1713: function getY(element) {
1714: var y = 0;
1715: while (element) {
1716: y += element.offsetTop;
1717: element = element.offsetParent;
1718: }
1719: return y;
1720: }
1721:
1722:
1.565 albertel 1723: function resize_textarea(textarea_id,bottom_id) {
1724: init_geometry();
1725: var textarea = document.getElementById(textarea_id);
1726: //alert(textarea);
1727:
1.588 albertel 1728: var textarea_top = getY(textarea);
1.565 albertel 1729: var textarea_height = textarea.offsetHeight;
1730: var bottom = document.getElementById(bottom_id);
1.588 albertel 1731: var bottom_top = getY(bottom);
1.565 albertel 1732: var bottom_height = bottom.offsetHeight;
1733: var window_height = Geometry.getViewportHeight();
1.588 albertel 1734: var fudge = 23;
1.565 albertel 1735: var new_height = window_height-fudge-textarea_top-bottom_height;
1736: if (new_height < 300) {
1737: new_height = 300;
1738: }
1739: textarea.style.height=new_height+'px';
1740: }
1.824 bisitz 1741: // ]]>
1.565 albertel 1742: </script>
1743: RESIZE
1744:
1745: }
1746:
1.1075.2.112 raeburn 1747: sub colorfuleditor_js {
1748: return <<"COLORFULEDIT"
1749: <script type="text/javascript">
1750: // <![CDATA[>
1751: function fold_box(curDepth, lastresource){
1752:
1753: // we need a list because there can be several blocks you need to fold in one tag
1754: var block = document.getElementsByName('foldblock_'+curDepth);
1755: // but there is only one folding button per tag
1756: var foldbutton = document.getElementById('folding_btn_'+curDepth);
1757:
1758: if(block.item(0).style.display == 'none'){
1759:
1760: foldbutton.value = '@{[&mt("Hide")]}';
1761: for (i = 0; i < block.length; i++){
1762: block.item(i).style.display = '';
1763: }
1764: }else{
1765:
1766: foldbutton.value = '@{[&mt("Show")]}';
1767: for (i = 0; i < block.length; i++){
1768: // block.item(i).style.visibility = 'collapse';
1769: block.item(i).style.display = 'none';
1770: }
1771: };
1772: saveState(lastresource);
1773: }
1774:
1775: function saveState (lastresource) {
1776:
1777: var tag_list = getTagList();
1778: if(tag_list != null){
1779: var timestamp = new Date().getTime();
1780: var key = lastresource;
1781:
1782: // the value pattern is: 'time;key1,value1;key2,value2; ... '
1783: // starting with timestamp
1784: var value = timestamp+';';
1785:
1786: // building the list of key-value pairs
1787: for(var i = 0; i < tag_list.length; i++){
1788: value += tag_list[i]+',';
1789: value += document.getElementsByName(tag_list[i])[0].style.display+';';
1790: }
1791:
1792: // only iterate whole storage if nothing to override
1793: if(localStorage.getItem(key) == null){
1794:
1795: // prevent storage from growing large
1796: if(localStorage.length > 50){
1797: var regex_getTimestamp = /^(?:\d)+;/;
1798: var oldest_timestamp = regex_getTimestamp.exec(localStorage.key(0));
1799: var oldest_key;
1800:
1801: for(var i = 1; i < localStorage.length; i++){
1802: if (regex_getTimestamp.exec(localStorage.key(i)) < oldest_timestamp) {
1803: oldest_key = localStorage.key(i);
1804: oldest_timestamp = regex_getTimestamp.exec(oldest_key);
1805: }
1806: }
1807: localStorage.removeItem(oldest_key);
1808: }
1809: }
1810: localStorage.setItem(key,value);
1811: }
1812: }
1813:
1814: // restore folding status of blocks (on page load)
1815: function restoreState (lastresource) {
1816: if(localStorage.getItem(lastresource) != null){
1817: var key = lastresource;
1818: var value = localStorage.getItem(key);
1819: var regex_delTimestamp = /^\d+;/;
1820:
1821: value.replace(regex_delTimestamp, '');
1822:
1823: var valueArr = value.split(';');
1824: var pairs;
1825: var elements;
1826: for (var i = 0; i < valueArr.length; i++){
1827: pairs = valueArr[i].split(',');
1828: elements = document.getElementsByName(pairs[0]);
1829:
1830: for (var j = 0; j < elements.length; j++){
1831: elements[j].style.display = pairs[1];
1832: if (pairs[1] == "none"){
1833: var regex_id = /([_\\d]+)\$/;
1834: regex_id.exec(pairs[0]);
1835: document.getElementById("folding_btn"+RegExp.\$1).value = "Show";
1836: }
1837: }
1838: }
1839: }
1840: }
1841:
1842: function getTagList () {
1843:
1844: var stringToSearch = document.lonhomework.innerHTML;
1845:
1846: var ret = new Array();
1847: var regex_findBlock = /(foldblock_.*?)"/g;
1848: var tag_list = stringToSearch.match(regex_findBlock);
1849:
1850: if(tag_list != null){
1851: for(var i = 0; i < tag_list.length; i++){
1852: ret.push(tag_list[i].replace(/"/, ''));
1853: }
1854: }
1855: return ret;
1856: }
1857:
1858: function saveScrollPosition (resource) {
1859: var tag_list = getTagList();
1860:
1861: // we dont always want to jump to the first block
1862: // 170 is roughly above the "Problem Editing" header. we just want to save if the user scrolled down further than this
1863: if(\$(window).scrollTop() > 170){
1864: if(tag_list != null){
1865: var result;
1866: for(var i = 0; i < tag_list.length; i++){
1867: if(isElementInViewport(tag_list[i])){
1868: result += tag_list[i]+';';
1869: }
1870: }
1871: sessionStorage.setItem('anchor_'+resource, result);
1872: }
1873: } else {
1874: // we dont need to save zero, just delete the item to leave everything tidy
1875: sessionStorage.removeItem('anchor_'+resource);
1876: }
1877: }
1878:
1879: function restoreScrollPosition(resource){
1880:
1881: var elem = sessionStorage.getItem('anchor_'+resource);
1882: if(elem != null){
1883: var tag_list = elem.split(';');
1884: var elem_list;
1885:
1886: for(var i = 0; i < tag_list.length; i++){
1887: elem_list = document.getElementsByName(tag_list[i]);
1888:
1889: if(elem_list.length > 0){
1890: elem = elem_list[0];
1891: break;
1892: }
1893: }
1894: elem.scrollIntoView();
1895: }
1896: }
1897:
1898: function isElementInViewport(el) {
1899:
1900: // change to last element instead of first
1901: var elem = document.getElementsByName(el);
1902: var rect = elem[0].getBoundingClientRect();
1903:
1904: return (
1905: rect.top >= 0 &&
1906: rect.left >= 0 &&
1907: rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */
1908: rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */
1909: );
1910: }
1911:
1912: function autosize(depth){
1913: var cmInst = window['cm'+depth];
1914: var fitsizeButton = document.getElementById('fitsize'+depth);
1915:
1916: // is fixed size, switching to dynamic
1917: if (sessionStorage.getItem("autosized_"+depth) == null) {
1918: cmInst.setSize("","auto");
1919: fitsizeButton.value = "@{[&mt('Fixed size')]}";
1920: sessionStorage.setItem("autosized_"+depth, "yes");
1921:
1922: // is dynamic size, switching to fixed
1923: } else {
1924: cmInst.setSize("","300px");
1925: fitsizeButton.value = "@{[&mt('Dynamic size')]}";
1926: sessionStorage.removeItem("autosized_"+depth);
1927: }
1928: }
1929:
1930:
1931:
1932: // ]]>
1933: </script>
1934: COLORFULEDIT
1935: }
1936:
1937: sub xmleditor_js {
1938: return <<XMLEDIT
1939: <script type="text/javascript" src="/adm/jQuery/addons/jquery-scrolltofixed.js"></script>
1940: <script type="text/javascript">
1941: // <![CDATA[>
1942:
1943: function saveScrollPosition (resource) {
1944:
1945: var scrollPos = \$(window).scrollTop();
1946: sessionStorage.setItem(resource,scrollPos);
1947: }
1948:
1949: function restoreScrollPosition(resource){
1950:
1951: var scrollPos = sessionStorage.getItem(resource);
1952: \$(window).scrollTop(scrollPos);
1953: }
1954:
1955: // unless internet explorer
1956: if (!(window.navigator.appName == "Microsoft Internet Explorer" && (document.documentMode || document.compatMode))){
1957:
1958: \$(document).ready(function() {
1959: \$(".LC_edit_actionbar").scrollToFixed(\{zIndex: 100\});
1960: });
1961: }
1962:
1963: // inserts text at cursor position into codemirror (xml editor only)
1964: function insertText(text){
1965: cm.focus();
1966: var curPos = cm.getCursor();
1967: cm.replaceRange(text.replace(/ESCAPEDSCRIPT/g,'script'), {line: curPos.line,ch: curPos.ch});
1968: }
1969: // ]]>
1970: </script>
1971: XMLEDIT
1972: }
1973:
1974: sub insert_folding_button {
1975: my $curDepth = $Apache::lonxml::curdepth;
1976: my $lastresource = $env{'request.ambiguous'};
1977:
1978: return "<input type=\"button\" id=\"folding_btn_$curDepth\"
1979: value=\"".&mt('Hide')."\" onclick=\"fold_box('$curDepth','$lastresource')\">";
1980: }
1981:
1982:
1.565 albertel 1983: =pod
1984:
1.256 matthew 1985: =head1 Excel and CSV file utility routines
1986:
1987: =cut
1988:
1989: ###############################################################
1990: ###############################################################
1991:
1992: =pod
1993:
1.1075.2.56 raeburn 1994: =over 4
1995:
1.648 raeburn 1996: =item * &csv_translate($text)
1.37 matthew 1997:
1.185 www 1998: Translate $text to allow it to be output as a 'comma separated values'
1.37 matthew 1999: format.
2000:
2001: =cut
2002:
1.180 matthew 2003: ###############################################################
2004: ###############################################################
1.37 matthew 2005: sub csv_translate {
2006: my $text = shift;
2007: $text =~ s/\"/\"\"/g;
1.209 albertel 2008: $text =~ s/\n/ /g;
1.37 matthew 2009: return $text;
2010: }
1.180 matthew 2011:
2012: ###############################################################
2013: ###############################################################
2014:
2015: =pod
2016:
1.648 raeburn 2017: =item * &define_excel_formats()
1.180 matthew 2018:
2019: Define some commonly used Excel cell formats.
2020:
2021: Currently supported formats:
2022:
2023: =over 4
2024:
2025: =item header
2026:
2027: =item bold
2028:
2029: =item h1
2030:
2031: =item h2
2032:
2033: =item h3
2034:
1.256 matthew 2035: =item h4
2036:
2037: =item i
2038:
1.180 matthew 2039: =item date
2040:
2041: =back
2042:
2043: Inputs: $workbook
2044:
2045: Returns: $format, a hash reference.
2046:
1.1057 foxr 2047:
1.180 matthew 2048: =cut
2049:
2050: ###############################################################
2051: ###############################################################
2052: sub define_excel_formats {
2053: my ($workbook) = @_;
2054: my $format;
2055: $format->{'header'} = $workbook->add_format(bold => 1,
2056: bottom => 1,
2057: align => 'center');
2058: $format->{'bold'} = $workbook->add_format(bold=>1);
2059: $format->{'h1'} = $workbook->add_format(bold=>1, size=>18);
2060: $format->{'h2'} = $workbook->add_format(bold=>1, size=>16);
2061: $format->{'h3'} = $workbook->add_format(bold=>1, size=>14);
1.255 matthew 2062: $format->{'h4'} = $workbook->add_format(bold=>1, size=>12);
1.246 matthew 2063: $format->{'i'} = $workbook->add_format(italic=>1);
1.180 matthew 2064: $format->{'date'} = $workbook->add_format(num_format=>
1.207 matthew 2065: 'mm/dd/yyyy hh:mm:ss');
1.180 matthew 2066: return $format;
2067: }
2068:
2069: ###############################################################
2070: ###############################################################
1.113 bowersj2 2071:
2072: =pod
2073:
1.648 raeburn 2074: =item * &create_workbook()
1.255 matthew 2075:
2076: Create an Excel worksheet. If it fails, output message on the
2077: request object and return undefs.
2078:
2079: Inputs: Apache request object
2080:
2081: Returns (undef) on failure,
2082: Excel worksheet object, scalar with filename, and formats
2083: from &Apache::loncommon::define_excel_formats on success
2084:
2085: =cut
2086:
2087: ###############################################################
2088: ###############################################################
2089: sub create_workbook {
2090: my ($r) = @_;
2091: #
2092: # Create the excel spreadsheet
2093: my $filename = '/prtspool/'.
1.258 albertel 2094: $env{'user.name'}.'_'.$env{'user.domain'}.'_'.
1.255 matthew 2095: time.'_'.rand(1000000000).'.xls';
2096: my $workbook = Spreadsheet::WriteExcel->new('/home/httpd'.$filename);
2097: if (! defined($workbook)) {
2098: $r->log_error("Error creating excel spreadsheet $filename: $!");
1.928 bisitz 2099: $r->print(
2100: '<p class="LC_error">'
2101: .&mt('Problems occurred in creating the new Excel file.')
2102: .' '.&mt('This error has been logged.')
2103: .' '.&mt('Please alert your LON-CAPA administrator.')
2104: .'</p>'
2105: );
1.255 matthew 2106: return (undef);
2107: }
2108: #
1.1014 foxr 2109: $workbook->set_tempdir(LONCAPA::tempdir());
1.255 matthew 2110: #
2111: my $format = &Apache::loncommon::define_excel_formats($workbook);
2112: return ($workbook,$filename,$format);
2113: }
2114:
2115: ###############################################################
2116: ###############################################################
2117:
2118: =pod
2119:
1.648 raeburn 2120: =item * &create_text_file()
1.113 bowersj2 2121:
1.542 raeburn 2122: Create a file to write to and eventually make available to the user.
1.256 matthew 2123: If file creation fails, outputs an error message on the request object and
2124: return undefs.
1.113 bowersj2 2125:
1.256 matthew 2126: Inputs: Apache request object, and file suffix
1.113 bowersj2 2127:
1.256 matthew 2128: Returns (undef) on failure,
2129: Filehandle and filename on success.
1.113 bowersj2 2130:
2131: =cut
2132:
1.256 matthew 2133: ###############################################################
2134: ###############################################################
2135: sub create_text_file {
2136: my ($r,$suffix) = @_;
2137: if (! defined($suffix)) { $suffix = 'txt'; };
2138: my $fh;
2139: my $filename = '/prtspool/'.
1.258 albertel 2140: $env{'user.name'}.'_'.$env{'user.domain'}.'_'.
1.256 matthew 2141: time.'_'.rand(1000000000).'.'.$suffix;
2142: $fh = Apache::File->new('>/home/httpd'.$filename);
2143: if (! defined($fh)) {
2144: $r->log_error("Couldn't open $filename for output $!");
1.928 bisitz 2145: $r->print(
2146: '<p class="LC_error">'
2147: .&mt('Problems occurred in creating the output file.')
2148: .' '.&mt('This error has been logged.')
2149: .' '.&mt('Please alert your LON-CAPA administrator.')
2150: .'</p>'
2151: );
1.113 bowersj2 2152: }
1.256 matthew 2153: return ($fh,$filename)
1.113 bowersj2 2154: }
2155:
2156:
1.256 matthew 2157: =pod
1.113 bowersj2 2158:
2159: =back
2160:
2161: =cut
1.37 matthew 2162:
2163: ###############################################################
1.33 matthew 2164: ## Home server <option> list generating code ##
2165: ###############################################################
1.35 matthew 2166:
1.169 www 2167: # ------------------------------------------
2168:
2169: sub domain_select {
2170: my ($name,$value,$multiple)=@_;
2171: my %domains=map {
1.514 albertel 2172: $_ => $_.' '. &Apache::lonnet::domain($_,'description')
1.512 albertel 2173: } &Apache::lonnet::all_domains();
1.169 www 2174: if ($multiple) {
2175: $domains{''}=&mt('Any domain');
1.550 albertel 2176: $domains{'select_form_order'} = [sort {lc($a) cmp lc($b) } (keys(%domains))];
1.287 albertel 2177: return &multiple_select_form($name,$value,4,\%domains);
1.169 www 2178: } else {
1.550 albertel 2179: $domains{'select_form_order'} = [sort {lc($a) cmp lc($b) } (keys(%domains))];
1.970 raeburn 2180: return &select_form($name,$value,\%domains);
1.169 www 2181: }
2182: }
2183:
1.282 albertel 2184: #-------------------------------------------
2185:
2186: =pod
2187:
1.519 raeburn 2188: =head1 Routines for form select boxes
2189:
2190: =over 4
2191:
1.648 raeburn 2192: =item * &multiple_select_form($name,$value,$size,$hash,$order)
1.282 albertel 2193:
2194: Returns a string containing a <select> element int multiple mode
2195:
2196:
2197: Args:
2198: $name - name of the <select> element
1.506 raeburn 2199: $value - scalar or array ref of values that should already be selected
1.282 albertel 2200: $size - number of rows long the select element is
1.283 albertel 2201: $hash - the elements should be 'option' => 'shown text'
1.282 albertel 2202: (shown text should already have been &mt())
1.506 raeburn 2203: $order - (optional) array ref of the order to show the elements in
1.283 albertel 2204:
1.282 albertel 2205: =cut
2206:
2207: #-------------------------------------------
1.169 www 2208: sub multiple_select_form {
1.284 albertel 2209: my ($name,$value,$size,$hash,$order)=@_;
1.169 www 2210: my %selected = map { $_ => 1 } ref($value)?@{$value}:($value);
2211: my $output='';
1.191 matthew 2212: if (! defined($size)) {
2213: $size = 4;
1.283 albertel 2214: if (scalar(keys(%$hash))<4) {
2215: $size = scalar(keys(%$hash));
1.191 matthew 2216: }
2217: }
1.734 bisitz 2218: $output.="\n".'<select name="'.$name.'" size="'.$size.'" multiple="multiple">';
1.501 banghart 2219: my @order;
1.506 raeburn 2220: if (ref($order) eq 'ARRAY') {
2221: @order = @{$order};
2222: } else {
2223: @order = sort(keys(%$hash));
1.501 banghart 2224: }
2225: if (exists($$hash{'select_form_order'})) {
2226: @order = @{$$hash{'select_form_order'}};
2227: }
2228:
1.284 albertel 2229: foreach my $key (@order) {
1.356 albertel 2230: $output.='<option value="'.&HTML::Entities::encode($key,'"<>&').'" ';
1.284 albertel 2231: $output.='selected="selected" ' if ($selected{$key});
2232: $output.='>'.$hash->{$key}."</option>\n";
1.169 www 2233: }
2234: $output.="</select>\n";
2235: return $output;
2236: }
2237:
1.88 www 2238: #-------------------------------------------
2239:
2240: =pod
2241:
1.1075.2.115! raeburn 2242: =item * &select_form($defdom,$name,$hashref,$onchange,$readonly)
1.88 www 2243:
2244: Returns a string containing a <select name='$name' size='1'> form to
1.970 raeburn 2245: allow a user to select options from a ref to a hash containing:
2246: option_name => displayed text. An optional $onchange can include
1.1075.2.115! raeburn 2247: a javascript onchange item, e.g., onchange="this.form.submit();".
! 2248: An optional arg -- $readonly -- if true will cause the select form
! 2249: to be disabled, e.g., for the case where an instructor has a section-
! 2250: specific role, and is viewing/modifying parameters.
1.970 raeburn 2251:
1.88 www 2252: See lonrights.pm for an example invocation and use.
2253:
2254: =cut
2255:
2256: #-------------------------------------------
2257: sub select_form {
1.1075.2.115! raeburn 2258: my ($def,$name,$hashref,$onchange,$readonly) = @_;
1.970 raeburn 2259: return unless (ref($hashref) eq 'HASH');
2260: if ($onchange) {
2261: $onchange = ' onchange="'.$onchange.'"';
2262: }
2263: my $selectform = "<select name=\"$name\" size=\"1\"$onchange>\n";
1.128 albertel 2264: my @keys;
1.970 raeburn 2265: if (exists($hashref->{'select_form_order'})) {
2266: @keys=@{$hashref->{'select_form_order'}};
1.128 albertel 2267: } else {
1.970 raeburn 2268: @keys=sort(keys(%{$hashref}));
1.128 albertel 2269: }
1.356 albertel 2270: foreach my $key (@keys) {
2271: $selectform.=
2272: '<option value="'.&HTML::Entities::encode($key,'"<>&').'" '.
2273: ($key eq $def ? 'selected="selected" ' : '').
1.970 raeburn 2274: ">".$hashref->{$key}."</option>\n";
1.88 www 2275: }
2276: $selectform.="</select>";
2277: return $selectform;
2278: }
2279:
1.475 www 2280: # For display filters
2281:
2282: sub display_filter {
1.1074 raeburn 2283: my ($context) = @_;
1.475 www 2284: if (!$env{'form.show'}) { $env{'form.show'}=10; }
1.477 www 2285: if (!$env{'form.displayfilter'}) { $env{'form.displayfilter'}='currentfolder'; }
1.1074 raeburn 2286: my $phraseinput = 'hidden';
2287: my $includeinput = 'hidden';
2288: my ($checked,$includetypestext);
2289: if ($env{'form.displayfilter'} eq 'containing') {
2290: $phraseinput = 'text';
2291: if ($context eq 'parmslog') {
2292: $includeinput = 'checkbox';
2293: if ($env{'form.includetypes'}) {
2294: $checked = ' checked="checked"';
2295: }
2296: $includetypestext = &mt('Include parameter types');
2297: }
2298: } else {
2299: $includetypestext = ' ';
2300: }
2301: my ($additional,$secondid,$thirdid);
2302: if ($context eq 'parmslog') {
2303: $additional =
2304: '<label><input type="'.$includeinput.'" name="includetypes"'.
2305: $checked.' name="includetypes" value="1" id="includetypes" />'.
2306: ' <span id="includetypestext">'.$includetypestext.'</span>'.
2307: '</label>';
2308: $secondid = 'includetypes';
2309: $thirdid = 'includetypestext';
2310: }
2311: my $onchange = "javascript:toggleHistoryOptions(this,'containingphrase','$context',
2312: '$secondid','$thirdid')";
2313: return '<span class="LC_nobreak"><label>'.&mt('Records: [_1]',
1.475 www 2314: &Apache::lonmeta::selectbox('show',$env{'form.show'},undef,
2315: (&mt('all'),10,20,50,100,1000,10000))).
1.714 bisitz 2316: '</label></span> <span class="LC_nobreak">'.
1.1074 raeburn 2317: &mt('Filter: [_1]',
1.477 www 2318: &select_form($env{'form.displayfilter'},
2319: 'displayfilter',
1.970 raeburn 2320: {'currentfolder' => 'Current folder/page',
1.477 www 2321: 'containing' => 'Containing phrase',
1.1074 raeburn 2322: 'none' => 'None'},$onchange)).' '.
2323: '<input type="'.$phraseinput.'" name="containingphrase" id="containingphrase" size="30" value="'.
2324: &HTML::Entities::encode($env{'form.containingphrase'}).
2325: '" />'.$additional;
2326: }
2327:
2328: sub display_filter_js {
2329: my $includetext = &mt('Include parameter types');
2330: return <<"ENDJS";
2331:
2332: function toggleHistoryOptions(setter,firstid,context,secondid,thirdid) {
2333: var firstType = 'hidden';
2334: if (setter.options[setter.selectedIndex].value == 'containing') {
2335: firstType = 'text';
2336: }
2337: firstObject = document.getElementById(firstid);
2338: if (typeof(firstObject) == 'object') {
2339: if (firstObject.type != firstType) {
2340: changeInputType(firstObject,firstType);
2341: }
2342: }
2343: if (context == 'parmslog') {
2344: var secondType = 'hidden';
2345: if (firstType == 'text') {
2346: secondType = 'checkbox';
2347: }
2348: secondObject = document.getElementById(secondid);
2349: if (typeof(secondObject) == 'object') {
2350: if (secondObject.type != secondType) {
2351: changeInputType(secondObject,secondType);
2352: }
2353: }
2354: var textItem = document.getElementById(thirdid);
2355: var currtext = textItem.innerHTML;
2356: var newtext;
2357: if (firstType == 'text') {
2358: newtext = '$includetext';
2359: } else {
2360: newtext = ' ';
2361: }
2362: if (currtext != newtext) {
2363: textItem.innerHTML = newtext;
2364: }
2365: }
2366: return;
2367: }
2368:
2369: function changeInputType(oldObject,newType) {
2370: var newObject = document.createElement('input');
2371: newObject.type = newType;
2372: if (oldObject.size) {
2373: newObject.size = oldObject.size;
2374: }
2375: if (oldObject.value) {
2376: newObject.value = oldObject.value;
2377: }
2378: if (oldObject.name) {
2379: newObject.name = oldObject.name;
2380: }
2381: if (oldObject.id) {
2382: newObject.id = oldObject.id;
2383: }
2384: oldObject.parentNode.replaceChild(newObject,oldObject);
2385: return;
2386: }
2387:
2388: ENDJS
1.475 www 2389: }
2390:
1.167 www 2391: sub gradeleveldescription {
2392: my $gradelevel=shift;
2393: my %gradelevels=(0 => 'Not specified',
2394: 1 => 'Grade 1',
2395: 2 => 'Grade 2',
2396: 3 => 'Grade 3',
2397: 4 => 'Grade 4',
2398: 5 => 'Grade 5',
2399: 6 => 'Grade 6',
2400: 7 => 'Grade 7',
2401: 8 => 'Grade 8',
2402: 9 => 'Grade 9',
2403: 10 => 'Grade 10',
2404: 11 => 'Grade 11',
2405: 12 => 'Grade 12',
2406: 13 => 'Grade 13',
2407: 14 => '100 Level',
2408: 15 => '200 Level',
2409: 16 => '300 Level',
2410: 17 => '400 Level',
2411: 18 => 'Graduate Level');
2412: return &mt($gradelevels{$gradelevel});
2413: }
2414:
1.163 www 2415: sub select_level_form {
2416: my ($deflevel,$name)=@_;
2417: unless ($deflevel) { $deflevel=0; }
1.167 www 2418: my $selectform = "<select name=\"$name\" size=\"1\">\n";
2419: for (my $i=0; $i<=18; $i++) {
2420: $selectform.="<option value=\"$i\" ".
1.253 albertel 2421: ($i==$deflevel ? 'selected="selected" ' : '').
1.167 www 2422: ">".&gradeleveldescription($i)."</option>\n";
2423: }
2424: $selectform.="</select>";
2425: return $selectform;
1.163 www 2426: }
1.167 www 2427:
1.35 matthew 2428: #-------------------------------------------
2429:
1.45 matthew 2430: =pod
2431:
1.1075.2.115! raeburn 2432: =item * &select_dom_form($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms,$excdoms,$disabled)
1.35 matthew 2433:
2434: Returns a string containing a <select name='$name' size='1'> form to
2435: allow a user to select the domain to preform an operation in.
2436: See loncreateuser.pm for an example invocation and use.
2437:
1.90 www 2438: If the $includeempty flag is set, it also includes an empty choice ("no domain
2439: selected");
2440:
1.743 raeburn 2441: If the $showdomdesc flag is set, the domain name is followed by the domain description.
2442:
1.910 raeburn 2443: 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.
2444:
1.1075.2.36 raeburn 2445: The optional $incdoms is a reference to an array of domains which will be the only available options.
2446:
1.1075.2.115! raeburn 2447: The optional $excdoms is a reference to an array of domains which will be excluded from the available options.
! 2448:
! 2449: The optional $disabled argument, if true, adds the disabled attribute to the select tag.
1.563 raeburn 2450:
1.35 matthew 2451: =cut
2452:
2453: #-------------------------------------------
1.34 matthew 2454: sub select_dom_form {
1.1075.2.115! raeburn 2455: my ($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms,$excdoms,$disabled) = @_;
1.872 raeburn 2456: if ($onchange) {
1.874 raeburn 2457: $onchange = ' onchange="'.$onchange.'"';
1.743 raeburn 2458: }
1.1075.2.115! raeburn 2459: if ($disabled) {
! 2460: $disabled = ' disabled="disabled"';
! 2461: }
1.1075.2.36 raeburn 2462: my (@domains,%exclude);
1.910 raeburn 2463: if (ref($incdoms) eq 'ARRAY') {
2464: @domains = sort {lc($a) cmp lc($b)} (@{$incdoms});
2465: } else {
2466: @domains = sort {lc($a) cmp lc($b)} (&Apache::lonnet::all_domains());
2467: }
1.90 www 2468: if ($includeempty) { @domains=('',@domains); }
1.1075.2.36 raeburn 2469: if (ref($excdoms) eq 'ARRAY') {
2470: map { $exclude{$_} = 1; } @{$excdoms};
2471: }
1.1075.2.115! raeburn 2472: my $selectdomain = "<select name=\"$name\" size=\"1\"$onchange$disabled>\n";
1.356 albertel 2473: foreach my $dom (@domains) {
1.1075.2.36 raeburn 2474: next if ($exclude{$dom});
1.356 albertel 2475: $selectdomain.="<option value=\"$dom\" ".
1.563 raeburn 2476: ($dom eq $defdom ? 'selected="selected" ' : '').'>'.$dom;
2477: if ($showdomdesc) {
2478: if ($dom ne '') {
2479: my $domdesc = &Apache::lonnet::domain($dom,'description');
2480: if ($domdesc ne '') {
2481: $selectdomain .= ' ('.$domdesc.')';
2482: }
2483: }
2484: }
2485: $selectdomain .= "</option>\n";
1.34 matthew 2486: }
2487: $selectdomain.="</select>";
2488: return $selectdomain;
2489: }
2490:
1.35 matthew 2491: #-------------------------------------------
2492:
1.45 matthew 2493: =pod
2494:
1.648 raeburn 2495: =item * &home_server_form_item($domain,$name,$defaultflag)
1.35 matthew 2496:
1.586 raeburn 2497: input: 4 arguments (two required, two optional) -
2498: $domain - domain of new user
2499: $name - name of form element
2500: $default - Value of 'default' causes a default item to be first
2501: option, and selected by default.
2502: $hide - Value of 'hide' causes hiding of the name of the server,
2503: if 1 server found, or default, if 0 found.
1.594 raeburn 2504: output: returns 2 items:
1.586 raeburn 2505: (a) form element which contains either:
2506: (i) <select name="$name">
2507: <option value="$hostid1">$hostid $servers{$hostid}</option>
2508: <option value="$hostid2">$hostid $servers{$hostid}</option>
2509: </select>
2510: form item if there are multiple library servers in $domain, or
2511: (ii) an <input type="hidden" name="$name" value="$hostid" /> form item
2512: if there is only one library server in $domain.
2513:
2514: (b) number of library servers found.
2515:
2516: See loncreateuser.pm for example of use.
1.35 matthew 2517:
2518: =cut
2519:
2520: #-------------------------------------------
1.586 raeburn 2521: sub home_server_form_item {
2522: my ($domain,$name,$default,$hide) = @_;
1.513 albertel 2523: my %servers = &Apache::lonnet::get_servers($domain,'library');
1.586 raeburn 2524: my $result;
2525: my $numlib = keys(%servers);
2526: if ($numlib > 1) {
2527: $result .= '<select name="'.$name.'" />'."\n";
2528: if ($default) {
1.804 bisitz 2529: $result .= '<option value="default" selected="selected">'.&mt('default').
1.586 raeburn 2530: '</option>'."\n";
2531: }
2532: foreach my $hostid (sort(keys(%servers))) {
2533: $result.= '<option value="'.$hostid.'">'.
2534: $hostid.' '.$servers{$hostid}."</option>\n";
2535: }
2536: $result .= '</select>'."\n";
2537: } elsif ($numlib == 1) {
2538: my $hostid;
2539: foreach my $item (keys(%servers)) {
2540: $hostid = $item;
2541: }
2542: $result .= '<input type="hidden" name="'.$name.'" value="'.
2543: $hostid.'" />';
2544: if (!$hide) {
2545: $result .= $hostid.' '.$servers{$hostid};
2546: }
2547: $result .= "\n";
2548: } elsif ($default) {
2549: $result .= '<input type="hidden" name="'.$name.
2550: '" value="default" />';
2551: if (!$hide) {
2552: $result .= &mt('default');
2553: }
2554: $result .= "\n";
1.33 matthew 2555: }
1.586 raeburn 2556: return ($result,$numlib);
1.33 matthew 2557: }
1.112 bowersj2 2558:
2559: =pod
2560:
1.534 albertel 2561: =back
2562:
1.112 bowersj2 2563: =cut
1.87 matthew 2564:
2565: ###############################################################
1.112 bowersj2 2566: ## Decoding User Agent ##
1.87 matthew 2567: ###############################################################
2568:
2569: =pod
2570:
1.112 bowersj2 2571: =head1 Decoding the User Agent
2572:
2573: =over 4
2574:
2575: =item * &decode_user_agent()
1.87 matthew 2576:
2577: Inputs: $r
2578:
2579: Outputs:
2580:
2581: =over 4
2582:
1.112 bowersj2 2583: =item * $httpbrowser
1.87 matthew 2584:
1.112 bowersj2 2585: =item * $clientbrowser
1.87 matthew 2586:
1.112 bowersj2 2587: =item * $clientversion
1.87 matthew 2588:
1.112 bowersj2 2589: =item * $clientmathml
1.87 matthew 2590:
1.112 bowersj2 2591: =item * $clientunicode
1.87 matthew 2592:
1.112 bowersj2 2593: =item * $clientos
1.87 matthew 2594:
1.1075.2.42 raeburn 2595: =item * $clientmobile
2596:
2597: =item * $clientinfo
2598:
1.1075.2.77 raeburn 2599: =item * $clientosversion
2600:
1.87 matthew 2601: =back
2602:
1.157 matthew 2603: =back
2604:
1.87 matthew 2605: =cut
2606:
2607: ###############################################################
2608: ###############################################################
2609: sub decode_user_agent {
1.247 albertel 2610: my ($r)=@_;
1.87 matthew 2611: my @browsertype=split(/\&/,$Apache::lonnet::perlvar{"lonBrowsDet"});
2612: my %mathcap=split(/\&/,$$Apache::lonnet::perlvar{"lonMathML"});
2613: my $httpbrowser=$ENV{"HTTP_USER_AGENT"};
1.247 albertel 2614: if (!$httpbrowser && $r) { $httpbrowser=$r->header_in('User-Agent'); }
1.87 matthew 2615: my $clientbrowser='unknown';
2616: my $clientversion='0';
2617: my $clientmathml='';
2618: my $clientunicode='0';
1.1075.2.42 raeburn 2619: my $clientmobile=0;
1.1075.2.77 raeburn 2620: my $clientosversion='';
1.87 matthew 2621: for (my $i=0;$i<=$#browsertype;$i++) {
1.1075.2.76 raeburn 2622: my ($bname,$match,$notmatch,$vreg,$minv,$univ)=split(/\%/,$browsertype[$i]);
1.87 matthew 2623: if (($httpbrowser=~/$match/i) && ($httpbrowser!~/$notmatch/i)) {
2624: $clientbrowser=$bname;
2625: $httpbrowser=~/$vreg/i;
2626: $clientversion=$1;
2627: $clientmathml=($clientversion>=$minv);
2628: $clientunicode=($clientversion>=$univ);
2629: }
2630: }
2631: my $clientos='unknown';
1.1075.2.42 raeburn 2632: my $clientinfo;
1.87 matthew 2633: if (($httpbrowser=~/linux/i) ||
2634: ($httpbrowser=~/unix/i) ||
2635: ($httpbrowser=~/ux/i) ||
2636: ($httpbrowser=~/solaris/i)) { $clientos='unix'; }
2637: if (($httpbrowser=~/vax/i) ||
2638: ($httpbrowser=~/vms/i)) { $clientos='vms'; }
2639: if ($httpbrowser=~/next/i) { $clientos='next'; }
2640: if (($httpbrowser=~/mac/i) ||
2641: ($httpbrowser=~/powerpc/i)) { $clientos='mac'; }
1.1075.2.77 raeburn 2642: if ($httpbrowser=~/win/i) {
2643: $clientos='win';
2644: if ($httpbrowser =~/Windows\s+NT\s+(\d+\.\d+)/i) {
2645: $clientosversion = $1;
2646: }
2647: }
1.87 matthew 2648: if ($httpbrowser=~/embed/i) { $clientos='pda'; }
1.1075.2.42 raeburn 2649: if ($httpbrowser=~/(Android|iPod|iPad|iPhone|webOS|Blackberry|Windows Phone|Opera m(?:ob|in)|Fennec)/i) {
2650: $clientmobile=lc($1);
2651: }
2652: if ($httpbrowser=~ m{Firefox/(\d+\.\d+)}) {
2653: $clientinfo = 'firefox-'.$1;
2654: } elsif ($httpbrowser=~ m{chromeframe/(\d+\.\d+)\.}) {
2655: $clientinfo = 'chromeframe-'.$1;
2656: }
1.87 matthew 2657: return ($httpbrowser,$clientbrowser,$clientversion,$clientmathml,
1.1075.2.77 raeburn 2658: $clientunicode,$clientos,$clientmobile,$clientinfo,
2659: $clientosversion);
1.87 matthew 2660: }
2661:
1.32 matthew 2662: ###############################################################
2663: ## Authentication changing form generation subroutines ##
2664: ###############################################################
2665: ##
2666: ## All of the authform_xxxxxxx subroutines take their inputs in a
2667: ## hash, and have reasonable default values.
2668: ##
2669: ## formname = the name given in the <form> tag.
1.35 matthew 2670: #-------------------------------------------
2671:
1.45 matthew 2672: =pod
2673:
1.112 bowersj2 2674: =head1 Authentication Routines
2675:
2676: =over 4
2677:
1.648 raeburn 2678: =item * &authform_xxxxxx()
1.35 matthew 2679:
2680: The authform_xxxxxx subroutines provide javascript and html forms which
2681: handle some of the conveniences required for authentication forms.
2682: This is not an optimal method, but it works.
2683:
2684: =over 4
2685:
1.112 bowersj2 2686: =item * authform_header
1.35 matthew 2687:
1.112 bowersj2 2688: =item * authform_authorwarning
1.35 matthew 2689:
1.112 bowersj2 2690: =item * authform_nochange
1.35 matthew 2691:
1.112 bowersj2 2692: =item * authform_kerberos
1.35 matthew 2693:
1.112 bowersj2 2694: =item * authform_internal
1.35 matthew 2695:
1.112 bowersj2 2696: =item * authform_filesystem
1.35 matthew 2697:
2698: =back
2699:
1.648 raeburn 2700: See loncreateuser.pm for invocation and use examples.
1.157 matthew 2701:
1.35 matthew 2702: =cut
2703:
2704: #-------------------------------------------
1.32 matthew 2705: sub authform_header{
2706: my %in = (
2707: formname => 'cu',
1.80 albertel 2708: kerb_def_dom => '',
1.32 matthew 2709: @_,
2710: );
2711: $in{'formname'} = 'document.' . $in{'formname'};
2712: my $result='';
1.80 albertel 2713:
2714: #---------------------------------------------- Code for upper case translation
2715: my $Javascript_toUpperCase;
2716: unless ($in{kerb_def_dom}) {
2717: $Javascript_toUpperCase =<<"END";
2718: switch (choice) {
2719: case 'krb': currentform.elements[choicearg].value =
2720: currentform.elements[choicearg].value.toUpperCase();
2721: break;
2722: default:
2723: }
2724: END
2725: } else {
2726: $Javascript_toUpperCase = "";
2727: }
2728:
1.165 raeburn 2729: my $radioval = "'nochange'";
1.591 raeburn 2730: if (defined($in{'curr_authtype'})) {
2731: if ($in{'curr_authtype'} ne '') {
2732: $radioval = "'".$in{'curr_authtype'}."arg'";
2733: }
1.174 matthew 2734: }
1.165 raeburn 2735: my $argfield = 'null';
1.591 raeburn 2736: if (defined($in{'mode'})) {
1.165 raeburn 2737: if ($in{'mode'} eq 'modifycourse') {
1.591 raeburn 2738: if (defined($in{'curr_autharg'})) {
2739: if ($in{'curr_autharg'} ne '') {
1.165 raeburn 2740: $argfield = "'$in{'curr_autharg'}'";
2741: }
2742: }
2743: }
2744: }
2745:
1.32 matthew 2746: $result.=<<"END";
2747: var current = new Object();
1.165 raeburn 2748: current.radiovalue = $radioval;
2749: current.argfield = $argfield;
1.32 matthew 2750:
2751: function changed_radio(choice,currentform) {
2752: var choicearg = choice + 'arg';
2753: // If a radio button in changed, we need to change the argfield
2754: if (current.radiovalue != choice) {
2755: current.radiovalue = choice;
2756: if (current.argfield != null) {
2757: currentform.elements[current.argfield].value = '';
2758: }
2759: if (choice == 'nochange') {
2760: current.argfield = null;
2761: } else {
2762: current.argfield = choicearg;
2763: switch(choice) {
2764: case 'krb':
2765: currentform.elements[current.argfield].value =
2766: "$in{'kerb_def_dom'}";
2767: break;
2768: default:
2769: break;
2770: }
2771: }
2772: }
2773: return;
2774: }
1.22 www 2775:
1.32 matthew 2776: function changed_text(choice,currentform) {
2777: var choicearg = choice + 'arg';
2778: if (currentform.elements[choicearg].value !='') {
1.80 albertel 2779: $Javascript_toUpperCase
1.32 matthew 2780: // clear old field
2781: if ((current.argfield != choicearg) && (current.argfield != null)) {
2782: currentform.elements[current.argfield].value = '';
2783: }
2784: current.argfield = choicearg;
2785: }
2786: set_auth_radio_buttons(choice,currentform);
2787: return;
1.20 www 2788: }
1.32 matthew 2789:
2790: function set_auth_radio_buttons(newvalue,currentform) {
1.986 raeburn 2791: var numauthchoices = currentform.login.length;
2792: if (typeof numauthchoices == "undefined") {
2793: return;
2794: }
1.32 matthew 2795: var i=0;
1.986 raeburn 2796: while (i < numauthchoices) {
1.32 matthew 2797: if (currentform.login[i].value == newvalue) { break; }
2798: i++;
2799: }
1.986 raeburn 2800: if (i == numauthchoices) {
1.32 matthew 2801: return;
2802: }
2803: current.radiovalue = newvalue;
2804: currentform.login[i].checked = true;
2805: return;
2806: }
2807: END
2808: return $result;
2809: }
2810:
1.1075.2.20 raeburn 2811: sub authform_authorwarning {
1.32 matthew 2812: my $result='';
1.144 matthew 2813: $result='<i>'.
2814: &mt('As a general rule, only authors or co-authors should be '.
2815: 'filesystem authenticated '.
2816: '(which allows access to the server filesystem).')."</i>\n";
1.32 matthew 2817: return $result;
2818: }
2819:
1.1075.2.20 raeburn 2820: sub authform_nochange {
1.32 matthew 2821: my %in = (
2822: formname => 'document.cu',
2823: kerb_def_dom => 'MSU.EDU',
2824: @_,
2825: );
1.1075.2.20 raeburn 2826: my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
1.586 raeburn 2827: my $result;
1.1075.2.20 raeburn 2828: if (!$authnum) {
2829: $result = &mt('Under your current role you are not permitted to change login settings for this user');
1.586 raeburn 2830: } else {
2831: $result = '<label>'.&mt('[_1] Do not change login data',
2832: '<input type="radio" name="login" value="nochange" '.
2833: 'checked="checked" onclick="'.
1.281 albertel 2834: "javascript:changed_radio('nochange',$in{'formname'});".'" />').
2835: '</label>';
1.586 raeburn 2836: }
1.32 matthew 2837: return $result;
2838: }
2839:
1.591 raeburn 2840: sub authform_kerberos {
1.32 matthew 2841: my %in = (
2842: formname => 'document.cu',
2843: kerb_def_dom => 'MSU.EDU',
1.80 albertel 2844: kerb_def_auth => 'krb4',
1.32 matthew 2845: @_,
2846: );
1.586 raeburn 2847: my ($check4,$check5,$krbcheck,$krbarg,$krbver,$result,$authtype,
2848: $autharg,$jscall);
1.1075.2.20 raeburn 2849: my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
1.80 albertel 2850: if ($in{'kerb_def_auth'} eq 'krb5') {
1.772 bisitz 2851: $check5 = ' checked="checked"';
1.80 albertel 2852: } else {
1.772 bisitz 2853: $check4 = ' checked="checked"';
1.80 albertel 2854: }
1.165 raeburn 2855: $krbarg = $in{'kerb_def_dom'};
1.591 raeburn 2856: if (defined($in{'curr_authtype'})) {
2857: if ($in{'curr_authtype'} eq 'krb') {
1.772 bisitz 2858: $krbcheck = ' checked="checked"';
1.623 raeburn 2859: if (defined($in{'mode'})) {
2860: if ($in{'mode'} eq 'modifyuser') {
2861: $krbcheck = '';
2862: }
2863: }
1.591 raeburn 2864: if (defined($in{'curr_kerb_ver'})) {
2865: if ($in{'curr_krb_ver'} eq '5') {
1.772 bisitz 2866: $check5 = ' checked="checked"';
1.591 raeburn 2867: $check4 = '';
2868: } else {
1.772 bisitz 2869: $check4 = ' checked="checked"';
1.591 raeburn 2870: $check5 = '';
2871: }
1.586 raeburn 2872: }
1.591 raeburn 2873: if (defined($in{'curr_autharg'})) {
1.165 raeburn 2874: $krbarg = $in{'curr_autharg'};
2875: }
1.586 raeburn 2876: if (!$can_assign{'krb4'} && !$can_assign{'krb5'}) {
1.591 raeburn 2877: if (defined($in{'curr_autharg'})) {
1.586 raeburn 2878: $result =
2879: &mt('Currently Kerberos authenticated with domain [_1] Version [_2].',
2880: $in{'curr_autharg'},$krbver);
2881: } else {
2882: $result =
2883: &mt('Currently Kerberos authenticated, Version [_1].',$krbver);
2884: }
2885: return $result;
2886: }
2887: }
2888: } else {
2889: if ($authnum == 1) {
1.784 bisitz 2890: $authtype = '<input type="hidden" name="login" value="krb" />';
1.165 raeburn 2891: }
2892: }
1.586 raeburn 2893: if (!$can_assign{'krb4'} && !$can_assign{'krb5'}) {
2894: return;
1.587 raeburn 2895: } elsif ($authtype eq '') {
1.591 raeburn 2896: if (defined($in{'mode'})) {
1.587 raeburn 2897: if ($in{'mode'} eq 'modifycourse') {
2898: if ($authnum == 1) {
1.1075.2.20 raeburn 2899: $authtype = '<input type="radio" name="login" value="krb" />';
1.587 raeburn 2900: }
2901: }
2902: }
1.586 raeburn 2903: }
2904: $jscall = "javascript:changed_radio('krb',$in{'formname'});";
2905: if ($authtype eq '') {
2906: $authtype = '<input type="radio" name="login" value="krb" '.
2907: 'onclick="'.$jscall.'" onchange="'.$jscall.'"'.
2908: $krbcheck.' />';
2909: }
2910: if (($can_assign{'krb4'} && $can_assign{'krb5'}) ||
1.1075.2.20 raeburn 2911: ($can_assign{'krb4'} && !$can_assign{'krb5'} &&
1.586 raeburn 2912: $in{'curr_authtype'} eq 'krb5') ||
1.1075.2.20 raeburn 2913: (!$can_assign{'krb4'} && $can_assign{'krb5'} &&
1.586 raeburn 2914: $in{'curr_authtype'} eq 'krb4')) {
2915: $result .= &mt
1.144 matthew 2916: ('[_1] Kerberos authenticated with domain [_2] '.
1.281 albertel 2917: '[_3] Version 4 [_4] Version 5 [_5]',
1.586 raeburn 2918: '<label>'.$authtype,
1.281 albertel 2919: '</label><input type="text" size="10" name="krbarg" '.
1.165 raeburn 2920: 'value="'.$krbarg.'" '.
1.144 matthew 2921: 'onchange="'.$jscall.'" />',
1.281 albertel 2922: '<label><input type="radio" name="krbver" value="4" '.$check4.' />',
2923: '</label><label><input type="radio" name="krbver" value="5" '.$check5.' />',
2924: '</label>');
1.586 raeburn 2925: } elsif ($can_assign{'krb4'}) {
2926: $result .= &mt
2927: ('[_1] Kerberos authenticated with domain [_2] '.
2928: '[_3] Version 4 [_4]',
2929: '<label>'.$authtype,
2930: '</label><input type="text" size="10" name="krbarg" '.
2931: 'value="'.$krbarg.'" '.
2932: 'onchange="'.$jscall.'" />',
2933: '<label><input type="hidden" name="krbver" value="4" />',
2934: '</label>');
2935: } elsif ($can_assign{'krb5'}) {
2936: $result .= &mt
2937: ('[_1] Kerberos authenticated with domain [_2] '.
2938: '[_3] Version 5 [_4]',
2939: '<label>'.$authtype,
2940: '</label><input type="text" size="10" name="krbarg" '.
2941: 'value="'.$krbarg.'" '.
2942: 'onchange="'.$jscall.'" />',
2943: '<label><input type="hidden" name="krbver" value="5" />',
2944: '</label>');
2945: }
1.32 matthew 2946: return $result;
2947: }
2948:
1.1075.2.20 raeburn 2949: sub authform_internal {
1.586 raeburn 2950: my %in = (
1.32 matthew 2951: formname => 'document.cu',
2952: kerb_def_dom => 'MSU.EDU',
2953: @_,
2954: );
1.586 raeburn 2955: my ($intcheck,$intarg,$result,$authtype,$autharg,$jscall);
1.1075.2.20 raeburn 2956: my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
1.591 raeburn 2957: if (defined($in{'curr_authtype'})) {
2958: if ($in{'curr_authtype'} eq 'int') {
1.586 raeburn 2959: if ($can_assign{'int'}) {
1.772 bisitz 2960: $intcheck = 'checked="checked" ';
1.623 raeburn 2961: if (defined($in{'mode'})) {
2962: if ($in{'mode'} eq 'modifyuser') {
2963: $intcheck = '';
2964: }
2965: }
1.591 raeburn 2966: if (defined($in{'curr_autharg'})) {
1.586 raeburn 2967: $intarg = $in{'curr_autharg'};
2968: }
2969: } else {
2970: $result = &mt('Currently internally authenticated.');
2971: return $result;
1.165 raeburn 2972: }
2973: }
1.586 raeburn 2974: } else {
2975: if ($authnum == 1) {
1.784 bisitz 2976: $authtype = '<input type="hidden" name="login" value="int" />';
1.586 raeburn 2977: }
2978: }
2979: if (!$can_assign{'int'}) {
2980: return;
1.587 raeburn 2981: } elsif ($authtype eq '') {
1.591 raeburn 2982: if (defined($in{'mode'})) {
1.587 raeburn 2983: if ($in{'mode'} eq 'modifycourse') {
2984: if ($authnum == 1) {
1.1075.2.20 raeburn 2985: $authtype = '<input type="radio" name="login" value="int" />';
1.587 raeburn 2986: }
2987: }
2988: }
1.165 raeburn 2989: }
1.586 raeburn 2990: $jscall = "javascript:changed_radio('int',$in{'formname'});";
2991: if ($authtype eq '') {
2992: $authtype = '<input type="radio" name="login" value="int" '.$intcheck.
2993: ' onchange="'.$jscall.'" onclick="'.$jscall.'" />';
2994: }
1.605 bisitz 2995: $autharg = '<input type="password" size="10" name="intarg" value="'.
1.586 raeburn 2996: $intarg.'" onchange="'.$jscall.'" />';
2997: $result = &mt
1.144 matthew 2998: ('[_1] Internally authenticated (with initial password [_2])',
1.586 raeburn 2999: '<label>'.$authtype,'</label>'.$autharg);
1.824 bisitz 3000: $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 3001: return $result;
3002: }
3003:
1.1075.2.20 raeburn 3004: sub authform_local {
1.32 matthew 3005: my %in = (
3006: formname => 'document.cu',
3007: kerb_def_dom => 'MSU.EDU',
3008: @_,
3009: );
1.586 raeburn 3010: my ($loccheck,$locarg,$result,$authtype,$autharg,$jscall);
1.1075.2.20 raeburn 3011: my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
1.591 raeburn 3012: if (defined($in{'curr_authtype'})) {
3013: if ($in{'curr_authtype'} eq 'loc') {
1.586 raeburn 3014: if ($can_assign{'loc'}) {
1.772 bisitz 3015: $loccheck = 'checked="checked" ';
1.623 raeburn 3016: if (defined($in{'mode'})) {
3017: if ($in{'mode'} eq 'modifyuser') {
3018: $loccheck = '';
3019: }
3020: }
1.591 raeburn 3021: if (defined($in{'curr_autharg'})) {
1.586 raeburn 3022: $locarg = $in{'curr_autharg'};
3023: }
3024: } else {
3025: $result = &mt('Currently using local (institutional) authentication.');
3026: return $result;
1.165 raeburn 3027: }
3028: }
1.586 raeburn 3029: } else {
3030: if ($authnum == 1) {
1.784 bisitz 3031: $authtype = '<input type="hidden" name="login" value="loc" />';
1.586 raeburn 3032: }
3033: }
3034: if (!$can_assign{'loc'}) {
3035: return;
1.587 raeburn 3036: } elsif ($authtype eq '') {
1.591 raeburn 3037: if (defined($in{'mode'})) {
1.587 raeburn 3038: if ($in{'mode'} eq 'modifycourse') {
3039: if ($authnum == 1) {
1.1075.2.20 raeburn 3040: $authtype = '<input type="radio" name="login" value="loc" />';
1.587 raeburn 3041: }
3042: }
3043: }
1.165 raeburn 3044: }
1.586 raeburn 3045: $jscall = "javascript:changed_radio('loc',$in{'formname'});";
3046: if ($authtype eq '') {
3047: $authtype = '<input type="radio" name="login" value="loc" '.
3048: $loccheck.' onchange="'.$jscall.'" onclick="'.
3049: $jscall.'" />';
3050: }
3051: $autharg = '<input type="text" size="10" name="locarg" value="'.
3052: $locarg.'" onchange="'.$jscall.'" />';
3053: $result = &mt('[_1] Local Authentication with argument [_2]',
3054: '<label>'.$authtype,'</label>'.$autharg);
1.32 matthew 3055: return $result;
3056: }
3057:
1.1075.2.20 raeburn 3058: sub authform_filesystem {
1.32 matthew 3059: my %in = (
3060: formname => 'document.cu',
3061: kerb_def_dom => 'MSU.EDU',
3062: @_,
3063: );
1.586 raeburn 3064: my ($fsyscheck,$result,$authtype,$autharg,$jscall);
1.1075.2.20 raeburn 3065: my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
1.591 raeburn 3066: if (defined($in{'curr_authtype'})) {
3067: if ($in{'curr_authtype'} eq 'fsys') {
1.586 raeburn 3068: if ($can_assign{'fsys'}) {
1.772 bisitz 3069: $fsyscheck = 'checked="checked" ';
1.623 raeburn 3070: if (defined($in{'mode'})) {
3071: if ($in{'mode'} eq 'modifyuser') {
3072: $fsyscheck = '';
3073: }
3074: }
1.586 raeburn 3075: } else {
3076: $result = &mt('Currently Filesystem Authenticated.');
3077: return $result;
3078: }
3079: }
3080: } else {
3081: if ($authnum == 1) {
1.784 bisitz 3082: $authtype = '<input type="hidden" name="login" value="fsys" />';
1.586 raeburn 3083: }
3084: }
3085: if (!$can_assign{'fsys'}) {
3086: return;
1.587 raeburn 3087: } elsif ($authtype eq '') {
1.591 raeburn 3088: if (defined($in{'mode'})) {
1.587 raeburn 3089: if ($in{'mode'} eq 'modifycourse') {
3090: if ($authnum == 1) {
1.1075.2.20 raeburn 3091: $authtype = '<input type="radio" name="login" value="fsys" />';
1.587 raeburn 3092: }
3093: }
3094: }
1.586 raeburn 3095: }
3096: $jscall = "javascript:changed_radio('fsys',$in{'formname'});";
3097: if ($authtype eq '') {
3098: $authtype = '<input type="radio" name="login" value="fsys" '.
3099: $fsyscheck.' onchange="'.$jscall.'" onclick="'.
3100: $jscall.'" />';
3101: }
3102: $autharg = '<input type="text" size="10" name="fsysarg" value=""'.
3103: ' onchange="'.$jscall.'" />';
3104: $result = &mt
1.144 matthew 3105: ('[_1] Filesystem Authenticated (with initial password [_2])',
1.281 albertel 3106: '<label><input type="radio" name="login" value="fsys" '.
1.586 raeburn 3107: $fsyscheck.'onchange="'.$jscall.'" onclick="'.$jscall.'" />',
1.605 bisitz 3108: '</label><input type="password" size="10" name="fsysarg" value="" '.
1.144 matthew 3109: 'onchange="'.$jscall.'" />');
1.32 matthew 3110: return $result;
3111: }
3112:
1.586 raeburn 3113: sub get_assignable_auth {
3114: my ($dom) = @_;
3115: if ($dom eq '') {
3116: $dom = $env{'request.role.domain'};
3117: }
3118: my %can_assign = (
3119: krb4 => 1,
3120: krb5 => 1,
3121: int => 1,
3122: loc => 1,
3123: );
3124: my %domconfig = &Apache::lonnet::get_dom('configuration',['usercreation'],$dom);
3125: if (ref($domconfig{'usercreation'}) eq 'HASH') {
3126: if (ref($domconfig{'usercreation'}{'authtypes'}) eq 'HASH') {
3127: my $authhash = $domconfig{'usercreation'}{'authtypes'};
3128: my $context;
3129: if ($env{'request.role'} =~ /^au/) {
3130: $context = 'author';
3131: } elsif ($env{'request.role'} =~ /^dc/) {
3132: $context = 'domain';
3133: } elsif ($env{'request.course.id'}) {
3134: $context = 'course';
3135: }
3136: if ($context) {
3137: if (ref($authhash->{$context}) eq 'HASH') {
3138: %can_assign = %{$authhash->{$context}};
3139: }
3140: }
3141: }
3142: }
3143: my $authnum = 0;
3144: foreach my $key (keys(%can_assign)) {
3145: if ($can_assign{$key}) {
3146: $authnum ++;
3147: }
3148: }
3149: if ($can_assign{'krb4'} && $can_assign{'krb5'}) {
3150: $authnum --;
3151: }
3152: return ($authnum,%can_assign);
3153: }
3154:
1.80 albertel 3155: ###############################################################
3156: ## Get Kerberos Defaults for Domain ##
3157: ###############################################################
3158: ##
3159: ## Returns default kerberos version and an associated argument
3160: ## as listed in file domain.tab. If not listed, provides
3161: ## appropriate default domain and kerberos version.
3162: ##
3163: #-------------------------------------------
3164:
3165: =pod
3166:
1.648 raeburn 3167: =item * &get_kerberos_defaults()
1.80 albertel 3168:
3169: get_kerberos_defaults($target_domain) returns the default kerberos
1.641 raeburn 3170: version and domain. If not found, it defaults to version 4 and the
3171: domain of the server.
1.80 albertel 3172:
1.648 raeburn 3173: =over 4
3174:
1.80 albertel 3175: ($def_version, $def_krb_domain) = &get_kerberos_defaults($target_domain);
3176:
1.648 raeburn 3177: =back
3178:
3179: =back
3180:
1.80 albertel 3181: =cut
3182:
3183: #-------------------------------------------
3184: sub get_kerberos_defaults {
3185: my $domain=shift;
1.641 raeburn 3186: my ($krbdef,$krbdefdom);
3187: my %domdefaults = &Apache::lonnet::get_domain_defaults($domain);
3188: if (($domdefaults{'auth_def'} =~/^krb(4|5)$/) && ($domdefaults{'auth_arg_def'} ne '')) {
3189: $krbdef = $domdefaults{'auth_def'};
3190: $krbdefdom = $domdefaults{'auth_arg_def'};
3191: } else {
1.80 albertel 3192: $ENV{'SERVER_NAME'}=~/(\w+\.\w+)$/;
3193: my $krbdefdom=$1;
3194: $krbdefdom=~tr/a-z/A-Z/;
3195: $krbdef = "krb4";
3196: }
3197: return ($krbdef,$krbdefdom);
3198: }
1.112 bowersj2 3199:
1.32 matthew 3200:
1.46 matthew 3201: ###############################################################
3202: ## Thesaurus Functions ##
3203: ###############################################################
1.20 www 3204:
1.46 matthew 3205: =pod
1.20 www 3206:
1.112 bowersj2 3207: =head1 Thesaurus Functions
3208:
3209: =over 4
3210:
1.648 raeburn 3211: =item * &initialize_keywords()
1.46 matthew 3212:
3213: Initializes the package variable %Keywords if it is empty. Uses the
3214: package variable $thesaurus_db_file.
3215:
3216: =cut
3217:
3218: ###################################################
3219:
3220: sub initialize_keywords {
3221: return 1 if (scalar keys(%Keywords));
3222: # If we are here, %Keywords is empty, so fill it up
3223: # Make sure the file we need exists...
3224: if (! -e $thesaurus_db_file) {
3225: &Apache::lonnet::logthis("Attempt to access $thesaurus_db_file".
3226: " failed because it does not exist");
3227: return 0;
3228: }
3229: # Set up the hash as a database
3230: my %thesaurus_db;
3231: if (! tie(%thesaurus_db,'GDBM_File',
1.53 albertel 3232: $thesaurus_db_file,&GDBM_READER(),0640)){
1.46 matthew 3233: &Apache::lonnet::logthis("Could not tie \%thesaurus_db to ".
3234: $thesaurus_db_file);
3235: return 0;
3236: }
3237: # Get the average number of appearances of a word.
3238: my $avecount = $thesaurus_db{'average.count'};
3239: # Put keywords (those that appear > average) into %Keywords
3240: while (my ($word,$data)=each (%thesaurus_db)) {
3241: my ($count,undef) = split /:/,$data;
3242: $Keywords{$word}++ if ($count > $avecount);
3243: }
3244: untie %thesaurus_db;
3245: # Remove special values from %Keywords.
1.356 albertel 3246: foreach my $value ('total.count','average.count') {
3247: delete($Keywords{$value}) if (exists($Keywords{$value}));
1.586 raeburn 3248: }
1.46 matthew 3249: return 1;
3250: }
3251:
3252: ###################################################
3253:
3254: =pod
3255:
1.648 raeburn 3256: =item * &keyword($word)
1.46 matthew 3257:
3258: Returns true if $word is a keyword. A keyword is a word that appears more
3259: than the average number of times in the thesaurus database. Calls
3260: &initialize_keywords
3261:
3262: =cut
3263:
3264: ###################################################
1.20 www 3265:
3266: sub keyword {
1.46 matthew 3267: return if (!&initialize_keywords());
3268: my $word=lc(shift());
3269: $word=~s/\W//g;
3270: return exists($Keywords{$word});
1.20 www 3271: }
1.46 matthew 3272:
3273: ###############################################################
3274:
3275: =pod
1.20 www 3276:
1.648 raeburn 3277: =item * &get_related_words()
1.46 matthew 3278:
1.160 matthew 3279: Look up a word in the thesaurus. Takes a scalar argument and returns
1.46 matthew 3280: an array of words. If the keyword is not in the thesaurus, an empty array
3281: will be returned. The order of the words returned is determined by the
3282: database which holds them.
3283:
3284: Uses global $thesaurus_db_file.
3285:
1.1057 foxr 3286:
1.46 matthew 3287: =cut
3288:
3289: ###############################################################
3290: sub get_related_words {
3291: my $keyword = shift;
3292: my %thesaurus_db;
3293: if (! -e $thesaurus_db_file) {
3294: &Apache::lonnet::logthis("Attempt to access $thesaurus_db_file ".
3295: "failed because the file does not exist");
3296: return ();
3297: }
3298: if (! tie(%thesaurus_db,'GDBM_File',
1.53 albertel 3299: $thesaurus_db_file,&GDBM_READER(),0640)){
1.46 matthew 3300: return ();
3301: }
3302: my @Words=();
1.429 www 3303: my $count=0;
1.46 matthew 3304: if (exists($thesaurus_db{$keyword})) {
1.356 albertel 3305: # The first element is the number of times
3306: # the word appears. We do not need it now.
1.429 www 3307: my (undef,@RelatedWords) = (split(/:/,$thesaurus_db{$keyword}));
3308: my (undef,$mostfrequentcount)=split(/\,/,$RelatedWords[0]);
3309: my $threshold=$mostfrequentcount/10;
3310: foreach my $possibleword (@RelatedWords) {
3311: my ($word,$wordcount)=split(/\,/,$possibleword);
3312: if ($wordcount>$threshold) {
3313: push(@Words,$word);
3314: $count++;
3315: if ($count>10) { last; }
3316: }
1.20 www 3317: }
3318: }
1.46 matthew 3319: untie %thesaurus_db;
3320: return @Words;
1.14 harris41 3321: }
1.46 matthew 3322:
1.112 bowersj2 3323: =pod
3324:
3325: =back
3326:
3327: =cut
1.61 www 3328:
3329: # -------------------------------------------------------------- Plaintext name
1.81 albertel 3330: =pod
3331:
1.112 bowersj2 3332: =head1 User Name Functions
3333:
3334: =over 4
3335:
1.648 raeburn 3336: =item * &plainname($uname,$udom,$first)
1.81 albertel 3337:
1.112 bowersj2 3338: Takes a users logon name and returns it as a string in
1.226 albertel 3339: "first middle last generation" form
3340: if $first is set to 'lastname' then it returns it as
3341: 'lastname generation, firstname middlename' if their is a lastname
1.81 albertel 3342:
3343: =cut
1.61 www 3344:
1.295 www 3345:
1.81 albertel 3346: ###############################################################
1.61 www 3347: sub plainname {
1.226 albertel 3348: my ($uname,$udom,$first)=@_;
1.537 albertel 3349: return if (!defined($uname) || !defined($udom));
1.295 www 3350: my %names=&getnames($uname,$udom);
1.226 albertel 3351: my $name=&Apache::lonnet::format_name($names{'firstname'},
3352: $names{'middlename'},
3353: $names{'lastname'},
3354: $names{'generation'},$first);
3355: $name=~s/^\s+//;
1.62 www 3356: $name=~s/\s+$//;
3357: $name=~s/\s+/ /g;
1.353 albertel 3358: if ($name !~ /\S/) { $name=$uname.':'.$udom; }
1.62 www 3359: return $name;
1.61 www 3360: }
1.66 www 3361:
3362: # -------------------------------------------------------------------- Nickname
1.81 albertel 3363: =pod
3364:
1.648 raeburn 3365: =item * &nickname($uname,$udom)
1.81 albertel 3366:
3367: Gets a users name and returns it as a string as
3368:
3369: ""nickname""
1.66 www 3370:
1.81 albertel 3371: if the user has a nickname or
3372:
3373: "first middle last generation"
3374:
3375: if the user does not
3376:
3377: =cut
1.66 www 3378:
3379: sub nickname {
3380: my ($uname,$udom)=@_;
1.537 albertel 3381: return if (!defined($uname) || !defined($udom));
1.295 www 3382: my %names=&getnames($uname,$udom);
1.68 albertel 3383: my $name=$names{'nickname'};
1.66 www 3384: if ($name) {
3385: $name='"'.$name.'"';
3386: } else {
3387: $name=$names{'firstname'}.' '.$names{'middlename'}.' '.
3388: $names{'lastname'}.' '.$names{'generation'};
3389: $name=~s/\s+$//;
3390: $name=~s/\s+/ /g;
3391: }
3392: return $name;
3393: }
3394:
1.295 www 3395: sub getnames {
3396: my ($uname,$udom)=@_;
1.537 albertel 3397: return if (!defined($uname) || !defined($udom));
1.433 albertel 3398: if ($udom eq 'public' && $uname eq 'public') {
3399: return ('lastname' => &mt('Public'));
3400: }
1.295 www 3401: my $id=$uname.':'.$udom;
3402: my ($names,$cached)=&Apache::lonnet::is_cached_new('namescache',$id);
3403: if ($cached) {
3404: return %{$names};
3405: } else {
3406: my %loadnames=&Apache::lonnet::get('environment',
3407: ['firstname','middlename','lastname','generation','nickname'],
3408: $udom,$uname);
3409: &Apache::lonnet::do_cache_new('namescache',$id,\%loadnames);
3410: return %loadnames;
3411: }
3412: }
1.61 www 3413:
1.542 raeburn 3414: # -------------------------------------------------------------------- getemails
1.648 raeburn 3415:
1.542 raeburn 3416: =pod
3417:
1.648 raeburn 3418: =item * &getemails($uname,$udom)
1.542 raeburn 3419:
3420: Gets a user's email information and returns it as a hash with keys:
3421: notification, critnotification, permanentemail
3422:
3423: For notification and critnotification, values are comma-separated lists
1.648 raeburn 3424: of e-mail addresses; for permanentemail, value is a single e-mail address.
1.542 raeburn 3425:
1.648 raeburn 3426:
1.542 raeburn 3427: =cut
3428:
1.648 raeburn 3429:
1.466 albertel 3430: sub getemails {
3431: my ($uname,$udom)=@_;
3432: if ($udom eq 'public' && $uname eq 'public') {
3433: return;
3434: }
1.467 www 3435: if (!$udom) { $udom=$env{'user.domain'}; }
3436: if (!$uname) { $uname=$env{'user.name'}; }
1.466 albertel 3437: my $id=$uname.':'.$udom;
3438: my ($names,$cached)=&Apache::lonnet::is_cached_new('emailscache',$id);
3439: if ($cached) {
3440: return %{$names};
3441: } else {
3442: my %loadnames=&Apache::lonnet::get('environment',
3443: ['notification','critnotification',
3444: 'permanentemail'],
3445: $udom,$uname);
3446: &Apache::lonnet::do_cache_new('emailscache',$id,\%loadnames);
3447: return %loadnames;
3448: }
3449: }
3450:
1.551 albertel 3451: sub flush_email_cache {
3452: my ($uname,$udom)=@_;
3453: if (!$udom) { $udom =$env{'user.domain'}; }
3454: if (!$uname) { $uname=$env{'user.name'}; }
3455: return if ($udom eq 'public' && $uname eq 'public');
3456: my $id=$uname.':'.$udom;
3457: &Apache::lonnet::devalidate_cache_new('emailscache',$id);
3458: }
3459:
1.728 raeburn 3460: # -------------------------------------------------------------------- getlangs
3461:
3462: =pod
3463:
3464: =item * &getlangs($uname,$udom)
3465:
3466: Gets a user's language preference and returns it as a hash with key:
3467: language.
3468:
3469: =cut
3470:
3471:
3472: sub getlangs {
3473: my ($uname,$udom) = @_;
3474: if (!$udom) { $udom =$env{'user.domain'}; }
3475: if (!$uname) { $uname=$env{'user.name'}; }
3476: my $id=$uname.':'.$udom;
3477: my ($langs,$cached)=&Apache::lonnet::is_cached_new('userlangs',$id);
3478: if ($cached) {
3479: return %{$langs};
3480: } else {
3481: my %loadlangs=&Apache::lonnet::get('environment',['languages'],
3482: $udom,$uname);
3483: &Apache::lonnet::do_cache_new('userlangs',$id,\%loadlangs);
3484: return %loadlangs;
3485: }
3486: }
3487:
3488: sub flush_langs_cache {
3489: my ($uname,$udom)=@_;
3490: if (!$udom) { $udom =$env{'user.domain'}; }
3491: if (!$uname) { $uname=$env{'user.name'}; }
3492: return if ($udom eq 'public' && $uname eq 'public');
3493: my $id=$uname.':'.$udom;
3494: &Apache::lonnet::devalidate_cache_new('userlangs',$id);
3495: }
3496:
1.61 www 3497: # ------------------------------------------------------------------ Screenname
1.81 albertel 3498:
3499: =pod
3500:
1.648 raeburn 3501: =item * &screenname($uname,$udom)
1.81 albertel 3502:
3503: Gets a users screenname and returns it as a string
3504:
3505: =cut
1.61 www 3506:
3507: sub screenname {
3508: my ($uname,$udom)=@_;
1.258 albertel 3509: if ($uname eq $env{'user.name'} &&
3510: $udom eq $env{'user.domain'}) {return $env{'environment.screenname'};}
1.212 albertel 3511: my %names=&Apache::lonnet::get('environment',['screenname'],$udom,$uname);
1.68 albertel 3512: return $names{'screenname'};
1.62 www 3513: }
3514:
1.212 albertel 3515:
1.802 bisitz 3516: # ------------------------------------------------------------- Confirm Wrapper
3517: =pod
3518:
1.1075.2.42 raeburn 3519: =item * &confirmwrapper($message)
1.802 bisitz 3520:
3521: Wrap messages about completion of operation in box
3522:
3523: =cut
3524:
3525: sub confirmwrapper {
3526: my ($message)=@_;
3527: if ($message) {
3528: return "\n".'<div class="LC_confirm_box">'."\n"
3529: .$message."\n"
3530: .'</div>'."\n";
3531: } else {
3532: return $message;
3533: }
3534: }
3535:
1.62 www 3536: # ------------------------------------------------------------- Message Wrapper
3537:
3538: sub messagewrapper {
1.369 www 3539: my ($link,$username,$domain,$subject,$text)=@_;
1.62 www 3540: return
1.441 albertel 3541: '<a href="/adm/email?compose=individual&'.
3542: 'recname='.$username.'&recdom='.$domain.
3543: '&subject='.&escape($subject).'&text='.&escape($text).'" '.
1.200 matthew 3544: 'title="'.&mt('Send message').'">'.$link.'</a>';
1.74 www 3545: }
1.802 bisitz 3546:
1.74 www 3547: # --------------------------------------------------------------- Notes Wrapper
3548:
3549: sub noteswrapper {
3550: my ($link,$un,$do)=@_;
3551: return
1.896 amueller 3552: "<a href='/adm/email?recordftf=retrieve&recname=$un&recdom=$do'>$link</a>";
1.62 www 3553: }
1.802 bisitz 3554:
1.62 www 3555: # ------------------------------------------------------------- Aboutme Wrapper
3556:
3557: sub aboutmewrapper {
1.1070 raeburn 3558: my ($link,$username,$domain,$target,$class)=@_;
1.447 raeburn 3559: if (!defined($username) && !defined($domain)) {
3560: return;
3561: }
1.1075.2.15 raeburn 3562: return '<a href="/adm/'.$domain.'/'.$username.'/aboutme"'.
1.1070 raeburn 3563: ($target?' target="'.$target.'"':'').($class?' class="'.$class.'"':'').' title="'.&mt("View this user's personal information page").'">'.$link.'</a>';
1.62 www 3564: }
3565:
3566: # ------------------------------------------------------------ Syllabus Wrapper
3567:
3568: sub syllabuswrapper {
1.707 bisitz 3569: my ($linktext,$coursedir,$domain)=@_;
1.208 matthew 3570: return qq{<a href="/public/$domain/$coursedir/syllabus">$linktext</a>};
1.61 www 3571: }
1.14 harris41 3572:
1.802 bisitz 3573: # -----------------------------------------------------------------------------
3574:
1.208 matthew 3575: sub track_student_link {
1.887 raeburn 3576: my ($linktext,$sname,$sdom,$target,$start,$only_body) = @_;
1.268 albertel 3577: my $link ="/adm/trackstudent?";
1.208 matthew 3578: my $title = 'View recent activity';
3579: if (defined($sname) && $sname !~ /^\s*$/ &&
3580: defined($sdom) && $sdom !~ /^\s*$/) {
1.268 albertel 3581: $link .= "selected_student=$sname:$sdom";
1.208 matthew 3582: $title .= ' of this student';
1.268 albertel 3583: }
1.208 matthew 3584: if (defined($target) && $target !~ /^\s*$/) {
3585: $target = qq{target="$target"};
3586: } else {
3587: $target = '';
3588: }
1.268 albertel 3589: if ($start) { $link.='&start='.$start; }
1.887 raeburn 3590: if ($only_body) { $link .= '&only_body=1'; }
1.554 albertel 3591: $title = &mt($title);
3592: $linktext = &mt($linktext);
1.448 albertel 3593: return qq{<a href="$link" title="$title" $target>$linktext</a>}.
3594: &help_open_topic('View_recent_activity');
1.208 matthew 3595: }
3596:
1.781 raeburn 3597: sub slot_reservations_link {
3598: my ($linktext,$sname,$sdom,$target) = @_;
3599: my $link ="/adm/slotrequest?command=showresv&origin=aboutme";
3600: my $title = 'View slot reservation history';
3601: if (defined($sname) && $sname !~ /^\s*$/ &&
3602: defined($sdom) && $sdom !~ /^\s*$/) {
3603: $link .= "&uname=$sname&udom=$sdom";
3604: $title .= ' of this student';
3605: }
3606: if (defined($target) && $target !~ /^\s*$/) {
3607: $target = qq{target="$target"};
3608: } else {
3609: $target = '';
3610: }
3611: $title = &mt($title);
3612: $linktext = &mt($linktext);
3613: return qq{<a href="$link" title="$title" $target>$linktext</a>};
3614: # FIXME uncomment when help item created: &help_open_topic('Slot_Reservation_History');
3615:
3616: }
3617:
1.508 www 3618: # ===================================================== Display a student photo
3619:
3620:
1.509 albertel 3621: sub student_image_tag {
1.508 www 3622: my ($domain,$user)=@_;
3623: my $imgsrc=&Apache::lonnet::studentphoto($domain,$user,'jpg');
3624: if (($imgsrc) && ($imgsrc ne '/adm/lonKaputt/lonlogo_broken.gif')) {
3625: return '<img src="'.$imgsrc.'" align="right" />';
3626: } else {
3627: return '';
3628: }
3629: }
3630:
1.112 bowersj2 3631: =pod
3632:
3633: =back
3634:
3635: =head1 Access .tab File Data
3636:
3637: =over 4
3638:
1.648 raeburn 3639: =item * &languageids()
1.112 bowersj2 3640:
3641: returns list of all language ids
3642:
3643: =cut
3644:
1.14 harris41 3645: sub languageids {
1.16 harris41 3646: return sort(keys(%language));
1.14 harris41 3647: }
3648:
1.112 bowersj2 3649: =pod
3650:
1.648 raeburn 3651: =item * &languagedescription()
1.112 bowersj2 3652:
3653: returns description of a specified language id
3654:
3655: =cut
3656:
1.14 harris41 3657: sub languagedescription {
1.125 www 3658: my $code=shift;
3659: return ($supported_language{$code}?'* ':'').
3660: $language{$code}.
1.126 www 3661: ($supported_language{$code}?' ('.&mt('interface available').')':'');
1.145 www 3662: }
3663:
1.1048 foxr 3664: =pod
3665:
3666: =item * &plainlanguagedescription
3667:
3668: Returns both the plain language description (e.g. 'Creoles and Pidgins, English-based (Other)')
3669: and the language character encoding (e.g. ISO) separated by a ' - ' string.
3670:
3671: =cut
3672:
1.145 www 3673: sub plainlanguagedescription {
3674: my $code=shift;
3675: return $language{$code};
3676: }
3677:
1.1048 foxr 3678: =pod
3679:
3680: =item * &supportedlanguagecode
3681:
3682: Returns the supported language code (e.g. sptutf maps to pt) given a language
3683: code.
3684:
3685: =cut
3686:
1.145 www 3687: sub supportedlanguagecode {
3688: my $code=shift;
3689: return $supported_language{$code};
1.97 www 3690: }
3691:
1.112 bowersj2 3692: =pod
3693:
1.1048 foxr 3694: =item * &latexlanguage()
3695:
3696: Given a language key code returns the correspondnig language to use
3697: to select the correct hyphenation on LaTeX printouts. This is undef if there
3698: is no supported hyphenation for the language code.
3699:
3700: =cut
3701:
3702: sub latexlanguage {
3703: my $code = shift;
3704: return $latex_language{$code};
3705: }
3706:
3707: =pod
3708:
3709: =item * &latexhyphenation()
3710:
3711: Same as above but what's supplied is the language as it might be stored
3712: in the metadata.
3713:
3714: =cut
3715:
3716: sub latexhyphenation {
3717: my $key = shift;
3718: return $latex_language_bykey{$key};
3719: }
3720:
3721: =pod
3722:
1.648 raeburn 3723: =item * ©rightids()
1.112 bowersj2 3724:
3725: returns list of all copyrights
3726:
3727: =cut
3728:
3729: sub copyrightids {
3730: return sort(keys(%cprtag));
3731: }
3732:
3733: =pod
3734:
1.648 raeburn 3735: =item * ©rightdescription()
1.112 bowersj2 3736:
3737: returns description of a specified copyright id
3738:
3739: =cut
3740:
3741: sub copyrightdescription {
1.166 www 3742: return &mt($cprtag{shift(@_)});
1.112 bowersj2 3743: }
1.197 matthew 3744:
3745: =pod
3746:
1.648 raeburn 3747: =item * &source_copyrightids()
1.192 taceyjo1 3748:
3749: returns list of all source copyrights
3750:
3751: =cut
3752:
3753: sub source_copyrightids {
3754: return sort(keys(%scprtag));
3755: }
3756:
3757: =pod
3758:
1.648 raeburn 3759: =item * &source_copyrightdescription()
1.192 taceyjo1 3760:
3761: returns description of a specified source copyright id
3762:
3763: =cut
3764:
3765: sub source_copyrightdescription {
3766: return &mt($scprtag{shift(@_)});
3767: }
1.112 bowersj2 3768:
3769: =pod
3770:
1.648 raeburn 3771: =item * &filecategories()
1.112 bowersj2 3772:
3773: returns list of all file categories
3774:
3775: =cut
3776:
3777: sub filecategories {
3778: return sort(keys(%category_extensions));
3779: }
3780:
3781: =pod
3782:
1.648 raeburn 3783: =item * &filecategorytypes()
1.112 bowersj2 3784:
3785: returns list of file types belonging to a given file
3786: category
3787:
3788: =cut
3789:
3790: sub filecategorytypes {
1.356 albertel 3791: my ($cat) = @_;
3792: return @{$category_extensions{lc($cat)}};
1.112 bowersj2 3793: }
3794:
3795: =pod
3796:
1.648 raeburn 3797: =item * &fileembstyle()
1.112 bowersj2 3798:
3799: returns embedding style for a specified file type
3800:
3801: =cut
3802:
3803: sub fileembstyle {
3804: return $fe{lc(shift(@_))};
1.169 www 3805: }
3806:
1.351 www 3807: sub filemimetype {
3808: return $fm{lc(shift(@_))};
3809: }
3810:
1.169 www 3811:
3812: sub filecategoryselect {
3813: my ($name,$value)=@_;
1.189 matthew 3814: return &select_form($value,$name,
1.970 raeburn 3815: {'' => &mt('Any category'), map { $_,$_ } sort(keys(%category_extensions))});
1.112 bowersj2 3816: }
3817:
3818: =pod
3819:
1.648 raeburn 3820: =item * &filedescription()
1.112 bowersj2 3821:
3822: returns description for a specified file type
3823:
3824: =cut
3825:
3826: sub filedescription {
1.188 matthew 3827: my $file_description = $fd{lc(shift())};
3828: $file_description =~ s:([\[\]]):~$1:g;
3829: return &mt($file_description);
1.112 bowersj2 3830: }
3831:
3832: =pod
3833:
1.648 raeburn 3834: =item * &filedescriptionex()
1.112 bowersj2 3835:
3836: returns description for a specified file type with
3837: extra formatting
3838:
3839: =cut
3840:
3841: sub filedescriptionex {
3842: my $ex=shift;
1.188 matthew 3843: my $file_description = $fd{lc($ex)};
3844: $file_description =~ s:([\[\]]):~$1:g;
3845: return '.'.$ex.' '.&mt($file_description);
1.112 bowersj2 3846: }
3847:
3848: # End of .tab access
3849: =pod
3850:
3851: =back
3852:
3853: =cut
3854:
3855: # ------------------------------------------------------------------ File Types
3856: sub fileextensions {
3857: return sort(keys(%fe));
3858: }
3859:
1.97 www 3860: # ----------------------------------------------------------- Display Languages
3861: # returns a hash with all desired display languages
3862: #
3863:
3864: sub display_languages {
3865: my %languages=();
1.695 raeburn 3866: foreach my $lang (&Apache::lonlocal::preferred_languages()) {
1.356 albertel 3867: $languages{$lang}=1;
1.97 www 3868: }
3869: &get_unprocessed_cgi($ENV{'QUERY_STRING'},['displaylanguage']);
1.258 albertel 3870: if ($env{'form.displaylanguage'}) {
1.356 albertel 3871: foreach my $lang (split(/\s*(\,|\;|\:)\s*/,$env{'form.displaylanguage'})) {
3872: $languages{$lang}=1;
1.97 www 3873: }
3874: }
3875: return %languages;
1.14 harris41 3876: }
3877:
1.582 albertel 3878: sub languages {
3879: my ($possible_langs) = @_;
1.695 raeburn 3880: my @preferred_langs = &Apache::lonlocal::preferred_languages();
1.582 albertel 3881: if (!ref($possible_langs)) {
3882: if( wantarray ) {
3883: return @preferred_langs;
3884: } else {
3885: return $preferred_langs[0];
3886: }
3887: }
3888: my %possibilities = map { $_ => 1 } (@$possible_langs);
3889: my @preferred_possibilities;
3890: foreach my $preferred_lang (@preferred_langs) {
3891: if (exists($possibilities{$preferred_lang})) {
3892: push(@preferred_possibilities, $preferred_lang);
3893: }
3894: }
3895: if( wantarray ) {
3896: return @preferred_possibilities;
3897: }
3898: return $preferred_possibilities[0];
3899: }
3900:
1.742 raeburn 3901: sub user_lang {
3902: my ($touname,$toudom,$fromcid) = @_;
3903: my @userlangs;
3904: if (($fromcid ne '') && ($env{'course.'.$fromcid.'.languages'} ne '')) {
3905: @userlangs=(@userlangs,split(/\s*(\,|\;|\:)\s*/,
3906: $env{'course.'.$fromcid.'.languages'}));
3907: } else {
3908: my %langhash = &getlangs($touname,$toudom);
3909: if ($langhash{'languages'} ne '') {
3910: @userlangs = split(/\s*(\,|\;|\:)\s*/,$langhash{'languages'});
3911: } else {
3912: my %domdefs = &Apache::lonnet::get_domain_defaults($toudom);
3913: if ($domdefs{'lang_def'} ne '') {
3914: @userlangs = ($domdefs{'lang_def'});
3915: }
3916: }
3917: }
3918: my @languages=&Apache::lonlocal::get_genlanguages(@userlangs);
3919: my $user_lh = Apache::localize->get_handle(@languages);
3920: return $user_lh;
3921: }
3922:
3923:
1.112 bowersj2 3924: ###############################################################
3925: ## Student Answer Attempts ##
3926: ###############################################################
3927:
3928: =pod
3929:
3930: =head1 Alternate Problem Views
3931:
3932: =over 4
3933:
1.648 raeburn 3934: =item * &get_previous_attempt($symb, $username, $domain, $course,
1.1075.2.86 raeburn 3935: $getattempt, $regexp, $gradesub, $usec, $identifier)
1.112 bowersj2 3936:
3937: Return string with previous attempt on problem. Arguments:
3938:
3939: =over 4
3940:
3941: =item * $symb: Problem, including path
3942:
3943: =item * $username: username of the desired student
3944:
3945: =item * $domain: domain of the desired student
1.14 harris41 3946:
1.112 bowersj2 3947: =item * $course: Course ID
1.14 harris41 3948:
1.112 bowersj2 3949: =item * $getattempt: Leave blank for all attempts, otherwise put
3950: something
1.14 harris41 3951:
1.112 bowersj2 3952: =item * $regexp: if string matches this regexp, the string will be
3953: sent to $gradesub
1.14 harris41 3954:
1.112 bowersj2 3955: =item * $gradesub: routine that processes the string if it matches $regexp
1.14 harris41 3956:
1.1075.2.86 raeburn 3957: =item * $usec: section of the desired student
3958:
3959: =item * $identifier: counter for student (multiple students one problem) or
3960: problem (one student; whole sequence).
3961:
1.112 bowersj2 3962: =back
1.14 harris41 3963:
1.112 bowersj2 3964: The output string is a table containing all desired attempts, if any.
1.16 harris41 3965:
1.112 bowersj2 3966: =cut
1.1 albertel 3967:
3968: sub get_previous_attempt {
1.1075.2.86 raeburn 3969: my ($symb,$username,$domain,$course,$getattempt,$regexp,$gradesub,$usec,$identifier)=@_;
1.1 albertel 3970: my $prevattempts='';
1.43 ng 3971: no strict 'refs';
1.1 albertel 3972: if ($symb) {
1.3 albertel 3973: my (%returnhash)=
3974: &Apache::lonnet::restore($symb,$course,$domain,$username);
1.1 albertel 3975: if ($returnhash{'version'}) {
3976: my %lasthash=();
3977: my $version;
3978: for ($version=1;$version<=$returnhash{'version'};$version++) {
1.1075.2.91 raeburn 3979: foreach my $key (reverse(sort(split(/\:/,$returnhash{$version.':keys'})))) {
3980: if ($key =~ /\.rawrndseed$/) {
3981: my ($id) = ($key =~ /^(.+)\.rawrndseed$/);
3982: $lasthash{$id.'.rndseed'} = $returnhash{$version.':'.$key};
3983: } else {
3984: $lasthash{$key}=$returnhash{$version.':'.$key};
3985: }
1.19 harris41 3986: }
1.1 albertel 3987: }
1.596 albertel 3988: $prevattempts=&start_data_table().&start_data_table_header_row();
3989: $prevattempts.='<th>'.&mt('History').'</th>';
1.1075.2.86 raeburn 3990: my (%typeparts,%lasthidden,%regraded,%hidestatus);
1.945 raeburn 3991: my $showsurv=&Apache::lonnet::allowed('vas',$env{'request.course.id'});
1.356 albertel 3992: foreach my $key (sort(keys(%lasthash))) {
3993: my ($ign,@parts) = split(/\./,$key);
1.41 ng 3994: if ($#parts > 0) {
1.31 albertel 3995: my $data=$parts[-1];
1.989 raeburn 3996: next if ($data eq 'foilorder');
1.31 albertel 3997: pop(@parts);
1.1010 www 3998: $prevattempts.='<th>'.&mt('Part ').join('.',@parts).'<br />'.$data.' </th>';
1.945 raeburn 3999: if ($data eq 'type') {
4000: unless ($showsurv) {
4001: my $id = join(',',@parts);
4002: $typeparts{$ign.'.'.$id} = $lasthash{$key};
1.978 raeburn 4003: if (($lasthash{$key} eq 'anonsurvey') || ($lasthash{$key} eq 'anonsurveycred')) {
4004: $lasthidden{$ign.'.'.$id} = 1;
4005: }
1.945 raeburn 4006: }
1.1075.2.86 raeburn 4007: if ($identifier ne '') {
4008: my $id = join(',',@parts);
4009: if (&Apache::lonnet::EXT("resource.$id.problemstatus",$symb,
4010: $domain,$username,$usec,undef,$course) =~ /^no/) {
4011: $hidestatus{$ign.'.'.$id} = 1;
4012: }
4013: }
4014: } elsif ($data eq 'regrader') {
4015: if (($identifier ne '') && (@parts)) {
4016: my $id = join(',',@parts);
4017: $regraded{$ign.'.'.$id} = 1;
4018: }
1.1010 www 4019: }
1.31 albertel 4020: } else {
1.41 ng 4021: if ($#parts == 0) {
4022: $prevattempts.='<th>'.$parts[0].'</th>';
4023: } else {
4024: $prevattempts.='<th>'.$ign.'</th>';
4025: }
1.31 albertel 4026: }
1.16 harris41 4027: }
1.596 albertel 4028: $prevattempts.=&end_data_table_header_row();
1.40 ng 4029: if ($getattempt eq '') {
1.1075.2.86 raeburn 4030: my (%solved,%resets,%probstatus);
4031: if (($identifier ne '') && (keys(%regraded) > 0)) {
4032: for ($version=1;$version<=$returnhash{'version'};$version++) {
4033: foreach my $id (keys(%regraded)) {
4034: if (($returnhash{$version.':'.$id.'.regrader'}) &&
4035: ($returnhash{$version.':'.$id.'.tries'} eq '') &&
4036: ($returnhash{$version.':'.$id.'.award'} eq '')) {
4037: push(@{$resets{$id}},$version);
4038: }
4039: }
4040: }
4041: }
1.40 ng 4042: for ($version=1;$version<=$returnhash{'version'};$version++) {
1.1075.2.86 raeburn 4043: my (@hidden,@unsolved);
1.945 raeburn 4044: if (%typeparts) {
4045: foreach my $id (keys(%typeparts)) {
1.1075.2.86 raeburn 4046: if (($returnhash{$version.':'.$id.'.type'} eq 'anonsurvey') ||
4047: ($returnhash{$version.':'.$id.'.type'} eq 'anonsurveycred')) {
1.945 raeburn 4048: push(@hidden,$id);
1.1075.2.86 raeburn 4049: } elsif ($identifier ne '') {
4050: unless (($returnhash{$version.':'.$id.'.type'} eq 'survey') ||
4051: ($returnhash{$version.':'.$id.'.type'} eq 'surveycred') ||
4052: ($hidestatus{$id})) {
4053: next if ((ref($resets{$id}) eq 'ARRAY') && grep(/^\Q$version\E$/,@{$resets{$id}}));
4054: if ($returnhash{$version.':'.$id.'.solved'} eq 'correct_by_student') {
4055: push(@{$solved{$id}},$version);
4056: } elsif (($returnhash{$version.':'.$id.'.solved'} ne '') &&
4057: (ref($solved{$id}) eq 'ARRAY')) {
4058: my $skip;
4059: if (ref($resets{$id}) eq 'ARRAY') {
4060: foreach my $reset (@{$resets{$id}}) {
4061: if ($reset > $solved{$id}[-1]) {
4062: $skip=1;
4063: last;
4064: }
4065: }
4066: }
4067: unless ($skip) {
4068: my ($ign,$partslist) = split(/\./,$id,2);
4069: push(@unsolved,$partslist);
4070: }
4071: }
4072: }
1.945 raeburn 4073: }
4074: }
4075: }
4076: $prevattempts.=&start_data_table_row().
1.1075.2.86 raeburn 4077: '<td>'.&mt('Transaction [_1]',$version);
4078: if (@unsolved) {
4079: $prevattempts .= '<span class="LC_nobreak"><label>'.
4080: '<input type="checkbox" name="HIDE'.$identifier.'" value="'.$version.':'.join('_',@unsolved).'" />'.
4081: &mt('Hide').'</label></span>';
4082: }
4083: $prevattempts .= '</td>';
1.945 raeburn 4084: if (@hidden) {
4085: foreach my $key (sort(keys(%lasthash))) {
1.989 raeburn 4086: next if ($key =~ /\.foilorder$/);
1.945 raeburn 4087: my $hide;
4088: foreach my $id (@hidden) {
4089: if ($key =~ /^\Q$id\E/) {
4090: $hide = 1;
4091: last;
4092: }
4093: }
4094: if ($hide) {
4095: my ($id,$data) = ($key =~ /^(.+)\.([^.]+)$/);
4096: if (($data eq 'award') || ($data eq 'awarddetail')) {
4097: my $value = &format_previous_attempt_value($key,
4098: $returnhash{$version.':'.$key});
4099: $prevattempts.='<td>'.$value.' </td>';
4100: } else {
4101: $prevattempts.='<td> </td>';
4102: }
4103: } else {
4104: if ($key =~ /\./) {
1.1075.2.91 raeburn 4105: my $value = $returnhash{$version.':'.$key};
4106: if ($key =~ /\.rndseed$/) {
4107: my ($id) = ($key =~ /^(.+)\.rndseed$/);
4108: if (exists($returnhash{$version.':'.$id.'.rawrndseed'})) {
4109: $value = $returnhash{$version.':'.$id.'.rawrndseed'};
4110: }
4111: }
4112: $prevattempts.='<td>'.&format_previous_attempt_value($key,$value).
4113: ' </td>';
1.945 raeburn 4114: } else {
4115: $prevattempts.='<td> </td>';
4116: }
4117: }
4118: }
4119: } else {
4120: foreach my $key (sort(keys(%lasthash))) {
1.989 raeburn 4121: next if ($key =~ /\.foilorder$/);
1.1075.2.91 raeburn 4122: my $value = $returnhash{$version.':'.$key};
4123: if ($key =~ /\.rndseed$/) {
4124: my ($id) = ($key =~ /^(.+)\.rndseed$/);
4125: if (exists($returnhash{$version.':'.$id.'.rawrndseed'})) {
4126: $value = $returnhash{$version.':'.$id.'.rawrndseed'};
4127: }
4128: }
4129: $prevattempts.='<td>'.&format_previous_attempt_value($key,$value).
4130: ' </td>';
1.945 raeburn 4131: }
4132: }
4133: $prevattempts.=&end_data_table_row();
1.40 ng 4134: }
1.1 albertel 4135: }
1.945 raeburn 4136: my @currhidden = keys(%lasthidden);
1.596 albertel 4137: $prevattempts.=&start_data_table_row().'<td>'.&mt('Current').'</td>';
1.356 albertel 4138: foreach my $key (sort(keys(%lasthash))) {
1.989 raeburn 4139: next if ($key =~ /\.foilorder$/);
1.945 raeburn 4140: if (%typeparts) {
4141: my $hidden;
4142: foreach my $id (@currhidden) {
4143: if ($key =~ /^\Q$id\E/) {
4144: $hidden = 1;
4145: last;
4146: }
4147: }
4148: if ($hidden) {
4149: my ($id,$data) = ($key =~ /^(.+)\.([^.]+)$/);
4150: if (($data eq 'award') || ($data eq 'awarddetail')) {
4151: my $value = &format_previous_attempt_value($key,$lasthash{$key});
4152: if ($key =~/$regexp$/ && (defined &$gradesub)) {
4153: $value = &$gradesub($value);
4154: }
4155: $prevattempts.='<td>'.$value.' </td>';
4156: } else {
4157: $prevattempts.='<td> </td>';
4158: }
4159: } else {
4160: my $value = &format_previous_attempt_value($key,$lasthash{$key});
4161: if ($key =~/$regexp$/ && (defined &$gradesub)) {
4162: $value = &$gradesub($value);
4163: }
4164: $prevattempts.='<td>'.$value.' </td>';
4165: }
4166: } else {
4167: my $value = &format_previous_attempt_value($key,$lasthash{$key});
4168: if ($key =~/$regexp$/ && (defined &$gradesub)) {
4169: $value = &$gradesub($value);
4170: }
4171: $prevattempts.='<td>'.$value.' </td>';
4172: }
1.16 harris41 4173: }
1.596 albertel 4174: $prevattempts.= &end_data_table_row().&end_data_table();
1.1 albertel 4175: } else {
1.596 albertel 4176: $prevattempts=
4177: &start_data_table().&start_data_table_row().
4178: '<td>'.&mt('Nothing submitted - no attempts.').'</td>'.
4179: &end_data_table_row().&end_data_table();
1.1 albertel 4180: }
4181: } else {
1.596 albertel 4182: $prevattempts=
4183: &start_data_table().&start_data_table_row().
4184: '<td>'.&mt('No data.').'</td>'.
4185: &end_data_table_row().&end_data_table();
1.1 albertel 4186: }
1.10 albertel 4187: }
4188:
1.581 albertel 4189: sub format_previous_attempt_value {
4190: my ($key,$value) = @_;
1.1011 www 4191: if (($key =~ /timestamp/) || ($key=~/duedate/)) {
1.581 albertel 4192: $value = &Apache::lonlocal::locallocaltime($value);
4193: } elsif (ref($value) eq 'ARRAY') {
4194: $value = '('.join(', ', @{ $value }).')';
1.988 raeburn 4195: } elsif ($key =~ /answerstring$/) {
4196: my %answers = &Apache::lonnet::str2hash($value);
4197: my @anskeys = sort(keys(%answers));
4198: if (@anskeys == 1) {
4199: my $answer = $answers{$anskeys[0]};
1.1001 raeburn 4200: if ($answer =~ m{\0}) {
4201: $answer =~ s{\0}{,}g;
1.988 raeburn 4202: }
4203: my $tag_internal_answer_name = 'INTERNAL';
4204: if ($anskeys[0] eq $tag_internal_answer_name) {
4205: $value = $answer;
4206: } else {
4207: $value = $anskeys[0].'='.$answer;
4208: }
4209: } else {
4210: foreach my $ans (@anskeys) {
4211: my $answer = $answers{$ans};
1.1001 raeburn 4212: if ($answer =~ m{\0}) {
4213: $answer =~ s{\0}{,}g;
1.988 raeburn 4214: }
4215: $value .= $ans.'='.$answer.'<br />';;
4216: }
4217: }
1.581 albertel 4218: } else {
4219: $value = &unescape($value);
4220: }
4221: return $value;
4222: }
4223:
4224:
1.107 albertel 4225: sub relative_to_absolute {
4226: my ($url,$output)=@_;
4227: my $parser=HTML::TokeParser->new(\$output);
4228: my $token;
4229: my $thisdir=$url;
4230: my @rlinks=();
4231: while ($token=$parser->get_token) {
4232: if ($token->[0] eq 'S') {
4233: if ($token->[1] eq 'a') {
4234: if ($token->[2]->{'href'}) {
4235: $rlinks[$#rlinks+1]=$token->[2]->{'href'};
4236: }
4237: } elsif ($token->[1] eq 'img' || $token->[1] eq 'embed' ) {
4238: $rlinks[$#rlinks+1]=$token->[2]->{'src'};
4239: } elsif ($token->[1] eq 'base') {
4240: $thisdir=$token->[2]->{'href'};
4241: }
4242: }
4243: }
4244: $thisdir=~s-/[^/]*$--;
1.356 albertel 4245: foreach my $link (@rlinks) {
1.726 raeburn 4246: unless (($link=~/^https?\:\/\//i) ||
1.356 albertel 4247: ($link=~/^\//) ||
4248: ($link=~/^javascript:/i) ||
4249: ($link=~/^mailto:/i) ||
4250: ($link=~/^\#/)) {
4251: my $newlocation=&Apache::lonnet::hreflocation($thisdir,$link);
4252: $output=~s/(\"|\'|\=\s*)\Q$link\E(\"|\'|\s|\>)/$1$newlocation$2/;
1.107 albertel 4253: }
4254: }
4255: # -------------------------------------------------- Deal with Applet codebases
4256: $output=~s/(\<applet[^\>]+)(codebase\=[^\S\>]+)*([^\>]*)\>/$1.($2?$2:' codebase="'.$thisdir.'"').$3.'>'/gei;
4257: return $output;
4258: }
4259:
1.112 bowersj2 4260: =pod
4261:
1.648 raeburn 4262: =item * &get_student_view()
1.112 bowersj2 4263:
4264: show a snapshot of what student was looking at
4265:
4266: =cut
4267:
1.10 albertel 4268: sub get_student_view {
1.186 albertel 4269: my ($symb,$username,$domain,$courseid,$target,$moreenv) = @_;
1.114 www 4270: my ($map,$id,$feedurl) = &Apache::lonnet::decode_symb($symb);
1.186 albertel 4271: my (%form);
1.10 albertel 4272: my @elements=('symb','courseid','domain','username');
4273: foreach my $element (@elements) {
1.186 albertel 4274: $form{'grade_'.$element}=eval '$'.$element #'
1.10 albertel 4275: }
1.186 albertel 4276: if (defined($moreenv)) {
4277: %form=(%form,%{$moreenv});
4278: }
1.236 albertel 4279: if (defined($target)) { $form{'grade_target'} = $target; }
1.107 albertel 4280: $feedurl=&Apache::lonnet::clutter($feedurl);
1.650 www 4281: my ($userview,$response)=&Apache::lonnet::ssi_body($feedurl,%form);
1.11 albertel 4282: $userview=~s/\<body[^\>]*\>//gi;
4283: $userview=~s/\<\/body\>//gi;
4284: $userview=~s/\<html\>//gi;
4285: $userview=~s/\<\/html\>//gi;
4286: $userview=~s/\<head\>//gi;
4287: $userview=~s/\<\/head\>//gi;
4288: $userview=~s/action\s*\=/would_be_action\=/gi;
1.107 albertel 4289: $userview=&relative_to_absolute($feedurl,$userview);
1.650 www 4290: if (wantarray) {
4291: return ($userview,$response);
4292: } else {
4293: return $userview;
4294: }
4295: }
4296:
4297: sub get_student_view_with_retries {
4298: my ($symb,$retries,$username,$domain,$courseid,$target,$moreenv) = @_;
4299:
4300: my $ok = 0; # True if we got a good response.
4301: my $content;
4302: my $response;
4303:
4304: # Try to get the student_view done. within the retries count:
4305:
4306: do {
4307: ($content, $response) = &get_student_view($symb,$username,$domain,$courseid,$target,$moreenv);
4308: $ok = $response->is_success;
4309: if (!$ok) {
4310: &Apache::lonnet::logthis("Failed get_student_view_with_retries on $symb: ".$response->is_success.', '.$response->code.', '.$response->message);
4311: }
4312: $retries--;
4313: } while (!$ok && ($retries > 0));
4314:
4315: if (!$ok) {
4316: $content = ''; # On error return an empty content.
4317: }
1.651 www 4318: if (wantarray) {
4319: return ($content, $response);
4320: } else {
4321: return $content;
4322: }
1.11 albertel 4323: }
4324:
1.112 bowersj2 4325: =pod
4326:
1.648 raeburn 4327: =item * &get_student_answers()
1.112 bowersj2 4328:
4329: show a snapshot of how student was answering problem
4330:
4331: =cut
4332:
1.11 albertel 4333: sub get_student_answers {
1.100 sakharuk 4334: my ($symb,$username,$domain,$courseid,%form) = @_;
1.114 www 4335: my ($map,$id,$feedurl) = &Apache::lonnet::decode_symb($symb);
1.186 albertel 4336: my (%moreenv);
1.11 albertel 4337: my @elements=('symb','courseid','domain','username');
4338: foreach my $element (@elements) {
1.186 albertel 4339: $moreenv{'grade_'.$element}=eval '$'.$element #'
1.10 albertel 4340: }
1.186 albertel 4341: $moreenv{'grade_target'}='answer';
4342: %moreenv=(%form,%moreenv);
1.497 raeburn 4343: $feedurl = &Apache::lonnet::clutter($feedurl);
4344: my $userview=&Apache::lonnet::ssi($feedurl,%moreenv);
1.10 albertel 4345: return $userview;
1.1 albertel 4346: }
1.116 albertel 4347:
4348: =pod
4349:
4350: =item * &submlink()
4351:
1.242 albertel 4352: Inputs: $text $uname $udom $symb $target
1.116 albertel 4353:
4354: Returns: A link to grades.pm such as to see the SUBM view of a student
4355:
4356: =cut
4357:
4358: ###############################################
4359: sub submlink {
1.242 albertel 4360: my ($text,$uname,$udom,$symb,$target)=@_;
1.116 albertel 4361: if (!($uname && $udom)) {
4362: (my $cursymb, my $courseid,$udom,$uname)=
1.463 albertel 4363: &Apache::lonnet::whichuser($symb);
1.116 albertel 4364: if (!$symb) { $symb=$cursymb; }
4365: }
1.254 matthew 4366: if (!$symb) { $symb=&Apache::lonnet::symbread(); }
1.369 www 4367: $symb=&escape($symb);
1.960 bisitz 4368: if ($target) { $target=" target=\"$target\""; }
4369: return
4370: '<a href="/adm/grades?command=submission'.
4371: '&symb='.$symb.
4372: '&student='.$uname.
4373: '&userdom='.$udom.'"'.
4374: $target.'>'.$text.'</a>';
1.242 albertel 4375: }
4376: ##############################################
4377:
4378: =pod
4379:
4380: =item * &pgrdlink()
4381:
4382: Inputs: $text $uname $udom $symb $target
4383:
4384: Returns: A link to grades.pm such as to see the PGRD view of a student
4385:
4386: =cut
4387:
4388: ###############################################
4389: sub pgrdlink {
4390: my $link=&submlink(@_);
4391: $link=~s/(&command=submission)/$1&showgrading=yes/;
4392: return $link;
4393: }
4394: ##############################################
4395:
4396: =pod
4397:
4398: =item * &pprmlink()
4399:
4400: Inputs: $text $uname $udom $symb $target
4401:
4402: Returns: A link to parmset.pm such as to see the PPRM view of a
1.283 albertel 4403: student and a specific resource
1.242 albertel 4404:
4405: =cut
4406:
4407: ###############################################
4408: sub pprmlink {
4409: my ($text,$uname,$udom,$symb,$target)=@_;
4410: if (!($uname && $udom)) {
4411: (my $cursymb, my $courseid,$udom,$uname)=
1.463 albertel 4412: &Apache::lonnet::whichuser($symb);
1.242 albertel 4413: if (!$symb) { $symb=$cursymb; }
4414: }
1.254 matthew 4415: if (!$symb) { $symb=&Apache::lonnet::symbread(); }
1.369 www 4416: $symb=&escape($symb);
1.242 albertel 4417: if ($target) { $target="target=\"$target\""; }
1.595 albertel 4418: return '<a href="/adm/parmset?command=set&'.
4419: 'symb='.$symb.'&uname='.$uname.
4420: '&udom='.$udom.'" '.$target.'>'.$text.'</a>';
1.116 albertel 4421: }
4422: ##############################################
1.37 matthew 4423:
1.112 bowersj2 4424: =pod
4425:
4426: =back
4427:
4428: =cut
4429:
1.37 matthew 4430: ###############################################
1.51 www 4431:
4432:
4433: sub timehash {
1.687 raeburn 4434: my ($thistime) = @_;
4435: my $timezone = &Apache::lonlocal::gettimezone();
4436: my $dt = DateTime->from_epoch(epoch => $thistime)
4437: ->set_time_zone($timezone);
4438: my $wday = $dt->day_of_week();
4439: if ($wday == 7) { $wday = 0; }
4440: return ( 'second' => $dt->second(),
4441: 'minute' => $dt->minute(),
4442: 'hour' => $dt->hour(),
4443: 'day' => $dt->day_of_month(),
4444: 'month' => $dt->month(),
4445: 'year' => $dt->year(),
4446: 'weekday' => $wday,
4447: 'dayyear' => $dt->day_of_year(),
4448: 'dlsav' => $dt->is_dst() );
1.51 www 4449: }
4450:
1.370 www 4451: sub utc_string {
4452: my ($date)=@_;
1.371 www 4453: return strftime("%Y%m%dT%H%M%SZ",gmtime($date));
1.370 www 4454: }
4455:
1.51 www 4456: sub maketime {
4457: my %th=@_;
1.687 raeburn 4458: my ($epoch_time,$timezone,$dt);
4459: $timezone = &Apache::lonlocal::gettimezone();
4460: eval {
4461: $dt = DateTime->new( year => $th{'year'},
4462: month => $th{'month'},
4463: day => $th{'day'},
4464: hour => $th{'hour'},
4465: minute => $th{'minute'},
4466: second => $th{'second'},
4467: time_zone => $timezone,
4468: );
4469: };
4470: if (!$@) {
4471: $epoch_time = $dt->epoch;
4472: if ($epoch_time) {
4473: return $epoch_time;
4474: }
4475: }
1.51 www 4476: return POSIX::mktime(
4477: ($th{'seconds'},$th{'minutes'},$th{'hours'},
1.210 www 4478: $th{'day'},$th{'month'}-1,$th{'year'}-1900,0,0,-1));
1.70 www 4479: }
4480:
4481: #########################################
1.51 www 4482:
4483: sub findallcourses {
1.482 raeburn 4484: my ($roles,$uname,$udom) = @_;
1.355 albertel 4485: my %roles;
4486: if (ref($roles)) { %roles = map { $_ => 1 } @{$roles}; }
1.348 albertel 4487: my %courses;
1.51 www 4488: my $now=time;
1.482 raeburn 4489: if (!defined($uname)) {
4490: $uname = $env{'user.name'};
4491: }
4492: if (!defined($udom)) {
4493: $udom = $env{'user.domain'};
4494: }
4495: if (($uname ne $env{'user.name'}) || ($udom ne $env{'user.domain'})) {
1.1073 raeburn 4496: my %roleshash = &Apache::lonnet::dump('roles',$udom,$uname);
1.482 raeburn 4497: if (!%roles) {
4498: %roles = (
4499: cc => 1,
1.907 raeburn 4500: co => 1,
1.482 raeburn 4501: in => 1,
4502: ep => 1,
4503: ta => 1,
4504: cr => 1,
4505: st => 1,
4506: );
4507: }
4508: foreach my $entry (keys(%roleshash)) {
4509: my ($trole,$tend,$tstart) = split(/_/,$roleshash{$entry});
4510: if ($trole =~ /^cr/) {
4511: next if (!exists($roles{$trole}) && !exists($roles{'cr'}));
4512: } else {
4513: next if (!exists($roles{$trole}));
4514: }
4515: if ($tend) {
4516: next if ($tend < $now);
4517: }
4518: if ($tstart) {
4519: next if ($tstart > $now);
4520: }
1.1058 raeburn 4521: my ($cdom,$cnum,$sec,$cnumpart,$secpart,$role);
1.482 raeburn 4522: (undef,$cdom,$cnumpart,$secpart) = split(/\//,$entry);
1.1058 raeburn 4523: my $value = $trole.'/'.$cdom.'/';
1.482 raeburn 4524: if ($secpart eq '') {
4525: ($cnum,$role) = split(/_/,$cnumpart);
4526: $sec = 'none';
1.1058 raeburn 4527: $value .= $cnum.'/';
1.482 raeburn 4528: } else {
4529: $cnum = $cnumpart;
4530: ($sec,$role) = split(/_/,$secpart);
1.1058 raeburn 4531: $value .= $cnum.'/'.$sec;
4532: }
4533: if (ref($courses{$cdom.'_'.$cnum}{$sec}) eq 'ARRAY') {
4534: unless (grep(/^\Q$value\E$/,@{$courses{$cdom.'_'.$cnum}{$sec}})) {
4535: push(@{$courses{$cdom.'_'.$cnum}{$sec}},$value);
4536: }
4537: } else {
4538: @{$courses{$cdom.'_'.$cnum}{$sec}} = ($value);
1.490 raeburn 4539: }
1.482 raeburn 4540: }
4541: } else {
4542: foreach my $key (keys(%env)) {
1.483 albertel 4543: if ( $key=~m{^user\.role\.(\w+)\./($match_domain)/($match_courseid)/?(\w*)$} ||
4544: $key=~m{^user\.role\.(cr/$match_domain/$match_username/\w+)\./($match_domain)/($match_courseid)/?(\w*)$}) {
1.482 raeburn 4545: my ($role,$cdom,$cnum,$sec) = ($1,$2,$3,$4);
4546: next if ($role eq 'ca' || $role eq 'aa');
4547: next if (%roles && !exists($roles{$role}));
4548: my ($starttime,$endtime)=split(/\./,$env{$key});
4549: my $active=1;
4550: if ($starttime) {
4551: if ($now<$starttime) { $active=0; }
4552: }
4553: if ($endtime) {
4554: if ($now>$endtime) { $active=0; }
4555: }
4556: if ($active) {
1.1058 raeburn 4557: my $value = $role.'/'.$cdom.'/'.$cnum.'/';
1.482 raeburn 4558: if ($sec eq '') {
4559: $sec = 'none';
1.1058 raeburn 4560: } else {
4561: $value .= $sec;
4562: }
4563: if (ref($courses{$cdom.'_'.$cnum}{$sec}) eq 'ARRAY') {
4564: unless (grep(/^\Q$value\E$/,@{$courses{$cdom.'_'.$cnum}{$sec}})) {
4565: push(@{$courses{$cdom.'_'.$cnum}{$sec}},$value);
4566: }
4567: } else {
4568: @{$courses{$cdom.'_'.$cnum}{$sec}} = ($value);
1.482 raeburn 4569: }
1.474 raeburn 4570: }
4571: }
1.51 www 4572: }
4573: }
1.474 raeburn 4574: return %courses;
1.51 www 4575: }
1.37 matthew 4576:
1.54 www 4577: ###############################################
1.474 raeburn 4578:
4579: sub blockcheck {
1.1075.2.73 raeburn 4580: my ($setters,$activity,$uname,$udom,$url,$is_course) = @_;
1.490 raeburn 4581:
1.1075.2.73 raeburn 4582: if (defined($udom) && defined($uname)) {
4583: # If uname and udom are for a course, check for blocks in the course.
4584: if (($is_course) || (&Apache::lonnet::is_course($udom,$uname))) {
4585: my ($startblock,$endblock,$triggerblock) =
4586: &get_blocks($setters,$activity,$udom,$uname,$url);
4587: return ($startblock,$endblock,$triggerblock);
4588: }
4589: } else {
1.490 raeburn 4590: $udom = $env{'user.domain'};
4591: $uname = $env{'user.name'};
4592: }
4593:
1.502 raeburn 4594: my $startblock = 0;
4595: my $endblock = 0;
1.1062 raeburn 4596: my $triggerblock = '';
1.482 raeburn 4597: my %live_courses = &findallcourses(undef,$uname,$udom);
1.474 raeburn 4598:
1.490 raeburn 4599: # If uname is for a user, and activity is course-specific, i.e.,
4600: # boards, chat or groups, check for blocking in current course only.
1.474 raeburn 4601:
1.490 raeburn 4602: if (($activity eq 'boards' || $activity eq 'chat' ||
1.1075.2.73 raeburn 4603: $activity eq 'groups' || $activity eq 'printout') &&
4604: ($env{'request.course.id'})) {
1.490 raeburn 4605: foreach my $key (keys(%live_courses)) {
4606: if ($key ne $env{'request.course.id'}) {
4607: delete($live_courses{$key});
4608: }
4609: }
4610: }
4611:
4612: my $otheruser = 0;
4613: my %own_courses;
4614: if ((($uname ne $env{'user.name'})) || ($udom ne $env{'user.domain'})) {
4615: # Resource belongs to user other than current user.
4616: $otheruser = 1;
4617: # Gather courses for current user
4618: %own_courses =
4619: &findallcourses(undef,$env{'user.name'},$env{'user.domain'});
4620: }
4621:
4622: # Gather active course roles - course coordinator, instructor,
4623: # exam proctor, ta, student, or custom role.
1.474 raeburn 4624:
4625: foreach my $course (keys(%live_courses)) {
1.482 raeburn 4626: my ($cdom,$cnum);
4627: if ((defined($env{'course.'.$course.'.domain'})) && (defined($env{'course.'.$course.'.num'}))) {
4628: $cdom = $env{'course.'.$course.'.domain'};
4629: $cnum = $env{'course.'.$course.'.num'};
4630: } else {
1.490 raeburn 4631: ($cdom,$cnum) = split(/_/,$course);
1.482 raeburn 4632: }
4633: my $no_ownblock = 0;
4634: my $no_userblock = 0;
1.533 raeburn 4635: if ($otheruser && $activity ne 'com') {
1.490 raeburn 4636: # Check if current user has 'evb' priv for this
4637: if (defined($own_courses{$course})) {
4638: foreach my $sec (keys(%{$own_courses{$course}})) {
4639: my $checkrole = 'cm./'.$cdom.'/'.$cnum;
4640: if ($sec ne 'none') {
4641: $checkrole .= '/'.$sec;
4642: }
4643: if (&Apache::lonnet::allowed('evb',undef,undef,$checkrole)) {
4644: $no_ownblock = 1;
4645: last;
4646: }
4647: }
4648: }
4649: # if they have 'evb' priv and are currently not playing student
4650: next if (($no_ownblock) &&
4651: ($env{'request.role'} !~ m{^st\./$cdom/$cnum}));
4652: }
1.474 raeburn 4653: foreach my $sec (keys(%{$live_courses{$course}})) {
1.482 raeburn 4654: my $checkrole = 'cm./'.$cdom.'/'.$cnum;
1.474 raeburn 4655: if ($sec ne 'none') {
1.482 raeburn 4656: $checkrole .= '/'.$sec;
1.474 raeburn 4657: }
1.490 raeburn 4658: if ($otheruser) {
4659: # Resource belongs to user other than current user.
4660: # Assemble privs for that user, and check for 'evb' priv.
1.1058 raeburn 4661: my (%allroles,%userroles);
4662: if (ref($live_courses{$course}{$sec}) eq 'ARRAY') {
4663: foreach my $entry (@{$live_courses{$course}{$sec}}) {
4664: my ($trole,$tdom,$tnum,$tsec);
4665: if ($entry =~ /^cr/) {
4666: ($trole,$tdom,$tnum,$tsec) =
4667: ($entry =~ m|^(cr/$match_domain/$match_username/\w+)\./($match_domain)/($match_username)/?(\w*)$|);
4668: } else {
4669: ($trole,$tdom,$tnum,$tsec) = split(/\//,$entry);
4670: }
4671: my ($spec,$area,$trest);
4672: $area = '/'.$tdom.'/'.$tnum;
4673: $trest = $tnum;
4674: if ($tsec ne '') {
4675: $area .= '/'.$tsec;
4676: $trest .= '/'.$tsec;
4677: }
4678: $spec = $trole.'.'.$area;
4679: if ($trole =~ /^cr/) {
4680: &Apache::lonnet::custom_roleprivs(\%allroles,$trole,
4681: $tdom,$spec,$trest,$area);
4682: } else {
4683: &Apache::lonnet::standard_roleprivs(\%allroles,$trole,
4684: $tdom,$spec,$trest,$area);
4685: }
4686: }
4687: my ($author,$adv) = &Apache::lonnet::set_userprivs(\%userroles,\%allroles);
4688: if ($userroles{'user.priv.'.$checkrole} =~ /evb\&([^\:]*)/) {
4689: if ($1) {
4690: $no_userblock = 1;
4691: last;
4692: }
1.486 raeburn 4693: }
4694: }
1.490 raeburn 4695: } else {
4696: # Resource belongs to current user
4697: # Check for 'evb' priv via lonnet::allowed().
1.482 raeburn 4698: if (&Apache::lonnet::allowed('evb',undef,undef,$checkrole)) {
4699: $no_ownblock = 1;
4700: last;
4701: }
1.474 raeburn 4702: }
4703: }
4704: # if they have the evb priv and are currently not playing student
1.482 raeburn 4705: next if (($no_ownblock) &&
1.491 albertel 4706: ($env{'request.role'} !~ m{^st\./\Q$cdom\E/\Q$cnum\E}));
1.482 raeburn 4707: next if ($no_userblock);
1.474 raeburn 4708:
1.866 kalberla 4709: # Retrieve blocking times and identity of locker for course
1.490 raeburn 4710: # of specified user, unless user has 'evb' privilege.
1.502 raeburn 4711:
1.1062 raeburn 4712: my ($start,$end,$trigger) =
4713: &get_blocks($setters,$activity,$cdom,$cnum,$url);
1.502 raeburn 4714: if (($start != 0) &&
4715: (($startblock == 0) || ($startblock > $start))) {
4716: $startblock = $start;
1.1062 raeburn 4717: if ($trigger ne '') {
4718: $triggerblock = $trigger;
4719: }
1.502 raeburn 4720: }
4721: if (($end != 0) &&
4722: (($endblock == 0) || ($endblock < $end))) {
4723: $endblock = $end;
1.1062 raeburn 4724: if ($trigger ne '') {
4725: $triggerblock = $trigger;
4726: }
1.502 raeburn 4727: }
1.490 raeburn 4728: }
1.1062 raeburn 4729: return ($startblock,$endblock,$triggerblock);
1.490 raeburn 4730: }
4731:
4732: sub get_blocks {
1.1062 raeburn 4733: my ($setters,$activity,$cdom,$cnum,$url) = @_;
1.490 raeburn 4734: my $startblock = 0;
4735: my $endblock = 0;
1.1062 raeburn 4736: my $triggerblock = '';
1.490 raeburn 4737: my $course = $cdom.'_'.$cnum;
4738: $setters->{$course} = {};
4739: $setters->{$course}{'staff'} = [];
4740: $setters->{$course}{'times'} = [];
1.1062 raeburn 4741: $setters->{$course}{'triggers'} = [];
4742: my (@blockers,%triggered);
4743: my $now = time;
4744: my %commblocks = &Apache::lonnet::get_comm_blocks($cdom,$cnum);
4745: if ($activity eq 'docs') {
4746: @blockers = &Apache::lonnet::has_comm_blocking('bre',undef,$url,\%commblocks);
4747: foreach my $block (@blockers) {
4748: if ($block =~ /^firstaccess____(.+)$/) {
4749: my $item = $1;
4750: my $type = 'map';
4751: my $timersymb = $item;
4752: if ($item eq 'course') {
4753: $type = 'course';
4754: } elsif ($item =~ /___\d+___/) {
4755: $type = 'resource';
4756: } else {
4757: $timersymb = &Apache::lonnet::symbread($item);
4758: }
4759: my $start = $env{'course.'.$cdom.'_'.$cnum.'.firstaccess.'.$timersymb};
4760: my $end = $start + $env{'course.'.$cdom.'_'.$cnum.'.timerinterval.'.$timersymb};
4761: $triggered{$block} = {
4762: start => $start,
4763: end => $end,
4764: type => $type,
4765: };
4766: }
4767: }
4768: } else {
4769: foreach my $block (keys(%commblocks)) {
4770: if ($block =~ m/^(\d+)____(\d+)$/) {
4771: my ($start,$end) = ($1,$2);
4772: if ($start <= time && $end >= time) {
4773: if (ref($commblocks{$block}) eq 'HASH') {
4774: if (ref($commblocks{$block}{'blocks'}) eq 'HASH') {
4775: if ($commblocks{$block}{'blocks'}{$activity} eq 'on') {
4776: unless(grep(/^\Q$block\E$/,@blockers)) {
4777: push(@blockers,$block);
4778: }
4779: }
4780: }
4781: }
4782: }
4783: } elsif ($block =~ /^firstaccess____(.+)$/) {
4784: my $item = $1;
4785: my $timersymb = $item;
4786: my $type = 'map';
4787: if ($item eq 'course') {
4788: $type = 'course';
4789: } elsif ($item =~ /___\d+___/) {
4790: $type = 'resource';
4791: } else {
4792: $timersymb = &Apache::lonnet::symbread($item);
4793: }
4794: my $start = $env{'course.'.$cdom.'_'.$cnum.'.firstaccess.'.$timersymb};
4795: my $end = $start + $env{'course.'.$cdom.'_'.$cnum.'.timerinterval.'.$timersymb};
4796: if ($start && $end) {
4797: if (($start <= time) && ($end >= time)) {
4798: unless (grep(/^\Q$block\E$/,@blockers)) {
4799: push(@blockers,$block);
4800: $triggered{$block} = {
4801: start => $start,
4802: end => $end,
4803: type => $type,
4804: };
4805: }
4806: }
1.490 raeburn 4807: }
1.1062 raeburn 4808: }
4809: }
4810: }
4811: foreach my $blocker (@blockers) {
4812: my ($staff_name,$staff_dom,$title,$blocks) =
4813: &parse_block_record($commblocks{$blocker});
4814: push(@{$$setters{$course}{'staff'}},[$staff_name,$staff_dom]);
4815: my ($start,$end,$triggertype);
4816: if ($blocker =~ m/^(\d+)____(\d+)$/) {
4817: ($start,$end) = ($1,$2);
4818: } elsif (ref($triggered{$blocker}) eq 'HASH') {
4819: $start = $triggered{$blocker}{'start'};
4820: $end = $triggered{$blocker}{'end'};
4821: $triggertype = $triggered{$blocker}{'type'};
4822: }
4823: if ($start) {
4824: push(@{$$setters{$course}{'times'}}, [$start,$end]);
4825: if ($triggertype) {
4826: push(@{$$setters{$course}{'triggers'}},$triggertype);
4827: } else {
4828: push(@{$$setters{$course}{'triggers'}},0);
4829: }
4830: if ( ($startblock == 0) || ($startblock > $start) ) {
4831: $startblock = $start;
4832: if ($triggertype) {
4833: $triggerblock = $blocker;
1.474 raeburn 4834: }
4835: }
1.1062 raeburn 4836: if ( ($endblock == 0) || ($endblock < $end) ) {
4837: $endblock = $end;
4838: if ($triggertype) {
4839: $triggerblock = $blocker;
4840: }
4841: }
1.474 raeburn 4842: }
4843: }
1.1062 raeburn 4844: return ($startblock,$endblock,$triggerblock);
1.474 raeburn 4845: }
4846:
4847: sub parse_block_record {
4848: my ($record) = @_;
4849: my ($setuname,$setudom,$title,$blocks);
4850: if (ref($record) eq 'HASH') {
4851: ($setuname,$setudom) = split(/:/,$record->{'setter'});
4852: $title = &unescape($record->{'event'});
4853: $blocks = $record->{'blocks'};
4854: } else {
4855: my @data = split(/:/,$record,3);
4856: if (scalar(@data) eq 2) {
4857: $title = $data[1];
4858: ($setuname,$setudom) = split(/@/,$data[0]);
4859: } else {
4860: ($setuname,$setudom,$title) = @data;
4861: }
4862: $blocks = { 'com' => 'on' };
4863: }
4864: return ($setuname,$setudom,$title,$blocks);
4865: }
4866:
1.854 kalberla 4867: sub blocking_status {
1.1075.2.73 raeburn 4868: my ($activity,$uname,$udom,$url,$is_course) = @_;
1.1061 raeburn 4869: my %setters;
1.890 droeschl 4870:
1.1061 raeburn 4871: # check for active blocking
1.1062 raeburn 4872: my ($startblock,$endblock,$triggerblock) =
1.1075.2.73 raeburn 4873: &blockcheck(\%setters,$activity,$uname,$udom,$url,$is_course);
1.1062 raeburn 4874: my $blocked = 0;
4875: if ($startblock && $endblock) {
4876: $blocked = 1;
4877: }
1.890 droeschl 4878:
1.1061 raeburn 4879: # caller just wants to know whether a block is active
4880: if (!wantarray) { return $blocked; }
4881:
4882: # build a link to a popup window containing the details
4883: my $querystring = "?activity=$activity";
4884: # $uname and $udom decide whose portfolio the user is trying to look at
1.1075.2.97 raeburn 4885: if (($activity eq 'port') || ($activity eq 'passwd')) {
4886: $querystring .= "&udom=$udom" if ($udom =~ /^$match_domain$/);
4887: $querystring .= "&uname=$uname" if ($uname =~ /^$match_username$/);
1.1062 raeburn 4888: } elsif ($activity eq 'docs') {
4889: $querystring .= '&url='.&HTML::Entities::encode($url,'&"');
4890: }
1.1061 raeburn 4891:
4892: my $output .= <<'END_MYBLOCK';
4893: function openWindow(url, wdwName, w, h, toolbar,scrollbar) {
4894: var options = "width=" + w + ",height=" + h + ",";
4895: options += "resizable=yes,scrollbars="+scrollbar+",status=no,";
4896: options += "menubar=no,toolbar="+toolbar+",location=no,directories=no";
4897: var newWin = window.open(url, wdwName, options);
4898: newWin.focus();
4899: }
1.890 droeschl 4900: END_MYBLOCK
1.854 kalberla 4901:
1.1061 raeburn 4902: $output = Apache::lonhtmlcommon::scripttag($output);
1.890 droeschl 4903:
1.1061 raeburn 4904: my $popupUrl = "/adm/blockingstatus/$querystring";
1.1062 raeburn 4905: my $text = &mt('Communication Blocked');
1.1075.2.93 raeburn 4906: my $class = 'LC_comblock';
1.1062 raeburn 4907: if ($activity eq 'docs') {
4908: $text = &mt('Content Access Blocked');
1.1075.2.93 raeburn 4909: $class = '';
1.1063 raeburn 4910: } elsif ($activity eq 'printout') {
4911: $text = &mt('Printing Blocked');
1.1075.2.97 raeburn 4912: } elsif ($activity eq 'passwd') {
4913: $text = &mt('Password Changing Blocked');
1.1062 raeburn 4914: }
1.1061 raeburn 4915: $output .= <<"END_BLOCK";
1.1075.2.93 raeburn 4916: <div class='$class'>
1.869 kalberla 4917: <a onclick='openWindow("$popupUrl","Blocking Table",600,300,"no","no");return false;' href='/adm/blockingstatus/$querystring'
1.890 droeschl 4918: title='$text'>
4919: <img class='LC_noBorder LC_middle' title='$text' src='/res/adm/pages/comblock.png' alt='$text'/></a>
1.869 kalberla 4920: <a onclick='openWindow("$popupUrl","Blocking Table",600,300,"no","no");return false;' href='/adm/blockingstatus/$querystring'
1.890 droeschl 4921: title='$text'>$text</a>
1.867 kalberla 4922: </div>
4923:
4924: END_BLOCK
1.474 raeburn 4925:
1.1061 raeburn 4926: return ($blocked, $output);
1.854 kalberla 4927: }
1.490 raeburn 4928:
1.60 matthew 4929: ###############################################
4930:
1.682 raeburn 4931: sub check_ip_acc {
1.1075.2.105 raeburn 4932: my ($acc,$clientip)=@_;
1.682 raeburn 4933: &Apache::lonxml::debug("acc is $acc");
4934: if (!defined($acc) || $acc =~ /^\s*$/ || $acc =~/^\s*no\s*$/i) {
4935: return 1;
4936: }
4937: my $allowed=0;
1.1075.2.111 raeburn 4938: my $ip=$ENV{'REMOTE_ADDR'} || $clientip || $env{'request.host'};
1.682 raeburn 4939:
4940: my $name;
4941: foreach my $pattern (split(',',$acc)) {
4942: $pattern =~ s/^\s*//;
4943: $pattern =~ s/\s*$//;
4944: if ($pattern =~ /\*$/) {
4945: #35.8.*
4946: $pattern=~s/\*//;
4947: if ($ip =~ /^\Q$pattern\E/) { $allowed=1; }
4948: } elsif ($pattern =~ /(\d+\.\d+\.\d+)\.\[(\d+)-(\d+)\]$/) {
4949: #35.8.3.[34-56]
4950: my $low=$2;
4951: my $high=$3;
4952: $pattern=$1;
4953: if ($ip =~ /^\Q$pattern\E/) {
4954: my $last=(split(/\./,$ip))[3];
4955: if ($last <=$high && $last >=$low) { $allowed=1; }
4956: }
4957: } elsif ($pattern =~ /^\*/) {
4958: #*.msu.edu
4959: $pattern=~s/\*//;
4960: if (!defined($name)) {
4961: use Socket;
4962: my $netaddr=inet_aton($ip);
4963: ($name)=gethostbyaddr($netaddr,AF_INET);
4964: }
4965: if ($name =~ /\Q$pattern\E$/i) { $allowed=1; }
4966: } elsif ($pattern =~ /\d+\.\d+\.\d+\.\d+/) {
4967: #127.0.0.1
4968: if ($ip =~ /^\Q$pattern\E/) { $allowed=1; }
4969: } else {
4970: #some.name.com
4971: if (!defined($name)) {
4972: use Socket;
4973: my $netaddr=inet_aton($ip);
4974: ($name)=gethostbyaddr($netaddr,AF_INET);
4975: }
4976: if ($name =~ /\Q$pattern\E$/i) { $allowed=1; }
4977: }
4978: if ($allowed) { last; }
4979: }
4980: return $allowed;
4981: }
4982:
4983: ###############################################
4984:
1.60 matthew 4985: =pod
4986:
1.112 bowersj2 4987: =head1 Domain Template Functions
4988:
4989: =over 4
4990:
4991: =item * &determinedomain()
1.60 matthew 4992:
4993: Inputs: $domain (usually will be undef)
4994:
1.63 www 4995: Returns: Determines which domain should be used for designs
1.60 matthew 4996:
4997: =cut
1.54 www 4998:
1.60 matthew 4999: ###############################################
1.63 www 5000: sub determinedomain {
5001: my $domain=shift;
1.531 albertel 5002: if (! $domain) {
1.60 matthew 5003: # Determine domain if we have not been given one
1.893 raeburn 5004: $domain = &Apache::lonnet::default_login_domain();
1.258 albertel 5005: if ($env{'user.domain'}) { $domain=$env{'user.domain'}; }
5006: if ($env{'request.role.domain'}) {
5007: $domain=$env{'request.role.domain'};
1.60 matthew 5008: }
5009: }
1.63 www 5010: return $domain;
5011: }
5012: ###############################################
1.517 raeburn 5013:
1.518 albertel 5014: sub devalidate_domconfig_cache {
5015: my ($udom)=@_;
5016: &Apache::lonnet::devalidate_cache_new('domainconfig',$udom);
5017: }
5018:
5019: # ---------------------- Get domain configuration for a domain
5020: sub get_domainconf {
5021: my ($udom) = @_;
5022: my $cachetime=1800;
5023: my ($result,$cached)=&Apache::lonnet::is_cached_new('domainconfig',$udom);
5024: if (defined($cached)) { return %{$result}; }
5025:
5026: my %domconfig = &Apache::lonnet::get_dom('configuration',
1.948 raeburn 5027: ['login','rolecolors','autoenroll'],$udom);
1.632 raeburn 5028: my (%designhash,%legacy);
1.518 albertel 5029: if (keys(%domconfig) > 0) {
5030: if (ref($domconfig{'login'}) eq 'HASH') {
1.632 raeburn 5031: if (keys(%{$domconfig{'login'}})) {
5032: foreach my $key (keys(%{$domconfig{'login'}})) {
1.699 raeburn 5033: if (ref($domconfig{'login'}{$key}) eq 'HASH') {
1.1075.2.87 raeburn 5034: if (($key eq 'loginvia') || ($key eq 'headtag')) {
5035: if (ref($domconfig{'login'}{$key}) eq 'HASH') {
5036: foreach my $hostname (keys(%{$domconfig{'login'}{$key}})) {
5037: if (ref($domconfig{'login'}{$key}{$hostname}) eq 'HASH') {
5038: if ($key eq 'loginvia') {
5039: if ($domconfig{'login'}{'loginvia'}{$hostname}{'server'}) {
5040: my $server = $domconfig{'login'}{'loginvia'}{$hostname}{'server'};
5041: $designhash{$udom.'.login.loginvia'} = $server;
5042: if ($domconfig{'login'}{'loginvia'}{$hostname}{'serverpath'} eq 'custom') {
5043: $designhash{$udom.'.login.loginvia_'.$hostname} = $server.':'.$domconfig{'login'}{'loginvia'}{$hostname}{'custompath'};
5044: } else {
5045: $designhash{$udom.'.login.loginvia_'.$hostname} = $server.':'.$domconfig{'login'}{'loginvia'}{$hostname}{'serverpath'};
5046: }
1.948 raeburn 5047: }
1.1075.2.87 raeburn 5048: } elsif ($key eq 'headtag') {
5049: if ($domconfig{'login'}{'headtag'}{$hostname}{'url'}) {
5050: $designhash{$udom.'.login.headtag_'.$hostname} = $domconfig{'login'}{'headtag'}{$hostname}{'url'};
1.948 raeburn 5051: }
1.946 raeburn 5052: }
1.1075.2.87 raeburn 5053: if ($domconfig{'login'}{$key}{$hostname}{'exempt'}) {
5054: $designhash{$udom.'.login.'.$key.'_exempt_'.$hostname} = $domconfig{'login'}{$key}{$hostname}{'exempt'};
5055: }
1.946 raeburn 5056: }
5057: }
5058: }
5059: } else {
5060: foreach my $img (keys(%{$domconfig{'login'}{$key}})) {
5061: $designhash{$udom.'.login.'.$key.'_'.$img} =
5062: $domconfig{'login'}{$key}{$img};
5063: }
1.699 raeburn 5064: }
5065: } else {
5066: $designhash{$udom.'.login.'.$key}=$domconfig{'login'}{$key};
5067: }
1.632 raeburn 5068: }
5069: } else {
5070: $legacy{'login'} = 1;
1.518 albertel 5071: }
1.632 raeburn 5072: } else {
5073: $legacy{'login'} = 1;
1.518 albertel 5074: }
5075: if (ref($domconfig{'rolecolors'}) eq 'HASH') {
1.632 raeburn 5076: if (keys(%{$domconfig{'rolecolors'}})) {
5077: foreach my $role (keys(%{$domconfig{'rolecolors'}})) {
5078: if (ref($domconfig{'rolecolors'}{$role}) eq 'HASH') {
5079: foreach my $item (keys(%{$domconfig{'rolecolors'}{$role}})) {
5080: $designhash{$udom.'.'.$role.'.'.$item}=$domconfig{'rolecolors'}{$role}{$item};
5081: }
1.518 albertel 5082: }
5083: }
1.632 raeburn 5084: } else {
5085: $legacy{'rolecolors'} = 1;
1.518 albertel 5086: }
1.632 raeburn 5087: } else {
5088: $legacy{'rolecolors'} = 1;
1.518 albertel 5089: }
1.948 raeburn 5090: if (ref($domconfig{'autoenroll'}) eq 'HASH') {
5091: if ($domconfig{'autoenroll'}{'co-owners'}) {
5092: $designhash{$udom.'.autoassign.co-owners'}=$domconfig{'autoenroll'}{'co-owners'};
5093: }
5094: }
1.632 raeburn 5095: if (keys(%legacy) > 0) {
5096: my %legacyhash = &get_legacy_domconf($udom);
5097: foreach my $item (keys(%legacyhash)) {
5098: if ($item =~ /^\Q$udom\E\.login/) {
5099: if ($legacy{'login'}) {
5100: $designhash{$item} = $legacyhash{$item};
5101: }
5102: } else {
5103: if ($legacy{'rolecolors'}) {
5104: $designhash{$item} = $legacyhash{$item};
5105: }
1.518 albertel 5106: }
5107: }
5108: }
1.632 raeburn 5109: } else {
5110: %designhash = &get_legacy_domconf($udom);
1.518 albertel 5111: }
5112: &Apache::lonnet::do_cache_new('domainconfig',$udom,\%designhash,
5113: $cachetime);
5114: return %designhash;
5115: }
5116:
1.632 raeburn 5117: sub get_legacy_domconf {
5118: my ($udom) = @_;
5119: my %legacyhash;
5120: my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors';
5121: my $designfile = $designdir.'/'.$udom.'.tab';
5122: if (-e $designfile) {
5123: if ( open (my $fh,"<$designfile") ) {
5124: while (my $line = <$fh>) {
5125: next if ($line =~ /^\#/);
5126: chomp($line);
5127: my ($key,$val)=(split(/\=/,$line));
5128: if ($val) { $legacyhash{$udom.'.'.$key}=$val; }
5129: }
5130: close($fh);
5131: }
5132: }
1.1026 raeburn 5133: if (-e $Apache::lonnet::perlvar{'lonDocRoot'}.'/adm/lonDomLogos/'.$udom.'.gif') {
1.632 raeburn 5134: $legacyhash{$udom.'.login.domlogo'} = "/adm/lonDomLogos/$udom.gif";
5135: }
5136: return %legacyhash;
5137: }
5138:
1.63 www 5139: =pod
5140:
1.112 bowersj2 5141: =item * &domainlogo()
1.63 www 5142:
5143: Inputs: $domain (usually will be undef)
5144:
5145: Returns: A link to a domain logo, if the domain logo exists.
5146: If the domain logo does not exist, a description of the domain.
5147:
5148: =cut
1.112 bowersj2 5149:
1.63 www 5150: ###############################################
5151: sub domainlogo {
1.517 raeburn 5152: my $domain = &determinedomain(shift);
1.518 albertel 5153: my %designhash = &get_domainconf($domain);
1.517 raeburn 5154: # See if there is a logo
5155: if ($designhash{$domain.'.login.domlogo'} ne '') {
1.519 raeburn 5156: my $imgsrc = $designhash{$domain.'.login.domlogo'};
1.538 albertel 5157: if ($imgsrc =~ m{^/(adm|res)/}) {
5158: if ($imgsrc =~ m{^/res/}) {
5159: my $local_name = &Apache::lonnet::filelocation('',$imgsrc);
5160: &Apache::lonnet::repcopy($local_name);
5161: }
5162: $imgsrc = &lonhttpdurl($imgsrc);
1.519 raeburn 5163: }
5164: return '<img src="'.$imgsrc.'" alt="'.$domain.'" />';
1.514 albertel 5165: } elsif (defined(&Apache::lonnet::domain($domain,'description'))) {
5166: return &Apache::lonnet::domain($domain,'description');
1.59 www 5167: } else {
1.60 matthew 5168: return '';
1.59 www 5169: }
5170: }
1.63 www 5171: ##############################################
5172:
5173: =pod
5174:
1.112 bowersj2 5175: =item * &designparm()
1.63 www 5176:
5177: Inputs: $which parameter; $domain (usually will be undef)
5178:
5179: Returns: value of designparamter $which
5180:
5181: =cut
1.112 bowersj2 5182:
1.397 albertel 5183:
1.400 albertel 5184: ##############################################
1.397 albertel 5185: sub designparm {
5186: my ($which,$domain)=@_;
5187: if (exists($env{'environment.color.'.$which})) {
1.817 bisitz 5188: return $env{'environment.color.'.$which};
1.96 www 5189: }
1.63 www 5190: $domain=&determinedomain($domain);
1.1016 raeburn 5191: my %domdesign;
5192: unless ($domain eq 'public') {
5193: %domdesign = &get_domainconf($domain);
5194: }
1.520 raeburn 5195: my $output;
1.517 raeburn 5196: if ($domdesign{$domain.'.'.$which} ne '') {
1.817 bisitz 5197: $output = $domdesign{$domain.'.'.$which};
1.63 www 5198: } else {
1.520 raeburn 5199: $output = $defaultdesign{$which};
5200: }
5201: if (($which =~ /^(student|coordinator|author|admin)\.img$/) ||
1.635 raeburn 5202: ($which =~ /login\.(img|logo|domlogo|login)/)) {
1.538 albertel 5203: if ($output =~ m{^/(adm|res)/}) {
1.817 bisitz 5204: if ($output =~ m{^/res/}) {
5205: my $local_name = &Apache::lonnet::filelocation('',$output);
5206: &Apache::lonnet::repcopy($local_name);
5207: }
1.520 raeburn 5208: $output = &lonhttpdurl($output);
5209: }
1.63 www 5210: }
1.520 raeburn 5211: return $output;
1.63 www 5212: }
1.59 www 5213:
1.822 bisitz 5214: ##############################################
5215: =pod
5216:
1.832 bisitz 5217: =item * &authorspace()
5218:
1.1028 raeburn 5219: Inputs: $url (usually will be undef).
1.832 bisitz 5220:
1.1075.2.40 raeburn 5221: Returns: Path to Authoring Space containing the resource or
1.1028 raeburn 5222: directory being viewed (or for which action is being taken).
5223: If $url is provided, and begins /priv/<domain>/<uname>
5224: the path will be that portion of the $context argument.
5225: Otherwise the path will be for the author space of the current
5226: user when the current role is author, or for that of the
5227: co-author/assistant co-author space when the current role
5228: is co-author or assistant co-author.
1.832 bisitz 5229:
5230: =cut
5231:
5232: sub authorspace {
1.1028 raeburn 5233: my ($url) = @_;
5234: if ($url ne '') {
5235: if ($url =~ m{^(/priv/$match_domain/$match_username/)}) {
5236: return $1;
5237: }
5238: }
1.832 bisitz 5239: my $caname = '';
1.1024 www 5240: my $cadom = '';
1.1028 raeburn 5241: if ($env{'request.role'} =~ /^(?:ca|aa)/) {
1.1024 www 5242: ($cadom,$caname) =
1.832 bisitz 5243: ($env{'request.role'}=~/($match_domain)\/($match_username)$/);
1.1028 raeburn 5244: } elsif ($env{'request.role'} =~ m{^au\./($match_domain)/}) {
1.832 bisitz 5245: $caname = $env{'user.name'};
1.1024 www 5246: $cadom = $env{'user.domain'};
1.832 bisitz 5247: }
1.1028 raeburn 5248: if (($caname ne '') && ($cadom ne '')) {
5249: return "/priv/$cadom/$caname/";
5250: }
5251: return;
1.832 bisitz 5252: }
5253:
5254: ##############################################
5255: =pod
5256:
1.822 bisitz 5257: =item * &head_subbox()
5258:
5259: Inputs: $content (contains HTML code with page functions, etc.)
5260:
5261: Returns: HTML div with $content
5262: To be included in page header
5263:
5264: =cut
5265:
5266: sub head_subbox {
5267: my ($content)=@_;
5268: my $output =
1.993 raeburn 5269: '<div class="LC_head_subbox">'
1.822 bisitz 5270: .$content
5271: .'</div>'
5272: }
5273:
5274: ##############################################
5275: =pod
5276:
5277: =item * &CSTR_pageheader()
5278:
1.1026 raeburn 5279: Input: (optional) filename from which breadcrumb trail is built.
5280: In most cases no input as needed, as $env{'request.filename'}
5281: is appropriate for use in building the breadcrumb trail.
1.822 bisitz 5282:
5283: Returns: HTML div with CSTR path and recent box
1.1075.2.40 raeburn 5284: To be included on Authoring Space pages
1.822 bisitz 5285:
5286: =cut
5287:
5288: sub CSTR_pageheader {
1.1026 raeburn 5289: my ($trailfile) = @_;
5290: if ($trailfile eq '') {
5291: $trailfile = $env{'request.filename'};
5292: }
5293:
5294: # this is for resources; directories have customtitle, and crumbs
5295: # and select recent are created in lonpubdir.pm
5296:
5297: my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'};
1.1022 www 5298: my ($udom,$uname,$thisdisfn)=
1.1075.2.29 raeburn 5299: ($trailfile =~ m{^\Q$londocroot\E/priv/([^/]+)/([^/]+)(?:|/(.*))$});
1.1026 raeburn 5300: my $formaction = "/priv/$udom/$uname/$thisdisfn";
5301: $formaction =~ s{/+}{/}g;
1.822 bisitz 5302:
5303: my $parentpath = '';
5304: my $lastitem = '';
5305: if ($thisdisfn =~ m-(.+/)([^/]*)$-) {
5306: $parentpath = $1;
5307: $lastitem = $2;
5308: } else {
5309: $lastitem = $thisdisfn;
5310: }
1.921 bisitz 5311:
5312: my $output =
1.822 bisitz 5313: '<div>'
5314: .&Apache::loncommon::help_open_menu('','',3,'Authoring') #FIXME: Broken? Where is it?
1.1075.2.40 raeburn 5315: .'<b>'.&mt('Authoring Space:').'</b> '
1.822 bisitz 5316: .'<form name="dirs" method="post" action="'.$formaction
1.921 bisitz 5317: .'" target="_top">' #FIXME lonpubdir: target="_parent"
1.1024 www 5318: .&Apache::lonhtmlcommon::crumbs($uname.'/'.$parentpath,'_top','/priv/'.$udom,undef,undef);
1.921 bisitz 5319:
5320: if ($lastitem) {
5321: $output .=
5322: '<span class="LC_filename">'
5323: .$lastitem
5324: .'</span>';
5325: }
5326: $output .=
5327: '<br />'
1.822 bisitz 5328: #FIXME lonpubdir: &Apache::lonhtmlcommon::crumbs($uname.$thisdisfn.'/','_top','/priv','','+1',1)."</b></tt><br />"
5329: .&Apache::lonhtmlcommon::select_recent('construct','recent','this.form.action=this.form.recent.value;this.form.submit()')
5330: .'</form>'
5331: .&Apache::lonmenu::constspaceform()
5332: .'</div>';
1.921 bisitz 5333:
5334: return $output;
1.822 bisitz 5335: }
5336:
1.60 matthew 5337: ###############################################
5338: ###############################################
5339:
5340: =pod
5341:
1.112 bowersj2 5342: =back
5343:
1.549 albertel 5344: =head1 HTML Helpers
1.112 bowersj2 5345:
5346: =over 4
5347:
5348: =item * &bodytag()
1.60 matthew 5349:
5350: Returns a uniform header for LON-CAPA web pages.
5351:
5352: Inputs:
5353:
1.112 bowersj2 5354: =over 4
5355:
5356: =item * $title, A title to be displayed on the page.
5357:
5358: =item * $function, the current role (can be undef).
5359:
5360: =item * $addentries, extra parameters for the <body> tag.
5361:
5362: =item * $bodyonly, if defined, only return the <body> tag.
5363:
5364: =item * $domain, if defined, force a given domain.
5365:
5366: =item * $forcereg, if page should register as content page (relevant for
1.86 www 5367: text interface only)
1.60 matthew 5368:
1.814 bisitz 5369: =item * $no_nav_bar, if true, keep the 'what is this' info but remove the
5370: navigational links
1.317 albertel 5371:
1.338 albertel 5372: =item * $bgcolor, used to override the bgcolor on a webpage to a specific value
5373:
1.1075.2.12 raeburn 5374: =item * $no_inline_link, if true and in remote mode, don't show the
5375: 'Switch To Inline Menu' link
5376:
1.460 albertel 5377: =item * $args, optional argument valid values are
5378: no_auto_mt_title -> prevents &mt()ing the title arg
5379:
1.1075.2.15 raeburn 5380: =item * $advtoolsref, optional argument, ref to an array containing
5381: inlineremote items to be added in "Functions" menu below
5382: breadcrumbs.
5383:
1.112 bowersj2 5384: =back
5385:
1.60 matthew 5386: Returns: A uniform header for LON-CAPA web pages.
5387: If $bodyonly is nonzero, a string containing a <body> tag will be returned.
5388: If $bodyonly is undef or zero, an html string containing a <body> tag and
5389: other decorations will be returned.
5390:
5391: =cut
5392:
1.54 www 5393: sub bodytag {
1.831 bisitz 5394: my ($title,$function,$addentries,$bodyonly,$domain,$forcereg,
1.1075.2.15 raeburn 5395: $no_nav_bar,$bgcolor,$no_inline_link,$args,$advtoolsref)=@_;
1.339 albertel 5396:
1.954 raeburn 5397: my $public;
5398: if ((($env{'user.name'} eq 'public') && ($env{'user.domain'} eq 'public'))
5399: || ($env{'user.name'} eq '') && ($env{'user.domain'} eq '')) {
5400: $public = 1;
5401: }
1.460 albertel 5402: if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); }
1.1075.2.52 raeburn 5403: my $httphost = $args->{'use_absolute'};
1.339 albertel 5404:
1.183 matthew 5405: $function = &get_users_function() if (!$function);
1.339 albertel 5406: my $img = &designparm($function.'.img',$domain);
5407: my $font = &designparm($function.'.font',$domain);
5408: my $pgbg = $bgcolor || &designparm($function.'.pgbg',$domain);
5409:
1.803 bisitz 5410: my %design = ( 'style' => 'margin-top: 0',
1.535 albertel 5411: 'bgcolor' => $pgbg,
1.339 albertel 5412: 'text' => $font,
5413: 'alink' => &designparm($function.'.alink',$domain),
5414: 'vlink' => &designparm($function.'.vlink',$domain),
5415: 'link' => &designparm($function.'.link',$domain),);
1.438 albertel 5416: @design{keys(%$addentries)} = @$addentries{keys(%$addentries)};
1.339 albertel 5417:
1.63 www 5418: # role and realm
1.1075.2.68 raeburn 5419: my ($role,$realm) = split(m{\./},$env{'request.role'},2);
5420: if ($realm) {
5421: $realm = '/'.$realm;
5422: }
1.378 raeburn 5423: if ($role eq 'ca') {
1.479 albertel 5424: my ($rdom,$rname) = ($realm =~ m{^/($match_domain)/($match_username)$});
1.500 albertel 5425: $realm = &plainname($rname,$rdom);
1.378 raeburn 5426: }
1.55 www 5427: # realm
1.258 albertel 5428: if ($env{'request.course.id'}) {
1.378 raeburn 5429: if ($env{'request.role'} !~ /^cr/) {
5430: $role = &Apache::lonnet::plaintext($role,&course_type());
1.1075.2.115! raeburn 5431: } elsif ($role =~ m{^cr/($match_domain)/\1-domainconfig/(\w+)$}) {
! 5432: $role = &mt('Helpdesk[_1]',' '.$2);
! 5433: } else {
! 5434: $role = (split(/\//,$role,4))[-1];
1.378 raeburn 5435: }
1.898 raeburn 5436: if ($env{'request.course.sec'}) {
5437: $role .= (' 'x2).'- '.&mt('section:').' '.$env{'request.course.sec'};
5438: }
1.359 albertel 5439: $realm = $env{'course.'.$env{'request.course.id'}.'.description'};
1.378 raeburn 5440: } else {
5441: $role = &Apache::lonnet::plaintext($role);
1.54 www 5442: }
1.433 albertel 5443:
1.359 albertel 5444: if (!$realm) { $realm=' '; }
1.330 albertel 5445:
1.438 albertel 5446: my $extra_body_attr = &make_attr_string($forcereg,\%design);
1.329 albertel 5447:
1.101 www 5448: # construct main body tag
1.359 albertel 5449: my $bodytag = "<body $extra_body_attr>".
1.1075.2.100 raeburn 5450: &Apache::lontexconvert::init_math_support();
1.252 albertel 5451:
1.1075.2.38 raeburn 5452: &get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['inhibitmenu']);
5453:
5454: if (($bodyonly) || ($no_nav_bar) || ($env{'form.inhibitmenu'} eq 'yes')) {
1.60 matthew 5455: return $bodytag;
1.1075.2.38 raeburn 5456: }
1.359 albertel 5457:
1.954 raeburn 5458: if ($public) {
1.433 albertel 5459: undef($role);
5460: }
1.359 albertel 5461:
1.762 bisitz 5462: my $titleinfo = '<h1>'.$title.'</h1>';
1.359 albertel 5463: #
5464: # Extra info if you are the DC
5465: my $dc_info = '';
5466: if ($env{'user.adv'} && exists($env{'user.role.dc./'.
5467: $env{'course.'.$env{'request.course.id'}.
5468: '.domain'}.'/'})) {
5469: my $cid = $env{'request.course.id'};
1.917 raeburn 5470: $dc_info = $cid.' '.$env{'course.'.$cid.'.internal.coursecode'};
1.380 www 5471: $dc_info =~ s/\s+$//;
1.359 albertel 5472: }
5473:
1.1075.2.108 raeburn 5474: $role = '<span class="LC_nobreak">('.$role.')</span>' if ($role && !$env{'browser.mobile'});
1.903 droeschl 5475:
1.1075.2.13 raeburn 5476: if ($env{'request.state'} eq 'construct') { $forcereg=1; }
5477:
1.1075.2.38 raeburn 5478:
5479:
1.1075.2.21 raeburn 5480: my $funclist;
5481: if (($env{'environment.remote'} eq 'on') && ($env{'request.state'} ne 'construct')) {
1.1075.2.52 raeburn 5482: $bodytag .= Apache::lonhtmlcommon::scripttag(Apache::lonmenu::utilityfunctions($httphost), 'start')."\n".
1.1075.2.21 raeburn 5483: Apache::lonmenu::serverform();
5484: my $forbodytag;
5485: &Apache::lonmenu::prepare_functions($env{'request.noversionuri'},
5486: $forcereg,$args->{'group'},
5487: $args->{'bread_crumbs'},
5488: $advtoolsref,'',\$forbodytag);
5489: unless (ref($args->{'bread_crumbs'}) eq 'ARRAY') {
5490: $funclist = $forbodytag;
5491: }
5492: } else {
1.903 droeschl 5493:
5494: # if ($env{'request.state'} eq 'construct') {
5495: # $titleinfo = &CSTR_pageheader(); #FIXME: Will be removed once all scripts have their own calls
5496: # }
5497:
1.1075.2.38 raeburn 5498: $bodytag .= Apache::lonhtmlcommon::scripttag(
1.1075.2.52 raeburn 5499: Apache::lonmenu::utilityfunctions($httphost), 'start');
1.359 albertel 5500:
1.1075.2.38 raeburn 5501: my ($left,$right) = Apache::lonmenu::primary_menu();
1.1075.2.2 raeburn 5502:
1.916 droeschl 5503: if ($env{'request.noversionuri'} =~ m{^/res/adm/pages/}) {
1.1075.2.22 raeburn 5504: if ($dc_info) {
5505: $dc_info = qq|<span class="LC_cusr_subheading">$dc_info</span>|;
1.1075.2.1 raeburn 5506: }
1.1075.2.38 raeburn 5507: $bodytag .= qq|<div id="LC_nav_bar">$left $role<br />
1.1075.2.22 raeburn 5508: <em>$realm</em> $dc_info</div>|;
1.903 droeschl 5509: return $bodytag;
5510: }
1.894 droeschl 5511:
1.927 raeburn 5512: unless ($env{'request.symb'} =~ m/\.page___\d+___/) {
1.1075.2.38 raeburn 5513: $bodytag .= qq|<div id="LC_nav_bar">$left $role</div>|;
1.927 raeburn 5514: }
1.916 droeschl 5515:
1.1075.2.38 raeburn 5516: $bodytag .= $right;
1.852 droeschl 5517:
1.917 raeburn 5518: if ($dc_info) {
5519: $dc_info = &dc_courseid_toggle($dc_info);
5520: }
5521: $bodytag .= qq|<div id="LC_realm">$realm $dc_info</div>|;
1.916 droeschl 5522:
1.1075.2.61 raeburn 5523: #if directed to not display the secondary menu, don't.
5524: if ($args->{'no_secondary_menu'}) {
5525: return $bodytag;
5526: }
1.903 droeschl 5527: #don't show menus for public users
1.954 raeburn 5528: if (!$public){
1.1075.2.52 raeburn 5529: $bodytag .= Apache::lonmenu::secondary_menu($httphost);
1.903 droeschl 5530: $bodytag .= Apache::lonmenu::serverform();
1.920 raeburn 5531: $bodytag .= Apache::lonhtmlcommon::scripttag('', 'end');
5532: if ($env{'request.state'} eq 'construct') {
1.962 droeschl 5533: $bodytag .= &Apache::lonmenu::innerregister($forcereg,
1.920 raeburn 5534: $args->{'bread_crumbs'});
5535: } elsif ($forcereg) {
1.1075.2.22 raeburn 5536: $bodytag .= &Apache::lonmenu::innerregister($forcereg,undef,
5537: $args->{'group'});
1.1075.2.15 raeburn 5538: } else {
1.1075.2.21 raeburn 5539: my $forbodytag;
5540: &Apache::lonmenu::prepare_functions($env{'request.noversionuri'},
5541: $forcereg,$args->{'group'},
5542: $args->{'bread_crumbs'},
5543: $advtoolsref,'',\$forbodytag);
5544: unless (ref($args->{'bread_crumbs'}) eq 'ARRAY') {
5545: $bodytag .= $forbodytag;
5546: }
1.920 raeburn 5547: }
1.903 droeschl 5548: }else{
5549: # this is to seperate menu from content when there's no secondary
5550: # menu. Especially needed for public accessible ressources.
5551: $bodytag .= '<hr style="clear:both" />';
5552: $bodytag .= Apache::lonhtmlcommon::scripttag('', 'end');
1.235 raeburn 5553: }
1.903 droeschl 5554:
1.235 raeburn 5555: return $bodytag;
1.1075.2.12 raeburn 5556: }
5557:
5558: #
5559: # Top frame rendering, Remote is up
5560: #
5561:
5562: my $imgsrc = $img;
5563: if ($img =~ /^\/adm/) {
5564: $imgsrc = &lonhttpdurl($img);
5565: }
5566: my $upperleft='<img src="'.$imgsrc.'" alt="'.$function.'" />';
5567:
1.1075.2.60 raeburn 5568: my $help=($no_inline_link?''
5569: :&Apache::loncommon::top_nav_help('Help'));
5570:
1.1075.2.12 raeburn 5571: # Explicit link to get inline menu
5572: my $menu= ($no_inline_link?''
5573: :'<a href="/adm/remote?action=collapse" target="_top">'.&mt('Switch to Inline Menu Mode').'</a>');
5574:
5575: if ($dc_info) {
5576: $dc_info = qq|<span class="LC_cusr_subheading">($dc_info)</span>|;
5577: }
5578:
1.1075.2.38 raeburn 5579: my $name = &plainname($env{'user.name'},$env{'user.domain'});
5580: unless ($public) {
5581: $name = &aboutmewrapper($name,$env{'user.name'},$env{'user.domain'},
5582: undef,'LC_menubuttons_link');
5583: }
5584:
1.1075.2.12 raeburn 5585: unless ($env{'form.inhibitmenu'}) {
5586: $bodytag .= qq|<div id="LC_nav_bar">$name $role</div>
1.1075.2.38 raeburn 5587: <ol class="LC_primary_menu LC_floatright LC_right">
1.1075.2.60 raeburn 5588: <li>$help</li>
1.1075.2.12 raeburn 5589: <li>$menu</li>
5590: </ol><div id="LC_realm"> $realm $dc_info</div>|;
5591: }
1.1075.2.13 raeburn 5592: if ($env{'request.state'} eq 'construct') {
5593: if (!$public){
5594: if ($env{'request.state'} eq 'construct') {
5595: $funclist = &Apache::lonhtmlcommon::scripttag(
1.1075.2.52 raeburn 5596: &Apache::lonmenu::utilityfunctions($httphost), 'start').
1.1075.2.13 raeburn 5597: &Apache::lonhtmlcommon::scripttag('','end').
5598: &Apache::lonmenu::innerregister($forcereg,
5599: $args->{'bread_crumbs'});
5600: }
5601: }
5602: }
1.1075.2.21 raeburn 5603: return $bodytag."\n".$funclist;
1.182 matthew 5604: }
5605:
1.917 raeburn 5606: sub dc_courseid_toggle {
5607: my ($dc_info) = @_;
1.980 raeburn 5608: return ' <span id="dccidtext" class="LC_cusr_subheading LC_nobreak">'.
1.1069 raeburn 5609: '<a href="javascript:showCourseID();" class="LC_menubuttons_link">'.
1.917 raeburn 5610: &mt('(More ...)').'</a></span>'.
5611: '<div id="dccid" class="LC_dccid">'.$dc_info.'</div>';
5612: }
5613:
1.330 albertel 5614: sub make_attr_string {
5615: my ($register,$attr_ref) = @_;
5616:
5617: if ($attr_ref && !ref($attr_ref)) {
5618: die("addentries Must be a hash ref ".
5619: join(':',caller(1))." ".
5620: join(':',caller(0))." ");
5621: }
5622:
5623: if ($register) {
1.339 albertel 5624: my ($on_load,$on_unload);
5625: foreach my $key (keys(%{$attr_ref})) {
5626: if (lc($key) eq 'onload') {
5627: $on_load.=$attr_ref->{$key}.';';
5628: delete($attr_ref->{$key});
5629:
5630: } elsif (lc($key) eq 'onunload') {
5631: $on_unload.=$attr_ref->{$key}.';';
5632: delete($attr_ref->{$key});
5633: }
5634: }
1.1075.2.12 raeburn 5635: if ($env{'environment.remote'} eq 'on') {
5636: $attr_ref->{'onload'} =
5637: &Apache::lonmenu::loadevents(). $on_load;
5638: $attr_ref->{'onunload'}=
5639: &Apache::lonmenu::unloadevents().$on_unload;
5640: } else {
5641: $attr_ref->{'onload'} = $on_load;
5642: $attr_ref->{'onunload'}= $on_unload;
5643: }
1.330 albertel 5644: }
1.339 albertel 5645:
1.330 albertel 5646: my $attr_string;
1.1075.2.56 raeburn 5647: foreach my $attr (sort(keys(%$attr_ref))) {
1.330 albertel 5648: $attr_string .= " $attr=\"".$attr_ref->{$attr}.'" ';
5649: }
5650: return $attr_string;
5651: }
5652:
5653:
1.182 matthew 5654: ###############################################
1.251 albertel 5655: ###############################################
5656:
5657: =pod
5658:
5659: =item * &endbodytag()
5660:
5661: Returns a uniform footer for LON-CAPA web pages.
5662:
1.635 raeburn 5663: Inputs: 1 - optional reference to an args hash
5664: If in the hash, key for noredirectlink has a value which evaluates to true,
5665: a 'Continue' link is not displayed if the page contains an
5666: internal redirect in the <head></head> section,
5667: i.e., $env{'internal.head.redirect'} exists
1.251 albertel 5668:
5669: =cut
5670:
5671: sub endbodytag {
1.635 raeburn 5672: my ($args) = @_;
1.1075.2.6 raeburn 5673: my $endbodytag;
5674: unless ((ref($args) eq 'HASH') && ($args->{'notbody'})) {
5675: $endbodytag='</body>';
5676: }
1.315 albertel 5677: if ( exists( $env{'internal.head.redirect'} ) ) {
1.635 raeburn 5678: if (!(ref($args) eq 'HASH' && $args->{'noredirectlink'})) {
5679: $endbodytag=
5680: "<br /><a href=\"$env{'internal.head.redirect'}\">".
5681: &mt('Continue').'</a>'.
5682: $endbodytag;
5683: }
1.315 albertel 5684: }
1.251 albertel 5685: return $endbodytag;
5686: }
5687:
1.352 albertel 5688: =pod
5689:
5690: =item * &standard_css()
5691:
5692: Returns a style sheet
5693:
5694: Inputs: (all optional)
5695: domain -> force to color decorate a page for a specific
5696: domain
5697: function -> force usage of a specific rolish color scheme
5698: bgcolor -> override the default page bgcolor
5699:
5700: =cut
5701:
1.343 albertel 5702: sub standard_css {
1.345 albertel 5703: my ($function,$domain,$bgcolor) = @_;
1.352 albertel 5704: $function = &get_users_function() if (!$function);
5705: my $img = &designparm($function.'.img', $domain);
5706: my $tabbg = &designparm($function.'.tabbg', $domain);
5707: my $font = &designparm($function.'.font', $domain);
1.801 tempelho 5708: my $fontmenu = &designparm($function.'.fontmenu', $domain);
1.791 tempelho 5709: #second colour for later usage
1.345 albertel 5710: my $sidebg = &designparm($function.'.sidebg',$domain);
1.382 albertel 5711: my $pgbg_or_bgcolor =
5712: $bgcolor ||
1.352 albertel 5713: &designparm($function.'.pgbg', $domain);
1.382 albertel 5714: my $pgbg = &designparm($function.'.pgbg', $domain);
1.352 albertel 5715: my $alink = &designparm($function.'.alink', $domain);
5716: my $vlink = &designparm($function.'.vlink', $domain);
5717: my $link = &designparm($function.'.link', $domain);
5718:
1.602 albertel 5719: my $sans = 'Verdana,Arial,Helvetica,sans-serif';
1.395 albertel 5720: my $mono = 'monospace';
1.850 bisitz 5721: my $data_table_head = $sidebg;
5722: my $data_table_light = '#FAFAFA';
1.1060 bisitz 5723: my $data_table_dark = '#E0E0E0';
1.470 banghart 5724: my $data_table_darker = '#CCCCCC';
1.349 albertel 5725: my $data_table_highlight = '#FFFF00';
1.352 albertel 5726: my $mail_new = '#FFBB77';
5727: my $mail_new_hover = '#DD9955';
5728: my $mail_read = '#BBBB77';
5729: my $mail_read_hover = '#999944';
5730: my $mail_replied = '#AAAA88';
5731: my $mail_replied_hover = '#888855';
5732: my $mail_other = '#99BBBB';
5733: my $mail_other_hover = '#669999';
1.391 albertel 5734: my $table_header = '#DDDDDD';
1.489 raeburn 5735: my $feedback_link_bg = '#BBBBBB';
1.911 bisitz 5736: my $lg_border_color = '#C8C8C8';
1.952 onken 5737: my $button_hover = '#BF2317';
1.392 albertel 5738:
1.608 albertel 5739: my $border = ($env{'browser.type'} eq 'explorer' ||
1.911 bisitz 5740: $env{'browser.type'} eq 'safari' ) ? '0 2px 0 2px'
5741: : '0 3px 0 4px';
1.448 albertel 5742:
1.523 albertel 5743:
1.343 albertel 5744: return <<END;
1.947 droeschl 5745:
5746: /* needed for iframe to allow 100% height in FF */
5747: body, html {
5748: margin: 0;
5749: padding: 0 0.5%;
5750: height: 99%; /* to avoid scrollbars */
5751: }
5752:
1.795 www 5753: body {
1.911 bisitz 5754: font-family: $sans;
5755: line-height:130%;
5756: font-size:0.83em;
5757: color:$font;
1.795 www 5758: }
5759:
1.959 onken 5760: a:focus,
5761: a:focus img {
1.795 www 5762: color: red;
5763: }
1.698 harmsja 5764:
1.911 bisitz 5765: form, .inline {
5766: display: inline;
1.795 www 5767: }
1.721 harmsja 5768:
1.795 www 5769: .LC_right {
1.911 bisitz 5770: text-align:right;
1.795 www 5771: }
5772:
5773: .LC_middle {
1.911 bisitz 5774: vertical-align:middle;
1.795 www 5775: }
1.721 harmsja 5776:
1.1075.2.38 raeburn 5777: .LC_floatleft {
5778: float: left;
5779: }
5780:
5781: .LC_floatright {
5782: float: right;
5783: }
5784:
1.911 bisitz 5785: .LC_400Box {
5786: width:400px;
5787: }
1.721 harmsja 5788:
1.947 droeschl 5789: .LC_iframecontainer {
5790: width: 98%;
5791: margin: 0;
5792: position: fixed;
5793: top: 8.5em;
5794: bottom: 0;
5795: }
5796:
5797: .LC_iframecontainer iframe{
5798: border: none;
5799: width: 100%;
5800: height: 100%;
5801: }
5802:
1.778 bisitz 5803: .LC_filename {
5804: font-family: $mono;
5805: white-space:pre;
1.921 bisitz 5806: font-size: 120%;
1.778 bisitz 5807: }
5808:
5809: .LC_fileicon {
5810: border: none;
5811: height: 1.3em;
5812: vertical-align: text-bottom;
5813: margin-right: 0.3em;
5814: text-decoration:none;
5815: }
5816:
1.1008 www 5817: .LC_setting {
5818: text-decoration:underline;
5819: }
5820:
1.350 albertel 5821: .LC_error {
5822: color: red;
5823: }
1.795 www 5824:
1.1075.2.15 raeburn 5825: .LC_warning {
5826: color: darkorange;
5827: }
5828:
1.457 albertel 5829: .LC_diff_removed {
1.733 bisitz 5830: color: red;
1.394 albertel 5831: }
1.532 albertel 5832:
5833: .LC_info,
1.457 albertel 5834: .LC_success,
5835: .LC_diff_added {
1.350 albertel 5836: color: green;
5837: }
1.795 www 5838:
1.802 bisitz 5839: div.LC_confirm_box {
5840: background-color: #FAFAFA;
5841: border: 1px solid $lg_border_color;
5842: margin-right: 0;
5843: padding: 5px;
5844: }
5845:
5846: div.LC_confirm_box .LC_error img,
5847: div.LC_confirm_box .LC_success img {
5848: vertical-align: middle;
5849: }
5850:
1.1075.2.108 raeburn 5851: .LC_maxwidth {
5852: max-width: 100%;
5853: height: auto;
5854: }
5855:
5856: .LC_textsize_mobile {
5857: \@media only screen and (max-device-width: 480px) {
5858: -webkit-text-size-adjust:100%; -moz-text-size-adjust:100%; -ms-text-size-adjust:100%;
5859: }
5860: }
5861:
1.440 albertel 5862: .LC_icon {
1.771 droeschl 5863: border: none;
1.790 droeschl 5864: vertical-align: middle;
1.771 droeschl 5865: }
5866:
1.543 albertel 5867: .LC_docs_spacer {
5868: width: 25px;
5869: height: 1px;
1.771 droeschl 5870: border: none;
1.543 albertel 5871: }
1.346 albertel 5872:
1.532 albertel 5873: .LC_internal_info {
1.735 bisitz 5874: color: #999999;
1.532 albertel 5875: }
5876:
1.794 www 5877: .LC_discussion {
1.1050 www 5878: background: $data_table_dark;
1.911 bisitz 5879: border: 1px solid black;
5880: margin: 2px;
1.794 www 5881: }
5882:
5883: .LC_disc_action_left {
1.1050 www 5884: background: $sidebg;
1.911 bisitz 5885: text-align: left;
1.1050 www 5886: padding: 4px;
5887: margin: 2px;
1.794 www 5888: }
5889:
5890: .LC_disc_action_right {
1.1050 www 5891: background: $sidebg;
1.911 bisitz 5892: text-align: right;
1.1050 www 5893: padding: 4px;
5894: margin: 2px;
1.794 www 5895: }
5896:
5897: .LC_disc_new_item {
1.911 bisitz 5898: background: white;
5899: border: 2px solid red;
1.1050 www 5900: margin: 4px;
5901: padding: 4px;
1.794 www 5902: }
5903:
5904: .LC_disc_old_item {
1.911 bisitz 5905: background: white;
1.1050 www 5906: margin: 4px;
5907: padding: 4px;
1.794 www 5908: }
5909:
1.458 albertel 5910: table.LC_pastsubmission {
5911: border: 1px solid black;
5912: margin: 2px;
5913: }
5914:
1.924 bisitz 5915: table#LC_menubuttons {
1.345 albertel 5916: width: 100%;
5917: background: $pgbg;
1.392 albertel 5918: border: 2px;
1.402 albertel 5919: border-collapse: separate;
1.803 bisitz 5920: padding: 0;
1.345 albertel 5921: }
1.392 albertel 5922:
1.801 tempelho 5923: table#LC_title_bar a {
5924: color: $fontmenu;
5925: }
1.836 bisitz 5926:
1.807 droeschl 5927: table#LC_title_bar {
1.819 tempelho 5928: clear: both;
1.836 bisitz 5929: display: none;
1.807 droeschl 5930: }
5931:
1.795 www 5932: table#LC_title_bar,
1.933 droeschl 5933: table.LC_breadcrumbs, /* obsolete? */
1.393 albertel 5934: table#LC_title_bar.LC_with_remote {
1.359 albertel 5935: width: 100%;
1.392 albertel 5936: border-color: $pgbg;
5937: border-style: solid;
5938: border-width: $border;
1.379 albertel 5939: background: $pgbg;
1.801 tempelho 5940: color: $fontmenu;
1.392 albertel 5941: border-collapse: collapse;
1.803 bisitz 5942: padding: 0;
1.819 tempelho 5943: margin: 0;
1.359 albertel 5944: }
1.795 www 5945:
1.933 droeschl 5946: ul.LC_breadcrumb_tools_outerlist {
1.913 droeschl 5947: margin: 0;
5948: padding: 0;
1.933 droeschl 5949: position: relative;
5950: list-style: none;
1.913 droeschl 5951: }
1.933 droeschl 5952: ul.LC_breadcrumb_tools_outerlist li {
1.913 droeschl 5953: display: inline;
5954: }
1.933 droeschl 5955:
5956: .LC_breadcrumb_tools_navigation {
1.913 droeschl 5957: padding: 0;
1.933 droeschl 5958: margin: 0;
5959: float: left;
1.913 droeschl 5960: }
1.933 droeschl 5961: .LC_breadcrumb_tools_tools {
5962: padding: 0;
5963: margin: 0;
1.913 droeschl 5964: float: right;
5965: }
5966:
1.359 albertel 5967: table#LC_title_bar td {
5968: background: $tabbg;
5969: }
1.795 www 5970:
1.911 bisitz 5971: table#LC_menubuttons img {
1.803 bisitz 5972: border: none;
1.346 albertel 5973: }
1.795 www 5974:
1.842 droeschl 5975: .LC_breadcrumbs_component {
1.911 bisitz 5976: float: right;
5977: margin: 0 1em;
1.357 albertel 5978: }
1.842 droeschl 5979: .LC_breadcrumbs_component img {
1.911 bisitz 5980: vertical-align: middle;
1.777 tempelho 5981: }
1.795 www 5982:
1.1075.2.108 raeburn 5983: .LC_breadcrumbs_hoverable {
5984: background: $sidebg;
5985: }
5986:
1.383 albertel 5987: td.LC_table_cell_checkbox {
5988: text-align: center;
5989: }
1.795 www 5990:
5991: .LC_fontsize_small {
1.911 bisitz 5992: font-size: 70%;
1.705 tempelho 5993: }
5994:
1.844 bisitz 5995: #LC_breadcrumbs {
1.911 bisitz 5996: clear:both;
5997: background: $sidebg;
5998: border-bottom: 1px solid $lg_border_color;
5999: line-height: 2.5em;
1.933 droeschl 6000: overflow: hidden;
1.911 bisitz 6001: margin: 0;
6002: padding: 0;
1.995 raeburn 6003: text-align: left;
1.819 tempelho 6004: }
1.862 bisitz 6005:
1.1075.2.16 raeburn 6006: .LC_head_subbox, .LC_actionbox {
1.911 bisitz 6007: clear:both;
6008: background: #F8F8F8; /* $sidebg; */
1.915 droeschl 6009: border: 1px solid $sidebg;
1.1075.2.16 raeburn 6010: margin: 0 0 10px 0;
1.966 bisitz 6011: padding: 3px;
1.995 raeburn 6012: text-align: left;
1.822 bisitz 6013: }
6014:
1.795 www 6015: .LC_fontsize_medium {
1.911 bisitz 6016: font-size: 85%;
1.705 tempelho 6017: }
6018:
1.795 www 6019: .LC_fontsize_large {
1.911 bisitz 6020: font-size: 120%;
1.705 tempelho 6021: }
6022:
1.346 albertel 6023: .LC_menubuttons_inline_text {
6024: color: $font;
1.698 harmsja 6025: font-size: 90%;
1.701 harmsja 6026: padding-left:3px;
1.346 albertel 6027: }
6028:
1.934 droeschl 6029: .LC_menubuttons_inline_text img{
6030: vertical-align: middle;
6031: }
6032:
1.1051 www 6033: li.LC_menubuttons_inline_text img {
1.951 onken 6034: cursor:pointer;
1.1002 droeschl 6035: text-decoration: none;
1.951 onken 6036: }
6037:
1.526 www 6038: .LC_menubuttons_link {
6039: text-decoration: none;
6040: }
1.795 www 6041:
1.522 albertel 6042: .LC_menubuttons_category {
1.521 www 6043: color: $font;
1.526 www 6044: background: $pgbg;
1.521 www 6045: font-size: larger;
6046: font-weight: bold;
6047: }
6048:
1.346 albertel 6049: td.LC_menubuttons_text {
1.911 bisitz 6050: color: $font;
1.346 albertel 6051: }
1.706 harmsja 6052:
1.346 albertel 6053: .LC_current_location {
6054: background: $tabbg;
6055: }
1.795 www 6056:
1.938 bisitz 6057: table.LC_data_table {
1.347 albertel 6058: border: 1px solid #000000;
1.402 albertel 6059: border-collapse: separate;
1.426 albertel 6060: border-spacing: 1px;
1.610 albertel 6061: background: $pgbg;
1.347 albertel 6062: }
1.795 www 6063:
1.422 albertel 6064: .LC_data_table_dense {
6065: font-size: small;
6066: }
1.795 www 6067:
1.507 raeburn 6068: table.LC_nested_outer {
6069: border: 1px solid #000000;
1.589 raeburn 6070: border-collapse: collapse;
1.803 bisitz 6071: border-spacing: 0;
1.507 raeburn 6072: width: 100%;
6073: }
1.795 www 6074:
1.879 raeburn 6075: table.LC_innerpickbox,
1.507 raeburn 6076: table.LC_nested {
1.803 bisitz 6077: border: none;
1.589 raeburn 6078: border-collapse: collapse;
1.803 bisitz 6079: border-spacing: 0;
1.507 raeburn 6080: width: 100%;
6081: }
1.795 www 6082:
1.911 bisitz 6083: table.LC_data_table tr th,
6084: table.LC_calendar tr th,
1.879 raeburn 6085: table.LC_prior_tries tr th,
6086: table.LC_innerpickbox tr th {
1.349 albertel 6087: font-weight: bold;
6088: background-color: $data_table_head;
1.801 tempelho 6089: color:$fontmenu;
1.701 harmsja 6090: font-size:90%;
1.347 albertel 6091: }
1.795 www 6092:
1.879 raeburn 6093: table.LC_innerpickbox tr th,
6094: table.LC_innerpickbox tr td {
6095: vertical-align: top;
6096: }
6097:
1.711 raeburn 6098: table.LC_data_table tr.LC_info_row > td {
1.735 bisitz 6099: background-color: #CCCCCC;
1.711 raeburn 6100: font-weight: bold;
6101: text-align: left;
6102: }
1.795 www 6103:
1.912 bisitz 6104: table.LC_data_table tr.LC_odd_row > td {
6105: background-color: $data_table_light;
6106: padding: 2px;
6107: vertical-align: top;
6108: }
6109:
1.809 bisitz 6110: table.LC_pick_box tr > td.LC_odd_row {
1.349 albertel 6111: background-color: $data_table_light;
1.912 bisitz 6112: vertical-align: top;
6113: }
6114:
6115: table.LC_data_table tr.LC_even_row > td {
6116: background-color: $data_table_dark;
1.425 albertel 6117: padding: 2px;
1.900 bisitz 6118: vertical-align: top;
1.347 albertel 6119: }
1.795 www 6120:
1.809 bisitz 6121: table.LC_pick_box tr > td.LC_even_row {
1.349 albertel 6122: background-color: $data_table_dark;
1.900 bisitz 6123: vertical-align: top;
1.347 albertel 6124: }
1.795 www 6125:
1.425 albertel 6126: table.LC_data_table tr.LC_data_table_highlight td {
6127: background-color: $data_table_darker;
6128: }
1.795 www 6129:
1.639 raeburn 6130: table.LC_data_table tr td.LC_leftcol_header {
6131: background-color: $data_table_head;
6132: font-weight: bold;
6133: }
1.795 www 6134:
1.451 albertel 6135: table.LC_data_table tr.LC_empty_row td,
1.507 raeburn 6136: table.LC_nested tr.LC_empty_row td {
1.421 albertel 6137: font-weight: bold;
6138: font-style: italic;
6139: text-align: center;
6140: padding: 8px;
1.347 albertel 6141: }
1.795 www 6142:
1.1075.2.30 raeburn 6143: table.LC_data_table tr.LC_empty_row td,
6144: table.LC_data_table tr.LC_footer_row td {
1.940 bisitz 6145: background-color: $sidebg;
6146: }
6147:
6148: table.LC_nested tr.LC_empty_row td {
6149: background-color: #FFFFFF;
6150: }
6151:
1.890 droeschl 6152: table.LC_caption {
6153: }
6154:
1.507 raeburn 6155: table.LC_nested tr.LC_empty_row td {
1.465 albertel 6156: padding: 4ex
6157: }
1.795 www 6158:
1.507 raeburn 6159: table.LC_nested_outer tr th {
6160: font-weight: bold;
1.801 tempelho 6161: color:$fontmenu;
1.507 raeburn 6162: background-color: $data_table_head;
1.701 harmsja 6163: font-size: small;
1.507 raeburn 6164: border-bottom: 1px solid #000000;
6165: }
1.795 www 6166:
1.507 raeburn 6167: table.LC_nested_outer tr td.LC_subheader {
6168: background-color: $data_table_head;
6169: font-weight: bold;
6170: font-size: small;
6171: border-bottom: 1px solid #000000;
6172: text-align: right;
1.451 albertel 6173: }
1.795 www 6174:
1.507 raeburn 6175: table.LC_nested tr.LC_info_row td {
1.735 bisitz 6176: background-color: #CCCCCC;
1.451 albertel 6177: font-weight: bold;
6178: font-size: small;
1.507 raeburn 6179: text-align: center;
6180: }
1.795 www 6181:
1.589 raeburn 6182: table.LC_nested tr.LC_info_row td.LC_left_item,
6183: table.LC_nested_outer tr th.LC_left_item {
1.507 raeburn 6184: text-align: left;
1.451 albertel 6185: }
1.795 www 6186:
1.507 raeburn 6187: table.LC_nested td {
1.735 bisitz 6188: background-color: #FFFFFF;
1.451 albertel 6189: font-size: small;
1.507 raeburn 6190: }
1.795 www 6191:
1.507 raeburn 6192: table.LC_nested_outer tr th.LC_right_item,
6193: table.LC_nested tr.LC_info_row td.LC_right_item,
6194: table.LC_nested tr.LC_odd_row td.LC_right_item,
6195: table.LC_nested tr td.LC_right_item {
1.451 albertel 6196: text-align: right;
6197: }
6198:
1.507 raeburn 6199: table.LC_nested tr.LC_odd_row td {
1.735 bisitz 6200: background-color: #EEEEEE;
1.451 albertel 6201: }
6202:
1.473 raeburn 6203: table.LC_createuser {
6204: }
6205:
6206: table.LC_createuser tr.LC_section_row td {
1.701 harmsja 6207: font-size: small;
1.473 raeburn 6208: }
6209:
6210: table.LC_createuser tr.LC_info_row td {
1.735 bisitz 6211: background-color: #CCCCCC;
1.473 raeburn 6212: font-weight: bold;
6213: text-align: center;
6214: }
6215:
1.349 albertel 6216: table.LC_calendar {
6217: border: 1px solid #000000;
6218: border-collapse: collapse;
1.917 raeburn 6219: width: 98%;
1.349 albertel 6220: }
1.795 www 6221:
1.349 albertel 6222: table.LC_calendar_pickdate {
6223: font-size: xx-small;
6224: }
1.795 www 6225:
1.349 albertel 6226: table.LC_calendar tr td {
6227: border: 1px solid #000000;
6228: vertical-align: top;
1.917 raeburn 6229: width: 14%;
1.349 albertel 6230: }
1.795 www 6231:
1.349 albertel 6232: table.LC_calendar tr td.LC_calendar_day_empty {
6233: background-color: $data_table_dark;
6234: }
1.795 www 6235:
1.779 bisitz 6236: table.LC_calendar tr td.LC_calendar_day_current {
6237: background-color: $data_table_highlight;
1.777 tempelho 6238: }
1.795 www 6239:
1.938 bisitz 6240: table.LC_data_table tr td.LC_mail_new {
1.349 albertel 6241: background-color: $mail_new;
6242: }
1.795 www 6243:
1.938 bisitz 6244: table.LC_data_table tr.LC_mail_new:hover {
1.349 albertel 6245: background-color: $mail_new_hover;
6246: }
1.795 www 6247:
1.938 bisitz 6248: table.LC_data_table tr td.LC_mail_read {
1.349 albertel 6249: background-color: $mail_read;
6250: }
1.795 www 6251:
1.938 bisitz 6252: /*
6253: table.LC_data_table tr.LC_mail_read:hover {
1.349 albertel 6254: background-color: $mail_read_hover;
6255: }
1.938 bisitz 6256: */
1.795 www 6257:
1.938 bisitz 6258: table.LC_data_table tr td.LC_mail_replied {
1.349 albertel 6259: background-color: $mail_replied;
6260: }
1.795 www 6261:
1.938 bisitz 6262: /*
6263: table.LC_data_table tr.LC_mail_replied:hover {
1.349 albertel 6264: background-color: $mail_replied_hover;
6265: }
1.938 bisitz 6266: */
1.795 www 6267:
1.938 bisitz 6268: table.LC_data_table tr td.LC_mail_other {
1.349 albertel 6269: background-color: $mail_other;
6270: }
1.795 www 6271:
1.938 bisitz 6272: /*
6273: table.LC_data_table tr.LC_mail_other:hover {
1.349 albertel 6274: background-color: $mail_other_hover;
6275: }
1.938 bisitz 6276: */
1.494 raeburn 6277:
1.777 tempelho 6278: table.LC_data_table tr > td.LC_browser_file,
6279: table.LC_data_table tr > td.LC_browser_file_published {
1.899 bisitz 6280: background: #AAEE77;
1.389 albertel 6281: }
1.795 www 6282:
1.777 tempelho 6283: table.LC_data_table tr > td.LC_browser_file_locked,
6284: table.LC_data_table tr > td.LC_browser_file_unpublished {
1.389 albertel 6285: background: #FFAA99;
1.387 albertel 6286: }
1.795 www 6287:
1.777 tempelho 6288: table.LC_data_table tr > td.LC_browser_file_obsolete {
1.899 bisitz 6289: background: #888888;
1.779 bisitz 6290: }
1.795 www 6291:
1.777 tempelho 6292: table.LC_data_table tr > td.LC_browser_file_modified,
1.779 bisitz 6293: table.LC_data_table tr > td.LC_browser_file_metamodified {
1.899 bisitz 6294: background: #F8F866;
1.777 tempelho 6295: }
1.795 www 6296:
1.696 bisitz 6297: table.LC_data_table tr.LC_browser_folder > td {
1.899 bisitz 6298: background: #E0E8FF;
1.387 albertel 6299: }
1.696 bisitz 6300:
1.707 bisitz 6301: table.LC_data_table tr > td.LC_roles_is {
1.911 bisitz 6302: /* background: #77FF77; */
1.707 bisitz 6303: }
1.795 www 6304:
1.707 bisitz 6305: table.LC_data_table tr > td.LC_roles_future {
1.939 bisitz 6306: border-right: 8px solid #FFFF77;
1.707 bisitz 6307: }
1.795 www 6308:
1.707 bisitz 6309: table.LC_data_table tr > td.LC_roles_will {
1.939 bisitz 6310: border-right: 8px solid #FFAA77;
1.707 bisitz 6311: }
1.795 www 6312:
1.707 bisitz 6313: table.LC_data_table tr > td.LC_roles_expired {
1.939 bisitz 6314: border-right: 8px solid #FF7777;
1.707 bisitz 6315: }
1.795 www 6316:
1.707 bisitz 6317: table.LC_data_table tr > td.LC_roles_will_not {
1.939 bisitz 6318: border-right: 8px solid #AAFF77;
1.707 bisitz 6319: }
1.795 www 6320:
1.707 bisitz 6321: table.LC_data_table tr > td.LC_roles_selected {
1.939 bisitz 6322: border-right: 8px solid #11CC55;
1.707 bisitz 6323: }
6324:
1.388 albertel 6325: span.LC_current_location {
1.701 harmsja 6326: font-size:larger;
1.388 albertel 6327: background: $pgbg;
6328: }
1.387 albertel 6329:
1.1029 www 6330: span.LC_current_nav_location {
6331: font-weight:bold;
6332: background: $sidebg;
6333: }
6334:
1.395 albertel 6335: span.LC_parm_menu_item {
6336: font-size: larger;
6337: }
1.795 www 6338:
1.395 albertel 6339: span.LC_parm_scope_all {
6340: color: red;
6341: }
1.795 www 6342:
1.395 albertel 6343: span.LC_parm_scope_folder {
6344: color: green;
6345: }
1.795 www 6346:
1.395 albertel 6347: span.LC_parm_scope_resource {
6348: color: orange;
6349: }
1.795 www 6350:
1.395 albertel 6351: span.LC_parm_part {
6352: color: blue;
6353: }
1.795 www 6354:
1.911 bisitz 6355: span.LC_parm_folder,
6356: span.LC_parm_symb {
1.395 albertel 6357: font-size: x-small;
6358: font-family: $mono;
6359: color: #AAAAAA;
6360: }
6361:
1.977 bisitz 6362: ul.LC_parm_parmlist li {
6363: display: inline-block;
6364: padding: 0.3em 0.8em;
6365: vertical-align: top;
6366: width: 150px;
6367: border-top:1px solid $lg_border_color;
6368: }
6369:
1.795 www 6370: td.LC_parm_overview_level_menu,
6371: td.LC_parm_overview_map_menu,
6372: td.LC_parm_overview_parm_selectors,
6373: td.LC_parm_overview_restrictions {
1.396 albertel 6374: border: 1px solid black;
6375: border-collapse: collapse;
6376: }
1.795 www 6377:
1.396 albertel 6378: table.LC_parm_overview_restrictions td {
6379: border-width: 1px 4px 1px 4px;
6380: border-style: solid;
6381: border-color: $pgbg;
6382: text-align: center;
6383: }
1.795 www 6384:
1.396 albertel 6385: table.LC_parm_overview_restrictions th {
6386: background: $tabbg;
6387: border-width: 1px 4px 1px 4px;
6388: border-style: solid;
6389: border-color: $pgbg;
6390: }
1.795 www 6391:
1.398 albertel 6392: table#LC_helpmenu {
1.803 bisitz 6393: border: none;
1.398 albertel 6394: height: 55px;
1.803 bisitz 6395: border-spacing: 0;
1.398 albertel 6396: }
6397:
6398: table#LC_helpmenu fieldset legend {
6399: font-size: larger;
6400: }
1.795 www 6401:
1.397 albertel 6402: table#LC_helpmenu_links {
6403: width: 100%;
6404: border: 1px solid black;
6405: background: $pgbg;
1.803 bisitz 6406: padding: 0;
1.397 albertel 6407: border-spacing: 1px;
6408: }
1.795 www 6409:
1.397 albertel 6410: table#LC_helpmenu_links tr td {
6411: padding: 1px;
6412: background: $tabbg;
1.399 albertel 6413: text-align: center;
6414: font-weight: bold;
1.397 albertel 6415: }
1.396 albertel 6416:
1.795 www 6417: table#LC_helpmenu_links a:link,
6418: table#LC_helpmenu_links a:visited,
1.397 albertel 6419: table#LC_helpmenu_links a:active {
6420: text-decoration: none;
6421: color: $font;
6422: }
1.795 www 6423:
1.397 albertel 6424: table#LC_helpmenu_links a:hover {
6425: text-decoration: underline;
6426: color: $vlink;
6427: }
1.396 albertel 6428:
1.417 albertel 6429: .LC_chrt_popup_exists {
6430: border: 1px solid #339933;
6431: margin: -1px;
6432: }
1.795 www 6433:
1.417 albertel 6434: .LC_chrt_popup_up {
6435: border: 1px solid yellow;
6436: margin: -1px;
6437: }
1.795 www 6438:
1.417 albertel 6439: .LC_chrt_popup {
6440: border: 1px solid #8888FF;
6441: background: #CCCCFF;
6442: }
1.795 www 6443:
1.421 albertel 6444: table.LC_pick_box {
6445: border-collapse: separate;
6446: background: white;
6447: border: 1px solid black;
6448: border-spacing: 1px;
6449: }
1.795 www 6450:
1.421 albertel 6451: table.LC_pick_box td.LC_pick_box_title {
1.850 bisitz 6452: background: $sidebg;
1.421 albertel 6453: font-weight: bold;
1.900 bisitz 6454: text-align: left;
1.740 bisitz 6455: vertical-align: top;
1.421 albertel 6456: width: 184px;
6457: padding: 8px;
6458: }
1.795 www 6459:
1.579 raeburn 6460: table.LC_pick_box td.LC_pick_box_value {
6461: text-align: left;
6462: padding: 8px;
6463: }
1.795 www 6464:
1.579 raeburn 6465: table.LC_pick_box td.LC_pick_box_select {
6466: text-align: left;
6467: padding: 8px;
6468: }
1.795 www 6469:
1.424 albertel 6470: table.LC_pick_box td.LC_pick_box_separator {
1.803 bisitz 6471: padding: 0;
1.421 albertel 6472: height: 1px;
6473: background: black;
6474: }
1.795 www 6475:
1.421 albertel 6476: table.LC_pick_box td.LC_pick_box_submit {
6477: text-align: right;
6478: }
1.795 www 6479:
1.579 raeburn 6480: table.LC_pick_box td.LC_evenrow_value {
6481: text-align: left;
6482: padding: 8px;
6483: background-color: $data_table_light;
6484: }
1.795 www 6485:
1.579 raeburn 6486: table.LC_pick_box td.LC_oddrow_value {
6487: text-align: left;
6488: padding: 8px;
6489: background-color: $data_table_light;
6490: }
1.795 www 6491:
1.579 raeburn 6492: span.LC_helpform_receipt_cat {
6493: font-weight: bold;
6494: }
1.795 www 6495:
1.424 albertel 6496: table.LC_group_priv_box {
6497: background: white;
6498: border: 1px solid black;
6499: border-spacing: 1px;
6500: }
1.795 www 6501:
1.424 albertel 6502: table.LC_group_priv_box td.LC_pick_box_title {
6503: background: $tabbg;
6504: font-weight: bold;
6505: text-align: right;
6506: width: 184px;
6507: }
1.795 www 6508:
1.424 albertel 6509: table.LC_group_priv_box td.LC_groups_fixed {
6510: background: $data_table_light;
6511: text-align: center;
6512: }
1.795 www 6513:
1.424 albertel 6514: table.LC_group_priv_box td.LC_groups_optional {
6515: background: $data_table_dark;
6516: text-align: center;
6517: }
1.795 www 6518:
1.424 albertel 6519: table.LC_group_priv_box td.LC_groups_functionality {
6520: background: $data_table_darker;
6521: text-align: center;
6522: font-weight: bold;
6523: }
1.795 www 6524:
1.424 albertel 6525: table.LC_group_priv td {
6526: text-align: left;
1.803 bisitz 6527: padding: 0;
1.424 albertel 6528: }
6529:
6530: .LC_navbuttons {
6531: margin: 2ex 0ex 2ex 0ex;
6532: }
1.795 www 6533:
1.423 albertel 6534: .LC_topic_bar {
6535: font-weight: bold;
6536: background: $tabbg;
1.918 wenzelju 6537: margin: 1em 0em 1em 2em;
1.805 bisitz 6538: padding: 3px;
1.918 wenzelju 6539: font-size: 1.2em;
1.423 albertel 6540: }
1.795 www 6541:
1.423 albertel 6542: .LC_topic_bar span {
1.918 wenzelju 6543: left: 0.5em;
6544: position: absolute;
1.423 albertel 6545: vertical-align: middle;
1.918 wenzelju 6546: font-size: 1.2em;
1.423 albertel 6547: }
1.795 www 6548:
1.423 albertel 6549: table.LC_course_group_status {
6550: margin: 20px;
6551: }
1.795 www 6552:
1.423 albertel 6553: table.LC_status_selector td {
6554: vertical-align: top;
6555: text-align: center;
1.424 albertel 6556: padding: 4px;
6557: }
1.795 www 6558:
1.599 albertel 6559: div.LC_feedback_link {
1.616 albertel 6560: clear: both;
1.829 kalberla 6561: background: $sidebg;
1.779 bisitz 6562: width: 100%;
1.829 kalberla 6563: padding-bottom: 10px;
6564: border: 1px $tabbg solid;
1.833 kalberla 6565: height: 22px;
6566: line-height: 22px;
6567: padding-top: 5px;
6568: }
6569:
6570: div.LC_feedback_link img {
6571: height: 22px;
1.867 kalberla 6572: vertical-align:middle;
1.829 kalberla 6573: }
6574:
1.911 bisitz 6575: div.LC_feedback_link a {
1.829 kalberla 6576: text-decoration: none;
1.489 raeburn 6577: }
1.795 www 6578:
1.867 kalberla 6579: div.LC_comblock {
1.911 bisitz 6580: display:inline;
1.867 kalberla 6581: color:$font;
6582: font-size:90%;
6583: }
6584:
6585: div.LC_feedback_link div.LC_comblock {
6586: padding-left:5px;
6587: }
6588:
6589: div.LC_feedback_link div.LC_comblock a {
6590: color:$font;
6591: }
6592:
1.489 raeburn 6593: span.LC_feedback_link {
1.858 bisitz 6594: /* background: $feedback_link_bg; */
1.599 albertel 6595: font-size: larger;
6596: }
1.795 www 6597:
1.599 albertel 6598: span.LC_message_link {
1.858 bisitz 6599: /* background: $feedback_link_bg; */
1.599 albertel 6600: font-size: larger;
6601: position: absolute;
6602: right: 1em;
1.489 raeburn 6603: }
1.421 albertel 6604:
1.515 albertel 6605: table.LC_prior_tries {
1.524 albertel 6606: border: 1px solid #000000;
6607: border-collapse: separate;
6608: border-spacing: 1px;
1.515 albertel 6609: }
1.523 albertel 6610:
1.515 albertel 6611: table.LC_prior_tries td {
1.524 albertel 6612: padding: 2px;
1.515 albertel 6613: }
1.523 albertel 6614:
6615: .LC_answer_correct {
1.795 www 6616: background: lightgreen;
6617: color: darkgreen;
6618: padding: 6px;
1.523 albertel 6619: }
1.795 www 6620:
1.523 albertel 6621: .LC_answer_charged_try {
1.797 www 6622: background: #FFAAAA;
1.795 www 6623: color: darkred;
6624: padding: 6px;
1.523 albertel 6625: }
1.795 www 6626:
1.779 bisitz 6627: .LC_answer_not_charged_try,
1.523 albertel 6628: .LC_answer_no_grade,
6629: .LC_answer_late {
1.795 www 6630: background: lightyellow;
1.523 albertel 6631: color: black;
1.795 www 6632: padding: 6px;
1.523 albertel 6633: }
1.795 www 6634:
1.523 albertel 6635: .LC_answer_previous {
1.795 www 6636: background: lightblue;
6637: color: darkblue;
6638: padding: 6px;
1.523 albertel 6639: }
1.795 www 6640:
1.779 bisitz 6641: .LC_answer_no_message {
1.777 tempelho 6642: background: #FFFFFF;
6643: color: black;
1.795 www 6644: padding: 6px;
1.779 bisitz 6645: }
1.795 www 6646:
1.779 bisitz 6647: .LC_answer_unknown {
6648: background: orange;
6649: color: black;
1.795 www 6650: padding: 6px;
1.777 tempelho 6651: }
1.795 www 6652:
1.529 albertel 6653: span.LC_prior_numerical,
6654: span.LC_prior_string,
6655: span.LC_prior_custom,
6656: span.LC_prior_reaction,
6657: span.LC_prior_math {
1.925 bisitz 6658: font-family: $mono;
1.523 albertel 6659: white-space: pre;
6660: }
6661:
1.525 albertel 6662: span.LC_prior_string {
1.925 bisitz 6663: font-family: $mono;
1.525 albertel 6664: white-space: pre;
6665: }
6666:
1.523 albertel 6667: table.LC_prior_option {
6668: width: 100%;
6669: border-collapse: collapse;
6670: }
1.795 www 6671:
1.911 bisitz 6672: table.LC_prior_rank,
1.795 www 6673: table.LC_prior_match {
1.528 albertel 6674: border-collapse: collapse;
6675: }
1.795 www 6676:
1.528 albertel 6677: table.LC_prior_option tr td,
6678: table.LC_prior_rank tr td,
6679: table.LC_prior_match tr td {
1.524 albertel 6680: border: 1px solid #000000;
1.515 albertel 6681: }
6682:
1.855 bisitz 6683: .LC_nobreak {
1.544 albertel 6684: white-space: nowrap;
1.519 raeburn 6685: }
6686:
1.576 raeburn 6687: span.LC_cusr_emph {
6688: font-style: italic;
6689: }
6690:
1.633 raeburn 6691: span.LC_cusr_subheading {
6692: font-weight: normal;
6693: font-size: 85%;
6694: }
6695:
1.861 bisitz 6696: div.LC_docs_entry_move {
1.859 bisitz 6697: border: 1px solid #BBBBBB;
1.545 albertel 6698: background: #DDDDDD;
1.861 bisitz 6699: width: 22px;
1.859 bisitz 6700: padding: 1px;
6701: margin: 0;
1.545 albertel 6702: }
6703:
1.861 bisitz 6704: table.LC_data_table tr > td.LC_docs_entry_commands,
6705: table.LC_data_table tr > td.LC_docs_entry_parameter {
1.545 albertel 6706: font-size: x-small;
6707: }
1.795 www 6708:
1.861 bisitz 6709: .LC_docs_entry_parameter {
6710: white-space: nowrap;
6711: }
6712:
1.544 albertel 6713: .LC_docs_copy {
1.545 albertel 6714: color: #000099;
1.544 albertel 6715: }
1.795 www 6716:
1.544 albertel 6717: .LC_docs_cut {
1.545 albertel 6718: color: #550044;
1.544 albertel 6719: }
1.795 www 6720:
1.544 albertel 6721: .LC_docs_rename {
1.545 albertel 6722: color: #009900;
1.544 albertel 6723: }
1.795 www 6724:
1.544 albertel 6725: .LC_docs_remove {
1.545 albertel 6726: color: #990000;
6727: }
6728:
1.547 albertel 6729: .LC_docs_reinit_warn,
6730: .LC_docs_ext_edit {
6731: font-size: x-small;
6732: }
6733:
1.545 albertel 6734: table.LC_docs_adddocs td,
6735: table.LC_docs_adddocs th {
6736: border: 1px solid #BBBBBB;
6737: padding: 4px;
6738: background: #DDDDDD;
1.543 albertel 6739: }
6740:
1.584 albertel 6741: table.LC_sty_begin {
6742: background: #BBFFBB;
6743: }
1.795 www 6744:
1.584 albertel 6745: table.LC_sty_end {
6746: background: #FFBBBB;
6747: }
6748:
1.589 raeburn 6749: table.LC_double_column {
1.803 bisitz 6750: border-width: 0;
1.589 raeburn 6751: border-collapse: collapse;
6752: width: 100%;
6753: padding: 2px;
6754: }
6755:
6756: table.LC_double_column tr td.LC_left_col {
1.590 raeburn 6757: top: 2px;
1.589 raeburn 6758: left: 2px;
6759: width: 47%;
6760: vertical-align: top;
6761: }
6762:
6763: table.LC_double_column tr td.LC_right_col {
6764: top: 2px;
1.779 bisitz 6765: right: 2px;
1.589 raeburn 6766: width: 47%;
6767: vertical-align: top;
6768: }
6769:
1.591 raeburn 6770: div.LC_left_float {
6771: float: left;
6772: padding-right: 5%;
1.597 albertel 6773: padding-bottom: 4px;
1.591 raeburn 6774: }
6775:
6776: div.LC_clear_float_header {
1.597 albertel 6777: padding-bottom: 2px;
1.591 raeburn 6778: }
6779:
6780: div.LC_clear_float_footer {
1.597 albertel 6781: padding-top: 10px;
1.591 raeburn 6782: clear: both;
6783: }
6784:
1.597 albertel 6785: div.LC_grade_show_user {
1.941 bisitz 6786: /* border-left: 5px solid $sidebg; */
6787: border-top: 5px solid #000000;
6788: margin: 50px 0 0 0;
1.936 bisitz 6789: padding: 15px 0 5px 10px;
1.597 albertel 6790: }
1.795 www 6791:
1.936 bisitz 6792: div.LC_grade_show_user_odd_row {
1.941 bisitz 6793: /* border-left: 5px solid #000000; */
6794: }
6795:
6796: div.LC_grade_show_user div.LC_Box {
6797: margin-right: 50px;
1.597 albertel 6798: }
6799:
6800: div.LC_grade_submissions,
6801: div.LC_grade_message_center,
1.936 bisitz 6802: div.LC_grade_info_links {
1.597 albertel 6803: margin: 5px;
6804: width: 99%;
6805: background: #FFFFFF;
6806: }
1.795 www 6807:
1.597 albertel 6808: div.LC_grade_submissions_header,
1.936 bisitz 6809: div.LC_grade_message_center_header {
1.705 tempelho 6810: font-weight: bold;
6811: font-size: large;
1.597 albertel 6812: }
1.795 www 6813:
1.597 albertel 6814: div.LC_grade_submissions_body,
1.936 bisitz 6815: div.LC_grade_message_center_body {
1.597 albertel 6816: border: 1px solid black;
6817: width: 99%;
6818: background: #FFFFFF;
6819: }
1.795 www 6820:
1.613 albertel 6821: table.LC_scantron_action {
6822: width: 100%;
6823: }
1.795 www 6824:
1.613 albertel 6825: table.LC_scantron_action tr th {
1.698 harmsja 6826: font-weight:bold;
6827: font-style:normal;
1.613 albertel 6828: }
1.795 www 6829:
1.779 bisitz 6830: .LC_edit_problem_header,
1.614 albertel 6831: div.LC_edit_problem_footer {
1.705 tempelho 6832: font-weight: normal;
6833: font-size: medium;
1.602 albertel 6834: margin: 2px;
1.1060 bisitz 6835: background-color: $sidebg;
1.600 albertel 6836: }
1.795 www 6837:
1.600 albertel 6838: div.LC_edit_problem_header,
1.602 albertel 6839: div.LC_edit_problem_header div,
1.614 albertel 6840: div.LC_edit_problem_footer,
6841: div.LC_edit_problem_footer div,
1.602 albertel 6842: div.LC_edit_problem_editxml_header,
6843: div.LC_edit_problem_editxml_header div {
1.1075.2.112 raeburn 6844: z-index: 100;
1.600 albertel 6845: }
1.795 www 6846:
1.600 albertel 6847: div.LC_edit_problem_header_title {
1.705 tempelho 6848: font-weight: bold;
6849: font-size: larger;
1.602 albertel 6850: background: $tabbg;
6851: padding: 3px;
1.1060 bisitz 6852: margin: 0 0 5px 0;
1.602 albertel 6853: }
1.795 www 6854:
1.602 albertel 6855: table.LC_edit_problem_header_title {
6856: width: 100%;
1.600 albertel 6857: background: $tabbg;
1.602 albertel 6858: }
6859:
1.1075.2.112 raeburn 6860: div.LC_edit_actionbar {
6861: background-color: $sidebg;
6862: margin: 0;
6863: padding: 0;
6864: line-height: 200%;
1.602 albertel 6865: }
1.795 www 6866:
1.1075.2.112 raeburn 6867: div.LC_edit_actionbar div{
6868: padding: 0;
6869: margin: 0;
6870: display: inline-block;
1.600 albertel 6871: }
1.795 www 6872:
1.1075.2.34 raeburn 6873: .LC_edit_opt {
6874: padding-left: 1em;
6875: white-space: nowrap;
6876: }
6877:
1.1075.2.57 raeburn 6878: .LC_edit_problem_latexhelper{
6879: text-align: right;
6880: }
6881:
6882: #LC_edit_problem_colorful div{
6883: margin-left: 40px;
6884: }
6885:
1.1075.2.112 raeburn 6886: #LC_edit_problem_codemirror div{
6887: margin-left: 0px;
6888: }
6889:
1.911 bisitz 6890: img.stift {
1.803 bisitz 6891: border-width: 0;
6892: vertical-align: middle;
1.677 riegler 6893: }
1.680 riegler 6894:
1.923 bisitz 6895: table td.LC_mainmenu_col_fieldset {
1.680 riegler 6896: vertical-align: top;
1.777 tempelho 6897: }
1.795 www 6898:
1.716 raeburn 6899: div.LC_createcourse {
1.911 bisitz 6900: margin: 10px 10px 10px 10px;
1.716 raeburn 6901: }
6902:
1.917 raeburn 6903: .LC_dccid {
1.1075.2.38 raeburn 6904: float: right;
1.917 raeburn 6905: margin: 0.2em 0 0 0;
6906: padding: 0;
6907: font-size: 90%;
6908: display:none;
6909: }
6910:
1.897 wenzelju 6911: ol.LC_primary_menu a:hover,
1.721 harmsja 6912: ol#LC_MenuBreadcrumbs a:hover,
6913: ol#LC_PathBreadcrumbs a:hover,
1.897 wenzelju 6914: ul#LC_secondary_menu a:hover,
1.721 harmsja 6915: .LC_FormSectionClearButton input:hover
1.795 www 6916: ul.LC_TabContent li:hover a {
1.952 onken 6917: color:$button_hover;
1.911 bisitz 6918: text-decoration:none;
1.693 droeschl 6919: }
6920:
1.779 bisitz 6921: h1 {
1.911 bisitz 6922: padding: 0;
6923: line-height:130%;
1.693 droeschl 6924: }
1.698 harmsja 6925:
1.911 bisitz 6926: h2,
6927: h3,
6928: h4,
6929: h5,
6930: h6 {
6931: margin: 5px 0 5px 0;
6932: padding: 0;
6933: line-height:130%;
1.693 droeschl 6934: }
1.795 www 6935:
6936: .LC_hcell {
1.911 bisitz 6937: padding:3px 15px 3px 15px;
6938: margin: 0;
6939: background-color:$tabbg;
6940: color:$fontmenu;
6941: border-bottom:solid 1px $lg_border_color;
1.693 droeschl 6942: }
1.795 www 6943:
1.840 bisitz 6944: .LC_Box > .LC_hcell {
1.911 bisitz 6945: margin: 0 -10px 10px -10px;
1.835 bisitz 6946: }
6947:
1.721 harmsja 6948: .LC_noBorder {
1.911 bisitz 6949: border: 0;
1.698 harmsja 6950: }
1.693 droeschl 6951:
1.721 harmsja 6952: .LC_FormSectionClearButton input {
1.911 bisitz 6953: background-color:transparent;
6954: border: none;
6955: cursor:pointer;
6956: text-decoration:underline;
1.693 droeschl 6957: }
1.763 bisitz 6958:
6959: .LC_help_open_topic {
1.911 bisitz 6960: color: #FFFFFF;
6961: background-color: #EEEEFF;
6962: margin: 1px;
6963: padding: 4px;
6964: border: 1px solid #000033;
6965: white-space: nowrap;
6966: /* vertical-align: middle; */
1.759 neumanie 6967: }
1.693 droeschl 6968:
1.911 bisitz 6969: dl,
6970: ul,
6971: div,
6972: fieldset {
6973: margin: 10px 10px 10px 0;
6974: /* overflow: hidden; */
1.693 droeschl 6975: }
1.795 www 6976:
1.1075.2.90 raeburn 6977: article.geogebraweb div {
6978: margin: 0;
6979: }
6980:
1.838 bisitz 6981: fieldset > legend {
1.911 bisitz 6982: font-weight: bold;
6983: padding: 0 5px 0 5px;
1.838 bisitz 6984: }
6985:
1.813 bisitz 6986: #LC_nav_bar {
1.911 bisitz 6987: float: left;
1.995 raeburn 6988: background-color: $pgbg_or_bgcolor;
1.966 bisitz 6989: margin: 0 0 2px 0;
1.807 droeschl 6990: }
6991:
1.916 droeschl 6992: #LC_realm {
6993: margin: 0.2em 0 0 0;
6994: padding: 0;
6995: font-weight: bold;
6996: text-align: center;
1.995 raeburn 6997: background-color: $pgbg_or_bgcolor;
1.916 droeschl 6998: }
6999:
1.911 bisitz 7000: #LC_nav_bar em {
7001: font-weight: bold;
7002: font-style: normal;
1.807 droeschl 7003: }
7004:
1.897 wenzelju 7005: ol.LC_primary_menu {
1.934 droeschl 7006: margin: 0;
1.1075.2.2 raeburn 7007: padding: 0;
1.807 droeschl 7008: }
7009:
1.852 droeschl 7010: ol#LC_PathBreadcrumbs {
1.911 bisitz 7011: margin: 0;
1.693 droeschl 7012: }
7013:
1.897 wenzelju 7014: ol.LC_primary_menu li {
1.1075.2.2 raeburn 7015: color: RGB(80, 80, 80);
7016: vertical-align: middle;
7017: text-align: left;
7018: list-style: none;
1.1075.2.112 raeburn 7019: position: relative;
1.1075.2.2 raeburn 7020: float: left;
1.1075.2.112 raeburn 7021: z-index: 100; /* will be displayed above codemirror and underneath the help-layer */
7022: line-height: 1.5em;
1.1075.2.2 raeburn 7023: }
7024:
1.1075.2.113 raeburn 7025: ol.LC_primary_menu li a,
1.1075.2.112 raeburn 7026: ol.LC_primary_menu li p {
1.1075.2.2 raeburn 7027: display: block;
7028: margin: 0;
7029: padding: 0 5px 0 10px;
7030: text-decoration: none;
7031: }
7032:
1.1075.2.112 raeburn 7033: ol.LC_primary_menu li p span.LC_primary_menu_innertitle {
7034: display: inline-block;
7035: width: 95%;
7036: text-align: left;
7037: }
7038:
7039: ol.LC_primary_menu li p span.LC_primary_menu_innerarrow {
7040: display: inline-block;
7041: width: 5%;
7042: float: right;
7043: text-align: right;
7044: font-size: 70%;
7045: }
7046:
7047: ol.LC_primary_menu ul {
1.1075.2.2 raeburn 7048: display: none;
1.1075.2.112 raeburn 7049: width: 15em;
1.1075.2.2 raeburn 7050: background-color: $data_table_light;
1.1075.2.112 raeburn 7051: position: absolute;
7052: top: 100%;
7053: }
7054:
7055: ol.LC_primary_menu ul ul {
7056: left: 100%;
7057: top: 0;
1.1075.2.2 raeburn 7058: }
7059:
1.1075.2.112 raeburn 7060: ol.LC_primary_menu li:hover > ul, ol.LC_primary_menu li.hover > ul {
1.1075.2.2 raeburn 7061: display: block;
7062: position: absolute;
7063: margin: 0;
7064: padding: 0;
1.1075.2.5 raeburn 7065: z-index: 2;
1.1075.2.2 raeburn 7066: }
7067:
7068: ol.LC_primary_menu li:hover li, ol.LC_primary_menu li.hover li {
1.1075.2.112 raeburn 7069: /* First Submenu -> size should be smaller than the menu title of the whole menu */
1.1075.2.2 raeburn 7070: font-size: 90%;
1.911 bisitz 7071: vertical-align: top;
1.1075.2.2 raeburn 7072: float: none;
1.1075.2.5 raeburn 7073: border-left: 1px solid black;
7074: border-right: 1px solid black;
1.1075.2.112 raeburn 7075: /* A dark bottom border to visualize different menu options;
7076: overwritten in the create_submenu routine for the last border-bottom of the menu */
7077: border-bottom: 1px solid $data_table_dark;
1.1075.2.2 raeburn 7078: }
7079:
1.1075.2.112 raeburn 7080: ol.LC_primary_menu li li p:hover {
7081: color:$button_hover;
7082: text-decoration:none;
7083: background-color:$data_table_dark;
1.1075.2.2 raeburn 7084: }
7085:
7086: ol.LC_primary_menu li li a:hover {
7087: color:$button_hover;
7088: background-color:$data_table_dark;
1.693 droeschl 7089: }
7090:
1.1075.2.112 raeburn 7091: /* Font-size equal to the size of the predecessors*/
7092: ol.LC_primary_menu li:hover li li {
7093: font-size: 100%;
7094: }
7095:
1.897 wenzelju 7096: ol.LC_primary_menu li img {
1.911 bisitz 7097: vertical-align: bottom;
1.934 droeschl 7098: height: 1.1em;
1.1075.2.3 raeburn 7099: margin: 0.2em 0 0 0;
1.693 droeschl 7100: }
7101:
1.897 wenzelju 7102: ol.LC_primary_menu a {
1.911 bisitz 7103: color: RGB(80, 80, 80);
7104: text-decoration: none;
1.693 droeschl 7105: }
1.795 www 7106:
1.949 droeschl 7107: ol.LC_primary_menu a.LC_new_message {
7108: font-weight:bold;
7109: color: darkred;
7110: }
7111:
1.975 raeburn 7112: ol.LC_docs_parameters {
7113: margin-left: 0;
7114: padding: 0;
7115: list-style: none;
7116: }
7117:
7118: ol.LC_docs_parameters li {
7119: margin: 0;
7120: padding-right: 20px;
7121: display: inline;
7122: }
7123:
1.976 raeburn 7124: ol.LC_docs_parameters li:before {
7125: content: "\\002022 \\0020";
7126: }
7127:
7128: li.LC_docs_parameters_title {
7129: font-weight: bold;
7130: }
7131:
7132: ol.LC_docs_parameters li.LC_docs_parameters_title:before {
7133: content: "";
7134: }
7135:
1.897 wenzelju 7136: ul#LC_secondary_menu {
1.1075.2.23 raeburn 7137: clear: right;
1.911 bisitz 7138: color: $fontmenu;
7139: background: $tabbg;
7140: list-style: none;
7141: padding: 0;
7142: margin: 0;
7143: width: 100%;
1.995 raeburn 7144: text-align: left;
1.1075.2.4 raeburn 7145: float: left;
1.808 droeschl 7146: }
7147:
1.897 wenzelju 7148: ul#LC_secondary_menu li {
1.911 bisitz 7149: font-weight: bold;
7150: line-height: 1.8em;
7151: border-right: 1px solid black;
1.1075.2.4 raeburn 7152: float: left;
7153: }
7154:
7155: ul#LC_secondary_menu li.LC_hoverable:hover, ul#LC_secondary_menu li.hover {
7156: background-color: $data_table_light;
7157: }
7158:
7159: ul#LC_secondary_menu li a {
7160: padding: 0 0.8em;
7161: }
7162:
7163: ul#LC_secondary_menu li ul {
7164: display: none;
7165: }
7166:
7167: ul#LC_secondary_menu li:hover ul, ul#LC_secondary_menu li.hover ul {
7168: display: block;
7169: position: absolute;
7170: margin: 0;
7171: padding: 0;
7172: list-style:none;
7173: float: none;
7174: background-color: $data_table_light;
1.1075.2.5 raeburn 7175: z-index: 2;
1.1075.2.10 raeburn 7176: margin-left: -1px;
1.1075.2.4 raeburn 7177: }
7178:
7179: ul#LC_secondary_menu li ul li {
7180: font-size: 90%;
7181: vertical-align: top;
7182: border-left: 1px solid black;
7183: border-right: 1px solid black;
1.1075.2.33 raeburn 7184: background-color: $data_table_light;
1.1075.2.4 raeburn 7185: list-style:none;
7186: float: none;
7187: }
7188:
7189: ul#LC_secondary_menu li ul li:hover, ul#LC_secondary_menu li ul li.hover {
7190: background-color: $data_table_dark;
1.807 droeschl 7191: }
7192:
1.847 tempelho 7193: ul.LC_TabContent {
1.911 bisitz 7194: display:block;
7195: background: $sidebg;
7196: border-bottom: solid 1px $lg_border_color;
7197: list-style:none;
1.1020 raeburn 7198: margin: -1px -10px 0 -10px;
1.911 bisitz 7199: padding: 0;
1.693 droeschl 7200: }
7201:
1.795 www 7202: ul.LC_TabContent li,
7203: ul.LC_TabContentBigger li {
1.911 bisitz 7204: float:left;
1.741 harmsja 7205: }
1.795 www 7206:
1.897 wenzelju 7207: ul#LC_secondary_menu li a {
1.911 bisitz 7208: color: $fontmenu;
7209: text-decoration: none;
1.693 droeschl 7210: }
1.795 www 7211:
1.721 harmsja 7212: ul.LC_TabContent {
1.952 onken 7213: min-height:20px;
1.721 harmsja 7214: }
1.795 www 7215:
7216: ul.LC_TabContent li {
1.911 bisitz 7217: vertical-align:middle;
1.959 onken 7218: padding: 0 16px 0 10px;
1.911 bisitz 7219: background-color:$tabbg;
7220: border-bottom:solid 1px $lg_border_color;
1.1020 raeburn 7221: border-left: solid 1px $font;
1.721 harmsja 7222: }
1.795 www 7223:
1.847 tempelho 7224: ul.LC_TabContent .right {
1.911 bisitz 7225: float:right;
1.847 tempelho 7226: }
7227:
1.911 bisitz 7228: ul.LC_TabContent li a,
7229: ul.LC_TabContent li {
7230: color:rgb(47,47,47);
7231: text-decoration:none;
7232: font-size:95%;
7233: font-weight:bold;
1.952 onken 7234: min-height:20px;
7235: }
7236:
1.959 onken 7237: ul.LC_TabContent li a:hover,
7238: ul.LC_TabContent li a:focus {
1.952 onken 7239: color: $button_hover;
1.959 onken 7240: background:none;
7241: outline:none;
1.952 onken 7242: }
7243:
7244: ul.LC_TabContent li:hover {
7245: color: $button_hover;
7246: cursor:pointer;
1.721 harmsja 7247: }
1.795 www 7248:
1.911 bisitz 7249: ul.LC_TabContent li.active {
1.952 onken 7250: color: $font;
1.911 bisitz 7251: background:#FFFFFF url(/adm/lonIcons/open.gif) no-repeat scroll right center;
1.952 onken 7252: border-bottom:solid 1px #FFFFFF;
7253: cursor: default;
1.744 ehlerst 7254: }
1.795 www 7255:
1.959 onken 7256: ul.LC_TabContent li.active a {
7257: color:$font;
7258: background:#FFFFFF;
7259: outline: none;
7260: }
1.1047 raeburn 7261:
7262: ul.LC_TabContent li.goback {
7263: float: left;
7264: border-left: none;
7265: }
7266:
1.870 tempelho 7267: #maincoursedoc {
1.911 bisitz 7268: clear:both;
1.870 tempelho 7269: }
7270:
7271: ul.LC_TabContentBigger {
1.911 bisitz 7272: display:block;
7273: list-style:none;
7274: padding: 0;
1.870 tempelho 7275: }
7276:
1.795 www 7277: ul.LC_TabContentBigger li {
1.911 bisitz 7278: vertical-align:bottom;
7279: height: 30px;
7280: font-size:110%;
7281: font-weight:bold;
7282: color: #737373;
1.841 tempelho 7283: }
7284:
1.957 onken 7285: ul.LC_TabContentBigger li.active {
7286: position: relative;
7287: top: 1px;
7288: }
7289:
1.870 tempelho 7290: ul.LC_TabContentBigger li a {
1.911 bisitz 7291: background:url('/adm/lonIcons/tabbgleft.gif') left bottom no-repeat;
7292: height: 30px;
7293: line-height: 30px;
7294: text-align: center;
7295: display: block;
7296: text-decoration: none;
1.958 onken 7297: outline: none;
1.741 harmsja 7298: }
1.795 www 7299:
1.870 tempelho 7300: ul.LC_TabContentBigger li.active a {
1.911 bisitz 7301: background:url('/adm/lonIcons/tabbgleft.gif') left top no-repeat;
7302: color:$font;
1.744 ehlerst 7303: }
1.795 www 7304:
1.870 tempelho 7305: ul.LC_TabContentBigger li b {
1.911 bisitz 7306: background: url('/adm/lonIcons/tabbgright.gif') no-repeat right bottom;
7307: display: block;
7308: float: left;
7309: padding: 0 30px;
1.957 onken 7310: border-bottom: 1px solid $lg_border_color;
1.870 tempelho 7311: }
7312:
1.956 onken 7313: ul.LC_TabContentBigger li:hover b {
7314: color:$button_hover;
7315: }
7316:
1.870 tempelho 7317: ul.LC_TabContentBigger li.active b {
1.911 bisitz 7318: background:url('/adm/lonIcons/tabbgright.gif') right top no-repeat;
7319: color:$font;
1.957 onken 7320: border: 0;
1.741 harmsja 7321: }
1.693 droeschl 7322:
1.870 tempelho 7323:
1.862 bisitz 7324: ul.LC_CourseBreadcrumbs {
7325: background: $sidebg;
1.1020 raeburn 7326: height: 2em;
1.862 bisitz 7327: padding-left: 10px;
1.1020 raeburn 7328: margin: 0;
1.862 bisitz 7329: list-style-position: inside;
7330: }
7331:
1.911 bisitz 7332: ol#LC_MenuBreadcrumbs,
1.862 bisitz 7333: ol#LC_PathBreadcrumbs {
1.911 bisitz 7334: padding-left: 10px;
7335: margin: 0;
1.933 droeschl 7336: height: 2.5em; /* equal to #LC_breadcrumbs line-height */
1.693 droeschl 7337: }
7338:
1.911 bisitz 7339: ol#LC_MenuBreadcrumbs li,
7340: ol#LC_PathBreadcrumbs li,
1.862 bisitz 7341: ul.LC_CourseBreadcrumbs li {
1.911 bisitz 7342: display: inline;
1.933 droeschl 7343: white-space: normal;
1.693 droeschl 7344: }
7345:
1.823 bisitz 7346: ol#LC_MenuBreadcrumbs li a,
1.862 bisitz 7347: ul.LC_CourseBreadcrumbs li a {
1.911 bisitz 7348: text-decoration: none;
7349: font-size:90%;
1.693 droeschl 7350: }
1.795 www 7351:
1.969 droeschl 7352: ol#LC_MenuBreadcrumbs h1 {
7353: display: inline;
7354: font-size: 90%;
7355: line-height: 2.5em;
7356: margin: 0;
7357: padding: 0;
7358: }
7359:
1.795 www 7360: ol#LC_PathBreadcrumbs li a {
1.911 bisitz 7361: text-decoration:none;
7362: font-size:100%;
7363: font-weight:bold;
1.693 droeschl 7364: }
1.795 www 7365:
1.840 bisitz 7366: .LC_Box {
1.911 bisitz 7367: border: solid 1px $lg_border_color;
7368: padding: 0 10px 10px 10px;
1.746 neumanie 7369: }
1.795 www 7370:
1.1020 raeburn 7371: .LC_DocsBox {
7372: border: solid 1px $lg_border_color;
7373: padding: 0 0 10px 10px;
7374: }
7375:
1.795 www 7376: .LC_AboutMe_Image {
1.911 bisitz 7377: float:left;
7378: margin-right:10px;
1.747 neumanie 7379: }
1.795 www 7380:
7381: .LC_Clear_AboutMe_Image {
1.911 bisitz 7382: clear:left;
1.747 neumanie 7383: }
1.795 www 7384:
1.721 harmsja 7385: dl.LC_ListStyleClean dt {
1.911 bisitz 7386: padding-right: 5px;
7387: display: table-header-group;
1.693 droeschl 7388: }
7389:
1.721 harmsja 7390: dl.LC_ListStyleClean dd {
1.911 bisitz 7391: display: table-row;
1.693 droeschl 7392: }
7393:
1.721 harmsja 7394: .LC_ListStyleClean,
7395: .LC_ListStyleSimple,
7396: .LC_ListStyleNormal,
1.795 www 7397: .LC_ListStyleSpecial {
1.911 bisitz 7398: /* display:block; */
7399: list-style-position: inside;
7400: list-style-type: none;
7401: overflow: hidden;
7402: padding: 0;
1.693 droeschl 7403: }
7404:
1.721 harmsja 7405: .LC_ListStyleSimple li,
7406: .LC_ListStyleSimple dd,
7407: .LC_ListStyleNormal li,
7408: .LC_ListStyleNormal dd,
7409: .LC_ListStyleSpecial li,
1.795 www 7410: .LC_ListStyleSpecial dd {
1.911 bisitz 7411: margin: 0;
7412: padding: 5px 5px 5px 10px;
7413: clear: both;
1.693 droeschl 7414: }
7415:
1.721 harmsja 7416: .LC_ListStyleClean li,
7417: .LC_ListStyleClean dd {
1.911 bisitz 7418: padding-top: 0;
7419: padding-bottom: 0;
1.693 droeschl 7420: }
7421:
1.721 harmsja 7422: .LC_ListStyleSimple dd,
1.795 www 7423: .LC_ListStyleSimple li {
1.911 bisitz 7424: border-bottom: solid 1px $lg_border_color;
1.693 droeschl 7425: }
7426:
1.721 harmsja 7427: .LC_ListStyleSpecial li,
7428: .LC_ListStyleSpecial dd {
1.911 bisitz 7429: list-style-type: none;
7430: background-color: RGB(220, 220, 220);
7431: margin-bottom: 4px;
1.693 droeschl 7432: }
7433:
1.721 harmsja 7434: table.LC_SimpleTable {
1.911 bisitz 7435: margin:5px;
7436: border:solid 1px $lg_border_color;
1.795 www 7437: }
1.693 droeschl 7438:
1.721 harmsja 7439: table.LC_SimpleTable tr {
1.911 bisitz 7440: padding: 0;
7441: border:solid 1px $lg_border_color;
1.693 droeschl 7442: }
1.795 www 7443:
7444: table.LC_SimpleTable thead {
1.911 bisitz 7445: background:rgb(220,220,220);
1.693 droeschl 7446: }
7447:
1.721 harmsja 7448: div.LC_columnSection {
1.911 bisitz 7449: display: block;
7450: clear: both;
7451: overflow: hidden;
7452: margin: 0;
1.693 droeschl 7453: }
7454:
1.721 harmsja 7455: div.LC_columnSection>* {
1.911 bisitz 7456: float: left;
7457: margin: 10px 20px 10px 0;
7458: overflow:hidden;
1.693 droeschl 7459: }
1.721 harmsja 7460:
1.795 www 7461: table em {
1.911 bisitz 7462: font-weight: bold;
7463: font-style: normal;
1.748 schulted 7464: }
1.795 www 7465:
1.779 bisitz 7466: table.LC_tableBrowseRes,
1.795 www 7467: table.LC_tableOfContent {
1.911 bisitz 7468: border:none;
7469: border-spacing: 1px;
7470: padding: 3px;
7471: background-color: #FFFFFF;
7472: font-size: 90%;
1.753 droeschl 7473: }
1.789 droeschl 7474:
1.911 bisitz 7475: table.LC_tableOfContent {
7476: border-collapse: collapse;
1.789 droeschl 7477: }
7478:
1.771 droeschl 7479: table.LC_tableBrowseRes a,
1.768 schulted 7480: table.LC_tableOfContent a {
1.911 bisitz 7481: background-color: transparent;
7482: text-decoration: none;
1.753 droeschl 7483: }
7484:
1.795 www 7485: table.LC_tableOfContent img {
1.911 bisitz 7486: border: none;
7487: height: 1.3em;
7488: vertical-align: text-bottom;
7489: margin-right: 0.3em;
1.753 droeschl 7490: }
1.757 schulted 7491:
1.795 www 7492: a#LC_content_toolbar_firsthomework {
1.911 bisitz 7493: background-image:url(/res/adm/pages/open-first-problem.gif);
1.774 ehlerst 7494: }
7495:
1.795 www 7496: a#LC_content_toolbar_everything {
1.911 bisitz 7497: background-image:url(/res/adm/pages/show-all.gif);
1.774 ehlerst 7498: }
7499:
1.795 www 7500: a#LC_content_toolbar_uncompleted {
1.911 bisitz 7501: background-image:url(/res/adm/pages/show-incomplete-problems.gif);
1.774 ehlerst 7502: }
7503:
1.795 www 7504: #LC_content_toolbar_clearbubbles {
1.911 bisitz 7505: background-image:url(/res/adm/pages/mark-discussionentries-read.gif);
1.774 ehlerst 7506: }
7507:
1.795 www 7508: a#LC_content_toolbar_changefolder {
1.911 bisitz 7509: background : url(/res/adm/pages/close-all-folders.gif) top center ;
1.757 schulted 7510: }
7511:
1.795 www 7512: a#LC_content_toolbar_changefolder_toggled {
1.911 bisitz 7513: background-image:url(/res/adm/pages/open-all-folders.gif);
1.757 schulted 7514: }
7515:
1.1043 raeburn 7516: a#LC_content_toolbar_edittoplevel {
7517: background-image:url(/res/adm/pages/edittoplevel.gif);
7518: }
7519:
1.795 www 7520: ul#LC_toolbar li a:hover {
1.911 bisitz 7521: background-position: bottom center;
1.757 schulted 7522: }
7523:
1.795 www 7524: ul#LC_toolbar {
1.911 bisitz 7525: padding: 0;
7526: margin: 2px;
7527: list-style:none;
7528: position:relative;
7529: background-color:white;
1.1075.2.9 raeburn 7530: overflow: auto;
1.757 schulted 7531: }
7532:
1.795 www 7533: ul#LC_toolbar li {
1.911 bisitz 7534: border:1px solid white;
7535: padding: 0;
7536: margin: 0;
7537: float: left;
7538: display:inline;
7539: vertical-align:middle;
1.1075.2.9 raeburn 7540: white-space: nowrap;
1.911 bisitz 7541: }
1.757 schulted 7542:
1.783 amueller 7543:
1.795 www 7544: a.LC_toolbarItem {
1.911 bisitz 7545: display:block;
7546: padding: 0;
7547: margin: 0;
7548: height: 32px;
7549: width: 32px;
7550: color:white;
7551: border: none;
7552: background-repeat:no-repeat;
7553: background-color:transparent;
1.757 schulted 7554: }
7555:
1.915 droeschl 7556: ul.LC_funclist {
7557: margin: 0;
7558: padding: 0.5em 1em 0.5em 0;
7559: }
7560:
1.933 droeschl 7561: ul.LC_funclist > li:first-child {
7562: font-weight:bold;
7563: margin-left:0.8em;
7564: }
7565:
1.915 droeschl 7566: ul.LC_funclist + ul.LC_funclist {
7567: /*
7568: left border as a seperator if we have more than
7569: one list
7570: */
7571: border-left: 1px solid $sidebg;
7572: /*
7573: this hides the left border behind the border of the
7574: outer box if element is wrapped to the next 'line'
7575: */
7576: margin-left: -1px;
7577: }
7578:
1.843 bisitz 7579: ul.LC_funclist li {
1.915 droeschl 7580: display: inline;
1.782 bisitz 7581: white-space: nowrap;
1.915 droeschl 7582: margin: 0 0 0 25px;
7583: line-height: 150%;
1.782 bisitz 7584: }
7585:
1.974 wenzelju 7586: .LC_hidden {
7587: display: none;
7588: }
7589:
1.1030 www 7590: .LCmodal-overlay {
7591: position:fixed;
7592: top:0;
7593: right:0;
7594: bottom:0;
7595: left:0;
7596: height:100%;
7597: width:100%;
7598: margin:0;
7599: padding:0;
7600: background:#999;
7601: opacity:.75;
7602: filter: alpha(opacity=75);
7603: -moz-opacity: 0.75;
7604: z-index:101;
7605: }
7606:
7607: * html .LCmodal-overlay {
7608: position: absolute;
7609: height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px');
7610: }
7611:
7612: .LCmodal-window {
7613: position:fixed;
7614: top:50%;
7615: left:50%;
7616: margin:0;
7617: padding:0;
7618: z-index:102;
7619: }
7620:
7621: * html .LCmodal-window {
7622: position:absolute;
7623: }
7624:
7625: .LCclose-window {
7626: position:absolute;
7627: width:32px;
7628: height:32px;
7629: right:8px;
7630: top:8px;
7631: background:transparent url('/res/adm/pages/process-stop.png') no-repeat scroll right top;
7632: text-indent:-99999px;
7633: overflow:hidden;
7634: cursor:pointer;
7635: }
7636:
1.1075.2.17 raeburn 7637: /*
7638: styles used by TTH when "Default set of options to pass to tth/m
7639: when converting TeX" in course settings has been set
7640:
7641: option passed: -t
7642:
7643: */
7644:
7645: td div.comp { margin-top: -0.6ex; margin-bottom: -1ex;}
7646: td div.comb { margin-top: -0.6ex; margin-bottom: -.6ex;}
7647: td div.hrcomp { line-height: 0.9; margin-top: -0.8ex; margin-bottom: -1ex;}
7648: td div.norm {line-height:normal;}
7649:
7650: /*
7651: option passed -y3
7652: */
7653:
7654: span.roman {font-family: serif; font-style: normal; font-weight: normal;}
7655: span.overacc2 {position: relative; left: .8em; top: -1.2ex;}
7656: span.overacc1 {position: relative; left: .6em; top: -1.2ex;}
7657:
1.343 albertel 7658: END
7659: }
7660:
1.306 albertel 7661: =pod
7662:
7663: =item * &headtag()
7664:
7665: Returns a uniform footer for LON-CAPA web pages.
7666:
1.307 albertel 7667: Inputs: $title - optional title for the head
7668: $head_extra - optional extra HTML to put inside the <head>
1.315 albertel 7669: $args - optional arguments
1.319 albertel 7670: force_register - if is true call registerurl so the remote is
7671: informed
1.415 albertel 7672: redirect -> array ref of
7673: 1- seconds before redirect occurs
7674: 2- url to redirect to
7675: 3- whether the side effect should occur
1.315 albertel 7676: (side effect of setting
7677: $env{'internal.head.redirect'} to the url
7678: redirected too)
1.352 albertel 7679: domain -> force to color decorate a page for a specific
7680: domain
7681: function -> force usage of a specific rolish color scheme
7682: bgcolor -> override the default page bgcolor
1.460 albertel 7683: no_auto_mt_title
7684: -> prevent &mt()ing the title arg
1.464 albertel 7685:
1.306 albertel 7686: =cut
7687:
7688: sub headtag {
1.313 albertel 7689: my ($title,$head_extra,$args) = @_;
1.306 albertel 7690:
1.363 albertel 7691: my $function = $args->{'function'} || &get_users_function();
7692: my $domain = $args->{'domain'} || &determinedomain();
7693: my $bgcolor = $args->{'bgcolor'} || &designparm($function.'.pgbg',$domain);
1.1075.2.52 raeburn 7694: my $httphost = $args->{'use_absolute'};
1.418 albertel 7695: my $url = join(':',$env{'user.name'},$env{'user.domain'},
1.458 albertel 7696: $Apache::lonnet::perlvar{'lonVersion'},
1.531 albertel 7697: #time(),
1.418 albertel 7698: $env{'environment.color.timestamp'},
1.363 albertel 7699: $function,$domain,$bgcolor);
7700:
1.369 www 7701: $url = '/adm/css/'.&escape($url).'.css';
1.363 albertel 7702:
1.308 albertel 7703: my $result =
7704: '<head>'.
1.1075.2.56 raeburn 7705: &font_settings($args);
1.319 albertel 7706:
1.1075.2.72 raeburn 7707: my $inhibitprint;
7708: if ($args->{'print_suppress'}) {
7709: $inhibitprint = &print_suppression();
7710: }
1.1064 raeburn 7711:
1.461 albertel 7712: if (!$args->{'frameset'}) {
7713: $result .= &Apache::lonhtmlcommon::htmlareaheaders();
7714: }
1.1075.2.12 raeburn 7715: if ($args->{'force_register'}) {
7716: $result .= &Apache::lonmenu::registerurl(1);
1.319 albertel 7717: }
1.436 albertel 7718: if (!$args->{'no_nav_bar'}
7719: && !$args->{'only_body'}
7720: && !$args->{'frameset'}) {
1.1075.2.52 raeburn 7721: $result .= &help_menu_js($httphost);
1.1032 www 7722: $result.=&modal_window();
1.1038 www 7723: $result.=&togglebox_script();
1.1034 www 7724: $result.=&wishlist_window();
1.1041 www 7725: $result.=&LCprogressbarUpdate_script();
1.1034 www 7726: } else {
7727: if ($args->{'add_modal'}) {
7728: $result.=&modal_window();
7729: }
7730: if ($args->{'add_wishlist'}) {
7731: $result.=&wishlist_window();
7732: }
1.1038 www 7733: if ($args->{'add_togglebox'}) {
7734: $result.=&togglebox_script();
7735: }
1.1041 www 7736: if ($args->{'add_progressbar'}) {
7737: $result.=&LCprogressbarUpdate_script();
7738: }
1.436 albertel 7739: }
1.314 albertel 7740: if (ref($args->{'redirect'})) {
1.414 albertel 7741: my ($time,$url,$inhibit_continue) = @{$args->{'redirect'}};
1.315 albertel 7742: $url = &Apache::lonenc::check_encrypt($url);
1.414 albertel 7743: if (!$inhibit_continue) {
7744: $env{'internal.head.redirect'} = $url;
7745: }
1.313 albertel 7746: $result.=<<ADDMETA
7747: <meta http-equiv="pragma" content="no-cache" />
1.344 albertel 7748: <meta http-equiv="Refresh" content="$time; url=$url" />
1.313 albertel 7749: ADDMETA
1.1075.2.89 raeburn 7750: } else {
7751: unless (($args->{'frameset'}) || ($args->{'js_ready'}) || ($args->{'only_body'}) || ($args->{'no_nav_bar'})) {
7752: my $requrl = $env{'request.uri'};
7753: if ($requrl eq '') {
7754: $requrl = $ENV{'REQUEST_URI'};
7755: $requrl =~ s/\?.+$//;
7756: }
7757: unless (($requrl =~ m{^/adm/(?:switchserver|login|authenticate|logout|groupsort|cleanup|helper|slotrequest|grades)(\?|$)}) ||
7758: (($requrl =~ m{^/res/}) && (($env{'form.submitted'} eq 'scantron') ||
7759: ($env{'form.grade_symb'}) || ($Apache::lonhomework::scantronmode)))) {
7760: my $dom_in_use = $Apache::lonnet::perlvar{'lonDefDomain'};
7761: unless (&Apache::lonnet::allowed('mau',$dom_in_use)) {
7762: my %domdefs = &Apache::lonnet::get_domain_defaults($dom_in_use);
7763: if (ref($domdefs{'offloadnow'}) eq 'HASH') {
7764: my $lonhost = $Apache::lonnet::perlvar{'lonHostID'};
7765: if ($domdefs{'offloadnow'}{$lonhost}) {
7766: my $newserver = &Apache::lonnet::spareserver(30000,undef,1,$dom_in_use);
7767: if (($newserver) && ($newserver ne $lonhost)) {
7768: my $numsec = 5;
7769: my $timeout = $numsec * 1000;
7770: my ($newurl,$locknum,%locks,$msg);
7771: if ($env{'request.role.adv'}) {
7772: ($locknum,%locks) = &Apache::lonnet::get_locks();
7773: }
7774: my $disable_submit = 0;
7775: if ($requrl =~ /$LONCAPA::assess_re/) {
7776: $disable_submit = 1;
7777: }
7778: if ($locknum) {
7779: my @lockinfo = sort(values(%locks));
7780: $msg = &mt('Once the following tasks are complete: ')."\\n".
7781: join(", ",sort(values(%locks)))."\\n".
7782: &mt('your session will be transferred to a different server, after you click "Roles".');
7783: } else {
7784: if (($requrl =~ m{^/res/}) && ($env{'form.submitted'} =~ /^part_/)) {
7785: $msg = &mt('Your LON-CAPA submission has been recorded')."\\n";
7786: }
7787: $msg .= &mt('Your current LON-CAPA session will be transferred to a different server in [quant,_1,second].',$numsec);
7788: $newurl = '/adm/switchserver?otherserver='.$newserver;
7789: if (($env{'request.role'}) && ($env{'request.role'} ne 'cm')) {
7790: $newurl .= '&role='.$env{'request.role'};
7791: }
7792: if ($env{'request.symb'}) {
7793: $newurl .= '&symb='.$env{'request.symb'};
7794: } else {
7795: $newurl .= '&origurl='.$requrl;
7796: }
7797: }
1.1075.2.98 raeburn 7798: &js_escape(\$msg);
1.1075.2.89 raeburn 7799: $result.=<<OFFLOAD
7800: <meta http-equiv="pragma" content="no-cache" />
7801: <script type="text/javascript">
1.1075.2.92 raeburn 7802: // <![CDATA[
1.1075.2.89 raeburn 7803: function LC_Offload_Now() {
7804: var dest = "$newurl";
7805: if (dest != '') {
7806: window.location.href="$newurl";
7807: }
7808: }
1.1075.2.92 raeburn 7809: \$(document).ready(function () {
7810: window.alert('$msg');
7811: if ($disable_submit) {
1.1075.2.89 raeburn 7812: \$(".LC_hwk_submit").prop("disabled", true);
7813: \$( ".LC_textline" ).prop( "readonly", "readonly");
1.1075.2.92 raeburn 7814: }
7815: setTimeout('LC_Offload_Now()', $timeout);
7816: });
7817: // ]]>
1.1075.2.89 raeburn 7818: </script>
7819: OFFLOAD
7820: }
7821: }
7822: }
7823: }
7824: }
7825: }
1.313 albertel 7826: }
1.306 albertel 7827: if (!defined($title)) {
7828: $title = 'The LearningOnline Network with CAPA';
7829: }
1.460 albertel 7830: if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); }
7831: $result .= '<title> LON-CAPA '.$title.'</title>'
1.1075.2.61 raeburn 7832: .'<link rel="stylesheet" type="text/css" href="'.$url.'"';
7833: if (!$args->{'frameset'}) {
7834: $result .= ' /';
7835: }
7836: $result .= '>'
1.1064 raeburn 7837: .$inhibitprint
1.414 albertel 7838: .$head_extra;
1.1075.2.108 raeburn 7839: my $clientmobile;
7840: if (($env{'user.name'} eq '') && ($env{'user.domain'} eq '')) {
7841: (undef,undef,undef,undef,undef,undef,$clientmobile) = &decode_user_agent();
7842: } else {
7843: $clientmobile = $env{'browser.mobile'};
7844: }
7845: if ($clientmobile) {
1.1075.2.42 raeburn 7846: $result .= '
7847: <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0">
7848: <meta name="apple-mobile-web-app-capable" content="yes" />';
7849: }
1.962 droeschl 7850: return $result.'</head>';
1.306 albertel 7851: }
7852:
7853: =pod
7854:
1.340 albertel 7855: =item * &font_settings()
7856:
7857: Returns neccessary <meta> to set the proper encoding
7858:
1.1075.2.56 raeburn 7859: Inputs: optional reference to HASH -- $args passed to &headtag()
1.340 albertel 7860:
7861: =cut
7862:
7863: sub font_settings {
1.1075.2.56 raeburn 7864: my ($args) = @_;
1.340 albertel 7865: my $headerstring='';
1.1075.2.56 raeburn 7866: if ((!$env{'browser.mathml'} && $env{'browser.unicode'}) ||
7867: ((ref($args) eq 'HASH') && ($args->{'browser.unicode'}))) {
1.340 albertel 7868: $headerstring.=
1.1075.2.61 raeburn 7869: '<meta http-equiv="Content-Type" content="text/html; charset=utf-8"';
7870: if (!$args->{'frameset'}) {
7871: $headerstring.= ' /';
7872: }
7873: $headerstring .= '>'."\n";
1.340 albertel 7874: }
7875: return $headerstring;
7876: }
7877:
1.341 albertel 7878: =pod
7879:
1.1064 raeburn 7880: =item * &print_suppression()
7881:
7882: In course context returns css which causes the body to be blank when media="print",
7883: if printout generation is unavailable for the current resource.
7884:
7885: This could be because:
7886:
7887: (a) printstartdate is in the future
7888:
7889: (b) printenddate is in the past
7890:
7891: (c) there is an active exam block with "printout"
7892: functionality blocked
7893:
7894: Users with pav, pfo or evb privileges are exempt.
7895:
7896: Inputs: none
7897:
7898: =cut
7899:
7900:
7901: sub print_suppression {
7902: my $noprint;
7903: if ($env{'request.course.id'}) {
7904: my $scope = $env{'request.course.id'};
7905: if ((&Apache::lonnet::allowed('pav',$scope)) ||
7906: (&Apache::lonnet::allowed('pfo',$scope))) {
7907: return;
7908: }
7909: if ($env{'request.course.sec'} ne '') {
7910: $scope .= "/$env{'request.course.sec'}";
7911: if ((&Apache::lonnet::allowed('pav',$scope)) ||
7912: (&Apache::lonnet::allowed('pfo',$scope))) {
1.1065 raeburn 7913: return;
1.1064 raeburn 7914: }
7915: }
7916: my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
7917: my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
1.1075.2.73 raeburn 7918: my $blocked = &blocking_status('printout',$cnum,$cdom,undef,1);
1.1064 raeburn 7919: if ($blocked) {
7920: my $checkrole = "cm./$cdom/$cnum";
7921: if ($env{'request.course.sec'} ne '') {
7922: $checkrole .= "/$env{'request.course.sec'}";
7923: }
7924: unless ((&Apache::lonnet::allowed('evb',undef,undef,$checkrole)) &&
7925: ($env{'request.role'} !~ m{^st\./$cdom/$cnum})) {
7926: $noprint = 1;
7927: }
7928: }
7929: unless ($noprint) {
7930: my $symb = &Apache::lonnet::symbread();
7931: if ($symb ne '') {
7932: my $navmap = Apache::lonnavmaps::navmap->new();
7933: if (ref($navmap)) {
7934: my $res = $navmap->getBySymb($symb);
7935: if (ref($res)) {
7936: if (!$res->resprintable()) {
7937: $noprint = 1;
7938: }
7939: }
7940: }
7941: }
7942: }
7943: if ($noprint) {
7944: return <<"ENDSTYLE";
7945: <style type="text/css" media="print">
7946: body { display:none }
7947: </style>
7948: ENDSTYLE
7949: }
7950: }
7951: return;
7952: }
7953:
7954: =pod
7955:
1.341 albertel 7956: =item * &xml_begin()
7957:
7958: Returns the needed doctype and <html>
7959:
7960: Inputs: none
7961:
7962: =cut
7963:
7964: sub xml_begin {
1.1075.2.61 raeburn 7965: my ($is_frameset) = @_;
1.341 albertel 7966: my $output='';
7967:
7968: if ($env{'browser.mathml'}) {
7969: $output='<?xml version="1.0"?>'
7970: #.'<?xml-stylesheet type="text/css" href="/adm/MathML/mathml.css"?>'."\n"
7971: # .'<!DOCTYPE html SYSTEM "/adm/MathML/mathml.dtd" '
7972:
7973: # .'<!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">] >'
7974: .'<!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">'
7975: .'<html xmlns:math="http://www.w3.org/1998/Math/MathML" '
7976: .'xmlns="http://www.w3.org/1999/xhtml">';
1.1075.2.61 raeburn 7977: } elsif ($is_frameset) {
7978: $output='<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">'."\n".
7979: '<html>'."\n";
1.341 albertel 7980: } else {
1.1075.2.61 raeburn 7981: $output='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'."\n".
7982: '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">'."\n";
1.341 albertel 7983: }
7984: return $output;
7985: }
1.340 albertel 7986:
7987: =pod
7988:
1.306 albertel 7989: =item * &start_page()
7990:
7991: Returns a complete <html> .. <body> section for LON-CAPA web pages.
7992:
1.648 raeburn 7993: Inputs:
7994:
7995: =over 4
7996:
7997: $title - optional title for the page
7998:
7999: $head_extra - optional extra HTML to incude inside the <head>
8000:
8001: $args - additional optional args supported are:
8002:
8003: =over 8
8004:
8005: only_body -> is true will set &bodytag() onlybodytag
1.317 albertel 8006: arg on
1.814 bisitz 8007: no_nav_bar -> is true will set &bodytag() no_nav_bar arg on
1.648 raeburn 8008: add_entries -> additional attributes to add to the <body>
8009: domain -> force to color decorate a page for a
1.317 albertel 8010: specific domain
1.648 raeburn 8011: function -> force usage of a specific rolish color
1.317 albertel 8012: scheme
1.648 raeburn 8013: redirect -> see &headtag()
8014: bgcolor -> override the default page bg color
8015: js_ready -> return a string ready for being used in
1.317 albertel 8016: a javascript writeln
1.648 raeburn 8017: html_encode -> return a string ready for being used in
1.320 albertel 8018: a html attribute
1.648 raeburn 8019: force_register -> if is true will turn on the &bodytag()
1.317 albertel 8020: $forcereg arg
1.648 raeburn 8021: frameset -> if true will start with a <frameset>
1.330 albertel 8022: rather than <body>
1.648 raeburn 8023: skip_phases -> hash ref of
1.338 albertel 8024: head -> skip the <html><head> generation
8025: body -> skip all <body> generation
1.1075.2.12 raeburn 8026: no_inline_link -> if true and in remote mode, don't show the
8027: 'Switch To Inline Menu' link
1.648 raeburn 8028: no_auto_mt_title -> prevent &mt()ing the title arg
1.867 kalberla 8029: bread_crumbs -> Array containing breadcrumbs
1.983 raeburn 8030: bread_crumbs_component -> if exists show it as headline else show only the breadcrumbs
1.1075.2.15 raeburn 8031: group -> includes the current group, if page is for a
8032: specific group
1.361 albertel 8033:
1.648 raeburn 8034: =back
1.460 albertel 8035:
1.648 raeburn 8036: =back
1.562 albertel 8037:
1.306 albertel 8038: =cut
8039:
8040: sub start_page {
1.309 albertel 8041: my ($title,$head_extra,$args) = @_;
1.318 albertel 8042: #&Apache::lonnet::logthis("start_page ".join(':',caller(0)));
1.319 albertel 8043:
1.315 albertel 8044: $env{'internal.start_page'}++;
1.1075.2.15 raeburn 8045: my ($result,@advtools);
1.964 droeschl 8046:
1.338 albertel 8047: if (! exists($args->{'skip_phases'}{'head'}) ) {
1.1075.2.62 raeburn 8048: $result .= &xml_begin($args->{'frameset'}) . &headtag($title, $head_extra, $args);
1.338 albertel 8049: }
8050:
8051: if (! exists($args->{'skip_phases'}{'body'}) ) {
8052: if ($args->{'frameset'}) {
8053: my $attr_string = &make_attr_string($args->{'force_register'},
8054: $args->{'add_entries'});
8055: $result .= "\n<frameset $attr_string>\n";
1.831 bisitz 8056: } else {
8057: $result .=
8058: &bodytag($title,
8059: $args->{'function'}, $args->{'add_entries'},
8060: $args->{'only_body'}, $args->{'domain'},
8061: $args->{'force_register'}, $args->{'no_nav_bar'},
1.1075.2.12 raeburn 8062: $args->{'bgcolor'}, $args->{'no_inline_link'},
1.1075.2.15 raeburn 8063: $args, \@advtools);
1.831 bisitz 8064: }
1.330 albertel 8065: }
1.338 albertel 8066:
1.315 albertel 8067: if ($args->{'js_ready'}) {
1.713 kaisler 8068: $result = &js_ready($result);
1.315 albertel 8069: }
1.320 albertel 8070: if ($args->{'html_encode'}) {
1.713 kaisler 8071: $result = &html_encode($result);
8072: }
8073:
1.813 bisitz 8074: # Preparation for new and consistent functionlist at top of screen
8075: # if ($args->{'functionlist'}) {
8076: # $result .= &build_functionlist();
8077: #}
8078:
1.964 droeschl 8079: # Don't add anything more if only_body wanted or in const space
8080: return $result if $args->{'only_body'}
8081: || $env{'request.state'} eq 'construct';
1.813 bisitz 8082:
8083: #Breadcrumbs
1.758 kaisler 8084: if (exists($args->{'bread_crumbs'}) or exists($args->{'bread_crumbs_component'})) {
8085: &Apache::lonhtmlcommon::clear_breadcrumbs();
8086: #if any br links exists, add them to the breadcrumbs
8087: if (exists($args->{'bread_crumbs'}) and ref($args->{'bread_crumbs'}) eq 'ARRAY') {
8088: foreach my $crumb (@{$args->{'bread_crumbs'}}){
8089: &Apache::lonhtmlcommon::add_breadcrumb($crumb);
8090: }
8091: }
1.1075.2.19 raeburn 8092: # if @advtools array contains items add then to the breadcrumbs
8093: if (@advtools > 0) {
8094: &Apache::lonmenu::advtools_crumbs(@advtools);
8095: }
1.758 kaisler 8096:
8097: #if bread_crumbs_component exists show it as headline else show only the breadcrumbs
8098: if(exists($args->{'bread_crumbs_component'})){
8099: $result .= &Apache::lonhtmlcommon::breadcrumbs($args->{'bread_crumbs_component'});
8100: }else{
8101: $result .= &Apache::lonhtmlcommon::breadcrumbs();
8102: }
1.1075.2.24 raeburn 8103: } elsif (($env{'environment.remote'} eq 'on') &&
8104: ($env{'form.inhibitmenu'} ne 'yes') &&
8105: ($env{'request.noversionuri'} =~ m{^/res/}) &&
8106: ($env{'request.noversionuri'} !~ m{^/res/adm/pages/})) {
1.1075.2.21 raeburn 8107: $result .= '<div style="padding:0;margin:0;clear:both"><hr /></div>';
1.320 albertel 8108: }
1.315 albertel 8109: return $result;
1.306 albertel 8110: }
8111:
8112: sub end_page {
1.315 albertel 8113: my ($args) = @_;
8114: $env{'internal.end_page'}++;
1.330 albertel 8115: my $result;
1.335 albertel 8116: if ($args->{'discussion'}) {
8117: my ($target,$parser);
8118: if (ref($args->{'discussion'})) {
8119: ($target,$parser) =($args->{'discussion'}{'target'},
8120: $args->{'discussion'}{'parser'});
8121: }
8122: $result .= &Apache::lonxml::xmlend($target,$parser);
8123: }
1.330 albertel 8124: if ($args->{'frameset'}) {
8125: $result .= '</frameset>';
8126: } else {
1.635 raeburn 8127: $result .= &endbodytag($args);
1.330 albertel 8128: }
1.1075.2.6 raeburn 8129: unless ($args->{'notbody'}) {
8130: $result .= "\n</html>";
8131: }
1.330 albertel 8132:
1.315 albertel 8133: if ($args->{'js_ready'}) {
1.317 albertel 8134: $result = &js_ready($result);
1.315 albertel 8135: }
1.335 albertel 8136:
1.320 albertel 8137: if ($args->{'html_encode'}) {
8138: $result = &html_encode($result);
8139: }
1.335 albertel 8140:
1.315 albertel 8141: return $result;
8142: }
8143:
1.1034 www 8144: sub wishlist_window {
8145: return(<<'ENDWISHLIST');
1.1046 raeburn 8146: <script type="text/javascript">
1.1034 www 8147: // <![CDATA[
8148: // <!-- BEGIN LON-CAPA Internal
8149: function set_wishlistlink(title, path) {
8150: if (!title) {
8151: title = document.title;
8152: title = title.replace(/^LON-CAPA /,'');
8153: }
1.1075.2.65 raeburn 8154: title = encodeURIComponent(title);
1.1075.2.83 raeburn 8155: title = title.replace("'","\\\'");
1.1034 www 8156: if (!path) {
8157: path = location.pathname;
8158: }
1.1075.2.65 raeburn 8159: path = encodeURIComponent(path);
1.1075.2.83 raeburn 8160: path = path.replace("'","\\\'");
1.1034 www 8161: Win = window.open('/adm/wishlist?mode=newLink&setTitle='+title+'&setPath='+path,
8162: 'wishlistNewLink','width=560,height=350,scrollbars=0');
8163: }
8164: // END LON-CAPA Internal -->
8165: // ]]>
8166: </script>
8167: ENDWISHLIST
8168: }
8169:
1.1030 www 8170: sub modal_window {
8171: return(<<'ENDMODAL');
1.1046 raeburn 8172: <script type="text/javascript">
1.1030 www 8173: // <![CDATA[
8174: // <!-- BEGIN LON-CAPA Internal
8175: var modalWindow = {
8176: parent:"body",
8177: windowId:null,
8178: content:null,
8179: width:null,
8180: height:null,
8181: close:function()
8182: {
8183: $(".LCmodal-window").remove();
8184: $(".LCmodal-overlay").remove();
8185: },
8186: open:function()
8187: {
8188: var modal = "";
8189: modal += "<div class=\"LCmodal-overlay\"></div>";
8190: 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;\">";
8191: modal += this.content;
8192: modal += "</div>";
8193:
8194: $(this.parent).append(modal);
8195:
8196: $(".LCmodal-window").append("<a class=\"LCclose-window\"></a>");
8197: $(".LCclose-window").click(function(){modalWindow.close();});
8198: $(".LCmodal-overlay").click(function(){modalWindow.close();});
8199: }
8200: };
1.1075.2.42 raeburn 8201: var openMyModal = function(source,width,height,scrolling,transparency,style)
1.1030 www 8202: {
1.1075.2.83 raeburn 8203: source = source.replace("'","'");
1.1030 www 8204: modalWindow.windowId = "myModal";
8205: modalWindow.width = width;
8206: modalWindow.height = height;
1.1075.2.80 raeburn 8207: modalWindow.content = "<iframe width='"+width+"' height='"+height+"' frameborder='0' scrolling='"+scrolling+"' allowtransparency='"+transparency+"' src='" + source + "' style='"+style+"'></iframe>";
1.1030 www 8208: modalWindow.open();
1.1075.2.87 raeburn 8209: };
1.1030 www 8210: // END LON-CAPA Internal -->
8211: // ]]>
8212: </script>
8213: ENDMODAL
8214: }
8215:
8216: sub modal_link {
1.1075.2.42 raeburn 8217: my ($link,$linktext,$width,$height,$target,$scrolling,$title,$transparency,$style)=@_;
1.1030 www 8218: unless ($width) { $width=480; }
8219: unless ($height) { $height=400; }
1.1031 www 8220: unless ($scrolling) { $scrolling='yes'; }
1.1075.2.42 raeburn 8221: unless ($transparency) { $transparency='true'; }
8222:
1.1074 raeburn 8223: my $target_attr;
8224: if (defined($target)) {
8225: $target_attr = 'target="'.$target.'"';
8226: }
8227: return <<"ENDLINK";
1.1075.2.42 raeburn 8228: <a href="$link" $target_attr title="$title" onclick="javascript:openMyModal('$link',$width,$height,'$scrolling','$transparency','$style'); return false;">
1.1074 raeburn 8229: $linktext</a>
8230: ENDLINK
1.1030 www 8231: }
8232:
1.1032 www 8233: sub modal_adhoc_script {
8234: my ($funcname,$width,$height,$content)=@_;
8235: return (<<ENDADHOC);
1.1046 raeburn 8236: <script type="text/javascript">
1.1032 www 8237: // <![CDATA[
8238: var $funcname = function()
8239: {
8240: modalWindow.windowId = "myModal";
8241: modalWindow.width = $width;
8242: modalWindow.height = $height;
8243: modalWindow.content = '$content';
8244: modalWindow.open();
8245: };
8246: // ]]>
8247: </script>
8248: ENDADHOC
8249: }
8250:
1.1041 www 8251: sub modal_adhoc_inner {
8252: my ($funcname,$width,$height,$content)=@_;
8253: my $innerwidth=$width-20;
8254: $content=&js_ready(
1.1042 www 8255: &start_page('Dialog',undef,{'only_body'=>1,'bgcolor'=>'#FFFFFF'}).
1.1075.2.42 raeburn 8256: &start_scrollbox($width.'px',$innerwidth.'px',$height.'px','myModal','#FFFFFF',undef,1).
8257: $content.
1.1041 www 8258: &end_scrollbox().
1.1075.2.42 raeburn 8259: &end_page()
1.1041 www 8260: );
8261: return &modal_adhoc_script($funcname,$width,$height,$content);
8262: }
8263:
8264: sub modal_adhoc_window {
8265: my ($funcname,$width,$height,$content,$linktext)=@_;
8266: return &modal_adhoc_inner($funcname,$width,$height,$content).
8267: "<a href=\"javascript:$funcname();void(0);\">".$linktext."</a>";
8268: }
8269:
8270: sub modal_adhoc_launch {
8271: my ($funcname,$width,$height,$content)=@_;
8272: return &modal_adhoc_inner($funcname,$width,$height,$content).(<<ENDLAUNCH);
8273: <script type="text/javascript">
8274: // <![CDATA[
8275: $funcname();
8276: // ]]>
8277: </script>
8278: ENDLAUNCH
8279: }
8280:
8281: sub modal_adhoc_close {
8282: return (<<ENDCLOSE);
8283: <script type="text/javascript">
8284: // <![CDATA[
8285: modalWindow.close();
8286: // ]]>
8287: </script>
8288: ENDCLOSE
8289: }
8290:
1.1038 www 8291: sub togglebox_script {
8292: return(<<ENDTOGGLE);
8293: <script type="text/javascript">
8294: // <![CDATA[
8295: function LCtoggleDisplay(id,hidetext,showtext) {
8296: link = document.getElementById(id + "link").childNodes[0];
8297: with (document.getElementById(id).style) {
8298: if (display == "none" ) {
8299: display = "inline";
8300: link.nodeValue = hidetext;
8301: } else {
8302: display = "none";
8303: link.nodeValue = showtext;
8304: }
8305: }
8306: }
8307: // ]]>
8308: </script>
8309: ENDTOGGLE
8310: }
8311:
1.1039 www 8312: sub start_togglebox {
8313: my ($id,$heading,$headerbg,$hidetext,$showtext)=@_;
8314: unless ($heading) { $heading=''; } else { $heading.=' '; }
8315: unless ($showtext) { $showtext=&mt('show'); }
8316: unless ($hidetext) { $hidetext=&mt('hide'); }
8317: unless ($headerbg) { $headerbg='#FFFFFF'; }
8318: return &start_data_table().
8319: &start_data_table_header_row().
8320: '<td bgcolor="'.$headerbg.'">'.$heading.
8321: '[<a id="'.$id.'link" href="javascript:LCtoggleDisplay(\''.$id.'\',\''.$hidetext.'\',\''.
8322: $showtext.'\')">'.$showtext.'</a>]</td>'.
8323: &end_data_table_header_row().
8324: '<tr id="'.$id.'" style="display:none""><td>';
8325: }
8326:
8327: sub end_togglebox {
8328: return '</td></tr>'.&end_data_table();
8329: }
8330:
1.1041 www 8331: sub LCprogressbar_script {
1.1045 www 8332: my ($id)=@_;
1.1041 www 8333: return(<<ENDPROGRESS);
8334: <script type="text/javascript">
8335: // <![CDATA[
1.1045 www 8336: \$('#progressbar$id').progressbar({
1.1041 www 8337: value: 0,
8338: change: function(event, ui) {
8339: var newVal = \$(this).progressbar('option', 'value');
8340: \$('.pblabel', this).text(LCprogressTxt);
8341: }
8342: });
8343: // ]]>
8344: </script>
8345: ENDPROGRESS
8346: }
8347:
8348: sub LCprogressbarUpdate_script {
8349: return(<<ENDPROGRESSUPDATE);
8350: <style type="text/css">
8351: .ui-progressbar { position:relative; }
8352: .pblabel { position: absolute; width: 100%; text-align: center; line-height: 1.9em; }
8353: </style>
8354: <script type="text/javascript">
8355: // <![CDATA[
1.1045 www 8356: var LCprogressTxt='---';
8357:
8358: function LCupdateProgress(percent,progresstext,id) {
1.1041 www 8359: LCprogressTxt=progresstext;
1.1045 www 8360: \$('#progressbar'+id).progressbar('value',percent);
1.1041 www 8361: }
8362: // ]]>
8363: </script>
8364: ENDPROGRESSUPDATE
8365: }
8366:
1.1042 www 8367: my $LClastpercent;
1.1045 www 8368: my $LCidcnt;
8369: my $LCcurrentid;
1.1042 www 8370:
1.1041 www 8371: sub LCprogressbar {
1.1042 www 8372: my ($r)=(@_);
8373: $LClastpercent=0;
1.1045 www 8374: $LCidcnt++;
8375: $LCcurrentid=$$.'_'.$LCidcnt;
1.1041 www 8376: my $starting=&mt('Starting');
8377: my $content=(<<ENDPROGBAR);
1.1045 www 8378: <div id="progressbar$LCcurrentid">
1.1041 www 8379: <span class="pblabel">$starting</span>
8380: </div>
8381: ENDPROGBAR
1.1045 www 8382: &r_print($r,$content.&LCprogressbar_script($LCcurrentid));
1.1041 www 8383: }
8384:
8385: sub LCprogressbarUpdate {
1.1042 www 8386: my ($r,$val,$text)=@_;
8387: unless ($val) {
8388: if ($LClastpercent) {
8389: $val=$LClastpercent;
8390: } else {
8391: $val=0;
8392: }
8393: }
1.1041 www 8394: if ($val<0) { $val=0; }
8395: if ($val>100) { $val=0; }
1.1042 www 8396: $LClastpercent=$val;
1.1041 www 8397: unless ($text) { $text=$val.'%'; }
8398: $text=&js_ready($text);
1.1044 www 8399: &r_print($r,<<ENDUPDATE);
1.1041 www 8400: <script type="text/javascript">
8401: // <![CDATA[
1.1045 www 8402: LCupdateProgress($val,'$text','$LCcurrentid');
1.1041 www 8403: // ]]>
8404: </script>
8405: ENDUPDATE
1.1035 www 8406: }
8407:
1.1042 www 8408: sub LCprogressbarClose {
8409: my ($r)=@_;
8410: $LClastpercent=0;
1.1044 www 8411: &r_print($r,<<ENDCLOSE);
1.1042 www 8412: <script type="text/javascript">
8413: // <![CDATA[
1.1045 www 8414: \$("#progressbar$LCcurrentid").hide('slow');
1.1042 www 8415: // ]]>
8416: </script>
8417: ENDCLOSE
1.1044 www 8418: }
8419:
8420: sub r_print {
8421: my ($r,$to_print)=@_;
8422: if ($r) {
8423: $r->print($to_print);
8424: $r->rflush();
8425: } else {
8426: print($to_print);
8427: }
1.1042 www 8428: }
8429:
1.320 albertel 8430: sub html_encode {
8431: my ($result) = @_;
8432:
1.322 albertel 8433: $result = &HTML::Entities::encode($result,'<>&"');
1.320 albertel 8434:
8435: return $result;
8436: }
1.1044 www 8437:
1.317 albertel 8438: sub js_ready {
8439: my ($result) = @_;
8440:
1.323 albertel 8441: $result =~ s/[\n\r]/ /xmsg;
8442: $result =~ s/\\/\\\\/xmsg;
8443: $result =~ s/'/\\'/xmsg;
1.372 albertel 8444: $result =~ s{</}{<\\/}xmsg;
1.317 albertel 8445:
8446: return $result;
8447: }
8448:
1.315 albertel 8449: sub validate_page {
8450: if ( exists($env{'internal.start_page'})
1.316 albertel 8451: && $env{'internal.start_page'} > 1) {
8452: &Apache::lonnet::logthis('start_page called multiple times '.
1.318 albertel 8453: $env{'internal.start_page'}.' '.
1.316 albertel 8454: $ENV{'request.filename'});
1.315 albertel 8455: }
8456: if ( exists($env{'internal.end_page'})
1.316 albertel 8457: && $env{'internal.end_page'} > 1) {
8458: &Apache::lonnet::logthis('end_page called multiple times '.
1.318 albertel 8459: $env{'internal.end_page'}.' '.
1.316 albertel 8460: $env{'request.filename'});
1.315 albertel 8461: }
8462: if ( exists($env{'internal.start_page'})
8463: && ! exists($env{'internal.end_page'})) {
1.316 albertel 8464: &Apache::lonnet::logthis('start_page called without end_page '.
8465: $env{'request.filename'});
1.315 albertel 8466: }
8467: if ( ! exists($env{'internal.start_page'})
8468: && exists($env{'internal.end_page'})) {
1.316 albertel 8469: &Apache::lonnet::logthis('end_page called without start_page'.
8470: $env{'request.filename'});
1.315 albertel 8471: }
1.306 albertel 8472: }
1.315 albertel 8473:
1.996 www 8474:
8475: sub start_scrollbox {
1.1075.2.56 raeburn 8476: my ($outerwidth,$width,$height,$id,$bgcolor,$cursor,$needjsready) = @_;
1.998 raeburn 8477: unless ($outerwidth) { $outerwidth='520px'; }
8478: unless ($width) { $width='500px'; }
8479: unless ($height) { $height='200px'; }
1.1075 raeburn 8480: my ($table_id,$div_id,$tdcol);
1.1018 raeburn 8481: if ($id ne '') {
1.1075.2.42 raeburn 8482: $table_id = ' id="table_'.$id.'"';
8483: $div_id = ' id="div_'.$id.'"';
1.1018 raeburn 8484: }
1.1075 raeburn 8485: if ($bgcolor ne '') {
8486: $tdcol = "background-color: $bgcolor;";
8487: }
1.1075.2.42 raeburn 8488: my $nicescroll_js;
8489: if ($env{'browser.mobile'}) {
8490: $nicescroll_js = &nicescroll_javascript('div_'.$id,$cursor,$needjsready);
8491: }
1.1075 raeburn 8492: return <<"END";
1.1075.2.42 raeburn 8493: $nicescroll_js
8494:
8495: <table style="width: $outerwidth; border: 1px solid none;"$table_id><tr><td style="width: $width;$tdcol">
1.1075.2.56 raeburn 8496: <div style="overflow:auto; width:$width; height:$height;"$div_id>
1.1075 raeburn 8497: END
1.996 www 8498: }
8499:
8500: sub end_scrollbox {
1.1036 www 8501: return '</div></td></tr></table>';
1.996 www 8502: }
8503:
1.1075.2.42 raeburn 8504: sub nicescroll_javascript {
8505: my ($id,$cursor,$needjsready,$framecheck,$location) = @_;
8506: my %options;
8507: if (ref($cursor) eq 'HASH') {
8508: %options = %{$cursor};
8509: }
8510: unless ($options{'railalign'} =~ /^left|right$/) {
8511: $options{'railalign'} = 'left';
8512: }
8513: unless ($options{'cursorcolor'} =~ /^\#\w+$/) {
8514: my $function = &get_users_function();
8515: $options{'cursorcolor'} = &designparm($function.'.sidebg',$env{'request.role.domain'});
8516: unless ($options{'cursorcolor'} =~ /^\#\w+$/) {
8517: $options{'cursorcolor'} = '#00F';
8518: }
8519: }
8520: if ($options{'cursoropacity'} =~ /^[\d.]+$/) {
8521: unless ($options{'cursoropacity'} >= 0.0 && $options{'cursoropacity'} <=1.0) {
8522: $options{'cursoropacity'}='1.0';
8523: }
8524: } else {
8525: $options{'cursoropacity'}='1.0';
8526: }
8527: if ($options{'cursorfixedheight'} eq 'none') {
8528: delete($options{'cursorfixedheight'});
8529: } else {
8530: unless ($options{'cursorfixedheight'} =~ /^\d+$/) { $options{'cursorfixedheight'}='50'; }
8531: }
8532: unless ($options{'railoffset'} =~ /^{[\w\:\d\-,]+}$/) {
8533: delete($options{'railoffset'});
8534: }
8535: my @niceoptions;
8536: while (my($key,$value) = each(%options)) {
8537: if ($value =~ /^\{.+\}$/) {
8538: push(@niceoptions,$key.':'.$value);
8539: } else {
8540: push(@niceoptions,$key.':"'.$value.'"');
8541: }
8542: }
8543: my $nicescroll_js = '
8544: $(document).ready(
8545: function() {
8546: $("#'.$id.'").niceScroll({'.join(',',@niceoptions).'});
8547: }
8548: );
8549: ';
8550: if ($framecheck) {
8551: $nicescroll_js .= '
8552: function expand_div(caller) {
8553: if (top === self) {
8554: document.getElementById("'.$id.'").style.width = "auto";
8555: document.getElementById("'.$id.'").style.height = "auto";
8556: } else {
8557: try {
8558: if (parent.frames) {
8559: if (parent.frames.length > 1) {
8560: var framesrc = parent.frames[1].location.href;
8561: var currsrc = framesrc.replace(/\#.*$/,"");
8562: if ((caller == "search") || (currsrc == "'.$location.'")) {
8563: document.getElementById("'.$id.'").style.width = "auto";
8564: document.getElementById("'.$id.'").style.height = "auto";
8565: }
8566: }
8567: }
8568: } catch (e) {
8569: return;
8570: }
8571: }
8572: return;
8573: }
8574: ';
8575: }
8576: if ($needjsready) {
8577: $nicescroll_js = '
8578: <script type="text/javascript">'."\n".$nicescroll_js."\n</script>\n";
8579: } else {
8580: $nicescroll_js = &Apache::lonhtmlcommon::scripttag($nicescroll_js);
8581: }
8582: return $nicescroll_js;
8583: }
8584:
1.318 albertel 8585: sub simple_error_page {
1.1075.2.49 raeburn 8586: my ($r,$title,$msg,$args) = @_;
8587: if (ref($args) eq 'HASH') {
8588: if (!$args->{'no_auto_mt_msg'}) { $msg = &mt($msg); }
8589: } else {
8590: $msg = &mt($msg);
8591: }
8592:
1.318 albertel 8593: my $page =
8594: &Apache::loncommon::start_page($title).
1.1075.2.49 raeburn 8595: '<p class="LC_error">'.$msg.'</p>'.
1.318 albertel 8596: &Apache::loncommon::end_page();
8597: if (ref($r)) {
8598: $r->print($page);
1.327 albertel 8599: return;
1.318 albertel 8600: }
8601: return $page;
8602: }
1.347 albertel 8603:
8604: {
1.610 albertel 8605: my @row_count;
1.961 onken 8606:
8607: sub start_data_table_count {
8608: unshift(@row_count, 0);
8609: return;
8610: }
8611:
8612: sub end_data_table_count {
8613: shift(@row_count);
8614: return;
8615: }
8616:
1.347 albertel 8617: sub start_data_table {
1.1018 raeburn 8618: my ($add_class,$id) = @_;
1.422 albertel 8619: my $css_class = (join(' ','LC_data_table',$add_class));
1.1018 raeburn 8620: my $table_id;
8621: if (defined($id)) {
8622: $table_id = ' id="'.$id.'"';
8623: }
1.961 onken 8624: &start_data_table_count();
1.1018 raeburn 8625: return '<table class="'.$css_class.'"'.$table_id.'>'."\n";
1.347 albertel 8626: }
8627:
8628: sub end_data_table {
1.961 onken 8629: &end_data_table_count();
1.389 albertel 8630: return '</table>'."\n";;
1.347 albertel 8631: }
8632:
8633: sub start_data_table_row {
1.974 wenzelju 8634: my ($add_class, $id) = @_;
1.610 albertel 8635: $row_count[0]++;
8636: my $css_class = ($row_count[0] % 2)?'LC_odd_row':'LC_even_row';
1.900 bisitz 8637: $css_class = (join(' ',$css_class,$add_class)) unless ($add_class eq '');
1.974 wenzelju 8638: $id = (' id="'.$id.'"') unless ($id eq '');
8639: return '<tr class="'.$css_class.'"'.$id.'>'."\n";
1.347 albertel 8640: }
1.471 banghart 8641:
8642: sub continue_data_table_row {
1.974 wenzelju 8643: my ($add_class, $id) = @_;
1.610 albertel 8644: my $css_class = ($row_count[0] % 2)?'LC_odd_row':'LC_even_row';
1.974 wenzelju 8645: $css_class = (join(' ',$css_class,$add_class)) unless ($add_class eq '');
8646: $id = (' id="'.$id.'"') unless ($id eq '');
8647: return '<tr class="'.$css_class.'"'.$id.'>'."\n";
1.471 banghart 8648: }
1.347 albertel 8649:
8650: sub end_data_table_row {
1.389 albertel 8651: return '</tr>'."\n";;
1.347 albertel 8652: }
1.367 www 8653:
1.421 albertel 8654: sub start_data_table_empty_row {
1.707 bisitz 8655: # $row_count[0]++;
1.421 albertel 8656: return '<tr class="LC_empty_row" >'."\n";;
8657: }
8658:
8659: sub end_data_table_empty_row {
8660: return '</tr>'."\n";;
8661: }
8662:
1.367 www 8663: sub start_data_table_header_row {
1.389 albertel 8664: return '<tr class="LC_header_row">'."\n";;
1.367 www 8665: }
8666:
8667: sub end_data_table_header_row {
1.389 albertel 8668: return '</tr>'."\n";;
1.367 www 8669: }
1.890 droeschl 8670:
8671: sub data_table_caption {
8672: my $caption = shift;
8673: return "<caption class=\"LC_caption\">$caption</caption>";
8674: }
1.347 albertel 8675: }
8676:
1.548 albertel 8677: =pod
8678:
8679: =item * &inhibit_menu_check($arg)
8680:
8681: Checks for a inhibitmenu state and generates output to preserve it
8682:
8683: Inputs: $arg - can be any of
8684: - undef - in which case the return value is a string
8685: to add into arguments list of a uri
8686: - 'input' - in which case the return value is a HTML
8687: <form> <input> field of type hidden to
8688: preserve the value
8689: - a url - in which case the return value is the url with
8690: the neccesary cgi args added to preserve the
8691: inhibitmenu state
8692: - a ref to a url - no return value, but the string is
8693: updated to include the neccessary cgi
8694: args to preserve the inhibitmenu state
8695:
8696: =cut
8697:
8698: sub inhibit_menu_check {
8699: my ($arg) = @_;
8700: &get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['inhibitmenu']);
8701: if ($arg eq 'input') {
8702: if ($env{'form.inhibitmenu'}) {
8703: return '<input type="hidden" name="inhibitmenu" value="'.$env{'form.inhibitmenu'}.'" />';
8704: } else {
8705: return
8706: }
8707: }
8708: if ($env{'form.inhibitmenu'}) {
8709: if (ref($arg)) {
8710: $$arg .= '?inhibitmenu='.$env{'form.inhibitmenu'};
8711: } elsif ($arg eq '') {
8712: $arg .= 'inhibitmenu='.$env{'form.inhibitmenu'};
8713: } else {
8714: $arg .= '?inhibitmenu='.$env{'form.inhibitmenu'};
8715: }
8716: }
8717: if (!ref($arg)) {
8718: return $arg;
8719: }
8720: }
8721:
1.251 albertel 8722: ###############################################
1.182 matthew 8723:
8724: =pod
8725:
1.549 albertel 8726: =back
8727:
8728: =head1 User Information Routines
8729:
8730: =over 4
8731:
1.405 albertel 8732: =item * &get_users_function()
1.182 matthew 8733:
8734: Used by &bodytag to determine the current users primary role.
8735: Returns either 'student','coordinator','admin', or 'author'.
8736:
8737: =cut
8738:
8739: ###############################################
8740: sub get_users_function {
1.815 tempelho 8741: my $function = 'norole';
1.818 tempelho 8742: if ($env{'request.role'}=~/^(st)/) {
8743: $function='student';
8744: }
1.907 raeburn 8745: if ($env{'request.role'}=~/^(cc|co|in|ta|ep)/) {
1.182 matthew 8746: $function='coordinator';
8747: }
1.258 albertel 8748: if ($env{'request.role'}=~/^(su|dc|ad|li)/) {
1.182 matthew 8749: $function='admin';
8750: }
1.826 bisitz 8751: if (($env{'request.role'}=~/^(au|ca|aa)/) ||
1.1025 raeburn 8752: ($ENV{'REQUEST_URI'}=~ m{/^(/priv)})) {
1.182 matthew 8753: $function='author';
8754: }
8755: return $function;
1.54 www 8756: }
1.99 www 8757:
8758: ###############################################
8759:
1.233 raeburn 8760: =pod
8761:
1.821 raeburn 8762: =item * &show_course()
8763:
8764: Used by lonmenu.pm and lonroles.pm to determine whether to use the word
8765: 'Courses' or 'Roles' in inline navigation and on screen displaying user's roles.
8766:
8767: Inputs:
8768: None
8769:
8770: Outputs:
8771: Scalar: 1 if 'Course' to be used, 0 otherwise.
8772:
8773: =cut
8774:
8775: ###############################################
8776: sub show_course {
8777: my $course = !$env{'user.adv'};
8778: if (!$env{'user.adv'}) {
8779: foreach my $env (keys(%env)) {
8780: next if ($env !~ m/^user\.priv\./);
8781: if ($env !~ m/^user\.priv\.(?:st|cm)/) {
8782: $course = 0;
8783: last;
8784: }
8785: }
8786: }
8787: return $course;
8788: }
8789:
8790: ###############################################
8791:
8792: =pod
8793:
1.542 raeburn 8794: =item * &check_user_status()
1.274 raeburn 8795:
8796: Determines current status of supplied role for a
8797: specific user. Roles can be active, previous or future.
8798:
8799: Inputs:
8800: user's domain, user's username, course's domain,
1.375 raeburn 8801: course's number, optional section ID.
1.274 raeburn 8802:
8803: Outputs:
8804: role status: active, previous or future.
8805:
8806: =cut
8807:
8808: sub check_user_status {
1.412 raeburn 8809: my ($udom,$uname,$cdom,$crs,$role,$sec) = @_;
1.1073 raeburn 8810: my %userinfo = &Apache::lonnet::dump('roles',$udom,$uname);
1.1075.2.85 raeburn 8811: my @uroles = keys(%userinfo);
1.274 raeburn 8812: my $srchstr;
8813: my $active_chk = 'none';
1.412 raeburn 8814: my $now = time;
1.274 raeburn 8815: if (@uroles > 0) {
1.908 raeburn 8816: if (($role eq 'cc') || ($role eq 'co') || ($sec eq '') || (!defined($sec))) {
1.274 raeburn 8817: $srchstr = '/'.$cdom.'/'.$crs.'_'.$role;
8818: } else {
1.412 raeburn 8819: $srchstr = '/'.$cdom.'/'.$crs.'/'.$sec.'_'.$role;
8820: }
8821: if (grep/^\Q$srchstr\E$/,@uroles) {
1.274 raeburn 8822: my $role_end = 0;
8823: my $role_start = 0;
8824: $active_chk = 'active';
1.412 raeburn 8825: if ($userinfo{$srchstr} =~ m/^\Q$role\E_(\d+)/) {
8826: $role_end = $1;
8827: if ($userinfo{$srchstr} =~ m/^\Q$role\E_\Q$role_end\E_(\d+)$/) {
8828: $role_start = $1;
1.274 raeburn 8829: }
8830: }
8831: if ($role_start > 0) {
1.412 raeburn 8832: if ($now < $role_start) {
1.274 raeburn 8833: $active_chk = 'future';
8834: }
8835: }
8836: if ($role_end > 0) {
1.412 raeburn 8837: if ($now > $role_end) {
1.274 raeburn 8838: $active_chk = 'previous';
8839: }
8840: }
8841: }
8842: }
8843: return $active_chk;
8844: }
8845:
8846: ###############################################
8847:
8848: =pod
8849:
1.405 albertel 8850: =item * &get_sections()
1.233 raeburn 8851:
8852: Determines all the sections for a course including
8853: sections with students and sections containing other roles.
1.419 raeburn 8854: Incoming parameters:
8855:
8856: 1. domain
8857: 2. course number
8858: 3. reference to array containing roles for which sections should
8859: be gathered (optional).
8860: 4. reference to array containing status types for which sections
8861: should be gathered (optional).
8862:
8863: If the third argument is undefined, sections are gathered for any role.
8864: If the fourth argument is undefined, sections are gathered for any status.
8865: Permissible values are 'active' or 'future' or 'previous'.
1.233 raeburn 8866:
1.374 raeburn 8867: Returns section hash (keys are section IDs, values are
8868: number of users in each section), subject to the
1.419 raeburn 8869: optional roles filter, optional status filter
1.233 raeburn 8870:
8871: =cut
8872:
8873: ###############################################
8874: sub get_sections {
1.419 raeburn 8875: my ($cdom,$cnum,$possible_roles,$possible_status) = @_;
1.366 albertel 8876: if (!defined($cdom) || !defined($cnum)) {
8877: my $cid = $env{'request.course.id'};
8878:
8879: return if (!defined($cid));
8880:
8881: $cdom = $env{'course.'.$cid.'.domain'};
8882: $cnum = $env{'course.'.$cid.'.num'};
8883: }
8884:
8885: my %sectioncount;
1.419 raeburn 8886: my $now = time;
1.240 albertel 8887:
1.1075.2.33 raeburn 8888: my $check_students = 1;
8889: my $only_students = 0;
8890: if (ref($possible_roles) eq 'ARRAY') {
8891: if (grep(/^st$/,@{$possible_roles})) {
8892: if (@{$possible_roles} == 1) {
8893: $only_students = 1;
8894: }
8895: } else {
8896: $check_students = 0;
8897: }
8898: }
8899:
8900: if ($check_students) {
1.276 albertel 8901: my ($classlist) = &Apache::loncoursedata::get_classlist($cdom,$cnum);
1.240 albertel 8902: my $sec_index = &Apache::loncoursedata::CL_SECTION();
8903: my $status_index = &Apache::loncoursedata::CL_STATUS();
1.419 raeburn 8904: my $start_index = &Apache::loncoursedata::CL_START();
8905: my $end_index = &Apache::loncoursedata::CL_END();
8906: my $status;
1.366 albertel 8907: while (my ($student,$data) = each(%$classlist)) {
1.419 raeburn 8908: my ($section,$stu_status,$start,$end) = ($data->[$sec_index],
8909: $data->[$status_index],
8910: $data->[$start_index],
8911: $data->[$end_index]);
8912: if ($stu_status eq 'Active') {
8913: $status = 'active';
8914: } elsif ($end < $now) {
8915: $status = 'previous';
8916: } elsif ($start > $now) {
8917: $status = 'future';
8918: }
8919: if ($section ne '-1' && $section !~ /^\s*$/) {
8920: if ((!defined($possible_status)) || (($status ne '') &&
8921: (grep/^\Q$status\E$/,@{$possible_status}))) {
8922: $sectioncount{$section}++;
8923: }
1.240 albertel 8924: }
8925: }
8926: }
1.1075.2.33 raeburn 8927: if ($only_students) {
8928: return %sectioncount;
8929: }
1.240 albertel 8930: my %courseroles = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
8931: foreach my $user (sort(keys(%courseroles))) {
8932: if ($user !~ /^(\w{2})/) { next; }
8933: my ($role) = ($user =~ /^(\w{2})/);
8934: if ($possible_roles && !(grep(/^$role$/,@$possible_roles))) { next; }
1.419 raeburn 8935: my ($section,$status);
1.240 albertel 8936: if ($role eq 'cr' &&
8937: $user =~ m-^$role/[^/]*/[^/]*/[^/]*:[^:]*:[^:]*:(\w+)-) {
8938: $section=$1;
8939: }
8940: if ($user =~ /^$role:[^:]*:[^:]*:(\w+)/) { $section=$1; }
8941: if (!defined($section) || $section eq '-1') { next; }
1.419 raeburn 8942: my ($end,$start) = ($courseroles{$user} =~ /^([^:]*):([^:]*)$/);
8943: if ($end == -1 && $start == -1) {
8944: next; #deleted role
8945: }
8946: if (!defined($possible_status)) {
8947: $sectioncount{$section}++;
8948: } else {
8949: if ((!$end || $end >= $now) && (!$start || $start <= $now)) {
8950: $status = 'active';
8951: } elsif ($end < $now) {
8952: $status = 'future';
8953: } elsif ($start > $now) {
8954: $status = 'previous';
8955: }
8956: if (($status ne '') && (grep/^\Q$status\E$/,@{$possible_status})) {
8957: $sectioncount{$section}++;
8958: }
8959: }
1.233 raeburn 8960: }
1.366 albertel 8961: return %sectioncount;
1.233 raeburn 8962: }
8963:
1.274 raeburn 8964: ###############################################
1.294 raeburn 8965:
8966: =pod
1.405 albertel 8967:
8968: =item * &get_course_users()
8969:
1.275 raeburn 8970: Retrieves usernames:domains for users in the specified course
8971: with specific role(s), and access status.
8972:
8973: Incoming parameters:
1.277 albertel 8974: 1. course domain
8975: 2. course number
8976: 3. access status: users must have - either active,
1.275 raeburn 8977: previous, future, or all.
1.277 albertel 8978: 4. reference to array of permissible roles
1.288 raeburn 8979: 5. reference to array of section restrictions (optional)
8980: 6. reference to results object (hash of hashes).
8981: 7. reference to optional userdata hash
1.609 raeburn 8982: 8. reference to optional statushash
1.630 raeburn 8983: 9. flag if privileged users (except those set to unhide in
8984: course settings) should be excluded
1.609 raeburn 8985: Keys of top level results hash are roles.
1.275 raeburn 8986: Keys of inner hashes are username:domain, with
8987: values set to access type.
1.288 raeburn 8988: Optional userdata hash returns an array with arguments in the
8989: same order as loncoursedata::get_classlist() for student data.
8990:
1.609 raeburn 8991: Optional statushash returns
8992:
1.288 raeburn 8993: Entries for end, start, section and status are blank because
8994: of the possibility of multiple values for non-student roles.
8995:
1.275 raeburn 8996: =cut
1.405 albertel 8997:
1.275 raeburn 8998: ###############################################
1.405 albertel 8999:
1.275 raeburn 9000: sub get_course_users {
1.630 raeburn 9001: my ($cdom,$cnum,$types,$roles,$sections,$users,$userdata,$statushash,$hidepriv) = @_;
1.288 raeburn 9002: my %idx = ();
1.419 raeburn 9003: my %seclists;
1.288 raeburn 9004:
9005: $idx{udom} = &Apache::loncoursedata::CL_SDOM();
9006: $idx{uname} = &Apache::loncoursedata::CL_SNAME();
9007: $idx{end} = &Apache::loncoursedata::CL_END();
9008: $idx{start} = &Apache::loncoursedata::CL_START();
9009: $idx{id} = &Apache::loncoursedata::CL_ID();
9010: $idx{section} = &Apache::loncoursedata::CL_SECTION();
9011: $idx{fullname} = &Apache::loncoursedata::CL_FULLNAME();
9012: $idx{status} = &Apache::loncoursedata::CL_STATUS();
9013:
1.290 albertel 9014: if (grep(/^st$/,@{$roles})) {
1.276 albertel 9015: my ($classlist,$keylist)=&Apache::loncoursedata::get_classlist($cdom,$cnum);
1.278 raeburn 9016: my $now = time;
1.277 albertel 9017: foreach my $student (keys(%{$classlist})) {
1.288 raeburn 9018: my $match = 0;
1.412 raeburn 9019: my $secmatch = 0;
1.419 raeburn 9020: my $section = $$classlist{$student}[$idx{section}];
1.609 raeburn 9021: my $status = $$classlist{$student}[$idx{status}];
1.419 raeburn 9022: if ($section eq '') {
9023: $section = 'none';
9024: }
1.291 albertel 9025: if ((ref($sections) eq 'ARRAY') && (@{$sections} > 0)) {
1.420 albertel 9026: if (grep(/^all$/,@{$sections})) {
1.412 raeburn 9027: $secmatch = 1;
9028: } elsif ($$classlist{$student}[$idx{section}] eq '') {
1.420 albertel 9029: if (grep(/^none$/,@{$sections})) {
1.412 raeburn 9030: $secmatch = 1;
9031: }
9032: } else {
1.419 raeburn 9033: if (grep(/^\Q$section\E$/,@{$sections})) {
1.412 raeburn 9034: $secmatch = 1;
9035: }
1.290 albertel 9036: }
1.412 raeburn 9037: if (!$secmatch) {
9038: next;
9039: }
1.419 raeburn 9040: }
1.275 raeburn 9041: if (defined($$types{'active'})) {
1.288 raeburn 9042: if ($$classlist{$student}[$idx{status}] eq 'Active') {
1.275 raeburn 9043: push(@{$$users{st}{$student}},'active');
1.288 raeburn 9044: $match = 1;
1.275 raeburn 9045: }
9046: }
9047: if (defined($$types{'previous'})) {
1.609 raeburn 9048: if ($$classlist{$student}[$idx{status}] eq 'Expired') {
1.275 raeburn 9049: push(@{$$users{st}{$student}},'previous');
1.288 raeburn 9050: $match = 1;
1.275 raeburn 9051: }
9052: }
9053: if (defined($$types{'future'})) {
1.609 raeburn 9054: if ($$classlist{$student}[$idx{status}] eq 'Future') {
1.275 raeburn 9055: push(@{$$users{st}{$student}},'future');
1.288 raeburn 9056: $match = 1;
1.275 raeburn 9057: }
9058: }
1.609 raeburn 9059: if ($match) {
9060: push(@{$seclists{$student}},$section);
9061: if (ref($userdata) eq 'HASH') {
9062: $$userdata{$student} = $$classlist{$student};
9063: }
9064: if (ref($statushash) eq 'HASH') {
9065: $statushash->{$student}{'st'}{$section} = $status;
9066: }
1.288 raeburn 9067: }
1.275 raeburn 9068: }
9069: }
1.412 raeburn 9070: if ((@{$roles} > 1) || ((@{$roles} == 1) && ($$roles[0] ne "st"))) {
1.439 raeburn 9071: my %coursepersonnel = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
9072: my $now = time;
1.609 raeburn 9073: my %displaystatus = ( previous => 'Expired',
9074: active => 'Active',
9075: future => 'Future',
9076: );
1.1075.2.36 raeburn 9077: my (%nothide,@possdoms);
1.630 raeburn 9078: if ($hidepriv) {
9079: my %coursehash=&Apache::lonnet::coursedescription($cdom.'_'.$cnum);
9080: foreach my $user (split(/\s*\,\s*/,$coursehash{'nothideprivileged'})) {
9081: if ($user !~ /:/) {
9082: $nothide{join(':',split(/[\@]/,$user))}=1;
9083: } else {
9084: $nothide{$user} = 1;
9085: }
9086: }
1.1075.2.36 raeburn 9087: my @possdoms = ($cdom);
9088: if ($coursehash{'checkforpriv'}) {
9089: push(@possdoms,split(/,/,$coursehash{'checkforpriv'}));
9090: }
1.630 raeburn 9091: }
1.439 raeburn 9092: foreach my $person (sort(keys(%coursepersonnel))) {
1.288 raeburn 9093: my $match = 0;
1.412 raeburn 9094: my $secmatch = 0;
1.439 raeburn 9095: my $status;
1.412 raeburn 9096: my ($role,$user,$usec) = ($person =~ /^([^:]*):([^:]+:[^:]+):([^:]*)/);
1.275 raeburn 9097: $user =~ s/:$//;
1.439 raeburn 9098: my ($end,$start) = split(/:/,$coursepersonnel{$person});
9099: if ($end == -1 || $start == -1) {
9100: next;
9101: }
9102: if (($role) && ((grep(/^\Q$role\E$/,@{$roles})) ||
9103: (grep(/^cr$/,@{$roles}) && $role =~ /^cr\//))) {
1.412 raeburn 9104: my ($uname,$udom) = split(/:/,$user);
9105: if ((ref($sections) eq 'ARRAY') && (@{$sections} > 0)) {
1.420 albertel 9106: if (grep(/^all$/,@{$sections})) {
1.412 raeburn 9107: $secmatch = 1;
9108: } elsif ($usec eq '') {
1.420 albertel 9109: if (grep(/^none$/,@{$sections})) {
1.412 raeburn 9110: $secmatch = 1;
9111: }
9112: } else {
9113: if (grep(/^\Q$usec\E$/,@{$sections})) {
9114: $secmatch = 1;
9115: }
9116: }
9117: if (!$secmatch) {
9118: next;
9119: }
1.288 raeburn 9120: }
1.419 raeburn 9121: if ($usec eq '') {
9122: $usec = 'none';
9123: }
1.275 raeburn 9124: if ($uname ne '' && $udom ne '') {
1.630 raeburn 9125: if ($hidepriv) {
1.1075.2.36 raeburn 9126: if ((&Apache::lonnet::privileged($uname,$udom,\@possdoms)) &&
1.630 raeburn 9127: (!$nothide{$uname.':'.$udom})) {
9128: next;
9129: }
9130: }
1.503 raeburn 9131: if ($end > 0 && $end < $now) {
1.439 raeburn 9132: $status = 'previous';
9133: } elsif ($start > $now) {
9134: $status = 'future';
9135: } else {
9136: $status = 'active';
9137: }
1.277 albertel 9138: foreach my $type (keys(%{$types})) {
1.275 raeburn 9139: if ($status eq $type) {
1.420 albertel 9140: if (!grep(/^\Q$type\E$/,@{$$users{$role}{$user}})) {
1.419 raeburn 9141: push(@{$$users{$role}{$user}},$type);
9142: }
1.288 raeburn 9143: $match = 1;
9144: }
9145: }
1.419 raeburn 9146: if (($match) && (ref($userdata) eq 'HASH')) {
9147: if (!exists($$userdata{$uname.':'.$udom})) {
9148: &get_user_info($udom,$uname,\%idx,$userdata);
9149: }
1.420 albertel 9150: if (!grep(/^\Q$usec\E$/,@{$seclists{$uname.':'.$udom}})) {
1.419 raeburn 9151: push(@{$seclists{$uname.':'.$udom}},$usec);
9152: }
1.609 raeburn 9153: if (ref($statushash) eq 'HASH') {
9154: $statushash->{$uname.':'.$udom}{$role}{$usec} = $displaystatus{$status};
9155: }
1.275 raeburn 9156: }
9157: }
9158: }
9159: }
1.290 albertel 9160: if (grep(/^ow$/,@{$roles})) {
1.279 raeburn 9161: if ((defined($cdom)) && (defined($cnum))) {
9162: my %csettings = &Apache::lonnet::get('environment',['internal.courseowner'],$cdom,$cnum);
9163: if ( defined($csettings{'internal.courseowner'}) ) {
9164: my $owner = $csettings{'internal.courseowner'};
1.609 raeburn 9165: next if ($owner eq '');
9166: my ($ownername,$ownerdom);
9167: if ($owner =~ /^([^:]+):([^:]+)$/) {
9168: $ownername = $1;
9169: $ownerdom = $2;
9170: } else {
9171: $ownername = $owner;
9172: $ownerdom = $cdom;
9173: $owner = $ownername.':'.$ownerdom;
1.439 raeburn 9174: }
9175: @{$$users{'ow'}{$owner}} = 'any';
1.290 albertel 9176: if (defined($userdata) &&
1.609 raeburn 9177: !exists($$userdata{$owner})) {
9178: &get_user_info($ownerdom,$ownername,\%idx,$userdata);
9179: if (!grep(/^none$/,@{$seclists{$owner}})) {
9180: push(@{$seclists{$owner}},'none');
9181: }
9182: if (ref($statushash) eq 'HASH') {
9183: $statushash->{$owner}{'ow'}{'none'} = 'Any';
1.419 raeburn 9184: }
1.290 albertel 9185: }
1.279 raeburn 9186: }
9187: }
9188: }
1.419 raeburn 9189: foreach my $user (keys(%seclists)) {
9190: @{$seclists{$user}} = (sort {$a <=> $b} @{$seclists{$user}});
9191: $$userdata{$user}[$idx{section}] = join(',',@{$seclists{$user}});
9192: }
1.275 raeburn 9193: }
9194: return;
9195: }
9196:
1.288 raeburn 9197: sub get_user_info {
9198: my ($udom,$uname,$idx,$userdata) = @_;
1.289 albertel 9199: $$userdata{$uname.':'.$udom}[$$idx{fullname}] =
9200: &plainname($uname,$udom,'lastname');
1.291 albertel 9201: $$userdata{$uname.':'.$udom}[$$idx{uname}] = $uname;
1.297 raeburn 9202: $$userdata{$uname.':'.$udom}[$$idx{udom}] = $udom;
1.609 raeburn 9203: my %idhash = &Apache::lonnet::idrget($udom,($uname));
9204: $$userdata{$uname.':'.$udom}[$$idx{id}] = $idhash{$uname};
1.288 raeburn 9205: return;
9206: }
1.275 raeburn 9207:
1.472 raeburn 9208: ###############################################
9209:
9210: =pod
9211:
9212: =item * &get_user_quota()
9213:
1.1075.2.41 raeburn 9214: Retrieves quota assigned for storage of user files.
9215: Default is to report quota for portfolio files.
1.472 raeburn 9216:
9217: Incoming parameters:
9218: 1. user's username
9219: 2. user's domain
1.1075.2.41 raeburn 9220: 3. quota name - portfolio, author, or course
9221: (if no quota name provided, defaults to portfolio).
1.1075.2.59 raeburn 9222: 4. crstype - official, unofficial, textbook or community, if quota name is
1.1075.2.42 raeburn 9223: course
1.472 raeburn 9224:
9225: Returns:
1.1075.2.58 raeburn 9226: 1. Disk quota (in MB) assigned to student.
1.536 raeburn 9227: 2. (Optional) Type of setting: custom or default
9228: (individually assigned or default for user's
9229: institutional status).
9230: 3. (Optional) - User's institutional status (e.g., faculty, staff
9231: or student - types as defined in localenroll::inst_usertypes
9232: for user's domain, which determines default quota for user.
9233: 4. (Optional) - Default quota which would apply to the user.
1.472 raeburn 9234:
9235: If a value has been stored in the user's environment,
1.536 raeburn 9236: it will return that, otherwise it returns the maximal default
1.1075.2.41 raeburn 9237: defined for the user's institutional status(es) in the domain.
1.472 raeburn 9238:
9239: =cut
9240:
9241: ###############################################
9242:
9243:
9244: sub get_user_quota {
1.1075.2.42 raeburn 9245: my ($uname,$udom,$quotaname,$crstype) = @_;
1.536 raeburn 9246: my ($quota,$quotatype,$settingstatus,$defquota);
1.472 raeburn 9247: if (!defined($udom)) {
9248: $udom = $env{'user.domain'};
9249: }
9250: if (!defined($uname)) {
9251: $uname = $env{'user.name'};
9252: }
9253: if (($udom eq '' || $uname eq '') ||
9254: ($udom eq 'public') && ($uname eq 'public')) {
9255: $quota = 0;
1.536 raeburn 9256: $quotatype = 'default';
9257: $defquota = 0;
1.472 raeburn 9258: } else {
1.536 raeburn 9259: my $inststatus;
1.1075.2.41 raeburn 9260: if ($quotaname eq 'course') {
9261: if (($env{'course.'.$udom.'_'.$uname.'.num'} eq $uname) &&
9262: ($env{'course.'.$udom.'_'.$uname.'.domain'} eq $udom)) {
9263: $quota = $env{'course.'.$udom.'_'.$uname.'.internal.uploadquota'};
9264: } else {
9265: my %cenv = &Apache::lonnet::coursedescription("$udom/$uname");
9266: $quota = $cenv{'internal.uploadquota'};
9267: }
1.536 raeburn 9268: } else {
1.1075.2.41 raeburn 9269: if ($udom eq $env{'user.domain'} && $uname eq $env{'user.name'}) {
9270: if ($quotaname eq 'author') {
9271: $quota = $env{'environment.authorquota'};
9272: } else {
9273: $quota = $env{'environment.portfolioquota'};
9274: }
9275: $inststatus = $env{'environment.inststatus'};
9276: } else {
9277: my %userenv =
9278: &Apache::lonnet::get('environment',['portfolioquota',
9279: 'authorquota','inststatus'],$udom,$uname);
9280: my ($tmp) = keys(%userenv);
9281: if ($tmp !~ /^(con_lost|error|no_such_host)/i) {
9282: if ($quotaname eq 'author') {
9283: $quota = $userenv{'authorquota'};
9284: } else {
9285: $quota = $userenv{'portfolioquota'};
9286: }
9287: $inststatus = $userenv{'inststatus'};
9288: } else {
9289: undef(%userenv);
9290: }
9291: }
9292: }
9293: if ($quota eq '' || wantarray) {
9294: if ($quotaname eq 'course') {
9295: my %domdefs = &Apache::lonnet::get_domain_defaults($udom);
1.1075.2.59 raeburn 9296: if (($crstype eq 'official') || ($crstype eq 'unofficial') ||
9297: ($crstype eq 'community') || ($crstype eq 'textbook')) {
1.1075.2.42 raeburn 9298: $defquota = $domdefs{$crstype.'quota'};
9299: }
9300: if ($defquota eq '') {
9301: $defquota = 500;
9302: }
1.1075.2.41 raeburn 9303: } else {
9304: ($defquota,$settingstatus) = &default_quota($udom,$inststatus,$quotaname);
9305: }
9306: if ($quota eq '') {
9307: $quota = $defquota;
9308: $quotatype = 'default';
9309: } else {
9310: $quotatype = 'custom';
9311: }
1.472 raeburn 9312: }
9313: }
1.536 raeburn 9314: if (wantarray) {
9315: return ($quota,$quotatype,$settingstatus,$defquota);
9316: } else {
9317: return $quota;
9318: }
1.472 raeburn 9319: }
9320:
9321: ###############################################
9322:
9323: =pod
9324:
9325: =item * &default_quota()
9326:
1.536 raeburn 9327: Retrieves default quota assigned for storage of user portfolio files,
9328: given an (optional) user's institutional status.
1.472 raeburn 9329:
9330: Incoming parameters:
1.1075.2.42 raeburn 9331:
1.472 raeburn 9332: 1. domain
1.536 raeburn 9333: 2. (Optional) institutional status(es). This is a : separated list of
9334: status types (e.g., faculty, staff, student etc.)
9335: which apply to the user for whom the default is being retrieved.
9336: If the institutional status string in undefined, the domain
1.1075.2.41 raeburn 9337: default quota will be returned.
9338: 3. quota name - portfolio, author, or course
9339: (if no quota name provided, defaults to portfolio).
1.472 raeburn 9340:
9341: Returns:
1.1075.2.42 raeburn 9342:
1.1075.2.58 raeburn 9343: 1. Default disk quota (in MB) for user portfolios in the domain.
1.536 raeburn 9344: 2. (Optional) institutional type which determined the value of the
9345: default quota.
1.472 raeburn 9346:
9347: If a value has been stored in the domain's configuration db,
9348: it will return that, otherwise it returns 20 (for backwards
9349: compatibility with domains which have not set up a configuration
1.1075.2.58 raeburn 9350: db file; the original statically defined portfolio quota was 20 MB).
1.472 raeburn 9351:
1.536 raeburn 9352: If the user's status includes multiple types (e.g., staff and student),
9353: the largest default quota which applies to the user determines the
9354: default quota returned.
9355:
1.472 raeburn 9356: =cut
9357:
9358: ###############################################
9359:
9360:
9361: sub default_quota {
1.1075.2.41 raeburn 9362: my ($udom,$inststatus,$quotaname) = @_;
1.536 raeburn 9363: my ($defquota,$settingstatus);
9364: my %quotahash = &Apache::lonnet::get_dom('configuration',
1.622 raeburn 9365: ['quotas'],$udom);
1.1075.2.41 raeburn 9366: my $key = 'defaultquota';
9367: if ($quotaname eq 'author') {
9368: $key = 'authorquota';
9369: }
1.622 raeburn 9370: if (ref($quotahash{'quotas'}) eq 'HASH') {
1.536 raeburn 9371: if ($inststatus ne '') {
1.765 raeburn 9372: my @statuses = map { &unescape($_); } split(/:/,$inststatus);
1.536 raeburn 9373: foreach my $item (@statuses) {
1.1075.2.41 raeburn 9374: if (ref($quotahash{'quotas'}{$key}) eq 'HASH') {
9375: if ($quotahash{'quotas'}{$key}{$item} ne '') {
1.711 raeburn 9376: if ($defquota eq '') {
1.1075.2.41 raeburn 9377: $defquota = $quotahash{'quotas'}{$key}{$item};
1.711 raeburn 9378: $settingstatus = $item;
1.1075.2.41 raeburn 9379: } elsif ($quotahash{'quotas'}{$key}{$item} > $defquota) {
9380: $defquota = $quotahash{'quotas'}{$key}{$item};
1.711 raeburn 9381: $settingstatus = $item;
9382: }
9383: }
1.1075.2.41 raeburn 9384: } elsif ($key eq 'defaultquota') {
1.711 raeburn 9385: if ($quotahash{'quotas'}{$item} ne '') {
9386: if ($defquota eq '') {
9387: $defquota = $quotahash{'quotas'}{$item};
9388: $settingstatus = $item;
9389: } elsif ($quotahash{'quotas'}{$item} > $defquota) {
9390: $defquota = $quotahash{'quotas'}{$item};
9391: $settingstatus = $item;
9392: }
1.536 raeburn 9393: }
9394: }
9395: }
9396: }
9397: if ($defquota eq '') {
1.1075.2.41 raeburn 9398: if (ref($quotahash{'quotas'}{$key}) eq 'HASH') {
9399: $defquota = $quotahash{'quotas'}{$key}{'default'};
9400: } elsif ($key eq 'defaultquota') {
1.711 raeburn 9401: $defquota = $quotahash{'quotas'}{'default'};
9402: }
1.536 raeburn 9403: $settingstatus = 'default';
1.1075.2.42 raeburn 9404: if ($defquota eq '') {
9405: if ($quotaname eq 'author') {
9406: $defquota = 500;
9407: }
9408: }
1.536 raeburn 9409: }
9410: } else {
9411: $settingstatus = 'default';
1.1075.2.41 raeburn 9412: if ($quotaname eq 'author') {
9413: $defquota = 500;
9414: } else {
9415: $defquota = 20;
9416: }
1.536 raeburn 9417: }
9418: if (wantarray) {
9419: return ($defquota,$settingstatus);
1.472 raeburn 9420: } else {
1.536 raeburn 9421: return $defquota;
1.472 raeburn 9422: }
9423: }
9424:
1.1075.2.41 raeburn 9425: ###############################################
9426:
9427: =pod
9428:
1.1075.2.42 raeburn 9429: =item * &excess_filesize_warning()
1.1075.2.41 raeburn 9430:
9431: Returns warning message if upload of file to authoring space, or copying
1.1075.2.42 raeburn 9432: of existing file within authoring space will cause quota for the authoring
9433: space to be exceeded.
9434:
9435: Same, if upload of a file directly to a course/community via Course Editor
9436: will cause quota for uploaded content for the course to be exceeded.
1.1075.2.41 raeburn 9437:
1.1075.2.61 raeburn 9438: Inputs: 7
1.1075.2.42 raeburn 9439: 1. username or coursenum
1.1075.2.41 raeburn 9440: 2. domain
1.1075.2.42 raeburn 9441: 3. context ('author' or 'course')
1.1075.2.41 raeburn 9442: 4. filename of file for which action is being requested
9443: 5. filesize (kB) of file
9444: 6. action being taken: copy or upload.
1.1075.2.59 raeburn 9445: 7. quotatype (in course context -- official, unofficial, community or textbook).
1.1075.2.41 raeburn 9446:
9447: Returns: 1 scalar: HTML to display containing warning if quota would be exceeded,
9448: otherwise return null.
9449:
1.1075.2.42 raeburn 9450: =back
9451:
1.1075.2.41 raeburn 9452: =cut
9453:
1.1075.2.42 raeburn 9454: sub excess_filesize_warning {
1.1075.2.59 raeburn 9455: my ($uname,$udom,$context,$filename,$filesize,$action,$quotatype) = @_;
1.1075.2.42 raeburn 9456: my $current_disk_usage = 0;
1.1075.2.59 raeburn 9457: my $disk_quota = &get_user_quota($uname,$udom,$context,$quotatype); #expressed in MB
1.1075.2.42 raeburn 9458: if ($context eq 'author') {
9459: my $authorspace = $Apache::lonnet::perlvar{'lonDocRoot'}."/priv/$udom/$uname";
9460: $current_disk_usage = &Apache::lonnet::diskusage($udom,$uname,$authorspace);
9461: } else {
9462: foreach my $subdir ('docs','supplemental') {
9463: $current_disk_usage += &Apache::lonnet::diskusage($udom,$uname,"userfiles/$subdir",1);
9464: }
9465: }
1.1075.2.41 raeburn 9466: $disk_quota = int($disk_quota * 1000);
9467: if (($current_disk_usage + $filesize) > $disk_quota) {
1.1075.2.69 raeburn 9468: return '<p class="LC_warning">'.
1.1075.2.41 raeburn 9469: &mt("Unable to $action [_1]. (size = [_2] kilobytes). Disk quota will be exceeded.",
1.1075.2.69 raeburn 9470: '<span class="LC_filename">'.$filename.'</span>',$filesize).'</p>'.
9471: '<p>'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.',
1.1075.2.41 raeburn 9472: $disk_quota,$current_disk_usage).
9473: '</p>';
9474: }
9475: return;
9476: }
9477:
9478: ###############################################
9479:
9480:
1.384 raeburn 9481: sub get_secgrprole_info {
9482: my ($cdom,$cnum,$needroles,$type) = @_;
9483: my %sections_count = &get_sections($cdom,$cnum);
9484: my @sections = (sort {$a <=> $b} keys(%sections_count));
9485: my %curr_groups = &Apache::longroup::coursegroups($cdom,$cnum);
9486: my @groups = sort(keys(%curr_groups));
9487: my $allroles = [];
9488: my $rolehash;
9489: my $accesshash = {
9490: active => 'Currently has access',
9491: future => 'Will have future access',
9492: previous => 'Previously had access',
9493: };
9494: if ($needroles) {
9495: $rolehash = {'all' => 'all'};
1.385 albertel 9496: my %user_roles = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
9497: if (&Apache::lonnet::error(%user_roles)) {
9498: undef(%user_roles);
9499: }
9500: foreach my $item (keys(%user_roles)) {
1.384 raeburn 9501: my ($role)=split(/\:/,$item,2);
9502: if ($role eq 'cr') { next; }
9503: if ($role =~ /^cr/) {
9504: $$rolehash{$role} = (split('/',$role))[3];
9505: } else {
9506: $$rolehash{$role} = &Apache::lonnet::plaintext($role,$type);
9507: }
9508: }
9509: foreach my $key (sort(keys(%{$rolehash}))) {
9510: push(@{$allroles},$key);
9511: }
9512: push (@{$allroles},'st');
9513: $$rolehash{'st'} = &Apache::lonnet::plaintext('st',$type);
9514: }
9515: return (\@sections,\@groups,$allroles,$rolehash,$accesshash);
9516: }
9517:
1.555 raeburn 9518: sub user_picker {
1.1075.2.115! raeburn 9519: my ($dom,$srch,$forcenewuser,$caller,$cancreate,$usertype,$context,$fixeddom) = @_;
1.555 raeburn 9520: my $currdom = $dom;
1.1075.2.114 raeburn 9521: my @alldoms = &Apache::lonnet::all_domains();
9522: if (@alldoms == 1) {
9523: my %domsrch = &Apache::lonnet::get_dom('configuration',
9524: ['directorysrch'],$alldoms[0]);
9525: my $domdesc = &Apache::lonnet::domain($alldoms[0],'description');
9526: my $showdom = $domdesc;
9527: if ($showdom eq '') {
9528: $showdom = $dom;
9529: }
9530: if (ref($domsrch{'directorysrch'}) eq 'HASH') {
9531: if ((!$domsrch{'directorysrch'}{'available'}) &&
9532: ($domsrch{'directorysrch'}{'lcavailable'} eq '0')) {
9533: return (&mt('LON-CAPA directory search is not available in domain: [_1]',$showdom),0);
9534: }
9535: }
9536: }
1.555 raeburn 9537: my %curr_selected = (
9538: srchin => 'dom',
1.580 raeburn 9539: srchby => 'lastname',
1.555 raeburn 9540: );
9541: my $srchterm;
1.625 raeburn 9542: if ((ref($srch) eq 'HASH') && ($env{'form.origform'} ne 'crtusername')) {
1.555 raeburn 9543: if ($srch->{'srchby'} ne '') {
9544: $curr_selected{'srchby'} = $srch->{'srchby'};
9545: }
9546: if ($srch->{'srchin'} ne '') {
9547: $curr_selected{'srchin'} = $srch->{'srchin'};
9548: }
9549: if ($srch->{'srchtype'} ne '') {
9550: $curr_selected{'srchtype'} = $srch->{'srchtype'};
9551: }
9552: if ($srch->{'srchdomain'} ne '') {
9553: $currdom = $srch->{'srchdomain'};
9554: }
9555: $srchterm = $srch->{'srchterm'};
9556: }
1.1075.2.98 raeburn 9557: my %html_lt=&Apache::lonlocal::texthash(
1.573 raeburn 9558: 'usr' => 'Search criteria',
1.563 raeburn 9559: 'doma' => 'Domain/institution to search',
1.558 albertel 9560: 'uname' => 'username',
9561: 'lastname' => 'last name',
1.555 raeburn 9562: 'lastfirst' => 'last name, first name',
1.558 albertel 9563: 'crs' => 'in this course',
1.576 raeburn 9564: 'dom' => 'in selected LON-CAPA domain',
1.558 albertel 9565: 'alc' => 'all LON-CAPA',
1.573 raeburn 9566: 'instd' => 'in institutional directory for selected domain',
1.558 albertel 9567: 'exact' => 'is',
9568: 'contains' => 'contains',
1.569 raeburn 9569: 'begins' => 'begins with',
1.1075.2.98 raeburn 9570: );
9571: my %js_lt=&Apache::lonlocal::texthash(
1.571 raeburn 9572: 'youm' => "You must include some text to search for.",
9573: 'thte' => "The text you are searching for must contain at least two characters when using a 'begins' type search.",
9574: 'thet' => "The text you are searching for must contain at least three characters when using a 'contains' type search.",
9575: 'yomc' => "You must choose a domain when using an institutional directory search.",
9576: 'ymcd' => "You must choose a domain when using a domain search.",
9577: 'whus' => "When using searching by last,first you must include a comma as separator between last name and first name.",
9578: 'whse' => "When searching by last,first you must include at least one character in the first name.",
9579: 'thfo' => "The following need to be corrected before the search can be run:",
1.555 raeburn 9580: );
1.1075.2.98 raeburn 9581: &html_escape(\%html_lt);
9582: &js_escape(\%js_lt);
1.1075.2.115! raeburn 9583: my $domform;
! 9584: if ($fixeddom) {
! 9585: $domform = &select_dom_form($currdom,'srchdomain',1,1,undef,[$currdom]);
! 9586: } else {
! 9587: $domform = &select_dom_form($currdom,'srchdomain',1,1);
! 9588: }
1.563 raeburn 9589: my $srchinsel = ' <select name="srchin">';
1.555 raeburn 9590:
9591: my @srchins = ('crs','dom','alc','instd');
9592:
9593: foreach my $option (@srchins) {
9594: # FIXME 'alc' option unavailable until
9595: # loncreateuser::print_user_query_page()
9596: # has been completed.
9597: next if ($option eq 'alc');
1.880 raeburn 9598: next if (($option eq 'crs') && ($env{'form.form'} eq 'requestcrs'));
1.555 raeburn 9599: next if ($option eq 'crs' && !$env{'request.course.id'});
1.563 raeburn 9600: if ($curr_selected{'srchin'} eq $option) {
9601: $srchinsel .= '
1.1075.2.98 raeburn 9602: <option value="'.$option.'" selected="selected">'.$html_lt{$option}.'</option>';
1.563 raeburn 9603: } else {
9604: $srchinsel .= '
1.1075.2.98 raeburn 9605: <option value="'.$option.'">'.$html_lt{$option}.'</option>';
1.563 raeburn 9606: }
1.555 raeburn 9607: }
1.563 raeburn 9608: $srchinsel .= "\n </select>\n";
1.555 raeburn 9609:
9610: my $srchbysel = ' <select name="srchby">';
1.580 raeburn 9611: foreach my $option ('lastname','lastfirst','uname') {
1.555 raeburn 9612: if ($curr_selected{'srchby'} eq $option) {
9613: $srchbysel .= '
1.1075.2.98 raeburn 9614: <option value="'.$option.'" selected="selected">'.$html_lt{$option}.'</option>';
1.555 raeburn 9615: } else {
9616: $srchbysel .= '
1.1075.2.98 raeburn 9617: <option value="'.$option.'">'.$html_lt{$option}.'</option>';
1.555 raeburn 9618: }
9619: }
9620: $srchbysel .= "\n </select>\n";
9621:
9622: my $srchtypesel = ' <select name="srchtype">';
1.580 raeburn 9623: foreach my $option ('begins','contains','exact') {
1.555 raeburn 9624: if ($curr_selected{'srchtype'} eq $option) {
9625: $srchtypesel .= '
1.1075.2.98 raeburn 9626: <option value="'.$option.'" selected="selected">'.$html_lt{$option}.'</option>';
1.555 raeburn 9627: } else {
9628: $srchtypesel .= '
1.1075.2.98 raeburn 9629: <option value="'.$option.'">'.$html_lt{$option}.'</option>';
1.555 raeburn 9630: }
9631: }
9632: $srchtypesel .= "\n </select>\n";
9633:
1.558 albertel 9634: my ($newuserscript,$new_user_create);
1.994 raeburn 9635: my $context_dom = $env{'request.role.domain'};
9636: if ($context eq 'requestcrs') {
9637: if ($env{'form.coursedom'} ne '') {
9638: $context_dom = $env{'form.coursedom'};
9639: }
9640: }
1.556 raeburn 9641: if ($forcenewuser) {
1.576 raeburn 9642: if (ref($srch) eq 'HASH') {
1.994 raeburn 9643: if ($srch->{'srchby'} eq 'uname' && $srch->{'srchtype'} eq 'exact' && $srch->{'srchin'} eq 'dom' && $srch->{'srchdomain'} eq $context_dom) {
1.627 raeburn 9644: if ($cancreate) {
9645: $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>';
9646: } else {
1.799 bisitz 9647: my $helplink = 'javascript:helpMenu('."'display'".')';
1.627 raeburn 9648: my %usertypetext = (
9649: official => 'institutional',
9650: unofficial => 'non-institutional',
9651: );
1.799 bisitz 9652: $new_user_create = '<p class="LC_warning">'
9653: .&mt("You are not authorized to create new $usertypetext{$usertype} users in this domain.")
9654: .' '
9655: .&mt('Please contact the [_1]helpdesk[_2] for assistance.'
9656: ,'<a href="'.$helplink.'">','</a>')
9657: .'</p><br />';
1.627 raeburn 9658: }
1.576 raeburn 9659: }
9660: }
9661:
1.556 raeburn 9662: $newuserscript = <<"ENDSCRIPT";
9663:
1.570 raeburn 9664: function setSearch(createnew,callingForm) {
1.556 raeburn 9665: if (createnew == 1) {
1.570 raeburn 9666: for (var i=0; i<callingForm.srchby.length; i++) {
9667: if (callingForm.srchby.options[i].value == 'uname') {
9668: callingForm.srchby.selectedIndex = i;
1.556 raeburn 9669: }
9670: }
1.570 raeburn 9671: for (var i=0; i<callingForm.srchin.length; i++) {
9672: if ( callingForm.srchin.options[i].value == 'dom') {
9673: callingForm.srchin.selectedIndex = i;
1.556 raeburn 9674: }
9675: }
1.570 raeburn 9676: for (var i=0; i<callingForm.srchtype.length; i++) {
9677: if (callingForm.srchtype.options[i].value == 'exact') {
9678: callingForm.srchtype.selectedIndex = i;
1.556 raeburn 9679: }
9680: }
1.570 raeburn 9681: for (var i=0; i<callingForm.srchdomain.length; i++) {
1.994 raeburn 9682: if (callingForm.srchdomain.options[i].value == '$context_dom') {
1.570 raeburn 9683: callingForm.srchdomain.selectedIndex = i;
1.556 raeburn 9684: }
9685: }
9686: }
9687: }
9688: ENDSCRIPT
1.558 albertel 9689:
1.556 raeburn 9690: }
9691:
1.555 raeburn 9692: my $output = <<"END_BLOCK";
1.556 raeburn 9693: <script type="text/javascript">
1.824 bisitz 9694: // <![CDATA[
1.570 raeburn 9695: function validateEntry(callingForm) {
1.558 albertel 9696:
1.556 raeburn 9697: var checkok = 1;
1.558 albertel 9698: var srchin;
1.570 raeburn 9699: for (var i=0; i<callingForm.srchin.length; i++) {
9700: if ( callingForm.srchin[i].checked ) {
9701: srchin = callingForm.srchin[i].value;
1.558 albertel 9702: }
9703: }
9704:
1.570 raeburn 9705: var srchtype = callingForm.srchtype.options[callingForm.srchtype.selectedIndex].value;
9706: var srchby = callingForm.srchby.options[callingForm.srchby.selectedIndex].value;
9707: var srchdomain = callingForm.srchdomain.options[callingForm.srchdomain.selectedIndex].value;
9708: var srchterm = callingForm.srchterm.value;
9709: var srchin = callingForm.srchin.options[callingForm.srchin.selectedIndex].value;
1.556 raeburn 9710: var msg = "";
9711:
9712: if (srchterm == "") {
9713: checkok = 0;
1.1075.2.98 raeburn 9714: msg += "$js_lt{'youm'}\\n";
1.556 raeburn 9715: }
9716:
1.569 raeburn 9717: if (srchtype== 'begins') {
9718: if (srchterm.length < 2) {
9719: checkok = 0;
1.1075.2.98 raeburn 9720: msg += "$js_lt{'thte'}\\n";
1.569 raeburn 9721: }
9722: }
9723:
1.556 raeburn 9724: if (srchtype== 'contains') {
9725: if (srchterm.length < 3) {
9726: checkok = 0;
1.1075.2.98 raeburn 9727: msg += "$js_lt{'thet'}\\n";
1.556 raeburn 9728: }
9729: }
9730: if (srchin == 'instd') {
9731: if (srchdomain == '') {
9732: checkok = 0;
1.1075.2.98 raeburn 9733: msg += "$js_lt{'yomc'}\\n";
1.556 raeburn 9734: }
9735: }
9736: if (srchin == 'dom') {
9737: if (srchdomain == '') {
9738: checkok = 0;
1.1075.2.98 raeburn 9739: msg += "$js_lt{'ymcd'}\\n";
1.556 raeburn 9740: }
9741: }
9742: if (srchby == 'lastfirst') {
9743: if (srchterm.indexOf(",") == -1) {
9744: checkok = 0;
1.1075.2.98 raeburn 9745: msg += "$js_lt{'whus'}\\n";
1.556 raeburn 9746: }
9747: if (srchterm.indexOf(",") == srchterm.length -1) {
9748: checkok = 0;
1.1075.2.98 raeburn 9749: msg += "$js_lt{'whse'}\\n";
1.556 raeburn 9750: }
9751: }
9752: if (checkok == 0) {
1.1075.2.98 raeburn 9753: alert("$js_lt{'thfo'}\\n"+msg);
1.556 raeburn 9754: return;
9755: }
9756: if (checkok == 1) {
1.570 raeburn 9757: callingForm.submit();
1.556 raeburn 9758: }
9759: }
9760:
9761: $newuserscript
9762:
1.824 bisitz 9763: // ]]>
1.556 raeburn 9764: </script>
1.558 albertel 9765:
9766: $new_user_create
9767:
1.555 raeburn 9768: END_BLOCK
1.558 albertel 9769:
1.876 raeburn 9770: $output .= &Apache::lonhtmlcommon::start_pick_box().
1.1075.2.98 raeburn 9771: &Apache::lonhtmlcommon::row_title($html_lt{'doma'}).
1.876 raeburn 9772: $domform.
9773: &Apache::lonhtmlcommon::row_closure().
1.1075.2.98 raeburn 9774: &Apache::lonhtmlcommon::row_title($html_lt{'usr'}).
1.876 raeburn 9775: $srchbysel.
9776: $srchtypesel.
9777: '<input type="text" size="15" name="srchterm" value="'.$srchterm.'" />'.
9778: $srchinsel.
9779: &Apache::lonhtmlcommon::row_closure(1).
9780: &Apache::lonhtmlcommon::end_pick_box().
9781: '<br />';
1.1075.2.114 raeburn 9782: return ($output,1);
1.555 raeburn 9783: }
9784:
1.612 raeburn 9785: sub user_rule_check {
1.615 raeburn 9786: my ($usershash,$checks,$alerts,$rulematch,$inst_results,$curr_rules,$got_rules) = @_;
1.1075.2.99 raeburn 9787: my ($response,%inst_response);
1.612 raeburn 9788: if (ref($usershash) eq 'HASH') {
1.1075.2.99 raeburn 9789: if (keys(%{$usershash}) > 1) {
9790: my (%by_username,%by_id,%userdoms);
9791: my $checkid;
1.612 raeburn 9792: if (ref($checks) eq 'HASH') {
1.1075.2.99 raeburn 9793: if ((!defined($checks->{'username'})) && (defined($checks->{'id'}))) {
9794: $checkid = 1;
9795: }
9796: }
9797: foreach my $user (keys(%{$usershash})) {
9798: my ($uname,$udom) = split(/:/,$user);
9799: if ($checkid) {
9800: if (ref($usershash->{$user}) eq 'HASH') {
9801: if ($usershash->{$user}->{'id'} ne '') {
9802: $by_id{$udom}{$usershash->{$user}->{'id'}} = $uname;
9803: $userdoms{$udom} = 1;
9804: if (ref($inst_results) eq 'HASH') {
9805: $inst_results->{$uname.':'.$udom} = {};
9806: }
9807: }
9808: }
9809: } else {
9810: $by_username{$udom}{$uname} = 1;
9811: $userdoms{$udom} = 1;
9812: if (ref($inst_results) eq 'HASH') {
9813: $inst_results->{$uname.':'.$udom} = {};
9814: }
9815: }
9816: }
9817: foreach my $udom (keys(%userdoms)) {
9818: if (!$got_rules->{$udom}) {
9819: my %domconfig = &Apache::lonnet::get_dom('configuration',
9820: ['usercreation'],$udom);
9821: if (ref($domconfig{'usercreation'}) eq 'HASH') {
9822: foreach my $item ('username','id') {
9823: if (ref($domconfig{'usercreation'}{$item.'_rule'}) eq 'ARRAY') {
9824: $$curr_rules{$udom}{$item} =
9825: $domconfig{'usercreation'}{$item.'_rule'};
9826: }
9827: }
9828: }
9829: $got_rules->{$udom} = 1;
9830: }
9831: }
9832: if ($checkid) {
9833: foreach my $udom (keys(%by_id)) {
9834: my ($outcome,$results) = &Apache::lonnet::get_multiple_instusers($udom,$by_id{$udom},'id');
9835: if ($outcome eq 'ok') {
9836: foreach my $id (keys(%{$by_id{$udom}})) {
9837: my $uname = $by_id{$udom}{$id};
9838: $inst_response{$uname.':'.$udom} = $outcome;
9839: }
9840: if (ref($results) eq 'HASH') {
9841: foreach my $uname (keys(%{$results})) {
9842: if (exists($inst_response{$uname.':'.$udom})) {
9843: $inst_response{$uname.':'.$udom} = $outcome;
9844: $inst_results->{$uname.':'.$udom} = $results->{$uname};
9845: }
9846: }
9847: }
9848: }
1.612 raeburn 9849: }
1.615 raeburn 9850: } else {
1.1075.2.99 raeburn 9851: foreach my $udom (keys(%by_username)) {
9852: my ($outcome,$results) = &Apache::lonnet::get_multiple_instusers($udom,$by_username{$udom});
9853: if ($outcome eq 'ok') {
9854: foreach my $uname (keys(%{$by_username{$udom}})) {
9855: $inst_response{$uname.':'.$udom} = $outcome;
9856: }
9857: if (ref($results) eq 'HASH') {
9858: foreach my $uname (keys(%{$results})) {
9859: $inst_results->{$uname.':'.$udom} = $results->{$uname};
9860: }
9861: }
9862: }
9863: }
1.612 raeburn 9864: }
1.1075.2.99 raeburn 9865: } elsif (keys(%{$usershash}) == 1) {
9866: my $user = (keys(%{$usershash}))[0];
9867: my ($uname,$udom) = split(/:/,$user);
9868: if (($udom ne '') && ($uname ne '')) {
9869: if (ref($usershash->{$user}) eq 'HASH') {
9870: if (ref($checks) eq 'HASH') {
9871: if (defined($checks->{'username'})) {
9872: ($inst_response{$user},%{$inst_results->{$user}}) =
9873: &Apache::lonnet::get_instuser($udom,$uname);
9874: } elsif (defined($checks->{'id'})) {
9875: if ($usershash->{$user}->{'id'} ne '') {
9876: ($inst_response{$user},%{$inst_results->{$user}}) =
9877: &Apache::lonnet::get_instuser($udom,undef,
9878: $usershash->{$user}->{'id'});
9879: } else {
9880: ($inst_response{$user},%{$inst_results->{$user}}) =
9881: &Apache::lonnet::get_instuser($udom,$uname);
9882: }
9883: }
9884: } else {
9885: ($inst_response{$user},%{$inst_results->{$user}}) =
9886: &Apache::lonnet::get_instuser($udom,$uname);
9887: return;
9888: }
9889: if (!$got_rules->{$udom}) {
9890: my %domconfig = &Apache::lonnet::get_dom('configuration',
9891: ['usercreation'],$udom);
9892: if (ref($domconfig{'usercreation'}) eq 'HASH') {
9893: foreach my $item ('username','id') {
9894: if (ref($domconfig{'usercreation'}{$item.'_rule'}) eq 'ARRAY') {
9895: $$curr_rules{$udom}{$item} =
9896: $domconfig{'usercreation'}{$item.'_rule'};
9897: }
9898: }
1.585 raeburn 9899: }
1.1075.2.99 raeburn 9900: $got_rules->{$udom} = 1;
1.585 raeburn 9901: }
9902: }
1.1075.2.99 raeburn 9903: } else {
9904: return;
9905: }
9906: } else {
9907: return;
9908: }
9909: foreach my $user (keys(%{$usershash})) {
9910: my ($uname,$udom) = split(/:/,$user);
9911: next if (($udom eq '') || ($uname eq ''));
9912: my $id;
9913: if (ref($inst_results) eq 'HASH') {
9914: if (ref($inst_results->{$user}) eq 'HASH') {
9915: $id = $inst_results->{$user}->{'id'};
9916: }
9917: }
9918: if ($id eq '') {
9919: if (ref($usershash->{$user})) {
9920: $id = $usershash->{$user}->{'id'};
9921: }
1.585 raeburn 9922: }
1.612 raeburn 9923: foreach my $item (keys(%{$checks})) {
9924: if (ref($$curr_rules{$udom}) eq 'HASH') {
9925: if (ref($$curr_rules{$udom}{$item}) eq 'ARRAY') {
9926: if (@{$$curr_rules{$udom}{$item}} > 0) {
1.1075.2.99 raeburn 9927: my %rule_check = &Apache::lonnet::inst_rulecheck($udom,$uname,$id,$item,
9928: $$curr_rules{$udom}{$item});
1.612 raeburn 9929: foreach my $rule (@{$$curr_rules{$udom}{$item}}) {
9930: if ($rule_check{$rule}) {
9931: $$rulematch{$user}{$item} = $rule;
1.1075.2.99 raeburn 9932: if ($inst_response{$user} eq 'ok') {
1.615 raeburn 9933: if (ref($inst_results) eq 'HASH') {
9934: if (ref($inst_results->{$user}) eq 'HASH') {
9935: if (keys(%{$inst_results->{$user}}) == 0) {
9936: $$alerts{$item}{$udom}{$uname} = 1;
1.1075.2.99 raeburn 9937: } elsif ($item eq 'id') {
9938: if ($inst_results->{$user}->{'id'} eq '') {
9939: $$alerts{$item}{$udom}{$uname} = 1;
9940: }
1.615 raeburn 9941: }
1.612 raeburn 9942: }
9943: }
1.615 raeburn 9944: }
9945: last;
1.585 raeburn 9946: }
9947: }
9948: }
9949: }
9950: }
9951: }
9952: }
9953: }
1.612 raeburn 9954: return;
9955: }
9956:
9957: sub user_rule_formats {
9958: my ($domain,$domdesc,$curr_rules,$check) = @_;
9959: my %text = (
9960: 'username' => 'Usernames',
9961: 'id' => 'IDs',
9962: );
9963: my $output;
9964: my ($rules,$ruleorder) = &Apache::lonnet::inst_userrules($domain,$check);
9965: if ((ref($rules) eq 'HASH') && (ref($ruleorder) eq 'ARRAY')) {
9966: if (@{$ruleorder} > 0) {
1.1075.2.20 raeburn 9967: $output = '<br />'.
9968: &mt($text{$check}.' with the following format(s) may [_1]only[_2] be used for verified users at [_3]:',
9969: '<span class="LC_cusr_emph">','</span>',$domdesc).
9970: ' <ul>';
1.612 raeburn 9971: foreach my $rule (@{$ruleorder}) {
9972: if (ref($curr_rules) eq 'ARRAY') {
9973: if (grep(/^\Q$rule\E$/,@{$curr_rules})) {
9974: if (ref($rules->{$rule}) eq 'HASH') {
9975: $output .= '<li>'.$rules->{$rule}{'name'}.': '.
9976: $rules->{$rule}{'desc'}.'</li>';
9977: }
9978: }
9979: }
9980: }
9981: $output .= '</ul>';
9982: }
9983: }
9984: return $output;
9985: }
9986:
9987: sub instrule_disallow_msg {
1.615 raeburn 9988: my ($checkitem,$domdesc,$count,$mode) = @_;
1.612 raeburn 9989: my $response;
9990: my %text = (
9991: item => 'username',
9992: items => 'usernames',
9993: match => 'matches',
9994: do => 'does',
9995: action => 'a username',
9996: one => 'one',
9997: );
9998: if ($count > 1) {
9999: $text{'item'} = 'usernames';
10000: $text{'match'} ='match';
10001: $text{'do'} = 'do';
10002: $text{'action'} = 'usernames',
10003: $text{'one'} = 'ones';
10004: }
10005: if ($checkitem eq 'id') {
10006: $text{'items'} = 'IDs';
10007: $text{'item'} = 'ID';
10008: $text{'action'} = 'an ID';
1.615 raeburn 10009: if ($count > 1) {
10010: $text{'item'} = 'IDs';
10011: $text{'action'} = 'IDs';
10012: }
1.612 raeburn 10013: }
1.674 bisitz 10014: $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 10015: if ($mode eq 'upload') {
10016: if ($checkitem eq 'username') {
10017: $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'}.");
10018: } elsif ($checkitem eq 'id') {
1.674 bisitz 10019: $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 10020: }
1.669 raeburn 10021: } elsif ($mode eq 'selfcreate') {
10022: if ($checkitem eq 'id') {
10023: $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.");
10024: }
1.615 raeburn 10025: } else {
10026: if ($checkitem eq 'username') {
10027: $response .= &mt("You must choose $text{'action'} with a different format -- $text{'one'} that will not conflict with 'official' institutional $text{'items'}.");
10028: } elsif ($checkitem eq 'id') {
10029: $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.");
10030: }
1.612 raeburn 10031: }
10032: return $response;
1.585 raeburn 10033: }
10034:
1.624 raeburn 10035: sub personal_data_fieldtitles {
10036: my %fieldtitles = &Apache::lonlocal::texthash (
10037: id => 'Student/Employee ID',
10038: permanentemail => 'E-mail address',
10039: lastname => 'Last Name',
10040: firstname => 'First Name',
10041: middlename => 'Middle Name',
10042: generation => 'Generation',
10043: gen => 'Generation',
1.765 raeburn 10044: inststatus => 'Affiliation',
1.624 raeburn 10045: );
10046: return %fieldtitles;
10047: }
10048:
1.642 raeburn 10049: sub sorted_inst_types {
10050: my ($dom) = @_;
1.1075.2.70 raeburn 10051: my ($usertypes,$order);
10052: my %domdefaults = &Apache::lonnet::get_domain_defaults($dom);
10053: if (ref($domdefaults{'inststatus'}) eq 'HASH') {
10054: $usertypes = $domdefaults{'inststatus'}{'inststatustypes'};
10055: $order = $domdefaults{'inststatus'}{'inststatusorder'};
10056: } else {
10057: ($usertypes,$order) = &Apache::lonnet::retrieve_inst_usertypes($dom);
10058: }
1.642 raeburn 10059: my $othertitle = &mt('All users');
10060: if ($env{'request.course.id'}) {
1.668 raeburn 10061: $othertitle = &mt('Any users');
1.642 raeburn 10062: }
10063: my @types;
10064: if (ref($order) eq 'ARRAY') {
10065: @types = @{$order};
10066: }
10067: if (@types == 0) {
10068: if (ref($usertypes) eq 'HASH') {
10069: @types = sort(keys(%{$usertypes}));
10070: }
10071: }
10072: if (keys(%{$usertypes}) > 0) {
10073: $othertitle = &mt('Other users');
10074: }
10075: return ($othertitle,$usertypes,\@types);
10076: }
10077:
1.645 raeburn 10078: sub get_institutional_codes {
10079: my ($settings,$allcourses,$LC_code) = @_;
10080: # Get complete list of course sections to update
10081: my @currsections = ();
10082: my @currxlists = ();
10083: my $coursecode = $$settings{'internal.coursecode'};
10084:
10085: if ($$settings{'internal.sectionnums'} ne '') {
10086: @currsections = split(/,/,$$settings{'internal.sectionnums'});
10087: }
10088:
10089: if ($$settings{'internal.crosslistings'} ne '') {
10090: @currxlists = split(/,/,$$settings{'internal.crosslistings'});
10091: }
10092:
10093: if (@currxlists > 0) {
10094: foreach (@currxlists) {
10095: if (m/^([^:]+):(\w*)$/) {
10096: unless (grep/^$1$/,@{$allcourses}) {
10097: push @{$allcourses},$1;
10098: $$LC_code{$1} = $2;
10099: }
10100: }
10101: }
10102: }
10103:
10104: if (@currsections > 0) {
10105: foreach (@currsections) {
10106: if (m/^(\w+):(\w*)$/) {
10107: my $sec = $coursecode.$1;
10108: my $lc_sec = $2;
10109: unless (grep/^$sec$/,@{$allcourses}) {
10110: push @{$allcourses},$sec;
10111: $$LC_code{$sec} = $lc_sec;
10112: }
10113: }
10114: }
10115: }
10116: return;
10117: }
10118:
1.971 raeburn 10119: sub get_standard_codeitems {
10120: return ('Year','Semester','Department','Number','Section');
10121: }
10122:
1.112 bowersj2 10123: =pod
10124:
1.780 raeburn 10125: =head1 Slot Helpers
10126:
10127: =over 4
10128:
10129: =item * sorted_slots()
10130:
1.1040 raeburn 10131: Sorts an array of slot names in order of an optional sort key,
10132: default sort is by slot start time (earliest first).
1.780 raeburn 10133:
10134: Inputs:
10135:
10136: =over 4
10137:
10138: slotsarr - Reference to array of unsorted slot names.
10139:
10140: slots - Reference to hash of hash, where outer hash keys are slot names.
10141:
1.1040 raeburn 10142: sortkey - Name of key in inner hash to be sorted on (e.g., starttime).
10143:
1.549 albertel 10144: =back
10145:
1.780 raeburn 10146: Returns:
10147:
10148: =over 4
10149:
1.1040 raeburn 10150: sorted - An array of slot names sorted by a specified sort key
10151: (default sort key is start time of the slot).
1.780 raeburn 10152:
10153: =back
10154:
10155: =cut
10156:
10157:
10158: sub sorted_slots {
1.1040 raeburn 10159: my ($slotsarr,$slots,$sortkey) = @_;
10160: if ($sortkey eq '') {
10161: $sortkey = 'starttime';
10162: }
1.780 raeburn 10163: my @sorted;
10164: if ((ref($slotsarr) eq 'ARRAY') && (ref($slots) eq 'HASH')) {
10165: @sorted =
10166: sort {
10167: if (ref($slots->{$a}) && ref($slots->{$b})) {
1.1040 raeburn 10168: return $slots->{$a}{$sortkey} <=> $slots->{$b}{$sortkey}
1.780 raeburn 10169: }
10170: if (ref($slots->{$a})) { return -1;}
10171: if (ref($slots->{$b})) { return 1;}
10172: return 0;
10173: } @{$slotsarr};
10174: }
10175: return @sorted;
10176: }
10177:
1.1040 raeburn 10178: =pod
10179:
10180: =item * get_future_slots()
10181:
10182: Inputs:
10183:
10184: =over 4
10185:
10186: cnum - course number
10187:
10188: cdom - course domain
10189:
10190: now - current UNIX time
10191:
10192: symb - optional symb
10193:
10194: =back
10195:
10196: Returns:
10197:
10198: =over 4
10199:
10200: sorted_reservable - ref to array of student_schedulable slots currently
10201: reservable, ordered by end date of reservation period.
10202:
10203: reservable_now - ref to hash of student_schedulable slots currently
10204: reservable.
10205:
10206: Keys in inner hash are:
10207: (a) symb: either blank or symb to which slot use is restricted.
1.1075.2.104 raeburn 10208: (b) endreserve: end date of reservation period.
10209: (c) uniqueperiod: start,end dates when slot is to be uniquely
10210: selected.
1.1040 raeburn 10211:
10212: sorted_future - ref to array of student_schedulable slots reservable in
10213: the future, ordered by start date of reservation period.
10214:
10215: future_reservable - ref to hash of student_schedulable slots reservable
10216: in the future.
10217:
10218: Keys in inner hash are:
10219: (a) symb: either blank or symb to which slot use is restricted.
10220: (b) startreserve: start date of reservation period.
1.1075.2.104 raeburn 10221: (c) uniqueperiod: start,end dates when slot is to be uniquely
10222: selected.
1.1040 raeburn 10223:
10224: =back
10225:
10226: =cut
10227:
10228: sub get_future_slots {
10229: my ($cnum,$cdom,$now,$symb) = @_;
10230: my (%reservable_now,%future_reservable,@sorted_reservable,@sorted_future);
10231: my %slots = &Apache::lonnet::get_course_slots($cnum,$cdom);
10232: foreach my $slot (keys(%slots)) {
10233: next unless($slots{$slot}->{'type'} eq 'schedulable_student');
10234: if ($symb) {
10235: next if (($slots{$slot}->{'symb'} ne '') &&
10236: ($slots{$slot}->{'symb'} ne $symb));
10237: }
10238: if (($slots{$slot}->{'starttime'} > $now) &&
10239: ($slots{$slot}->{'endtime'} > $now)) {
10240: if (($slots{$slot}->{'allowedsections'}) || ($slots{$slot}->{'allowedusers'})) {
10241: my $userallowed = 0;
10242: if ($slots{$slot}->{'allowedsections'}) {
10243: my @allowed_sec = split(',',$slots{$slot}->{'allowedsections'});
10244: if (!defined($env{'request.role.sec'})
10245: && grep(/^No section assigned$/,@allowed_sec)) {
10246: $userallowed=1;
10247: } else {
10248: if (grep(/^\Q$env{'request.role.sec'}\E$/,@allowed_sec)) {
10249: $userallowed=1;
10250: }
10251: }
10252: unless ($userallowed) {
10253: if (defined($env{'request.course.groups'})) {
10254: my @groups = split(/:/,$env{'request.course.groups'});
10255: foreach my $group (@groups) {
10256: if (grep(/^\Q$group\E$/,@allowed_sec)) {
10257: $userallowed=1;
10258: last;
10259: }
10260: }
10261: }
10262: }
10263: }
10264: if ($slots{$slot}->{'allowedusers'}) {
10265: my @allowed_users = split(',',$slots{$slot}->{'allowedusers'});
10266: my $user = $env{'user.name'}.':'.$env{'user.domain'};
10267: if (grep(/^\Q$user\E$/,@allowed_users)) {
10268: $userallowed = 1;
10269: }
10270: }
10271: next unless($userallowed);
10272: }
10273: my $startreserve = $slots{$slot}->{'startreserve'};
10274: my $endreserve = $slots{$slot}->{'endreserve'};
10275: my $symb = $slots{$slot}->{'symb'};
1.1075.2.104 raeburn 10276: my $uniqueperiod;
10277: if (ref($slots{$slot}->{'uniqueperiod'}) eq 'ARRAY') {
10278: $uniqueperiod = join(',',@{$slots{$slot}->{'uniqueperiod'}});
10279: }
1.1040 raeburn 10280: if (($startreserve < $now) &&
10281: (!$endreserve || $endreserve > $now)) {
10282: my $lastres = $endreserve;
10283: if (!$lastres) {
10284: $lastres = $slots{$slot}->{'starttime'};
10285: }
10286: $reservable_now{$slot} = {
10287: symb => $symb,
1.1075.2.104 raeburn 10288: endreserve => $lastres,
10289: uniqueperiod => $uniqueperiod,
1.1040 raeburn 10290: };
10291: } elsif (($startreserve > $now) &&
10292: (!$endreserve || $endreserve > $startreserve)) {
10293: $future_reservable{$slot} = {
10294: symb => $symb,
1.1075.2.104 raeburn 10295: startreserve => $startreserve,
10296: uniqueperiod => $uniqueperiod,
1.1040 raeburn 10297: };
10298: }
10299: }
10300: }
10301: my @unsorted_reservable = keys(%reservable_now);
10302: if (@unsorted_reservable > 0) {
10303: @sorted_reservable =
10304: &sorted_slots(\@unsorted_reservable,\%reservable_now,'endreserve');
10305: }
10306: my @unsorted_future = keys(%future_reservable);
10307: if (@unsorted_future > 0) {
10308: @sorted_future =
10309: &sorted_slots(\@unsorted_future,\%future_reservable,'startreserve');
10310: }
10311: return (\@sorted_reservable,\%reservable_now,\@sorted_future,\%future_reservable);
10312: }
1.780 raeburn 10313:
10314: =pod
10315:
1.1057 foxr 10316: =back
10317:
1.549 albertel 10318: =head1 HTTP Helpers
10319:
10320: =over 4
10321:
1.648 raeburn 10322: =item * &get_unprocessed_cgi($query,$possible_names)
1.112 bowersj2 10323:
1.258 albertel 10324: Modify the %env hash to contain unprocessed CGI form parameters held in
1.112 bowersj2 10325: $query. The parameters listed in $possible_names (an array reference),
1.258 albertel 10326: will be set in $env{'form.name'} if they do not already exist.
1.112 bowersj2 10327:
10328: Typically called with $ENV{'QUERY_STRING'} as the first parameter.
10329: $possible_names is an ref to an array of form element names. As an example:
10330: get_unprocessed_cgi($ENV{'QUERY_STRING'},['uname','udom']);
1.258 albertel 10331: will result in $env{'form.uname'} and $env{'form.udom'} being set.
1.112 bowersj2 10332:
10333: =cut
1.1 albertel 10334:
1.6 albertel 10335: sub get_unprocessed_cgi {
1.25 albertel 10336: my ($query,$possible_names)= @_;
1.26 matthew 10337: # $Apache::lonxml::debug=1;
1.356 albertel 10338: foreach my $pair (split(/&/,$query)) {
10339: my ($name, $value) = split(/=/,$pair);
1.369 www 10340: $name = &unescape($name);
1.25 albertel 10341: if (!defined($possible_names) || (grep {$_ eq $name} @$possible_names)) {
10342: $value =~ tr/+/ /;
10343: $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
1.258 albertel 10344: unless (defined($env{'form.'.$name})) { &add_to_env('form.'.$name,$value) };
1.25 albertel 10345: }
1.16 harris41 10346: }
1.6 albertel 10347: }
10348:
1.112 bowersj2 10349: =pod
10350:
1.648 raeburn 10351: =item * &cacheheader()
1.112 bowersj2 10352:
10353: returns cache-controlling header code
10354:
10355: =cut
10356:
1.7 albertel 10357: sub cacheheader {
1.258 albertel 10358: unless ($env{'request.method'} eq 'GET') { return ''; }
1.216 albertel 10359: my $date=strftime("%a, %d %b %Y %H:%M:%S GMT",gmtime);
10360: my $output .='<meta HTTP-EQUIV="Expires" CONTENT="'.$date.'" />
1.7 albertel 10361: <meta HTTP-EQUIV="Cache-control" CONTENT="no-cache" />
10362: <meta HTTP-EQUIV="Pragma" CONTENT="no-cache" />';
1.216 albertel 10363: return $output;
1.7 albertel 10364: }
10365:
1.112 bowersj2 10366: =pod
10367:
1.648 raeburn 10368: =item * &no_cache($r)
1.112 bowersj2 10369:
10370: specifies header code to not have cache
10371:
10372: =cut
10373:
1.9 albertel 10374: sub no_cache {
1.216 albertel 10375: my ($r) = @_;
10376: if ($ENV{'REQUEST_METHOD'} ne 'GET' &&
1.258 albertel 10377: $env{'request.method'} ne 'GET') { return ''; }
1.216 albertel 10378: my $date=strftime("%a, %d %b %Y %H:%M:%S GMT",gmtime(time));
10379: $r->no_cache(1);
10380: $r->header_out("Expires" => $date);
10381: $r->header_out("Pragma" => "no-cache");
1.123 www 10382: }
10383:
10384: sub content_type {
1.181 albertel 10385: my ($r,$type,$charset) = @_;
1.299 foxr 10386: if ($r) {
10387: # Note that printout.pl calls this with undef for $r.
10388: &no_cache($r);
10389: }
1.258 albertel 10390: if ($env{'browser.mathml'} && $type eq 'text/html') { $type='text/xml'; }
1.181 albertel 10391: unless ($charset) {
10392: $charset=&Apache::lonlocal::current_encoding;
10393: }
10394: if ($charset) { $type.='; charset='.$charset; }
10395: if ($r) {
10396: $r->content_type($type);
10397: } else {
10398: print("Content-type: $type\n\n");
10399: }
1.9 albertel 10400: }
1.25 albertel 10401:
1.112 bowersj2 10402: =pod
10403:
1.648 raeburn 10404: =item * &add_to_env($name,$value)
1.112 bowersj2 10405:
1.258 albertel 10406: adds $name to the %env hash with value
1.112 bowersj2 10407: $value, if $name already exists, the entry is converted to an array
10408: reference and $value is added to the array.
10409:
10410: =cut
10411:
1.25 albertel 10412: sub add_to_env {
10413: my ($name,$value)=@_;
1.258 albertel 10414: if (defined($env{$name})) {
10415: if (ref($env{$name})) {
1.25 albertel 10416: #already have multiple values
1.258 albertel 10417: push(@{ $env{$name} },$value);
1.25 albertel 10418: } else {
10419: #first time seeing multiple values, convert hash entry to an arrayref
1.258 albertel 10420: my $first=$env{$name};
10421: undef($env{$name});
10422: push(@{ $env{$name} },$first,$value);
1.25 albertel 10423: }
10424: } else {
1.258 albertel 10425: $env{$name}=$value;
1.25 albertel 10426: }
1.31 albertel 10427: }
1.149 albertel 10428:
10429: =pod
10430:
1.648 raeburn 10431: =item * &get_env_multiple($name)
1.149 albertel 10432:
1.258 albertel 10433: gets $name from the %env hash, it seemlessly handles the cases where multiple
1.149 albertel 10434: values may be defined and end up as an array ref.
10435:
10436: returns an array of values
10437:
10438: =cut
10439:
10440: sub get_env_multiple {
10441: my ($name) = @_;
10442: my @values;
1.258 albertel 10443: if (defined($env{$name})) {
1.149 albertel 10444: # exists is it an array
1.258 albertel 10445: if (ref($env{$name})) {
10446: @values=@{ $env{$name} };
1.149 albertel 10447: } else {
1.258 albertel 10448: $values[0]=$env{$name};
1.149 albertel 10449: }
10450: }
10451: return(@values);
10452: }
10453:
1.660 raeburn 10454: sub ask_for_embedded_content {
10455: my ($actionurl,$state,$allfiles,$codebase,$args)=@_;
1.1071 raeburn 10456: my (%subdependencies,%dependencies,%mapping,%existing,%newfiles,%pathchanges,
1.1075.2.11 raeburn 10457: %currsubfile,%unused,$rem);
1.1071 raeburn 10458: my $counter = 0;
10459: my $numnew = 0;
1.987 raeburn 10460: my $numremref = 0;
10461: my $numinvalid = 0;
10462: my $numpathchg = 0;
10463: my $numexisting = 0;
1.1071 raeburn 10464: my $numunused = 0;
10465: my ($output,$upload_output,$toplevel,$url,$udom,$uname,$getpropath,$cdom,$cnum,
1.1075.2.53 raeburn 10466: $fileloc,$filename,$delete_output,$modify_output,$title,$symb,$path,$navmap);
1.1071 raeburn 10467: my $heading = &mt('Upload embedded files');
10468: my $buttontext = &mt('Upload');
10469:
1.1075.2.11 raeburn 10470: if ($env{'request.course.id'}) {
1.1075.2.35 raeburn 10471: if ($actionurl eq '/adm/dependencies') {
10472: $navmap = Apache::lonnavmaps::navmap->new();
10473: }
10474: $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
10475: $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
1.1075.2.11 raeburn 10476: }
1.1075.2.35 raeburn 10477: if (($actionurl eq '/adm/portfolio') ||
10478: ($actionurl eq '/adm/coursegrp_portfolio')) {
1.984 raeburn 10479: my $current_path='/';
10480: if ($env{'form.currentpath'}) {
10481: $current_path = $env{'form.currentpath'};
10482: }
10483: if ($actionurl eq '/adm/coursegrp_portfolio') {
1.1075.2.35 raeburn 10484: $udom = $cdom;
10485: $uname = $cnum;
1.984 raeburn 10486: $url = '/userfiles/groups/'.$env{'form.group'}.'/portfolio';
10487: } else {
10488: $udom = $env{'user.domain'};
10489: $uname = $env{'user.name'};
10490: $url = '/userfiles/portfolio';
10491: }
1.987 raeburn 10492: $toplevel = $url.'/';
1.984 raeburn 10493: $url .= $current_path;
10494: $getpropath = 1;
1.987 raeburn 10495: } elsif (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank') ||
10496: ($actionurl eq '/adm/imsimport')) {
1.1022 www 10497: my ($udom,$uname,$rest) = ($args->{'current_path'} =~ m{/priv/($match_domain)/($match_username)/?(.*)$});
1.1026 raeburn 10498: $url = $Apache::lonnet::perlvar{'lonDocRoot'}."/priv/$udom/$uname/";
1.987 raeburn 10499: $toplevel = $url;
1.984 raeburn 10500: if ($rest ne '') {
1.987 raeburn 10501: $url .= $rest;
10502: }
10503: } elsif ($actionurl eq '/adm/coursedocs') {
10504: if (ref($args) eq 'HASH') {
1.1071 raeburn 10505: $url = $args->{'docs_url'};
10506: $toplevel = $url;
1.1075.2.11 raeburn 10507: if ($args->{'context'} eq 'paste') {
10508: ($cdom,$cnum) = ($url =~ m{^\Q/uploaded/\E($match_domain)/($match_courseid)/});
10509: ($path) =
10510: ($toplevel =~ m{^(\Q/uploaded/$cdom/$cnum/\E(?:docs|supplemental)/(?:default|\d+)/\d+)/});
10511: $fileloc = &Apache::lonnet::filelocation('',$toplevel);
10512: $fileloc =~ s{^/}{};
10513: }
1.1071 raeburn 10514: }
10515: } elsif ($actionurl eq '/adm/dependencies') {
10516: if ($env{'request.course.id'} ne '') {
10517: if (ref($args) eq 'HASH') {
10518: $url = $args->{'docs_url'};
10519: $title = $args->{'docs_title'};
1.1075.2.35 raeburn 10520: $toplevel = $url;
10521: unless ($toplevel =~ m{^/}) {
10522: $toplevel = "/$url";
10523: }
1.1075.2.11 raeburn 10524: ($rem) = ($toplevel =~ m{^(.+/)[^/]+$});
1.1075.2.35 raeburn 10525: if ($toplevel =~ m{^(\Q/uploaded/$cdom/$cnum/portfolio/syllabus\E)}) {
10526: $path = $1;
10527: } else {
10528: ($path) =
10529: ($toplevel =~ m{^(\Q/uploaded/$cdom/$cnum/\E(?:docs|supplemental)/(?:default|\d+)/\d+)/});
10530: }
1.1075.2.79 raeburn 10531: if ($toplevel=~/^\/*(uploaded|editupload)/) {
10532: $fileloc = $toplevel;
10533: $fileloc=~ s/^\s*(\S+)\s*$/$1/;
10534: my ($udom,$uname,$fname) =
10535: ($fileloc=~ m{^/+(?:uploaded|editupload)/+($match_domain)/+($match_name)/+(.*)$});
10536: $fileloc = propath($udom,$uname).'/userfiles/'.$fname;
10537: } else {
10538: $fileloc = &Apache::lonnet::filelocation('',$toplevel);
10539: }
1.1071 raeburn 10540: $fileloc =~ s{^/}{};
10541: ($filename) = ($fileloc =~ m{.+/([^/]+)$});
10542: $heading = &mt('Status of dependencies in [_1]',"$title ($filename)");
10543: }
1.987 raeburn 10544: }
1.1075.2.35 raeburn 10545: } elsif ($actionurl eq "/public/$cdom/$cnum/syllabus") {
10546: $udom = $cdom;
10547: $uname = $cnum;
10548: $url = "/uploaded/$cdom/$cnum/portfolio/syllabus";
10549: $toplevel = $url;
10550: $path = $url;
10551: $fileloc = &Apache::lonnet::filelocation('',$toplevel).'/';
10552: $fileloc =~ s{^/}{};
10553: }
10554: foreach my $file (keys(%{$allfiles})) {
10555: my $embed_file;
10556: if (($path eq "/uploaded/$cdom/$cnum/portfolio/syllabus") && ($file =~ m{^\Q$path/\E(.+)$})) {
10557: $embed_file = $1;
10558: } else {
10559: $embed_file = $file;
10560: }
1.1075.2.55 raeburn 10561: my ($absolutepath,$cleaned_file);
10562: if ($embed_file =~ m{^\w+://}) {
10563: $cleaned_file = $embed_file;
1.1075.2.47 raeburn 10564: $newfiles{$cleaned_file} = 1;
10565: $mapping{$cleaned_file} = $embed_file;
1.987 raeburn 10566: } else {
1.1075.2.55 raeburn 10567: $cleaned_file = &clean_path($embed_file);
1.987 raeburn 10568: if ($embed_file =~ m{^/}) {
10569: $absolutepath = $embed_file;
10570: }
1.1075.2.47 raeburn 10571: if ($cleaned_file =~ m{/}) {
10572: my ($path,$fname) = ($cleaned_file =~ m{^(.+)/([^/]*)$});
1.987 raeburn 10573: $path = &check_for_traversal($path,$url,$toplevel);
10574: my $item = $fname;
10575: if ($path ne '') {
10576: $item = $path.'/'.$fname;
10577: $subdependencies{$path}{$fname} = 1;
10578: } else {
10579: $dependencies{$item} = 1;
10580: }
10581: if ($absolutepath) {
10582: $mapping{$item} = $absolutepath;
10583: } else {
10584: $mapping{$item} = $embed_file;
10585: }
10586: } else {
10587: $dependencies{$embed_file} = 1;
10588: if ($absolutepath) {
1.1075.2.47 raeburn 10589: $mapping{$cleaned_file} = $absolutepath;
1.987 raeburn 10590: } else {
1.1075.2.47 raeburn 10591: $mapping{$cleaned_file} = $embed_file;
1.987 raeburn 10592: }
10593: }
1.984 raeburn 10594: }
10595: }
1.1071 raeburn 10596: my $dirptr = 16384;
1.984 raeburn 10597: foreach my $path (keys(%subdependencies)) {
1.1071 raeburn 10598: $currsubfile{$path} = {};
1.1075.2.35 raeburn 10599: if (($actionurl eq '/adm/portfolio') ||
10600: ($actionurl eq '/adm/coursegrp_portfolio')) {
1.1021 raeburn 10601: my ($sublistref,$listerror) =
10602: &Apache::lonnet::dirlist($url.$path,$udom,$uname,$getpropath);
10603: if (ref($sublistref) eq 'ARRAY') {
10604: foreach my $line (@{$sublistref}) {
10605: my ($file_name,$rest) = split(/\&/,$line,2);
1.1071 raeburn 10606: $currsubfile{$path}{$file_name} = 1;
1.1021 raeburn 10607: }
1.984 raeburn 10608: }
1.987 raeburn 10609: } elsif (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank')) {
1.984 raeburn 10610: if (opendir(my $dir,$url.'/'.$path)) {
10611: my @subdir_list = grep(!/^\./,readdir($dir));
1.1071 raeburn 10612: map {$currsubfile{$path}{$_} = 1;} @subdir_list;
10613: }
1.1075.2.11 raeburn 10614: } elsif (($actionurl eq '/adm/dependencies') ||
10615: (($actionurl eq '/adm/coursedocs') && (ref($args) eq 'HASH') &&
1.1075.2.35 raeburn 10616: ($args->{'context'} eq 'paste')) ||
10617: ($actionurl eq "/public/$cdom/$cnum/syllabus")) {
1.1071 raeburn 10618: if ($env{'request.course.id'} ne '') {
1.1075.2.35 raeburn 10619: my $dir;
10620: if ($actionurl eq "/public/$cdom/$cnum/syllabus") {
10621: $dir = $fileloc;
10622: } else {
10623: ($dir) = ($fileloc =~ m{^(.+/)[^/]+$});
10624: }
1.1071 raeburn 10625: if ($dir ne '') {
10626: my ($sublistref,$listerror) =
10627: &Apache::lonnet::dirlist($dir.$path,$cdom,$cnum,$getpropath,undef,'/');
10628: if (ref($sublistref) eq 'ARRAY') {
10629: foreach my $line (@{$sublistref}) {
10630: my ($file_name,$dom,undef,$testdir,undef,undef,undef,undef,$size,
10631: undef,$mtime)=split(/\&/,$line,12);
10632: unless (($testdir&$dirptr) ||
10633: ($file_name =~ /^\.\.?$/)) {
10634: $currsubfile{$path}{$file_name} = [$size,$mtime];
10635: }
10636: }
10637: }
10638: }
1.984 raeburn 10639: }
10640: }
10641: foreach my $file (keys(%{$subdependencies{$path}})) {
1.1071 raeburn 10642: if (exists($currsubfile{$path}{$file})) {
1.987 raeburn 10643: my $item = $path.'/'.$file;
10644: unless ($mapping{$item} eq $item) {
10645: $pathchanges{$item} = 1;
10646: }
10647: $existing{$item} = 1;
10648: $numexisting ++;
10649: } else {
10650: $newfiles{$path.'/'.$file} = 1;
1.984 raeburn 10651: }
10652: }
1.1071 raeburn 10653: if ($actionurl eq '/adm/dependencies') {
10654: foreach my $path (keys(%currsubfile)) {
10655: if (ref($currsubfile{$path}) eq 'HASH') {
10656: foreach my $file (keys(%{$currsubfile{$path}})) {
10657: unless ($subdependencies{$path}{$file}) {
1.1075.2.11 raeburn 10658: next if (($rem ne '') &&
10659: (($env{"httpref.$rem"."$path/$file"} ne '') ||
10660: (ref($navmap) &&
10661: (($navmap->getResourceByUrl($rem."$path/$file") ne '') ||
10662: (($file =~ /^(.*\.s?html?)\.bak$/i) &&
10663: ($navmap->getResourceByUrl($rem."$path/$1")))))));
1.1071 raeburn 10664: $unused{$path.'/'.$file} = 1;
10665: }
10666: }
10667: }
10668: }
10669: }
1.984 raeburn 10670: }
1.987 raeburn 10671: my %currfile;
1.1075.2.35 raeburn 10672: if (($actionurl eq '/adm/portfolio') ||
10673: ($actionurl eq '/adm/coursegrp_portfolio')) {
1.1021 raeburn 10674: my ($dirlistref,$listerror) =
10675: &Apache::lonnet::dirlist($url,$udom,$uname,$getpropath);
10676: if (ref($dirlistref) eq 'ARRAY') {
10677: foreach my $line (@{$dirlistref}) {
10678: my ($file_name,$rest) = split(/\&/,$line,2);
10679: $currfile{$file_name} = 1;
10680: }
1.984 raeburn 10681: }
1.987 raeburn 10682: } elsif (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank')) {
1.984 raeburn 10683: if (opendir(my $dir,$url)) {
1.987 raeburn 10684: my @dir_list = grep(!/^\./,readdir($dir));
1.984 raeburn 10685: map {$currfile{$_} = 1;} @dir_list;
10686: }
1.1075.2.11 raeburn 10687: } elsif (($actionurl eq '/adm/dependencies') ||
10688: (($actionurl eq '/adm/coursedocs') && (ref($args) eq 'HASH') &&
1.1075.2.35 raeburn 10689: ($args->{'context'} eq 'paste')) ||
10690: ($actionurl eq "/public/$cdom/$cnum/syllabus")) {
1.1071 raeburn 10691: if ($env{'request.course.id'} ne '') {
10692: my ($dir) = ($fileloc =~ m{^(.+/)[^/]+$});
10693: if ($dir ne '') {
10694: my ($dirlistref,$listerror) =
10695: &Apache::lonnet::dirlist($dir,$cdom,$cnum,$getpropath,undef,'/');
10696: if (ref($dirlistref) eq 'ARRAY') {
10697: foreach my $line (@{$dirlistref}) {
10698: my ($file_name,$dom,undef,$testdir,undef,undef,undef,undef,
10699: $size,undef,$mtime)=split(/\&/,$line,12);
10700: unless (($testdir&$dirptr) ||
10701: ($file_name =~ /^\.\.?$/)) {
10702: $currfile{$file_name} = [$size,$mtime];
10703: }
10704: }
10705: }
10706: }
10707: }
1.984 raeburn 10708: }
10709: foreach my $file (keys(%dependencies)) {
1.1071 raeburn 10710: if (exists($currfile{$file})) {
1.987 raeburn 10711: unless ($mapping{$file} eq $file) {
10712: $pathchanges{$file} = 1;
10713: }
10714: $existing{$file} = 1;
10715: $numexisting ++;
10716: } else {
1.984 raeburn 10717: $newfiles{$file} = 1;
10718: }
10719: }
1.1071 raeburn 10720: foreach my $file (keys(%currfile)) {
10721: unless (($file eq $filename) ||
10722: ($file eq $filename.'.bak') ||
10723: ($dependencies{$file})) {
1.1075.2.11 raeburn 10724: if ($actionurl eq '/adm/dependencies') {
1.1075.2.35 raeburn 10725: unless ($toplevel =~ m{^\Q/uploaded/$cdom/$cnum/portfolio/syllabus\E}) {
10726: next if (($rem ne '') &&
10727: (($env{"httpref.$rem".$file} ne '') ||
10728: (ref($navmap) &&
10729: (($navmap->getResourceByUrl($rem.$file) ne '') ||
10730: (($file =~ /^(.*\.s?html?)\.bak$/i) &&
10731: ($navmap->getResourceByUrl($rem.$1)))))));
10732: }
1.1075.2.11 raeburn 10733: }
1.1071 raeburn 10734: $unused{$file} = 1;
10735: }
10736: }
1.1075.2.11 raeburn 10737: if (($actionurl eq '/adm/coursedocs') && (ref($args) eq 'HASH') &&
10738: ($args->{'context'} eq 'paste')) {
10739: $counter = scalar(keys(%existing));
10740: $numpathchg = scalar(keys(%pathchanges));
10741: return ($output,$counter,$numpathchg,\%existing);
1.1075.2.35 raeburn 10742: } elsif (($actionurl eq "/public/$cdom/$cnum/syllabus") &&
10743: (ref($args) eq 'HASH') && ($args->{'context'} eq 'rewrites')) {
10744: $counter = scalar(keys(%existing));
10745: $numpathchg = scalar(keys(%pathchanges));
10746: return ($output,$counter,$numpathchg,\%existing,\%mapping);
1.1075.2.11 raeburn 10747: }
1.984 raeburn 10748: foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%newfiles)) {
1.1071 raeburn 10749: if ($actionurl eq '/adm/dependencies') {
10750: next if ($embed_file =~ m{^\w+://});
10751: }
1.660 raeburn 10752: $upload_output .= &start_data_table_row().
1.1075.2.35 raeburn 10753: '<td valign="top"><img src="'.&icon($embed_file).'" /> '.
1.1071 raeburn 10754: '<span class="LC_filename">'.$embed_file.'</span>';
1.987 raeburn 10755: unless ($mapping{$embed_file} eq $embed_file) {
1.1075.2.35 raeburn 10756: $upload_output .= '<br /><span class="LC_info" style="font-size:smaller;">'.
10757: &mt('changed from: [_1]',$mapping{$embed_file}).'</span>';
1.987 raeburn 10758: }
1.1075.2.35 raeburn 10759: $upload_output .= '</td>';
1.1071 raeburn 10760: if ($args->{'ignore_remote_references'} && $embed_file =~ m{^\w+://}) {
1.1075.2.35 raeburn 10761: $upload_output.='<td align="right">'.
10762: '<span class="LC_info LC_fontsize_medium">'.
10763: &mt("URL points to web address").'</span>';
1.987 raeburn 10764: $numremref++;
1.660 raeburn 10765: } elsif ($args->{'error_on_invalid_names'}
10766: && $embed_file ne &Apache::lonnet::clean_filename($embed_file,{'keep_path' => 1,})) {
1.1075.2.35 raeburn 10767: $upload_output.='<td align="right"><span class="LC_warning">'.
10768: &mt('Invalid characters').'</span>';
1.987 raeburn 10769: $numinvalid++;
1.660 raeburn 10770: } else {
1.1075.2.35 raeburn 10771: $upload_output .= '<td>'.
10772: &embedded_file_element('upload_embedded',$counter,
1.987 raeburn 10773: $embed_file,\%mapping,
1.1071 raeburn 10774: $allfiles,$codebase,'upload');
10775: $counter ++;
10776: $numnew ++;
1.987 raeburn 10777: }
10778: $upload_output .= '</td>'.&Apache::loncommon::end_data_table_row()."\n";
10779: }
10780: foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%existing)) {
1.1071 raeburn 10781: if ($actionurl eq '/adm/dependencies') {
10782: my ($size,$mtime) = &get_dependency_details(\%currfile,\%currsubfile,$embed_file);
10783: $modify_output .= &start_data_table_row().
10784: '<td><a href="'.$path.'/'.$embed_file.'" style="text-decoration:none;">'.
10785: '<img src="'.&icon($embed_file).'" border="0" />'.
10786: ' <span class="LC_filename">'.$embed_file.'</span></a></td>'.
10787: '<td>'.$size.'</td>'.
10788: '<td>'.$mtime.'</td>'.
10789: '<td><label><input type="checkbox" name="mod_upload_dep" '.
10790: 'onclick="toggleBrowse('."'$counter'".')" id="mod_upload_dep_'.
10791: $counter.'" value="'.$counter.'" />'.&mt('Yes').'</label>'.
10792: '<div id="moduploaddep_'.$counter.'" style="display:none;">'.
10793: &embedded_file_element('upload_embedded',$counter,
10794: $embed_file,\%mapping,
10795: $allfiles,$codebase,'modify').
10796: '</div></td>'.
10797: &end_data_table_row()."\n";
10798: $counter ++;
10799: } else {
10800: $upload_output .= &start_data_table_row().
1.1075.2.35 raeburn 10801: '<td valign="top"><img src="'.&icon($embed_file).'" /> '.
10802: '<span class="LC_filename">'.$embed_file.'</span></td>'.
10803: '<td align="right"><span class="LC_info LC_fontsize_medium">'.&mt('Already exists').'</span></td>'.
1.1071 raeburn 10804: &Apache::loncommon::end_data_table_row()."\n";
10805: }
10806: }
10807: my $delidx = $counter;
10808: foreach my $oldfile (sort {lc($a) cmp lc($b)} keys(%unused)) {
10809: my ($size,$mtime) = &get_dependency_details(\%currfile,\%currsubfile,$oldfile);
10810: $delete_output .= &start_data_table_row().
10811: '<td><img src="'.&icon($oldfile).'" />'.
10812: ' <span class="LC_filename">'.$oldfile.'</span></td>'.
10813: '<td>'.$size.'</td>'.
10814: '<td>'.$mtime.'</td>'.
10815: '<td><label><input type="checkbox" name="del_upload_dep" '.
10816: ' value="'.$delidx.'" />'.&mt('Yes').'</label>'.
10817: &embedded_file_element('upload_embedded',$delidx,
10818: $oldfile,\%mapping,$allfiles,
10819: $codebase,'delete').'</td>'.
10820: &end_data_table_row()."\n";
10821: $numunused ++;
10822: $delidx ++;
1.987 raeburn 10823: }
10824: if ($upload_output) {
10825: $upload_output = &start_data_table().
10826: $upload_output.
10827: &end_data_table()."\n";
10828: }
1.1071 raeburn 10829: if ($modify_output) {
10830: $modify_output = &start_data_table().
10831: &start_data_table_header_row().
10832: '<th>'.&mt('File').'</th>'.
10833: '<th>'.&mt('Size (KB)').'</th>'.
10834: '<th>'.&mt('Modified').'</th>'.
10835: '<th>'.&mt('Upload replacement?').'</th>'.
10836: &end_data_table_header_row().
10837: $modify_output.
10838: &end_data_table()."\n";
10839: }
10840: if ($delete_output) {
10841: $delete_output = &start_data_table().
10842: &start_data_table_header_row().
10843: '<th>'.&mt('File').'</th>'.
10844: '<th>'.&mt('Size (KB)').'</th>'.
10845: '<th>'.&mt('Modified').'</th>'.
10846: '<th>'.&mt('Delete?').'</th>'.
10847: &end_data_table_header_row().
10848: $delete_output.
10849: &end_data_table()."\n";
10850: }
1.987 raeburn 10851: my $applies = 0;
10852: if ($numremref) {
10853: $applies ++;
10854: }
10855: if ($numinvalid) {
10856: $applies ++;
10857: }
10858: if ($numexisting) {
10859: $applies ++;
10860: }
1.1071 raeburn 10861: if ($counter || $numunused) {
1.987 raeburn 10862: $output = '<form name="upload_embedded" action="'.$actionurl.'"'.
10863: ' method="post" enctype="multipart/form-data">'."\n".
1.1071 raeburn 10864: $state.'<h3>'.$heading.'</h3>';
10865: if ($actionurl eq '/adm/dependencies') {
10866: if ($numnew) {
10867: $output .= '<h4>'.&mt('Missing dependencies').'</h4>'.
10868: '<p>'.&mt('The following files need to be uploaded.').'</p>'."\n".
10869: $upload_output.'<br />'."\n";
10870: }
10871: if ($numexisting) {
10872: $output .= '<h4>'.&mt('Uploaded dependencies (in use)').'</h4>'.
10873: '<p>'.&mt('Upload a new file to replace the one currently in use.').'</p>'."\n".
10874: $modify_output.'<br />'."\n";
10875: $buttontext = &mt('Save changes');
10876: }
10877: if ($numunused) {
10878: $output .= '<h4>'.&mt('Unused files').'</h4>'.
10879: '<p>'.&mt('The following uploaded files are no longer used.').'</p>'."\n".
10880: $delete_output.'<br />'."\n";
10881: $buttontext = &mt('Save changes');
10882: }
10883: } else {
10884: $output .= $upload_output.'<br />'."\n";
10885: }
10886: $output .= '<input type ="hidden" name="number_embedded_items" value="'.
10887: $counter.'" />'."\n";
10888: if ($actionurl eq '/adm/dependencies') {
10889: $output .= '<input type ="hidden" name="number_newemb_items" value="'.
10890: $numnew.'" />'."\n";
10891: } elsif ($actionurl eq '') {
1.987 raeburn 10892: $output .= '<input type="hidden" name="phase" value="three" />';
10893: }
10894: } elsif ($applies) {
10895: $output = '<b>'.&mt('Referenced files').'</b>:<br />';
10896: if ($applies > 1) {
10897: $output .=
1.1075.2.35 raeburn 10898: &mt('No dependencies need to be uploaded, as one of the following applies to each reference:').'<ul>';
1.987 raeburn 10899: if ($numremref) {
10900: $output .= '<li>'.&mt('reference is to a URL which points to another server').'</li>'."\n";
10901: }
10902: if ($numinvalid) {
10903: $output .= '<li>'.&mt('reference is to file with a name containing invalid characters').'</li>'."\n";
10904: }
10905: if ($numexisting) {
10906: $output .= '<li>'.&mt('reference is to an existing file at the specified location').'</li>'."\n";
10907: }
10908: $output .= '</ul><br />';
10909: } elsif ($numremref) {
10910: $output .= '<p>'.&mt('None to upload, as all references are to URLs pointing to another server.').'</p>';
10911: } elsif ($numinvalid) {
10912: $output .= '<p>'.&mt('None to upload, as all references are to files with names containing invalid characters.').'</p>';
10913: } elsif ($numexisting) {
10914: $output .= '<p>'.&mt('None to upload, as all references are to existing files.').'</p>';
10915: }
10916: $output .= $upload_output.'<br />';
10917: }
10918: my ($pathchange_output,$chgcount);
1.1071 raeburn 10919: $chgcount = $counter;
1.987 raeburn 10920: if (keys(%pathchanges) > 0) {
10921: foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%pathchanges)) {
1.1071 raeburn 10922: if ($counter) {
1.987 raeburn 10923: $output .= &embedded_file_element('pathchange',$chgcount,
10924: $embed_file,\%mapping,
1.1071 raeburn 10925: $allfiles,$codebase,'change');
1.987 raeburn 10926: } else {
10927: $pathchange_output .=
10928: &start_data_table_row().
10929: '<td><input type ="checkbox" name="namechange" value="'.
10930: $chgcount.'" checked="checked" /></td>'.
10931: '<td>'.$mapping{$embed_file}.'</td>'.
10932: '<td>'.$embed_file.
10933: &embedded_file_element('pathchange',$numpathchg,$embed_file,
1.1071 raeburn 10934: \%mapping,$allfiles,$codebase,'change').
1.987 raeburn 10935: '</td>'.&end_data_table_row();
1.660 raeburn 10936: }
1.987 raeburn 10937: $numpathchg ++;
10938: $chgcount ++;
1.660 raeburn 10939: }
10940: }
1.1075.2.35 raeburn 10941: if (($counter) || ($numunused)) {
1.987 raeburn 10942: if ($numpathchg) {
10943: $output .= '<input type ="hidden" name="number_pathchange_items" value="'.
10944: $numpathchg.'" />'."\n";
10945: }
10946: if (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank') ||
10947: ($actionurl eq '/adm/imsimport')) {
10948: $output .= '<input type="hidden" name="phase" value="three" />'."\n";
10949: } elsif ($actionurl eq '/adm/portfolio' || $actionurl eq '/adm/coursegrp_portfolio') {
10950: $output .= '<input type="hidden" name="action" value="upload_embedded" />';
1.1071 raeburn 10951: } elsif ($actionurl eq '/adm/dependencies') {
10952: $output .= '<input type="hidden" name="action" value="process_changes" />';
1.987 raeburn 10953: }
1.1075.2.35 raeburn 10954: $output .= '<input type ="submit" value="'.$buttontext.'" />'."\n".'</form>'."\n";
1.987 raeburn 10955: } elsif ($numpathchg) {
10956: my %pathchange = ();
10957: $output .= &modify_html_form('pathchange',$actionurl,$state,\%pathchange,$pathchange_output);
10958: if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) {
10959: $output .= '<p>'.&mt('or').'</p>';
1.1075.2.35 raeburn 10960: }
1.987 raeburn 10961: }
1.1071 raeburn 10962: return ($output,$counter,$numpathchg);
1.987 raeburn 10963: }
10964:
1.1075.2.47 raeburn 10965: =pod
10966:
10967: =item * clean_path($name)
10968:
10969: Performs clean-up of directories, subdirectories and filename in an
10970: embedded object, referenced in an HTML file which is being uploaded
10971: to a course or portfolio, where
10972: "Upload embedded images/multimedia files if HTML file" checkbox was
10973: checked.
10974:
10975: Clean-up is similar to replacements in lonnet::clean_filename()
10976: except each / between sub-directory and next level is preserved.
10977:
10978: =cut
10979:
10980: sub clean_path {
10981: my ($embed_file) = @_;
10982: $embed_file =~s{^/+}{};
10983: my @contents;
10984: if ($embed_file =~ m{/}) {
10985: @contents = split(/\//,$embed_file);
10986: } else {
10987: @contents = ($embed_file);
10988: }
10989: my $lastidx = scalar(@contents)-1;
10990: for (my $i=0; $i<=$lastidx; $i++) {
10991: $contents[$i]=~s{\\}{/}g;
10992: $contents[$i]=~s/\s+/\_/g;
10993: $contents[$i]=~s{[^/\w\.\-]}{}g;
10994: if ($i == $lastidx) {
10995: $contents[$i]=~s/\.(\d+)(?=\.)/_$1/g;
10996: }
10997: }
10998: if ($lastidx > 0) {
10999: return join('/',@contents);
11000: } else {
11001: return $contents[0];
11002: }
11003: }
11004:
1.987 raeburn 11005: sub embedded_file_element {
1.1071 raeburn 11006: my ($context,$num,$embed_file,$mapping,$allfiles,$codebase,$type) = @_;
1.987 raeburn 11007: return unless ((ref($mapping) eq 'HASH') && (ref($allfiles) eq 'HASH') &&
11008: (ref($codebase) eq 'HASH'));
11009: my $output;
1.1071 raeburn 11010: if (($context eq 'upload_embedded') && ($type ne 'delete')) {
1.987 raeburn 11011: $output = '<input name="embedded_item_'.$num.'" type="file" value="" />'."\n";
11012: }
11013: $output .= '<input name="embedded_orig_'.$num.'" type="hidden" value="'.
11014: &escape($embed_file).'" />';
11015: unless (($context eq 'upload_embedded') &&
11016: ($mapping->{$embed_file} eq $embed_file)) {
11017: $output .='
11018: <input name="embedded_ref_'.$num.'" type="hidden" value="'.&escape($mapping->{$embed_file}).'" />';
11019: }
11020: my $attrib;
11021: if (ref($allfiles->{$mapping->{$embed_file}}) eq 'ARRAY') {
11022: $attrib = &escape(join(':',@{$allfiles->{$mapping->{$embed_file}}}));
11023: }
11024: $output .=
11025: "\n\t\t".
11026: '<input name="embedded_attrib_'.$num.'" type="hidden" value="'.
11027: $attrib.'" />';
11028: if (exists($codebase->{$mapping->{$embed_file}})) {
11029: $output .=
11030: "\n\t\t".
11031: '<input name="codebase_'.$num.'" type="hidden" value="'.
11032: &escape($codebase->{$mapping->{$embed_file}}).'" />';
1.984 raeburn 11033: }
1.987 raeburn 11034: return $output;
1.660 raeburn 11035: }
11036:
1.1071 raeburn 11037: sub get_dependency_details {
11038: my ($currfile,$currsubfile,$embed_file) = @_;
11039: my ($size,$mtime,$showsize,$showmtime);
11040: if ((ref($currfile) eq 'HASH') && (ref($currsubfile))) {
11041: if ($embed_file =~ m{/}) {
11042: my ($path,$fname) = split(/\//,$embed_file);
11043: if (ref($currsubfile->{$path}{$fname}) eq 'ARRAY') {
11044: ($size,$mtime) = @{$currsubfile->{$path}{$fname}};
11045: }
11046: } else {
11047: if (ref($currfile->{$embed_file}) eq 'ARRAY') {
11048: ($size,$mtime) = @{$currfile->{$embed_file}};
11049: }
11050: }
11051: $showsize = $size/1024.0;
11052: $showsize = sprintf("%.1f",$showsize);
11053: if ($mtime > 0) {
11054: $showmtime = &Apache::lonlocal::locallocaltime($mtime);
11055: }
11056: }
11057: return ($showsize,$showmtime);
11058: }
11059:
11060: sub ask_embedded_js {
11061: return <<"END";
11062: <script type="text/javascript"">
11063: // <![CDATA[
11064: function toggleBrowse(counter) {
11065: var chkboxid = document.getElementById('mod_upload_dep_'+counter);
11066: var fileid = document.getElementById('embedded_item_'+counter);
11067: var uploaddivid = document.getElementById('moduploaddep_'+counter);
11068: if (chkboxid.checked == true) {
11069: uploaddivid.style.display='block';
11070: } else {
11071: uploaddivid.style.display='none';
11072: fileid.value = '';
11073: }
11074: }
11075: // ]]>
11076: </script>
11077:
11078: END
11079: }
11080:
1.661 raeburn 11081: sub upload_embedded {
11082: my ($context,$dirpath,$uname,$udom,$dir_root,$url_root,$group,$disk_quota,
1.987 raeburn 11083: $current_disk_usage,$hiddenstate,$actionurl) = @_;
11084: my (%pathchange,$output,$modifyform,$footer,$returnflag);
1.661 raeburn 11085: for (my $i=0; $i<$env{'form.number_embedded_items'}; $i++) {
11086: next if (!exists($env{'form.embedded_item_'.$i.'.filename'}));
11087: my $orig_uploaded_filename =
11088: $env{'form.embedded_item_'.$i.'.filename'};
1.987 raeburn 11089: foreach my $type ('orig','ref','attrib','codebase') {
11090: if ($env{'form.embedded_'.$type.'_'.$i} ne '') {
11091: $env{'form.embedded_'.$type.'_'.$i} =
11092: &unescape($env{'form.embedded_'.$type.'_'.$i});
11093: }
11094: }
1.661 raeburn 11095: my ($path,$fname) =
11096: ($env{'form.embedded_orig_'.$i} =~ m{(.*/)([^/]*)});
11097: # no path, whole string is fname
11098: if (!$fname) { $fname = $env{'form.embedded_orig_'.$i} };
11099: $fname = &Apache::lonnet::clean_filename($fname);
11100: # See if there is anything left
11101: next if ($fname eq '');
11102:
11103: # Check if file already exists as a file or directory.
11104: my ($state,$msg);
11105: if ($context eq 'portfolio') {
11106: my $port_path = $dirpath;
11107: if ($group ne '') {
11108: $port_path = "groups/$group/$port_path";
11109: }
1.987 raeburn 11110: ($state,$msg) = &check_for_upload($env{'form.currentpath'}.$path,
11111: $fname,$group,'embedded_item_'.$i,
1.661 raeburn 11112: $dir_root,$port_path,$disk_quota,
11113: $current_disk_usage,$uname,$udom);
11114: if ($state eq 'will_exceed_quota'
1.984 raeburn 11115: || $state eq 'file_locked') {
1.661 raeburn 11116: $output .= $msg;
11117: next;
11118: }
11119: } elsif (($context eq 'author') || ($context eq 'testbank')) {
11120: ($state,$msg) = &check_for_existing($path,$fname,'embedded_item_'.$i);
11121: if ($state eq 'exists') {
11122: $output .= $msg;
11123: next;
11124: }
11125: }
11126: # Check if extension is valid
11127: if (($fname =~ /\.(\w+)$/) &&
11128: (&Apache::loncommon::fileembstyle($1) eq 'hdn')) {
1.1075.2.53 raeburn 11129: $output .= &mt('Invalid file extension ([_1]) - reserved for internal use.',$1)
11130: .' '.&mt('Rename the file with a different extension and re-upload.').'<br />';
1.661 raeburn 11131: next;
11132: } elsif (($fname =~ /\.(\w+)$/) &&
11133: (!defined(&Apache::loncommon::fileembstyle($1)))) {
1.987 raeburn 11134: $output .= &mt('Unrecognized file extension ([_1]) - rename the file with a proper extension and re-upload.',$1).'<br />';
1.661 raeburn 11135: next;
11136: } elsif ($fname=~/\.(\d+)\.(\w+)$/) {
1.1075.2.34 raeburn 11137: $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 11138: next;
11139: }
11140: $env{'form.embedded_item_'.$i.'.filename'}=$fname;
1.1075.2.35 raeburn 11141: my $subdir = $path;
11142: $subdir =~ s{/+$}{};
1.661 raeburn 11143: if ($context eq 'portfolio') {
1.984 raeburn 11144: my $result;
11145: if ($state eq 'existingfile') {
11146: $result=
11147: &Apache::lonnet::userfileupload('embedded_item_'.$i,'existingfile',
1.1075.2.35 raeburn 11148: $dirpath.$env{'form.currentpath'}.$subdir);
1.661 raeburn 11149: } else {
1.984 raeburn 11150: $result=
11151: &Apache::lonnet::userfileupload('embedded_item_'.$i,'',
1.987 raeburn 11152: $dirpath.
1.1075.2.35 raeburn 11153: $env{'form.currentpath'}.$subdir);
1.984 raeburn 11154: if ($result !~ m|^/uploaded/|) {
11155: $output .= '<span class="LC_error">'
11156: .&mt('An error occurred ([_1]) while trying to upload [_2] for embedded element [_3].'
11157: ,$result,$orig_uploaded_filename,$env{'form.embedded_orig_'.$i})
11158: .'</span><br />';
11159: next;
11160: } else {
1.987 raeburn 11161: $output .= &mt('Uploaded [_1]','<span class="LC_filename">'.
11162: $path.$fname.'</span>').'<br />';
1.984 raeburn 11163: }
1.661 raeburn 11164: }
1.1075.2.35 raeburn 11165: } elsif (($context eq 'coursedoc') || ($context eq 'syllabus')) {
11166: my $extendedsubdir = $dirpath.'/'.$subdir;
11167: $extendedsubdir =~ s{/+$}{};
1.987 raeburn 11168: my $result =
1.1075.2.35 raeburn 11169: &Apache::lonnet::userfileupload('embedded_item_'.$i,$context,$extendedsubdir);
1.987 raeburn 11170: if ($result !~ m|^/uploaded/|) {
11171: $output .= '<span class="LC_error">'
11172: .&mt('An error occurred ([_1]) while trying to upload [_2] for embedded element [_3].'
11173: ,$result,$orig_uploaded_filename,$env{'form.embedded_orig_'.$i})
11174: .'</span><br />';
11175: next;
11176: } else {
11177: $output .= &mt('Uploaded [_1]','<span class="LC_filename">'.
11178: $path.$fname.'</span>').'<br />';
1.1075.2.35 raeburn 11179: if ($context eq 'syllabus') {
11180: &Apache::lonnet::make_public_indefinitely($result);
11181: }
1.987 raeburn 11182: }
1.661 raeburn 11183: } else {
11184: # Save the file
11185: my $target = $env{'form.embedded_item_'.$i};
11186: my $fullpath = $dir_root.$dirpath.'/'.$path;
11187: my $dest = $fullpath.$fname;
11188: my $url = $url_root.$dirpath.'/'.$path.$fname;
1.1027 raeburn 11189: my @parts=split(/\//,"$dirpath/$path");
1.661 raeburn 11190: my $count;
11191: my $filepath = $dir_root;
1.1027 raeburn 11192: foreach my $subdir (@parts) {
11193: $filepath .= "/$subdir";
11194: if (!-e $filepath) {
1.661 raeburn 11195: mkdir($filepath,0770);
11196: }
11197: }
11198: my $fh;
11199: if (!open($fh,'>'.$dest)) {
11200: &Apache::lonnet::logthis('Failed to create '.$dest);
11201: $output .= '<span class="LC_error">'.
1.1071 raeburn 11202: &mt('An error occurred while trying to upload [_1] for embedded element [_2].',
11203: $orig_uploaded_filename,$env{'form.embedded_orig_'.$i}).
1.661 raeburn 11204: '</span><br />';
11205: } else {
11206: if (!print $fh $env{'form.embedded_item_'.$i}) {
11207: &Apache::lonnet::logthis('Failed to write to '.$dest);
11208: $output .= '<span class="LC_error">'.
1.1071 raeburn 11209: &mt('An error occurred while writing the file [_1] for embedded element [_2].',
11210: $orig_uploaded_filename,$env{'form.embedded_orig_'.$i}).
1.661 raeburn 11211: '</span><br />';
11212: } else {
1.987 raeburn 11213: $output .= &mt('Uploaded [_1]','<span class="LC_filename">'.
11214: $url.'</span>').'<br />';
11215: unless ($context eq 'testbank') {
11216: $footer .= &mt('View embedded file: [_1]',
11217: '<a href="'.$url.'">'.$fname.'</a>').'<br />';
11218: }
11219: }
11220: close($fh);
11221: }
11222: }
11223: if ($env{'form.embedded_ref_'.$i}) {
11224: $pathchange{$i} = 1;
11225: }
11226: }
11227: if ($output) {
11228: $output = '<p>'.$output.'</p>';
11229: }
11230: $output .= &modify_html_form('upload_embedded',$actionurl,$hiddenstate,\%pathchange);
11231: $returnflag = 'ok';
1.1071 raeburn 11232: my $numpathchgs = scalar(keys(%pathchange));
11233: if ($numpathchgs > 0) {
1.987 raeburn 11234: if ($context eq 'portfolio') {
11235: $output .= '<p>'.&mt('or').'</p>';
11236: } elsif ($context eq 'testbank') {
1.1071 raeburn 11237: $output .= '<p>'.&mt('Or [_1]continue[_2] the testbank import without modifying the reference(s).',
11238: '<a href="javascript:document.testbankForm.submit();">','</a>').'</p>';
1.987 raeburn 11239: $returnflag = 'modify_orightml';
11240: }
11241: }
1.1071 raeburn 11242: return ($output.$footer,$returnflag,$numpathchgs);
1.987 raeburn 11243: }
11244:
11245: sub modify_html_form {
11246: my ($context,$actionurl,$hiddenstate,$pathchange,$pathchgtable) = @_;
11247: my $end = 0;
11248: my $modifyform;
11249: if ($context eq 'upload_embedded') {
11250: return unless (ref($pathchange) eq 'HASH');
11251: if ($env{'form.number_embedded_items'}) {
11252: $end += $env{'form.number_embedded_items'};
11253: }
11254: if ($env{'form.number_pathchange_items'}) {
11255: $end += $env{'form.number_pathchange_items'};
11256: }
11257: if ($end) {
11258: for (my $i=0; $i<$end; $i++) {
11259: if ($i < $env{'form.number_embedded_items'}) {
11260: next unless($pathchange->{$i});
11261: }
11262: $modifyform .=
11263: &start_data_table_row().
11264: '<td><input type ="checkbox" name="namechange" value="'.$i.'" '.
11265: 'checked="checked" /></td>'.
11266: '<td>'.$env{'form.embedded_ref_'.$i}.
11267: '<input type="hidden" name="embedded_ref_'.$i.'" value="'.
11268: &escape($env{'form.embedded_ref_'.$i}).'" />'.
11269: '<input type="hidden" name="embedded_codebase_'.$i.'" value="'.
11270: &escape($env{'form.embedded_codebase_'.$i}).'" />'.
11271: '<input type="hidden" name="embedded_attrib_'.$i.'" value="'.
11272: &escape($env{'form.embedded_attrib_'.$i}).'" /></td>'.
11273: '<td>'.$env{'form.embedded_orig_'.$i}.
11274: '<input type="hidden" name="embedded_orig_'.$i.'" value="'.
11275: &escape($env{'form.embedded_orig_'.$i}).'" /></td>'.
11276: &end_data_table_row();
1.1071 raeburn 11277: }
1.987 raeburn 11278: }
11279: } else {
11280: $modifyform = $pathchgtable;
11281: if (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank')) {
11282: $hiddenstate .= '<input type="hidden" name="phase" value="four" />';
11283: } elsif (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) {
11284: $hiddenstate .= '<input type="hidden" name="action" value="modify_orightml" />';
11285: }
11286: }
11287: if ($modifyform) {
1.1071 raeburn 11288: if ($actionurl eq '/adm/dependencies') {
11289: $hiddenstate .= '<input type="hidden" name="action" value="modifyhrefs" />';
11290: }
1.987 raeburn 11291: return '<h3>'.&mt('Changes in content of HTML file required').'</h3>'."\n".
11292: '<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".
11293: '<li>'.&mt('For consistency between the reference(s) and the location of the corresponding stored file within LON-CAPA.').'</li>'."\n".
11294: '<li>'.&mt('To change absolute paths to relative paths, or replace directory traversal via "../" within the original reference.').'</li>'."\n".
11295: '</ol></p>'."\n".'<p>'.
11296: &mt('LON-CAPA can make the required changes to your HTML file.').'</p>'."\n".
11297: '<form method="post" name="refchanger" action="'.$actionurl.'">'.
11298: &start_data_table()."\n".
11299: &start_data_table_header_row().
11300: '<th>'.&mt('Change?').'</th>'.
11301: '<th>'.&mt('Current reference').'</th>'.
11302: '<th>'.&mt('Required reference').'</th>'.
11303: &end_data_table_header_row()."\n".
11304: $modifyform.
11305: &end_data_table().'<br />'."\n".$hiddenstate.
11306: '<input type="submit" name="pathchanges" value="'.&mt('Modify HTML file').'" />'.
11307: '</form>'."\n";
11308: }
11309: return;
11310: }
11311:
11312: sub modify_html_refs {
1.1075.2.35 raeburn 11313: my ($context,$dirpath,$uname,$udom,$dir_root,$url) = @_;
1.987 raeburn 11314: my $container;
11315: if ($context eq 'portfolio') {
11316: $container = $env{'form.container'};
11317: } elsif ($context eq 'coursedoc') {
11318: $container = $env{'form.primaryurl'};
1.1071 raeburn 11319: } elsif ($context eq 'manage_dependencies') {
11320: (undef,undef,$container) = &Apache::lonnet::decode_symb($env{'form.symb'});
11321: $container = "/$container";
1.1075.2.35 raeburn 11322: } elsif ($context eq 'syllabus') {
11323: $container = $url;
1.987 raeburn 11324: } else {
1.1027 raeburn 11325: $container = $Apache::lonnet::perlvar{'lonDocRoot'}.$env{'form.filename'};
1.987 raeburn 11326: }
11327: my (%allfiles,%codebase,$output,$content);
11328: my @changes = &get_env_multiple('form.namechange');
1.1075.2.35 raeburn 11329: unless ((@changes > 0) || ($context eq 'syllabus')) {
1.1071 raeburn 11330: if (wantarray) {
11331: return ('',0,0);
11332: } else {
11333: return;
11334: }
11335: }
11336: if (($context eq 'portfolio') || ($context eq 'coursedoc') ||
1.1075.2.35 raeburn 11337: ($context eq 'manage_dependencies') || ($context eq 'syllabus')) {
1.1071 raeburn 11338: unless ($container =~ m{^/uploaded/\Q$udom\E/\Q$uname\E/}) {
11339: if (wantarray) {
11340: return ('',0,0);
11341: } else {
11342: return;
11343: }
11344: }
1.987 raeburn 11345: $content = &Apache::lonnet::getfile($container);
1.1071 raeburn 11346: if ($content eq '-1') {
11347: if (wantarray) {
11348: return ('',0,0);
11349: } else {
11350: return;
11351: }
11352: }
1.987 raeburn 11353: } else {
1.1071 raeburn 11354: unless ($container =~ /^\Q$dir_root\E/) {
11355: if (wantarray) {
11356: return ('',0,0);
11357: } else {
11358: return;
11359: }
11360: }
1.987 raeburn 11361: if (open(my $fh,"<$container")) {
11362: $content = join('', <$fh>);
11363: close($fh);
11364: } else {
1.1071 raeburn 11365: if (wantarray) {
11366: return ('',0,0);
11367: } else {
11368: return;
11369: }
1.987 raeburn 11370: }
11371: }
11372: my ($count,$codebasecount) = (0,0);
11373: my $mm = new File::MMagic;
11374: my $mime_type = $mm->checktype_contents($content);
11375: if ($mime_type eq 'text/html') {
11376: my $parse_result =
11377: &Apache::lonnet::extract_embedded_items($container,\%allfiles,
11378: \%codebase,\$content);
11379: if ($parse_result eq 'ok') {
11380: foreach my $i (@changes) {
11381: my $orig = &unescape($env{'form.embedded_orig_'.$i});
11382: my $ref = &unescape($env{'form.embedded_ref_'.$i});
11383: if ($allfiles{$ref}) {
11384: my $newname = $orig;
11385: my ($attrib_regexp,$codebase);
1.1006 raeburn 11386: $attrib_regexp = &unescape($env{'form.embedded_attrib_'.$i});
1.987 raeburn 11387: if ($attrib_regexp =~ /:/) {
11388: $attrib_regexp =~ s/\:/|/g;
11389: }
11390: if ($content =~ m{($attrib_regexp\s*=\s*['"]?)\Q$ref\E(['"]?)}) {
11391: my $numchg = ($content =~ s{($attrib_regexp\s*=\s*['"]?)\Q$ref\E(['"]?)}{$1$newname$2}gi);
11392: $count += $numchg;
1.1075.2.35 raeburn 11393: $allfiles{$newname} = $allfiles{$ref};
1.1075.2.48 raeburn 11394: delete($allfiles{$ref});
1.987 raeburn 11395: }
11396: if ($env{'form.embedded_codebase_'.$i} ne '') {
1.1006 raeburn 11397: $codebase = &unescape($env{'form.embedded_codebase_'.$i});
1.987 raeburn 11398: my $numchg = ($content =~ s/(codebase\s*=\s*["']?)\Q$codebase\E(["']?)/$1.$2/i); #' stupid emacs
11399: $codebasecount ++;
11400: }
11401: }
11402: }
1.1075.2.35 raeburn 11403: my $skiprewrites;
1.987 raeburn 11404: if ($count || $codebasecount) {
11405: my $saveresult;
1.1071 raeburn 11406: if (($context eq 'portfolio') || ($context eq 'coursedoc') ||
1.1075.2.35 raeburn 11407: ($context eq 'manage_dependencies') || ($context eq 'syllabus')) {
1.987 raeburn 11408: my $url = &Apache::lonnet::store_edited_file($container,$content,$udom,$uname,\$saveresult);
11409: if ($url eq $container) {
11410: my ($fname) = ($container =~ m{/([^/]+)$});
11411: $output = '<p>'.&mt('Updated [quant,_1,reference] in [_2].',
11412: $count,'<span class="LC_filename">'.
1.1071 raeburn 11413: $fname.'</span>').'</p>';
1.987 raeburn 11414: } else {
11415: $output = '<p class="LC_error">'.
11416: &mt('Error: update failed for: [_1].',
11417: '<span class="LC_filename">'.
11418: $container.'</span>').'</p>';
11419: }
1.1075.2.35 raeburn 11420: if ($context eq 'syllabus') {
11421: unless ($saveresult eq 'ok') {
11422: $skiprewrites = 1;
11423: }
11424: }
1.987 raeburn 11425: } else {
11426: if (open(my $fh,">$container")) {
11427: print $fh $content;
11428: close($fh);
11429: $output = '<p>'.&mt('Updated [quant,_1,reference] in [_2].',
11430: $count,'<span class="LC_filename">'.
11431: $container.'</span>').'</p>';
1.661 raeburn 11432: } else {
1.987 raeburn 11433: $output = '<p class="LC_error">'.
11434: &mt('Error: could not update [_1].',
11435: '<span class="LC_filename">'.
11436: $container.'</span>').'</p>';
1.661 raeburn 11437: }
11438: }
11439: }
1.1075.2.35 raeburn 11440: if (($context eq 'syllabus') && (!$skiprewrites)) {
11441: my ($actionurl,$state);
11442: $actionurl = "/public/$udom/$uname/syllabus";
11443: my ($ignore,$num,$numpathchanges,$existing,$mapping) =
11444: &ask_for_embedded_content($actionurl,$state,\%allfiles,
11445: \%codebase,
11446: {'context' => 'rewrites',
11447: 'ignore_remote_references' => 1,});
11448: if (ref($mapping) eq 'HASH') {
11449: my $rewrites = 0;
11450: foreach my $key (keys(%{$mapping})) {
11451: next if ($key =~ m{^https?://});
11452: my $ref = $mapping->{$key};
11453: my $newname = "/uploaded/$udom/$uname/portfolio/syllabus/$key";
11454: my $attrib;
11455: if (ref($allfiles{$mapping->{$key}}) eq 'ARRAY') {
11456: $attrib = join('|',@{$allfiles{$mapping->{$key}}});
11457: }
11458: if ($content =~ m{($attrib\s*=\s*['"]?)\Q$ref\E(['"]?)}) {
11459: my $numchg = ($content =~ s{($attrib\s*=\s*['"]?)\Q$ref\E(['"]?)}{$1$newname$2}gi);
11460: $rewrites += $numchg;
11461: }
11462: }
11463: if ($rewrites) {
11464: my $saveresult;
11465: my $url = &Apache::lonnet::store_edited_file($container,$content,$udom,$uname,\$saveresult);
11466: if ($url eq $container) {
11467: my ($fname) = ($container =~ m{/([^/]+)$});
11468: $output .= '<p>'.&mt('Rewrote [quant,_1,link] as [quant,_1,absolute link] in [_2].',
11469: $count,'<span class="LC_filename">'.
11470: $fname.'</span>').'</p>';
11471: } else {
11472: $output .= '<p class="LC_error">'.
11473: &mt('Error: could not update links in [_1].',
11474: '<span class="LC_filename">'.
11475: $container.'</span>').'</p>';
11476:
11477: }
11478: }
11479: }
11480: }
1.987 raeburn 11481: } else {
11482: &logthis('Failed to parse '.$container.
11483: ' to modify references: '.$parse_result);
1.661 raeburn 11484: }
11485: }
1.1071 raeburn 11486: if (wantarray) {
11487: return ($output,$count,$codebasecount);
11488: } else {
11489: return $output;
11490: }
1.661 raeburn 11491: }
11492:
11493: sub check_for_existing {
11494: my ($path,$fname,$element) = @_;
11495: my ($state,$msg);
11496: if (-d $path.'/'.$fname) {
11497: $state = 'exists';
11498: $msg = &mt('Unable to upload [_1]. A directory by that name was found in [_2].','<span class="LC_filename">'.$fname.'</span>',$path);
11499: } elsif (-e $path.'/'.$fname) {
11500: $state = 'exists';
11501: $msg = &mt('Unable to upload [_1]. A file by that name was found in [_2].','<span class="LC_filename">'.$fname.'</span>',$path);
11502: }
11503: if ($state eq 'exists') {
11504: $msg = '<span class="LC_error">'.$msg.'</span><br />';
11505: }
11506: return ($state,$msg);
11507: }
11508:
11509: sub check_for_upload {
11510: my ($path,$fname,$group,$element,$portfolio_root,$port_path,
11511: $disk_quota,$current_disk_usage,$uname,$udom) = @_;
1.985 raeburn 11512: my $filesize = length($env{'form.'.$element});
11513: if (!$filesize) {
11514: my $msg = '<span class="LC_error">'.
11515: &mt('Unable to upload [_1]. (size = [_2] bytes)',
11516: '<span class="LC_filename">'.$fname.'</span>',
11517: $filesize).'<br />'.
1.1007 raeburn 11518: &mt('Either the file you attempted to upload was empty, or your web browser was unable to read its contents.').'<br />'.
1.985 raeburn 11519: '</span>';
11520: return ('zero_bytes',$msg);
11521: }
11522: $filesize = $filesize/1000; #express in k (1024?)
1.661 raeburn 11523: my $getpropath = 1;
1.1021 raeburn 11524: my ($dirlistref,$listerror) =
11525: &Apache::lonnet::dirlist($portfolio_root.$path,$udom,$uname,$getpropath);
1.661 raeburn 11526: my $found_file = 0;
11527: my $locked_file = 0;
1.991 raeburn 11528: my @lockers;
11529: my $navmap;
11530: if ($env{'request.course.id'}) {
11531: $navmap = Apache::lonnavmaps::navmap->new();
11532: }
1.1021 raeburn 11533: if (ref($dirlistref) eq 'ARRAY') {
11534: foreach my $line (@{$dirlistref}) {
11535: my ($file_name,$rest)=split(/\&/,$line,2);
11536: if ($file_name eq $fname){
11537: $file_name = $path.$file_name;
11538: if ($group ne '') {
11539: $file_name = $group.$file_name;
11540: }
11541: $found_file = 1;
11542: if (&Apache::lonnet::is_locked($file_name,$udom,$uname,\@lockers) eq 'true') {
11543: foreach my $lock (@lockers) {
11544: if (ref($lock) eq 'ARRAY') {
11545: my ($symb,$crsid) = @{$lock};
11546: if ($crsid eq $env{'request.course.id'}) {
11547: if (ref($navmap)) {
11548: my $res = $navmap->getBySymb($symb);
11549: foreach my $part (@{$res->parts()}) {
11550: my ($slot_status,$slot_time,$slot_name)=$res->check_for_slot($part);
11551: unless (($slot_status == $res->RESERVED) ||
11552: ($slot_status == $res->RESERVED_LOCATION)) {
11553: $locked_file = 1;
11554: }
1.991 raeburn 11555: }
1.1021 raeburn 11556: } else {
11557: $locked_file = 1;
1.991 raeburn 11558: }
11559: } else {
11560: $locked_file = 1;
11561: }
11562: }
1.1021 raeburn 11563: }
11564: } else {
11565: my @info = split(/\&/,$rest);
11566: my $currsize = $info[6]/1000;
11567: if ($currsize < $filesize) {
11568: my $extra = $filesize - $currsize;
11569: if (($current_disk_usage + $extra) > $disk_quota) {
1.1075.2.69 raeburn 11570: my $msg = '<p class="LC_warning">'.
1.1021 raeburn 11571: &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 11572: '<span class="LC_filename">'.$fname.'</span>',$filesize,$currsize).'</p>'.
11573: '<p>'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.',
11574: $disk_quota,$current_disk_usage).'</p>';
1.1021 raeburn 11575: return ('will_exceed_quota',$msg);
11576: }
1.984 raeburn 11577: }
11578: }
1.661 raeburn 11579: }
11580: }
11581: }
11582: if (($current_disk_usage + $filesize) > $disk_quota){
1.1075.2.69 raeburn 11583: my $msg = '<p class="LC_warning">'.
11584: &mt('Unable to upload [_1]. (size = [_2] kilobytes). Disk quota will be exceeded.','<span class="LC_filename">'.$fname.'</span>',$filesize).'</p>'.
11585: '<p>'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.',$disk_quota,$current_disk_usage).'</p>';
1.661 raeburn 11586: return ('will_exceed_quota',$msg);
11587: } elsif ($found_file) {
11588: if ($locked_file) {
1.1075.2.69 raeburn 11589: my $msg = '<p class="LC_warning">';
1.661 raeburn 11590: $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 11591: $msg .= '</p>';
1.661 raeburn 11592: $msg .= &mt('You will be able to rename or delete existing [_1] after a grade has been assigned.','<span class="LC_filename">'.$fname.'</span>');
11593: return ('file_locked',$msg);
11594: } else {
1.1075.2.69 raeburn 11595: my $msg = '<p class="LC_error">';
1.984 raeburn 11596: $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 11597: $msg .= '</p>';
1.984 raeburn 11598: return ('existingfile',$msg);
1.661 raeburn 11599: }
11600: }
11601: }
11602:
1.987 raeburn 11603: sub check_for_traversal {
11604: my ($path,$url,$toplevel) = @_;
11605: my @parts=split(/\//,$path);
11606: my $cleanpath;
11607: my $fullpath = $url;
11608: for (my $i=0;$i<@parts;$i++) {
11609: next if ($parts[$i] eq '.');
11610: if ($parts[$i] eq '..') {
11611: $fullpath =~ s{([^/]+/)$}{};
11612: } else {
11613: $fullpath .= $parts[$i].'/';
11614: }
11615: }
11616: if ($fullpath =~ /^\Q$url\E(.*)$/) {
11617: $cleanpath = $1;
11618: } elsif ($fullpath =~ /^\Q$toplevel\E(.*)$/) {
11619: my $curr_toprel = $1;
11620: my @parts = split(/\//,$curr_toprel);
11621: my ($url_toprel) = ($url =~ /^\Q$toplevel\E(.*)$/);
11622: my @urlparts = split(/\//,$url_toprel);
11623: my $doubledots;
11624: my $startdiff = -1;
11625: for (my $i=0; $i<@urlparts; $i++) {
11626: if ($startdiff == -1) {
11627: unless ($urlparts[$i] eq $parts[$i]) {
11628: $startdiff = $i;
11629: $doubledots .= '../';
11630: }
11631: } else {
11632: $doubledots .= '../';
11633: }
11634: }
11635: if ($startdiff > -1) {
11636: $cleanpath = $doubledots;
11637: for (my $i=$startdiff; $i<@parts; $i++) {
11638: $cleanpath .= $parts[$i].'/';
11639: }
11640: }
11641: }
11642: $cleanpath =~ s{(/)$}{};
11643: return $cleanpath;
11644: }
1.31 albertel 11645:
1.1053 raeburn 11646: sub is_archive_file {
11647: my ($mimetype) = @_;
11648: if (($mimetype eq 'application/octet-stream') ||
11649: ($mimetype eq 'application/x-stuffit') ||
11650: ($mimetype =~ m{^application/(x\-)?(compressed|tar|zip|tgz|gz|gtar|gzip|gunzip|bz|bz2|bzip2)})) {
11651: return 1;
11652: }
11653: return;
11654: }
11655:
11656: sub decompress_form {
1.1065 raeburn 11657: my ($mimetype,$archiveurl,$action,$noextract,$hiddenelements,$dirlist) = @_;
1.1053 raeburn 11658: my %lt = &Apache::lonlocal::texthash (
11659: this => 'This file is an archive file.',
1.1067 raeburn 11660: camt => 'This file is a Camtasia archive file.',
1.1065 raeburn 11661: itsc => 'Its contents are as follows:',
1.1053 raeburn 11662: youm => 'You may wish to extract its contents.',
11663: extr => 'Extract contents',
1.1067 raeburn 11664: auto => 'LON-CAPA can process the files automatically, or you can decide how each should be handled.',
11665: proa => 'Process automatically?',
1.1053 raeburn 11666: yes => 'Yes',
11667: no => 'No',
1.1067 raeburn 11668: fold => 'Title for folder containing movie',
11669: movi => 'Title for page containing embedded movie',
1.1053 raeburn 11670: );
1.1065 raeburn 11671: my $fileloc = &Apache::lonnet::filelocation(undef,$archiveurl);
1.1067 raeburn 11672: my ($is_camtasia,$topdir,%toplevel,@paths);
1.1065 raeburn 11673: my $info = &list_archive_contents($fileloc,\@paths);
11674: if (@paths) {
11675: foreach my $path (@paths) {
11676: $path =~ s{^/}{};
1.1067 raeburn 11677: if ($path =~ m{^([^/]+)/$}) {
11678: $topdir = $1;
11679: }
1.1065 raeburn 11680: if ($path =~ m{^([^/]+)/}) {
11681: $toplevel{$1} = $path;
11682: } else {
11683: $toplevel{$path} = $path;
11684: }
11685: }
11686: }
1.1067 raeburn 11687: if ($mimetype =~ m{^application/(x\-)?(compressed|zip)}) {
1.1075.2.59 raeburn 11688: my @camtasia6 = ("$topdir/","$topdir/index.html",
1.1067 raeburn 11689: "$topdir/media/",
11690: "$topdir/media/$topdir.mp4",
11691: "$topdir/media/FirstFrame.png",
11692: "$topdir/media/player.swf",
11693: "$topdir/media/swfobject.js",
11694: "$topdir/media/expressInstall.swf");
1.1075.2.81 raeburn 11695: my @camtasia8_1 = ("$topdir/","$topdir/$topdir.html",
1.1075.2.59 raeburn 11696: "$topdir/$topdir.mp4",
11697: "$topdir/$topdir\_config.xml",
11698: "$topdir/$topdir\_controller.swf",
11699: "$topdir/$topdir\_embed.css",
11700: "$topdir/$topdir\_First_Frame.png",
11701: "$topdir/$topdir\_player.html",
11702: "$topdir/$topdir\_Thumbnails.png",
11703: "$topdir/playerProductInstall.swf",
11704: "$topdir/scripts/",
11705: "$topdir/scripts/config_xml.js",
11706: "$topdir/scripts/handlebars.js",
11707: "$topdir/scripts/jquery-1.7.1.min.js",
11708: "$topdir/scripts/jquery-ui-1.8.15.custom.min.js",
11709: "$topdir/scripts/modernizr.js",
11710: "$topdir/scripts/player-min.js",
11711: "$topdir/scripts/swfobject.js",
11712: "$topdir/skins/",
11713: "$topdir/skins/configuration_express.xml",
11714: "$topdir/skins/express_show/",
11715: "$topdir/skins/express_show/player-min.css",
11716: "$topdir/skins/express_show/spritesheet.png");
1.1075.2.81 raeburn 11717: my @camtasia8_4 = ("$topdir/","$topdir/$topdir.html",
11718: "$topdir/$topdir.mp4",
11719: "$topdir/$topdir\_config.xml",
11720: "$topdir/$topdir\_controller.swf",
11721: "$topdir/$topdir\_embed.css",
11722: "$topdir/$topdir\_First_Frame.png",
11723: "$topdir/$topdir\_player.html",
11724: "$topdir/$topdir\_Thumbnails.png",
11725: "$topdir/playerProductInstall.swf",
11726: "$topdir/scripts/",
11727: "$topdir/scripts/config_xml.js",
11728: "$topdir/scripts/techsmith-smart-player.min.js",
11729: "$topdir/skins/",
11730: "$topdir/skins/configuration_express.xml",
11731: "$topdir/skins/express_show/",
11732: "$topdir/skins/express_show/spritesheet.min.css",
11733: "$topdir/skins/express_show/spritesheet.png",
11734: "$topdir/skins/express_show/techsmith-smart-player.min.css");
1.1075.2.59 raeburn 11735: my @diffs = &compare_arrays(\@paths,\@camtasia6);
1.1067 raeburn 11736: if (@diffs == 0) {
1.1075.2.59 raeburn 11737: $is_camtasia = 6;
11738: } else {
1.1075.2.81 raeburn 11739: @diffs = &compare_arrays(\@paths,\@camtasia8_1);
1.1075.2.59 raeburn 11740: if (@diffs == 0) {
11741: $is_camtasia = 8;
1.1075.2.81 raeburn 11742: } else {
11743: @diffs = &compare_arrays(\@paths,\@camtasia8_4);
11744: if (@diffs == 0) {
11745: $is_camtasia = 8;
11746: }
1.1075.2.59 raeburn 11747: }
1.1067 raeburn 11748: }
11749: }
11750: my $output;
11751: if ($is_camtasia) {
11752: $output = <<"ENDCAM";
11753: <script type="text/javascript" language="Javascript">
11754: // <![CDATA[
11755:
11756: function camtasiaToggle() {
11757: for (var i=0; i<document.uploaded_decompress.autoextract_camtasia.length; i++) {
11758: if (document.uploaded_decompress.autoextract_camtasia[i].checked) {
1.1075.2.59 raeburn 11759: if (document.uploaded_decompress.autoextract_camtasia[i].value == $is_camtasia) {
1.1067 raeburn 11760: document.getElementById('camtasia_titles').style.display='block';
11761: } else {
11762: document.getElementById('camtasia_titles').style.display='none';
11763: }
11764: }
11765: }
11766: return;
11767: }
11768:
11769: // ]]>
11770: </script>
11771: <p>$lt{'camt'}</p>
11772: ENDCAM
1.1065 raeburn 11773: } else {
1.1067 raeburn 11774: $output = '<p>'.$lt{'this'};
11775: if ($info eq '') {
11776: $output .= ' '.$lt{'youm'}.'</p>'."\n";
11777: } else {
11778: $output .= ' '.$lt{'itsc'}.'</p>'."\n".
11779: '<div><pre>'.$info.'</pre></div>';
11780: }
1.1065 raeburn 11781: }
1.1067 raeburn 11782: $output .= '<form name="uploaded_decompress" action="'.$action.'" method="post">'."\n";
1.1065 raeburn 11783: my $duplicates;
11784: my $num = 0;
11785: if (ref($dirlist) eq 'ARRAY') {
11786: foreach my $item (@{$dirlist}) {
11787: if (ref($item) eq 'ARRAY') {
11788: if (exists($toplevel{$item->[0]})) {
11789: $duplicates .=
11790: &start_data_table_row().
11791: '<td><label><input type="radio" name="archive_overwrite_'.$num.'" '.
11792: 'value="0" checked="checked" />'.&mt('No').'</label>'.
11793: ' <label><input type="radio" name="archive_overwrite_'.$num.'" '.
11794: 'value="1" />'.&mt('Yes').'</label>'.
11795: '<input type="hidden" name="archive_overwrite_name_'.$num.'" value="'.$item->[0].'" /></td>'."\n".
11796: '<td>'.$item->[0].'</td>';
11797: if ($item->[2]) {
11798: $duplicates .= '<td>'.&mt('Directory').'</td>';
11799: } else {
11800: $duplicates .= '<td>'.&mt('File').'</td>';
11801: }
11802: $duplicates .= '<td>'.$item->[3].'</td>'.
11803: '<td>'.
11804: &Apache::lonlocal::locallocaltime($item->[4]).
11805: '</td>'.
11806: &end_data_table_row();
11807: $num ++;
11808: }
11809: }
11810: }
11811: }
11812: my $itemcount;
11813: if (@paths > 0) {
11814: $itemcount = scalar(@paths);
11815: } else {
11816: $itemcount = 1;
11817: }
1.1067 raeburn 11818: if ($is_camtasia) {
11819: $output .= $lt{'auto'}.'<br />'.
11820: '<span class="LC_nobreak">'.$lt{'proa'}.'<label>'.
1.1075.2.59 raeburn 11821: '<input type="radio" name="autoextract_camtasia" value="'.$is_camtasia.'" onclick="javascript:camtasiaToggle();" checked="checked" />'.
1.1067 raeburn 11822: $lt{'yes'}.'</label> <label>'.
11823: '<input type="radio" name="autoextract_camtasia" value="0" onclick="javascript:camtasiaToggle();" />'.
11824: $lt{'no'}.'</label></span><br />'.
11825: '<div id="camtasia_titles" style="display:block">'.
11826: &Apache::lonhtmlcommon::start_pick_box().
11827: &Apache::lonhtmlcommon::row_title($lt{'fold'}).
11828: '<input type="textbox" name="camtasia_foldername" value="'.$env{'form.comment'}.'" />'."\n".
11829: &Apache::lonhtmlcommon::row_closure().
11830: &Apache::lonhtmlcommon::row_title($lt{'movi'}).
11831: '<input type="textbox" name="camtasia_moviename" value="" />'."\n".
11832: &Apache::lonhtmlcommon::row_closure(1).
11833: &Apache::lonhtmlcommon::end_pick_box().
11834: '</div>';
11835: }
1.1065 raeburn 11836: $output .=
11837: '<input type="hidden" name="archive_overwrite_total" value="'.$num.'" />'.
1.1067 raeburn 11838: '<input type="hidden" name="archive_itemcount" value="'.$itemcount.'" />'.
11839: "\n";
1.1065 raeburn 11840: if ($duplicates ne '') {
11841: $output .= '<p><span class="LC_warning">'.
11842: &mt('Warning: decompression of the archive will overwrite the following items which already exist:').'</span><br />'.
11843: &start_data_table().
11844: &start_data_table_header_row().
11845: '<th>'.&mt('Overwrite?').'</th>'.
11846: '<th>'.&mt('Name').'</th>'.
11847: '<th>'.&mt('Type').'</th>'.
11848: '<th>'.&mt('Size').'</th>'.
11849: '<th>'.&mt('Last modified').'</th>'.
11850: &end_data_table_header_row().
11851: $duplicates.
11852: &end_data_table().
11853: '</p>';
11854: }
1.1067 raeburn 11855: $output .= '<input type="hidden" name="archiveurl" value="'.$archiveurl.'" />'."\n";
1.1053 raeburn 11856: if (ref($hiddenelements) eq 'HASH') {
11857: foreach my $hidden (sort(keys(%{$hiddenelements}))) {
11858: $output .= '<input type="hidden" name="'.$hidden.'" value="'.$hiddenelements->{$hidden}.'" />'."\n";
11859: }
11860: }
11861: $output .= <<"END";
1.1067 raeburn 11862: <br />
1.1053 raeburn 11863: <input type="submit" name="decompress" value="$lt{'extr'}" />
11864: </form>
11865: $noextract
11866: END
11867: return $output;
11868: }
11869:
1.1065 raeburn 11870: sub decompression_utility {
11871: my ($program) = @_;
11872: my @utilities = ('tar','gunzip','bunzip2','unzip');
11873: my $location;
11874: if (grep(/^\Q$program\E$/,@utilities)) {
11875: foreach my $dir ('/bin/','/usr/bin/','/usr/local/bin/','/sbin/',
11876: '/usr/sbin/') {
11877: if (-x $dir.$program) {
11878: $location = $dir.$program;
11879: last;
11880: }
11881: }
11882: }
11883: return $location;
11884: }
11885:
11886: sub list_archive_contents {
11887: my ($file,$pathsref) = @_;
11888: my (@cmd,$output);
11889: my $needsregexp;
11890: if ($file =~ /\.zip$/) {
11891: @cmd = (&decompression_utility('unzip'),"-l");
11892: $needsregexp = 1;
11893: } elsif (($file =~ m/\.tar\.gz$/) ||
11894: ($file =~ /\.tgz$/)) {
11895: @cmd = (&decompression_utility('tar'),"-ztf");
11896: } elsif ($file =~ /\.tar\.bz2$/) {
11897: @cmd = (&decompression_utility('tar'),"-jtf");
11898: } elsif ($file =~ m|\.tar$|) {
11899: @cmd = (&decompression_utility('tar'),"-tf");
11900: }
11901: if (@cmd) {
11902: undef($!);
11903: undef($@);
11904: if (open(my $fh,"-|", @cmd, $file)) {
11905: while (my $line = <$fh>) {
11906: $output .= $line;
11907: chomp($line);
11908: my $item;
11909: if ($needsregexp) {
11910: ($item) = ($line =~ /^\s*\d+\s+[\d\-]+\s+[\d:]+\s*(.+)$/);
11911: } else {
11912: $item = $line;
11913: }
11914: if ($item ne '') {
11915: unless (grep(/^\Q$item\E$/,@{$pathsref})) {
11916: push(@{$pathsref},$item);
11917: }
11918: }
11919: }
11920: close($fh);
11921: }
11922: }
11923: return $output;
11924: }
11925:
1.1053 raeburn 11926: sub decompress_uploaded_file {
11927: my ($file,$dir) = @_;
11928: &Apache::lonnet::appenv({'cgi.file' => $file});
11929: &Apache::lonnet::appenv({'cgi.dir' => $dir});
11930: my $result = &Apache::lonnet::ssi_body('/cgi-bin/decompress.pl');
11931: my ($handle) = ($env{'user.environment'} =~m{/([^/]+)\.id$});
11932: my $lonidsdir = $Apache::lonnet::perlvar{'lonIDsDir'};
11933: &Apache::lonnet::transfer_profile_to_env($lonidsdir,$handle,1);
11934: my $decompressed = $env{'cgi.decompressed'};
11935: &Apache::lonnet::delenv('cgi.file');
11936: &Apache::lonnet::delenv('cgi.dir');
11937: &Apache::lonnet::delenv('cgi.decompressed');
11938: return ($decompressed,$result);
11939: }
11940:
1.1055 raeburn 11941: sub process_decompression {
11942: my ($docudom,$docuname,$file,$destination,$dir_root,$hiddenelem) = @_;
11943: my ($dir,$error,$warning,$output);
1.1075.2.69 raeburn 11944: if ($file !~ /\.(zip|tar|bz2|gz|tar.gz|tar.bz2|tgz)$/i) {
1.1075.2.34 raeburn 11945: $error = &mt('Filename not a supported archive file type.').
11946: '<br />'.&mt('Filename should end with one of: [_1].',
1.1055 raeburn 11947: '.zip, .tar, .bz2, .gz, .tar.gz, .tar.bz2, .tgz');
11948: } else {
11949: my $docuhome = &Apache::lonnet::homeserver($docuname,$docudom);
11950: if ($docuhome eq 'no_host') {
11951: $error = &mt('Could not determine home server for course.');
11952: } else {
11953: my @ids=&Apache::lonnet::current_machine_ids();
11954: my $currdir = "$dir_root/$destination";
11955: if (grep(/^\Q$docuhome\E$/,@ids)) {
11956: $dir = &LONCAPA::propath($docudom,$docuname).
11957: "$dir_root/$destination";
11958: } else {
11959: $dir = $Apache::lonnet::perlvar{'lonDocRoot'}.
11960: "$dir_root/$docudom/$docuname/$destination";
11961: unless (&Apache::lonnet::repcopy_userfile("$dir/$file") eq 'ok') {
11962: $error = &mt('Archive file not found.');
11963: }
11964: }
1.1065 raeburn 11965: my (@to_overwrite,@to_skip);
11966: if ($env{'form.archive_overwrite_total'} > 0) {
11967: my $total = $env{'form.archive_overwrite_total'};
11968: for (my $i=0; $i<$total; $i++) {
11969: if ($env{'form.archive_overwrite_'.$i} == 1) {
11970: push(@to_overwrite,$env{'form.archive_overwrite_name_'.$i});
11971: } elsif ($env{'form.archive_overwrite_'.$i} == 0) {
11972: push(@to_skip,$env{'form.archive_overwrite_name_'.$i});
11973: }
11974: }
11975: }
11976: my $numskip = scalar(@to_skip);
11977: if (($numskip > 0) &&
11978: ($numskip == $env{'form.archive_itemcount'})) {
11979: $warning = &mt('All items in the archive file already exist, and no overwriting of existing files has been requested.');
11980: } elsif ($dir eq '') {
1.1055 raeburn 11981: $error = &mt('Directory containing archive file unavailable.');
11982: } elsif (!$error) {
1.1065 raeburn 11983: my ($decompressed,$display);
11984: if ($numskip > 0) {
11985: my $tempdir = time.'_'.$$.int(rand(10000));
11986: mkdir("$dir/$tempdir",0755);
11987: system("mv $dir/$file $dir/$tempdir/$file");
11988: ($decompressed,$display) =
11989: &decompress_uploaded_file($file,"$dir/$tempdir");
11990: foreach my $item (@to_skip) {
11991: if (($item ne '') && ($item !~ /\.\./)) {
11992: if (-f "$dir/$tempdir/$item") {
11993: unlink("$dir/$tempdir/$item");
11994: } elsif (-d "$dir/$tempdir/$item") {
11995: system("rm -rf $dir/$tempdir/$item");
11996: }
11997: }
11998: }
11999: system("mv $dir/$tempdir/* $dir");
12000: rmdir("$dir/$tempdir");
12001: } else {
12002: ($decompressed,$display) =
12003: &decompress_uploaded_file($file,$dir);
12004: }
1.1055 raeburn 12005: if ($decompressed eq 'ok') {
1.1065 raeburn 12006: $output = '<p class="LC_info">'.
12007: &mt('Files extracted successfully from archive.').
12008: '</p>'."\n";
1.1055 raeburn 12009: my ($warning,$result,@contents);
12010: my ($newdirlistref,$newlisterror) =
12011: &Apache::lonnet::dirlist($currdir,$docudom,
12012: $docuname,1);
12013: my (%is_dir,%changes,@newitems);
12014: my $dirptr = 16384;
1.1065 raeburn 12015: if (ref($newdirlistref) eq 'ARRAY') {
1.1055 raeburn 12016: foreach my $dir_line (@{$newdirlistref}) {
12017: my ($item,undef,undef,$testdir)=split(/\&/,$dir_line,5);
1.1065 raeburn 12018: unless (($item =~ /^\.+$/) || ($item eq $file) ||
12019: ((@to_skip > 0) && (grep(/^\Q$item\E$/,@to_skip)))) {
1.1055 raeburn 12020: push(@newitems,$item);
12021: if ($dirptr&$testdir) {
12022: $is_dir{$item} = 1;
12023: }
12024: $changes{$item} = 1;
12025: }
12026: }
12027: }
12028: if (keys(%changes) > 0) {
12029: foreach my $item (sort(@newitems)) {
12030: if ($changes{$item}) {
12031: push(@contents,$item);
12032: }
12033: }
12034: }
12035: if (@contents > 0) {
1.1067 raeburn 12036: my $wantform;
12037: unless ($env{'form.autoextract_camtasia'}) {
12038: $wantform = 1;
12039: }
1.1056 raeburn 12040: my (%children,%parent,%dirorder,%titles);
1.1055 raeburn 12041: my ($count,$datatable) = &get_extracted($docudom,$docuname,
12042: $currdir,\%is_dir,
12043: \%children,\%parent,
1.1056 raeburn 12044: \@contents,\%dirorder,
12045: \%titles,$wantform);
1.1055 raeburn 12046: if ($datatable ne '') {
12047: $output .= &archive_options_form('decompressed',$datatable,
12048: $count,$hiddenelem);
1.1065 raeburn 12049: my $startcount = 6;
1.1055 raeburn 12050: $output .= &archive_javascript($startcount,$count,
1.1056 raeburn 12051: \%titles,\%children);
1.1055 raeburn 12052: }
1.1067 raeburn 12053: if ($env{'form.autoextract_camtasia'}) {
1.1075.2.59 raeburn 12054: my $version = $env{'form.autoextract_camtasia'};
1.1067 raeburn 12055: my %displayed;
12056: my $total = 1;
12057: $env{'form.archive_directory'} = [];
12058: foreach my $i (sort { $a <=> $b } keys(%dirorder)) {
12059: my $path = join('/',map { $titles{$_}; } @{$dirorder{$i}});
12060: $path =~ s{/$}{};
12061: my $item;
12062: if ($path ne '') {
12063: $item = "$path/$titles{$i}";
12064: } else {
12065: $item = $titles{$i};
12066: }
12067: $env{'form.archive_content_'.$i} = "$dir_root/$destination/$item";
12068: if ($item eq $contents[0]) {
12069: push(@{$env{'form.archive_directory'}},$i);
12070: $env{'form.archive_'.$i} = 'display';
12071: $env{'form.archive_title_'.$i} = $env{'form.camtasia_foldername'};
12072: $displayed{'folder'} = $i;
1.1075.2.59 raeburn 12073: } elsif ((($item eq "$contents[0]/index.html") && ($version == 6)) ||
12074: (($item eq "$contents[0]/$contents[0]".'.html') && ($version == 8))) {
1.1067 raeburn 12075: $env{'form.archive_'.$i} = 'display';
12076: $env{'form.archive_title_'.$i} = $env{'form.camtasia_moviename'};
12077: $displayed{'web'} = $i;
12078: } else {
1.1075.2.59 raeburn 12079: if ((($item eq "$contents[0]/media") && ($version == 6)) ||
12080: ((($item eq "$contents[0]/scripts") || ($item eq "$contents[0]/skins") ||
12081: ($item eq "$contents[0]/skins/express_show")) && ($version == 8))) {
1.1067 raeburn 12082: push(@{$env{'form.archive_directory'}},$i);
12083: }
12084: $env{'form.archive_'.$i} = 'dependency';
12085: }
12086: $total ++;
12087: }
12088: for (my $i=1; $i<$total; $i++) {
12089: next if ($i == $displayed{'web'});
12090: next if ($i == $displayed{'folder'});
12091: $env{'form.archive_dependent_on_'.$i} = $displayed{'web'};
12092: }
12093: $env{'form.phase'} = 'decompress_cleanup';
12094: $env{'form.archivedelete'} = 1;
12095: $env{'form.archive_count'} = $total-1;
12096: $output .=
12097: &process_extracted_files('coursedocs',$docudom,
12098: $docuname,$destination,
12099: $dir_root,$hiddenelem);
12100: }
1.1055 raeburn 12101: } else {
12102: $warning = &mt('No new items extracted from archive file.');
12103: }
12104: } else {
12105: $output = $display;
12106: $error = &mt('An error occurred during extraction from the archive file.');
12107: }
12108: }
12109: }
12110: }
12111: if ($error) {
12112: $output .= '<p class="LC_error">'.&mt('Not extracted.').'<br />'.
12113: $error.'</p>'."\n";
12114: }
12115: if ($warning) {
12116: $output .= '<p class="LC_warning">'.$warning.'</p>'."\n";
12117: }
12118: return $output;
12119: }
12120:
12121: sub get_extracted {
1.1056 raeburn 12122: my ($docudom,$docuname,$currdir,$is_dir,$children,$parent,$contents,$dirorder,
12123: $titles,$wantform) = @_;
1.1055 raeburn 12124: my $count = 0;
12125: my $depth = 0;
12126: my $datatable;
1.1056 raeburn 12127: my @hierarchy;
1.1055 raeburn 12128: return unless ((ref($is_dir) eq 'HASH') && (ref($children) eq 'HASH') &&
1.1056 raeburn 12129: (ref($parent) eq 'HASH') && (ref($contents) eq 'ARRAY') &&
12130: (ref($dirorder) eq 'HASH') && (ref($titles) eq 'HASH'));
1.1055 raeburn 12131: foreach my $item (@{$contents}) {
12132: $count ++;
1.1056 raeburn 12133: @{$dirorder->{$count}} = @hierarchy;
12134: $titles->{$count} = $item;
1.1055 raeburn 12135: &archive_hierarchy($depth,$count,$parent,$children);
12136: if ($wantform) {
12137: $datatable .= &archive_row($is_dir->{$item},$item,
12138: $currdir,$depth,$count);
12139: }
12140: if ($is_dir->{$item}) {
12141: $depth ++;
1.1056 raeburn 12142: push(@hierarchy,$count);
12143: $parent->{$depth} = $count;
1.1055 raeburn 12144: $datatable .=
12145: &recurse_extracted_archive("$currdir/$item",$docudom,$docuname,
1.1056 raeburn 12146: \$depth,\$count,\@hierarchy,$dirorder,
12147: $children,$parent,$titles,$wantform);
1.1055 raeburn 12148: $depth --;
1.1056 raeburn 12149: pop(@hierarchy);
1.1055 raeburn 12150: }
12151: }
12152: return ($count,$datatable);
12153: }
12154:
12155: sub recurse_extracted_archive {
1.1056 raeburn 12156: my ($currdir,$docudom,$docuname,$depth,$count,$hierarchy,$dirorder,
12157: $children,$parent,$titles,$wantform) = @_;
1.1055 raeburn 12158: my $result='';
1.1056 raeburn 12159: unless ((ref($depth)) && (ref($count)) && (ref($hierarchy) eq 'ARRAY') &&
12160: (ref($children) eq 'HASH') && (ref($parent) eq 'HASH') &&
12161: (ref($dirorder) eq 'HASH')) {
1.1055 raeburn 12162: return $result;
12163: }
12164: my $dirptr = 16384;
12165: my ($newdirlistref,$newlisterror) =
12166: &Apache::lonnet::dirlist($currdir,$docudom,$docuname,1);
12167: if (ref($newdirlistref) eq 'ARRAY') {
12168: foreach my $dir_line (@{$newdirlistref}) {
12169: my ($item,undef,undef,$testdir)=split(/\&/,$dir_line,5);
12170: unless ($item =~ /^\.+$/) {
12171: $$count ++;
1.1056 raeburn 12172: @{$dirorder->{$$count}} = @{$hierarchy};
12173: $titles->{$$count} = $item;
1.1055 raeburn 12174: &archive_hierarchy($$depth,$$count,$parent,$children);
1.1056 raeburn 12175:
1.1055 raeburn 12176: my $is_dir;
12177: if ($dirptr&$testdir) {
12178: $is_dir = 1;
12179: }
12180: if ($wantform) {
12181: $result .= &archive_row($is_dir,$item,$currdir,$$depth,$$count);
12182: }
12183: if ($is_dir) {
12184: $$depth ++;
1.1056 raeburn 12185: push(@{$hierarchy},$$count);
12186: $parent->{$$depth} = $$count;
1.1055 raeburn 12187: $result .=
12188: &recurse_extracted_archive("$currdir/$item",$docudom,
12189: $docuname,$depth,$count,
1.1056 raeburn 12190: $hierarchy,$dirorder,$children,
12191: $parent,$titles,$wantform);
1.1055 raeburn 12192: $$depth --;
1.1056 raeburn 12193: pop(@{$hierarchy});
1.1055 raeburn 12194: }
12195: }
12196: }
12197: }
12198: return $result;
12199: }
12200:
12201: sub archive_hierarchy {
12202: my ($depth,$count,$parent,$children) =@_;
12203: if ((ref($parent) eq 'HASH') && (ref($children) eq 'HASH')) {
12204: if (exists($parent->{$depth})) {
12205: $children->{$parent->{$depth}} .= $count.':';
12206: }
12207: }
12208: return;
12209: }
12210:
12211: sub archive_row {
12212: my ($is_dir,$item,$currdir,$depth,$count) = @_;
12213: my ($name) = ($item =~ m{([^/]+)$});
12214: my %choices = &Apache::lonlocal::texthash (
1.1059 raeburn 12215: 'display' => 'Add as file',
1.1055 raeburn 12216: 'dependency' => 'Include as dependency',
12217: 'discard' => 'Discard',
12218: );
12219: if ($is_dir) {
1.1059 raeburn 12220: $choices{'display'} = &mt('Add as folder');
1.1055 raeburn 12221: }
1.1056 raeburn 12222: my $output = &start_data_table_row().'<td align="right">'.$count.'</td>'."\n";
12223: my $offset = 0;
1.1055 raeburn 12224: foreach my $action ('display','dependency','discard') {
1.1056 raeburn 12225: $offset ++;
1.1065 raeburn 12226: if ($action ne 'display') {
12227: $offset ++;
12228: }
1.1055 raeburn 12229: $output .= '<td><span class="LC_nobreak">'.
12230: '<label><input type="radio" name="archive_'.$count.
12231: '" id="archive_'.$action.'_'.$count.'" value="'.$action.'"';
12232: my $text = $choices{$action};
12233: if ($is_dir) {
12234: $output .= ' onclick="javascript:propagateCheck(this.form,'."'$count'".');"';
12235: if ($action eq 'display') {
1.1059 raeburn 12236: $text = &mt('Add as folder');
1.1055 raeburn 12237: }
1.1056 raeburn 12238: } else {
12239: $output .= ' onclick="javascript:dependencyCheck(this.form,'."$count,$offset".');"';
12240:
12241: }
12242: $output .= ' /> '.$choices{$action}.'</label></span>';
12243: if ($action eq 'dependency') {
12244: $output .= '<div id="arc_depon_'.$count.'" style="display:none;">'."\n".
12245: &mt('Used by:').' <select name="archive_dependent_on_'.$count.'" '.
12246: 'onchange="propagateSelect(this.form,'."$count,$offset".')">'."\n".
12247: '<option value=""></option>'."\n".
12248: '</select>'."\n".
12249: '</div>';
1.1059 raeburn 12250: } elsif ($action eq 'display') {
12251: $output .= '<div id="arc_title_'.$count.'" style="display:none;">'."\n".
12252: &mt('Title:').' <input type="text" name="archive_title_'.$count.'" id="archive_title_'.$count.'" />'."\n".
12253: '</div>';
1.1055 raeburn 12254: }
1.1056 raeburn 12255: $output .= '</td>';
1.1055 raeburn 12256: }
12257: $output .= '<td><input type="hidden" name="archive_content_'.$count.'" value="'.
12258: &HTML::Entities::encode("$currdir/$item",'"<>&').'" />'.(' ' x 2);
12259: for (my $i=0; $i<$depth; $i++) {
12260: $output .= ('<img src="/adm/lonIcons/whitespace1.gif" class="LC_docs_spacer" alt="" />' x2)."\n";
12261: }
12262: if ($is_dir) {
12263: $output .= '<img src="/adm/lonIcons/navmap.folder.open.gif" alt="" /> '."\n".
12264: '<input type="hidden" name="archive_directory" value="'.$count.'" />'."\n";
12265: } else {
12266: $output .= '<input type="hidden" name="archive_file" value="'.$count.'" />'."\n";
12267: }
12268: $output .= ' '.$name.'</td>'."\n".
12269: &end_data_table_row();
12270: return $output;
12271: }
12272:
12273: sub archive_options_form {
1.1065 raeburn 12274: my ($form,$display,$count,$hiddenelem) = @_;
12275: my %lt = &Apache::lonlocal::texthash(
12276: perm => 'Permanently remove archive file?',
12277: hows => 'How should each extracted item be incorporated in the course?',
12278: cont => 'Content actions for all',
12279: addf => 'Add as folder/file',
12280: incd => 'Include as dependency for a displayed file',
12281: disc => 'Discard',
12282: no => 'No',
12283: yes => 'Yes',
12284: save => 'Save',
12285: );
12286: my $output = <<"END";
12287: <form name="$form" method="post" action="">
12288: <p><span class="LC_nobreak">$lt{'perm'}
12289: <label>
12290: <input type="radio" name="archivedelete" value="0" checked="checked" />$lt{'no'}
12291: </label>
12292:
12293: <label>
12294: <input type="radio" name="archivedelete" value="1" />$lt{'yes'}</label>
12295: </span>
12296: </p>
12297: <input type="hidden" name="phase" value="decompress_cleanup" />
12298: <br />$lt{'hows'}
12299: <div class="LC_columnSection">
12300: <fieldset>
12301: <legend>$lt{'cont'}</legend>
12302: <input type="button" value="$lt{'addf'}" onclick="javascript:checkAll(document.$form,'display');" />
12303: <input type="button" value="$lt{'incd'}" onclick="javascript:checkAll(document.$form,'dependency');" />
12304: <input type="button" value="$lt{'disc'}" onclick="javascript:checkAll(document.$form,'discard');" />
12305: </fieldset>
12306: </div>
12307: END
12308: return $output.
1.1055 raeburn 12309: &start_data_table()."\n".
1.1065 raeburn 12310: $display."\n".
1.1055 raeburn 12311: &end_data_table()."\n".
12312: '<input type="hidden" name="archive_count" value="'.$count.'" />'.
12313: $hiddenelem.
1.1065 raeburn 12314: '<br /><input type="submit" name="archive_submit" value="'.$lt{'save'}.'" />'.
1.1055 raeburn 12315: '</form>';
12316: }
12317:
12318: sub archive_javascript {
1.1056 raeburn 12319: my ($startcount,$numitems,$titles,$children) = @_;
12320: return unless ((ref($titles) eq 'HASH') && (ref($children) eq 'HASH'));
1.1059 raeburn 12321: my $maintitle = $env{'form.comment'};
1.1055 raeburn 12322: my $scripttag = <<START;
12323: <script type="text/javascript">
12324: // <![CDATA[
12325:
12326: function checkAll(form,prefix) {
12327: var idstr = new RegExp("^archive_"+prefix+"_\\\\d+\$");
12328: for (var i=0; i < form.elements.length; i++) {
12329: var id = form.elements[i].id;
12330: if ((id != '') && (id != undefined)) {
12331: if (idstr.test(id)) {
12332: if (form.elements[i].type == 'radio') {
12333: form.elements[i].checked = true;
1.1056 raeburn 12334: var nostart = i-$startcount;
1.1059 raeburn 12335: var offset = nostart%7;
12336: var count = (nostart-offset)/7;
1.1056 raeburn 12337: dependencyCheck(form,count,offset);
1.1055 raeburn 12338: }
12339: }
12340: }
12341: }
12342: }
12343:
12344: function propagateCheck(form,count) {
12345: if (count > 0) {
1.1059 raeburn 12346: var startelement = $startcount + ((count-1) * 7);
12347: for (var j=1; j<6; j++) {
12348: if ((j != 2) && (j != 4)) {
1.1056 raeburn 12349: var item = startelement + j;
12350: if (form.elements[item].type == 'radio') {
12351: if (form.elements[item].checked) {
12352: containerCheck(form,count,j);
12353: break;
12354: }
1.1055 raeburn 12355: }
12356: }
12357: }
12358: }
12359: }
12360:
12361: numitems = $numitems
1.1056 raeburn 12362: var titles = new Array(numitems);
12363: var parents = new Array(numitems);
1.1055 raeburn 12364: for (var i=0; i<numitems; i++) {
1.1056 raeburn 12365: parents[i] = new Array;
1.1055 raeburn 12366: }
1.1059 raeburn 12367: var maintitle = '$maintitle';
1.1055 raeburn 12368:
12369: START
12370:
1.1056 raeburn 12371: foreach my $container (sort { $a <=> $b } (keys(%{$children}))) {
12372: my @contents = split(/:/,$children->{$container});
1.1055 raeburn 12373: for (my $i=0; $i<@contents; $i ++) {
12374: $scripttag .= 'parents['.$container.']['.$i.'] = '.$contents[$i]."\n";
12375: }
12376: }
12377:
1.1056 raeburn 12378: foreach my $key (sort { $a <=> $b } (keys(%{$titles}))) {
12379: $scripttag .= "titles[$key] = '".$titles->{$key}."';\n";
12380: }
12381:
1.1055 raeburn 12382: $scripttag .= <<END;
12383:
12384: function containerCheck(form,count,offset) {
12385: if (count > 0) {
1.1056 raeburn 12386: dependencyCheck(form,count,offset);
1.1059 raeburn 12387: var item = (offset+$startcount)+7*(count-1);
1.1055 raeburn 12388: form.elements[item].checked = true;
12389: if(Object.prototype.toString.call(parents[count]) === '[object Array]') {
12390: if (parents[count].length > 0) {
12391: for (var j=0; j<parents[count].length; j++) {
1.1056 raeburn 12392: containerCheck(form,parents[count][j],offset);
12393: }
12394: }
12395: }
12396: }
12397: }
12398:
12399: function dependencyCheck(form,count,offset) {
12400: if (count > 0) {
1.1059 raeburn 12401: var chosen = (offset+$startcount)+7*(count-1);
12402: var depitem = $startcount + ((count-1) * 7) + 4;
1.1056 raeburn 12403: var currtype = form.elements[depitem].type;
12404: if (form.elements[chosen].value == 'dependency') {
12405: document.getElementById('arc_depon_'+count).style.display='block';
12406: form.elements[depitem].options.length = 0;
12407: form.elements[depitem].options[0] = new Option('Select','',true,true);
1.1075.2.11 raeburn 12408: for (var i=1; i<=numitems; i++) {
12409: if (i == count) {
12410: continue;
12411: }
1.1059 raeburn 12412: var startelement = $startcount + (i-1) * 7;
12413: for (var j=1; j<6; j++) {
12414: if ((j != 2) && (j!= 4)) {
1.1056 raeburn 12415: var item = startelement + j;
12416: if (form.elements[item].type == 'radio') {
12417: if (form.elements[item].checked) {
12418: if (form.elements[item].value == 'display') {
12419: var n = form.elements[depitem].options.length;
12420: form.elements[depitem].options[n] = new Option(titles[i],i,false,false);
12421: }
12422: }
12423: }
12424: }
12425: }
12426: }
12427: } else {
12428: document.getElementById('arc_depon_'+count).style.display='none';
12429: form.elements[depitem].options.length = 0;
12430: form.elements[depitem].options[0] = new Option('Select','',true,true);
12431: }
1.1059 raeburn 12432: titleCheck(form,count,offset);
1.1056 raeburn 12433: }
12434: }
12435:
12436: function propagateSelect(form,count,offset) {
12437: if (count > 0) {
1.1065 raeburn 12438: var item = (1+offset+$startcount)+7*(count-1);
1.1056 raeburn 12439: var picked = form.elements[item].options[form.elements[item].selectedIndex].value;
12440: if (Object.prototype.toString.call(parents[count]) === '[object Array]') {
12441: if (parents[count].length > 0) {
12442: for (var j=0; j<parents[count].length; j++) {
12443: containerSelect(form,parents[count][j],offset,picked);
1.1055 raeburn 12444: }
12445: }
12446: }
12447: }
12448: }
1.1056 raeburn 12449:
12450: function containerSelect(form,count,offset,picked) {
12451: if (count > 0) {
1.1065 raeburn 12452: var item = (offset+$startcount)+7*(count-1);
1.1056 raeburn 12453: if (form.elements[item].type == 'radio') {
12454: if (form.elements[item].value == 'dependency') {
12455: if (form.elements[item+1].type == 'select-one') {
12456: for (var i=0; i<form.elements[item+1].options.length; i++) {
12457: if (form.elements[item+1].options[i].value == picked) {
12458: form.elements[item+1].selectedIndex = i;
12459: break;
12460: }
12461: }
12462: }
12463: if (Object.prototype.toString.call(parents[count]) === '[object Array]') {
12464: if (parents[count].length > 0) {
12465: for (var j=0; j<parents[count].length; j++) {
12466: containerSelect(form,parents[count][j],offset,picked);
12467: }
12468: }
12469: }
12470: }
12471: }
12472: }
12473: }
12474:
1.1059 raeburn 12475: function titleCheck(form,count,offset) {
12476: if (count > 0) {
12477: var chosen = (offset+$startcount)+7*(count-1);
12478: var depitem = $startcount + ((count-1) * 7) + 2;
12479: var currtype = form.elements[depitem].type;
12480: if (form.elements[chosen].value == 'display') {
12481: document.getElementById('arc_title_'+count).style.display='block';
12482: if ((count==1) && ((parents[count].length > 0) || (numitems == 1))) {
12483: document.getElementById('archive_title_'+count).value=maintitle;
12484: }
12485: } else {
12486: document.getElementById('arc_title_'+count).style.display='none';
12487: if (currtype == 'text') {
12488: document.getElementById('archive_title_'+count).value='';
12489: }
12490: }
12491: }
12492: return;
12493: }
12494:
1.1055 raeburn 12495: // ]]>
12496: </script>
12497: END
12498: return $scripttag;
12499: }
12500:
12501: sub process_extracted_files {
1.1067 raeburn 12502: my ($context,$docudom,$docuname,$destination,$dir_root,$hiddenelem) = @_;
1.1055 raeburn 12503: my $numitems = $env{'form.archive_count'};
12504: return unless ($numitems);
12505: my @ids=&Apache::lonnet::current_machine_ids();
12506: my ($prefix,$pathtocheck,$dir,$ishome,$error,$warning,%toplevelitems,%is_dir,
1.1067 raeburn 12507: %folders,%containers,%mapinner,%prompttofetch);
1.1055 raeburn 12508: my $docuhome = &Apache::lonnet::homeserver($docuname,$docudom);
12509: if (grep(/^\Q$docuhome\E$/,@ids)) {
12510: $prefix = &LONCAPA::propath($docudom,$docuname);
12511: $pathtocheck = "$dir_root/$destination";
12512: $dir = $dir_root;
12513: $ishome = 1;
12514: } else {
12515: $prefix = $Apache::lonnet::perlvar{'lonDocRoot'};
12516: $pathtocheck = "$dir_root/$docudom/$docuname/$destination";
12517: $dir = "$dir_root/$docudom/$docuname";
12518: }
12519: my $currdir = "$dir_root/$destination";
12520: (my $docstype,$mapinner{'0'}) = ($destination =~ m{^(docs|supplemental)/(\w+)/});
12521: if ($env{'form.folderpath'}) {
12522: my @items = split('&',$env{'form.folderpath'});
12523: $folders{'0'} = $items[-2];
1.1075.2.17 raeburn 12524: if ($env{'form.folderpath'} =~ /\:1$/) {
12525: $containers{'0'}='page';
12526: } else {
12527: $containers{'0'}='sequence';
12528: }
1.1055 raeburn 12529: }
12530: my @archdirs = &get_env_multiple('form.archive_directory');
12531: if ($numitems) {
12532: for (my $i=1; $i<=$numitems; $i++) {
12533: my $path = $env{'form.archive_content_'.$i};
12534: if ($path =~ m{^\Q$pathtocheck\E/([^/]+)$}) {
12535: my $item = $1;
12536: $toplevelitems{$item} = $i;
12537: if (grep(/^\Q$i\E$/,@archdirs)) {
12538: $is_dir{$item} = 1;
12539: }
12540: }
12541: }
12542: }
1.1067 raeburn 12543: my ($output,%children,%parent,%titles,%dirorder,$result);
1.1055 raeburn 12544: if (keys(%toplevelitems) > 0) {
12545: my @contents = sort(keys(%toplevelitems));
1.1056 raeburn 12546: (my $count,undef) = &get_extracted($docudom,$docuname,$currdir,\%is_dir,\%children,
12547: \%parent,\@contents,\%dirorder,\%titles);
1.1055 raeburn 12548: }
1.1066 raeburn 12549: my (%referrer,%orphaned,%todelete,%todeletedir,%newdest,%newseqid);
1.1055 raeburn 12550: if ($numitems) {
12551: for (my $i=1; $i<=$numitems; $i++) {
1.1075.2.11 raeburn 12552: next if ($env{'form.archive_'.$i} eq 'dependency');
1.1055 raeburn 12553: my $path = $env{'form.archive_content_'.$i};
12554: if ($path =~ /^\Q$pathtocheck\E/) {
12555: if ($env{'form.archive_'.$i} eq 'discard') {
12556: if ($prefix ne '' && $path ne '') {
12557: if (-e $prefix.$path) {
1.1066 raeburn 12558: if ((@archdirs > 0) &&
12559: (grep(/^\Q$i\E$/,@archdirs))) {
12560: $todeletedir{$prefix.$path} = 1;
12561: } else {
12562: $todelete{$prefix.$path} = 1;
12563: }
1.1055 raeburn 12564: }
12565: }
12566: } elsif ($env{'form.archive_'.$i} eq 'display') {
1.1059 raeburn 12567: my ($docstitle,$title,$url,$outer);
1.1055 raeburn 12568: ($title) = ($path =~ m{/([^/]+)$});
1.1059 raeburn 12569: $docstitle = $env{'form.archive_title_'.$i};
12570: if ($docstitle eq '') {
12571: $docstitle = $title;
12572: }
1.1055 raeburn 12573: $outer = 0;
1.1056 raeburn 12574: if (ref($dirorder{$i}) eq 'ARRAY') {
12575: if (@{$dirorder{$i}} > 0) {
12576: foreach my $item (reverse(@{$dirorder{$i}})) {
1.1055 raeburn 12577: if ($env{'form.archive_'.$item} eq 'display') {
12578: $outer = $item;
12579: last;
12580: }
12581: }
12582: }
12583: }
12584: my ($errtext,$fatal) =
12585: &LONCAPA::map::mapread('/uploaded/'.$docudom.'/'.$docuname.
12586: '/'.$folders{$outer}.'.'.
12587: $containers{$outer});
12588: next if ($fatal);
12589: if ((@archdirs > 0) && (grep(/^\Q$i\E$/,@archdirs))) {
12590: if ($context eq 'coursedocs') {
1.1056 raeburn 12591: $mapinner{$i} = time;
1.1055 raeburn 12592: $folders{$i} = 'default_'.$mapinner{$i};
12593: $containers{$i} = 'sequence';
12594: my $url = '/uploaded/'.$docudom.'/'.$docuname.'/'.
12595: $folders{$i}.'.'.$containers{$i};
12596: my $newidx = &LONCAPA::map::getresidx();
12597: $LONCAPA::map::resources[$newidx]=
1.1059 raeburn 12598: $docstitle.':'.$url.':false:normal:res';
1.1055 raeburn 12599: push(@LONCAPA::map::order,$newidx);
12600: my ($outtext,$errtext) =
12601: &LONCAPA::map::storemap('/uploaded/'.$docudom.'/'.
12602: $docuname.'/'.$folders{$outer}.
1.1075.2.11 raeburn 12603: '.'.$containers{$outer},1,1);
1.1056 raeburn 12604: $newseqid{$i} = $newidx;
1.1067 raeburn 12605: unless ($errtext) {
12606: $result .= '<li>'.&mt('Folder: [_1] added to course',$docstitle).'</li>'."\n";
12607: }
1.1055 raeburn 12608: }
12609: } else {
12610: if ($context eq 'coursedocs') {
12611: my $newidx=&LONCAPA::map::getresidx();
12612: my $url = '/uploaded/'.$docudom.'/'.$docuname.'/'.
12613: $docstype.'/'.$mapinner{$outer}.'/'.$newidx.'/'.
12614: $title;
12615: if (!-e "$prefix$dir/$docstype/$mapinner{$outer}") {
12616: mkdir("$prefix$dir/$docstype/$mapinner{$outer}",0755);
12617: }
12618: if (!-e "$prefix$dir/$docstype/$mapinner{$outer}/$newidx") {
12619: mkdir("$prefix$dir/$docstype/$mapinner{$outer}/$newidx");
12620: }
12621: if (-e "$prefix$dir/$docstype/$mapinner{$outer}/$newidx") {
12622: system("mv $prefix$path $prefix$dir/$docstype/$mapinner{$outer}/$newidx/$title");
1.1056 raeburn 12623: $newdest{$i} = "$prefix$dir/$docstype/$mapinner{$outer}/$newidx";
1.1067 raeburn 12624: unless ($ishome) {
12625: my $fetch = "$newdest{$i}/$title";
12626: $fetch =~ s/^\Q$prefix$dir\E//;
12627: $prompttofetch{$fetch} = 1;
12628: }
1.1055 raeburn 12629: }
12630: $LONCAPA::map::resources[$newidx]=
1.1059 raeburn 12631: $docstitle.':'.$url.':false:normal:res';
1.1055 raeburn 12632: push(@LONCAPA::map::order, $newidx);
12633: my ($outtext,$errtext)=
12634: &LONCAPA::map::storemap('/uploaded/'.$docudom.'/'.
12635: $docuname.'/'.$folders{$outer}.
1.1075.2.11 raeburn 12636: '.'.$containers{$outer},1,1);
1.1067 raeburn 12637: unless ($errtext) {
12638: if (-e "$prefix$dir/$docstype/$mapinner{$outer}/$newidx/$title") {
12639: $result .= '<li>'.&mt('File: [_1] added to course',$docstitle).'</li>'."\n";
12640: }
12641: }
1.1055 raeburn 12642: }
12643: }
1.1075.2.11 raeburn 12644: }
12645: } else {
12646: $warning .= &mt('Item extracted from archive: [_1] has unexpected path.',$path).'<br />';
12647: }
12648: }
12649: for (my $i=1; $i<=$numitems; $i++) {
12650: next unless ($env{'form.archive_'.$i} eq 'dependency');
12651: my $path = $env{'form.archive_content_'.$i};
12652: if ($path =~ /^\Q$pathtocheck\E/) {
12653: my ($title) = ($path =~ m{/([^/]+)$});
12654: $referrer{$i} = $env{'form.archive_dependent_on_'.$i};
12655: if ($env{'form.archive_'.$referrer{$i}} eq 'display') {
12656: if (ref($dirorder{$i}) eq 'ARRAY') {
12657: my ($itemidx,$fullpath,$relpath);
12658: if (ref($dirorder{$referrer{$i}}) eq 'ARRAY') {
12659: my $container = $dirorder{$referrer{$i}}->[-1];
1.1056 raeburn 12660: for (my $j=0; $j<@{$dirorder{$i}}; $j++) {
1.1075.2.11 raeburn 12661: if ($dirorder{$i}->[$j] eq $container) {
12662: $itemidx = $j;
1.1056 raeburn 12663: }
12664: }
1.1075.2.11 raeburn 12665: }
12666: if ($itemidx eq '') {
12667: $itemidx = 0;
12668: }
12669: if (grep(/^\Q$referrer{$i}\E$/,@archdirs)) {
12670: if ($mapinner{$referrer{$i}}) {
12671: $fullpath = "$prefix$dir/$docstype/$mapinner{$referrer{$i}}";
12672: for (my $j=$itemidx; $j<@{$dirorder{$i}}; $j++) {
12673: if (grep(/^\Q$dirorder{$i}->[$j]\E$/,@archdirs)) {
12674: unless (defined($newseqid{$dirorder{$i}->[$j]})) {
12675: $fullpath .= '/'.$titles{$dirorder{$i}->[$j]};
12676: $relpath .= '/'.$titles{$dirorder{$i}->[$j]};
12677: if (!-e $fullpath) {
12678: mkdir($fullpath,0755);
1.1056 raeburn 12679: }
12680: }
1.1075.2.11 raeburn 12681: } else {
12682: last;
1.1056 raeburn 12683: }
1.1075.2.11 raeburn 12684: }
12685: }
12686: } elsif ($newdest{$referrer{$i}}) {
12687: $fullpath = $newdest{$referrer{$i}};
12688: for (my $j=$itemidx; $j<@{$dirorder{$i}}; $j++) {
12689: if ($env{'form.archive_'.$dirorder{$i}->[$j]} eq 'discard') {
12690: $orphaned{$i} = $env{'form.archive_'.$dirorder{$i}->[$j]};
12691: last;
12692: } elsif (grep(/^\Q$dirorder{$i}->[$j]\E$/,@archdirs)) {
12693: unless (defined($newseqid{$dirorder{$i}->[$j]})) {
12694: $fullpath .= '/'.$titles{$dirorder{$i}->[$j]};
12695: $relpath .= '/'.$titles{$dirorder{$i}->[$j]};
12696: if (!-e $fullpath) {
12697: mkdir($fullpath,0755);
1.1056 raeburn 12698: }
12699: }
1.1075.2.11 raeburn 12700: } else {
12701: last;
1.1056 raeburn 12702: }
1.1075.2.11 raeburn 12703: }
12704: }
12705: if ($fullpath ne '') {
12706: if (-e "$prefix$path") {
12707: system("mv $prefix$path $fullpath/$title");
12708: }
12709: if (-e "$fullpath/$title") {
12710: my $showpath;
12711: if ($relpath ne '') {
12712: $showpath = "$relpath/$title";
12713: } else {
12714: $showpath = "/$title";
1.1056 raeburn 12715: }
1.1075.2.11 raeburn 12716: $result .= '<li>'.&mt('[_1] included as a dependency',$showpath).'</li>'."\n";
12717: }
12718: unless ($ishome) {
12719: my $fetch = "$fullpath/$title";
12720: $fetch =~ s/^\Q$prefix$dir\E//;
12721: $prompttofetch{$fetch} = 1;
1.1055 raeburn 12722: }
12723: }
12724: }
1.1075.2.11 raeburn 12725: } elsif ($env{'form.archive_'.$referrer{$i}} eq 'discard') {
12726: $warning .= &mt('[_1] is a dependency of [_2], which was discarded.',
12727: $path,$env{'form.archive_content_'.$referrer{$i}}).'<br />';
1.1055 raeburn 12728: }
12729: } else {
1.1075.2.11 raeburn 12730: $warning .= &mt('Item extracted from archive: [_1] has unexpected path.',$path).'<br />';
1.1055 raeburn 12731: }
12732: }
12733: if (keys(%todelete)) {
12734: foreach my $key (keys(%todelete)) {
12735: unlink($key);
1.1066 raeburn 12736: }
12737: }
12738: if (keys(%todeletedir)) {
12739: foreach my $key (keys(%todeletedir)) {
12740: rmdir($key);
12741: }
12742: }
12743: foreach my $dir (sort(keys(%is_dir))) {
12744: if (($pathtocheck ne '') && ($dir ne '')) {
12745: &cleanup_empty_dirs($prefix."$pathtocheck/$dir");
1.1055 raeburn 12746: }
12747: }
1.1067 raeburn 12748: if ($result ne '') {
12749: $output .= '<ul>'."\n".
12750: $result."\n".
12751: '</ul>';
12752: }
12753: unless ($ishome) {
12754: my $replicationfail;
12755: foreach my $item (keys(%prompttofetch)) {
12756: my $fetchresult= &Apache::lonnet::reply('fetchuserfile:'.$item,$docuhome);
12757: unless ($fetchresult eq 'ok') {
12758: $replicationfail .= '<li>'.$item.'</li>'."\n";
12759: }
12760: }
12761: if ($replicationfail) {
12762: $output .= '<p class="LC_error">'.
12763: &mt('Course home server failed to retrieve:').'<ul>'.
12764: $replicationfail.
12765: '</ul></p>';
12766: }
12767: }
1.1055 raeburn 12768: } else {
12769: $warning = &mt('No items found in archive.');
12770: }
12771: if ($error) {
12772: $output .= '<p class="LC_error">'.&mt('Not extracted.').'<br />'.
12773: $error.'</p>'."\n";
12774: }
12775: if ($warning) {
12776: $output .= '<p class="LC_warning">'.$warning.'</p>'."\n";
12777: }
12778: return $output;
12779: }
12780:
1.1066 raeburn 12781: sub cleanup_empty_dirs {
12782: my ($path) = @_;
12783: if (($path ne '') && (-d $path)) {
12784: if (opendir(my $dirh,$path)) {
12785: my @dircontents = grep(!/^\./,readdir($dirh));
12786: my $numitems = 0;
12787: foreach my $item (@dircontents) {
12788: if (-d "$path/$item") {
1.1075.2.28 raeburn 12789: &cleanup_empty_dirs("$path/$item");
1.1066 raeburn 12790: if (-e "$path/$item") {
12791: $numitems ++;
12792: }
12793: } else {
12794: $numitems ++;
12795: }
12796: }
12797: if ($numitems == 0) {
12798: rmdir($path);
12799: }
12800: closedir($dirh);
12801: }
12802: }
12803: return;
12804: }
12805:
1.41 ng 12806: =pod
1.45 matthew 12807:
1.1075.2.56 raeburn 12808: =item * &get_folder_hierarchy()
1.1068 raeburn 12809:
12810: Provides hierarchy of names of folders/sub-folders containing the current
12811: item,
12812:
12813: Inputs: 3
12814: - $navmap - navmaps object
12815:
12816: - $map - url for map (either the trigger itself, or map containing
12817: the resource, which is the trigger).
12818:
12819: - $showitem - 1 => show title for map itself; 0 => do not show.
12820:
12821: Outputs: 1 @pathitems - array of folder/subfolder names.
12822:
12823: =cut
12824:
12825: sub get_folder_hierarchy {
12826: my ($navmap,$map,$showitem) = @_;
12827: my @pathitems;
12828: if (ref($navmap)) {
12829: my $mapres = $navmap->getResourceByUrl($map);
12830: if (ref($mapres)) {
12831: my $pcslist = $mapres->map_hierarchy();
12832: if ($pcslist ne '') {
12833: my @pcs = split(/,/,$pcslist);
12834: foreach my $pc (@pcs) {
12835: if ($pc == 1) {
1.1075.2.38 raeburn 12836: push(@pathitems,&mt('Main Content'));
1.1068 raeburn 12837: } else {
12838: my $res = $navmap->getByMapPc($pc);
12839: if (ref($res)) {
12840: my $title = $res->compTitle();
12841: $title =~ s/\W+/_/g;
12842: if ($title ne '') {
12843: push(@pathitems,$title);
12844: }
12845: }
12846: }
12847: }
12848: }
1.1071 raeburn 12849: if ($showitem) {
12850: if ($mapres->{ID} eq '0.0') {
1.1075.2.38 raeburn 12851: push(@pathitems,&mt('Main Content'));
1.1071 raeburn 12852: } else {
12853: my $maptitle = $mapres->compTitle();
12854: $maptitle =~ s/\W+/_/g;
12855: if ($maptitle ne '') {
12856: push(@pathitems,$maptitle);
12857: }
1.1068 raeburn 12858: }
12859: }
12860: }
12861: }
12862: return @pathitems;
12863: }
12864:
12865: =pod
12866:
1.1015 raeburn 12867: =item * &get_turnedin_filepath()
12868:
12869: Determines path in a user's portfolio file for storage of files uploaded
12870: to a specific essayresponse or dropbox item.
12871:
12872: Inputs: 3 required + 1 optional.
12873: $symb is symb for resource, $uname and $udom are for current user (required).
12874: $caller is optional (can be "submission", if routine is called when storing
12875: an upoaded file when "Submit Answer" button was pressed).
12876:
12877: Returns array containing $path and $multiresp.
12878: $path is path in portfolio. $multiresp is 1 if this resource contains more
12879: than one file upload item. Callers of routine should append partid as a
12880: subdirectory to $path in cases where $multiresp is 1.
12881:
12882: Called by: homework/essayresponse.pm and homework/structuretags.pm
12883:
12884: =cut
12885:
12886: sub get_turnedin_filepath {
12887: my ($symb,$uname,$udom,$caller) = @_;
12888: my ($map,$resid,$resurl)=&Apache::lonnet::decode_symb($symb);
12889: my $turnindir;
12890: my %userhash = &Apache::lonnet::userenvironment($udom,$uname,'turnindir');
12891: $turnindir = $userhash{'turnindir'};
12892: my ($path,$multiresp);
12893: if ($turnindir eq '') {
12894: if ($caller eq 'submission') {
12895: $turnindir = &mt('turned in');
12896: $turnindir =~ s/\W+/_/g;
12897: my %newhash = (
12898: 'turnindir' => $turnindir,
12899: );
12900: &Apache::lonnet::put('environment',\%newhash,$udom,$uname);
12901: }
12902: }
12903: if ($turnindir ne '') {
12904: $path = '/'.$turnindir.'/';
12905: my ($multipart,$turnin,@pathitems);
12906: my $navmap = Apache::lonnavmaps::navmap->new();
12907: if (defined($navmap)) {
12908: my $mapres = $navmap->getResourceByUrl($map);
12909: if (ref($mapres)) {
12910: my $pcslist = $mapres->map_hierarchy();
12911: if ($pcslist ne '') {
12912: foreach my $pc (split(/,/,$pcslist)) {
12913: my $res = $navmap->getByMapPc($pc);
12914: if (ref($res)) {
12915: my $title = $res->compTitle();
12916: $title =~ s/\W+/_/g;
12917: if ($title ne '') {
1.1075.2.48 raeburn 12918: if (($pc > 1) && (length($title) > 12)) {
12919: $title = substr($title,0,12);
12920: }
1.1015 raeburn 12921: push(@pathitems,$title);
12922: }
12923: }
12924: }
12925: }
12926: my $maptitle = $mapres->compTitle();
12927: $maptitle =~ s/\W+/_/g;
12928: if ($maptitle ne '') {
1.1075.2.48 raeburn 12929: if (length($maptitle) > 12) {
12930: $maptitle = substr($maptitle,0,12);
12931: }
1.1015 raeburn 12932: push(@pathitems,$maptitle);
12933: }
12934: unless ($env{'request.state'} eq 'construct') {
12935: my $res = $navmap->getBySymb($symb);
12936: if (ref($res)) {
12937: my $partlist = $res->parts();
12938: my $totaluploads = 0;
12939: if (ref($partlist) eq 'ARRAY') {
12940: foreach my $part (@{$partlist}) {
12941: my @types = $res->responseType($part);
12942: my @ids = $res->responseIds($part);
12943: for (my $i=0; $i < scalar(@ids); $i++) {
12944: if ($types[$i] eq 'essay') {
12945: my $partid = $part.'_'.$ids[$i];
12946: if (&Apache::lonnet::EXT("resource.$partid.uploadedfiletypes") ne '') {
12947: $totaluploads ++;
12948: }
12949: }
12950: }
12951: }
12952: if ($totaluploads > 1) {
12953: $multiresp = 1;
12954: }
12955: }
12956: }
12957: }
12958: } else {
12959: return;
12960: }
12961: } else {
12962: return;
12963: }
12964: my $restitle=&Apache::lonnet::gettitle($symb);
12965: $restitle =~ s/\W+/_/g;
12966: if ($restitle eq '') {
12967: $restitle = ($resurl =~ m{/[^/]+$});
12968: if ($restitle eq '') {
12969: $restitle = time;
12970: }
12971: }
1.1075.2.48 raeburn 12972: if (length($restitle) > 12) {
12973: $restitle = substr($restitle,0,12);
12974: }
1.1015 raeburn 12975: push(@pathitems,$restitle);
12976: $path .= join('/',@pathitems);
12977: }
12978: return ($path,$multiresp);
12979: }
12980:
12981: =pod
12982:
1.464 albertel 12983: =back
1.41 ng 12984:
1.112 bowersj2 12985: =head1 CSV Upload/Handling functions
1.38 albertel 12986:
1.41 ng 12987: =over 4
12988:
1.648 raeburn 12989: =item * &upfile_store($r)
1.41 ng 12990:
12991: Store uploaded file, $r should be the HTTP Request object,
1.258 albertel 12992: needs $env{'form.upfile'}
1.41 ng 12993: returns $datatoken to be put into hidden field
12994:
12995: =cut
1.31 albertel 12996:
12997: sub upfile_store {
12998: my $r=shift;
1.258 albertel 12999: $env{'form.upfile'}=~s/\r/\n/gs;
13000: $env{'form.upfile'}=~s/\f/\n/gs;
13001: $env{'form.upfile'}=~s/\n+/\n/gs;
13002: $env{'form.upfile'}=~s/\n+$//gs;
1.31 albertel 13003:
1.258 albertel 13004: my $datatoken=$env{'user.name'}.'_'.$env{'user.domain'}.
13005: '_enroll_'.$env{'request.course.id'}.'_'.time.'_'.$$;
1.31 albertel 13006: {
1.158 raeburn 13007: my $datafile = $r->dir_config('lonDaemons').
13008: '/tmp/'.$datatoken.'.tmp';
13009: if ( open(my $fh,">$datafile") ) {
1.258 albertel 13010: print $fh $env{'form.upfile'};
1.158 raeburn 13011: close($fh);
13012: }
1.31 albertel 13013: }
13014: return $datatoken;
13015: }
13016:
1.56 matthew 13017: =pod
13018:
1.648 raeburn 13019: =item * &load_tmp_file($r)
1.41 ng 13020:
13021: Load uploaded file from tmp, $r should be the HTTP Request object,
1.258 albertel 13022: needs $env{'form.datatoken'},
13023: sets $env{'form.upfile'} to the contents of the file
1.41 ng 13024:
13025: =cut
1.31 albertel 13026:
13027: sub load_tmp_file {
13028: my $r=shift;
13029: my @studentdata=();
13030: {
1.158 raeburn 13031: my $studentfile = $r->dir_config('lonDaemons').
1.258 albertel 13032: '/tmp/'.$env{'form.datatoken'}.'.tmp';
1.158 raeburn 13033: if ( open(my $fh,"<$studentfile") ) {
13034: @studentdata=<$fh>;
13035: close($fh);
13036: }
1.31 albertel 13037: }
1.258 albertel 13038: $env{'form.upfile'}=join('',@studentdata);
1.31 albertel 13039: }
13040:
1.56 matthew 13041: =pod
13042:
1.648 raeburn 13043: =item * &upfile_record_sep()
1.41 ng 13044:
13045: Separate uploaded file into records
13046: returns array of records,
1.258 albertel 13047: needs $env{'form.upfile'} and $env{'form.upfiletype'}
1.41 ng 13048:
13049: =cut
1.31 albertel 13050:
13051: sub upfile_record_sep {
1.258 albertel 13052: if ($env{'form.upfiletype'} eq 'xml') {
1.31 albertel 13053: } else {
1.248 albertel 13054: my @records;
1.258 albertel 13055: foreach my $line (split(/\n/,$env{'form.upfile'})) {
1.248 albertel 13056: if ($line=~/^\s*$/) { next; }
13057: push(@records,$line);
13058: }
13059: return @records;
1.31 albertel 13060: }
13061: }
13062:
1.56 matthew 13063: =pod
13064:
1.648 raeburn 13065: =item * &record_sep($record)
1.41 ng 13066:
1.258 albertel 13067: Separate a record into fields $record should be an item from the upfile_record_sep(), needs $env{'form.upfiletype'}
1.41 ng 13068:
13069: =cut
13070:
1.263 www 13071: sub takeleft {
13072: my $index=shift;
13073: return substr('0000'.$index,-4,4);
13074: }
13075:
1.31 albertel 13076: sub record_sep {
13077: my $record=shift;
13078: my %components=();
1.258 albertel 13079: if ($env{'form.upfiletype'} eq 'xml') {
13080: } elsif ($env{'form.upfiletype'} eq 'space') {
1.31 albertel 13081: my $i=0;
1.356 albertel 13082: foreach my $field (split(/\s+/,$record)) {
1.31 albertel 13083: $field=~s/^(\"|\')//;
13084: $field=~s/(\"|\')$//;
1.263 www 13085: $components{&takeleft($i)}=$field;
1.31 albertel 13086: $i++;
13087: }
1.258 albertel 13088: } elsif ($env{'form.upfiletype'} eq 'tab') {
1.31 albertel 13089: my $i=0;
1.356 albertel 13090: foreach my $field (split(/\t/,$record)) {
1.31 albertel 13091: $field=~s/^(\"|\')//;
13092: $field=~s/(\"|\')$//;
1.263 www 13093: $components{&takeleft($i)}=$field;
1.31 albertel 13094: $i++;
13095: }
13096: } else {
1.561 www 13097: my $separator=',';
1.480 banghart 13098: if ($env{'form.upfiletype'} eq 'semisv') {
1.561 www 13099: $separator=';';
1.480 banghart 13100: }
1.31 albertel 13101: my $i=0;
1.561 www 13102: # the character we are looking for to indicate the end of a quote or a record
13103: my $looking_for=$separator;
13104: # do not add the characters to the fields
13105: my $ignore=0;
13106: # we just encountered a separator (or the beginning of the record)
13107: my $just_found_separator=1;
13108: # store the field we are working on here
13109: my $field='';
13110: # work our way through all characters in record
13111: foreach my $character ($record=~/(.)/g) {
13112: if ($character eq $looking_for) {
13113: if ($character ne $separator) {
13114: # Found the end of a quote, again looking for separator
13115: $looking_for=$separator;
13116: $ignore=1;
13117: } else {
13118: # Found a separator, store away what we got
13119: $components{&takeleft($i)}=$field;
13120: $i++;
13121: $just_found_separator=1;
13122: $ignore=0;
13123: $field='';
13124: }
13125: next;
13126: }
13127: # single or double quotation marks after a separator indicate beginning of a quote
13128: # we are now looking for the end of the quote and need to ignore separators
13129: if ((($character eq '"') || ($character eq "'")) && ($just_found_separator)) {
13130: $looking_for=$character;
13131: next;
13132: }
13133: # ignore would be true after we reached the end of a quote
13134: if ($ignore) { next; }
13135: if (($just_found_separator) && ($character=~/\s/)) { next; }
13136: $field.=$character;
13137: $just_found_separator=0;
1.31 albertel 13138: }
1.561 www 13139: # catch the very last entry, since we never encountered the separator
13140: $components{&takeleft($i)}=$field;
1.31 albertel 13141: }
13142: return %components;
13143: }
13144:
1.144 matthew 13145: ######################################################
13146: ######################################################
13147:
1.56 matthew 13148: =pod
13149:
1.648 raeburn 13150: =item * &upfile_select_html()
1.41 ng 13151:
1.144 matthew 13152: Return HTML code to select a file from the users machine and specify
13153: the file type.
1.41 ng 13154:
13155: =cut
13156:
1.144 matthew 13157: ######################################################
13158: ######################################################
1.31 albertel 13159: sub upfile_select_html {
1.144 matthew 13160: my %Types = (
13161: csv => &mt('CSV (comma separated values, spreadsheet)'),
1.480 banghart 13162: semisv => &mt('Semicolon separated values'),
1.144 matthew 13163: space => &mt('Space separated'),
13164: tab => &mt('Tabulator separated'),
13165: # xml => &mt('HTML/XML'),
13166: );
13167: my $Str = '<input type="file" name="upfile" size="50" />'.
1.727 riegler 13168: '<br />'.&mt('Type').': <select name="upfiletype">';
1.144 matthew 13169: foreach my $type (sort(keys(%Types))) {
13170: $Str .= '<option value="'.$type.'" >'.$Types{$type}."</option>\n";
13171: }
13172: $Str .= "</select>\n";
13173: return $Str;
1.31 albertel 13174: }
13175:
1.301 albertel 13176: sub get_samples {
13177: my ($records,$toget) = @_;
13178: my @samples=({});
13179: my $got=0;
13180: foreach my $rec (@$records) {
13181: my %temp = &record_sep($rec);
13182: if (! grep(/\S/, values(%temp))) { next; }
13183: if (%temp) {
13184: $samples[$got]=\%temp;
13185: $got++;
13186: if ($got == $toget) { last; }
13187: }
13188: }
13189: return \@samples;
13190: }
13191:
1.144 matthew 13192: ######################################################
13193: ######################################################
13194:
1.56 matthew 13195: =pod
13196:
1.648 raeburn 13197: =item * &csv_print_samples($r,$records)
1.41 ng 13198:
13199: Prints a table of sample values from each column uploaded $r is an
13200: Apache Request ref, $records is an arrayref from
13201: &Apache::loncommon::upfile_record_sep
13202:
13203: =cut
13204:
1.144 matthew 13205: ######################################################
13206: ######################################################
1.31 albertel 13207: sub csv_print_samples {
13208: my ($r,$records) = @_;
1.662 bisitz 13209: my $samples = &get_samples($records,5);
1.301 albertel 13210:
1.594 raeburn 13211: $r->print(&mt('Samples').'<br />'.&start_data_table().
13212: &start_data_table_header_row());
1.356 albertel 13213: foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) {
1.845 bisitz 13214: $r->print('<th>'.&mt('Column [_1]',($sample+1)).'</th>'); }
1.594 raeburn 13215: $r->print(&end_data_table_header_row());
1.301 albertel 13216: foreach my $hash (@$samples) {
1.594 raeburn 13217: $r->print(&start_data_table_row());
1.356 albertel 13218: foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) {
1.31 albertel 13219: $r->print('<td>');
1.356 albertel 13220: if (defined($$hash{$sample})) { $r->print($$hash{$sample}); }
1.31 albertel 13221: $r->print('</td>');
13222: }
1.594 raeburn 13223: $r->print(&end_data_table_row());
1.31 albertel 13224: }
1.594 raeburn 13225: $r->print(&end_data_table().'<br />'."\n");
1.31 albertel 13226: }
13227:
1.144 matthew 13228: ######################################################
13229: ######################################################
13230:
1.56 matthew 13231: =pod
13232:
1.648 raeburn 13233: =item * &csv_print_select_table($r,$records,$d)
1.41 ng 13234:
13235: Prints a table to create associations between values and table columns.
1.144 matthew 13236:
1.41 ng 13237: $r is an Apache Request ref,
13238: $records is an arrayref from &Apache::loncommon::upfile_record_sep,
1.174 matthew 13239: $d is an array of 2 element arrays (internal name, displayed name,defaultcol)
1.41 ng 13240:
13241: =cut
13242:
1.144 matthew 13243: ######################################################
13244: ######################################################
1.31 albertel 13245: sub csv_print_select_table {
13246: my ($r,$records,$d) = @_;
1.301 albertel 13247: my $i=0;
13248: my $samples = &get_samples($records,1);
1.144 matthew 13249: $r->print(&mt('Associate columns with student attributes.')."\n".
1.594 raeburn 13250: &start_data_table().&start_data_table_header_row().
1.144 matthew 13251: '<th>'.&mt('Attribute').'</th>'.
1.594 raeburn 13252: '<th>'.&mt('Column').'</th>'.
13253: &end_data_table_header_row()."\n");
1.356 albertel 13254: foreach my $array_ref (@$d) {
13255: my ($value,$display,$defaultcol)=@{ $array_ref };
1.729 raeburn 13256: $r->print(&start_data_table_row().'<td>'.$display.'</td>');
1.31 albertel 13257:
1.875 bisitz 13258: $r->print('<td><select name="f'.$i.'"'.
1.32 matthew 13259: ' onchange="javascript:flip(this.form,'.$i.');">');
1.31 albertel 13260: $r->print('<option value="none"></option>');
1.356 albertel 13261: foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) {
13262: $r->print('<option value="'.$sample.'"'.
13263: ($sample eq $defaultcol ? ' selected="selected" ' : '').
1.662 bisitz 13264: '>'.&mt('Column [_1]',($sample+1)).'</option>');
1.31 albertel 13265: }
1.594 raeburn 13266: $r->print('</select></td>'.&end_data_table_row()."\n");
1.31 albertel 13267: $i++;
13268: }
1.594 raeburn 13269: $r->print(&end_data_table());
1.31 albertel 13270: $i--;
13271: return $i;
13272: }
1.56 matthew 13273:
1.144 matthew 13274: ######################################################
13275: ######################################################
13276:
1.56 matthew 13277: =pod
1.31 albertel 13278:
1.648 raeburn 13279: =item * &csv_samples_select_table($r,$records,$d)
1.41 ng 13280:
13281: Prints a table of sample values from the upload and can make associate samples to internal names.
13282:
13283: $r is an Apache Request ref,
13284: $records is an arrayref from &Apache::loncommon::upfile_record_sep,
13285: $d is an array of 2 element arrays (internal name, displayed name)
13286:
13287: =cut
13288:
1.144 matthew 13289: ######################################################
13290: ######################################################
1.31 albertel 13291: sub csv_samples_select_table {
13292: my ($r,$records,$d) = @_;
13293: my $i=0;
1.144 matthew 13294: #
1.662 bisitz 13295: my $max_samples = 5;
13296: my $samples = &get_samples($records,$max_samples);
1.594 raeburn 13297: $r->print(&start_data_table().
13298: &start_data_table_header_row().'<th>'.
13299: &mt('Field').'</th><th>'.&mt('Samples').'</th>'.
13300: &end_data_table_header_row());
1.301 albertel 13301:
13302: foreach my $key (sort(keys(%{ $samples->[0] }))) {
1.594 raeburn 13303: $r->print(&start_data_table_row().'<td><select name="f'.$i.'"'.
1.32 matthew 13304: ' onchange="javascript:flip(this.form,'.$i.');">');
1.301 albertel 13305: foreach my $option (@$d) {
13306: my ($value,$display,$defaultcol)=@{ $option };
1.174 matthew 13307: $r->print('<option value="'.$value.'"'.
1.253 albertel 13308: ($i eq $defaultcol ? ' selected="selected" ':'').'>'.
1.174 matthew 13309: $display.'</option>');
1.31 albertel 13310: }
13311: $r->print('</select></td><td>');
1.662 bisitz 13312: foreach my $line (0..($max_samples-1)) {
1.301 albertel 13313: if (defined($samples->[$line]{$key})) {
13314: $r->print($samples->[$line]{$key}."<br />\n");
13315: }
13316: }
1.594 raeburn 13317: $r->print('</td>'.&end_data_table_row());
1.31 albertel 13318: $i++;
13319: }
1.594 raeburn 13320: $r->print(&end_data_table());
1.31 albertel 13321: $i--;
13322: return($i);
1.115 matthew 13323: }
13324:
1.144 matthew 13325: ######################################################
13326: ######################################################
13327:
1.115 matthew 13328: =pod
13329:
1.648 raeburn 13330: =item * &clean_excel_name($name)
1.115 matthew 13331:
13332: Returns a replacement for $name which does not contain any illegal characters.
13333:
13334: =cut
13335:
1.144 matthew 13336: ######################################################
13337: ######################################################
1.115 matthew 13338: sub clean_excel_name {
13339: my ($name) = @_;
13340: $name =~ s/[:\*\?\/\\]//g;
13341: if (length($name) > 31) {
13342: $name = substr($name,0,31);
13343: }
13344: return $name;
1.25 albertel 13345: }
1.84 albertel 13346:
1.85 albertel 13347: =pod
13348:
1.648 raeburn 13349: =item * &check_if_partid_hidden($id,$symb,$udom,$uname)
1.85 albertel 13350:
13351: Returns either 1 or undef
13352:
13353: 1 if the part is to be hidden, undef if it is to be shown
13354:
13355: Arguments are:
13356:
13357: $id the id of the part to be checked
13358: $symb, optional the symb of the resource to check
13359: $udom, optional the domain of the user to check for
13360: $uname, optional the username of the user to check for
13361:
13362: =cut
1.84 albertel 13363:
13364: sub check_if_partid_hidden {
13365: my ($id,$symb,$udom,$uname) = @_;
1.133 albertel 13366: my $hiddenparts=&Apache::lonnet::EXT('resource.0.hiddenparts',
1.84 albertel 13367: $symb,$udom,$uname);
1.141 albertel 13368: my $truth=1;
13369: #if the string starts with !, then the list is the list to show not hide
13370: if ($hiddenparts=~s/^\s*!//) { $truth=undef; }
1.84 albertel 13371: my @hiddenlist=split(/,/,$hiddenparts);
13372: foreach my $checkid (@hiddenlist) {
1.141 albertel 13373: if ($checkid =~ /^\s*\Q$id\E\s*$/) { return $truth; }
1.84 albertel 13374: }
1.141 albertel 13375: return !$truth;
1.84 albertel 13376: }
1.127 matthew 13377:
1.138 matthew 13378:
13379: ############################################################
13380: ############################################################
13381:
13382: =pod
13383:
1.157 matthew 13384: =back
13385:
1.138 matthew 13386: =head1 cgi-bin script and graphing routines
13387:
1.157 matthew 13388: =over 4
13389:
1.648 raeburn 13390: =item * &get_cgi_id()
1.138 matthew 13391:
13392: Inputs: none
13393:
13394: Returns an id which can be used to pass environment variables
13395: to various cgi-bin scripts. These environment variables will
13396: be removed from the users environment after a given time by
13397: the routine &Apache::lonnet::transfer_profile_to_env.
13398:
13399: =cut
13400:
13401: ############################################################
13402: ############################################################
1.152 albertel 13403: my $uniq=0;
1.136 matthew 13404: sub get_cgi_id {
1.154 albertel 13405: $uniq=($uniq+1)%100000;
1.280 albertel 13406: return (time.'_'.$$.'_'.$uniq);
1.136 matthew 13407: }
13408:
1.127 matthew 13409: ############################################################
13410: ############################################################
13411:
13412: =pod
13413:
1.648 raeburn 13414: =item * &DrawBarGraph()
1.127 matthew 13415:
1.138 matthew 13416: Facilitates the plotting of data in a (stacked) bar graph.
13417: Puts plot definition data into the users environment in order for
13418: graph.png to plot it. Returns an <img> tag for the plot.
13419: The bars on the plot are labeled '1','2',...,'n'.
13420:
13421: Inputs:
13422:
13423: =over 4
13424:
13425: =item $Title: string, the title of the plot
13426:
13427: =item $xlabel: string, text describing the X-axis of the plot
13428:
13429: =item $ylabel: string, text describing the Y-axis of the plot
13430:
13431: =item $Max: scalar, the maximum Y value to use in the plot
13432: If $Max is < any data point, the graph will not be rendered.
13433:
1.140 matthew 13434: =item $colors: array ref holding the colors to be used for the data sets when
1.138 matthew 13435: they are plotted. If undefined, default values will be used.
13436:
1.178 matthew 13437: =item $labels: array ref holding the labels to use on the x-axis for the bars.
13438:
1.138 matthew 13439: =item @Values: An array of array references. Each array reference holds data
13440: to be plotted in a stacked bar chart.
13441:
1.239 matthew 13442: =item If the final element of @Values is a hash reference the key/value
13443: pairs will be added to the graph definition.
13444:
1.138 matthew 13445: =back
13446:
13447: Returns:
13448:
13449: An <img> tag which references graph.png and the appropriate identifying
13450: information for the plot.
13451:
1.127 matthew 13452: =cut
13453:
13454: ############################################################
13455: ############################################################
1.134 matthew 13456: sub DrawBarGraph {
1.178 matthew 13457: my ($Title,$xlabel,$ylabel,$Max,$colors,$labels,@Values)=@_;
1.134 matthew 13458: #
13459: if (! defined($colors)) {
13460: $colors = ['#33ff00',
13461: '#0033cc', '#990000', '#aaaa66', '#663399', '#ff9933',
13462: '#66ccff', '#ff9999', '#cccc33', '#660000', '#33cc66',
13463: ];
13464: }
1.228 matthew 13465: my $extra_settings = {};
13466: if (ref($Values[-1]) eq 'HASH') {
13467: $extra_settings = pop(@Values);
13468: }
1.127 matthew 13469: #
1.136 matthew 13470: my $identifier = &get_cgi_id();
13471: my $id = 'cgi.'.$identifier;
1.129 matthew 13472: if (! @Values || ref($Values[0]) ne 'ARRAY') {
1.127 matthew 13473: return '';
13474: }
1.225 matthew 13475: #
13476: my @Labels;
13477: if (defined($labels)) {
13478: @Labels = @$labels;
13479: } else {
13480: for (my $i=0;$i<@{$Values[0]};$i++) {
13481: push (@Labels,$i+1);
13482: }
13483: }
13484: #
1.129 matthew 13485: my $NumBars = scalar(@{$Values[0]});
1.225 matthew 13486: if ($NumBars < scalar(@Labels)) { $NumBars = scalar(@Labels); }
1.129 matthew 13487: my %ValuesHash;
13488: my $NumSets=1;
13489: foreach my $array (@Values) {
13490: next if (! ref($array));
1.136 matthew 13491: $ValuesHash{$id.'.data.'.$NumSets++} =
1.132 matthew 13492: join(',',@$array);
1.129 matthew 13493: }
1.127 matthew 13494: #
1.136 matthew 13495: my ($height,$width,$xskip,$bar_width) = (200,120,1,15);
1.225 matthew 13496: if ($NumBars < 3) {
13497: $width = 120+$NumBars*32;
1.220 matthew 13498: $xskip = 1;
1.225 matthew 13499: $bar_width = 30;
13500: } elsif ($NumBars < 5) {
13501: $width = 120+$NumBars*20;
13502: $xskip = 1;
13503: $bar_width = 20;
1.220 matthew 13504: } elsif ($NumBars < 10) {
1.136 matthew 13505: $width = 120+$NumBars*15;
13506: $xskip = 1;
13507: $bar_width = 15;
13508: } elsif ($NumBars <= 25) {
13509: $width = 120+$NumBars*11;
13510: $xskip = 5;
13511: $bar_width = 8;
13512: } elsif ($NumBars <= 50) {
13513: $width = 120+$NumBars*8;
13514: $xskip = 5;
13515: $bar_width = 4;
13516: } else {
13517: $width = 120+$NumBars*8;
13518: $xskip = 5;
13519: $bar_width = 4;
13520: }
13521: #
1.137 matthew 13522: $Max = 1 if ($Max < 1);
13523: if ( int($Max) < $Max ) {
13524: $Max++;
13525: $Max = int($Max);
13526: }
1.127 matthew 13527: $Title = '' if (! defined($Title));
13528: $xlabel = '' if (! defined($xlabel));
13529: $ylabel = '' if (! defined($ylabel));
1.369 www 13530: $ValuesHash{$id.'.title'} = &escape($Title);
13531: $ValuesHash{$id.'.xlabel'} = &escape($xlabel);
13532: $ValuesHash{$id.'.ylabel'} = &escape($ylabel);
1.137 matthew 13533: $ValuesHash{$id.'.y_max_value'} = $Max;
1.136 matthew 13534: $ValuesHash{$id.'.NumBars'} = $NumBars;
13535: $ValuesHash{$id.'.NumSets'} = $NumSets;
13536: $ValuesHash{$id.'.PlotType'} = 'bar';
13537: $ValuesHash{$id.'.Colors'} = join(',',@{$colors});
13538: $ValuesHash{$id.'.height'} = $height;
13539: $ValuesHash{$id.'.width'} = $width;
13540: $ValuesHash{$id.'.xskip'} = $xskip;
13541: $ValuesHash{$id.'.bar_width'} = $bar_width;
13542: $ValuesHash{$id.'.labels'} = join(',',@Labels);
1.127 matthew 13543: #
1.228 matthew 13544: # Deal with other parameters
13545: while (my ($key,$value) = each(%$extra_settings)) {
13546: $ValuesHash{$id.'.'.$key} = $value;
13547: }
13548: #
1.646 raeburn 13549: &Apache::lonnet::appenv(\%ValuesHash);
1.137 matthew 13550: return '<img src="/cgi-bin/graph.png?'.$identifier.'" border="1" />';
13551: }
13552:
13553: ############################################################
13554: ############################################################
13555:
13556: =pod
13557:
1.648 raeburn 13558: =item * &DrawXYGraph()
1.137 matthew 13559:
1.138 matthew 13560: Facilitates the plotting of data in an XY graph.
13561: Puts plot definition data into the users environment in order for
13562: graph.png to plot it. Returns an <img> tag for the plot.
13563:
13564: Inputs:
13565:
13566: =over 4
13567:
13568: =item $Title: string, the title of the plot
13569:
13570: =item $xlabel: string, text describing the X-axis of the plot
13571:
13572: =item $ylabel: string, text describing the Y-axis of the plot
13573:
13574: =item $Max: scalar, the maximum Y value to use in the plot
13575: If $Max is < any data point, the graph will not be rendered.
13576:
13577: =item $colors: Array ref containing the hex color codes for the data to be
13578: plotted in. If undefined, default values will be used.
13579:
13580: =item $Xlabels: Array ref containing the labels to be used for the X-axis.
13581:
13582: =item $Ydata: Array ref containing Array refs.
1.185 www 13583: Each of the contained arrays will be plotted as a separate curve.
1.138 matthew 13584:
13585: =item %Values: hash indicating or overriding any default values which are
13586: passed to graph.png.
13587: Possible values are: width, xskip, x_ticks, x_tick_offset, among others.
13588:
13589: =back
13590:
13591: Returns:
13592:
13593: An <img> tag which references graph.png and the appropriate identifying
13594: information for the plot.
13595:
1.137 matthew 13596: =cut
13597:
13598: ############################################################
13599: ############################################################
13600: sub DrawXYGraph {
13601: my ($Title,$xlabel,$ylabel,$Max,$colors,$Xlabels,$Ydata,%Values)=@_;
13602: #
13603: # Create the identifier for the graph
13604: my $identifier = &get_cgi_id();
13605: my $id = 'cgi.'.$identifier;
13606: #
13607: $Title = '' if (! defined($Title));
13608: $xlabel = '' if (! defined($xlabel));
13609: $ylabel = '' if (! defined($ylabel));
13610: my %ValuesHash =
13611: (
1.369 www 13612: $id.'.title' => &escape($Title),
13613: $id.'.xlabel' => &escape($xlabel),
13614: $id.'.ylabel' => &escape($ylabel),
1.137 matthew 13615: $id.'.y_max_value'=> $Max,
13616: $id.'.labels' => join(',',@$Xlabels),
13617: $id.'.PlotType' => 'XY',
13618: );
13619: #
13620: if (defined($colors) && ref($colors) eq 'ARRAY') {
13621: $ValuesHash{$id.'.Colors'} = join(',',@{$colors});
13622: }
13623: #
13624: if (! ref($Ydata) || ref($Ydata) ne 'ARRAY') {
13625: return '';
13626: }
13627: my $NumSets=1;
1.138 matthew 13628: foreach my $array (@{$Ydata}){
1.137 matthew 13629: next if (! ref($array));
13630: $ValuesHash{$id.'.data.'.$NumSets++} = join(',',@$array);
13631: }
1.138 matthew 13632: $ValuesHash{$id.'.NumSets'} = $NumSets-1;
1.137 matthew 13633: #
13634: # Deal with other parameters
13635: while (my ($key,$value) = each(%Values)) {
13636: $ValuesHash{$id.'.'.$key} = $value;
1.127 matthew 13637: }
13638: #
1.646 raeburn 13639: &Apache::lonnet::appenv(\%ValuesHash);
1.136 matthew 13640: return '<img src="/cgi-bin/graph.png?'.$identifier.'" border="1" />';
13641: }
13642:
13643: ############################################################
13644: ############################################################
13645:
13646: =pod
13647:
1.648 raeburn 13648: =item * &DrawXYYGraph()
1.138 matthew 13649:
13650: Facilitates the plotting of data in an XY graph with two Y axes.
13651: Puts plot definition data into the users environment in order for
13652: graph.png to plot it. Returns an <img> tag for the plot.
13653:
13654: Inputs:
13655:
13656: =over 4
13657:
13658: =item $Title: string, the title of the plot
13659:
13660: =item $xlabel: string, text describing the X-axis of the plot
13661:
13662: =item $ylabel: string, text describing the Y-axis of the plot
13663:
13664: =item $colors: Array ref containing the hex color codes for the data to be
13665: plotted in. If undefined, default values will be used.
13666:
13667: =item $Xlabels: Array ref containing the labels to be used for the X-axis.
13668:
13669: =item $Ydata1: The first data set
13670:
13671: =item $Min1: The minimum value of the left Y-axis
13672:
13673: =item $Max1: The maximum value of the left Y-axis
13674:
13675: =item $Ydata2: The second data set
13676:
13677: =item $Min2: The minimum value of the right Y-axis
13678:
13679: =item $Max2: The maximum value of the left Y-axis
13680:
13681: =item %Values: hash indicating or overriding any default values which are
13682: passed to graph.png.
13683: Possible values are: width, xskip, x_ticks, x_tick_offset, among others.
13684:
13685: =back
13686:
13687: Returns:
13688:
13689: An <img> tag which references graph.png and the appropriate identifying
13690: information for the plot.
1.136 matthew 13691:
13692: =cut
13693:
13694: ############################################################
13695: ############################################################
1.137 matthew 13696: sub DrawXYYGraph {
13697: my ($Title,$xlabel,$ylabel,$colors,$Xlabels,$Ydata1,$Min1,$Max1,
13698: $Ydata2,$Min2,$Max2,%Values)=@_;
1.136 matthew 13699: #
13700: # Create the identifier for the graph
13701: my $identifier = &get_cgi_id();
13702: my $id = 'cgi.'.$identifier;
13703: #
13704: $Title = '' if (! defined($Title));
13705: $xlabel = '' if (! defined($xlabel));
13706: $ylabel = '' if (! defined($ylabel));
13707: my %ValuesHash =
13708: (
1.369 www 13709: $id.'.title' => &escape($Title),
13710: $id.'.xlabel' => &escape($xlabel),
13711: $id.'.ylabel' => &escape($ylabel),
1.136 matthew 13712: $id.'.labels' => join(',',@$Xlabels),
13713: $id.'.PlotType' => 'XY',
13714: $id.'.NumSets' => 2,
1.137 matthew 13715: $id.'.two_axes' => 1,
13716: $id.'.y1_max_value' => $Max1,
13717: $id.'.y1_min_value' => $Min1,
13718: $id.'.y2_max_value' => $Max2,
13719: $id.'.y2_min_value' => $Min2,
1.136 matthew 13720: );
13721: #
1.137 matthew 13722: if (defined($colors) && ref($colors) eq 'ARRAY') {
13723: $ValuesHash{$id.'.Colors'} = join(',',@{$colors});
13724: }
13725: #
13726: if (! ref($Ydata1) || ref($Ydata1) ne 'ARRAY' ||
13727: ! ref($Ydata2) || ref($Ydata2) ne 'ARRAY'){
1.136 matthew 13728: return '';
13729: }
13730: my $NumSets=1;
1.137 matthew 13731: foreach my $array ($Ydata1,$Ydata2){
1.136 matthew 13732: next if (! ref($array));
13733: $ValuesHash{$id.'.data.'.$NumSets++} = join(',',@$array);
1.137 matthew 13734: }
13735: #
13736: # Deal with other parameters
13737: while (my ($key,$value) = each(%Values)) {
13738: $ValuesHash{$id.'.'.$key} = $value;
1.136 matthew 13739: }
13740: #
1.646 raeburn 13741: &Apache::lonnet::appenv(\%ValuesHash);
1.130 albertel 13742: return '<img src="/cgi-bin/graph.png?'.$identifier.'" border="1" />';
1.139 matthew 13743: }
13744:
13745: ############################################################
13746: ############################################################
13747:
13748: =pod
13749:
1.157 matthew 13750: =back
13751:
1.139 matthew 13752: =head1 Statistics helper routines?
13753:
13754: Bad place for them but what the hell.
13755:
1.157 matthew 13756: =over 4
13757:
1.648 raeburn 13758: =item * &chartlink()
1.139 matthew 13759:
13760: Returns a link to the chart for a specific student.
13761:
13762: Inputs:
13763:
13764: =over 4
13765:
13766: =item $linktext: The text of the link
13767:
13768: =item $sname: The students username
13769:
13770: =item $sdomain: The students domain
13771:
13772: =back
13773:
1.157 matthew 13774: =back
13775:
1.139 matthew 13776: =cut
13777:
13778: ############################################################
13779: ############################################################
13780: sub chartlink {
13781: my ($linktext, $sname, $sdomain) = @_;
13782: my $link = '<a href="/adm/statistics?reportSelected=student_assessment'.
1.369 www 13783: '&SelectedStudent='.&escape($sname.':'.$sdomain).
1.219 albertel 13784: '&chartoutputmode='.HTML::Entities::encode('html, with all links').
1.139 matthew 13785: '">'.$linktext.'</a>';
1.153 matthew 13786: }
13787:
13788: #######################################################
13789: #######################################################
13790:
13791: =pod
13792:
13793: =head1 Course Environment Routines
1.157 matthew 13794:
13795: =over 4
1.153 matthew 13796:
1.648 raeburn 13797: =item * &restore_course_settings()
1.153 matthew 13798:
1.648 raeburn 13799: =item * &store_course_settings()
1.153 matthew 13800:
13801: Restores/Store indicated form parameters from the course environment.
13802: Will not overwrite existing values of the form parameters.
13803:
13804: Inputs:
13805: a scalar describing the data (e.g. 'chart', 'problem_analysis')
13806:
13807: a hash ref describing the data to be stored. For example:
13808:
13809: %Save_Parameters = ('Status' => 'scalar',
13810: 'chartoutputmode' => 'scalar',
13811: 'chartoutputdata' => 'scalar',
13812: 'Section' => 'array',
1.373 raeburn 13813: 'Group' => 'array',
1.153 matthew 13814: 'StudentData' => 'array',
13815: 'Maps' => 'array');
13816:
13817: Returns: both routines return nothing
13818:
1.631 raeburn 13819: =back
13820:
1.153 matthew 13821: =cut
13822:
13823: #######################################################
13824: #######################################################
13825: sub store_course_settings {
1.496 albertel 13826: return &store_settings($env{'request.course.id'},@_);
13827: }
13828:
13829: sub store_settings {
1.153 matthew 13830: # save to the environment
13831: # appenv the same items, just to be safe
1.300 albertel 13832: my $udom = $env{'user.domain'};
13833: my $uname = $env{'user.name'};
1.496 albertel 13834: my ($context,$prefix,$Settings) = @_;
1.153 matthew 13835: my %SaveHash;
13836: my %AppHash;
13837: while (my ($setting,$type) = each(%$Settings)) {
1.496 albertel 13838: my $basename = join('.','internal',$context,$prefix,$setting);
1.300 albertel 13839: my $envname = 'environment.'.$basename;
1.258 albertel 13840: if (exists($env{'form.'.$setting})) {
1.153 matthew 13841: # Save this value away
13842: if ($type eq 'scalar' &&
1.258 albertel 13843: (! exists($env{$envname}) ||
13844: $env{$envname} ne $env{'form.'.$setting})) {
13845: $SaveHash{$basename} = $env{'form.'.$setting};
13846: $AppHash{$envname} = $env{'form.'.$setting};
1.153 matthew 13847: } elsif ($type eq 'array') {
13848: my $stored_form;
1.258 albertel 13849: if (ref($env{'form.'.$setting})) {
1.153 matthew 13850: $stored_form = join(',',
13851: map {
1.369 www 13852: &escape($_);
1.258 albertel 13853: } sort(@{$env{'form.'.$setting}}));
1.153 matthew 13854: } else {
13855: $stored_form =
1.369 www 13856: &escape($env{'form.'.$setting});
1.153 matthew 13857: }
13858: # Determine if the array contents are the same.
1.258 albertel 13859: if ($stored_form ne $env{$envname}) {
1.153 matthew 13860: $SaveHash{$basename} = $stored_form;
13861: $AppHash{$envname} = $stored_form;
13862: }
13863: }
13864: }
13865: }
13866: my $put_result = &Apache::lonnet::put('environment',\%SaveHash,
1.300 albertel 13867: $udom,$uname);
1.153 matthew 13868: if ($put_result !~ /^(ok|delayed)/) {
13869: &Apache::lonnet::logthis('unable to save form parameters, '.
13870: 'got error:'.$put_result);
13871: }
13872: # Make sure these settings stick around in this session, too
1.646 raeburn 13873: &Apache::lonnet::appenv(\%AppHash);
1.153 matthew 13874: return;
13875: }
13876:
13877: sub restore_course_settings {
1.499 albertel 13878: return &restore_settings($env{'request.course.id'},@_);
1.496 albertel 13879: }
13880:
13881: sub restore_settings {
13882: my ($context,$prefix,$Settings) = @_;
1.153 matthew 13883: while (my ($setting,$type) = each(%$Settings)) {
1.258 albertel 13884: next if (exists($env{'form.'.$setting}));
1.496 albertel 13885: my $envname = 'environment.internal.'.$context.'.'.$prefix.
1.153 matthew 13886: '.'.$setting;
1.258 albertel 13887: if (exists($env{$envname})) {
1.153 matthew 13888: if ($type eq 'scalar') {
1.258 albertel 13889: $env{'form.'.$setting} = $env{$envname};
1.153 matthew 13890: } elsif ($type eq 'array') {
1.258 albertel 13891: $env{'form.'.$setting} = [
1.153 matthew 13892: map {
1.369 www 13893: &unescape($_);
1.258 albertel 13894: } split(',',$env{$envname})
1.153 matthew 13895: ];
13896: }
13897: }
13898: }
1.127 matthew 13899: }
13900:
1.618 raeburn 13901: #######################################################
13902: #######################################################
13903:
13904: =pod
13905:
13906: =head1 Domain E-mail Routines
13907:
13908: =over 4
13909:
1.648 raeburn 13910: =item * &build_recipient_list()
1.618 raeburn 13911:
1.1075.2.44 raeburn 13912: Build recipient lists for following types of e-mail:
1.766 raeburn 13913: (a) Error Reports, (b) Package Updates, (c) lonstatus warnings/errors
1.1075.2.44 raeburn 13914: (d) Help requests, (e) Course requests needing approval, (f) loncapa
13915: module change checking, student/employee ID conflict checks, as
13916: generated by lonerrorhandler.pm, CHECKRPMS, loncron,
13917: lonsupportreq.pm, loncoursequeueadmin.pm, searchcat.pl respectively.
1.618 raeburn 13918:
13919: Inputs:
1.1075.2.44 raeburn 13920: defmail (scalar - email address of default recipient),
13921: mailing type (scalar: errormail, packagesmail, helpdeskmail,
13922: requestsmail, updatesmail, or idconflictsmail).
13923:
1.619 raeburn 13924: defdom (domain for which to retrieve configuration settings),
1.1075.2.44 raeburn 13925:
13926: origmail (scalar - email address of recipient from loncapa.conf,
13927: i.e., predates configuration by DC via domainprefs.pm
1.618 raeburn 13928:
1.655 raeburn 13929: Returns: comma separated list of addresses to which to send e-mail.
13930:
13931: =back
1.618 raeburn 13932:
13933: =cut
13934:
13935: ############################################################
13936: ############################################################
13937: sub build_recipient_list {
1.619 raeburn 13938: my ($defmail,$mailing,$defdom,$origmail) = @_;
1.618 raeburn 13939: my @recipients;
13940: my $otheremails;
13941: my %domconfig =
13942: &Apache::lonnet::get_dom('configuration',['contacts'],$defdom);
13943: if (ref($domconfig{'contacts'}) eq 'HASH') {
1.766 raeburn 13944: if (exists($domconfig{'contacts'}{$mailing})) {
13945: if (ref($domconfig{'contacts'}{$mailing}) eq 'HASH') {
13946: my @contacts = ('adminemail','supportemail');
13947: foreach my $item (@contacts) {
13948: if ($domconfig{'contacts'}{$mailing}{$item}) {
13949: my $addr = $domconfig{'contacts'}{$item};
13950: if (!grep(/^\Q$addr\E$/,@recipients)) {
13951: push(@recipients,$addr);
13952: }
1.619 raeburn 13953: }
1.766 raeburn 13954: $otheremails = $domconfig{'contacts'}{$mailing}{'others'};
1.618 raeburn 13955: }
13956: }
1.766 raeburn 13957: } elsif ($origmail ne '') {
13958: push(@recipients,$origmail);
1.618 raeburn 13959: }
1.619 raeburn 13960: } elsif ($origmail ne '') {
13961: push(@recipients,$origmail);
1.618 raeburn 13962: }
1.688 raeburn 13963: if (defined($defmail)) {
13964: if ($defmail ne '') {
13965: push(@recipients,$defmail);
13966: }
1.618 raeburn 13967: }
13968: if ($otheremails) {
1.619 raeburn 13969: my @others;
13970: if ($otheremails =~ /,/) {
13971: @others = split(/,/,$otheremails);
1.618 raeburn 13972: } else {
1.619 raeburn 13973: push(@others,$otheremails);
13974: }
13975: foreach my $addr (@others) {
13976: if (!grep(/^\Q$addr\E$/,@recipients)) {
13977: push(@recipients,$addr);
13978: }
1.618 raeburn 13979: }
13980: }
1.619 raeburn 13981: my $recipientlist = join(',',@recipients);
1.618 raeburn 13982: return $recipientlist;
13983: }
13984:
1.127 matthew 13985: ############################################################
13986: ############################################################
1.154 albertel 13987:
1.655 raeburn 13988: =pod
13989:
13990: =head1 Course Catalog Routines
13991:
13992: =over 4
13993:
13994: =item * &gather_categories()
13995:
13996: Converts category definitions - keys of categories hash stored in
13997: coursecategories in configuration.db on the primary library server in a
13998: domain - to an array. Also generates javascript and idx hash used to
13999: generate Domain Coordinator interface for editing Course Categories.
14000:
14001: Inputs:
1.663 raeburn 14002:
1.655 raeburn 14003: categories (reference to hash of category definitions).
1.663 raeburn 14004:
1.655 raeburn 14005: cats (reference to array of arrays/hashes which encapsulates hierarchy of
14006: categories and subcategories).
1.663 raeburn 14007:
1.655 raeburn 14008: idx (reference to hash of counters used in Domain Coordinator interface for
14009: editing Course Categories).
1.663 raeburn 14010:
1.655 raeburn 14011: jsarray (reference to array of categories used to create Javascript arrays for
14012: Domain Coordinator interface for editing Course Categories).
14013:
14014: Returns: nothing
14015:
14016: Side effects: populates cats, idx and jsarray.
14017:
14018: =cut
14019:
14020: sub gather_categories {
14021: my ($categories,$cats,$idx,$jsarray) = @_;
14022: my %counters;
14023: my $num = 0;
14024: foreach my $item (keys(%{$categories})) {
14025: my ($cat,$container,$depth) = map { &unescape($_); } split(/:/,$item);
14026: if ($container eq '' && $depth == 0) {
14027: $cats->[$depth][$categories->{$item}] = $cat;
14028: } else {
14029: $cats->[$depth]{$container}[$categories->{$item}] = $cat;
14030: }
14031: my ($escitem,$tail) = split(/:/,$item,2);
14032: if ($counters{$tail} eq '') {
14033: $counters{$tail} = $num;
14034: $num ++;
14035: }
14036: if (ref($idx) eq 'HASH') {
14037: $idx->{$item} = $counters{$tail};
14038: }
14039: if (ref($jsarray) eq 'ARRAY') {
14040: push(@{$jsarray->[$counters{$tail}]},$item);
14041: }
14042: }
14043: return;
14044: }
14045:
14046: =pod
14047:
14048: =item * &extract_categories()
14049:
14050: Used to generate breadcrumb trails for course categories.
14051:
14052: Inputs:
1.663 raeburn 14053:
1.655 raeburn 14054: categories (reference to hash of category definitions).
1.663 raeburn 14055:
1.655 raeburn 14056: cats (reference to array of arrays/hashes which encapsulates hierarchy of
14057: categories and subcategories).
1.663 raeburn 14058:
1.655 raeburn 14059: trails (reference to array of breacrumb trails for each category).
1.663 raeburn 14060:
1.655 raeburn 14061: allitems (reference to hash - key is category key
14062: (format: escaped(name):escaped(parent category):depth in hierarchy).
1.663 raeburn 14063:
1.655 raeburn 14064: idx (reference to hash of counters used in Domain Coordinator interface for
14065: editing Course Categories).
1.663 raeburn 14066:
1.655 raeburn 14067: jsarray (reference to array of categories used to create Javascript arrays for
14068: Domain Coordinator interface for editing Course Categories).
14069:
1.665 raeburn 14070: subcats (reference to hash of arrays containing all subcategories within each
14071: category, -recursive)
14072:
1.655 raeburn 14073: Returns: nothing
14074:
14075: Side effects: populates trails and allitems hash references.
14076:
14077: =cut
14078:
14079: sub extract_categories {
1.665 raeburn 14080: my ($categories,$cats,$trails,$allitems,$idx,$jsarray,$subcats) = @_;
1.655 raeburn 14081: if (ref($categories) eq 'HASH') {
14082: &gather_categories($categories,$cats,$idx,$jsarray);
14083: if (ref($cats->[0]) eq 'ARRAY') {
14084: for (my $i=0; $i<@{$cats->[0]}; $i++) {
14085: my $name = $cats->[0][$i];
14086: my $item = &escape($name).'::0';
14087: my $trailstr;
14088: if ($name eq 'instcode') {
14089: $trailstr = &mt('Official courses (with institutional codes)');
1.919 raeburn 14090: } elsif ($name eq 'communities') {
14091: $trailstr = &mt('Communities');
1.655 raeburn 14092: } else {
14093: $trailstr = $name;
14094: }
14095: if ($allitems->{$item} eq '') {
14096: push(@{$trails},$trailstr);
14097: $allitems->{$item} = scalar(@{$trails})-1;
14098: }
14099: my @parents = ($name);
14100: if (ref($cats->[1]{$name}) eq 'ARRAY') {
14101: for (my $j=0; $j<@{$cats->[1]{$name}}; $j++) {
14102: my $category = $cats->[1]{$name}[$j];
1.665 raeburn 14103: if (ref($subcats) eq 'HASH') {
14104: push(@{$subcats->{$item}},&escape($category).':'.&escape($name).':1');
14105: }
14106: &recurse_categories($cats,2,$category,$trails,$allitems,\@parents,$subcats);
14107: }
14108: } else {
14109: if (ref($subcats) eq 'HASH') {
14110: $subcats->{$item} = [];
1.655 raeburn 14111: }
14112: }
14113: }
14114: }
14115: }
14116: return;
14117: }
14118:
14119: =pod
14120:
1.1075.2.56 raeburn 14121: =item * &recurse_categories()
1.655 raeburn 14122:
14123: Recursively used to generate breadcrumb trails for course categories.
14124:
14125: Inputs:
1.663 raeburn 14126:
1.655 raeburn 14127: cats (reference to array of arrays/hashes which encapsulates hierarchy of
14128: categories and subcategories).
1.663 raeburn 14129:
1.655 raeburn 14130: depth (current depth in hierarchy of categories and sub-categories - 0 indexed).
1.663 raeburn 14131:
14132: category (current course category, for which breadcrumb trail is being generated).
14133:
14134: trails (reference to array of breadcrumb trails for each category).
14135:
1.655 raeburn 14136: allitems (reference to hash - key is category key
14137: (format: escaped(name):escaped(parent category):depth in hierarchy).
1.663 raeburn 14138:
1.655 raeburn 14139: parents (array containing containers directories for current category,
14140: back to top level).
14141:
14142: Returns: nothing
14143:
14144: Side effects: populates trails and allitems hash references
14145:
14146: =cut
14147:
14148: sub recurse_categories {
1.665 raeburn 14149: my ($cats,$depth,$category,$trails,$allitems,$parents,$subcats) = @_;
1.655 raeburn 14150: my $shallower = $depth - 1;
14151: if (ref($cats->[$depth]{$category}) eq 'ARRAY') {
14152: for (my $k=0; $k<@{$cats->[$depth]{$category}}; $k++) {
14153: my $name = $cats->[$depth]{$category}[$k];
14154: my $item = &escape($category).':'.&escape($parents->[-1]).':'.$shallower;
14155: my $trailstr = join(' -> ',(@{$parents},$category));
14156: if ($allitems->{$item} eq '') {
14157: push(@{$trails},$trailstr);
14158: $allitems->{$item} = scalar(@{$trails})-1;
14159: }
14160: my $deeper = $depth+1;
14161: push(@{$parents},$category);
1.665 raeburn 14162: if (ref($subcats) eq 'HASH') {
14163: my $subcat = &escape($name).':'.$category.':'.$depth;
14164: for (my $j=@{$parents}; $j>=0; $j--) {
14165: my $higher;
14166: if ($j > 0) {
14167: $higher = &escape($parents->[$j]).':'.
14168: &escape($parents->[$j-1]).':'.$j;
14169: } else {
14170: $higher = &escape($parents->[$j]).'::'.$j;
14171: }
14172: push(@{$subcats->{$higher}},$subcat);
14173: }
14174: }
14175: &recurse_categories($cats,$deeper,$name,$trails,$allitems,$parents,
14176: $subcats);
1.655 raeburn 14177: pop(@{$parents});
14178: }
14179: } else {
14180: my $item = &escape($category).':'.&escape($parents->[-1]).':'.$shallower;
14181: my $trailstr = join(' -> ',(@{$parents},$category));
14182: if ($allitems->{$item} eq '') {
14183: push(@{$trails},$trailstr);
14184: $allitems->{$item} = scalar(@{$trails})-1;
14185: }
14186: }
14187: return;
14188: }
14189:
1.663 raeburn 14190: =pod
14191:
1.1075.2.56 raeburn 14192: =item * &assign_categories_table()
1.663 raeburn 14193:
14194: Create a datatable for display of hierarchical categories in a domain,
14195: with checkboxes to allow a course to be categorized.
14196:
14197: Inputs:
14198:
14199: cathash - reference to hash of categories defined for the domain (from
14200: configuration.db)
14201:
14202: currcat - scalar with an & separated list of categories assigned to a course.
14203:
1.919 raeburn 14204: type - scalar contains course type (Course or Community).
14205:
1.663 raeburn 14206: Returns: $output (markup to be displayed)
14207:
14208: =cut
14209:
14210: sub assign_categories_table {
1.919 raeburn 14211: my ($cathash,$currcat,$type) = @_;
1.663 raeburn 14212: my $output;
14213: if (ref($cathash) eq 'HASH') {
14214: my (@cats,@trails,%allitems,%idx,@jsarray,@path,$maxdepth);
14215: &extract_categories($cathash,\@cats,\@trails,\%allitems,\%idx,\@jsarray);
14216: $maxdepth = scalar(@cats);
14217: if (@cats > 0) {
14218: my $itemcount = 0;
14219: if (ref($cats[0]) eq 'ARRAY') {
14220: my @currcategories;
14221: if ($currcat ne '') {
14222: @currcategories = split('&',$currcat);
14223: }
1.919 raeburn 14224: my $table;
1.663 raeburn 14225: for (my $i=0; $i<@{$cats[0]}; $i++) {
14226: my $parent = $cats[0][$i];
1.919 raeburn 14227: next if ($parent eq 'instcode');
14228: if ($type eq 'Community') {
14229: next unless ($parent eq 'communities');
14230: } else {
14231: next if ($parent eq 'communities');
14232: }
1.663 raeburn 14233: my $css_class = $itemcount%2?' class="LC_odd_row"':'';
14234: my $item = &escape($parent).'::0';
14235: my $checked = '';
14236: if (@currcategories > 0) {
14237: if (grep(/^\Q$item\E$/,@currcategories)) {
1.772 bisitz 14238: $checked = ' checked="checked"';
1.663 raeburn 14239: }
14240: }
1.919 raeburn 14241: my $parent_title = $parent;
14242: if ($parent eq 'communities') {
14243: $parent_title = &mt('Communities');
14244: }
14245: $table .= '<tr '.$css_class.'><td><span class="LC_nobreak">'.
14246: '<input type="checkbox" name="usecategory" value="'.
14247: $item.'"'.$checked.' />'.$parent_title.'</span>'.
14248: '<input type="hidden" name="catname" value="'.$parent.'" /></td>';
1.663 raeburn 14249: my $depth = 1;
14250: push(@path,$parent);
1.919 raeburn 14251: $table .= &assign_category_rows($itemcount,\@cats,$depth,$parent,\@path,\@currcategories);
1.663 raeburn 14252: pop(@path);
1.919 raeburn 14253: $table .= '</tr><tr><td colspan="'.$maxdepth.'" class="LC_row_separator"></td></tr>';
1.663 raeburn 14254: $itemcount ++;
14255: }
1.919 raeburn 14256: if ($itemcount) {
14257: $output = &Apache::loncommon::start_data_table().
14258: $table.
14259: &Apache::loncommon::end_data_table();
14260: }
1.663 raeburn 14261: }
14262: }
14263: }
14264: return $output;
14265: }
14266:
14267: =pod
14268:
1.1075.2.56 raeburn 14269: =item * &assign_category_rows()
1.663 raeburn 14270:
14271: Create a datatable row for display of nested categories in a domain,
14272: with checkboxes to allow a course to be categorized,called recursively.
14273:
14274: Inputs:
14275:
14276: itemcount - track row number for alternating colors
14277:
14278: cats - reference to array of arrays/hashes which encapsulates hierarchy of
14279: categories and subcategories.
14280:
14281: depth - current depth in hierarchy of categories and sub-categories - 0 indexed.
14282:
14283: parent - parent of current category item
14284:
14285: path - Array containing all categories back up through the hierarchy from the
14286: current category to the top level.
14287:
14288: currcategories - reference to array of current categories assigned to the course
14289:
14290: Returns: $output (markup to be displayed).
14291:
14292: =cut
14293:
14294: sub assign_category_rows {
14295: my ($itemcount,$cats,$depth,$parent,$path,$currcategories) = @_;
14296: my ($text,$name,$item,$chgstr);
14297: if (ref($cats) eq 'ARRAY') {
14298: my $maxdepth = scalar(@{$cats});
14299: if (ref($cats->[$depth]) eq 'HASH') {
14300: if (ref($cats->[$depth]{$parent}) eq 'ARRAY') {
14301: my $numchildren = @{$cats->[$depth]{$parent}};
14302: my $css_class = $itemcount%2?' class="LC_odd_row"':'';
1.1075.2.45 raeburn 14303: $text .= '<td><table class="LC_data_table">';
1.663 raeburn 14304: for (my $j=0; $j<$numchildren; $j++) {
14305: $name = $cats->[$depth]{$parent}[$j];
14306: $item = &escape($name).':'.&escape($parent).':'.$depth;
14307: my $deeper = $depth+1;
14308: my $checked = '';
14309: if (ref($currcategories) eq 'ARRAY') {
14310: if (@{$currcategories} > 0) {
14311: if (grep(/^\Q$item\E$/,@{$currcategories})) {
1.772 bisitz 14312: $checked = ' checked="checked"';
1.663 raeburn 14313: }
14314: }
14315: }
1.664 raeburn 14316: $text .= '<tr><td><span class="LC_nobreak"><label>'.
14317: '<input type="checkbox" name="usecategory" value="'.
1.675 raeburn 14318: $item.'"'.$checked.' />'.$name.'</label></span>'.
14319: '<input type="hidden" name="catname" value="'.$name.'" />'.
14320: '</td><td>';
1.663 raeburn 14321: if (ref($path) eq 'ARRAY') {
14322: push(@{$path},$name);
14323: $text .= &assign_category_rows($itemcount,$cats,$deeper,$name,$path,$currcategories);
14324: pop(@{$path});
14325: }
14326: $text .= '</td></tr>';
14327: }
14328: $text .= '</table></td>';
14329: }
14330: }
14331: }
14332: return $text;
14333: }
14334:
1.1075.2.69 raeburn 14335: =pod
14336:
14337: =back
14338:
14339: =cut
14340:
1.655 raeburn 14341: ############################################################
14342: ############################################################
14343:
14344:
1.443 albertel 14345: sub commit_customrole {
1.664 raeburn 14346: my ($udom,$uname,$url,$three,$four,$five,$start,$end,$context) = @_;
1.630 raeburn 14347: my $output = &mt('Assigning custom role').' "'.$five.'" by '.$four.':'.$three.' in '.$url.
1.443 albertel 14348: ($start?', '.&mt('starting').' '.localtime($start):'').
14349: ($end?', ending '.localtime($end):'').': <b>'.
14350: &Apache::lonnet::assigncustomrole(
1.664 raeburn 14351: $udom,$uname,$url,$three,$four,$five,$end,$start,undef,undef,$context).
1.443 albertel 14352: '</b><br />';
14353: return $output;
14354: }
14355:
14356: sub commit_standardrole {
1.1075.2.31 raeburn 14357: my ($udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context,$credits) = @_;
1.541 raeburn 14358: my ($output,$logmsg,$linefeed);
14359: if ($context eq 'auto') {
14360: $linefeed = "\n";
14361: } else {
14362: $linefeed = "<br />\n";
14363: }
1.443 albertel 14364: if ($three eq 'st') {
1.541 raeburn 14365: my $result = &commit_studentrole(\$logmsg,$udom,$uname,$url,$three,$start,$end,
1.1075.2.31 raeburn 14366: $one,$two,$sec,$context,$credits);
1.541 raeburn 14367: if (($result =~ /^error/) || ($result eq 'not_in_class') ||
1.626 raeburn 14368: ($result eq 'unknown_course') || ($result eq 'refused')) {
14369: $output = $logmsg.' '.&mt('Error: ').$result."\n";
1.443 albertel 14370: } else {
1.541 raeburn 14371: $output = $logmsg.$linefeed.&mt('Assigning').' '.$three.' in '.$url.
1.443 albertel 14372: ($start?', '.&mt('starting').' '.localtime($start):'').
1.541 raeburn 14373: ($end?', '.&mt('ending').' '.localtime($end):'').': ';
14374: if ($context eq 'auto') {
14375: $output .= $result.$linefeed.&mt('Add to classlist').': ok';
14376: } else {
14377: $output .= '<b>'.$result.'</b>'.$linefeed.
14378: &mt('Add to classlist').': <b>ok</b>';
14379: }
14380: $output .= $linefeed;
1.443 albertel 14381: }
14382: } else {
14383: $output = &mt('Assigning').' '.$three.' in '.$url.
14384: ($start?', '.&mt('starting').' '.localtime($start):'').
1.541 raeburn 14385: ($end?', '.&mt('ending').' '.localtime($end):'').': ';
1.652 raeburn 14386: my $result = &Apache::lonnet::assignrole($udom,$uname,$url,$three,$end,$start,'','',$context);
1.541 raeburn 14387: if ($context eq 'auto') {
14388: $output .= $result.$linefeed;
14389: } else {
14390: $output .= '<b>'.$result.'</b>'.$linefeed;
14391: }
1.443 albertel 14392: }
14393: return $output;
14394: }
14395:
14396: sub commit_studentrole {
1.1075.2.31 raeburn 14397: my ($logmsg,$udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context,
14398: $credits) = @_;
1.626 raeburn 14399: my ($result,$linefeed,$oldsecurl,$newsecurl);
1.541 raeburn 14400: if ($context eq 'auto') {
14401: $linefeed = "\n";
14402: } else {
14403: $linefeed = '<br />'."\n";
14404: }
1.443 albertel 14405: if (defined($one) && defined($two)) {
14406: my $cid=$one.'_'.$two;
14407: my $oldsec=&Apache::lonnet::getsection($udom,$uname,$cid);
14408: my $secchange = 0;
14409: my $expire_role_result;
14410: my $modify_section_result;
1.628 raeburn 14411: if ($oldsec ne '-1') {
14412: if ($oldsec ne $sec) {
1.443 albertel 14413: $secchange = 1;
1.628 raeburn 14414: my $now = time;
1.443 albertel 14415: my $uurl='/'.$cid;
14416: $uurl=~s/\_/\//g;
14417: if ($oldsec) {
14418: $uurl.='/'.$oldsec;
14419: }
1.626 raeburn 14420: $oldsecurl = $uurl;
1.628 raeburn 14421: $expire_role_result =
1.652 raeburn 14422: &Apache::lonnet::assignrole($udom,$uname,$uurl,'st',$now,'','',$context);
1.628 raeburn 14423: if ($env{'request.course.sec'} ne '') {
14424: if ($expire_role_result eq 'refused') {
14425: my @roles = ('st');
14426: my @statuses = ('previous');
14427: my @roledoms = ($one);
14428: my $withsec = 1;
14429: my %roleshash =
14430: &Apache::lonnet::get_my_roles($uname,$udom,'userroles',
14431: \@statuses,\@roles,\@roledoms,$withsec);
14432: if (defined ($roleshash{$two.':'.$one.':st:'.$oldsec})) {
14433: my ($oldstart,$oldend) =
14434: split(':',$roleshash{$two.':'.$one.':st:'.$oldsec});
14435: if ($oldend > 0 && $oldend <= $now) {
14436: $expire_role_result = 'ok';
14437: }
14438: }
14439: }
14440: }
1.443 albertel 14441: $result = $expire_role_result;
14442: }
14443: }
14444: if (($expire_role_result eq 'ok') || ($secchange == 0)) {
1.1075.2.31 raeburn 14445: $modify_section_result =
14446: &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,
14447: undef,undef,undef,$sec,
14448: $end,$start,'','',$cid,
14449: '',$context,$credits);
1.443 albertel 14450: if ($modify_section_result =~ /^ok/) {
14451: if ($secchange == 1) {
1.628 raeburn 14452: if ($sec eq '') {
14453: $$logmsg .= &mt('Section for [_1] switched from (possibly expired) old section: [_2] to student role without a section.',$uname,$oldsec).$linefeed;
14454: } else {
14455: $$logmsg .= &mt('Section for [_1] switched from (possibly expired) old section: [_2] to new section: [_3].',$uname,$oldsec,$sec).$linefeed;
14456: }
1.443 albertel 14457: } elsif ($oldsec eq '-1') {
1.628 raeburn 14458: if ($sec eq '') {
14459: $$logmsg .= &mt('New student role without a section for [_1] in course [_2].',$uname,$cid).$linefeed;
14460: } else {
14461: $$logmsg .= &mt('New student role for [_1] in section [_2] in course [_3].',$uname,$sec,$cid).$linefeed;
14462: }
1.443 albertel 14463: } else {
1.628 raeburn 14464: if ($sec eq '') {
14465: $$logmsg .= &mt('Student [_1] assigned to course [_2] without a section.',$uname,$cid).$linefeed;
14466: } else {
14467: $$logmsg .= &mt('Student [_1] assigned to section [_2] in course [_3].',$uname,$sec,$cid).$linefeed;
14468: }
1.443 albertel 14469: }
14470: } else {
1.628 raeburn 14471: if ($secchange) {
14472: $$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;
14473: } else {
14474: $$logmsg .= &mt('Error when attempting to modify role for [_1] for section: "[_2]" in course [_3] -error:',$uname,$sec,$cid).' '.$modify_section_result.$linefeed;
14475: }
1.443 albertel 14476: }
14477: $result = $modify_section_result;
14478: } elsif ($secchange == 1) {
1.628 raeburn 14479: if ($oldsec eq '') {
1.1075.2.20 raeburn 14480: $$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 14481: } else {
14482: $$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;
14483: }
1.626 raeburn 14484: if ($expire_role_result eq 'refused') {
14485: my $newsecurl = '/'.$cid;
14486: $newsecurl =~ s/\_/\//g;
14487: if ($sec ne '') {
14488: $newsecurl.='/'.$sec;
14489: }
14490: if (&Apache::lonnet::allowed('cst',$newsecurl) && !(&Apache::lonnet::allowed('cst',$oldsecurl))) {
14491: if ($sec eq '') {
14492: $$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;
14493: } else {
14494: $$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;
14495: }
14496: }
14497: }
1.443 albertel 14498: }
14499: } else {
1.626 raeburn 14500: $$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 14501: $result = "error: incomplete course id\n";
14502: }
14503: return $result;
14504: }
14505:
1.1075.2.25 raeburn 14506: sub show_role_extent {
14507: my ($scope,$context,$role) = @_;
14508: $scope =~ s{^/}{};
14509: my @courseroles = &Apache::lonuserutils::roles_by_context('course',1);
14510: push(@courseroles,'co');
14511: my @authorroles = &Apache::lonuserutils::roles_by_context('author');
14512: if (($context eq 'course') || (grep(/^\Q$role\E/,@courseroles))) {
14513: $scope =~ s{/}{_};
14514: return '<span class="LC_cusr_emph">'.$env{'course.'.$scope.'.description'}.'</span>';
14515: } elsif (($context eq 'author') || (grep(/^\Q$role\E/,@authorroles))) {
14516: my ($audom,$auname) = split(/\//,$scope);
14517: return &mt('[_1] Author Space','<span class="LC_cusr_emph">'.
14518: &Apache::loncommon::plainname($auname,$audom).'</span>');
14519: } else {
14520: $scope =~ s{/$}{};
14521: return &mt('Domain: [_1]','<span class="LC_cusr_emph">'.
14522: &Apache::lonnet::domain($scope,'description').'</span>');
14523: }
14524: }
14525:
1.443 albertel 14526: ############################################################
14527: ############################################################
14528:
1.566 albertel 14529: sub check_clone {
1.578 raeburn 14530: my ($args,$linefeed) = @_;
1.566 albertel 14531: my $cloneid='/'.$args->{'clonedomain'}.'/'.$args->{'clonecourse'};
14532: my ($clonecrsudom,$clonecrsunum)= &LONCAPA::split_courseid($cloneid);
14533: my $clonehome=&Apache::lonnet::homeserver($clonecrsunum,$clonecrsudom);
14534: my $clonemsg;
14535: my $can_clone = 0;
1.944 raeburn 14536: my $lctype = lc($args->{'crstype'});
1.908 raeburn 14537: if ($lctype ne 'community') {
14538: $lctype = 'course';
14539: }
1.566 albertel 14540: if ($clonehome eq 'no_host') {
1.944 raeburn 14541: if ($args->{'crstype'} eq 'Community') {
1.908 raeburn 14542: $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'});
14543: } else {
14544: $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'});
14545: }
1.566 albertel 14546: } else {
14547: my %clonedesc = &Apache::lonnet::coursedescription($cloneid,{'one_time' => 1});
1.944 raeburn 14548: if ($args->{'crstype'} eq 'Community') {
1.908 raeburn 14549: if ($clonedesc{'type'} ne 'Community') {
14550: $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'});
14551: return ($can_clone, $clonemsg, $cloneid, $clonehome);
14552: }
14553: }
1.882 raeburn 14554: if (($env{'request.role.domain'} eq $args->{'clonedomain'}) &&
14555: (&Apache::lonnet::allowed('ccc',$env{'request.role.domain'}))) {
1.566 albertel 14556: $can_clone = 1;
14557: } else {
1.1075.2.95 raeburn 14558: my %clonehash = &Apache::lonnet::get('environment',['cloners','internal.coursecode'],
1.566 albertel 14559: $args->{'clonedomain'},$args->{'clonecourse'});
1.1075.2.95 raeburn 14560: if ($clonehash{'cloners'} eq '') {
14561: my %domdefs = &Apache::lonnet::get_domain_defaults($args->{'course_domain'});
14562: if ($domdefs{'canclone'}) {
14563: unless ($domdefs{'canclone'} eq 'none') {
14564: if ($domdefs{'canclone'} eq 'domain') {
14565: if ($args->{'ccdomain'} eq $args->{'clonedomain'}) {
14566: $can_clone = 1;
14567: }
14568: } elsif (($clonehash{'internal.coursecode'}) && ($args->{'crscode'}) &&
14569: ($args->{'clonedomain'} eq $args->{'course_domain'})) {
14570: if (&Apache::lonnet::default_instcode_cloning($args->{'clonedomain'},$domdefs{'canclone'},
14571: $clonehash{'internal.coursecode'},$args->{'crscode'})) {
14572: $can_clone = 1;
14573: }
14574: }
14575: }
1.908 raeburn 14576: }
1.1075.2.95 raeburn 14577: } else {
14578: my @cloners = split(/,/,$clonehash{'cloners'});
14579: if (grep(/^\*$/,@cloners)) {
1.942 raeburn 14580: $can_clone = 1;
1.1075.2.95 raeburn 14581: } elsif (grep(/^\*\:\Q$args->{'ccdomain'}\E$/,@cloners)) {
1.942 raeburn 14582: $can_clone = 1;
1.1075.2.96 raeburn 14583: } elsif (grep(/^\Q$args->{'ccuname'}\E:\Q$args->{'ccdomain'}\E$/,@cloners)) {
14584: $can_clone = 1;
1.1075.2.95 raeburn 14585: }
14586: unless ($can_clone) {
1.1075.2.96 raeburn 14587: if (($clonehash{'internal.coursecode'}) && ($args->{'crscode'}) &&
14588: ($args->{'clonedomain'} eq $args->{'course_domain'})) {
1.1075.2.95 raeburn 14589: my (%gotdomdefaults,%gotcodedefaults);
14590: foreach my $cloner (@cloners) {
14591: if (($cloner ne '*') && ($cloner !~ /^\*\:$match_domain$/) &&
14592: ($cloner !~ /^$match_username\:$match_domain$/) && ($cloner ne '')) {
14593: my (%codedefaults,@code_order);
14594: if (ref($gotcodedefaults{$args->{'clonedomain'}}) eq 'HASH') {
14595: if (ref($gotcodedefaults{$args->{'clonedomain'}}{'defaults'}) eq 'HASH') {
14596: %codedefaults = %{$gotcodedefaults{$args->{'clonedomain'}}{'defaults'}};
14597: }
14598: if (ref($gotcodedefaults{$args->{'clonedomain'}}{'order'}) eq 'ARRAY') {
14599: @code_order = @{$gotcodedefaults{$args->{'clonedomain'}}{'order'}};
14600: }
14601: } else {
14602: &Apache::lonnet::auto_instcode_defaults($args->{'clonedomain'},
14603: \%codedefaults,
14604: \@code_order);
14605: $gotcodedefaults{$args->{'clonedomain'}}{'defaults'} = \%codedefaults;
14606: $gotcodedefaults{$args->{'clonedomain'}}{'order'} = \@code_order;
14607: }
14608: if (@code_order > 0) {
14609: if (&Apache::lonnet::check_instcode_cloning(\%codedefaults,\@code_order,
14610: $cloner,$clonehash{'internal.coursecode'},
14611: $args->{'crscode'})) {
14612: $can_clone = 1;
14613: last;
14614: }
14615: }
14616: }
14617: }
14618: }
1.1075.2.96 raeburn 14619: }
14620: }
14621: unless ($can_clone) {
14622: my $ccrole = 'cc';
14623: if ($args->{'crstype'} eq 'Community') {
14624: $ccrole = 'co';
14625: }
14626: my %roleshash =
14627: &Apache::lonnet::get_my_roles($args->{'ccuname'},
14628: $args->{'ccdomain'},
14629: 'userroles',['active'],[$ccrole],
14630: [$args->{'clonedomain'}]);
14631: if ($roleshash{$args->{'clonecourse'}.':'.$args->{'clonedomain'}.':'.$ccrole}) {
14632: $can_clone = 1;
14633: } elsif (&Apache::lonnet::is_course_owner($args->{'clonedomain'},$args->{'clonecourse'},
14634: $args->{'ccuname'},$args->{'ccdomain'})) {
14635: $can_clone = 1;
1.1075.2.95 raeburn 14636: }
14637: }
14638: unless ($can_clone) {
14639: if ($args->{'crstype'} eq 'Community') {
14640: $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'});
14641: } else {
14642: $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'});
1.578 raeburn 14643: }
1.566 albertel 14644: }
1.578 raeburn 14645: }
1.566 albertel 14646: }
14647: return ($can_clone, $clonemsg, $cloneid, $clonehome);
14648: }
14649:
1.444 albertel 14650: sub construct_course {
1.1075.2.59 raeburn 14651: my ($args,$logmsg,$courseid,$crsudom,$crsunum,$udom,$uname,$context,$cnum,$category,$coderef) = @_;
1.444 albertel 14652: my $outcome;
1.541 raeburn 14653: my $linefeed = '<br />'."\n";
14654: if ($context eq 'auto') {
14655: $linefeed = "\n";
14656: }
1.566 albertel 14657:
14658: #
14659: # Are we cloning?
14660: #
14661: my ($can_clone, $clonemsg, $cloneid, $clonehome);
14662: if (($args->{'clonecourse'}) && ($args->{'clonedomain'})) {
1.578 raeburn 14663: ($can_clone, $clonemsg, $cloneid, $clonehome) = &check_clone($args,$linefeed);
1.566 albertel 14664: if ($context ne 'auto') {
1.578 raeburn 14665: if ($clonemsg ne '') {
14666: $clonemsg = '<span class="LC_error">'.$clonemsg.'</span>';
14667: }
1.566 albertel 14668: }
14669: $outcome .= $clonemsg.$linefeed;
14670:
14671: if (!$can_clone) {
14672: return (0,$outcome);
14673: }
14674: }
14675:
1.444 albertel 14676: #
14677: # Open course
14678: #
14679: my $crstype = lc($args->{'crstype'});
14680: my %cenv=();
14681: $$courseid=&Apache::lonnet::createcourse($args->{'course_domain'},
14682: $args->{'cdescr'},
14683: $args->{'curl'},
14684: $args->{'course_home'},
14685: $args->{'nonstandard'},
14686: $args->{'crscode'},
14687: $args->{'ccuname'}.':'.
14688: $args->{'ccdomain'},
1.882 raeburn 14689: $args->{'crstype'},
1.885 raeburn 14690: $cnum,$context,$category);
1.444 albertel 14691:
14692: # Note: The testing routines depend on this being output; see
14693: # Utils::Course. This needs to at least be output as a comment
14694: # if anyone ever decides to not show this, and Utils::Course::new
14695: # will need to be suitably modified.
1.541 raeburn 14696: $outcome .= &mt('New LON-CAPA [_1] ID: [_2]',$crstype,$$courseid).$linefeed;
1.943 raeburn 14697: if ($$courseid =~ /^error:/) {
14698: return (0,$outcome);
14699: }
14700:
1.444 albertel 14701: #
14702: # Check if created correctly
14703: #
1.479 albertel 14704: ($$crsudom,$$crsunum)= &LONCAPA::split_courseid($$courseid);
1.444 albertel 14705: my $crsuhome=&Apache::lonnet::homeserver($$crsunum,$$crsudom);
1.943 raeburn 14706: if ($crsuhome eq 'no_host') {
14707: $outcome .= &mt('Course creation failed, unrecognized course home server.').$linefeed;
14708: return (0,$outcome);
14709: }
1.541 raeburn 14710: $outcome .= &mt('Created on').': '.$crsuhome.$linefeed;
1.566 albertel 14711:
1.444 albertel 14712: #
1.566 albertel 14713: # Do the cloning
14714: #
14715: if ($can_clone && $cloneid) {
14716: $clonemsg = &mt('Cloning [_1] from [_2]',$crstype,$clonehome);
14717: if ($context ne 'auto') {
14718: $clonemsg = '<span class="LC_success">'.$clonemsg.'</span>';
14719: }
14720: $outcome .= $clonemsg.$linefeed;
14721: my %oldcenv=&Apache::lonnet::dump('environment',$$crsudom,$$crsunum);
1.444 albertel 14722: # Copy all files
1.637 www 14723: &Apache::lonclonecourse::copycoursefiles($cloneid,$$courseid,$args->{'datemode'},$args->{'dateshift'});
1.444 albertel 14724: # Restore URL
1.566 albertel 14725: $cenv{'url'}=$oldcenv{'url'};
1.444 albertel 14726: # Restore title
1.566 albertel 14727: $cenv{'description'}=$oldcenv{'description'};
1.955 raeburn 14728: # Restore creation date, creator and creation context.
14729: $cenv{'internal.created'}=$oldcenv{'internal.created'};
14730: $cenv{'internal.creator'}=$oldcenv{'internal.creator'};
14731: $cenv{'internal.creationcontext'}=$oldcenv{'internal.creationcontext'};
1.444 albertel 14732: # Mark as cloned
1.566 albertel 14733: $cenv{'clonedfrom'}=$cloneid;
1.638 www 14734: # Need to clone grading mode
14735: my %newenv=&Apache::lonnet::get('environment',['grading'],$$crsudom,$$crsunum);
14736: $cenv{'grading'}=$newenv{'grading'};
14737: # Do not clone these environment entries
14738: &Apache::lonnet::del('environment',
14739: ['default_enrollment_start_date',
14740: 'default_enrollment_end_date',
14741: 'question.email',
14742: 'policy.email',
14743: 'comment.email',
14744: 'pch.users.denied',
1.725 raeburn 14745: 'plc.users.denied',
14746: 'hidefromcat',
1.1075.2.36 raeburn 14747: 'checkforpriv',
1.1075.2.59 raeburn 14748: 'categories',
14749: 'internal.uniquecode'],
1.638 www 14750: $$crsudom,$$crsunum);
1.1075.2.63 raeburn 14751: if ($args->{'textbook'}) {
14752: $cenv{'internal.textbook'} = $args->{'textbook'};
14753: }
1.444 albertel 14754: }
1.566 albertel 14755:
1.444 albertel 14756: #
14757: # Set environment (will override cloned, if existing)
14758: #
14759: my @sections = ();
14760: my @xlists = ();
14761: if ($args->{'crstype'}) {
14762: $cenv{'type'}=$args->{'crstype'};
14763: }
14764: if ($args->{'crsid'}) {
14765: $cenv{'courseid'}=$args->{'crsid'};
14766: }
14767: if ($args->{'crscode'}) {
14768: $cenv{'internal.coursecode'}=$args->{'crscode'};
14769: }
14770: if ($args->{'crsquota'} ne '') {
14771: $cenv{'internal.coursequota'}=$args->{'crsquota'};
14772: } else {
14773: $cenv{'internal.coursequota'}=$args->{'crsquota'} = 20;
14774: }
14775: if ($args->{'ccuname'}) {
14776: $cenv{'internal.courseowner'} = $args->{'ccuname'}.
14777: ':'.$args->{'ccdomain'};
14778: } else {
14779: $cenv{'internal.courseowner'} = $args->{'curruser'};
14780: }
1.1075.2.31 raeburn 14781: if ($args->{'defaultcredits'}) {
14782: $cenv{'internal.defaultcredits'} = $args->{'defaultcredits'};
14783: }
1.444 albertel 14784: my @badclasses = (); # Used to accumulate sections/crosslistings that did not pass classlist access check for course owner.
14785: if ($args->{'crssections'}) {
14786: $cenv{'internal.sectionnums'} = '';
14787: if ($args->{'crssections'} =~ m/,/) {
14788: @sections = split/,/,$args->{'crssections'};
14789: } else {
14790: $sections[0] = $args->{'crssections'};
14791: }
14792: if (@sections > 0) {
14793: foreach my $item (@sections) {
14794: my ($sec,$gp) = split/:/,$item;
14795: my $class = $args->{'crscode'}.$sec;
14796: my $addcheck = &Apache::lonnet::auto_new_course($$crsunum,$$crsudom,$class,$cenv{'internal.courseowner'});
14797: $cenv{'internal.sectionnums'} .= $item.',';
14798: unless ($addcheck eq 'ok') {
14799: push @badclasses, $class;
14800: }
14801: }
14802: $cenv{'internal.sectionnums'} =~ s/,$//;
14803: }
14804: }
14805: # do not hide course coordinator from staff listing,
14806: # even if privileged
14807: $cenv{'nothideprivileged'}=$args->{'ccuname'}.':'.$args->{'ccdomain'};
1.1075.2.36 raeburn 14808: # add course coordinator's domain to domains to check for privileged users
14809: # if different to course domain
14810: if ($$crsudom ne $args->{'ccdomain'}) {
14811: $cenv{'checkforpriv'} = $args->{'ccdomain'};
14812: }
1.444 albertel 14813: # add crosslistings
14814: if ($args->{'crsxlist'}) {
14815: $cenv{'internal.crosslistings'}='';
14816: if ($args->{'crsxlist'} =~ m/,/) {
14817: @xlists = split/,/,$args->{'crsxlist'};
14818: } else {
14819: $xlists[0] = $args->{'crsxlist'};
14820: }
14821: if (@xlists > 0) {
14822: foreach my $item (@xlists) {
14823: my ($xl,$gp) = split/:/,$item;
14824: my $addcheck = &Apache::lonnet::auto_new_course($$crsunum,$$crsudom,$xl,$cenv{'internal.courseowner'});
14825: $cenv{'internal.crosslistings'} .= $item.',';
14826: unless ($addcheck eq 'ok') {
14827: push @badclasses, $xl;
14828: }
14829: }
14830: $cenv{'internal.crosslistings'} =~ s/,$//;
14831: }
14832: }
14833: if ($args->{'autoadds'}) {
14834: $cenv{'internal.autoadds'}=$args->{'autoadds'};
14835: }
14836: if ($args->{'autodrops'}) {
14837: $cenv{'internal.autodrops'}=$args->{'autodrops'};
14838: }
14839: # check for notification of enrollment changes
14840: my @notified = ();
14841: if ($args->{'notify_owner'}) {
14842: if ($args->{'ccuname'} ne '') {
14843: push(@notified,$args->{'ccuname'}.':'.$args->{'ccdomain'});
14844: }
14845: }
14846: if ($args->{'notify_dc'}) {
14847: if ($uname ne '') {
1.630 raeburn 14848: push(@notified,$uname.':'.$udom);
1.444 albertel 14849: }
14850: }
14851: if (@notified > 0) {
14852: my $notifylist;
14853: if (@notified > 1) {
14854: $notifylist = join(',',@notified);
14855: } else {
14856: $notifylist = $notified[0];
14857: }
14858: $cenv{'internal.notifylist'} = $notifylist;
14859: }
14860: if (@badclasses > 0) {
14861: my %lt=&Apache::lonlocal::texthash(
14862: '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',
14863: 'dnhr' => 'does not have rights to access enrollment in these classes',
14864: 'adby' => 'as determined by the policies of your institution on access to official classlists'
14865: );
1.541 raeburn 14866: my $badclass_msg = $cenv{'internal.courseowner'}.') - '.$lt{'dnhr'}.
14867: ' ('.$lt{'adby'}.')';
14868: if ($context eq 'auto') {
14869: $outcome .= $badclass_msg.$linefeed;
1.566 albertel 14870: $outcome .= '<div class="LC_warning">'.$badclass_msg.$linefeed.'<ul>'."\n";
1.541 raeburn 14871: foreach my $item (@badclasses) {
14872: if ($context eq 'auto') {
14873: $outcome .= " - $item\n";
14874: } else {
14875: $outcome .= "<li>$item</li>\n";
14876: }
14877: }
14878: if ($context eq 'auto') {
14879: $outcome .= $linefeed;
14880: } else {
1.566 albertel 14881: $outcome .= "</ul><br /><br /></div>\n";
1.541 raeburn 14882: }
14883: }
1.444 albertel 14884: }
14885: if ($args->{'no_end_date'}) {
14886: $args->{'endaccess'} = 0;
14887: }
14888: $cenv{'internal.autostart'}=$args->{'enrollstart'};
14889: $cenv{'internal.autoend'}=$args->{'enrollend'};
14890: $cenv{'default_enrollment_start_date'}=$args->{'startaccess'};
14891: $cenv{'default_enrollment_end_date'}=$args->{'endaccess'};
14892: if ($args->{'showphotos'}) {
14893: $cenv{'internal.showphotos'}=$args->{'showphotos'};
14894: }
14895: $cenv{'internal.authtype'} = $args->{'authtype'};
14896: $cenv{'internal.autharg'} = $args->{'autharg'};
14897: if ( ($cenv{'internal.authtype'} =~ /^krb/) && ($cenv{'internal.autoadds'} == 1)) {
14898: if (! defined($cenv{'internal.autharg'}) || $cenv{'internal.autharg'} eq '') {
1.541 raeburn 14899: 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');
14900: if ($context eq 'auto') {
14901: $outcome .= $krb_msg;
14902: } else {
1.566 albertel 14903: $outcome .= '<span class="LC_error">'.$krb_msg.'</span>';
1.541 raeburn 14904: }
14905: $outcome .= $linefeed;
1.444 albertel 14906: }
14907: }
14908: if (($args->{'ccdomain'}) && ($args->{'ccuname'})) {
14909: if ($args->{'setpolicy'}) {
14910: $cenv{'policy.email'}=$args->{'ccuname'}.':'.$args->{'ccdomain'};
14911: }
14912: if ($args->{'setcontent'}) {
14913: $cenv{'question.email'}=$args->{'ccuname'}.':'.$args->{'ccdomain'};
14914: }
1.1075.2.110 raeburn 14915: if ($args->{'setcomment'}) {
14916: $cenv{'comment.email'}=$args->{'ccuname'}.':'.$args->{'ccdomain'};
14917: }
1.444 albertel 14918: }
14919: if ($args->{'reshome'}) {
14920: $cenv{'reshome'}=$args->{'reshome'}.'/';
14921: $cenv{'reshome'}=~s/\/+$/\//;
14922: }
14923: #
14924: # course has keyed access
14925: #
14926: if ($args->{'setkeys'}) {
14927: $cenv{'keyaccess'}='yes';
14928: }
14929: # if specified, key authority is not course, but user
14930: # only active if keyaccess is yes
14931: if ($args->{'keyauth'}) {
1.487 albertel 14932: my ($user,$domain) = split(':',$args->{'keyauth'});
14933: $user = &LONCAPA::clean_username($user);
14934: $domain = &LONCAPA::clean_username($domain);
1.488 foxr 14935: if ($user ne '' && $domain ne '') {
1.487 albertel 14936: $cenv{'keyauth'}=$user.':'.$domain;
1.444 albertel 14937: }
14938: }
14939:
1.1075.2.59 raeburn 14940: #
14941: # generate and store uniquecode (available to course requester), if course should have one.
14942: #
14943: if ($args->{'uniquecode'}) {
14944: my ($code,$error) = &make_unique_code($$crsudom,$$crsunum);
14945: if ($code) {
14946: $cenv{'internal.uniquecode'} = $code;
14947: my %crsinfo =
14948: &Apache::lonnet::courseiddump($$crsudom,'.',1,'.','.',$$crsunum,undef,undef,'.');
14949: if (ref($crsinfo{$$crsudom.'_'.$$crsunum}) eq 'HASH') {
14950: $crsinfo{$$crsudom.'_'.$$crsunum}{'uniquecode'} = $code;
14951: my $putres = &Apache::lonnet::courseidput($$crsudom,\%crsinfo,$crsuhome,'notime');
14952: }
14953: if (ref($coderef)) {
14954: $$coderef = $code;
14955: }
14956: }
14957: }
14958:
1.444 albertel 14959: if ($args->{'disresdis'}) {
14960: $cenv{'pch.roles.denied'}='st';
14961: }
14962: if ($args->{'disablechat'}) {
14963: $cenv{'plc.roles.denied'}='st';
14964: }
14965:
14966: # Record we've not yet viewed the Course Initialization Helper for this
14967: # course
14968: $cenv{'course.helper.not.run'} = 1;
14969: #
14970: # Use new Randomseed
14971: #
14972: $cenv{'rndseed'}=&Apache::lonnet::latest_rnd_algorithm_id();;
14973: $cenv{'receiptalg'}=&Apache::lonnet::latest_receipt_algorithm_id();;
14974: #
14975: # The encryption code and receipt prefix for this course
14976: #
14977: $cenv{'internal.encseed'}=$Apache::lonnet::perlvar{'lonReceipt'}.$$.time.int(rand(9999));
14978: $cenv{'internal.encpref'}=100+int(9*rand(99));
14979: #
14980: # By default, use standard grading
14981: if (!defined($cenv{'grading'})) { $cenv{'grading'} = 'standard'; }
14982:
1.541 raeburn 14983: $outcome .= $linefeed.&mt('Setting environment').': '.
14984: &Apache::lonnet::put('environment',\%cenv,$$crsudom,$$crsunum).$linefeed;
1.444 albertel 14985: #
14986: # Open all assignments
14987: #
14988: if ($args->{'openall'}) {
14989: my $storeunder=$$crsudom.'_'.$$crsunum.'.0.opendate';
14990: my %storecontent = ($storeunder => time,
14991: $storeunder.'.type' => 'date_start');
14992:
14993: $outcome .= &mt('Opening all assignments').': '.&Apache::lonnet::cput
1.541 raeburn 14994: ('resourcedata',\%storecontent,$$crsudom,$$crsunum).$linefeed;
1.444 albertel 14995: }
14996: #
14997: # Set first page
14998: #
14999: unless (($args->{'nonstandard'}) || ($args->{'firstres'} eq 'blank')
15000: || ($cloneid)) {
1.445 albertel 15001: use LONCAPA::map;
1.444 albertel 15002: $outcome .= &mt('Setting first resource').': ';
1.445 albertel 15003:
15004: my $map = '/uploaded/'.$$crsudom.'/'.$$crsunum.'/default.sequence';
15005: my ($errtext,$fatal)=&LONCAPA::map::mapread($map);
15006:
1.444 albertel 15007: $outcome .= ($fatal?$errtext:'read ok').' - ';
15008: my $title; my $url;
15009: if ($args->{'firstres'} eq 'syl') {
1.690 bisitz 15010: $title=&mt('Syllabus');
1.444 albertel 15011: $url='/public/'.$$crsudom.'/'.$$crsunum.'/syllabus';
15012: } else {
1.963 raeburn 15013: $title=&mt('Table of Contents');
1.444 albertel 15014: $url='/adm/navmaps';
15015: }
1.445 albertel 15016:
15017: $LONCAPA::map::resources[1]=$title.':'.$url.':false:start:res';
15018: (my $outtext,$errtext) = &LONCAPA::map::storemap($map,1);
15019:
15020: if ($errtext) { $fatal=2; }
1.541 raeburn 15021: $outcome .= ($fatal?$errtext:'write ok').$linefeed;
1.444 albertel 15022: }
1.566 albertel 15023:
15024: return (1,$outcome);
1.444 albertel 15025: }
15026:
1.1075.2.59 raeburn 15027: sub make_unique_code {
15028: my ($cdom,$cnum) = @_;
15029: # get lock on uniquecodes db
15030: my $lockhash = {
15031: $cnum."\0".'uniquecodes' => $env{'user.name'}.
15032: ':'.$env{'user.domain'},
15033: };
15034: my $tries = 0;
15035: my $gotlock = &Apache::lonnet::newput_dom('uniquecodes',$lockhash,$cdom);
15036: my ($code,$error);
15037:
15038: while (($gotlock ne 'ok') && ($tries<3)) {
15039: $tries ++;
15040: sleep 1;
15041: $gotlock = &Apache::lonnet::newput_dom('uniquecodes',$lockhash,$cdom);
15042: }
15043: if ($gotlock eq 'ok') {
15044: my %currcodes = &Apache::lonnet::dump_dom('uniquecodes',$cdom);
15045: my $gotcode;
15046: my $attempts = 0;
15047: while ((!$gotcode) && ($attempts < 100)) {
15048: $code = &generate_code();
15049: if (!exists($currcodes{$code})) {
15050: $gotcode = 1;
15051: unless (&Apache::lonnet::newput_dom('uniquecodes',{ $code => $cnum },$cdom) eq 'ok') {
15052: $error = 'nostore';
15053: }
15054: }
15055: $attempts ++;
15056: }
15057: my @del_lock = ($cnum."\0".'uniquecodes');
15058: my $dellockoutcome = &Apache::lonnet::del_dom('uniquecodes',\@del_lock,$cdom);
15059: } else {
15060: $error = 'nolock';
15061: }
15062: return ($code,$error);
15063: }
15064:
15065: sub generate_code {
15066: my $code;
15067: my @letts = qw(B C D G H J K M N P Q R S T V W X Z);
15068: for (my $i=0; $i<6; $i++) {
15069: my $lettnum = int (rand 2);
15070: my $item = '';
15071: if ($lettnum) {
15072: $item = $letts[int( rand(18) )];
15073: } else {
15074: $item = 1+int( rand(8) );
15075: }
15076: $code .= $item;
15077: }
15078: return $code;
15079: }
15080:
1.444 albertel 15081: ############################################################
15082: ############################################################
15083:
1.953 droeschl 15084: #SD
15085: # only Community and Course, or anything else?
1.378 raeburn 15086: sub course_type {
15087: my ($cid) = @_;
15088: if (!defined($cid)) {
15089: $cid = $env{'request.course.id'};
15090: }
1.404 albertel 15091: if (defined($env{'course.'.$cid.'.type'})) {
15092: return $env{'course.'.$cid.'.type'};
1.378 raeburn 15093: } else {
15094: return 'Course';
1.377 raeburn 15095: }
15096: }
1.156 albertel 15097:
1.406 raeburn 15098: sub group_term {
15099: my $crstype = &course_type();
15100: my %names = (
15101: 'Course' => 'group',
1.865 raeburn 15102: 'Community' => 'group',
1.406 raeburn 15103: );
15104: return $names{$crstype};
15105: }
15106:
1.902 raeburn 15107: sub course_types {
1.1075.2.59 raeburn 15108: my @types = ('official','unofficial','community','textbook');
1.902 raeburn 15109: my %typename = (
15110: official => 'Official course',
15111: unofficial => 'Unofficial course',
15112: community => 'Community',
1.1075.2.59 raeburn 15113: textbook => 'Textbook course',
1.902 raeburn 15114: );
15115: return (\@types,\%typename);
15116: }
15117:
1.156 albertel 15118: sub icon {
15119: my ($file)=@_;
1.505 albertel 15120: my $curfext = lc((split(/\./,$file))[-1]);
1.168 albertel 15121: my $iconname=$Apache::lonnet::perlvar{'lonIconsURL'}.'/unknown.gif';
1.156 albertel 15122: my $embstyle = &Apache::loncommon::fileembstyle($curfext);
1.168 albertel 15123: if (!(!defined($embstyle) || $embstyle eq 'unk' || $embstyle eq 'hdn')) {
15124: if (-e $Apache::lonnet::perlvar{'lonDocRoot'}.'/'.
15125: $Apache::lonnet::perlvar{'lonIconsURL'}.'/'.
15126: $curfext.".gif") {
15127: $iconname=$Apache::lonnet::perlvar{'lonIconsURL'}.'/'.
15128: $curfext.".gif";
15129: }
15130: }
1.249 albertel 15131: return &lonhttpdurl($iconname);
1.154 albertel 15132: }
1.84 albertel 15133:
1.575 albertel 15134: sub lonhttpdurl {
1.692 www 15135: #
15136: # Had been used for "small fry" static images on separate port 8080.
15137: # Modify here if lightweight http functionality desired again.
15138: # Currently eliminated due to increasing firewall issues.
15139: #
1.575 albertel 15140: my ($url)=@_;
1.692 www 15141: return $url;
1.215 albertel 15142: }
15143:
1.213 albertel 15144: sub connection_aborted {
15145: my ($r)=@_;
15146: $r->print(" ");$r->rflush();
15147: my $c = $r->connection;
15148: return $c->aborted();
15149: }
15150:
1.221 foxr 15151: # Escapes strings that may have embedded 's that will be put into
1.222 foxr 15152: # strings as 'strings'.
15153: sub escape_single {
1.221 foxr 15154: my ($input) = @_;
1.223 albertel 15155: $input =~ s/\\/\\\\/g; # Escape the \'s..(must be first)>
1.221 foxr 15156: $input =~ s/\'/\\\'/g; # Esacpe the 's....
15157: return $input;
15158: }
1.223 albertel 15159:
1.222 foxr 15160: # Same as escape_single, but escape's "'s This
15161: # can be used for "strings"
15162: sub escape_double {
15163: my ($input) = @_;
15164: $input =~ s/\\/\\\\/g; # Escape the /'s..(must be first)>
15165: $input =~ s/\"/\\\"/g; # Esacpe the "s....
15166: return $input;
15167: }
1.223 albertel 15168:
1.222 foxr 15169: # Escapes the last element of a full URL.
15170: sub escape_url {
15171: my ($url) = @_;
1.238 raeburn 15172: my @urlslices = split(/\//, $url,-1);
1.369 www 15173: my $lastitem = &escape(pop(@urlslices));
1.1075.2.83 raeburn 15174: return &HTML::Entities::encode(join('/',@urlslices),"'").'/'.$lastitem;
1.222 foxr 15175: }
1.462 albertel 15176:
1.820 raeburn 15177: sub compare_arrays {
15178: my ($arrayref1,$arrayref2) = @_;
15179: my (@difference,%count);
15180: @difference = ();
15181: %count = ();
15182: if ((ref($arrayref1) eq 'ARRAY') && (ref($arrayref2) eq 'ARRAY')) {
15183: foreach my $element (@{$arrayref1}, @{$arrayref2}) { $count{$element}++; }
15184: foreach my $element (keys(%count)) {
15185: if ($count{$element} == 1) {
15186: push(@difference,$element);
15187: }
15188: }
15189: }
15190: return @difference;
15191: }
15192:
1.817 bisitz 15193: # -------------------------------------------------------- Initialize user login
1.462 albertel 15194: sub init_user_environment {
1.463 albertel 15195: my ($r, $username, $domain, $authhost, $form, $args) = @_;
1.462 albertel 15196: my $lonids=$Apache::lonnet::perlvar{'lonIDsDir'};
15197:
15198: my $public=($username eq 'public' && $domain eq 'public');
15199:
15200: # See if old ID present, if so, remove
15201:
1.1062 raeburn 15202: my ($filename,$cookie,$userroles,$firstaccenv,$timerintenv);
1.462 albertel 15203: my $now=time;
15204:
15205: if ($public) {
15206: my $max_public=100;
15207: my $oldest;
15208: my $oldest_time=0;
15209: for(my $next=1;$next<=$max_public;$next++) {
15210: if (-e $lonids."/publicuser_$next.id") {
15211: my $mtime=(stat($lonids."/publicuser_$next.id"))[9];
15212: if ($mtime<$oldest_time || !$oldest_time) {
15213: $oldest_time=$mtime;
15214: $oldest=$next;
15215: }
15216: } else {
15217: $cookie="publicuser_$next";
15218: last;
15219: }
15220: }
15221: if (!$cookie) { $cookie="publicuser_$oldest"; }
15222: } else {
1.463 albertel 15223: # if this isn't a robot, kill any existing non-robot sessions
15224: if (!$args->{'robot'}) {
15225: opendir(DIR,$lonids);
15226: while ($filename=readdir(DIR)) {
15227: if ($filename=~/^$username\_\d+\_$domain\_$authhost\.id$/) {
15228: unlink($lonids.'/'.$filename);
15229: }
1.462 albertel 15230: }
1.463 albertel 15231: closedir(DIR);
1.1075.2.84 raeburn 15232: # If there is a undeleted lockfile for the user's paste buffer remove it.
15233: my $namespace = 'nohist_courseeditor';
15234: my $lockingkey = 'paste'."\0".'locked_num';
15235: my %lockhash = &Apache::lonnet::get($namespace,[$lockingkey],
15236: $domain,$username);
15237: if (exists($lockhash{$lockingkey})) {
15238: my $delresult = &Apache::lonnet::del($namespace,[$lockingkey],$domain,$username);
15239: unless ($delresult eq 'ok') {
15240: &Apache::lonnet::logthis("Failed to delete paste buffer locking key in $namespace for ".$username.":".$domain." Result was: $delresult");
15241: }
15242: }
1.462 albertel 15243: }
15244: # Give them a new cookie
1.463 albertel 15245: my $id = ($args->{'robot'} ? 'robot'.$args->{'robot'}
1.684 www 15246: : $now.$$.int(rand(10000)));
1.463 albertel 15247: $cookie="$username\_$id\_$domain\_$authhost";
1.462 albertel 15248:
15249: # Initialize roles
15250:
1.1062 raeburn 15251: ($userroles,$firstaccenv,$timerintenv) =
15252: &Apache::lonnet::rolesinit($domain,$username,$authhost);
1.462 albertel 15253: }
15254: # ------------------------------------ Check browser type and MathML capability
15255:
1.1075.2.77 raeburn 15256: my ($httpbrowser,$clientbrowser,$clientversion,$clientmathml,$clientunicode,
15257: $clientos,$clientmobile,$clientinfo,$clientosversion) = &decode_user_agent($r);
1.462 albertel 15258:
15259: # ------------------------------------------------------------- Get environment
15260:
15261: my %userenv = &Apache::lonnet::dump('environment',$domain,$username);
15262: my ($tmp) = keys(%userenv);
15263: if ($tmp !~ /^(con_lost|error|no_such_host)/i) {
15264: } else {
15265: undef(%userenv);
15266: }
15267: if (($userenv{'interface'}) && (!$form->{'interface'})) {
15268: $form->{'interface'}=$userenv{'interface'};
15269: }
15270: if ($userenv{'texengine'} eq 'ttm') { $clientmathml=1; }
15271:
15272: # --------------- Do not trust query string to be put directly into environment
1.817 bisitz 15273: foreach my $option ('interface','localpath','localres') {
15274: $form->{$option}=~s/[\n\r\=]//gs;
1.462 albertel 15275: }
15276: # --------------------------------------------------------- Write first profile
15277:
15278: {
15279: my %initial_env =
15280: ("user.name" => $username,
15281: "user.domain" => $domain,
15282: "user.home" => $authhost,
15283: "browser.type" => $clientbrowser,
15284: "browser.version" => $clientversion,
15285: "browser.mathml" => $clientmathml,
15286: "browser.unicode" => $clientunicode,
15287: "browser.os" => $clientos,
1.1075.2.42 raeburn 15288: "browser.mobile" => $clientmobile,
15289: "browser.info" => $clientinfo,
1.1075.2.77 raeburn 15290: "browser.osversion" => $clientosversion,
1.462 albertel 15291: "server.domain" => $Apache::lonnet::perlvar{'lonDefDomain'},
15292: "request.course.fn" => '',
15293: "request.course.uri" => '',
15294: "request.course.sec" => '',
15295: "request.role" => 'cm',
15296: "request.role.adv" => $env{'user.adv'},
15297: "request.host" => $ENV{'REMOTE_ADDR'},);
15298:
15299: if ($form->{'localpath'}) {
15300: $initial_env{"browser.localpath"} = $form->{'localpath'};
15301: $initial_env{"browser.localres"} = $form->{'localres'};
15302: }
15303:
15304: if ($form->{'interface'}) {
15305: $form->{'interface'}=~s/\W//gs;
15306: $initial_env{"browser.interface"} = $form->{'interface'};
15307: $env{'browser.interface'}=$form->{'interface'};
15308: }
15309:
1.1075.2.54 raeburn 15310: if ($form->{'iptoken'}) {
15311: my $lonhost = $r->dir_config('lonHostID');
15312: $initial_env{"user.noloadbalance"} = $lonhost;
15313: $env{'user.noloadbalance'} = $lonhost;
15314: }
15315:
1.981 raeburn 15316: my %is_adv = ( is_adv => $env{'user.adv'} );
1.1016 raeburn 15317: my %domdef;
15318: unless ($domain eq 'public') {
15319: %domdef = &Apache::lonnet::get_domain_defaults($domain);
15320: }
1.980 raeburn 15321:
1.1075.2.7 raeburn 15322: foreach my $tool ('aboutme','blog','webdav','portfolio') {
1.724 raeburn 15323: $userenv{'availabletools.'.$tool} =
1.980 raeburn 15324: &Apache::lonnet::usertools_access($username,$domain,$tool,'reload',
15325: undef,\%userenv,\%domdef,\%is_adv);
1.724 raeburn 15326: }
15327:
1.1075.2.59 raeburn 15328: foreach my $crstype ('official','unofficial','community','textbook') {
1.765 raeburn 15329: $userenv{'canrequest.'.$crstype} =
15330: &Apache::lonnet::usertools_access($username,$domain,$crstype,
1.980 raeburn 15331: 'reload','requestcourses',
15332: \%userenv,\%domdef,\%is_adv);
1.765 raeburn 15333: }
15334:
1.1075.2.14 raeburn 15335: $userenv{'canrequest.author'} =
15336: &Apache::lonnet::usertools_access($username,$domain,'requestauthor',
15337: 'reload','requestauthor',
15338: \%userenv,\%domdef,\%is_adv);
15339: my %reqauthor = &Apache::lonnet::get('requestauthor',['author_status','author'],
15340: $domain,$username);
15341: my $reqstatus = $reqauthor{'author_status'};
15342: if ($reqstatus eq 'approval' || $reqstatus eq 'approved') {
15343: if (ref($reqauthor{'author'}) eq 'HASH') {
15344: $userenv{'requestauthorqueued'} = $reqstatus.':'.
15345: $reqauthor{'author'}{'timestamp'};
15346: }
15347: }
15348:
1.462 albertel 15349: $env{'user.environment'} = "$lonids/$cookie.id";
1.1062 raeburn 15350:
1.462 albertel 15351: if (tie(my %disk_env,'GDBM_File',"$lonids/$cookie.id",
15352: &GDBM_WRCREAT(),0640)) {
15353: &_add_to_env(\%disk_env,\%initial_env);
15354: &_add_to_env(\%disk_env,\%userenv,'environment.');
15355: &_add_to_env(\%disk_env,$userroles);
1.1062 raeburn 15356: if (ref($firstaccenv) eq 'HASH') {
15357: &_add_to_env(\%disk_env,$firstaccenv);
15358: }
15359: if (ref($timerintenv) eq 'HASH') {
15360: &_add_to_env(\%disk_env,$timerintenv);
15361: }
1.463 albertel 15362: if (ref($args->{'extra_env'})) {
15363: &_add_to_env(\%disk_env,$args->{'extra_env'});
15364: }
1.462 albertel 15365: untie(%disk_env);
15366: } else {
1.705 tempelho 15367: &Apache::lonnet::logthis("<span style=\"color:blue;\">WARNING: ".
15368: 'Could not create environment storage in lonauth: '.$!.'</span>');
1.462 albertel 15369: return 'error: '.$!;
15370: }
15371: }
15372: $env{'request.role'}='cm';
15373: $env{'request.role.adv'}=$env{'user.adv'};
15374: $env{'browser.type'}=$clientbrowser;
15375:
15376: return $cookie;
15377:
15378: }
15379:
15380: sub _add_to_env {
15381: my ($idf,$env_data,$prefix) = @_;
1.676 raeburn 15382: if (ref($env_data) eq 'HASH') {
15383: while (my ($key,$value) = each(%$env_data)) {
15384: $idf->{$prefix.$key} = $value;
15385: $env{$prefix.$key} = $value;
15386: }
1.462 albertel 15387: }
15388: }
15389:
1.685 tempelho 15390: # --- Get the symbolic name of a problem and the url
15391: sub get_symb {
15392: my ($request,$silent) = @_;
1.726 raeburn 15393: (my $url=$env{'form.url'}) =~ s-^https?\://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;
1.685 tempelho 15394: my $symb=($env{'form.symb'} ne '' ? $env{'form.symb'} : (&Apache::lonnet::symbread($url)));
15395: if ($symb eq '') {
15396: if (!$silent) {
1.1071 raeburn 15397: if (ref($request)) {
15398: $request->print("Unable to handle ambiguous references:$url:.");
15399: }
1.685 tempelho 15400: return ();
15401: }
15402: }
15403: &Apache::lonenc::check_decrypt(\$symb);
15404: return ($symb);
15405: }
15406:
15407: # --------------------------------------------------------------Get annotation
15408:
15409: sub get_annotation {
15410: my ($symb,$enc) = @_;
15411:
15412: my $key = $symb;
15413: if (!$enc) {
15414: $key =
15415: &Apache::lonnet::clutter((&Apache::lonnet::decode_symb($symb))[2]);
15416: }
15417: my %annotation=&Apache::lonnet::get('nohist_annotations',[$key]);
15418: return $annotation{$key};
15419: }
15420:
15421: sub clean_symb {
1.731 raeburn 15422: my ($symb,$delete_enc) = @_;
1.685 tempelho 15423:
15424: &Apache::lonenc::check_decrypt(\$symb);
15425: my $enc = $env{'request.enc'};
1.731 raeburn 15426: if ($delete_enc) {
1.730 raeburn 15427: delete($env{'request.enc'});
15428: }
1.685 tempelho 15429:
15430: return ($symb,$enc);
15431: }
1.462 albertel 15432:
1.1075.2.69 raeburn 15433: ############################################################
15434: ############################################################
15435:
15436: =pod
15437:
15438: =head1 Routines for building display used to search for courses
15439:
15440:
15441: =over 4
15442:
15443: =item * &build_filters()
15444:
15445: Create markup for a table used to set filters to use when selecting
15446: courses in a domain. Used by lonpickcourse.pm, lonmodifycourse.pm
15447: and quotacheck.pl
15448:
15449:
15450: Inputs:
15451:
15452: filterlist - anonymous array of fields to include as potential filters
15453:
15454: crstype - course type
15455:
15456: roleelement - fifth arg in selectcourse_link() populates fifth arg in javascript: opencrsbrowser() function, used
15457: to pop-open a course selector (will contain "extra element").
15458:
15459: multelement - if multiple course selections will be allowed, this will be a hidden form element: name: multiple; value: 1
15460:
15461: filter - anonymous hash of criteria and their values
15462:
15463: action - form action
15464:
15465: numfiltersref - ref to scalar (count of number of elements in institutional codes -- e.g., 4 for year, semester, department, and number)
15466:
15467: caller - caller context (e.g., set to 'modifycourse' when routine is called from lonmodifycourse.pm)
15468:
15469: cloneruname - username of owner of new course who wants to clone
15470:
15471: clonerudom - domain of owner of new course who wants to clone
15472:
15473: typeelem - text to use for left column in row containing course type (i.e., Course, Community or Course/Community)
15474:
15475: codetitlesref - reference to array of titles of components in institutional codes (official courses)
15476:
15477: codedom - domain
15478:
15479: formname - value of form element named "form".
15480:
15481: fixeddom - domain, if fixed.
15482:
15483: prevphase - value to assign to form element named "phase" when going back to the previous screen
15484:
15485: cnameelement - name of form element in form on opener page which will receive title of selected course
15486:
15487: cnumelement - name of form element in form on opener page which will receive courseID of selected course
15488:
15489: cdomelement - name of form element in form on opener page which will receive domain of selected course
15490:
15491: setroles - includes access constraint identifier when setting a roles-based condition for acces to a portfolio file
15492:
15493: clonetext - hidden form elements containing list of courses cloneable by intended course owner when DC creates a course
15494:
15495: clonewarning - warning message about missing information for intended course owner when DC creates a course
15496:
15497:
15498: Returns: $output - HTML for display of search criteria, and hidden form elements.
15499:
15500:
15501: Side Effects: None
15502:
15503: =cut
15504:
15505: # ---------------------------------------------- search for courses based on last activity etc.
15506:
15507: sub build_filters {
15508: my ($filterlist,$crstype,$roleelement,$multelement,$filter,$action,
15509: $numtitlesref,$caller,$cloneruname,$clonerudom,$typeelement,
15510: $codetitlesref,$codedom,$formname,$fixeddom,$prevphase,
15511: $cnameelement,$cnumelement,$cdomelement,$setroles,
15512: $clonetext,$clonewarning) = @_;
15513: my ($list,$jscript);
15514: my $onchange = 'javascript:updateFilters(this)';
15515: my ($domainselectform,$sincefilterform,$createdfilterform,
15516: $ownerdomselectform,$persondomselectform,$instcodeform,
15517: $typeselectform,$instcodetitle);
15518: if ($formname eq '') {
15519: $formname = $caller;
15520: }
15521: foreach my $item (@{$filterlist}) {
15522: unless (($item eq 'descriptfilter') || ($item eq 'instcodefilter') ||
15523: ($item eq 'sincefilter') || ($item eq 'createdfilter')) {
15524: if ($item eq 'domainfilter') {
15525: $filter->{$item} = &LONCAPA::clean_domain($filter->{$item});
15526: } elsif ($item eq 'coursefilter') {
15527: $filter->{$item} = &LONCAPA::clean_courseid($filter->{$item});
15528: } elsif ($item eq 'ownerfilter') {
15529: $filter->{$item} = &LONCAPA::clean_username($filter->{$item});
15530: } elsif ($item eq 'ownerdomfilter') {
15531: $filter->{'ownerdomfilter'} =
15532: &LONCAPA::clean_domain($filter->{$item});
15533: $ownerdomselectform = &select_dom_form($filter->{'ownerdomfilter'},
15534: 'ownerdomfilter',1);
15535: } elsif ($item eq 'personfilter') {
15536: $filter->{$item} = &LONCAPA::clean_username($filter->{$item});
15537: } elsif ($item eq 'persondomfilter') {
15538: $persondomselectform = &select_dom_form($filter->{'persondomfilter'},
15539: 'persondomfilter',1);
15540: } else {
15541: $filter->{$item} =~ s/\W//g;
15542: }
15543: if (!$filter->{$item}) {
15544: $filter->{$item} = '';
15545: }
15546: }
15547: if ($item eq 'domainfilter') {
15548: my $allow_blank = 1;
15549: if ($formname eq 'portform') {
15550: $allow_blank=0;
15551: } elsif ($formname eq 'studentform') {
15552: $allow_blank=0;
15553: }
15554: if ($fixeddom) {
15555: $domainselectform = '<input type="hidden" name="domainfilter"'.
15556: ' value="'.$codedom.'" />'.
15557: &Apache::lonnet::domain($codedom,'description');
15558: } else {
15559: $domainselectform = &select_dom_form($filter->{$item},
15560: 'domainfilter',
15561: $allow_blank,'',$onchange);
15562: }
15563: } else {
15564: $list->{$item} = &HTML::Entities::encode($filter->{$item},'<>&"');
15565: }
15566: }
15567:
15568: # last course activity filter and selection
15569: $sincefilterform = &timebased_select_form('sincefilter',$filter);
15570:
15571: # course created filter and selection
15572: if (exists($filter->{'createdfilter'})) {
15573: $createdfilterform = &timebased_select_form('createdfilter',$filter);
15574: }
15575:
15576: my %lt = &Apache::lonlocal::texthash(
15577: 'cac' => "$crstype Activity",
15578: 'ccr' => "$crstype Created",
15579: 'cde' => "$crstype Title",
15580: 'cdo' => "$crstype Domain",
15581: 'ins' => 'Institutional Code',
15582: 'inc' => 'Institutional Categorization',
15583: 'cow' => "$crstype Owner/Co-owner",
15584: 'cop' => "$crstype Personnel Includes",
15585: 'cog' => 'Type',
15586: );
15587:
15588: if (($formname eq 'ccrs') || ($formname eq 'requestcrs')) {
15589: my $typeval = 'Course';
15590: if ($crstype eq 'Community') {
15591: $typeval = 'Community';
15592: }
15593: $typeselectform = '<input type="hidden" name="type" value="'.$typeval.'" />';
15594: } else {
15595: $typeselectform = '<select name="type" size="1"';
15596: if ($onchange) {
15597: $typeselectform .= ' onchange="'.$onchange.'"';
15598: }
15599: $typeselectform .= '>'."\n";
15600: foreach my $posstype ('Course','Community') {
15601: $typeselectform.='<option value="'.$posstype.'"'.
15602: ($posstype eq $crstype ? ' selected="selected" ' : ''). ">".&mt($posstype)."</option>\n";
15603: }
15604: $typeselectform.="</select>";
15605: }
15606:
15607: my ($cloneableonlyform,$cloneabletitle);
15608: if (exists($filter->{'cloneableonly'})) {
15609: my $cloneableon = '';
15610: my $cloneableoff = ' checked="checked"';
15611: if ($filter->{'cloneableonly'}) {
15612: $cloneableon = $cloneableoff;
15613: $cloneableoff = '';
15614: }
15615: $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>';
15616: if ($formname eq 'ccrs') {
1.1075.2.71 raeburn 15617: $cloneabletitle = &mt('Cloneable for [_1]',$cloneruname.':'.$clonerudom);
1.1075.2.69 raeburn 15618: } else {
15619: $cloneabletitle = &mt('Cloneable by you');
15620: }
15621: }
15622: my $officialjs;
15623: if ($crstype eq 'Course') {
15624: if (exists($filter->{'instcodefilter'})) {
15625: # if (($fixeddom) || ($formname eq 'requestcrs') ||
15626: # ($formname eq 'modifycourse') || ($formname eq 'filterpicker')) {
15627: if ($codedom) {
15628: $officialjs = 1;
15629: ($instcodeform,$jscript,$$numtitlesref) =
15630: &Apache::courseclassifier::instcode_selectors($codedom,'filterpicker',
15631: $officialjs,$codetitlesref);
15632: if ($jscript) {
15633: $jscript = '<script type="text/javascript">'."\n".
15634: '// <![CDATA['."\n".
15635: $jscript."\n".
15636: '// ]]>'."\n".
15637: '</script>'."\n";
15638: }
15639: }
15640: if ($instcodeform eq '') {
15641: $instcodeform =
15642: '<input type="text" name="instcodefilter" size="10" value="'.
15643: $list->{'instcodefilter'}.'" />';
15644: $instcodetitle = $lt{'ins'};
15645: } else {
15646: $instcodetitle = $lt{'inc'};
15647: }
15648: if ($fixeddom) {
15649: $instcodetitle .= '<br />('.$codedom.')';
15650: }
15651: }
15652: }
15653: my $output = qq|
15654: <form method="post" name="filterpicker" action="$action">
15655: <input type="hidden" name="form" value="$formname" />
15656: |;
15657: if ($formname eq 'modifycourse') {
15658: $output .= '<input type="hidden" name="phase" value="courselist" />'."\n".
15659: '<input type="hidden" name="prevphase" value="'.
15660: $prevphase.'" />'."\n";
1.1075.2.82 raeburn 15661: } elsif ($formname eq 'quotacheck') {
15662: $output .= qq|
15663: <input type="hidden" name="sortby" value="" />
15664: <input type="hidden" name="sortorder" value="" />
15665: |;
15666: } else {
1.1075.2.69 raeburn 15667: my $name_input;
15668: if ($cnameelement ne '') {
15669: $name_input = '<input type="hidden" name="cnameelement" value="'.
15670: $cnameelement.'" />';
15671: }
15672: $output .= qq|
15673: <input type="hidden" name="cnumelement" value="$cnumelement" />
15674: <input type="hidden" name="cdomelement" value="$cdomelement" />
15675: $name_input
15676: $roleelement
15677: $multelement
15678: $typeelement
15679: |;
15680: if ($formname eq 'portform') {
15681: $output .= '<input type="hidden" name="setroles" value="'.$setroles.'" />'."\n";
15682: }
15683: }
15684: if ($fixeddom) {
15685: $output .= '<input type="hidden" name="fixeddom" value="'.$fixeddom.'" />'."\n";
15686: }
15687: $output .= "<br />\n".&Apache::lonhtmlcommon::start_pick_box();
15688: if ($sincefilterform) {
15689: $output .= &Apache::lonhtmlcommon::row_title($lt{'cac'})
15690: .$sincefilterform
15691: .&Apache::lonhtmlcommon::row_closure();
15692: }
15693: if ($createdfilterform) {
15694: $output .= &Apache::lonhtmlcommon::row_title($lt{'ccr'})
15695: .$createdfilterform
15696: .&Apache::lonhtmlcommon::row_closure();
15697: }
15698: if ($domainselectform) {
15699: $output .= &Apache::lonhtmlcommon::row_title($lt{'cdo'})
15700: .$domainselectform
15701: .&Apache::lonhtmlcommon::row_closure();
15702: }
15703: if ($typeselectform) {
15704: if (($formname eq 'ccrs') || ($formname eq 'requestcrs')) {
15705: $output .= $typeselectform;
15706: } else {
15707: $output .= &Apache::lonhtmlcommon::row_title($lt{'cog'})
15708: .$typeselectform
15709: .&Apache::lonhtmlcommon::row_closure();
15710: }
15711: }
15712: if ($instcodeform) {
15713: $output .= &Apache::lonhtmlcommon::row_title($instcodetitle)
15714: .$instcodeform
15715: .&Apache::lonhtmlcommon::row_closure();
15716: }
15717: if (exists($filter->{'ownerfilter'})) {
15718: $output .= &Apache::lonhtmlcommon::row_title($lt{'cow'}).
15719: '<table><tr><td>'.&mt('Username').'<br />'.
15720: '<input type="text" name="ownerfilter" size="20" value="'.
15721: $list->{'ownerfilter'}.'" /></td><td>'.&mt('Domain').'<br />'.
15722: $ownerdomselectform.'</td></tr></table>'.
15723: &Apache::lonhtmlcommon::row_closure();
15724: }
15725: if (exists($filter->{'personfilter'})) {
15726: $output .= &Apache::lonhtmlcommon::row_title($lt{'cop'}).
15727: '<table><tr><td>'.&mt('Username').'<br />'.
15728: '<input type="text" name="personfilter" size="20" value="'.
15729: $list->{'personfilter'}.'" /></td><td>'.&mt('Domain').'<br />'.
15730: $persondomselectform.'</td></tr></table>'.
15731: &Apache::lonhtmlcommon::row_closure();
15732: }
15733: if (exists($filter->{'coursefilter'})) {
15734: $output .= &Apache::lonhtmlcommon::row_title(&mt('LON-CAPA course ID'))
15735: .'<input type="text" name="coursefilter" size="25" value="'
15736: .$list->{'coursefilter'}.'" />'
15737: .&Apache::lonhtmlcommon::row_closure();
15738: }
15739: if ($cloneableonlyform) {
15740: $output .= &Apache::lonhtmlcommon::row_title($cloneabletitle).
15741: $cloneableonlyform.&Apache::lonhtmlcommon::row_closure();
15742: }
15743: if (exists($filter->{'descriptfilter'})) {
15744: $output .= &Apache::lonhtmlcommon::row_title($lt{'cde'})
15745: .'<input type="text" name="descriptfilter" size="40" value="'
15746: .$list->{'descriptfilter'}.'" />'
15747: .&Apache::lonhtmlcommon::row_closure(1);
15748: }
15749: $output .= &Apache::lonhtmlcommon::end_pick_box().'<p>'.$clonetext."\n".
15750: '<input type="hidden" name="updater" value="" />'."\n".
15751: '<input type="submit" name="gosearch" value="'.
15752: &mt('Search').'" /></p>'."\n".'</form>'."\n".'<hr />'."\n";
15753: return $jscript.$clonewarning.$output;
15754: }
15755:
15756: =pod
15757:
15758: =item * &timebased_select_form()
15759:
15760: Create markup for a dropdown list used to select a time-based
15761: filter e.g., Course Activity, Course Created, when searching for courses
15762: or communities
15763:
15764: Inputs:
15765:
15766: item - name of form element (sincefilter or createdfilter)
15767:
15768: filter - anonymous hash of criteria and their values
15769:
15770: Returns: HTML for a select box contained a blank, then six time selections,
15771: with value set in incoming form variables currently selected.
15772:
15773: Side Effects: None
15774:
15775: =cut
15776:
15777: sub timebased_select_form {
15778: my ($item,$filter) = @_;
15779: if (ref($filter) eq 'HASH') {
15780: $filter->{$item} =~ s/[^\d-]//g;
15781: if (!$filter->{$item}) { $filter->{$item}=-1; }
15782: return &select_form(
15783: $filter->{$item},
15784: $item,
15785: { '-1' => '',
15786: '86400' => &mt('today'),
15787: '604800' => &mt('last week'),
15788: '2592000' => &mt('last month'),
15789: '7776000' => &mt('last three months'),
15790: '15552000' => &mt('last six months'),
15791: '31104000' => &mt('last year'),
15792: 'select_form_order' =>
15793: ['-1','86400','604800','2592000','7776000',
15794: '15552000','31104000']});
15795: }
15796: }
15797:
15798: =pod
15799:
15800: =item * &js_changer()
15801:
15802: Create script tag containing Javascript used to submit course search form
15803: when course type or domain is changed, and also to hide 'Searching ...' on
15804: page load completion for page showing search result.
15805:
15806: Inputs: None
15807:
15808: Returns: markup containing updateFilters() and hideSearching() javascript functions.
15809:
15810: Side Effects: None
15811:
15812: =cut
15813:
15814: sub js_changer {
15815: return <<ENDJS;
15816: <script type="text/javascript">
15817: // <![CDATA[
15818: function updateFilters(caller) {
15819: if (typeof(caller) != "undefined") {
15820: document.filterpicker.updater.value = caller.name;
15821: }
15822: document.filterpicker.submit();
15823: }
15824:
15825: function hideSearching() {
15826: if (document.getElementById('searching')) {
15827: document.getElementById('searching').style.display = 'none';
15828: }
15829: return;
15830: }
15831:
15832: // ]]>
15833: </script>
15834:
15835: ENDJS
15836: }
15837:
15838: =pod
15839:
15840: =item * &search_courses()
15841:
15842: Process selected filters form course search form and pass to lonnet::courseiddump
15843: to retrieve a hash for which keys are courseIDs which match the selected filters.
15844:
15845: Inputs:
15846:
15847: dom - domain being searched
15848:
15849: type - course type ('Course' or 'Community' or '.' if any).
15850:
15851: filter - anonymous hash of criteria and their values
15852:
15853: numtitles - for institutional codes - number of categories
15854:
15855: cloneruname - optional username of new course owner
15856:
15857: clonerudom - optional domain of new course owner
15858:
1.1075.2.95 raeburn 15859: domcloner - optional "domcloner" flag; has value=1 if user has ccc priv in domain being filtered by,
1.1075.2.69 raeburn 15860: (used when DC is using course creation form)
15861:
15862: codetitles - reference to array of titles of components in institutional codes (official courses).
15863:
1.1075.2.95 raeburn 15864: cc_clone - escaped comma separated list of courses for which course cloner has active CC role
15865: (and so can clone automatically)
15866:
15867: reqcrsdom - domain of new course, where search_courses is used to identify potential courses to clone
15868:
15869: reqinstcode - institutional code of new course, where search_courses is used to identify potential
15870: courses to clone
1.1075.2.69 raeburn 15871:
15872: Returns: %courses - hash of courses satisfying search criteria, keys = course IDs, values are corresponding colon-separated escaped description, institutional code, owner and type.
15873:
15874:
15875: Side Effects: None
15876:
15877: =cut
15878:
15879:
15880: sub search_courses {
1.1075.2.95 raeburn 15881: my ($dom,$type,$filter,$numtitles,$cloneruname,$clonerudom,$domcloner,$codetitles,
15882: $cc_clone,$reqcrsdom,$reqinstcode) = @_;
1.1075.2.69 raeburn 15883: my (%courses,%showcourses,$cloner);
15884: if (($filter->{'ownerfilter'} ne '') ||
15885: ($filter->{'ownerdomfilter'} ne '')) {
15886: $filter->{'combownerfilter'} = $filter->{'ownerfilter'}.':'.
15887: $filter->{'ownerdomfilter'};
15888: }
15889: foreach my $item ('descriptfilter','coursefilter','combownerfilter') {
15890: if (!$filter->{$item}) {
15891: $filter->{$item}='.';
15892: }
15893: }
15894: my $now = time;
15895: my $timefilter =
15896: ($filter->{'sincefilter'}==-1?1:$now-$filter->{'sincefilter'});
15897: my ($createdbefore,$createdafter);
15898: if (($filter->{'createdfilter'} ne '') && ($filter->{'createdfilter'} !=-1)) {
15899: $createdbefore = $now;
15900: $createdafter = $now-$filter->{'createdfilter'};
15901: }
15902: my ($instcodefilter,$regexpok);
15903: if ($numtitles) {
15904: if ($env{'form.official'} eq 'on') {
15905: $instcodefilter =
15906: &Apache::courseclassifier::instcode_search_str($dom,$numtitles,$codetitles);
15907: $regexpok = 1;
15908: } elsif ($env{'form.official'} eq 'off') {
15909: $instcodefilter = &Apache::courseclassifier::instcode_search_str($dom,$numtitles,$codetitles);
15910: unless ($instcodefilter eq '') {
15911: $regexpok = -1;
15912: }
15913: }
15914: } else {
15915: $instcodefilter = $filter->{'instcodefilter'};
15916: }
15917: if ($instcodefilter eq '') { $instcodefilter = '.'; }
15918: if ($type eq '') { $type = '.'; }
15919:
15920: if (($clonerudom ne '') && ($cloneruname ne '')) {
15921: $cloner = $cloneruname.':'.$clonerudom;
15922: }
15923: %courses = &Apache::lonnet::courseiddump($dom,
15924: $filter->{'descriptfilter'},
15925: $timefilter,
15926: $instcodefilter,
15927: $filter->{'combownerfilter'},
15928: $filter->{'coursefilter'},
15929: undef,undef,$type,$regexpok,undef,undef,
1.1075.2.95 raeburn 15930: undef,undef,$cloner,$cc_clone,
1.1075.2.69 raeburn 15931: $filter->{'cloneableonly'},
15932: $createdbefore,$createdafter,undef,
1.1075.2.95 raeburn 15933: $domcloner,undef,$reqcrsdom,$reqinstcode);
1.1075.2.69 raeburn 15934: if (($filter->{'personfilter'} ne '') && ($filter->{'persondomfilter'} ne '')) {
15935: my $ccrole;
15936: if ($type eq 'Community') {
15937: $ccrole = 'co';
15938: } else {
15939: $ccrole = 'cc';
15940: }
15941: my %rolehash = &Apache::lonnet::get_my_roles($filter->{'personfilter'},
15942: $filter->{'persondomfilter'},
15943: 'userroles',undef,
15944: [$ccrole,'in','ad','ep','ta','cr'],
15945: $dom);
15946: foreach my $role (keys(%rolehash)) {
15947: my ($cnum,$cdom,$courserole) = split(':',$role);
15948: my $cid = $cdom.'_'.$cnum;
15949: if (exists($courses{$cid})) {
15950: if (ref($courses{$cid}) eq 'HASH') {
15951: if (ref($courses{$cid}{roles}) eq 'ARRAY') {
15952: if (!grep(/^\Q$courserole\E$/,@{$courses{$cid}{roles}})) {
15953: push (@{$courses{$cid}{roles}},$courserole);
15954: }
15955: } else {
15956: $courses{$cid}{roles} = [$courserole];
15957: }
15958: $showcourses{$cid} = $courses{$cid};
15959: }
15960: }
15961: }
15962: %courses = %showcourses;
15963: }
15964: return %courses;
15965: }
15966:
15967: =pod
15968:
15969: =back
15970:
1.1075.2.88 raeburn 15971: =head1 Routines for version requirements for current course.
15972:
15973: =over 4
15974:
15975: =item * &check_release_required()
15976:
15977: Compares required LON-CAPA version with version on server, and
15978: if required version is newer looks for a server with the required version.
15979:
15980: Looks first at servers in user's owen domain; if none suitable, looks at
15981: servers in course's domain are permitted to host sessions for user's domain.
15982:
15983: Inputs:
15984:
15985: $loncaparev - Version on current server (format: Major.Minor.Subrelease-datestamp)
15986:
15987: $courseid - Course ID of current course
15988:
15989: $rolecode - User's current role in course (for switchserver query string).
15990:
15991: $required - LON-CAPA version needed by course (format: Major.Minor).
15992:
15993:
15994: Returns:
15995:
15996: $switchserver - query string tp append to /adm/switchserver call (if
15997: current server's LON-CAPA version is too old.
15998:
15999: $warning - Message is displayed if no suitable server could be found.
16000:
16001: =cut
16002:
16003: sub check_release_required {
16004: my ($loncaparev,$courseid,$rolecode,$required) = @_;
16005: my ($switchserver,$warning);
16006: if ($required ne '') {
16007: my ($reqdmajor,$reqdminor) = ($required =~ /^(\d+)\.(\d+)$/);
16008: my ($major,$minor) = ($loncaparev =~ /^\'?(\d+)\.(\d+)\.[\w.\-]+\'?$/);
16009: if ($reqdmajor ne '' && $reqdminor ne '') {
16010: my $otherserver;
16011: if (($major eq '' && $minor eq '') ||
16012: (($reqdmajor > $major) || (($reqdmajor == $major) && ($reqdminor > $minor)))) {
16013: my ($userdomserver) = &Apache::lonnet::choose_server($env{'user.domain'},undef,$required,1);
16014: my $switchlcrev =
16015: &Apache::lonnet::get_server_loncaparev($env{'user.domain'},
16016: $userdomserver);
16017: my ($swmajor,$swminor) = ($switchlcrev =~ /^\'?(\d+)\.(\d+)\.[\w.\-]+\'?$/);
16018: if (($swmajor eq '' && $swminor eq '') || ($reqdmajor > $swmajor) ||
16019: (($reqdmajor == $swmajor) && ($reqdminor > $swminor))) {
16020: my $cdom = $env{'course.'.$courseid.'.domain'};
16021: if ($cdom ne $env{'user.domain'}) {
16022: my ($coursedomserver,$coursehostname) = &Apache::lonnet::choose_server($cdom,undef,$required,1);
16023: my $serverhomeID = &Apache::lonnet::get_server_homeID($coursehostname);
16024: my $serverhomedom = &Apache::lonnet::host_domain($serverhomeID);
16025: my %defdomdefaults = &Apache::lonnet::get_domain_defaults($serverhomedom);
16026: my %udomdefaults = &Apache::lonnet::get_domain_defaults($env{'user.domain'});
16027: my $remoterev = &Apache::lonnet::get_server_loncaparev($serverhomedom,$coursedomserver);
16028: my $canhost =
16029: &Apache::lonnet::can_host_session($env{'user.domain'},
16030: $coursedomserver,
16031: $remoterev,
16032: $udomdefaults{'remotesessions'},
16033: $defdomdefaults{'hostedsessions'});
16034:
16035: if ($canhost) {
16036: $otherserver = $coursedomserver;
16037: } else {
16038: $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.");
16039: }
16040: } else {
16041: $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).");
16042: }
16043: } else {
16044: $otherserver = $userdomserver;
16045: }
16046: }
16047: if ($otherserver ne '') {
16048: $switchserver = 'otherserver='.$otherserver.'&role='.$rolecode;
16049: }
16050: }
16051: }
16052: return ($switchserver,$warning);
16053: }
16054:
16055: =pod
16056:
16057: =item * &check_release_result()
16058:
16059: Inputs:
16060:
16061: $switchwarning - Warning message if no suitable server found to host session.
16062:
16063: $switchserver - query string to append to /adm/switchserver containing lonHostID
16064: and current role.
16065:
16066: Returns: HTML to display with information about requirement to switch server.
16067: Either displaying warning with link to Roles/Courses screen or
16068: display link to switchserver.
16069:
1.1075.2.69 raeburn 16070: =cut
16071:
1.1075.2.88 raeburn 16072: sub check_release_result {
16073: my ($switchwarning,$switchserver) = @_;
16074: my $output = &start_page('Selected course unavailable on this server').
16075: '<p class="LC_warning">';
16076: if ($switchwarning) {
16077: $output .= $switchwarning.'<br /><a href="/adm/roles">';
16078: if (&show_course()) {
16079: $output .= &mt('Display courses');
16080: } else {
16081: $output .= &mt('Display roles');
16082: }
16083: $output .= '</a>';
16084: } elsif ($switchserver) {
16085: $output .= &mt('This course requires a newer version of LON-CAPA than is installed on this server.').
16086: '<br />'.
16087: '<a href="/adm/switchserver?'.$switchserver.'">'.
16088: &mt('Switch Server').
16089: '</a>';
16090: }
16091: $output .= '</p>'.&end_page();
16092: return $output;
16093: }
16094:
16095: =pod
16096:
16097: =item * &needs_coursereinit()
16098:
16099: Determine if course contents stored for user's session needs to be
16100: refreshed, because content has changed since "Big Hash" last tied.
16101:
16102: Check for change is made if time last checked is more than 10 minutes ago
16103: (by default).
16104:
16105: Inputs:
16106:
16107: $loncaparev - Version on current server (format: Major.Minor.Subrelease-datestamp)
16108:
16109: $interval (optional) - Time which may elapse (in s) between last check for content
16110: change in current course. (default: 600 s).
16111:
16112: Returns: an array; first element is:
16113:
16114: =over 4
16115:
16116: 'switch' - if content updates mean user's session
16117: needs to be switched to a server running a newer LON-CAPA version
16118:
16119: 'update' - if course session needs to be refreshed (i.e., Big Hash needs to be reloaded)
16120: on current server hosting user's session
16121:
16122: '' - if no action required.
16123:
16124: =back
16125:
16126: If first item element is 'switch':
16127:
16128: second item is $switchwarning - Warning message if no suitable server found to host session.
16129:
16130: third item is $switchserver - query string to append to /adm/switchserver containing lonHostID
16131: and current role.
16132:
16133: otherwise: no other elements returned.
16134:
16135: =back
16136:
16137: =cut
16138:
16139: sub needs_coursereinit {
16140: my ($loncaparev,$interval) = @_;
16141: return() unless ($env{'request.course.id'} && $env{'request.course.tied'});
16142: my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
16143: my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
16144: my $now = time;
16145: if ($interval eq '') {
16146: $interval = 600;
16147: }
16148: if (($now-$env{'request.course.timechecked'})>$interval) {
16149: my $lastchange = &Apache::lonnet::get_coursechange($cdom,$cnum);
16150: &Apache::lonnet::appenv({'request.course.timechecked'=>$now});
16151: if ($lastchange > $env{'request.course.tied'}) {
16152: my %curr_reqd_hash = &Apache::lonnet::userenvironment($cdom,$cnum,'internal.releaserequired');
16153: if ($curr_reqd_hash{'internal.releaserequired'} ne '') {
16154: my $required = $env{'course.'.$cdom.'_'.$cnum.'.internal.releaserequired'};
16155: if ($curr_reqd_hash{'internal.releaserequired'} ne $required) {
16156: &Apache::lonnet::appenv({'course.'.$cdom.'_'.$cnum.'.internal.releaserequired' =>
16157: $curr_reqd_hash{'internal.releaserequired'}});
16158: my ($switchserver,$switchwarning) =
16159: &check_release_required($loncaparev,$cdom.'_'.$cnum,$env{'request.role'},
16160: $curr_reqd_hash{'internal.releaserequired'});
16161: if ($switchwarning ne '' || $switchserver ne '') {
16162: return ('switch',$switchwarning,$switchserver);
16163: }
16164: }
16165: }
16166: return ('update');
16167: }
16168: }
16169: return ();
16170: }
1.1075.2.69 raeburn 16171:
1.1075.2.11 raeburn 16172: sub update_content_constraints {
16173: my ($cdom,$cnum,$chome,$cid) = @_;
16174: my %curr_reqd_hash = &Apache::lonnet::userenvironment($cdom,$cnum,'internal.releaserequired');
16175: my ($reqdmajor,$reqdminor) = split(/\./,$curr_reqd_hash{'internal.releaserequired'});
16176: my %checkresponsetypes;
16177: foreach my $key (keys(%Apache::lonnet::needsrelease)) {
16178: my ($item,$name,$value) = split(/:/,$key);
16179: if ($item eq 'resourcetag') {
16180: if ($name eq 'responsetype') {
16181: $checkresponsetypes{$value} = $Apache::lonnet::needsrelease{$key}
16182: }
16183: }
16184: }
16185: my $navmap = Apache::lonnavmaps::navmap->new();
16186: if (defined($navmap)) {
16187: my %allresponses;
16188: foreach my $res ($navmap->retrieveResources(undef,sub { $_[0]->is_problem() },1,0)) {
16189: my %responses = $res->responseTypes();
16190: foreach my $key (keys(%responses)) {
16191: next unless(exists($checkresponsetypes{$key}));
16192: $allresponses{$key} += $responses{$key};
16193: }
16194: }
16195: foreach my $key (keys(%allresponses)) {
16196: my ($major,$minor) = split(/\./,$checkresponsetypes{$key});
16197: if (($major > $reqdmajor) || ($major == $reqdmajor && $minor > $reqdminor)) {
16198: ($reqdmajor,$reqdminor) = ($major,$minor);
16199: }
16200: }
16201: undef($navmap);
16202: }
16203: unless (($reqdmajor eq '') && ($reqdminor eq '')) {
16204: &Apache::lonnet::update_released_required($reqdmajor.'.'.$reqdminor,$cdom,$cnum,$chome,$cid);
16205: }
16206: return;
16207: }
16208:
1.1075.2.27 raeburn 16209: sub allmaps_incourse {
16210: my ($cdom,$cnum,$chome,$cid) = @_;
16211: if ($cdom eq '' || $cnum eq '' || $chome eq '' || $cid eq '') {
16212: $cid = $env{'request.course.id'};
16213: $cdom = $env{'course.'.$cid.'.domain'};
16214: $cnum = $env{'course.'.$cid.'.num'};
16215: $chome = $env{'course.'.$cid.'.home'};
16216: }
16217: my %allmaps = ();
16218: my $lastchange =
16219: &Apache::lonnet::get_coursechange($cdom,$cnum);
16220: if ($lastchange > $env{'request.course.tied'}) {
16221: my ($furl,$ferr) = &Apache::lonuserstate::readmap("$cdom/$cnum");
16222: unless ($ferr) {
16223: &update_content_constraints($cdom,$cnum,$chome,$cid);
16224: }
16225: }
16226: my $navmap = Apache::lonnavmaps::navmap->new();
16227: if (defined($navmap)) {
16228: foreach my $res ($navmap->retrieveResources(undef,sub { $_[0]->is_map() },1,0,1)) {
16229: $allmaps{$res->src()} = 1;
16230: }
16231: }
16232: return \%allmaps;
16233: }
16234:
1.1075.2.11 raeburn 16235: sub parse_supplemental_title {
16236: my ($title) = @_;
16237:
16238: my ($foldertitle,$renametitle);
16239: if ($title =~ /&&&/) {
16240: $title = &HTML::Entites::decode($title);
16241: }
16242: if ($title =~ m/^(\d+)___&&&___($match_username)___&&&___($match_domain)___&&&___(.*)$/) {
16243: $renametitle=$4;
16244: my ($time,$uname,$udom) = ($1,$2,$3);
16245: $foldertitle=&Apache::lontexconvert::msgtexconverted($4);
16246: my $name = &plainname($uname,$udom);
16247: $name = &HTML::Entities::encode($name,'"<>&\'');
16248: $renametitle = &HTML::Entities::encode($renametitle,'"<>&\'');
16249: $title='<i>'.&Apache::lonlocal::locallocaltime($time).'</i> '.
16250: $name.': <br />'.$foldertitle;
16251: }
16252: if (wantarray) {
16253: return ($title,$foldertitle,$renametitle);
16254: }
16255: return $title;
16256: }
16257:
1.1075.2.43 raeburn 16258: sub recurse_supplemental {
16259: my ($cnum,$cdom,$suppmap,$numfiles,$errors) = @_;
16260: if ($suppmap) {
16261: my ($errtext,$fatal) = &LONCAPA::map::mapread('/uploaded/'.$cdom.'/'.$cnum.'/'.$suppmap);
16262: if ($fatal) {
16263: $errors ++;
16264: } else {
16265: if ($#LONCAPA::map::resources > 0) {
16266: foreach my $res (@LONCAPA::map::resources) {
16267: my ($title,$src,$ext,$type,$status)=split(/\:/,$res);
16268: if (($src ne '') && ($status eq 'res')) {
1.1075.2.46 raeburn 16269: if ($src =~ m{^\Q/uploaded/$cdom/$cnum/\E(supplemental_\d+\.sequence)$}) {
16270: ($numfiles,$errors) = &recurse_supplemental($cnum,$cdom,$1,$numfiles,$errors);
1.1075.2.43 raeburn 16271: } else {
16272: $numfiles ++;
16273: }
16274: }
16275: }
16276: }
16277: }
16278: }
16279: return ($numfiles,$errors);
16280: }
16281:
1.1075.2.18 raeburn 16282: sub symb_to_docspath {
16283: my ($symb) = @_;
16284: return unless ($symb);
16285: my ($mapurl,$id,$resurl) = &Apache::lonnet::decode_symb($symb);
16286: if ($resurl=~/\.(sequence|page)$/) {
16287: $mapurl=$resurl;
16288: } elsif ($resurl eq 'adm/navmaps') {
16289: $mapurl=$env{'course.'.$env{'request.course.id'}.'.url'};
16290: }
16291: my $mapresobj;
16292: my $navmap = Apache::lonnavmaps::navmap->new();
16293: if (ref($navmap)) {
16294: $mapresobj = $navmap->getResourceByUrl($mapurl);
16295: }
16296: $mapurl=~s{^.*/([^/]+)\.(\w+)$}{$1};
16297: my $type=$2;
16298: my $path;
16299: if (ref($mapresobj)) {
16300: my $pcslist = $mapresobj->map_hierarchy();
16301: if ($pcslist ne '') {
16302: foreach my $pc (split(/,/,$pcslist)) {
16303: next if ($pc <= 1);
16304: my $res = $navmap->getByMapPc($pc);
16305: if (ref($res)) {
16306: my $thisurl = $res->src();
16307: $thisurl=~s{^.*/([^/]+)\.\w+$}{$1};
16308: my $thistitle = $res->title();
16309: $path .= '&'.
16310: &Apache::lonhtmlcommon::entity_encode($thisurl).'&'.
1.1075.2.46 raeburn 16311: &escape($thistitle).
1.1075.2.18 raeburn 16312: ':'.$res->randompick().
16313: ':'.$res->randomout().
16314: ':'.$res->encrypted().
16315: ':'.$res->randomorder().
16316: ':'.$res->is_page();
16317: }
16318: }
16319: }
16320: $path =~ s/^\&//;
16321: my $maptitle = $mapresobj->title();
16322: if ($mapurl eq 'default') {
1.1075.2.38 raeburn 16323: $maptitle = 'Main Content';
1.1075.2.18 raeburn 16324: }
16325: $path .= (($path ne '')? '&' : '').
16326: &Apache::lonhtmlcommon::entity_encode($mapurl).'&'.
1.1075.2.46 raeburn 16327: &escape($maptitle).
1.1075.2.18 raeburn 16328: ':'.$mapresobj->randompick().
16329: ':'.$mapresobj->randomout().
16330: ':'.$mapresobj->encrypted().
16331: ':'.$mapresobj->randomorder().
16332: ':'.$mapresobj->is_page();
16333: } else {
16334: my $maptitle = &Apache::lonnet::gettitle($mapurl);
16335: my $ispage = (($type eq 'page')? 1 : '');
16336: if ($mapurl eq 'default') {
1.1075.2.38 raeburn 16337: $maptitle = 'Main Content';
1.1075.2.18 raeburn 16338: }
16339: $path = &Apache::lonhtmlcommon::entity_encode($mapurl).'&'.
1.1075.2.46 raeburn 16340: &escape($maptitle).':::::'.$ispage;
1.1075.2.18 raeburn 16341: }
16342: unless ($mapurl eq 'default') {
16343: $path = 'default&'.
1.1075.2.46 raeburn 16344: &escape('Main Content').
1.1075.2.18 raeburn 16345: ':::::&'.$path;
16346: }
16347: return $path;
16348: }
16349:
1.1075.2.14 raeburn 16350: sub captcha_display {
16351: my ($context,$lonhost) = @_;
16352: my ($output,$error);
1.1075.2.107 raeburn 16353: my ($captcha,$pubkey,$privkey,$version) =
16354: &get_captcha_config($context,$lonhost);
1.1075.2.14 raeburn 16355: if ($captcha eq 'original') {
16356: $output = &create_captcha();
16357: unless ($output) {
16358: $error = 'captcha';
16359: }
16360: } elsif ($captcha eq 'recaptcha') {
1.1075.2.107 raeburn 16361: $output = &create_recaptcha($pubkey,$version);
1.1075.2.14 raeburn 16362: unless ($output) {
16363: $error = 'recaptcha';
16364: }
16365: }
1.1075.2.107 raeburn 16366: return ($output,$error,$captcha,$version);
1.1075.2.14 raeburn 16367: }
16368:
16369: sub captcha_response {
16370: my ($context,$lonhost) = @_;
16371: my ($captcha_chk,$captcha_error);
1.1075.2.109 raeburn 16372: my ($captcha,$pubkey,$privkey,$version) = &get_captcha_config($context,$lonhost);
1.1075.2.14 raeburn 16373: if ($captcha eq 'original') {
16374: ($captcha_chk,$captcha_error) = &check_captcha();
16375: } elsif ($captcha eq 'recaptcha') {
1.1075.2.107 raeburn 16376: $captcha_chk = &check_recaptcha($privkey,$version);
1.1075.2.14 raeburn 16377: } else {
16378: $captcha_chk = 1;
16379: }
16380: return ($captcha_chk,$captcha_error);
16381: }
16382:
16383: sub get_captcha_config {
16384: my ($context,$lonhost) = @_;
1.1075.2.107 raeburn 16385: my ($captcha,$pubkey,$privkey,$version,$hashtocheck);
1.1075.2.14 raeburn 16386: my $hostname = &Apache::lonnet::hostname($lonhost);
16387: my $serverhomeID = &Apache::lonnet::get_server_homeID($hostname);
16388: my $serverhomedom = &Apache::lonnet::host_domain($serverhomeID);
16389: if ($context eq 'usercreation') {
16390: my %domconfig = &Apache::lonnet::get_dom('configuration',[$context],$serverhomedom);
16391: if (ref($domconfig{$context}) eq 'HASH') {
16392: $hashtocheck = $domconfig{$context}{'cancreate'};
16393: if (ref($hashtocheck) eq 'HASH') {
16394: if ($hashtocheck->{'captcha'} eq 'recaptcha') {
16395: if (ref($hashtocheck->{'recaptchakeys'}) eq 'HASH') {
16396: $pubkey = $hashtocheck->{'recaptchakeys'}{'public'};
16397: $privkey = $hashtocheck->{'recaptchakeys'}{'private'};
16398: }
16399: if ($privkey && $pubkey) {
16400: $captcha = 'recaptcha';
1.1075.2.107 raeburn 16401: $version = $hashtocheck->{'recaptchaversion'};
16402: if ($version ne '2') {
16403: $version = 1;
16404: }
1.1075.2.14 raeburn 16405: } else {
16406: $captcha = 'original';
16407: }
16408: } elsif ($hashtocheck->{'captcha'} ne 'notused') {
16409: $captcha = 'original';
16410: }
16411: }
16412: } else {
16413: $captcha = 'captcha';
16414: }
16415: } elsif ($context eq 'login') {
16416: my %domconfhash = &Apache::loncommon::get_domainconf($serverhomedom);
16417: if ($domconfhash{$serverhomedom.'.login.captcha'} eq 'recaptcha') {
16418: $pubkey = $domconfhash{$serverhomedom.'.login.recaptchakeys_public'};
16419: $privkey = $domconfhash{$serverhomedom.'.login.recaptchakeys_private'};
16420: if ($privkey && $pubkey) {
16421: $captcha = 'recaptcha';
1.1075.2.107 raeburn 16422: $version = $domconfhash{$serverhomedom.'.login.recaptchaversion'};
16423: if ($version ne '2') {
16424: $version = 1;
16425: }
1.1075.2.14 raeburn 16426: } else {
16427: $captcha = 'original';
16428: }
16429: } elsif ($domconfhash{$serverhomedom.'.login.captcha'} eq 'original') {
16430: $captcha = 'original';
16431: }
16432: }
1.1075.2.107 raeburn 16433: return ($captcha,$pubkey,$privkey,$version);
1.1075.2.14 raeburn 16434: }
16435:
16436: sub create_captcha {
16437: my %captcha_params = &captcha_settings();
16438: my ($output,$maxtries,$tries) = ('',10,0);
16439: while ($tries < $maxtries) {
16440: $tries ++;
16441: my $captcha = Authen::Captcha->new (
16442: output_folder => $captcha_params{'output_dir'},
16443: data_folder => $captcha_params{'db_dir'},
16444: );
16445: my $md5sum = $captcha->generate_code($captcha_params{'numchars'});
16446:
16447: if (-e $Apache::lonnet::perlvar{'lonCaptchaDir'}.'/'.$md5sum.'.png') {
16448: $output = '<input type="hidden" name="crypt" value="'.$md5sum.'" />'."\n".
16449: &mt('Type in the letters/numbers shown below').' '.
1.1075.2.66 raeburn 16450: '<input type="text" size="5" name="code" value="" autocomplete="off" />'.
16451: '<br />'.
16452: '<img src="'.$captcha_params{'www_output_dir'}.'/'.$md5sum.'.png" alt="captcha" />';
1.1075.2.14 raeburn 16453: last;
16454: }
16455: }
16456: return $output;
16457: }
16458:
16459: sub captcha_settings {
16460: my %captcha_params = (
16461: output_dir => $Apache::lonnet::perlvar{'lonCaptchaDir'},
16462: www_output_dir => "/captchaspool",
16463: db_dir => $Apache::lonnet::perlvar{'lonCaptchaDb'},
16464: numchars => '5',
16465: );
16466: return %captcha_params;
16467: }
16468:
16469: sub check_captcha {
16470: my ($captcha_chk,$captcha_error);
16471: my $code = $env{'form.code'};
16472: my $md5sum = $env{'form.crypt'};
16473: my %captcha_params = &captcha_settings();
16474: my $captcha = Authen::Captcha->new(
16475: output_folder => $captcha_params{'output_dir'},
16476: data_folder => $captcha_params{'db_dir'},
16477: );
1.1075.2.26 raeburn 16478: $captcha_chk = $captcha->check_code($code,$md5sum);
1.1075.2.14 raeburn 16479: my %captcha_hash = (
16480: 0 => 'Code not checked (file error)',
16481: -1 => 'Failed: code expired',
16482: -2 => 'Failed: invalid code (not in database)',
16483: -3 => 'Failed: invalid code (code does not match crypt)',
16484: );
16485: if ($captcha_chk != 1) {
16486: $captcha_error = $captcha_hash{$captcha_chk}
16487: }
16488: return ($captcha_chk,$captcha_error);
16489: }
16490:
16491: sub create_recaptcha {
1.1075.2.107 raeburn 16492: my ($pubkey,$version) = @_;
16493: if ($version >= 2) {
16494: return '<div class="g-recaptcha" data-sitekey="'.$pubkey.'"></div>';
16495: } else {
16496: my $use_ssl;
16497: if ($ENV{'SERVER_PORT'} == 443) {
16498: $use_ssl = 1;
16499: }
16500: my $captcha = Captcha::reCAPTCHA->new;
16501: return $captcha->get_options_setter({theme => 'white'})."\n".
16502: $captcha->get_html($pubkey,undef,$use_ssl).
16503: &mt('If the text is hard to read, [_1] will replace them.',
16504: '<img src="/res/adm/pages/refresh.gif" alt="reCAPTCHA refresh" />').
16505: '<br /><br />';
16506: }
1.1075.2.14 raeburn 16507: }
16508:
16509: sub check_recaptcha {
1.1075.2.107 raeburn 16510: my ($privkey,$version) = @_;
1.1075.2.14 raeburn 16511: my $captcha_chk;
1.1075.2.107 raeburn 16512: if ($version >= 2) {
16513: my $ua = LWP::UserAgent->new;
16514: $ua->timeout(10);
16515: my %info = (
16516: secret => $privkey,
16517: response => $env{'form.g-recaptcha-response'},
16518: remoteip => $ENV{'REMOTE_ADDR'},
16519: );
16520: my $response = $ua->post('https://www.google.com/recaptcha/api/siteverify',\%info);
16521: if ($response->is_success) {
16522: my $data = JSON::DWIW->from_json($response->decoded_content);
16523: if (ref($data) eq 'HASH') {
16524: if ($data->{'success'}) {
16525: $captcha_chk = 1;
16526: }
16527: }
16528: }
16529: } else {
16530: my $captcha = Captcha::reCAPTCHA->new;
16531: my $captcha_result =
16532: $captcha->check_answer(
16533: $privkey,
16534: $ENV{'REMOTE_ADDR'},
16535: $env{'form.recaptcha_challenge_field'},
16536: $env{'form.recaptcha_response_field'},
16537: );
16538: if ($captcha_result->{is_valid}) {
16539: $captcha_chk = 1;
16540: }
1.1075.2.14 raeburn 16541: }
16542: return $captcha_chk;
16543: }
16544:
1.1075.2.64 raeburn 16545: sub emailusername_info {
1.1075.2.103 raeburn 16546: my @fields = ('firstname','lastname','institution','web','location','officialemail','id');
1.1075.2.64 raeburn 16547: my %titles = &Apache::lonlocal::texthash (
16548: lastname => 'Last Name',
16549: firstname => 'First Name',
16550: institution => 'School/college/university',
16551: location => "School's city, state/province, country",
16552: web => "School's web address",
16553: officialemail => 'E-mail address at institution (if different)',
1.1075.2.103 raeburn 16554: id => 'Student/Employee ID',
1.1075.2.64 raeburn 16555: );
16556: return (\@fields,\%titles);
16557: }
16558:
1.1075.2.56 raeburn 16559: sub cleanup_html {
16560: my ($incoming) = @_;
16561: my $outgoing;
16562: if ($incoming ne '') {
16563: $outgoing = $incoming;
16564: $outgoing =~ s/;/;/g;
16565: $outgoing =~ s/\#/#/g;
16566: $outgoing =~ s/\&/&/g;
16567: $outgoing =~ s/</</g;
16568: $outgoing =~ s/>/>/g;
16569: $outgoing =~ s/\(/(/g;
16570: $outgoing =~ s/\)/)/g;
16571: $outgoing =~ s/"/"/g;
16572: $outgoing =~ s/'/'/g;
16573: $outgoing =~ s/\$/$/g;
16574: $outgoing =~ s{/}{/}g;
16575: $outgoing =~ s/=/=/g;
16576: $outgoing =~ s/\\/\/g
16577: }
16578: return $outgoing;
16579: }
16580:
1.1075.2.74 raeburn 16581: # Checks for critical messages and returns a redirect url if one exists.
16582: # $interval indicates how often to check for messages.
16583: sub critical_redirect {
16584: my ($interval) = @_;
16585: if ((time-$env{'user.criticalcheck.time'})>$interval) {
16586: my @what=&Apache::lonnet::dump('critical', $env{'user.domain'},
16587: $env{'user.name'});
16588: &Apache::lonnet::appenv({'user.criticalcheck.time'=>time});
16589: my $redirecturl;
16590: if ($what[0]) {
16591: if (($what[0] ne 'con_lost') && ($what[0]!~/^error\:/)) {
16592: $redirecturl='/adm/email?critical=display';
16593: my $url=&Apache::lonnet::absolute_url().$redirecturl;
16594: return (1, $url);
16595: }
16596: }
16597: }
16598: return ();
16599: }
16600:
1.1075.2.64 raeburn 16601: # Use:
16602: # my $answer=reply("encrypt:passwd:$udom:$uname:$upass",$tryserver);
16603: #
16604: ##################################################
16605: # password associated functions #
16606: ##################################################
16607: sub des_keys {
16608: # Make a new key for DES encryption.
16609: # Each key has two parts which are returned separately.
16610: # Please note: Each key must be passed through the &hex function
16611: # before it is output to the web browser. The hex versions cannot
16612: # be used to decrypt.
16613: my @hexstr=('0','1','2','3','4','5','6','7',
16614: '8','9','a','b','c','d','e','f');
16615: my $lkey='';
16616: for (0..7) {
16617: $lkey.=$hexstr[rand(15)];
16618: }
16619: my $ukey='';
16620: for (0..7) {
16621: $ukey.=$hexstr[rand(15)];
16622: }
16623: return ($lkey,$ukey);
16624: }
16625:
16626: sub des_decrypt {
16627: my ($key,$cyphertext) = @_;
16628: my $keybin=pack("H16",$key);
16629: my $cypher;
16630: if ($Crypt::DES::VERSION>=2.03) {
16631: $cypher=new Crypt::DES $keybin;
16632: } else {
16633: $cypher=new DES $keybin;
16634: }
1.1075.2.106 raeburn 16635: my $plaintext='';
16636: my $cypherlength = length($cyphertext);
16637: my $numchunks = int($cypherlength/32);
16638: for (my $j=0; $j<$numchunks; $j++) {
16639: my $start = $j*32;
16640: my $cypherblock = substr($cyphertext,$start,32);
16641: my $chunk =
16642: $cypher->decrypt(unpack("a8",pack("H16",substr($cypherblock,0,16))));
16643: $chunk .=
16644: $cypher->decrypt(unpack("a8",pack("H16",substr($cypherblock,16,16))));
16645: $chunk=substr($chunk,1,ord(substr($chunk,0,1)) );
16646: $plaintext .= $chunk;
16647: }
1.1075.2.64 raeburn 16648: return $plaintext;
16649: }
16650:
1.112 bowersj2 16651: 1;
16652: __END__;
1.41 ng 16653:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>