# The LearningOnline Network # # $Id: loncourserespicker.pm,v 1.4 2013/01/14 18:47:14 bisitz Exp $ # # Copyright Michigan State University Board of Trustees # # This file is part of the LearningOnline Network with CAPA (LON-CAPA). # # LON-CAPA is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # LON-CAPA is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with LON-CAPA; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # /home/httpd/html/adm/gpl.txt # # http://www.lon-capa.org/ # =pod =head1 NAME loncourserespicker - Utilities to choose folders and resources in a course. =head1 SYNOPSIS loncourserespicker provides an interface for selecting which folders and/or resources are to be either: (a) exported to an IMS Content Package (b) subject to access blocking for the duriation of an exam/quiz. =head1 DESCRIPTION This module provides routines to generate a hierarchical display of folders and resources in a course which can be selected for specific actions. The choice of items is copied back to the main window from which the pop-up window used to display the Course Contents was opened. =head1 OVERVIEW The main subroutine: &create_picker() will display the hierarchy of folders, sub-folders, and resources in the Main Course Documents area. Items can be selected using checkboxes, and/or a "Check All" button. Selection of a folder causes the contents of the folder to also be selected automatically. The propagation of check status is recursive into sub-folders. Likewise, if an item deep in a nested set of folders and sub-folders is unchecked, the uncheck will propagate up through the hierarchy causing any folders at a higher level to become unchecked. There is a submit button, which will be named differently according to the content in which resource/folder selection is being made. The two contexts currently supported are: IMS export and selection of content to be subject to access restructions for the duration of an exam. =head1 INTERNAL SUBROUTINES =item &create_picker() Created HTML mark up to display contents of course with checkboxes to select items. Checking a folder causes recursive checking of items within the folder. Unchecking a resource causing unchecking of folders containing the item back up to the top level. Inputs: 7. - $navmap -- Reference to LON-CAPA navmap object (encapsulates information about resources in the course). - $context -- Context in which course resource selection is being made. Currently imsexport and examblock are supported. - $formname -- Name of the form in the window from which the pop-up used to select course items was launched. - $crstype -- Course or Community - $blockedmaps -- Reference to hash of previously selected maps (e.g., for a live exam block). - $blockedresources -- Reference to hash of resources selected previously (e.g., for an exam block). - $block -- An internal ID (integer) used to track which exam block currently being configured. Output: $output is the HTML mark-up for display/selection of content items in the pop-up window. =item &respicker_javascript() Creates javascript functions for checking/unchecking all items, and for recursive checking triggered by checking a folder, or recursive (upeards) unchecking of an item within a folder. Inputs: 7. - $startcount -- Starting offset of form element numbering for items - $numcount -- Total numer of folders and resources in course. - $context -- Context in which resources are being displayed (imsexport or examblock). - $formname -- Name of form. - $children -- Reference to hash of items contained within a folder. - $hierarchy -- Reference to hierarchy of folders containing an item. - $checked_maps -- Reference to array of folders currently checked. Output: 1. Javascript (witthin tags. =item &get_navmap_object() Instantiates a navmaps object, and generates an error message if no object instantiated. Inputs: 2. - $crstype -- Container type: Course or Community - $context -- Context: imsexport or examblock =over =back =cut package Apache::loncourserespicker; use strict; use Apache::lonnet; use Apache::loncommon; use Apache::lonhtmlcommon; use Apache::lonnavmaps; use Apache::londocs; use Apache::lonlocal; use LONCAPA qw(:DEFAULT :match); sub create_picker { my ($navmap,$context,$formname,$crstype,$blockedmaps,$blockedresources,$block) = @_; return unless (ref($navmap)); my ($it,$output,$numdisc,%maps,%resources,%discussiontime,%currmaps,%currresources); $it = $navmap->getIterator(undef,undef,undef,1,undef,undef); if (ref($blockedmaps) eq 'HASH') { %currmaps = %{$blockedmaps}; } if (ref($blockedresources) eq 'HASH') { %currresources = %{$blockedresources}; } my @checked_maps; my $curRes; my $numprobs = 0; my $depth = 0; my $count = 0; my $boards = 0; my $startcount = 1; my %parent = (); my %children = (); my %hierarchy = (); my $location=&Apache::loncommon::lonhttpdurl("/adm/lonIcons"); my $whitespace = ''; my $onsubmit; if ($context eq 'examblock') { my $maps_elem = 'docs_maps_'.$block; my $res_elem = 'docs_resources_'.$block; $onsubmit = ' onsubmit="return writeToOpener('."'$maps_elem','$res_elem'".');"'; } my $display = '
'."\n". '

'; if ($context eq 'imsexport') { $display .= &mt('Choose which items you wish to export from your '. $crstype.'.'); $startcount = 5; } elsif ($context eq 'examblock') { $display .= &mt('Items in '.lc($crstype).' for which access will be blocked.'); } $display .= '

'; if ($context eq 'imsexport') { $display .= '
'."\n". '
'. ''.&mt('Content items').''."\n"; } $display .= ''. '  '; if ($context eq 'imsexport') { $display .= '
'; %discussiontime = &Apache::lonnet::dump('discussiontimes', $env{'course.'.$env{'request.course.id'}.'.domain'}, $env{'course.'.$env{'request.course.id'}.'.num'}); $numdisc = keys(%discussiontime); if ($numdisc > 0) { $display .= '
'. ''.&mt('Discussion posts').''. ''. '  '. '
'; } $display .= '
'; } my $lastcontainer = $startcount; $display .= &Apache::loncommon::start_data_table() .&Apache::loncommon::start_data_table_header_row(); if ($context eq 'imsexport') { $display .= ''.&mt('Export content item?').''; if ($numdisc > 0) { $display .= ''.&mt('Export discussion posts?').''; } } elsif ($context eq 'examblock') { $display .= ''.&mt('Access blocked?').''; } $display .= &Apache::loncommon::end_data_table_header_row(); while ($curRes = $it->next()) { if (ref($curRes)) { $count ++; } if ($curRes == $it->BEGIN_MAP()) { $depth++; $parent{$depth} = $lastcontainer; } if ($curRes == $it->END_MAP()) { $depth--; $lastcontainer = $parent{$depth}; } if (ref($curRes)) { my $symb = $curRes->symb(); my $ressymb = $symb; if ($ressymb =~ m|adm/($match_domain)/($match_username)/(\d+)/bulletinboard$|) { unless ($ressymb =~ m|adm/wrapper/adm|) { $ressymb = 'bulletin___'.$3.'___adm/wrapper/adm/'.$1.'/'.$2.'/'.$3.'/bulletinboard'; } } my $currelem = $count+$boards+$startcount; $display .= &Apache::loncommon::start_data_table_row(). ''."\n". 'is_sequence()) || ($curRes->is_page())) { $lastcontainer = $currelem; $display .= 'onclick="javascript:checkFolder(this.form,'."'$currelem'".')" '; my $mapurl = (&Apache::lonnet::decode_symb($symb))[2]; if ($currmaps{$mapurl}) { $display .= 'checked="checked"'; push(@checked_maps,$currelem); } } else { if ($curRes->is_problem()) { $numprobs ++; } $display .= 'onclick="javascript:checkResource(this.form,'."'$currelem'".')" '; if ($currresources{$symb}) { $display .= 'checked="checked"'; } } $display .= ' />'."\n"; for (my $i=0; $i<$depth; $i++) { $display .= "$whitespace\n"; } my $icon = 'src="'.$location.'/unknown.gif" alt=""'; if ($curRes->is_sequence()) { $icon = 'src="'.$location.'/navmap.folder.open.gif" alt="'.&mt('Folder').'"'; } elsif ($curRes->is_page()) { $icon = 'src="'.$location.'/navmap.page.open.gif" alt="'.&mt('Composite Page').'"'; } elsif ($curRes->is_problem()) { $icon = 'src="'.$location.'/problem.gif" alt="'.&mt('Problem').'"'; } elsif ($curRes->is_task()) { $icon = 'src="'.$location.'/task.gif" alt="'.&mt('Task').'"'; } elsif ($curRes->src ne '') { $icon = 'src="'.&Apache::loncommon::icon($curRes->src).'" alt=""'; } $display .= ' '."\n"; $children{$parent{$depth}} .= $currelem.':'; if ($context eq 'examblock') { if ($parent{$depth} > 1) { if ($hierarchy{$parent{$depth}}) { $hierarchy{$currelem} = $hierarchy{$parent{$depth}}.",'$parent{$depth}'"; } else { $hierarchy{$currelem} = "'$parent{$depth}'"; } } } $display .= ' '.$curRes->title().''."\n"; if ($context eq 'imsexport') { # Existing discussion posts? if ($discussiontime{$ressymb} > 0) { $boards ++; $display .= '' .'' .''."\n"; } elsif ($numdisc > 0) { $display .= ' '."\n"; } } $display .= &Apache::loncommon::end_data_table_row(); } } $display .= &Apache::loncommon::end_data_table(); if ($context eq 'imsexport') { if ($numprobs > 0) { $display .= '

'. &mt('Export format for LON-CAPA problems:'). ''.(' ' x3). ''.(' ' x3). '

'; } } $display .= '

'; if ($context eq 'imsexport') { $display .= ''. ''; } elsif ($context eq 'examblock') { $display .= ''; } $display .= '

'; my $numcount = $count + $boards + $startcount; my $scripttag = &respicker_javascript($startcount,$numcount,$context,$formname,\%children, \%hierarchy,\@checked_maps); my ($title,$crumbs,$args); if ($context eq 'imsexport') { $title = 'Export '.$crstype.' to IMS Package'; } elsif ($context eq 'examblock') { $title = 'Resources with Access blocked'; $args = {'only_body' => 1, 'add_entries' => { onload => 'javascript:recurseFolders();' }, }; } $output = &Apache::loncommon::start_page($title,$scripttag,$args); if ($context eq 'imsexport') { $output .= &Apache::lonhtmlcommon::breadcrumbs('IMS Export'). &Apache::londocs::startContentScreen('tools'); } $output .= $display; if ($context eq 'examblock') { $output .= &Apache::loncommon::end_page(); } elsif ($context eq 'imsexport') { $output .= &Apache::londocs::endContentScreen(); } return $output; } sub respicker_javascript { my ($startcount,$numitems,$context,$formname,$children,$hierarchy, $checked_maps) = @_; return unless ((ref($children) eq 'HASH') && (ref($hierarchy) eq 'HASH') && (ref($checked_maps) eq 'ARRAY')); my $scripttag = <<"START"; '; return $scripttag; } sub get_navmap_object { my ($crstype,$context) = @_; my $navmap = Apache::lonnavmaps::navmap->new(); my $outcome; if (!defined($navmap)) { if ($context eq 'imsexport') { $outcome = &Apache::loncommon::start_page('Export '.$crstype.' to IMS Package'). '

'.&mt('IMS Export Failed').'

'; } elsif ($context eq 'examblock') { $outcome = &Apache::loncommon::start_page('Selection of Resources for Blocking', undef,{'only_body' => 1,}). '

'.&mt('Resource Display Failed').'

'; } $outcome .= '
'; if ($crstype eq 'Community') { $outcome .= &mt('Unable to retrieve information about community contents'); } else { $outcome .= &mt('Unable to retrieve information about course contents'); } $outcome .= '
'; if ($context eq 'imsexport') { $outcome .= ''; if ($crstype eq 'Community') { $outcome .= &mt('Return to Community Editor'); } else { $outcome .= &mt('Return to Course Editor'); } $outcome .= ''; &logthis('IMS export failed - could not create navmap object in '.lc($crstype).':'.$env{'request.course.id'}); } elsif ($context eq 'examblock') { $outcome .= ''.&mt('Close window').''; } return (undef,$outcome); } else { return ($navmap); } } 1;