Annotation of loncom/interface/loncourserespicker.pm, revision 1.14
1.1 raeburn 1: # The LearningOnline Network
2: #
1.14 ! raeburn 3: # $Id: loncourserespicker.pm,v 1.13 2015/06/09 21:22:56 damieng Exp $
1.1 raeburn 4: #
5: # Copyright Michigan State University Board of Trustees
6: #
7: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
8: #
9: # LON-CAPA is free software; you can redistribute it and/or modify
10: # it under the terms of the GNU General Public License as published by
11: # the Free Software Foundation; either version 2 of the License, or
12: # (at your option) any later version.
13: #
14: # LON-CAPA is distributed in the hope that it will be useful,
15: # but WITHOUT ANY WARRANTY; without even the implied warranty of
16: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17: # GNU General Public License for more details.
18: #
19: # You should have received a copy of the GNU General Public License
20: # along with LON-CAPA; if not, write to the Free Software
21: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22: #
23: # /home/httpd/html/adm/gpl.txt
24: #
25: # http://www.lon-capa.org/
26: #
27:
28: =pod
29:
30: =head1 NAME
31:
32: loncourserespicker - Utilities to choose folders and resources in a course.
33:
34: =head1 SYNOPSIS
35:
36: loncourserespicker provides an interface for selecting which folders and/or
37: resources are to be either:
38:
39: (a) exported to an IMS Content Package
1.7 raeburn 40: (b) subject to access blocking for the duriation of an exam/quiz.
41: (c) dumped to an Authoring Space
1.1 raeburn 42:
43: =head1 DESCRIPTION
44:
45: This module provides routines to generate a hierarchical display of folders
46: and resources in a course which can be selected for specific actions.
47:
48: The choice of items is copied back to the main window from which the pop-up
49: window used to display the Course Contents was opened.
50:
51: =head1 OVERVIEW
52:
53: The main subroutine: &create_picker() will display the hierarchy of folders,
1.6 raeburn 54: sub-folders, and resources in the Main Content area. Items can be selected
55: using checkboxes, and/or a "Check All" button. Selection of a folder
1.1 raeburn 56: causes the contents of the folder to also be selected automatically. The
57: propagation of check status is recursive into sub-folders. Likewise, if an
58: item deep in a nested set of folders and sub-folders is unchecked, the
59: uncheck will propagate up through the hierarchy causing any folders at
60: a higher level to become unchecked.
61:
62: There is a submit button, which will be named differently according to the
1.7 raeburn 63: context in which resource/folder selection is being made.
1.1 raeburn 64:
1.7 raeburn 65: The three contexts currently supported are: IMS export, selection of
1.1 raeburn 66: content to be subject to access restructions for the duration of an
1.7 raeburn 67: exam, and selection of items for dumping to an Authoring Space.
1.1 raeburn 68:
69: =head1 INTERNAL SUBROUTINES
70:
71: =item &create_picker()
72:
73: Created HTML mark up to display contents of course with checkboxes to
74: select items. Checking a folder causes recursive checking of items
75: within the folder. Unchecking a resource causing unchecking of folders
76: containing the item back up to the top level.
77:
1.14 ! raeburn 78: Inputs: 11.
1.1 raeburn 79: - $navmap -- Reference to LON-CAPA navmap object
80: (encapsulates information about resources in the course).
81:
82: - $context -- Context in which course resource selection is being made.
83: Currently imsexport and examblock are supported.
84:
85: - $formname -- Name of the form in the window from which the pop-up
86: used to select course items was launched.
87:
88: - $crstype -- Course or Community
89:
90: - $blockedmaps -- Reference to hash of previously selected maps
91: (e.g., for a live exam block).
92:
93: - $blockedresources -- Reference to hash of resources selected
94: previously (e.g., for an exam block).
95:
96: - $block -- An internal ID (integer) used to track which exam
97: block currently being configured.
98:
1.7 raeburn 99: - $preamble -- HTML form elements used to select Authoring Space
100: if more than one available, and also set name of 'Folder
101: in Authoring Space' where content will be dumped, when
102: context is 'dumpdocs'.
103:
104: - $numhome -- number of possible Authoring Spaces where content could
105: be dumped when context is 'dumpdocs'.
106:
107: - $uploadedfiles -- Reference to hash: keys are paths to files in
108: /home/httpd/lonUsers/$cdom/$1/$2/$3/$cnum/userfiles.
1.14 ! raeburn 109:
! 110: - $readonly -- if true, no "check all" or "uncheck all" buttons will
! 111: be displayed, and checkboxes will be disabled, if this
! 112: is for an exam block.
1.7 raeburn 113:
1.1 raeburn 114:
115: Output: $output is the HTML mark-up for display/selection of content
116: items in the pop-up window.
117:
118: =item &respicker_javascript()
119:
120: Creates javascript functions for checking/unchecking all items, and
121: for recursive checking triggered by checking a folder, or recursive
122: (upeards) unchecking of an item within a folder.
123:
124: Inputs: 7.
125: - $startcount -- Starting offset of form element numbering for items
126:
127: - $numcount -- Total numer of folders and resources in course.
128:
129: - $context -- Context in which resources are being displayed
1.7 raeburn 130: (imsexport, examblock or dumpdocs).
1.1 raeburn 131:
132: - $formname -- Name of form.
133:
134: - $children -- Reference to hash of items contained within a folder.
135:
136: - $hierarchy -- Reference to hierarchy of folders containing an item.
137:
138: - $checked_maps -- Reference to array of folders currently checked.
139:
1.7 raeburn 140: Output: 1. Javascript (within <script></script> tags.
1.1 raeburn 141:
142:
143: =item &get_navmap_object()
144:
145: Instantiates a navmaps object, and generates an error message if
146: no object instantiated.
147:
148: Inputs: 2.
149: - $crstype -- Container type: Course or Community
150:
1.7 raeburn 151: - $context -- Context: imsexport, examblock or dumpdocs
152:
153:
154: =item &clean()
155:
156: Takes incoming title and replaces non-alphanumeric characters with underscore,
157: so title can be used as suggested file name (with appended extension) for file
1.11 bisitz 158: copied from course to Authoring Space.
1.7 raeburn 159:
160:
161: =item &enumerate_course_contents()
162:
163: Create hashes of maps (for folders/pages) and symbs (for resources) in
164: a course, where keys are numbers (starting with 1) and values are
165: map url, or symb, for an iteration through the course, as seen by
166: a Course Coordinator. Used to generate numerical IDs to facilitate
167: (a) storage of lists of maps or resources to be blocked during an exam,
168: (b) processing selected form element during dumping of selected course
1.11 bisitz 169: content to Authoring Space.
1.7 raeburn 170:
171: Inputs: 7
172:
173: $navmap - navmaps object
174:
175: $map_url - reference to hash to contain URLs of maps in course
176:
177: $resource_symb - reference to hash to contain symbs for
178: resources in course
179:
180: $title_ref - reference to hash containing titles for items in
181: course
182:
183: $context - examblock or dumpdocs
184:
185: $cdom - course's domain
186:
187: $cnum - courseID
188:
189: Outputs: None
190:
191: Side Effects: $map_url and $resource_symb hashrefs are populated.
192:
1.1 raeburn 193:
194: =over
195:
196: =back
197:
198: =cut
199:
200:
201: package Apache::loncourserespicker;
202:
203: use strict;
204: use Apache::lonnet;
205: use Apache::loncommon;
206: use Apache::lonhtmlcommon;
207: use Apache::lonnavmaps;
1.2 raeburn 208: use Apache::londocs;
1.1 raeburn 209: use Apache::lonlocal;
210: use LONCAPA qw(:DEFAULT :match);
211:
212: sub create_picker {
1.14 ! raeburn 213: my ($navmap,$context,$formname,$crstype,$blockedmaps,$blockedresources,$block,$preamble,
! 214: $numhome,$uploadedfiles,$readonly) = @_;
1.1 raeburn 215: return unless (ref($navmap));
1.7 raeburn 216: my ($it,$output,$numdisc,%maps,%resources,%discussiontime,%currmaps,%currresources,%files);
1.1 raeburn 217: $it = $navmap->getIterator(undef,undef,undef,1,undef,undef);
218: if (ref($blockedmaps) eq 'HASH') {
219: %currmaps = %{$blockedmaps};
220: }
221: if (ref($blockedresources) eq 'HASH') {
222: %currresources = %{$blockedresources};
1.7 raeburn 223: } elsif (ref($uploadedfiles) eq 'HASH') {
224: %files = %{$uploadedfiles};
1.1 raeburn 225: }
226: my @checked_maps;
227: my $curRes;
228: my $numprobs = 0;
229: my $depth = 0;
230: my $count = 0;
231: my $boards = 0;
232: my $startcount = 1;
233: my %parent = ();
234: my %children = ();
235: my %hierarchy = ();
236: my $location=&Apache::loncommon::lonhttpdurl("/adm/lonIcons");
1.7 raeburn 237: my $whitespace =
1.1 raeburn 238: '<img src="'.$location.'/whitespace_21.gif" class="LC_docs_spacer" alt="" />';
239:
1.7 raeburn 240: my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
241: my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
242: my $crsprefix = &propath($cdom,$cnum).'/userfiles/';
243:
1.14 ! raeburn 244: my ($info,$display,$onsubmit,$togglebuttons,$disabled);
1.1 raeburn 245: if ($context eq 'examblock') {
246: my $maps_elem = 'docs_maps_'.$block;
247: my $res_elem = 'docs_resources_'.$block;
248: $onsubmit = ' onsubmit="return writeToOpener('."'$maps_elem','$res_elem'".');"';
1.7 raeburn 249: $info = &mt('Items in '.lc($crstype).' for which access will be blocked.');
1.14 ! raeburn 250: if ($readonly) {
! 251: $disabled = ' disabled="disabled"';
! 252: }
1.1 raeburn 253: }
1.7 raeburn 254: if ($context eq 'dumpdocs') {
255: $info = '<span class="LC_fontsize_medium">'.
1.11 bisitz 256: &mt('Choose the uploaded course items and templated pages/problems to be copied to Authoring Space.').
1.7 raeburn 257: '</span><br /><br />';
258: $startcount = 3 + $numhome;
259: $onsubmit = ' onsubmit="return checkUnique(document.'.$formname.',document.'.$formname.'.archive);"';
260: } elsif ($context eq 'imsexport') {
261: $info = &mt('Choose which items you wish to export from your '.$crstype.'.');
1.1 raeburn 262: $startcount = 5;
263: }
1.14 ! raeburn 264: if ($disabled) {
! 265: $togglebuttons = '<br />';
! 266: } else {
! 267: $togglebuttons = '<input type="button" value="'.&mt('check all').'" '.
! 268: 'onclick="javascript:checkAll(document.'.$formname.'.archive)" />'.
! 269: ' <input type="button" value="'.&mt('uncheck all').'"'.
! 270: ' onclick="javascript:uncheckAll(document.'.$formname.'.archive)" />';
! 271: }
1.7 raeburn 272: $display = '<form name="'.$formname.'" action="" method="post"'.$onsubmit.'>'."\n";
1.1 raeburn 273: if ($context eq 'imsexport') {
1.7 raeburn 274: $display .= $info.
275: '<div class="LC_columnSection">'."\n".
1.1 raeburn 276: '<fieldset>'.
1.7 raeburn 277: '<legend>'.&mt('Content items').'</legend>'."\n".
278: $togglebuttons.
279: '</fieldset>';
280: %discussiontime = &Apache::lonnet::dump('discussiontimes',$cdom,$cnum);
1.1 raeburn 281: $numdisc = keys(%discussiontime);
282: if ($numdisc > 0) {
283: $display .=
284: '<fieldset>'.
285: '<legend>'.&mt('Discussion posts').'</legend>'.
286: '<input type="button" value="'.&mt('check all').'"'.
287: ' onclick="javascript:checkAll(document.'.$formname.'.discussion)" />'.
288: ' <input type="button" value="'.&mt('uncheck all').'"'.
289: ' onclick="javascript:uncheckAll(document.'.$formname.'.discussion)" />'.
1.2 raeburn 290: '</fieldset>';
1.1 raeburn 291: }
1.7 raeburn 292: $display .= '</div>';
293: } elsif ($context eq 'examblock') {
294: $display .= $info.$togglebuttons;
295: } elsif ($context eq 'dumpdocs') {
296: $display .= $preamble.
297: '<div class="LC_left_float">'.
298: '<fieldset>'.
299: '<legend>'.&mt('Content to copy').(' 'x4).$togglebuttons.'</legend>'.
300: $info;
1.1 raeburn 301: }
302: my $lastcontainer = $startcount;
303: $display .= &Apache::loncommon::start_data_table()
304: .&Apache::loncommon::start_data_table_header_row();
305: if ($context eq 'imsexport') {
306: $display .= '<th>'.&mt('Export content item?').'</th>';
307: if ($numdisc > 0) {
308: $display .= '<th>'.&mt('Export discussion posts?').'</th>';
309: }
310: } elsif ($context eq 'examblock') {
311: $display .= '<th>'.&mt('Access blocked?').'</th>';
1.7 raeburn 312: } elsif ($context eq 'dumpdocs') {
313: $display .= '<th>'.&mt('Copy?').'</th>'.
314: '<th>'.&mt("Title in $crstype").
315: '<th>'.&mt('Internal Identifier').'</th>'.
316: '<th>'.&mt('Save as ...').'</th>';
1.1 raeburn 317: }
318: $display .= &Apache::loncommon::end_data_table_header_row();
319: while ($curRes = $it->next()) {
320: if ($curRes == $it->BEGIN_MAP()) {
321: $depth++;
322: $parent{$depth} = $lastcontainer;
323: }
324: if ($curRes == $it->END_MAP()) {
325: $depth--;
326: $lastcontainer = $parent{$depth};
327: }
328: if (ref($curRes)) {
329: my $symb = $curRes->symb();
330: my $ressymb = $symb;
1.7 raeburn 331: if ($context eq 'dumpdocs') {
332: next unless (($curRes->src() =~ m{^\Q/uploaded/$cdom/$cnum/\E(docs|supplemental|simplepage)}) ||
333: ($curRes->src() =~ m{^\Q/uploaded/$cdom/$cnum/\E(default|supplemental)_\d+\.(sequence|page)}) ||
334: ($curRes->src() eq '/res/lib/templates/simpleproblem.problem') ||
335: ($curRes->src() =~ m{^/adm/$match_domain/$match_username/\d+/smppg}));
336: } elsif ($ressymb =~ m|adm/($match_domain)/($match_username)/(\d+)/bulletinboard$|) {
1.1 raeburn 337: unless ($ressymb =~ m|adm/wrapper/adm|) {
338: $ressymb = 'bulletin___'.$3.'___adm/wrapper/adm/'.$1.'/'.$2.'/'.$3.'/bulletinboard';
339: }
340: }
1.7 raeburn 341: $count ++;
342: my $currelem;
343: if ($context eq 'imsexport') {
344: $currelem = $count+$boards+$startcount;
345: } else {
346: $currelem = $count+$startcount;
347: }
1.1 raeburn 348: $display .= &Apache::loncommon::start_data_table_row().
349: '<td>'."\n".
350: '<input type="checkbox" name="archive" value="'.$count.'" ';
351: if (($curRes->is_sequence()) || ($curRes->is_page())) {
352: $lastcontainer = $currelem;
1.7 raeburn 353: $display .= 'onclick="javascript:checkFolder(document.'.$formname.','."'$currelem'".')" ';
1.1 raeburn 354: my $mapurl = (&Apache::lonnet::decode_symb($symb))[2];
355: if ($currmaps{$mapurl}) {
356: $display .= 'checked="checked"';
357: push(@checked_maps,$currelem);
358: }
359: } else {
360: if ($curRes->is_problem()) {
361: $numprobs ++;
362: }
1.7 raeburn 363: $display .= 'onclick="javascript:checkResource(document.'.$formname.','."'$currelem'".')" ';
1.1 raeburn 364: if ($currresources{$symb}) {
365: $display .= 'checked="checked"';
366: }
367: }
1.14 ! raeburn 368: $display .= $disabled.' />'."\n";
1.7 raeburn 369: if ($context eq 'dumpdocs') {
370: $display .= '</td><td valign="top">';
371: }
1.1 raeburn 372: for (my $i=0; $i<$depth; $i++) {
373: $display .= "$whitespace\n";
374: }
375: my $icon = 'src="'.$location.'/unknown.gif" alt=""';
376: if ($curRes->is_sequence()) {
1.4 bisitz 377: $icon = 'src="'.$location.'/navmap.folder.open.gif" alt="'.&mt('Folder').'"';
1.1 raeburn 378: } elsif ($curRes->is_page()) {
379: $icon = 'src="'.$location.'/navmap.page.open.gif" alt="'.&mt('Composite Page').'"';
380: } elsif ($curRes->is_problem()) {
381: $icon = 'src="'.$location.'/problem.gif" alt="'.&mt('Problem').'"';
382: } elsif ($curRes->is_task()) {
383: $icon = 'src="'.$location.'/task.gif" alt="'.&mt('Task').'"';
384: } elsif ($curRes->src ne '') {
385: $icon = 'src="'.&Apache::loncommon::icon($curRes->src).'" alt=""';
386: }
387: $display .= '<img '.$icon.' /> '."\n";
388: $children{$parent{$depth}} .= $currelem.':';
389: if ($context eq 'examblock') {
390: if ($parent{$depth} > 1) {
391: if ($hierarchy{$parent{$depth}}) {
392: $hierarchy{$currelem} = $hierarchy{$parent{$depth}}.",'$parent{$depth}'";
393: } else {
394: $hierarchy{$currelem} = "'$parent{$depth}'";
395: }
396: }
397: }
1.7 raeburn 398: $display .= ' '.$curRes->title().$whitespace.'</td>'."\n";
1.1 raeburn 399:
400: if ($context eq 'imsexport') {
401: # Existing discussion posts?
402: if ($discussiontime{$ressymb} > 0) {
403: $boards ++;
404: $display .= '<td align="right">'
405: .'<input type="checkbox" name="discussion" value="'.$count.'" />'
406: .'</td>'."\n";
407: } elsif ($numdisc > 0) {
408: $display .= '<td> </td>'."\n";
409: }
1.7 raeburn 410: } elsif ($context eq 'dumpdocs') {
411: my $src = $curRes->src();
412: my ($filepath,$title);
413: if ($src =~ m{^\Q/uploaded/$cdom/$cnum/\E}) {
414: $filepath = &Apache::lonnet::filelocation('',$src);
415: $filepath =~ s/\Q$crsprefix\E//;
416: if ($curRes->is_map()) {
417: $title = $files{$filepath};
418: } else {
419: $filepath =~ s{docs/}{};
420: $title = $filepath;
421: $title =~ s{^(default|\d+)/\d*/?}{};
422: }
423: } else {
424: $title = $curRes->title();
425: $title =~ s{/}{_}g;
426: $title = &clean($title);
427: if ($src eq '/res/lib/templates/simpleproblem.problem') {
428: my ($map,$id,$res) = &Apache::lonnet::decode_symb($symb);
429: $map =~ s{^uploaded/$cdom/$cnum/}{};
430: $filepath = $map.'_'.$id;
431: $title .= '.problem';
432: } elsif ($src =~ m{^/adm/$match_domain/$match_username/(\d+)/smppg}) {
433: $filepath = 'smppage_'.$1.'.db';
434: $title .= '.html';
435: }
436: }
437: $display .= '<td>'.$filepath.'</td>'.
438: '<td><input type="text" size="40" name="namefor_'.$count.'" id="namefor_'.$count.'" value="'.$title.'" /></td>'."\n";
1.1 raeburn 439: }
440: $display .= &Apache::loncommon::end_data_table_row();
441: }
442: }
443: $display .= &Apache::loncommon::end_data_table();
444: if ($context eq 'imsexport') {
445: if ($numprobs > 0) {
446: $display .= '<p><span class="LC_nobreak">'.
447: &mt('Export format for LON-CAPA problems:').
448: '<label><input type="radio" name="format" value="xml" checked="checked" />'.
449: ' '.&mt('XML').'</label>'.(' ' x3).
450: '<label><input type="radio" name="format" value="html" />'.
451: ' '.&mt('HTML').'</label>'.(' ' x3).
452: '<label><input type="radio" name="format" value="plaintext" />'.
453: ' '.&mt('Text').'</label></span></p>';
454: }
455: }
1.7 raeburn 456: my $numcount;
1.1 raeburn 457: if ($context eq 'imsexport') {
458: $display .=
1.7 raeburn 459: '<p>'.
1.1 raeburn 460: '<input type="hidden" name="finishexport" value="1" />'.
461: '<input type="submit" name="exportcourse" value="'.
1.7 raeburn 462: &mt('Export').'" /></p>';
463: $numcount = $count + $boards + $startcount;
1.1 raeburn 464: } elsif ($context eq 'examblock') {
1.14 ! raeburn 465: unless ($readonly) {
! 466: $display .=
! 467: '<p>'.
! 468: '<input type="submit" name="resourceblocks" value="'.
! 469: &mt('Copy Choices to Main Window').'" /></p>';
! 470: }
1.7 raeburn 471: $numcount = $count + $startcount;
472: } elsif ($context eq 'dumpdocs') {
473: $display .= '</fieldset>'.
474: '</div><div style="padding:0;clear:both;margin:0;border:0"></div>'.
475: '<div>'.
1.8 raeburn 476: '<input type="submit" name="dumpcourse" value="'.&mt("Copy $crstype Content").'" />'.
1.7 raeburn 477: '</div>';
478: $numcount = $count + $startcount;
1.1 raeburn 479: }
1.7 raeburn 480: $display .= '</form>';
1.1 raeburn 481: my $scripttag =
482: &respicker_javascript($startcount,$numcount,$context,$formname,\%children,
1.9 raeburn 483: \%hierarchy,\@checked_maps,$numhome);
1.7 raeburn 484: if ($context eq 'dumpdocs') {
485: return $scripttag.$display;
486: }
1.1 raeburn 487: my ($title,$crumbs,$args);
1.7 raeburn 488: if ($context eq 'imsexport') {
1.1 raeburn 489: $title = 'Export '.$crstype.' to IMS Package';
490: } elsif ($context eq 'examblock') {
491: $title = 'Resources with Access blocked';
492: $args = {'only_body' => 1,
493: 'add_entries' => { onload => 'javascript:recurseFolders();' },
494: };
495: }
1.3 raeburn 496: $output = &Apache::loncommon::start_page($title,$scripttag,$args);
1.1 raeburn 497: if ($context eq 'imsexport') {
1.2 raeburn 498: $output .= &Apache::lonhtmlcommon::breadcrumbs('IMS Export').
499: &Apache::londocs::startContentScreen('tools');
1.7 raeburn 500: } elsif ($context eq 'dumpdocs') {
1.8 raeburn 501: $output .= &Apache::lonhtmlcommon::breadcrumbs('Copying to Authoring Space').
1.7 raeburn 502: &Apache::londocs::startContentScreen('tools');
1.1 raeburn 503: }
504: $output .= $display;
505: if ($context eq 'examblock') {
506: $output .= &Apache::loncommon::end_page();
1.2 raeburn 507: } elsif ($context eq 'imsexport') {
508: $output .= &Apache::londocs::endContentScreen();
1.1 raeburn 509: }
510: return $output;
511: }
512:
513: sub respicker_javascript {
514: my ($startcount,$numitems,$context,$formname,$children,$hierarchy,
1.9 raeburn 515: $checked_maps,$numhome) = @_;
1.1 raeburn 516: return unless ((ref($children) eq 'HASH') && (ref($hierarchy) eq 'HASH')
517: && (ref($checked_maps) eq 'ARRAY'));
1.7 raeburn 518: my ($elem,$nested,$nameforelem);
519: if ($context eq 'dumpdocs') {
520: $elem='((parseInt(item)-'.$startcount.')*2)+'.$startcount;
521: $nested='((parseInt(nesting[item][i])-'.$startcount.')*2)+'.$startcount;
522: $nameforelem=$elem+1;
523: } else {
524: $elem='parseInt(item)';
525: $nested='parseInt(nesting[item][i])';
526: }
1.1 raeburn 527: my $scripttag = <<"START";
528: <script type="text/javascript">
529: // <![CDATA[
530: function checkAll(field) {
531: if (field.length > 0) {
532: for (i = 0; i < field.length; i++) {
533: field[i].checked = true ;
534: }
535: } else {
536: field.checked = true
537: }
538: }
539:
540: function uncheckAll(field) {
541: if (field.length > 0) {
542: for (i = 0; i < field.length; i++) {
543: field[i].checked = false;
544: }
545: } else {
546: field.checked = false;
547: }
548: }
549:
550: function checkFolder(form,item) {
1.7 raeburn 551: var elem = $elem;
552: if (form.elements[elem].checked == true) {
1.1 raeburn 553: containerCheck(form,item);
554: } else {
555: containerUncheck(form,item);
556: }
557: }
558:
559: function checkResource(form,item) {
1.7 raeburn 560: var elem = $elem;
561: if (form.elements[elem].checked == false) {
1.1 raeburn 562: containerUncheck(form,item);
563: }
564: }
565:
566: numitems = $numitems;
567: var parents = new Array(numitems);
568: var nesting = new Array(numitems);
569: var initial = new Array();
570: for (var i=$startcount; i<numitems; i++) {
571: parents[i] = new Array();
572: nesting[i] = new Array();
573: }
574:
575: START
576:
577: foreach my $container (sort { $a <=> $b } (keys(%{$children}))) {
578: my @contents = split(/:/,$children->{$container});
579: for (my $i=0; $i<@contents; $i ++) {
580: $scripttag .= 'parents['.$container.']['.$i.'] = '.$contents[$i]."\n";
581: }
582: }
583:
584: if ($context eq 'examblock') {
585: foreach my $item (sort { $a <=> $b } (keys(%{$hierarchy}))) {
586: $scripttag .= "nesting[$item] = new Array($hierarchy->{$item});\n";
587: }
588:
589: my @sorted_maps = sort { $a <=> $b } (@{$checked_maps});
590: for (my $i=0; $i<@sorted_maps; $i++) {
591: $scripttag .= "initial[$i] = '$sorted_maps[$i]'\n";
592: }
593: $scripttag .= <<"EXTRA";
594:
595: function recurseFolders() {
596: if (initial.length > 0) {
597: for (var i=0; i<initial.length; i++) {
598: containerCheck(document.$formname,initial[i]);
599: }
600: }
601: return;
602: }
603:
604: EXTRA
1.7 raeburn 605: } elsif ($context eq 'dumpdocs') {
606: my $blankmsg = &mt('An item selected has no filename set in the "Save as ..." column.');
607: my $dupmsg = &mt('Items selected for copying need unique filenames in the "Save as ..." column.');
1.11 bisitz 608: my $homemsg = &mt('An Authoring Space needs to be selected.');
1.13 damieng 609: &js_escape(\$blankmsg);
610: &js_escape(\$dupmsg);
611: &js_escape(\$homemsg);
1.7 raeburn 612: $scripttag .= <<"EXTRA";
613:
614: function checkUnique(form,field) {
615: var duplicate = 0;
616: var blank = 0;
1.9 raeburn 617: var numhome = '$numhome';
1.7 raeburn 618: if (field.length > 0) {
619: for (i=0; i<field.length; i++) {
620: if (field[i].checked) {
621: var item = field[i].value;
622: var namefor = document.getElementById('namefor_'+item);
623: if (namefor) {
624: var possval = namefor.value;
625: if (!possval) {
626: blank = item;
627: break;
628: }
629: for (j=i+1; j<field.length; j++) {
630: if (field[j].checked) {
631: var curritem = field[j].value;
632: var currnamefor = document.getElementById('namefor_'+curritem);
633: if (currnamefor) {
634: var currval = currnamefor.value;
635: if (currval == possval) {
636: duplicate = curritem;
637: break;
638: }
639: }
640: }
641: }
642: if (duplicate) {
643: break;
644: }
645: }
646: }
647: }
648: }
649: if (blank) {
650: alert('$blankmsg');
651: return false;
652: }
653: if (duplicate) {
654: alert('$dupmsg');
655: return false;
656: }
1.9 raeburn 657: if (numhome > 1) {
658: if (!form.authorspace.options[form.authorspace.selectedIndex].value) {
659: alert('$homemsg');
660: return false;
661: }
662: }
1.7 raeburn 663: return true;
664: }
665:
666: EXTRA
667:
1.1 raeburn 668: }
669:
670: $scripttag .= <<"END";
671:
672: function containerCheck(form,item) {
1.7 raeburn 673: var elem = $elem;
674: form.elements[elem].checked = true;
1.1 raeburn 675: if(Object.prototype.toString.call(parents[item]) === '[object Array]') {
676: if (parents[item].length > 0) {
677: for (var j=0; j<parents[item].length; j++) {
678: containerCheck(form,parents[item][j]);
679: }
680: }
681: }
682: }
683:
684: function containerUncheck(form,item) {
685: if(Object.prototype.toString.call(nesting[item]) === '[object Array]') {
686: if (nesting[item].length > 0) {
687: for (var i=0; i<nesting[item].length; i++) {
1.7 raeburn 688: var nested = $nested;
1.1 raeburn 689: }
690: }
691: }
692: return;
693: }
694:
695: END
696:
697: if ($context eq 'examblock') {
698: $scripttag .= <<ENDEX;
699: function writeToOpener(maps,resources) {
700: var checkedmaps = '';
701: var checkedresources = '';
702: for (var i=0; i<document.$formname.archive.length; i++) {
703: if (document.$formname.archive[i].checked) {
704: var isResource = 1;
705: var include = 1;
706: var elemnum = i+1+$startcount;
707: if (Object.prototype.toString.call(parents[elemnum]) === '[object Array]') {
708: if (parents[elemnum].length > 0) {
709: isResource = 0;
710: }
711: }
712: if (isResource == 1) {
1.12 raeburn 713: if (nesting[elemnum] != null) {
714: if (nesting[elemnum].length > 0) {
715: var lastelem = nesting[elemnum].length-1;
716: if (document.$formname.elements[nesting[elemnum][lastelem]].checked) {
717: include = 0;
718: }
1.1 raeburn 719: }
720: }
721: }
722: if (include == 1) {
723: if (isResource == 1) {
724: checkedresources += document.$formname.archive[i].value+',';
725: } else {
726: checkedmaps += document.$formname.archive[i].value+',';
727: }
728: }
729: }
730: }
731: opener.document.getElementById(maps).value = checkedmaps;
732: opener.document.getElementById(resources).value = checkedresources;
733: window.close();
734: return false;
735: }
736:
737: ENDEX
738: }
739:
740: $scripttag .= '
741: // ]]>
742: </script>
743: ';
744: return $scripttag;
745: }
746:
747: sub get_navmap_object {
748: my ($crstype,$context) = @_;
749: my $navmap = Apache::lonnavmaps::navmap->new();
750: my $outcome;
751: if (!defined($navmap)) {
752: if ($context eq 'imsexport') {
753: $outcome = &Apache::loncommon::start_page('Export '.$crstype.' to IMS Package').
754: '<h2>'.&mt('IMS Export Failed').'</h2>';
755: } elsif ($context eq 'examblock') {
756: $outcome = &Apache::loncommon::start_page('Selection of Resources for Blocking',
757: undef,{'only_body' => 1,}).
758: '<h2>'.&mt('Resource Display Failed').'</h2>';
1.7 raeburn 759: } elsif ($context eq 'dumpdocs') {
1.10 raeburn 760: $outcome = '<h2>'.&mt('Copying to Authoring Space unavailable');
1.7 raeburn 761: }
1.1 raeburn 762: $outcome .= '<div class="LC_error">';
763: if ($crstype eq 'Community') {
764: $outcome .= &mt('Unable to retrieve information about community contents');
765: } else {
766: $outcome .= &mt('Unable to retrieve information about course contents');
767: }
768: $outcome .= '</div>';
1.7 raeburn 769: if (($context eq 'imsexport') || ($context eq 'dumpdocs')) {
1.1 raeburn 770: $outcome .= '<a href="/adm/coursedocs">';
771: if ($crstype eq 'Community') {
772: $outcome .= &mt('Return to Community Editor');
773: } else {
774: $outcome .= &mt('Return to Course Editor');
775: }
776: $outcome .= '</a>';
1.7 raeburn 777: if ($context eq 'imsexport') {
778: &Apache::lonnet::logthis('IMS export failed - could not create navmap object in '.lc($crstype).':'.$env{'request.course.id'});
779: } else {
1.8 raeburn 780: &Apache::lonnet::logthis('Copying to Authoring Space failed - could not create navmap object in '.lc($crstype).':'.$env{'request.course.id'});
1.7 raeburn 781: }
1.1 raeburn 782: } elsif ($context eq 'examblock') {
783: $outcome .= '<href="javascript:window.close();">'.&mt('Close window').'</a>';
784: }
785: return (undef,$outcome);
786: } else {
787: return ($navmap);
788: }
789: }
790:
1.7 raeburn 791: sub clean {
792: my ($title)=@_;
793: $title=~s/[^\w\/\!\$\%\^\*\-\_\=\+\;\:\,\\\|\`\~]+/\_/gs;
794: return $title;
795: }
796:
797: sub enumerate_course_contents {
798: my ($navmap,$map_url,$resource_symb,$titleref,$context,$cdom,$cnum) = @_;
799: if ((ref($navmap)) && (ref($map_url) eq 'HASH') &&
800: (ref($resource_symb) eq 'HASH') && (ref($titleref) eq 'HASH')) {
801: my $it = $navmap->getIterator(undef,undef,undef,1,undef,undef);
802: my $count = 0;
803: while (my $curRes = $it->next()) {
804: if (ref($curRes)) {
805: my $symb = $curRes->symb();
806: my $ressymb = $symb;
807: if ($context eq 'dumpdocs') {
808: next unless (($curRes->src() =~ m{^\Q/uploaded/$cdom/$cnum/\E(docs|supplemental|simplepage)/}) ||
809: ($curRes->src() =~ m{^\Q/uploaded/$cdom/$cnum/\E(default|supplemental)_\d+\.(sequence|page)}) ||
810: ($curRes->src() eq '/res/lib/templates/simpleproblem.problem') ||
811: ($curRes->src() =~ m{^/adm/$match_domain/$match_username/\d+/smppg}));
812: } elsif ($ressymb =~ m{adm/($match_domain)/($match_username)/(\d+)/bulletinboard$}) {
813: unless ($ressymb =~ m{adm/wrapper/adm}) {
814: $ressymb = 'bulletin___'.$3.'___adm/wrapper/adm/'.$1.'/'.$2.'/'.$3.
815: '/bulletinboard';
816: }
817: }
818: $count ++;
819: if (($curRes->is_sequence()) || ($curRes->is_page())) {
820: $map_url->{$count} = (&Apache::lonnet::decode_symb($symb))[2];
821: } else {
822: $resource_symb->{$count} = $ressymb;
823: }
824: $titleref->{$count} = $curRes->title();
825: }
826: }
827: }
828: return;
829: }
830:
1.1 raeburn 831: 1;
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>