Annotation of modules/gci/londocsgci.pm, revision 1.17
1.1 gci 1: # The LearningOnline Network
2: # Custom Edit Course Routines for Assembly of Valid Concept Tests from
3: # Geoscience Concept Inventory.
4: #
1.17 ! gci 5: # $Id: londocsgci.pm,v 1.16 2010/11/29 04:33:35 gci Exp $
1.1 gci 6: #
7: # Copyright Michigan State University Board of Trustees
8: #
9: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
10: #
11: # LON-CAPA is free software; you can redistribute it and/or modify
12: # it under the terms of the GNU General Public License as published by
13: # the Free Software Foundation; either version 2 of the License, or
14: # (at your option) any later version.
15: #
16: # LON-CAPA is distributed in the hope that it will be useful,
17: # but WITHOUT ANY WARRANTY; without even the implied warranty of
18: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19: # GNU General Public License for more details.
20: #
21: # You should have received a copy of the GNU General Public License
22: # along with LON-CAPA; if not, write to the Free Software
23: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24: #
25: # /home/httpd/html/adm/gpl.txt
26: #
27: # http://www.lon-capa.org/
28: #
29:
30:
31: package Apache::londocsgci;
32:
33: use strict;
34:
35: use Apache::lonnet;
36: use Apache::loncommon;
37: use LONCAPA::map();
38: use Apache::lonindexer;
39: use Apache::lonlocal;
40: use LONCAPA qw(:DEFAULT :match);
41:
42: { #scope variables
43:
44: my $path;
45: my $version;
46: my $reqnum;
1.6 gci 47: my @mandcats;
48: my @bincats;
1.1 gci 49: my @categories;
50: my @allprobs;
51: my %probcat;
52: my %prereqs;
1.6 gci 53: my %revreqs;
1.1 gci 54: my @defchosen;
55: my @chosen;
1.5 gci 56: my @mandprobs;
57: my @bins;
58: my @optional;
1.3 gci 59: my %mandatory;
1.5 gci 60: my @development;
1.1 gci 61:
62: sub setdefaults {
1.17 ! gci 63: my ($cdom) = @_;
! 64: if ($cdom eq 'gcitest') {
! 65: $path='/res/gci/gci';
! 66: $version='GCIv2-1-1';
! 67: $reqnum=15;
! 68: @allprobs=('01','02','37','2004_73','03','04','05','06','07',
! 69: '08','10',
! 70: '09',
! 71: '11','12','13','14','15','16','17',
! 72: '18','69',
! 73: '19','20',
! 74: '21','22','23','24','25','26','27','28','29','30',
! 75: '31','32','33','34','35','36','38',
! 76: '39A','39B',
! 77: '40',
! 78: '41','42','43','44','45','46','47','48','49','50',
! 79: '51',
! 80: '52','57',
! 81: '53','54','55','56','58',
! 82: '60',
! 83: '61','62','63','64','65','66','67','68','70',
! 84: '71');
! 85: @bins = ( ['03','04','06'],
! 86: ['07','08','09'],
! 87: ['10','12','13','14','15','16','17'],
! 88: ['18','19','20','21','22','23','24','25'],
! 89: ['26','27','28','30'],
! 90: ['32','33','34','35','36'],
! 91: ['38','39A','39B','40','41','42','43','44','45','46'],
! 92: ['47','48','49','50','51','52','53'],
! 93: ['54','55','56','57','58','60','61','62'],
! 94: ['63','64','65'],
! 95: ['66','67','68','69','70','71']);
! 96: @optional = ('05','11','29','31');
! 97: @mandcats = ('M1','M2','M3','M4');
! 98: @bincats = ('A','B','C','D','E','F','G','H','I','J','K');
! 99: @categories=(@mandcats,@bincats);
! 100: %probcat =('01' => 'M1' ,'02' => 'M2' ,'37' => 'M3' ,'2004_73' => 'M4' ,
! 101: '03' => 'A' ,'04' => 'A','05' => '' ,'06' => 'A' ,'07' => 'B' ,
! 102: '08' => 'B' ,'09' => 'B' ,'10' => 'C' ,'11' => '' ,'12' => 'C' ,
! 103: '13' => 'C' ,'14' => 'C' ,'15' => 'C' ,'16' => 'C' ,'17' => 'C' ,'18' => 'D' ,'19' => 'D' ,'20' => 'D' ,
! 104: '21' => 'D' ,'22' => 'D' ,'23' => 'D' ,'24' => 'D' ,'25' => 'D' ,'26' => 'E' ,'27' => 'E' ,'28' => 'E' ,'29' => '' ,'30' => 'E' ,
! 105: '31' => '' ,'32' => 'F' ,'33' => 'F' ,'34' => 'F' ,'35' => 'F' ,'36' => 'F' ,'38' => 'G' ,
! 106: '39A'=> 'G' ,'39B'=> 'G' ,
! 107: '40' => 'G' ,
! 108: '41' => 'G' ,'42' => 'G' ,'43' => 'G' ,'44' => 'G' ,'45' => 'G' ,'46' => 'G' ,'47' => 'H' ,'48' => 'H' ,'49' => 'H' ,'50' => 'H' ,
! 109: '51' => 'H' ,'52' => 'H' ,'53' => 'H' ,'54' => 'I' ,'55' => 'I' ,'56' => 'I' ,'57' => 'I' ,'58' => 'I' ,
! 110: '60' => 'I' ,
! 111: '61' => 'I' ,'62' => 'I' ,'63' => 'J' ,'64' => 'J' ,'65' => 'J' ,'66' => 'K' ,'67' => 'K' ,'68' => 'K' ,'69' => 'K' ,'70' => 'K' ,
! 112: '71' => 'K');
! 113: %mandatory=('01' => 1 ,'02' => 1,'37' => 1, '2004_73' => 1);
! 114: @mandprobs = ('01','02','37','2004_73');
! 115: %prereqs=('10' => '08', '57' => '52', '69' => '18');
! 116: foreach my $item (keys(%prereqs)) {
! 117: $revreqs{$prereqs{$item}} = $item;
! 118: }
! 119: @defchosen=('01','02','03','07','12','18','26','32','37','38','47','54','63','66','2004_73');
! 120: @development = ('001','002','003','004','005','006','007','008','009','010','011','012','013','014','015','016','017','018','019','020','021','022','023','024','025','026','027');
1.6 gci 121: }
1.1 gci 122: }
123:
124: sub checkvalid {
1.17 ! gci 125: my ($cdom) = @_;
1.1 gci 126: my %covered=();
127: my %chosenproblems=();
128: my @errors=();
129: my $num=$#chosen+1;
130: if ($num<$reqnum) {
131: push(@errors,&mt('Test requires at least [_1] items, but has only [_2].',$reqnum,$num));
132: }
133: foreach my $item (@chosen) {
134: $chosenproblems{$item}=1;
135: $covered{$probcat{$item}}=1;
136: }
137: foreach my $cat (@categories) {
138: unless ($covered{$cat}) {
1.3 gci 139: push(@errors,&mt('Bin [_1] not covered.',$cat));
1.1 gci 140: }
141: }
142: foreach my $item (@chosen) {
143: if ($prereqs{$item}) {
144: unless ($chosenproblems{$prereqs{$item}}) {
1.17 ! gci 145: my $url = &fullurl($item,$cdom);
1.6 gci 146: my $title = &Apache::lonnet::metadata($url,'title');
1.17 ! gci 147: my $prerequrl = &fullurl($prereqs{$item},$cdom);
1.6 gci 148: my $prereqtitle = &Apache::lonnet::metadata($prerequrl,'title');
149: push(@errors,&mt('[_1] requires [_2].',"'$title'","'$prereqtitle'"));
1.1 gci 150: }
151: }
152: }
153: return @errors;
154: }
155:
156: sub fullurl {
1.17 ! gci 157: my ($item,$cdom,$catname)=@_;
! 158: if ($cdom eq 'gcitest') {
! 159: unless ($item=~/\_/) { $item='_'.$item; }
! 160: if ($catname eq 'development') {
! 161: return $path.'/pilot/pilot'.$item.'.problem';
! 162: }
! 163: return $path.'/'.$version.'/GCI'.$item.'.problem';
! 164: }
1.1 gci 165: }
166:
1.6 gci 167: sub item_from_url {
168: my ($url)=@_;
1.7 gci 169: if ($url =~ m{\Q$path\E/\Q$version\E/GCI_?([^.]+)\.problem$}) {
1.6 gci 170: return $1;
171: }
172: }
173:
1.3 gci 174: sub validcheck {
1.17 ! gci 175: my ($r,$cdom)=@_;
! 176: my @errors=&checkvalid($cdom);
1.1 gci 177: if ($#errors>-1) {
178: $r->print('<span class="LC_error">'.&mt('Your test is not yet valid.').'</span><p>'.&mt('The following issues must be addressed before you can use the test:').'<ul>');
179: foreach my $message (@errors) {
180: $r->print('<li>'.$message.'</li>');
181: }
182: $r->print('</ul></p>');
1.3 gci 183: return 0;
184: }
185: return 1;
186: }
187:
188: sub listresources {
1.5 gci 189: my ($r,$context,$cdom,$cnum)=@_;
190: my $numchosen = scalar(@chosen);
1.9 gci 191: my $multipart = 0;
192: my $composites;
193: if ($numchosen > 0) {
194: foreach my $key (keys(%prereqs)) {
195: if (grep(/^\Q$key\E/,@chosen)) {
196: $multipart ++;
197: $numchosen --;
198: }
199: }
200: if ($multipart) {
201: $composites = &mt(' (of which [quant,_1,is a combination question,are combination questions] in which students select both an answer, and the reasoning used).',$multipart).'<br />';
202: } else {
203: $composites = '. ';
204: }
205: }
1.5 gci 206: unless ($numchosen > 0) {
207: $r->print('<h3>'.&mt('Create a Concept Test').'</h3>'.
208: '<p>'.&mt('Choose how the test should be built:').'<br />'.
209: '<form name="choices" method="post" action="/adm/coursedocs" onsubmit="javascript:setDocsPhase();">'.
210: '<label><input type="radio" name="concepttest" value="defchosen" />'.&mt('Have a valid test built automatically by the WebCenter.').'</label><br />'.
211: '<label><input type="radio" name="concepttest" value="editmyown" checked="checked" />'.&mt('Make your own selection of questions from the Geoscience Concept Inventory.').'</label><br /><br />'.
212: '<input type="hidden" name="phase" value="" />'.
213: '<input type="submit" name="choosetest" value="'.&mt('Next').'"></p>');
214: return;
215: }
1.17 ! gci 216: if ((!&validcheck($r,$cdom)) || ($env{'form.concepttest'} eq 'editmyown')) {
1.5 gci 217: &editor($r,$context,$cdom,$cnum);
1.3 gci 218: } else {
1.5 gci 219: my $numsub = &get_submissions_count($cdom,$cnum);
220: unless ($env{'form.phase'} eq 'storemap') {
1.9 gci 221: $r->print('<p>'.&mt('This course contains a valid concept test which includes [quant,_1,question]',$numchosen).$composites.'<a href="/adm/navmaps" target="_coursecontents">'.&mt('Display Contents').'</a><br />');
1.5 gci 222: }
223: if ($numsub > 0) {
224: $r->print(&mt('As there are existing student submissions, modification of the [_1]contents[_2] of the Concept Test will result in loss of student performance data, and is [_3]not[_4] permitted.','<i>','</i>','<b>','</b>').'<br />'.&mt('Modification of open and close dates [_1]is[_2] permitted.','<b>','</b>').'</p>');
225: } else {
226: $r->print('<fieldset><legend>'.&mt('Modify Test').'</legend>'.
227: &mt('Currently no student submissions have been recorded, so you may modify the contents of the Concept Test.').
1.16 gci 228: '<br /><br /><form name="changetest" method="post" action="/adm/coursedocs">'.
1.5 gci 229: '<input type="hidden" name="concepttest" value="editmyown" />'.
230: '<input type="submit" name="modifytest" value="'.&mt('Edit Concept Test').'" /></form></fieldset></p>');
1.3 gci 231: }
1.5 gci 232: my ($crsparms,$ineffect,$parmlev) = ¤t_parms($cdom,$cnum);
233: my $formname = 'datesform';
234: my $datebutton = &mt('Save');
1.16 gci 235: my $hide_timezone = 1;
1.5 gci 236: my $startform =
237: &Apache::lonhtmlcommon::date_setter($formname,'opendate',
1.16 gci 238: $crsparms->{'opendate'},'','','',
239: '','','','','',$hide_timezone);
1.5 gci 240: my $endform =
241: &Apache::lonhtmlcommon::date_setter($formname,'duedate',
1.16 gci 242: $crsparms->{'duedate'},'','','',
243: '','','','','',$hide_timezone);
244: my $includeempty = 1;
245: my $timezone = &Apache::lonlocal::gettimezone();
246: my $tzform = &Apache::loncommon::select_timezone('timezone',$timezone,
247: undef,$includeempty);
1.5 gci 248: $r->print('<p><fieldset><legend>'.&mt('Test Availability').'</legend>'.
249: &mt('Open and close dates for test items for the concept test are currently set as follows:').
1.16 gci 250: '<br /><br />'.
1.5 gci 251: '<form name="'.$formname.'" method="post" '.
252: 'action="/adm/coursedocs">'.
253: &Apache::lonhtmlcommon::start_pick_box().
1.16 gci 254: &Apache::lonhtmlcommon::row_title(&mt('Time zone')).
255: $tzform.
256: &Apache::lonhtmlcommon::row_closure(1).
1.5 gci 257: &Apache::lonhtmlcommon::row_title(&mt('Open date')).
258: $startform.
1.6 gci 259: &Apache::lonhtmlcommon::row_closure(1).
1.5 gci 260: &Apache::lonhtmlcommon::row_title(&mt('Close date')).
261: $endform.
1.10 gci 262: &Apache::lonhtmlcommon::row_closure(1).
263: &Apache::lonhtmlcommon::end_pick_box().'<br />'.
1.5 gci 264: '<input type="hidden" name="phase" value="storeparms" />'.
265: '<input type="submit" value="'.$datebutton.'" />'.
266: '</form></fieldset></p>');
1.1 gci 267: }
1.3 gci 268: }
269:
270: sub editor {
1.5 gci 271: my ($r,$context,$cdom,$cnum)=@_;
272: my %chosenitems=();
273: my $havedev = 0;
274: foreach my $item (@chosen) {
275: $chosenitems{$item}=1;
276: }
277: my @devitems = &get_development_questions($cdom,$cnum);
278: &Apache::lonnet::appenv({'request.gcicontext' => 'buildtest'});
279: $r->print('<form name="selecteditems" method="post" action="/adm/coursedocs"
280: onsubmit="return validTestCheck()">');
281: $r->print(&mt('Select test items from the numbered bins below and then press [_1]"Store Problem Selection"[_2] at the bottom of the page.','<i>','</i>').'<br />');
1.17 ! gci 282: if ($cdom eq 'gcitest') {
! 283: $r->print('<ul>'.
! 284: '<li>'.&mt('Tests will contain a minimum of [_1] questions from the GCI 2 Inventory.',"<b>$reqnum</b>").'</li>'.
! 285: '<li>'.&mt('Tests must contain [_1]four[_2] mandatory questions and at least one item from each of [_1]eleven[_2] other bins.','<b>','</b>').'</li>'.
! 286: '<li>'.&mt('All tests conclude with [_1]two[_2] questions selected by the system (at random) from a pool of development questions being piloted by the GCI team.','<b>','</b>').'</li>'.
! 287: '</ul>');
! 288: }
1.5 gci 289: my $mandleg = &mt('Mandatory Questions');
1.17 ! gci 290: $r->print(&display_questions(\@mandprobs,'mandatory',$mandleg,\%chosenitems,$cdom));
1.5 gci 291: for (my $i=0; $i<@bins; $i++) {
292: my $num = $i+1;
293: my $legend = &mt('Bin [_1]',$num);
294: my $catname = 'bin'.$i;
1.17 ! gci 295: $r->print(&display_questions($bins[$i],$catname,$legend,\%chosenitems,$cdom));
1.5 gci 296: }
297: my $optleg = &mt('Optional Questions');
1.17 ! gci 298: $r->print(&display_questions(\@optional,'optional',$optleg,\%chosenitems,$cdom));
1.5 gci 299: my $devleg = &mt('Development Questions');
1.17 ! gci 300: $r->print(&display_questions(\@devitems,'development',$devleg,\%chosenitems,$cdom));
1.5 gci 301: $r->print('<input type="hidden" name="phase" value="storemap" />'.
302: '<input type="hidden" name="context" value="'.$context.'" />'.
1.14 gci 303: '<input type="hidden" name="concepttest" value="'.$env{'form.concepttest'}.'" />'.
1.5 gci 304: '<input type="submit" value="'.&mt('Store Problem Selection').'" />'.
305: '</form>');
306: &Apache::lonnet::delenv('request.gcicontext');
307: }
308:
309: sub display_questions {
1.17 ! gci 310: my ($questions,$catname,$catlegend,$chosenitems,$cdom) = @_;
1.5 gci 311: return unless((ref($questions) eq 'ARRAY') && (ref($chosenitems) eq 'HASH'));
312: my $total = 0;
313: foreach my $item (@{$questions}) {
314: if ($chosenitems->{$item}) {
315: $total ++;
316: }
317: }
318: my $fieldid = 'GCI_'.$catname.'_q';
319: my $titleid = 'GCI_'.$catname.'_t';
320: my $countid = 'GCI_'.$catname.'_count';
321: my $output = '<fieldset>';
322: my %fixed = (
323: mandatory => 4,
324: development => 2,
325: );
326: if (($catname eq 'mandatory') || ($catname eq 'development')) {
327: $output .= '<legend>'.&mt('[_1] [_2] selected automatically',$catlegend,
328: '<input type="text" name="'.$countid.'" size="1" '.
329: 'value="'.$fixed{$catname}.'" readonly="readonly" />').'</legend>';
330: } else {
331: $output .= '<legend>'.&mt('[_1]: currently [_2] selected',$catlegend,
1.10 gci 332: '<input type="text" name="'.$countid.'" id="'.$countid.'" size="1" value="'.
1.5 gci 333: $total.'" readonly="readonly" />').'</legend>';
334: }
335: $output .= '<span id="'.$titleid.'">'.
336: '<a href="javascript:showQuestions('."'$fieldid','$titleid'".')">'.
337: &mt('Show').'</a> ...</span><br />'.
1.13 gci 338: '<div id="'.$fieldid.'" style="display: none">'.
1.5 gci 339: &Apache::loncommon::start_data_table().
340: &Apache::loncommon::start_data_table_header_row();
341: unless (($catname eq 'development') || ($catname eq 'mandatory')) {
342: $output .= '<th>'.&mt('Select').'</th>';
343: }
344: $output .= '<th>'.&mt('Problem').
345: '</th><th>'.&mt('Preview').'</th>'.
346: &Apache::loncommon::end_data_table_header_row();
347: foreach my $item (@{$questions}) {
1.17 ! gci 348: my $url = &fullurl($item,$cdom,$catname);
1.5 gci 349: my $title = &Apache::lonnet::metadata($url,'title');
350: $output .= &Apache::loncommon::start_data_table_row().'<td>';
1.8 gci 351: if ($catname eq 'mandatory') {
1.5 gci 352: $output .= '<input type="hidden" name="item'.$item.'" value="checked" />';
1.8 gci 353: } elsif ($catname eq 'development') {
354: $output .= '<input type="hidden" name="pilot'.$item.'" value="checked" />';
1.5 gci 355: } else {
1.10 gci 356: $output .= '<input type="checkbox" name="item'.$item.'" id="item'.$item.'"';
1.5 gci 357: if ($chosenitems->{$item}) { $output .= ' checked="checked"'; }
1.6 gci 358: $output .= ' onclick="countChecked('."'$catname'".');';
359: my $binname;
360: if ($prereqs{$item}) {
361: for (my $i=0; $i<@bincats; $i++) {
362: if ($bincats[$i] eq $probcat{$prereqs{$item}}) {
363: $binname = 'bin'.$i;
364: last;
365: }
366: }
367: $output .= 'checkPrereqs('."'dep','$item','$prereqs{$item}','$binname'".');';
368: } elsif ($revreqs{$item}) {
369: for (my $i=0; $i<@bincats; $i++) {
370: if ($bincats[$i] eq $probcat{$item}) {
371: $binname = 'bin'.$i;
372: last;
373: }
374: }
375: $output .= 'checkPrereqs('."'pre','$revreqs{$item}','$item','$binname'".');';
376: }
377: $output .= '" />'.
1.5 gci 378: '<input type="hidden" name="container'.$item.'" value="'.
379: $catname.'"></td><td>';
380: }
381: $output .= '<b>'.$title.'</b></td>';
382: my $content=&Apache::lonindexer::showpreview($url);
1.12 gci 383: my $startformtag = '<form name="lonhomework" enctype="multipart/form-data" method="post" action="'.$url.'?inhibitmenu=yes" >';
384: my $endtag = '<table><tr><td><input onmouseup="javascript:setSubmittedPart';
385: $content =~ s/^\Q$startformtag\E//;
386: $content =~ s/\Q$endtag\E.+$//s;
1.5 gci 387: $output .= '<td> '.($content eq '' ? ' ':$content).' </td>'."\n".
388: &Apache::loncommon::end_data_table_row();
389: }
390: $output .= &Apache::loncommon::end_data_table().
391: '</div></fieldset><br />';
392: return $output;
393: }
394:
395: sub get_development_questions {
396: my ($cdom,$cnum) = @_;
397: my $cid = $cdom.'_'.$cnum;
398: my %courseenv = &Apache::lonnet::userenvironment($cdom,$cnum,
399: ('internal.courseowner'));
400: my $seed = $courseenv{'internal.courseowner'};
401: my $rndseed=&Apache::lonnet::rndseed($seed,$cid,$cdom,$cnum);
402: &Apache::lonnet::setup_random_from_rndseed($rndseed);
403: my @devitems = &Math::Random::random_permutation(@development);
404: return ($devitems[0],$devitems[1]);
1.1 gci 405: }
406:
407: sub evaluate {
408: if ($env{'form.phase'} eq 'storemap') {
409: @chosen=();
410: foreach my $item (@allprobs) {
411: if ($env{'form.item'.$item}) {
412: push(@chosen,$item);
413: }
414: }
415: }
416: }
417:
418: sub mapread_gci {
419: my $coursedom=$env{'course.'.$env{'request.course.id'}.'.domain'};
420: my $coursenum=$env{'course.'.$env{'request.course.id'}.'.num'};
1.17 ! gci 421: my $sequence = &Apache::loncommon::get_citest_map($coursedom);
1.1 gci 422: return
1.17 ! gci 423: &LONCAPA::map::mapread('/uploaded/'.$coursedom.'/'.$coursenum.'/'.$sequence);
1.1 gci 424: }
425:
426: sub storemap_gci {
1.5 gci 427: my ($coursedom,$coursenum) = @_;
428: if (($coursedom !~ /^$match_domain$/) || ($coursenum !~ /^$match_courseid$/)) {
429: $coursedom=$env{'course.'.$env{'request.course.id'}.'.domain'};
430: $coursenum=$env{'course.'.$env{'request.course.id'}.'.num'};
431: }
432: return ('unauthorized',2) if (($coursedom eq '') || ($coursedom eq '') ||
433: (!&Apache::lonnet::allowed('mdc',$coursedom.'_'.$coursenum)));
1.17 ! gci 434: my $sequence = &Apache::loncommon::get_citest_map($coursedom);
! 435: my ($outtext,$errtext);
! 436: if ($sequence) {
! 437: ($outtext,$errtext)=
! 438: &LONCAPA::map::storemap('/uploaded/'.$coursedom.'/'.$coursenum.'/'.$sequence,1);
! 439: }
1.1 gci 440: if ($errtext) { return ($errtext,2); }
441: return ($errtext,0);
442: }
443:
444: sub chosen_to_map {
1.17 ! gci 445: my ($cdom) = @_;
1.1 gci 446: my %chosenproblems=();
447: foreach my $item (@chosen) {
448: $chosenproblems{$item}=1;
449: }
450: @LONCAPA::map::order=();
451: @LONCAPA::map::resources=();
1.5 gci 452: my $counter = 0;
1.8 gci 453: my $residx;
1.1 gci 454: for (my $idx=0;$idx<=$#allprobs;$idx++) {
1.8 gci 455: $residx=$idx+1;
1.1 gci 456: if ($chosenproblems{$allprobs[$idx]}) {
1.17 ! gci 457: my $url = &LONCAPA::map::qtunescape(&fullurl($allprobs[$idx],$cdom));
1.6 gci 458: if (($revreqs{$allprobs[$idx]}) &&
459: ($chosenproblems{$revreqs{$allprobs[$idx]}})) {
1.7 gci 460: my $probnum = '_'.$allprobs[$idx].'_'.$revreqs{$allprobs[$idx]};
1.17 ! gci 461: $url = &LONCAPA::map::qtunescape(&fullurl($probnum,$cdom));
1.6 gci 462: } elsif ($prereqs{$allprobs[$idx]}) {
463: next;
464: }
1.1 gci 465: push(@LONCAPA::map::order,$residx);
1.5 gci 466: $counter ++;
467: my $name = &LONCAPA::map::qtunescape('Problem '.$counter);
1.1 gci 468: $LONCAPA::map::resources[$residx]=join(':', ($name, $url, 'false', 'normal', 'res'));
469: }
470: }
1.8 gci 471: foreach my $devitem (@development) {
472: if ($env{'form.pilot'.$devitem}) {
1.17 ! gci 473: my $url = &LONCAPA::map::qtunescape(&fullurl($devitem,$cdom,'development'));
1.8 gci 474: $residx ++;
475: push(@LONCAPA::map::order,$residx);
476: $counter ++;
477: my $name = &LONCAPA::map::qtunescape('Problem '.$counter);
478: $LONCAPA::map::resources[$residx]=join(':', ($name, $url, 'false', 'normal', 'res'));
479: }
480: }
1.1 gci 481: }
482:
483: sub map_to_chosen {
484: @chosen=();
485: foreach my $idx (@LONCAPA::map::order) {
1.6 gci 486: my ($title,$url)=split(':',$LONCAPA::map::resources[$idx]);
487: my $item;
1.5 gci 488: unless ($url eq '') {
1.6 gci 489: $item = &item_from_url($url);
490: if (($item =~ /^(\d+)_(\d+)$/) && ($prereqs{$2} eq $1)) {
491: push(@chosen,($1,$2));
492: } else {
493: push(@chosen,$item);
494: }
1.5 gci 495: }
496: }
497: if (($env{'form.concepttest'} eq 'defchosen') ||
498: ((@chosen == 0) && ($env{'form.concepttest'} eq 'editmyown'))) {
499: @chosen = @defchosen;
1.1 gci 500: }
501: }
502:
503: sub store {
1.5 gci 504: my ($caller,$cdom,$cnum)=@_;
505: if ($env{'form.concepttest'} eq 'defchosen') {
506: @chosen = @defchosen;
507: }
1.17 ! gci 508: my @errors=&checkvalid($cdom);
1.5 gci 509: if (@errors > 0) {
510: if (($caller eq 'requestcrs') && ($env{'form.concepttest'} eq 'defchosen')) {
1.6 gci 511: return &mt('Invalid concept test.');
1.5 gci 512: } else {
1.6 gci 513: my $errormsg = '<span class="LC_warning">'.&mt('Invalid concept test:');
514: if (@errors > 1) {
515: $errormsg .= '<ul><li>'.join('</li><li>',@errors).'</li></ul>';
516: } else {
517: $errormsg .= '<br />'.$errors[0];
518: }
519: $errormsg .= '</span>';
520: return $errormsg;
1.5 gci 521: }
522: }
1.1 gci 523: &chosen_to_map();
1.5 gci 524: my ($err,$errnum) = &storemap_gci($cdom,$cnum);
525: if ($caller eq 'requestcrs') {
526: if ($errnum == 0) {
527: return;
528: } else {
529: return 'An error occurred when storing the concept test';
530: }
531: }
1.3 gci 532: if ($env{'form.phase'} eq 'storemap') {
1.5 gci 533: if ($errnum == 0) {
534: &Apache::lonuserstate::readmap($cdom.'/'.$cnum);
535: return '<p>'.&mt('You have successfully assembled a valid test.').'</p>'.
536: '<p><a href="/adm/navmaps">'.&mt('Display Table of Contents').
537: '</a>'.(' ' x4).'<a href="/adm/menu">'.&mt('Return to Main Menu').'</a></p>';
538: } else {
539: return '<div class="LC_error">'.&mt('An error occurred when storing your concept test: [_1].',$err).'</div>';
1.3 gci 540: }
1.1 gci 541: }
1.5 gci 542: return;
1.1 gci 543: }
544:
545: sub load {
1.17 ! gci 546: my ($cdom) = @_;
1.1 gci 547: &mapread_gci();
548: &map_to_chosen();
1.5 gci 549: if (@chosen > 0) {
1.17 ! gci 550: my @errors=&checkvalid($cdom);
1.5 gci 551: if ($#errors>1) { @chosen=@defchosen; }
552: }
553: }
554:
555: sub current_parms {
556: my ($cdom,$cnum) = @_;
557: my $courseopt=&Apache::lonnet::get_courseresdata($cnum,$cdom);
558: my (%crsparms,%ineffect,%parmlev);
559: foreach my $item ('opendate','duedate') {
560: $crsparms{$item} = $courseopt->{$env{'request.course.id'}.'.0.'.$item};
561: my ($result,@outpar) =
562: &Apache::lonparmset::parmval('0.'.$item,'0.0',undef,undef,
563: $cdom,undef,undef,$courseopt);
564: if ($result) {
565: $ineffect{$item} = $outpar[$result];
566: $parmlev{$item} = $result;
567: }
568: }
569: return (\%crsparms,\%ineffect,\%parmlev);
570: }
571:
572: sub store_dates_parms {
573: my ($cdom,$cnum) = @_;
574: my $topsymb = '___0___uploaded/'.$cdom.'/'.$cnum.'/default.sequence';
1.16 gci 575: my $tz_change;
576: my $timezone = &Apache::lonlocal::gettimezone();
577: if ($env{'form.timezone'} ne '') {
578: if (&Apache::lonlocal::gettimezone($env{'form.timezone'}) ne 'local') {
579: if ($timezone ne $env{'form.timezone'}) {
580: $tz_change = 1;
581: $timezone = $env{'form.timezone'};
582: }
583: }
584: }
1.5 gci 585: my ($opendate,$duedate) =
1.16 gci 586: &Apache::lonuserutils::get_dates_from_form('opendate','duedate',$timezone);
1.5 gci 587: my %dates = (
588: opendate => {
589: value => $opendate,
590: type => 'date_start',
591: },
592: duedate => {
593: value => $duedate,
594: type => 'date_end',
595: },
596: );
597: my %parmresult;
598: foreach my $date (keys(%dates)) {
599: $parmresult{$date} =
600: &Apache::lonparmset::storeparm_by_symb($topsymb,
601: '0_'.$date,14,$dates{$date}{'value'},
602: $dates{$date}{'type'},undef,$cdom);
603: }
1.16 gci 604: if ($tz_change) {
605: &Apache::lonnet::appenv({'course.'.$env{'request.course.id'}.'.timezone' => $timezone});
606: }
1.5 gci 607: my $output = &mt('Open and Close dates set for test items').'<ul>'.
608: '<li>'.&mt('Concept Test Questions open:').' '.
1.16 gci 609: &Apache::lonlocal::locallocaltime($opendate,$timezone).'</li>'.
1.5 gci 610: '<li>'.&mt('Concept Test Questions close:').' '.
1.16 gci 611: &Apache::lonlocal::locallocaltime($duedate,$timezone).'</li>'.
1.5 gci 612: '</ul>';
613: return $output;
614: }
615:
616: sub get_submissions_count {
617: my ($cdom,$cnum) = @_;
618: my $navmap = Apache::lonnavmaps::navmap->new();
619: if (!defined($navmap)) {
620: my $itemserror = '<span class="LC_warning">'.&mt('An error occurred retrieving information about the course.').'<br />'.&mt('It is recommended that you [_1]re-select the course[_2].','<a href="/adm/roles">','</a>').'</span>';
621: return $itemserror;
622: }
1.17 ! gci 623: my (%resourcetracker,$submissioncount,@allres);
! 624: my $sequence = &Apache::loncommon::get_citest_map($cdom);
! 625: @allres=$navmap->retrieveResources('/uploaded/'.$cdom.'/'.$cnum.'/'.$sequence,sub {if ($_[0]->is_problem) { $_[0]->parts();} return 1;});
! 626: %resourcetracker = &Apache::lonnet::dump('nohist_resourcetracker',
! 627: $cdom,$cnum);
1.5 gci 628: foreach my $resource (@allres) {
629: my $symb = $resource->symb();
630: my @parts = @{$resource->parts()};
631: foreach my $part (@parts) {
632: if ($resource->handgrade($part) eq 'yes') {
633: next;
634: }
635: if ($resource->is_survey($part)) {
636: next;
637: }
638: if (exists($resourcetracker{$symb."\0".$part."\0users"})) {
639: $submissioncount += $resourcetracker{$symb."\0".$part."\0users"};
640: }
641: }
642: }
643: return $submissioncount;
644: }
645:
646: sub builder_javascript {
1.17 ! gci 647: my ($cdom) = @_;
1.5 gci 648: my %lt = &Apache::lonlocal::texthash(
649: show => 'Show',
650: hide => 'Hide',
651: );
1.6 gci 652: my $prereqjs = "
653: function checkPrereqs(caller,item,prereq,binname) {
654: var changedPrereq = 0;
1.10 gci 655: element = document.getElementById('item'+item);
656: if (element.checked == false) {
1.6 gci 657: return;
658: } else {
1.10 gci 659: prereqelement = document.getElementById('item'+prereq);
660: if (!prereqelement.checked) {
661: prereqelement.checked = true;
1.6 gci 662: changedPrereq = 1;
663: countChecked(binname);
664: }
665: }
666: ";
667:
668: my ($hasdep,$prereq,$hasdeptitle,$prereqtitle) = ('','','','');
669: foreach my $item (sort(keys(%prereqs))) {
670: $hasdep .= "'$item',";
671: $prereq .= "'$prereqs{$item}',";
1.17 ! gci 672: my $url = &fullurl($item,$cdom);
1.6 gci 673: $hasdeptitle .= "'".&Apache::lonnet::metadata($url,'title')."',";
1.17 ! gci 674: my $purl = &fullurl($prereqs{$item},$cdom);
1.6 gci 675: $prereqtitle .= "'".&Apache::lonnet::metadata($purl,'title')."',";
676: }
677: $hasdep =~ s/,$//;
678: $prereq =~ s/,$//;
679: $hasdeptitle =~ s/,$//;
680: $prereqtitle =~ s/,$//;
681:
682: $prereqjs .= <<"ENDFN";
683:
684: var hasDeps = Array($hasdep);
685: var preReqs = Array($prereq);
686: var hasDepTitles = Array($hasdeptitle);
687: var preReqTitles = Array($prereqtitle);
688: for (var i=0; i<hasDeps.length; i++) {
689: if (hasDeps[i] == item) {
690: var msg = hasDepTitles[i]+' question has a prerequisite: '+preReqTitles[i]+'.\\nThe two questions will appear together in a composite question.';
691: if (changedPrereq == 1) {
692: msg = msg+'\\n\\nAs the prerequisite was not checked, inclusion of '+hasDepTitles[i]+' has now caused '+preReqTitles[i]+' to also be checked automatically.';
693: }
694: if (caller == 'pre') {
695: msg = msg +'\\n\\nIf you do not wish to include '+preReqTitles[i]+' you will first need to uncheck '+hasDepTitles[i]+', then uncheck '+preReqTitles[i]+' again.'
696: }
697: alert(msg);
698: break;
699: }
700: }
701: return;
702: }
703:
704: ENDFN
705:
1.5 gci 706: return <<ENDJS;
707: function showQuestions(content,title) {
708: document.getElementById(content).style.display = "";
709: document.getElementById(title).innerHTML='<a href="javascript:hideQuestions('+"'"+content+"','"+title+"'"+');">$lt{'hide'}</a> ...';
710: return;
711: }
712:
713: function hideQuestions(content,title) {
714: document.getElementById(content).style.display = "none";
715: document.getElementById(title).innerHTML='<a href="javascript:showQuestions('+"'"+content+"','"+title+"'"+')">$lt{'show'}</a> ...';
716: return;
717: }
718:
719: function countChecked(binname) {
720: var count = 0;
721: for (var i=0; i<document.selecteditems.elements.length; i++) {
722: if (document.selecteditems.elements[i].type == "hidden") {
723: if (document.selecteditems.elements[i].value == binname) {
724: var itemname = document.selecteditems.elements[i].name;
725: var itemnum = itemname.substr(9);
1.10 gci 726: element = document.getElementById('item'+itemnum);
727: if (element.checked) {
1.5 gci 728: count ++;
729: }
730: }
731: }
732: }
1.10 gci 733: countelement = document.getElementById('GCI_'+binname+'_count');
734: countelement.value = count;
1.5 gci 735: }
736:
737: function validTestCheck() {
738: var empty = '';
739: for (var i=0; i<11; i++) {
740: var binname = 'GCI_bin'+i+'_count';
741: var j = i+1;
1.10 gci 742: countelement = document.getElementById(binname);
743: if (countelement.value < 1) {
1.5 gci 744: empty = empty +' '+j;
745: }
746: }
747: if (empty != "") {
748: alert("Current test invalid - select at least one item from the following bin(s): "+empty);
749: return false;
750: }
751: return true;
752: }
753:
754: function setDocsPhase() {
755: if (document.choices.concepttest.length) {
756: for (var i=0; i<document.choices.concepttest.length; i++) {
757: if (document.choices.concepttest[i].checked) {
758: if (document.choices.concepttest[i].value == 'defchosen') {
759: document.choices.phase.value = 'storemap';
760: }
761: }
762: }
763: }
764: return;
765: }
766:
1.6 gci 767: $prereqjs
768:
1.5 gci 769: ENDJS
770:
1.1 gci 771: }
772:
773: } #end scope variables
774:
775: 1;
776: __END__
777:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>