Annotation of loncom/homework/chemresponse.pm, revision 1.101
1.1 albertel 1: # The LearningOnline Network with CAPA
2: # chemical equation style response
3: #
1.101 ! raeburn 4: # $Id: chemresponse.pm,v 1.100 2021/04/07 22:16:03 raeburn Exp $
1.1 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: #
28: #
29: package Apache::chemresponse;
30: use strict;
31: use Apache::lonxml;
32: use Apache::lonnet;
1.55 albertel 33: use Apache::lonlocal;
1.66 www 34: use lib '/home/httpd/lib/perl/';
35: use LONCAPA;
36:
1.1 albertel 37:
38: BEGIN {
1.46 albertel 39: &Apache::lonxml::register('Apache::chemresponse',('organicresponse','organicstructure','reactionresponse','chem'));
1.1 albertel 40: }
41:
1.34 albertel 42: sub chem_standard_order {
43: my ($reaction) = @_;
44: my ($re,$pr) = split(/->|<=>/,$reaction);
45: my @reactants = split(/\s\+/,$re);
46: my @products = split(/\s\+/,$pr);
47: foreach my $substance (@reactants,@products) {
48: $substance =~ s/(\^\d*)\s+/$1_/g; # protect superscript space
49: $substance =~ s/\s*//g; # strip whitespace
50: $substance =~ s/_/ /g; # restore superscript space
51: }
52: @reactants = sort @reactants;
53: @products = sort @products;
54: my $standard = '';
55: foreach my $substance (@reactants) {
56: $standard .= $substance;
57: $standard .= ' + ';
58: }
59: $standard =~ s/ \+ $//; # get rid of trailing plus sign
60: $standard .= ' -> ';
61: foreach my $substance (@products) {
62: $standard .= $substance;
63: $standard .= ' + ';
64: }
65: $standard =~ s/ \+ $//; # get rid of trailing plus sign
66: return $standard;
67: }
68:
1.30 www 69: sub separate_jme_window {
1.55 albertel 70: my ($smile_input,$jme_input,$molecule,$options,$shown_text)=@_;
1.94 raeburn 71: my $usejsme = 1;
1.95 raeburn 72: if (($env{'request.course.id'}) && ($env{'request.state'} ne 'construct')) {
73: if (exists($env{'course.'.$env{'request.course.id'}.'.usejsme'})) {
74: if ($env{'course.'.$env{'request.course.id'}.'.usejsme'} eq '0') {
75: $usejsme = 0;
76: }
77: } else {
78: my %domdefs = &Apache::lonnet::get_domain_defaults($env{'course.'.$env{'request.course.id'}.'.domain'});
79: if ($domdefs{'usejsme'} eq '0') {
80: $usejsme = 0;
81: }
82: }
83: } else {
84: my %domdefs = &Apache::lonnet::get_domain_defaults($env{'course.'.$env{'request.course.id'}.'.domain'});
85: if ($domdefs{'usejsme'} eq '0') {
86: $usejsme = 0;
87: }
88: }
89: if ($usejsme) {
1.96 raeburn 90: if ($env{'browser.type'} eq 'safari') {
91: unless ($env{'browser.mobile'}) {
1.97 raeburn 92: if ($env{'browser.version'} < 534) {
1.96 raeburn 93: $usejsme = 0;
94: }
95: }
96: } elsif ($env{'browser.type'} eq 'mozilla') {
97: if ($env{'browser.version'} < 5) {
98: $usejsme = 0;
99: } elsif ($env{'browser.info'} =~ /^firefox\-([\d\.]+)/) {
100: my $firefox = $1;
101: if ($firefox < 12) {
102: $usejsme = 0;
103: }
104: }
105: } elsif ($env{'browser.type'} eq 'explorer') {
106: if ($env{'browser.version'} < 7) {
107: $usejsme = 0;
108: }
109: } elsif ($env{'browser.type'} eq 'opera') {
110: if ($env{'browser.version'} < 15) {
1.95 raeburn 111: $usejsme = 0;
112: }
113: }
114: } else {
115: if ($env{'browser.mobile'}) {
116: $usejsme = 1;
117: }
118: }
1.94 raeburn 119: my $linkstyle = 'display:none';
120: my $creditstyle = 'display:inline';
121: if ($env{'browser.type'} eq 'explorer') {
122: if (($env{'browser.os'} eq 'win') && ($env{'browser.version'} < 9)) {
123: $linkstyle = 'display:inline';
124: $creditstyle = 'display:none';
125: }
126: }
1.2 albertel 127: my $smilesection;
128: if (defined($smile_input)) {
1.94 raeburn 129: my $smiles;
130: if ($usejsme) {
131: $smiles = 'document.JME.smiles()';
132: } else {
133: $smiles = 'document.applets.JME.smiles()';
134: }
1.2 albertel 135: $smilesection=<<SMILESECTION;
1.94 raeburn 136: opener.document.lonhomework.$smile_input.value = $smiles;
1.2 albertel 137: SMILESECTION
138: }
139: my $jmesection;
1.94 raeburn 140: my $jmefile;
1.2 albertel 141: if (defined($jme_input)) {
1.94 raeburn 142: if ($usejsme) {
143: $jmefile = 'document.JME.jmeFile()';
144: } else {
145: $jmefile = 'document.applets.JME.jmeFile()';
146: }
1.2 albertel 147: $jmesection=<<JMESECTION;
1.94 raeburn 148: opener.document.lonhomework.$jme_input.value = $jmefile;
1.2 albertel 149: JMESECTION
150: }
151:
1.94 raeburn 152: if ($molecule) {
153: if ($usejsme) {
154: $molecule = 'document.JME.readMolecule("'.$molecule.'")';
155: } else {
156: $molecule='<param name="jme" value="'.$molecule.'" />';
157: }
158: }
1.57 albertel 159: my $insert_answer;
1.59 albertel 160: if ($shown_text eq '') {
1.57 albertel 161: $insert_answer=
1.94 raeburn 162: '<input type="button" name="submit" value="'.&mt('Insert Answer').'" onclick="javascript:submitSmiles();" /><br />';
163: }
164:
165:
166:
167: my ($jsme_js,$js,$buttonstyle,$viewportjs,$resizejs);
168: if ($usejsme) {
169: $buttonstyle = 'display:none';
170: $resizejs =<<RESIZEJS;
171: <script type="text/javascript">
172: function callResize() {
173: var timer;
174: clearTimeout(timer);
175: timer=setTimeout('resize_jsme()',100);
176: }
177:
178: window.onresize = callResize;
179:
180: function resize_jsme() {
181: init_geometry();
182: var vph = Geometry.getViewportHeight();
183: var vpw = Geometry.getViewportWidth();
184: var lowerdivheight = document.getElementById('JMEbuttons').offsetHeight;
185: var formheight = document.getElementById('JMEform').offsetHeight;
186: var freevspace = vph-(lowerdivheight+50);
187: var freehspace = vpw-20;
188: if (typeof jsmeApplet !== 'undefined') {
189: jsmeApplet.setSize(freehspace,freevspace);
190: }
191: }
192: </script>
193: RESIZEJS
194: $resizejs = &Apache::loncommon::js_ready($resizejs);
195: $jsme_js = '
196: <script type="text/javascript" language="javascript" src="/adm/jsme/jsme.nocache.js"></script>'."\n";
197: $js =<<CHEMJS;
198: <script type="text/javascript">
199: function jsmeOnLoad() {
200: document.getElementById('JMErefresh').style.display="none";
201: document.getElementById('JMEcredits').style.display="inline";
1.100 raeburn 202: jsmeApplet = new JSApplet.JSME("jme", "420px", "330px", {"options" : "$options"});
1.94 raeburn 203: document.JME = jsmeApplet;
204: $molecule;
205: document.getElementById('JMEbuttons').style.display="block";
206: callResize();
207: }
208:
209: function submitSmiles() {
210: jmeFile = document.JME.jmeFile();
211: if (jmeFile == "") {
212: alert("Nothing to submit");
213: } else {
214: $jmesection
215: $smilesection
216: window.close();
1.57 albertel 217: }
1.94 raeburn 218: }
219: function openHelpWindow() {
220: window.open("http://peter-ertl.com/jsme/2013_03/help.html","","scrollbars=yes,resizable=yes,width=500,height=600");
221: }
222:
223: </script>
224:
225: CHEMJS
1.57 albertel 226:
1.94 raeburn 227: $viewportjs = &Apache::loncommon::viewport_geometry_js();
228: $viewportjs = '<script type="text/javascript">'."\n".
229: $viewportjs."\n".
230: '</script>';
231:
232: } else {
233: $buttonstyle = 'display:block';
234: $js =<<CHEMJS;
1.47 albertel 235: <script type="text/javascript">
1.1 albertel 236: function submitSmiles() {
1.21 albertel 237: jmeFile = document.applets.JME.jmeFile();
238: if (jmeFile == "") {
1.1 albertel 239: alert("Nothing to submit");
240: } else {
1.21 albertel 241: $jmesection
1.2 albertel 242: $smilesection
1.1 albertel 243: window.close();
244: }
245: }
246: function openHelpWindow() {
1.2 albertel 247: window.open("/adm/jme/jme_help.html","","scrollbars=yes,resizable=yes,width=500,height=600");
1.1 albertel 248: }
1.60 albertel 249: function substituent(r) {document.applets.JME.setSubstituent(r);}
1.1 albertel 250: </script>
1.65 albertel 251: CHEMJS
1.94 raeburn 252: }
1.65 albertel 253:
254: my $start_page =
1.94 raeburn 255: &Apache::loncommon::start_page('Molecule Editor',$viewportjs,
1.65 albertel 256: {'only_body' => 1,
1.69 albertel 257: 'js_ready' => 1,
1.65 albertel 258: 'bgcolor' => '#FFFFFF',});
1.69 albertel 259: my $end_page =
260: &Apache::loncommon::end_page({'js_ready' => 1,});
1.88 www 261: my $java_not_enabled=&Apache::lonhtmlcommon::java_not_enabled();
1.93 bisitz 262: my %lt = &Apache::lonlocal::texthash(
263: 'seltext' => 'Select substituent...',
264: 'close' => 'Close',
265: 'help' => 'Help',
266: );
1.94 raeburn 267: my $body = "
268: $jsme_js
269: $js".'
1.1 albertel 270: <center>
1.94 raeburn 271: <form action="" id="JMEform">
272: ';
273: if ($usejsme) {
274: $body.= <<"ENDCHEM";
275: <div id="jme">
276: <div id="JMEcredits" style="$creditstyle">
277: <span style="font-size:small; font-family:arial,sans-serif;"><a href="http://peter-ertl.com/jsme/">JSME Molecular Editor</a> courtesy of Peter Ertl (Novartis) and Bruno Bienfait</span></div>
278: </div>
279: ENDCHEM
280: } else {
281: $body.=<<CHEMPAGE;
1.60 albertel 282: <table width="440"><tr>
283: <td></td>
284: <td align="right">
285: <select onchange="javascript:substituent(options[selectedIndex].text)">
1.93 bisitz 286: <option>$lt{'seltext'}</option>
1.60 albertel 287: <option>-C(=O)OH</option>
288: <option>-C(=O)OMe</option>
289: <option>-OC(=O)Me</option>
290: <option>-CMe3</option>
291: <option>-CF3</option>
292: <option>-CCl3</option>
293: <option>-NO2</option>
294: <option>-SO2-NH2</option>
295: <option>-NH-SO2-Me</option>
296: <option>-NMe2</option>
297: <option>-C#N</option>
298: <option>-C#C-Me</option>
299: <option>-C#CH</option>
300: </select>
301: </td></tr>
302: </table>
303: <applet code="JME.class" name="JME" archive="/adm/jme/JME.jar" width="440" height="390" mayscript>
1.88 www 304: $java_not_enabled
1.12 albertel 305: $molecule
1.6 albertel 306: <param name="options" value="$options" />
1.94 raeburn 307: </applet>
308: <br />
1.49 albertel 309: <font face="arial,helvetica,sans-serif" size="-1"><a href="http://www.molinspiration.com/jme/index.html">JME Editor</a> courtesy of Peter Ertl, Novartis</font>
1.94 raeburn 310: CHEMPAGE
311: }
312: $body .= <<CHEMPAGE;
313: <div id="JMEbuttons" style="$buttonstyle">
1.57 albertel 314: $insert_answer
1.93 bisitz 315: <input type="button" value="$lt{'close'}" onclick="javascript:window.close()" />
1.1 albertel 316:
1.93 bisitz 317: <input type="button" value="$lt{'help'}" onclick="javascript:openHelpWindow()" />
1.94 raeburn 318: </div>
319: <div id="JMErefresh" style="$linkstyle">
320: <a href="javascript:location.reload();">Display Molecule Editor</a>
321: </div>
1.1 albertel 322: </form>
323: </center>
324: CHEMPAGE
1.65 albertel 325:
1.69 albertel 326: $body=&Apache::loncommon::js_ready($body);
1.53 albertel 327: my $nothing=&Apache::lonhtmlcommon::javascript_nothing();
1.41 www 328: my $docopen=&Apache::lonhtmlcommon::javascript_docopen();
1.55 albertel 329: my $display=&mt('Draw Molecule');
330: if (defined($shown_text)) { $display=&mt($shown_text); }
1.79 riegler 331: my $iconpath=$Apache::lonnet::perlvar{'lonIconsURL'};
1.94 raeburn 332: my $function =
1.91 raeburn 333: 'LONCAPA_draw_molecule_'.&get_uniq_name();
1.1 albertel 334: my $result=<<CHEMINPUT;
1.69 albertel 335: <script type="text/javascript">
336: function $function() {
337: editor=window.open($nothing,'jmeedit','width=500,height=500,menubar=no,scrollbars=no,resizable=yes');
1.94 raeburn 338: if (editor) {
339: editor.$docopen;
340: editor.document.write('$start_page $body $resizejs $end_page');
341: editor.document.close();
342: editor.focus();
343: }
1.69 albertel 344: }
345: </script>
1.86 raeburn 346: CHEMINPUT
1.94 raeburn 347: my $jscall = "javascript:$function();void(0);";
1.86 raeburn 348: if ($shown_text eq '') {
1.94 raeburn 349: $result .=<<PENCIL;
350: <a href="$jscall"><img class="stift" src="$iconpath/stift.gif" alt="$display" title="$display" /></a>
1.86 raeburn 351: PENCIL
352: } else {
1.94 raeburn 353: $result .= '<input type="button" value="'.&mt($shown_text).'" onclick="$jscall" />';
1.86 raeburn 354: }
1.1 albertel 355: return $result;
356: }
1.56 albertel 357: sub jme_img {
358: my ($jme,$smile,$width,$options)=@_;
359: my $id=&Apache::loncommon::get_cgi_id();
360: my $result='<img alt="'.$smile.'" src="/cgi-bin/convertjme.pl?'.$id.'"';
361: if ($options =~ /border/) { $result.= ' border="1"'; }
362: $result.=' />';
1.78 raeburn 363: &Apache::lonnet::appenv({'cgi.'.$id.'.JME' =>
364: &escape($jme),
365: 'cgi.'.$id.'.PNG' => 1,
366: 'cgi.'.$id.'.WIDTH' => $width});
1.56 albertel 367: return $result;
368: }
369:
1.6 albertel 370: sub start_organicresponse {
1.1 albertel 371: my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
372: my $result;
373: my $partid = $Apache::inputtags::part;
374: my $id = &Apache::response::start_response($parstack,$safeeval);
375: if ($target eq 'meta') {
1.28 albertel 376: $result=&Apache::response::meta_package_write('organicresponse');
1.1 albertel 377: } elsif ($target eq 'web') {
1.55 albertel 378: my $jmeanswer=&Apache::lonxml::get_param('jmeanswer',$parstack,
379: $safeeval);
1.86 raeburn 380: if (&Apache::response::show_answer()) {
381: my $jmeanswer=&Apache::lonxml::get_param('jmeanswer',$parstack,
382: $safeeval);
383: if ($jmeanswer ne '') {
384: my $options=&Apache::lonxml::get_param('options',$parstack,
385: $safeeval);
386: my $width=&Apache::lonxml::get_param('width',$parstack,
387: $safeeval);
388: my (@answers)=&Apache::lonxml::get_param_var('answer',$parstack,
389: $safeeval);
390: $result.=&jme_img($jmeanswer,$answers[0],$width,$options);
391: }
1.1 albertel 392: } else {
1.44 albertel 393: $result.= '<input type="hidden" name="MOLECULE_'.$id.'" value="" />';
1.1 albertel 394: }
1.2 albertel 395: } elsif ($target eq 'edit') {
396: $result .=&Apache::edit::tag_start($target,$token);
1.12 albertel 397: my $options=&Apache::lonxml::get_param('options',$parstack,
398: $safeeval);
399: if ($options !~ /multipart/) { $options.=',multipart'; }
1.83 bisitz 400: $result .='<span class="LC_nobreak">'.
1.7 albertel 401: &Apache::edit::text_arg('Starting Molecule:','molecule',
402: $token,40);
1.2 albertel 403: my $molecule=&Apache::lonxml::get_param('molecule',$parstack,
404: $safeeval);
1.30 www 405: $result .=&separate_jme_window(undef,
1.2 albertel 406: &Apache::edit::html_element_name('molecule'),
1.12 albertel 407: $molecule,$options);
1.83 bisitz 408: $result .='</span><br /><span class="LC_nobreak">';
1.2 albertel 409: $result .=&Apache::edit::text_arg('Correct Answer:','answer',
410: $token,40);
1.85 raeburn 411: $result .='</span><br /><span class="LC_nobreak">';
1.86 raeburn 412: $result .=&Apache::edit::text_arg('JME string of the answer - automatically updated by "Insert Answer" in the JME pop-up (click pencil):',
1.67 albertel 413: 'jmeanswer',$token);
1.2 albertel 414: my $jmeanswer=&Apache::lonxml::get_param('jmeanswer',$parstack,
415: $safeeval);
1.30 www 416: $result .=&separate_jme_window(
1.2 albertel 417: &Apache::edit::html_element_name('answer'),
418: &Apache::edit::html_element_name('jmeanswer'),
1.12 albertel 419: $jmeanswer,$options);
1.83 bisitz 420: $result .='</span><br />';
1.12 albertel 421: $result .=&Apache::edit::checked_arg('Options:','options',
1.29 www 422: [ ['autoez','Auto E,Z stereochemistry'],
1.18 albertel 423: ['multipart','Multipart Structures'],
1.12 albertel 424: ['nostereo','No stereochemistry'],
425: ['reaction','Is a reaction'],
1.18 albertel 426: ['number','Able to number atoms'] ],
1.12 albertel 427: ,$token);
1.44 albertel 428: $result .=&Apache::edit::text_arg('Width of correct answer image:',
429: 'width',$token,10);
1.2 albertel 430: $result .=&Apache::edit::end_row().&Apache::edit::start_spanning_row();
431: } elsif ($target eq 'modified') {
432: my $constructtag=&Apache::edit::get_new_args($token,$parstack,
433: $safeeval,'molecule',
1.6 albertel 434: 'answer','jmeanswer',
1.44 albertel 435: 'options','width');
1.2 albertel 436: if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); }
1.1 albertel 437: }
1.63 albertel 438:
1.1 albertel 439: return $result;
440: }
441:
1.6 albertel 442: sub end_organicresponse {
1.1 albertel 443: my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
444: my $result;
1.64 albertel 445:
446: my $partid = $Apache::inputtags::part;
447: my $id = $Apache::inputtags::response['-1'];
448:
449: if ($target eq 'grade'
450: && &Apache::response::submitted()
451: && $Apache::lonhomework::type eq 'exam') {
452:
453: &Apache::response::scored_response($partid,$id);
454:
455: } elsif ($target eq 'grade'
456: && &Apache::response::submitted()
457: && $Apache::lonhomework::type ne 'exam') {
458:
1.31 albertel 459: &Apache::response::setup_params($$tagstack[-1],$safeeval);
1.1 albertel 460: my $response = &Apache::response::getresponse();
461: if ( $response =~ /[^\s]/) {
1.13 albertel 462: my (@answers)=&Apache::lonxml::get_param_var('answer',$parstack,$safeeval);
1.1 albertel 463: my %previous = &Apache::response::check_for_previous($response,$partid,$id);
464: $Apache::lonhomework::results{"resource.$partid.$id.submission"}=$response;
465: my $ad;
1.13 albertel 466: foreach my $answer (@answers) {
467: &Apache::lonxml::debug("submitted a $response for $answer<br \>\n");
468: if ($response eq $answer) {
469: $ad='EXACT_ANS';
470: last;
471: } else {
472: $ad='INCORRECT';
473: }
1.1 albertel 474: }
1.87 raeburn 475: if ($ad) {
476: if ($Apache::lonhomework::type eq 'survey') {
477: $ad='SUBMITTED';
478: } elsif ($Apache::lonhomework::type eq 'surveycred') {
479: $ad='SUBMITTED_CREDIT';
480: } elsif ($Apache::lonhomework::type eq 'anonsurvey') {
481: $ad='ANONYMOUS';
482: } elsif ($Apache::lonhomework::type eq 'anonsurveycred') {
483: $ad='ANONYMOUS_CREDIT';
484: }
485: }
1.1 albertel 486: &Apache::response::handle_previous(\%previous,$ad);
487: $Apache::lonhomework::results{"resource.$partid.$id.awarddetail"}=$ad;
1.50 albertel 488: $Apache::lonhomework::results{"resource.$partid.$id.molecule"}=$env{"form.MOLECULE_$id"};
1.1 albertel 489: }
1.2 albertel 490: } elsif ($target eq "edit") {
491: $result.= &Apache::edit::tag_end($target,$token,'');
1.15 albertel 492: } elsif ($target eq 'answer') {
493: my (@answers)=&Apache::lonxml::get_param_var('answer',$parstack,
494: $safeeval);
495: $result.=&Apache::response::answer_header('organicresponse');
496: foreach my $answer (@answers) {
497: $result.=&Apache::response::answer_part('organicresponse',$answer);
498: }
499: $result.=&Apache::response::answer_footer('organicresponse');
1.1 albertel 500: }
1.73 albertel 501: if ($target eq 'web') {
502: &Apache::response::setup_prior_tries_hash(\&format_prior_answer_organic,
503: ['molecule'])
504: }
1.63 albertel 505:
506: if ($target eq 'grade' || $target eq 'web' || $target eq 'answer' ||
507: $target eq 'tex' || $target eq 'analyze') {
1.90 raeburn 508: my $repetition = &Apache::response::repetition();
509: &Apache::lonxml::increment_counter($repetition,"$partid.$id"); # part.response
1.74 foxr 510: if ($target eq 'analyze') {
1.76 raeburn 511: $Apache::lonhomework::analyze{"$partid.$id.type"} = 'organicresponse';
1.84 raeburn 512: push (@{ $Apache::lonhomework::analyze{"parts"} },"$partid.$id");
1.74 foxr 513: &Apache::lonhomework::set_bubble_lines();
514: }
1.63 albertel 515: }
1.86 raeburn 516: if ($target eq 'web' ) {
517: my ($showpencil,$shown_text);
518: if ($Apache::inputtags::status['-1'] eq 'CAN_ANSWER') {
519: $showpencil = 1;
520: } elsif (&Apache::response::show_answer()) {
521: my $jmeanswer=&Apache::lonxml::get_param('jmeanswer',$parstack, $safeeval);
522: if ($jmeanswer eq '') {
523: $showpencil = 1;
524: $shown_text="Show Your Last Answer";
525: }
526: }
527: if ($showpencil) {
1.79 riegler 528: my $options=&Apache::lonxml::get_param('options',$parstack,
529: $safeeval);
1.86 raeburn 530:
1.79 riegler 531: my $molecule;
532: if (defined($Apache::lonhomework::history{"resource.$partid.$id.molecule"})) {
533: $molecule=$Apache::lonhomework::history{"resource.$partid.$id.molecule"};
534: } else {
535: $molecule=&Apache::lonxml::get_param('molecule',$parstack,
536: $safeeval);
537: }
1.86 raeburn 538: $result.=&separate_jme_window("HWVAL_$id","MOLECULE_$id",$molecule,
539: $options,$shown_text);
540: }
1.79 riegler 541: }
1.63 albertel 542: &Apache::response::end_response();
1.1 albertel 543: return $result;
544: }
545:
1.73 albertel 546: sub format_prior_answer_organic {
547: my ($mode,$answer,$other_data) = @_;
1.93 bisitz 548: my $result=&mt('Smile representation: [_1]','"<tt>'.$answer.'</tt>"');
1.73 albertel 549: my $jme=$other_data->[0];
550: $result.=&jme_img($jme,$answer,400);
551: return $result;
552: }
553:
1.6 albertel 554: sub start_organicstructure {
1.3 albertel 555: my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
556: my $result;
557: if ($target eq 'web') {
558: my $width=&Apache::lonxml::get_param('width',$parstack,$safeeval);
559: my $molecule=&Apache::lonxml::get_param('molecule',$parstack,$safeeval);
1.12 albertel 560: my $options=&Apache::lonxml::get_param('options',$parstack,$safeeval);
1.23 albertel 561: my $id=&Apache::loncommon::get_cgi_id();
1.19 albertel 562: $result="<img src='/cgi-bin/convertjme.pl?$id'";
563: if ($options =~ /border/) { $result.= ' border="1"'; }
564: $result.=' />';
1.16 albertel 565: &Apache::lonnet::appenv(
1.78 raeburn 566: {'cgi.'.$id.'.JME' => &escape($molecule),
567: 'cgi.'.$id.'.PNG' => 1,
568: 'cgi.'.$id.'.WIDTH' => $width});
1.17 albertel 569: } elsif ($target eq 'tex') {
1.38 albertel 570: my $texwidth=&Apache::lonxml::get_param('texwidth',$parstack,$safeeval,undef,1);
1.58 foxr 571: my $webwidth=&Apache::lonxml::get_param('width', $parstack, $safeeval);
572: my $webheight=&Apache::lonxml::get_param('height', $parstack, $safeeval);
1.62 foxr 573: if (!$webheight) { $webheight = $webwidth; }
1.17 albertel 574: if (!$texwidth) { $texwidth='90'; }
1.58 foxr 575: $result = "%DYNAMICIMAGE:$webwidth:$webheight:$texwidth\n";
1.17 albertel 576: my $molecule=&Apache::lonxml::get_param('molecule',$parstack,$safeeval);
577: my $options=&Apache::lonxml::get_param('options',$parstack,$safeeval);
1.50 albertel 578: my $filename = $env{'user.name'}.'_'.$env{'user.domain'}.
1.17 albertel 579: '_'.time.'_'.$$.int(rand(1000)).'_organicstructure';
580: my $id=$filename;
581: &Apache::lonnet::appenv(
1.78 raeburn 582: {'cgi.'.$id.'.JME' => &escape($molecule),
583: 'cgi.'.$id.'.PS' => 1,
584: 'cgi.'.$id.'.WIDTH' => $texwidth});
1.66 www 585: $id=&escape($id);
1.17 albertel 586: &Apache::lonxml::register_ssi("/cgi-bin/convertjme.pl?$id");
1.20 albertel 587: if ($options =~ /border/) { $result.= '\fbox{'; }
1.89 foxr 588: $result .= '\graphicspath{{'.LONCAPA::tempdir().
589: '}}\includegraphics[width='.$texwidth.' mm]{'.$filename.'.eps}';
1.20 albertel 590: if ($options =~ /border/) { $result.= '} '; }
1.3 albertel 591: } elsif ($target eq 'edit') {
592: $result .=&Apache::edit::tag_start($target,$token);
1.22 albertel 593: $result .=&Apache::edit::text_arg('Width (pixels):','width',$token,5);
594: $result .=&Apache::edit::text_arg('TeXwidth (mm):','texwidth',$token,5);
1.83 bisitz 595: $result .='<span class="LC_nobreak">';
1.3 albertel 596: $result .=&Apache::edit::text_arg('Molecule:','molecule',$token,40);
597: my $molecule=&Apache::lonxml::get_param('molecule',$parstack,
598: $safeeval);
1.12 albertel 599: my $options=&Apache::lonxml::get_param('options',$parstack,
600: $safeeval);
601: if ($options !~ /reaction/) {
602: $options.= ',multipart,number';
603: }
604:
1.30 www 605: $result .=&separate_jme_window(undef,
1.12 albertel 606: &Apache::edit::html_element_name('molecule'),
607: $molecule,$options);
1.83 bisitz 608: $result.="</span><br />";
1.12 albertel 609: $result .=&Apache::edit::checked_arg('Options:','options',
1.18 albertel 610: [ ['reaction','Is a reaction'],
1.12 albertel 611: ['border','Draw a border'] ],
612: $token);
1.24 albertel 613: $result .=&Apache::edit::end_row();
1.3 albertel 614: } elsif ($target eq 'modified') {
615: my $constructtag=&Apache::edit::get_new_args($token,$parstack,
616: $safeeval,'molecule',
1.22 albertel 617: 'width','texwidth',
618: 'options');
1.3 albertel 619: if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); }
620: }
621: return $result;
1.1 albertel 622: }
623:
1.6 albertel 624: sub end_organicstructure {
1.3 albertel 625: my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
626: my $result;
627: if ($target eq "edit") {
628: $result.= &Apache::edit::tag_end($target,$token,'');
629: }
1.4 albertel 630: return $result;
631: }
632:
1.101 ! raeburn 633: sub edit_reaction_button {
! 634: my ($id,$field,$reaction)=@_;
! 635: my $id_es=&escape($id);
! 636: my $field_es=&escape($field);
! 637: my $reaction_es=&escape($reaction);
! 638: my $docopen=&Apache::lonhtmlcommon::javascript_docopen();
! 639: my $iconpath=$Apache::lonnet::perlvar{'lonIconsURL'};
! 640: my $display=&mt('Edit Answer');
! 641: my $start_page =
! 642: &Apache::loncommon::start_page('LON-CAPA Reaction Editor',undef,
! 643: {'frameset' => 1,
! 644: 'js_ready' => 1,
! 645: 'add_entries' => {
! 646: 'rows' => "30%,*",
! 647: 'border' => "0",}},);
! 648: my $end_page =
! 649: &Apache::loncommon::end_page({'frameset' => 1,
! 650: 'js_ready' => 1});
! 651: my $result=<<EDITREACTION;
! 652: <script type="text/javascript">
! 653: // <!--
! 654: function create_reaction_window_${id}_${field} () {
! 655: editor=window.open('','','width=500,height=270,scrollbars=no,resizable=yes');
! 656: editor.$docopen;
! 657: editor.document.writeln('$start_page <frame src="/adm/reactionresponse/reaction_viewer.html?inhibitmenu=yes" name="viewer" scrolling="no" /> <frame src="/adm/reactionresponse/reaction_editor.html?inhibitmenu=yes&reaction=$reaction_es&id=$id_es&field=$field_es" name="editor" scrolling="no" /> $end_page');
! 658: editor.document.close();
! 659: }
! 660: // -->
! 661: </script>
! 662: <a href="javascript:create_reaction_window_${id}_${field}();void(0);"><img class="stift" src='$iconpath/stift.gif' alt='$display' title='$display' /></a>
! 663: EDITREACTION
! 664: return $result;
! 665: }
! 666:
1.99 damieng 667: sub reaction_preview {
668: my ($field, $reaction) = @_;
669:
670: # NOTE: $reaction should be encoded if the document was sent as XHTML
671: $reaction =~ s/"//g;
672: my $result=<<JS_PREVIEW;
673: <input type="button" value="Help" onclick = "window.open('/adm/reactionresponse/reaction_help.html','','scrollbars=yes,resizable=yes,width=550,height=600')" />
1.10 albertel 674: <script type="text/javascript">
1.99 damieng 675: if (typeof reaction_preview_started === 'undefined') {
676: var script = document.createElement('script');
677: script.type = 'text/javascript';
678: script.src = '/adm/reactionresponse/reaction_preview.js';
679: document.body.appendChild(script);
680: reaction_preview_started = true;
681: }
682: window.addEventListener('load', function(e) {
683: var input = document.forms.lonhomework.$field;
684: input.readonly = '';
685: input.value = "$reaction";
686: if (!input.id)
687: input.id = "$field";
688: var preview = new LC.HW.ReactionPreview(input.id);
689: preview.start_preview();
690: }, false);
1.10 albertel 691: </script>
1.99 damieng 692: JS_PREVIEW
1.9 albertel 693: return $result;
694: }
695:
1.4 albertel 696: sub start_reactionresponse {
697: my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
698: my $result;
699: my $id = &Apache::response::start_response($parstack,$safeeval);
1.10 albertel 700: if ($target eq 'meta') {
1.28 albertel 701: $result=&Apache::response::meta_package_write('reactionresponse');
1.10 albertel 702: } elsif ($target eq 'web') {
1.11 albertel 703: my $partid = $Apache::inputtags::part;
704: my $id = $Apache::inputtags::response['-1'];
1.33 albertel 705: if ( &Apache::response::show_answer() ) {
706: my $ans=&Apache::lonxml::get_param('answer',$parstack,$safeeval);
1.51 albertel 707: if (!$Apache::lonxml::default_homework_loaded) {
708: &Apache::lonxml::default_homework_load($safeeval);
709: }
710: @Apache::scripttag::parser_env = @_;
1.71 albertel 711: $Apache::inputtags::answertxt{$id}=[&Apache::run::run("return &chemparse(q\0$ans\0);",$safeeval)];
1.33 albertel 712: }
1.4 albertel 713: } elsif ($target eq "edit") {
1.9 albertel 714: $result .=&Apache::edit::tag_start($target,$token);
715: my $answer=&Apache::lonxml::get_param('answer',$parstack,
716: $safeeval);
1.82 raeburn 717: $result .='<span class="LC_nobreak">'.
1.10 albertel 718: &Apache::edit::text_arg('Answer:','answer',$token,40);
1.101 ! raeburn 719: my $inline_chem = &use_inline_chem();
! 720: if ($inline_chem) {
! 721: $result .= &reaction_preview(&Apache::edit::html_element_name('answer'), $answer).'</span>';
! 722: } else {
! 723: $result .=&edit_reaction_button($id,&Apache::edit::html_element_name('answer'),$answer).'</span>';
! 724: }
1.35 albertel 725: my $initial=&Apache::lonxml::get_param('initial',$parstack,$safeeval);
1.82 raeburn 726: $result.='<span class="LC_nobreak">'.
1.43 albertel 727: &Apache::edit::text_arg('Initial Reaction:','initial',$token,40);
1.101 ! raeburn 728: if ($inline_chem) {
! 729: $result .= &reaction_preview(&Apache::edit::html_element_name('initial'), $initial).'</span>';
! 730: } else {
! 731: $result .=&edit_reaction_button($id,&Apache::edit::html_element_name('initial'),$initial).'</span>';
! 732: }
1.9 albertel 733: $result .=&Apache::edit::end_row().&Apache::edit::start_spanning_row();
1.10 albertel 734: } elsif ($target eq 'modified') {
735: my $constructtag=&Apache::edit::get_new_args($token,$parstack,
1.35 albertel 736: $safeeval,'answer',
737: 'initial');
1.10 albertel 738: if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); }
1.4 albertel 739: }
740: return $result;
741: }
742:
743: sub end_reactionresponse {
744: my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
745: my $result;
1.64 albertel 746:
747: my $partid = $Apache::inputtags::part;
748: my $id = $Apache::inputtags::response['-1'];
749:
750: if ($target eq 'grade'
751: && &Apache::response::submitted()
752: && $Apache::lonhomework::type eq 'exam') {
753:
754: &Apache::response::scored_response($partid,$id);
755:
756: } elsif ($target eq 'grade'
757: && &Apache::response::submitted()
758: && $Apache::lonhomework::type ne 'exam') {
759:
1.31 albertel 760: &Apache::response::setup_params($$tagstack[-1],$safeeval);
1.10 albertel 761: my $response = &Apache::response::getresponse();
762: if ( $response =~ /[^\s]/) {
1.15 albertel 763: my (@answers)=&Apache::lonxml::get_param_var('answer',$parstack,$safeeval);
1.10 albertel 764: my %previous = &Apache::response::check_for_previous($response,$partid,$id);
765: $Apache::lonhomework::results{"resource.$partid.$id.submission"}=$response;
766: my $ad;
1.13 albertel 767: foreach my $answer (@answers) {
768: &Apache::lonxml::debug("submitted a $response for $answer<br \>\n");
1.34 albertel 769: if (&chem_standard_order($response) eq
770: &chem_standard_order($answer)) {
1.13 albertel 771: $ad='EXACT_ANS';
772: } else {
773: $ad='INCORRECT';
774: }
1.10 albertel 775: }
1.87 raeburn 776: if ($ad) {
777: if ($Apache::lonhomework::type eq 'survey') {
778: $ad='SUBMITTED';
779: } elsif ($ad && $Apache::lonhomework::type eq 'surveycred') {
780: $ad='SUBMITTED_CREDIT';
781: } elsif ($ad && $Apache::lonhomework::type eq 'anonsurvey') {
782: $ad='ANONYMOUS';
783: } elsif ($ad && $Apache::lonhomework::type eq 'anonsurveycred') {
784: $ad='ANONYMOUS_CREDIT';
785: }
786: }
1.10 albertel 787: &Apache::response::handle_previous(\%previous,$ad);
788: $Apache::lonhomework::results{"resource.$partid.$id.awarddetail"}=$ad;
789: }
790: } elsif ($target eq "edit") {
1.4 albertel 791: $result.= &Apache::edit::tag_end($target,$token,'');
1.15 albertel 792: } elsif ($target eq 'answer') {
793: my (@answers)=&Apache::lonxml::get_param_var('answer',$parstack,
794: $safeeval);
795: $result.=&Apache::response::answer_header('reactionresponse');
796: foreach my $answer (@answers) {
797: $result.=&Apache::response::answer_part('reactionresponse',
798: $answer);
799: }
800: $result.=&Apache::response::answer_footer('reactionresponse');
1.4 albertel 801: }
1.72 albertel 802: if ($target eq 'web') {
803: &Apache::response::setup_prior_tries_hash(\&format_prior_response_reaction);
804: }
1.63 albertel 805:
806: if ($target eq 'grade' || $target eq 'web' || $target eq 'answer' ||
807: $target eq 'tex' || $target eq 'analyze') {
1.90 raeburn 808: my $repetition = &Apache::response::repetition();
809: &Apache::lonxml::increment_counter($repetition,"$partid.$id");
1.77 raeburn 810: if ($target eq 'analyze') {
811: $Apache::lonhomework::analyze{"$partid.$id.type"} = 'reactionresponse';
1.84 raeburn 812: push (@{ $Apache::lonhomework::analyze{"parts"} },"$partid.$id");
1.77 raeburn 813: &Apache::lonhomework::set_bubble_lines();
814: }
1.63 albertel 815: }
1.81 raeburn 816: my $status=$Apache::inputtags::status['-1'];
817: if (($target eq 'web') && ($Apache::lonhomework::type ne 'exam') && ($status eq 'CAN_ANSWER')) {
818: my $reaction=$Apache::lonhomework::history{"resource.$partid.$id.submission"};
819: if ($reaction eq '') { $reaction=&Apache::lonxml::get_param('initial',$parstack,$safeeval); }
1.101 ! raeburn 820: if (&use_inline_chem()) {
! 821: $result .= &reaction_preview("HWVAL_$id", $reaction);
! 822: } else {
! 823: $result.=&edit_reaction_button($id,"HWVAL_$id",$reaction);
! 824: }
1.81 raeburn 825: }
1.63 albertel 826: &Apache::response::end_response();
1.3 albertel 827: return $result;
1.1 albertel 828: }
829:
1.101 ! raeburn 830: sub use_inline_chem {
! 831: my $inline_chem = 1;
! 832: if (($env{'request.course.id'}) && ($env{'request.state'} ne 'construct')) {
! 833: if (exists($env{'course.'.$env{'request.course.id'}.'.inline_chem'})) {
! 834: if ($env{'course.'.$env{'request.course.id'}.'.inline_chem'} eq '0') {
! 835: $inline_chem = 0;
! 836: }
! 837: } else {
! 838: my %domdefs = &Apache::lonnet::get_domain_defaults($env{'course.'.$env{'request.course.id'}.'.domain'});
! 839: if ($domdefs{'inline_chem'} eq '0') {
! 840: $inline_chem = 0;
! 841: }
! 842: }
! 843: } else {
! 844: my %domdefs = &Apache::lonnet::get_domain_defaults($env{'course.'.$env{'request.course.id'}.'.domain'});
! 845: if ($domdefs{'inline_chem'} eq '0') {
! 846: $inline_chem = 0;
! 847: }
! 848: }
! 849: return $inline_chem;
! 850: }
! 851:
1.72 albertel 852: sub format_prior_response_reaction {
853: my ($mode,$answer) =@_;
854: return '<span class="LC_prior_reaction">'.
855: &HTML::Entities::encode($answer,'"<>&').'</span>';
856: }
857:
1.46 albertel 858: sub start_chem {
859: my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style) = @_;
860: my $result = '';
1.48 albertel 861: my $inside = &Apache::lonxml::get_all_text_unbalanced("/chem",$parser);
1.46 albertel 862: if ($target eq 'tex' || $target eq 'web') {
1.48 albertel 863: $inside=&Apache::run::evaluate($inside,$safeeval,$$parstack[-1]);
864: if (!$Apache::lonxml::default_homework_loaded) {
865: &Apache::lonxml::default_homework_load($safeeval);
866: }
867: @Apache::scripttag::parser_env = @_;
868: $result=&Apache::run::run("return &chemparse(q\0$inside\0);",$safeeval);
1.46 albertel 869: }
870: return $result;
871: }
872:
873: sub end_chem {
874: my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style) = @_;
875: my $result = '';
876: return $result;
877: }
878:
1.91 raeburn 879: my $uniq=0;
880: sub get_uniq_name {
881: $uniq++;
882: return 'uniquename'.$uniq;
883: }
884:
1.1 albertel 885: 1;
886: __END__
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>