--- loncom/homework/chemresponse.pm	2015/09/21 14:24:54	1.98
+++ loncom/homework/chemresponse.pm	2025/01/27 18:43:23	1.103
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # chemical equation style response
 #
-# $Id: chemresponse.pm,v 1.98 2015/09/21 14:24:54 raeburn Exp $
+# $Id: chemresponse.pm,v 1.103 2025/01/27 18:43:23 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -199,7 +199,7 @@ RESIZEJS
 function jsmeOnLoad() {
     document.getElementById('JMErefresh').style.display="none";
     document.getElementById('JMEcredits').style.display="inline";
-    jsmeApplet = new JSApplet.JSME("jme", "420px", "330px");
+    jsmeApplet = new JSApplet.JSME("jme", "420px", "330px", {"options" : "$options"});
     document.JME = jsmeApplet;
     $molecule;
     document.getElementById('JMEbuttons').style.display="block";
@@ -217,7 +217,7 @@ function submitSmiles() {
     }
 }
 function openHelpWindow() {
-    window.open("http://peter-ertl.com/jsme/2013_03/help.html","","scrollbars=yes,resizable=yes,width=500,height=600");
+    window.open("https://jsme-editor.github.io/help.html","","scrollbars=yes,resizable=yes,width=500,height=600");
 }
 
 </script>
@@ -558,10 +558,15 @@ sub start_organicstructure {
 	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 $alttext=&Apache::lonxml::get_param('alt',$parstack,$safeeval);
+        if ($alttext eq '') {
+            $alttext = &mt('Organic structure');
+        }
+        $alttext = &HTML::Entities::encode($alttext,'<>&"');
 	my $id=&Apache::loncommon::get_cgi_id();
 	$result="<img src='/cgi-bin/convertjme.pl?$id'";
 	if ($options =~ /border/) { $result.= ' border="1"'; }
-	$result.=' />';
+	$result.=' alt="'.$alttext.'" />';
 	&Apache::lonnet::appenv(
             {'cgi.'.$id.'.JME'   => &escape($molecule),
 	     'cgi.'.$id.'.PNG' => 1,
@@ -610,12 +615,14 @@ sub start_organicstructure {
 					     [ ['reaction','Is a reaction'],
 					       ['border','Draw a border'] ],
 					     $token);
+        $result .= '<br />'.&Apache::edit::text_arg('Alt text in JME img tag:','alt',$token,30).
+                   ' ('.&mt('student-viewable in HTML source').')';
 	$result .=&Apache::edit::end_row();
     } elsif ($target eq 'modified') {
 	my $constructtag=&Apache::edit::get_new_args($token,$parstack,
 						     $safeeval,'molecule',
 						     'width','texwidth',
-						     'options');
+						     'options','alt');
 	if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); }
     }
     return $result;
@@ -638,24 +645,24 @@ sub edit_reaction_button {
     my $docopen=&Apache::lonhtmlcommon::javascript_docopen();
     my $iconpath=$Apache::lonnet::perlvar{'lonIconsURL'};
     my $display=&mt('Edit Answer');
-    my $start_page = 
-	&Apache::loncommon::start_page('LON-CAPA Reaction Editor',undef,
-				       {'frameset'    => 1,
-					'js_ready'    => 1,
-					'add_entries' => {
-					    'rows'   => "30%,*",
-					    'border' => "0",}},);
-    my $end_page = 
-	&Apache::loncommon::end_page({'frameset' => 1,
-				      'js_ready' => 1});
+    my $start_page =
+        &Apache::loncommon::start_page('LON-CAPA Reaction Editor',undef,
+                                       {'frameset'    => 1,
+                                        'js_ready'    => 1,
+                                        'add_entries' => {
+                                            'rows'   => "30%,*",
+                                            'border' => "0",}},);
+    my $end_page =
+        &Apache::loncommon::end_page({'frameset' => 1,
+                                      'js_ready' => 1});
     my $result=<<EDITREACTION;
 <script type="text/javascript">
 // <!--
     function create_reaction_window_${id}_${field} () {
-	editor=window.open('','','width=500,height=270,scrollbars=no,resizable=yes');
-	editor.$docopen;
-	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');
-	editor.document.close();
+        editor=window.open('','','width=500,height=270,scrollbars=no,resizable=yes');
+        editor.$docopen;
+        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');
+        editor.document.close();
     }
 // -->
 </script>
@@ -664,6 +671,35 @@ EDITREACTION
     return $result;
 }
 
+sub reaction_preview {
+    my ($field, $reaction) = @_;
+    
+    # NOTE: $reaction should be encoded if the document was sent as XHTML
+    $reaction =~ s/"//g;
+    my $result=<<JS_PREVIEW;
+<input type="button" value="Help" onclick = "window.open('/adm/reactionresponse/reaction_help.html','','scrollbars=yes,resizable=yes,width=550,height=600')" />
+<script type="text/javascript">
+    if (typeof reaction_preview_started === 'undefined') {
+        var script = document.createElement('script');
+        script.type = 'text/javascript';
+        script.src = '/adm/reactionresponse/reaction_preview.js';
+        document.body.appendChild(script);
+        reaction_preview_started = true;
+    }
+    window.addEventListener('load', function(e) {
+        var input = document.forms.lonhomework.$field;
+        input.readonly = '';
+        input.value = "$reaction";
+        if (!input.id)
+            input.id = "$field";
+        var preview = new LC.HW.ReactionPreview(input.id);
+        preview.start_preview();
+    }, false);
+</script>
+JS_PREVIEW
+    return $result;
+}
+
 sub start_reactionresponse {
     my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
     my $result;
@@ -687,11 +723,20 @@ sub start_reactionresponse {
 						$safeeval);
 	$result .='<span class="LC_nobreak">'.
 	    &Apache::edit::text_arg('Answer:','answer',$token,40);
-	$result .=&edit_reaction_button($id,&Apache::edit::html_element_name('answer'),$answer).'</span>';
+        my $inline_chem = &use_inline_chem();
+        if ($inline_chem) {
+	    $result .= &reaction_preview(&Apache::edit::html_element_name('answer'), $answer).'</span>';
+        } else {
+            $result .=&edit_reaction_button($id,&Apache::edit::html_element_name('answer'),$answer).'</span>';
+        }
 	my $initial=&Apache::lonxml::get_param('initial',$parstack,$safeeval);
 	$result.='<span class="LC_nobreak">'.
 	    &Apache::edit::text_arg('Initial Reaction:','initial',$token,40);
-	$result .=&edit_reaction_button($id,&Apache::edit::html_element_name('initial'),$initial).'</span>';
+        if ($inline_chem) { 
+            $result .= &reaction_preview(&Apache::edit::html_element_name('initial'), $initial).'</span>';
+        } else {
+            $result .=&edit_reaction_button($id,&Apache::edit::html_element_name('initial'),$initial).'</span>';
+        }
 	$result .=&Apache::edit::end_row().&Apache::edit::start_spanning_row();
     }  elsif ($target eq 'modified') {
 	my $constructtag=&Apache::edit::get_new_args($token,$parstack,
@@ -779,12 +824,38 @@ sub end_reactionresponse {
     if  (($target eq 'web') && ($Apache::lonhomework::type ne 'exam') && ($status eq 'CAN_ANSWER')) {
         my $reaction=$Apache::lonhomework::history{"resource.$partid.$id.submission"};
         if ($reaction eq '') {  $reaction=&Apache::lonxml::get_param('initial',$parstack,$safeeval); }
-        $result.=&edit_reaction_button($id,"HWVAL_$id",$reaction);
+        if (&use_inline_chem()) {
+            $result .= &reaction_preview("HWVAL_$id", $reaction);
+        } else {
+            $result.=&edit_reaction_button($id,"HWVAL_$id",$reaction);
+        }
     }
     &Apache::response::end_response();
     return $result;
 }
 
+sub use_inline_chem {
+    my $inline_chem = 1;
+    if (($env{'request.course.id'}) && ($env{'request.state'} ne 'construct')) {
+        if (exists($env{'course.'.$env{'request.course.id'}.'.inline_chem'})) {
+            if ($env{'course.'.$env{'request.course.id'}.'.inline_chem'} eq '0') {
+                $inline_chem = 0;
+            }
+        } else {
+            my %domdefs = &Apache::lonnet::get_domain_defaults($env{'course.'.$env{'request.course.id'}.'.domain'});
+            if ($domdefs{'inline_chem'} eq '0') {
+                $inline_chem = 0;
+            }
+        }
+    } else {
+        my %domdefs = &Apache::lonnet::get_domain_defaults($env{'course.'.$env{'request.course.id'}.'.domain'});
+        if ($domdefs{'inline_chem'} eq '0') {
+            $inline_chem = 0;
+        }
+    }
+    return $inline_chem;
+}
+
 sub format_prior_response_reaction {
     my ($mode,$answer) =@_;
     return '<span class="LC_prior_reaction">'.