# The LearningOnline Network with CAPA # chemical equation style response # # $Id: chemresponse.pm,v 1.48 2005/02/18 23:12:29 albertel 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/ # # package Apache::chemresponse; use strict; use Apache::lonxml; use Apache::lonnet; BEGIN { &Apache::lonxml::register('Apache::chemresponse',('organicresponse','organicstructure','reactionresponse','chem')); } sub chem_standard_order { my ($reaction) = @_; my ($re,$pr) = split(/->|<=>/,$reaction); my @reactants = split(/\s\+/,$re); my @products = split(/\s\+/,$pr); foreach my $substance (@reactants,@products) { $substance =~ s/(\^\d*)\s+/$1_/g; # protect superscript space $substance =~ s/\s*//g; # strip whitespace $substance =~ s/_/ /g; # restore superscript space } @reactants = sort @reactants; @products = sort @products; my $standard = ''; foreach my $substance (@reactants) { $standard .= $substance; $standard .= ' + '; } $standard =~ s/ \+ $//; # get rid of trailing plus sign $standard .= ' -> '; foreach my $substance (@products) { $standard .= $substance; $standard .= ' + '; } $standard =~ s/ \+ $//; # get rid of trailing plus sign return $standard; } sub separate_jme_window { my ($smile_input,$jme_input,$molecule,$options)=@_; my $smilesection; if (defined($smile_input)) { $smilesection=<'; } my $body=< Molecule Editor
You have to enable Java and JavaScript on your machine. $molecule
JME Editor courtesy of Peter Ertl, Novartis

  
CHEMPAGE $body=&HTML::Entities::encode($body,'<>&"'); $body=~s/\n/ /g; my $docopen=&Apache::lonhtmlcommon::javascript_docopen(); my $result=< CHEMINPUT return $result; } sub start_organicresponse { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result; my $partid = $Apache::inputtags::part; my $id = &Apache::response::start_response($parstack,$safeeval); if ($target eq 'meta') { $result=&Apache::response::meta_package_write('organicresponse'); } elsif ($target eq 'web') { if ( &Apache::response::show_answer() ) { my $jmeanswer=&Apache::lonxml::get_param('jmeanswer',$parstack, $safeeval); my $options=&Apache::lonxml::get_param('options',$parstack, $safeeval); my $width=&Apache::lonxml::get_param('width',$parstack, $safeeval); my $id=&Apache::loncommon::get_cgi_id(); $result=" &Apache::lonnet::escape($jmeanswer), 'cgi.'.$id.'.PNG' => 1, 'cgi.'.$id.'.WIDTH' => $width); } else { my $molecule; if (defined($Apache::lonhomework::history{"resource.$partid.$id.molecule"})) { $molecule=$Apache::lonhomework::history{"resource.$partid.$id.molecule"}; } else { $molecule=&Apache::lonxml::get_param('molecule',$parstack, $safeeval); } my $options=&Apache::lonxml::get_param('options',$parstack, $safeeval); $result=&separate_jme_window("HWVAL_$id","MOLECULE_$id",$molecule,$options); $result.= ''; } } elsif ($target eq 'edit') { $result .=&Apache::edit::tag_start($target,$token); my $options=&Apache::lonxml::get_param('options',$parstack, $safeeval); if ($options !~ /multipart/) { $options.=',multipart'; } $result .=''. &Apache::edit::text_arg('Starting Molecule:','molecule', $token,40); my $molecule=&Apache::lonxml::get_param('molecule',$parstack, $safeeval); $result .=&separate_jme_window(undef, &Apache::edit::html_element_name('molecule'), $molecule,$options); $result .='
'; $result .=&Apache::edit::text_arg('Correct Answer:','answer', $token,40); $result .=&Apache::edit::hidden_arg('jmeanswer',$token); my $jmeanswer=&Apache::lonxml::get_param('jmeanswer',$parstack, $safeeval); $result .=&separate_jme_window( &Apache::edit::html_element_name('answer'), &Apache::edit::html_element_name('jmeanswer'), $jmeanswer,$options); $result .='
'; $result .=&Apache::edit::checked_arg('Options:','options', [ ['autoez','Auto E,Z stereochemistry'], ['multipart','Multipart Structures'], ['nostereo','No stereochemistry'], ['reaction','Is a reaction'], ['number','Able to number atoms'] ], ,$token); $result .=&Apache::edit::text_arg('Width of correct answer image:', 'width',$token,10); $result .=&Apache::edit::end_row().&Apache::edit::start_spanning_row(); } elsif ($target eq 'modified') { my $constructtag=&Apache::edit::get_new_args($token,$parstack, $safeeval,'molecule', 'answer','jmeanswer', 'options','width'); if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); } } return $result; } sub end_organicresponse { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result; if ($target eq 'grade' && &Apache::response::submitted()) { &Apache::response::setup_params($$tagstack[-1],$safeeval); my $response = &Apache::response::getresponse(); if ( $response =~ /[^\s]/) { my $partid = $Apache::inputtags::part; my $id = $Apache::inputtags::response['-1']; my (@answers)=&Apache::lonxml::get_param_var('answer',$parstack,$safeeval); my %previous = &Apache::response::check_for_previous($response,$partid,$id); $Apache::lonhomework::results{"resource.$partid.$id.submission"}=$response; my $ad; foreach my $answer (@answers) { &Apache::lonxml::debug("submitted a $response for $answer
\n"); if ($response eq $answer) { $ad='EXACT_ANS'; last; } else { $ad='INCORRECT'; } } if ($ad && $Apache::lonhomework::type eq 'survey') { $ad='SUBMITTED'; } &Apache::response::handle_previous(\%previous,$ad); $Apache::lonhomework::results{"resource.$partid.$id.awarddetail"}=$ad; $Apache::lonhomework::results{"resource.$partid.$id.molecule"}=$ENV{"form.MOLECULE_$id"}; } } elsif ($target eq "edit") { $result.= &Apache::edit::tag_end($target,$token,''); } elsif ($target eq 'answer') { my (@answers)=&Apache::lonxml::get_param_var('answer',$parstack, $safeeval); $result.=&Apache::response::answer_header('organicresponse'); foreach my $answer (@answers) { $result.=&Apache::response::answer_part('organicresponse',$answer); } $result.=&Apache::response::answer_footer('organicresponse'); } &Apache::response::end_response; return $result; } sub start_organicstructure { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result; if ($target eq 'web') { my $width=&Apache::lonxml::get_param('width',$parstack,$safeeval); my $molecule=&Apache::lonxml::get_param('molecule',$parstack,$safeeval); my $options=&Apache::lonxml::get_param('options',$parstack,$safeeval); my $id=&Apache::loncommon::get_cgi_id(); $result=" &Apache::lonnet::escape($molecule), 'cgi.'.$id.'.PNG' => 1, 'cgi.'.$id.'.WIDTH' => $width ); } elsif ($target eq 'tex') { my $texwidth=&Apache::lonxml::get_param('texwidth',$parstack,$safeeval,undef,1); if (!$texwidth) { $texwidth='90'; } my $molecule=&Apache::lonxml::get_param('molecule',$parstack,$safeeval); my $options=&Apache::lonxml::get_param('options',$parstack,$safeeval); my $filename = $ENV{'user.name'}.'_'.$ENV{'user.domain'}. '_'.time.'_'.$$.int(rand(1000)).'_organicstructure'; my $id=$filename; &Apache::lonnet::appenv( 'cgi.'.$id.'.JME' => &Apache::lonnet::escape($molecule), 'cgi.'.$id.'.PS' => 1, 'cgi.'.$id.'.WIDTH' => $texwidth ); $id=&Apache::lonnet::escape($id); &Apache::lonxml::register_ssi("/cgi-bin/convertjme.pl?$id"); if ($options =~ /border/) { $result.= '\fbox{'; } $result .= '\graphicspath{{/home/httpd/perl/tmp/}}\includegraphics[width='.$texwidth.' mm]{'.$filename.'.eps}'; if ($options =~ /border/) { $result.= '} '; } } elsif ($target eq 'edit') { $result .=&Apache::edit::tag_start($target,$token); $result .=&Apache::edit::text_arg('Width (pixels):','width',$token,5); $result .=&Apache::edit::text_arg('TeXwidth (mm):','texwidth',$token,5); $result .=''; $result .=&Apache::edit::text_arg('Molecule:','molecule',$token,40); my $molecule=&Apache::lonxml::get_param('molecule',$parstack, $safeeval); my $options=&Apache::lonxml::get_param('options',$parstack, $safeeval); if ($options !~ /reaction/) { $options.= ',multipart,number'; } $result .=&separate_jme_window(undef, &Apache::edit::html_element_name('molecule'), $molecule,$options); $result.="
"; $result .=&Apache::edit::checked_arg('Options:','options', [ ['reaction','Is a reaction'], ['border','Draw a border'] ], $token); $result .=&Apache::edit::end_row(); } elsif ($target eq 'modified') { my $constructtag=&Apache::edit::get_new_args($token,$parstack, $safeeval,'molecule', 'width','texwidth', 'options'); if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); } } return $result; } sub end_organicstructure { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result; if ($target eq "edit") { $result.= &Apache::edit::tag_end($target,$token,''); } return $result; } sub edit_reaction_button { my ($id,$field,$reaction)=@_; my $id_es=&Apache::lonnet::escape($id); my $field_es=&Apache::lonnet::escape($field); my $reaction_es=&Apache::lonnet::escape($reaction); my $docopen=&Apache::lonhtmlcommon::javascript_docopen(); my $result=< // EDITREACTION return $result; } sub start_reactionresponse { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result; my $id = &Apache::response::start_response($parstack,$safeeval); if ($target eq 'meta') { $result=&Apache::response::meta_package_write('reactionresponse'); } elsif ($target eq 'web') { my $partid = $Apache::inputtags::part; my $id = $Apache::inputtags::response['-1']; my $reaction=$Apache::lonhomework::history{"resource.$partid.$id.submission"}; if ($reaction eq '') { $reaction=&Apache::lonxml::get_param('initial',$parstack,$safeeval); } my $status=$Apache::inputtags::status['-1']; if ($status eq 'CAN_ANSWER') { $result.=&edit_reaction_button($id,"HWVAL_$id",$reaction); } if ( &Apache::response::show_answer() ) { my $ans=&Apache::lonxml::get_param('answer',$parstack,$safeeval); $ans=~s/(\\|\')/\\$1/g; $Apache::inputtags::answertxt{$id}=&Apache::run::run("return &chemparse('$ans');",$safeeval); } } elsif ($target eq "edit") { $result .=&Apache::edit::tag_start($target,$token); my $answer=&Apache::lonxml::get_param('answer',$parstack, $safeeval); $result .=''. &Apache::edit::text_arg('Answer:','answer',$token,40); $result .=&edit_reaction_button($id,&Apache::edit::html_element_name('answer'),$answer).''; my $initial=&Apache::lonxml::get_param('initial',$parstack,$safeeval); $result.=''. &Apache::edit::text_arg('Initial Reaction:','initial',$token,40); $result .=&edit_reaction_button($id,&Apache::edit::html_element_name('initial'),$initial).''; $result .=&Apache::edit::end_row().&Apache::edit::start_spanning_row(); } elsif ($target eq 'modified') { my $constructtag=&Apache::edit::get_new_args($token,$parstack, $safeeval,'answer', 'initial'); if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); } } return $result; } sub end_reactionresponse { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result; if ($target eq 'grade' && &Apache::response::submitted()) { &Apache::response::setup_params($$tagstack[-1],$safeeval); my $response = &Apache::response::getresponse(); if ( $response =~ /[^\s]/) { my $partid = $Apache::inputtags::part; my $id = $Apache::inputtags::response['-1']; my (@answers)=&Apache::lonxml::get_param_var('answer',$parstack,$safeeval); my %previous = &Apache::response::check_for_previous($response,$partid,$id); $Apache::lonhomework::results{"resource.$partid.$id.submission"}=$response; my $ad; foreach my $answer (@answers) { &Apache::lonxml::debug("submitted a $response for $answer
\n"); if (&chem_standard_order($response) eq &chem_standard_order($answer)) { $ad='EXACT_ANS'; } else { $ad='INCORRECT'; } } if ($ad && $Apache::lonhomework::type eq 'survey') { $ad='SUBMITTED'; } &Apache::response::handle_previous(\%previous,$ad); $Apache::lonhomework::results{"resource.$partid.$id.awarddetail"}=$ad; } } elsif ($target eq "edit") { $result.= &Apache::edit::tag_end($target,$token,''); } elsif ($target eq 'answer') { my (@answers)=&Apache::lonxml::get_param_var('answer',$parstack, $safeeval); $result.=&Apache::response::answer_header('reactionresponse'); foreach my $answer (@answers) { $result.=&Apache::response::answer_part('reactionresponse', $answer); } $result.=&Apache::response::answer_footer('reactionresponse'); } &Apache::response::end_response; return $result; } sub start_chem { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style) = @_; my $result = ''; my $inside = &Apache::lonxml::get_all_text_unbalanced("/chem",$parser); if ($target eq 'tex' || $target eq 'web') { $inside=&Apache::run::evaluate($inside,$safeeval,$$parstack[-1]); if (!$Apache::lonxml::default_homework_loaded) { &Apache::lonxml::default_homework_load($safeeval); } @Apache::scripttag::parser_env = @_; $result=&Apache::run::run("return &chemparse(q\0$inside\0);",$safeeval); } return $result; } sub end_chem { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style) = @_; my $result = ''; return $result; } 1; __END__