aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Michel Vedrine <vedrine@vedrine.org>2018-02-02 16:53:59 +0100
committerJean-Michel Vedrine <vedrine@vedrine.org>2018-02-02 16:53:59 +0100
commit8ad4a477c15f928323da24aff4188bd7f0dca1d9 (patch)
tree0f0e488eaacefc304154d6e68e1e2a41cb148cb5
parentec3cabf60551be0c589b11fa5db8de302645988e (diff)
Ajax dynamic formula display
-rw-r--r--ajax.php55
-rw-r--r--amd/build/display.min.js1
-rw-r--r--amd/src/display.js28
-rw-r--r--lang/en/qtype_algebra.php5
-rw-r--r--renderer.php97
-rw-r--r--settings.php7
-rw-r--r--styles.css10
-rw-r--r--version.php2
8 files changed, 176 insertions, 29 deletions
diff --git a/ajax.php b/ajax.php
new file mode 100644
index 0000000..156db22
--- /dev/null
+++ b/ajax.php
@@ -0,0 +1,55 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle 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 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle 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 Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * @package qtype_algebra
+ * @copyright 2018 Jean-Michel Vedrine
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+define('AJAX_SCRIPT', true);
+
+require_once(__DIR__ . '/../../../config.php');
+require_once(__DIR__ . '/parser.php');
+
+$p = new qtype_algebra_parser;
+
+$vars = required_param('vars', PARAM_RAW);
+$expr = required_param('expr', PARAM_RAW);
+/*
+if (!confirm_sesskey()) {
+ header('HTTP/1.1 403 Forbidden');
+ die();
+}
+*/
+try {
+ $vars = explode(',', $vars);
+ if (empty($expr)) {
+ $texexp = '';
+ } else {
+ $exp = $p->parse($expr, $vars);
+ $texexp = $exp->tex();
+ }
+} catch (Exception $e) {
+ $texexp = '';
+}
+if ($CFG->qtype_algebra_texdelimiters == 'old') {
+ $texexp = '$$' . $texexp . '$$';
+} else {
+ $texexp = '\\[' . $texexp . '\\]';
+}
+header('Content-Type: application/json; charset: utf-8');
+echo json_encode($texexp);
diff --git a/amd/build/display.min.js b/amd/build/display.min.js
new file mode 100644
index 0000000..cd5da13
--- /dev/null
+++ b/amd/build/display.min.js
@@ -0,0 +1 @@
+define(["jquery","core/config","core/notification"],function(a,b,c){return{init:function(){a(".algebra_answer").on("input paste keyup",null,null,function(){var d=a(this).attr("id"),e=d.replace(":","_"),f=a("#"+e+"_vars").html(),g=a(this).val(),h={vars:f,expr:g,sesskey:b.sesskey};a.post(b.wwwroot+"/question/type/algebra/ajax.php",h,null,"json").done(function(b){a("#"+e+"_display").html('<span class="filter_mathjaxloader_equation">'+b+"</span>"),MathJax.Hub.Queue(["Typeset",MathJax.Hub])}).fail(function(a,b,d){c.exception(d)})})}}}); \ No newline at end of file
diff --git a/amd/src/display.js b/amd/src/display.js
new file mode 100644
index 0000000..e2131b7
--- /dev/null
+++ b/amd/src/display.js
@@ -0,0 +1,28 @@
+define(['jquery', 'core/config', 'core/notification'], function($, config, notification) {
+ return {
+ init: function() {
+ $(".algebra_answer").on('input paste keyup', null, null, function() {
+ // Convert answer id to valid javascript name.
+ var id = $(this).attr('id');
+ var display = id.replace(':', '_');
+ var varnames = $('#' + display + '_vars').html();
+ var currentanswer = $(this).val();
+ var params = {
+ vars: varnames,
+ expr: currentanswer,
+ sesskey: config.sesskey,
+ };
+ $.post(config.wwwroot + '/question/type/algebra/ajax.php', params, null, 'json')
+ .done(function(data) {
+ // Replace TeX form in page.
+ $('#' + display + '_display').html("<span class=\"filter_mathjaxloader_equation\">" + data +"</span>");
+ // MathJax update.
+ MathJax.Hub.Queue(["Typeset", MathJax.Hub]);
+ })
+ .fail(function(jqXHR, status, error) {
+ notification.exception(error);
+ });
+ });
+ }
+ };
+}); \ No newline at end of file
diff --git a/lang/en/qtype_algebra.php b/lang/en/qtype_algebra.php
index 819e14b..4006858 100644
--- a/lang/en/qtype_algebra.php
+++ b/lang/en/qtype_algebra.php
@@ -145,4 +145,7 @@ $string['brackets'] = '\[...\]';
$string['invalidanswer'] = 'Invalid or unrecongnized answer';
$string['multiplyoperator'] = 'TeX operator for multiplication';
$string['times'] = '\\times';
-$string['cdot'] = '\\cdot'; \ No newline at end of file
+$string['cdot'] = '\\cdot';
+$string['iframe'] = 'Using an iframe element';
+$string['dynamic'] = 'Using dynamic AJAX request';
+$string['formuladisplay'] = 'Method to display answer formula'; \ No newline at end of file
diff --git a/renderer.php b/renderer.php
index 529fb0e..ec3d57e 100644
--- a/renderer.php
+++ b/renderer.php
@@ -38,6 +38,9 @@ class qtype_algebra_renderer extends qtype_renderer {
question_display_options $options) {
global $CFG;
+
+ $this->page->requires->js_call_amd('qtype_algebra/display', 'init');
+
$question = $qa->get_question();
$currentanswer = $qa->get_last_qt_var('answer');
@@ -50,6 +53,7 @@ class qtype_algebra_renderer extends qtype_renderer {
'name' => $inputname,
'value' => $currentanswer,
'id' => $inputname,
+ 'class' => 'algebra_answer',
'size' => 80,
);
@@ -65,13 +69,12 @@ class qtype_algebra_renderer extends qtype_renderer {
} else {
$fraction = 0;
}
- $inputattributes['class'] = $this->feedback_class($fraction);
+ $inputattributes['class'] = $this->feedback_class($fraction). ' algebra_answer';
$feedbackimg = $this->feedback_image($fraction);
+ } else {
+ $inputattributes['class'] = 'algebra_answer';
}
-
- $iframename = $nameprefix.'_if';
- // Name of the javascript function which causes the entered formula to be rendered.
- $dfname = $nameprefix.'_display';
+
// Create an array of variable names to use when displaying the function entered.
$varnames = array();
if ($question and isset($question->variables)) {
@@ -80,26 +83,14 @@ class qtype_algebra_renderer extends qtype_renderer {
$varnames[] = $var->name;
}
}
-
$varnames = implode(',', $varnames);
- // Javascript function which the button uses to display the rendering
- // This function sents the source of the iframe to the 'displayformula.php' script giving
- // it an argument of the formula entered by the student.
- $displayfunction = 'function '.$dfname."() {\n".
- ' var text="vars='.$varnames.'&expr="+escape(document.getElementsByName("'.$inputname.'")[0].value);'."\n".
- " if(text.length != 0) {\n".
- ' document.getElementsByName("'.$iframename.'")[0].src="'.
- $CFG->wwwroot.'/question/type/algebra/displayformula.php?"+'.
- 'text.replace(/\+/g,"%2b")'."\n".
- " }\n".
- " }\n";
$questiontext = $question->format_questiontext($qa);
$input = html_writer::empty_tag('input', $inputattributes) . $feedbackimg;
$result = html_writer::tag('div', $questiontext, array('class' => 'qtext'));
- $result .= html_writer::tag('script', $displayfunction, array('type' => 'text/javascript'));
+
$result .= html_writer::start_tag('div', array('class' => 'ablock'));
$result .= html_writer::start_tag('div', array('class' => 'prompt', 'style' => 'vertical-align: top'));
if (isset($question->answerprefix) and !empty($question->answerprefix)) {
@@ -118,15 +109,67 @@ class qtype_algebra_renderer extends qtype_renderer {
$question->get_validation_error(array('answer' => $currentanswer)),
array('class' => 'validationerror'));
}
- $result .= html_writer::start_tag('div', array('class' => 'dispresponse'));
- $result .= html_writer::empty_tag('input', array('type' => 'button',
- 'value' => get_string('displayresponse', 'qtype_algebra'), 'onclick' => $dfname.'()'));
- $result .= html_writer::start_tag('iframe',
- array('name' => $iframename, 'width' => '60%', 'height' => 60, 'align' => 'middle', 'src' => ''));
- $result .= html_writer::end_tag('iframe');
- $result .= html_writer::tag('script', $dfname.'();', array('type' => 'text/javascript'));
- $result .= html_writer::end_tag('div');
-
+ if (get_config('qtype_algebra', 'formuladisplay') == 'iframe') {
+ // Javascript function which the button uses to display the rendering
+ // This function sents the source of the iframe to the 'displayformula.php' script giving
+ // it an argument of the formula entered by the student.
+ $iframename = $nameprefix.'_if';
+ // Name of the javascript function which causes the entered formula to be rendered.
+ $dfname = $nameprefix.'_display';
+ $displayfunction = 'function '.$dfname."() {\n".
+ ' var text="vars='.$varnames.'&expr="+escape(document.getElementsByName("'.$inputname.'")[0].value);'."\n".
+ " if(text.length != 0) {\n".
+ ' document.getElementsByName("'.$iframename.'")[0].src="'.
+ $CFG->wwwroot.'/question/type/algebra/displayformula.php?"+'.
+ 'text.replace(/\+/g,"%2b")'."\n".
+ " }\n".
+ " }\n";
+ $result .= html_writer::tag('script', $displayfunction, array('type' => 'text/javascript'));
+ $result .= html_writer::start_tag('div', array('class' => 'dispresponse'));
+ $result .= html_writer::empty_tag('input', array('type' => 'button',
+ 'value' => get_string('displayresponse', 'qtype_algebra'), 'onclick' => $dfname.'()'));
+ $result .= html_writer::start_tag('iframe',
+ array('name' => $iframename, 'width' => '60%', 'height' => 60, 'align' => 'middle', 'src' => ''));
+ $result .= html_writer::end_tag('iframe');
+ $result .= html_writer::tag('script', $dfname.'();', array('type' => 'text/javascript'));
+ $result .= html_writer::end_tag('div');
+ } else {
+ $result .= html_writer::tag('div', $varnames ,array(
+ 'type' => 'text',
+ 'name' => $nameprefix . '_vars',
+ 'id' => $nameprefix . '_vars',
+ 'size' => 80,
+ 'style' => 'display:none',
+ )
+ );
+ $p = new qtype_algebra_parser;
+ try {
+ $vars = explode(',', $varnames);
+ if (empty($currentanswer)) {
+ $texexp = '';
+ } else {
+ $exp = $p->parse($currentanswer, $vars);
+ $texexp = $exp->tex();
+ }
+ } catch (Exception $e) {
+ $texexp = '';
+ }
+ if ($CFG->qtype_algebra_texdelimiters == 'old') {
+ $texexp = '$$' . $texexp . '$$';
+ } else {
+ $texexp = '\\[' . $texexp . '\\]';
+ }
+ $display = $question->format_text("<span class=\"filter_mathjaxloader_equation\">" . $texexp ."</span>",
+ 1 ,$qa, 'question', 'questiontext', $question->id);
+ $result .= html_writer::tag('div', $display ,array(
+ 'type' => 'text',
+ 'name' => $nameprefix . '_display',
+ 'id' => $nameprefix. '_display',
+ 'size' => 80,
+ 'class' => 'displayformula',
+ )
+ );
+ }
return $result;
}
diff --git a/settings.php b/settings.php
index 525324a..1c6fa30 100644
--- a/settings.php
+++ b/settings.php
@@ -54,4 +54,11 @@ if ($ADMIN->fulltree) {
array('times' => new lang_string('times', 'qtype_algebra'),
'cdot' => new lang_string('cdot', 'qtype_algebra')
)));
+ // Method to diplay TeX formatted answer formula.
+ $settings->add(new admin_setting_configselect('qtype_algebra/formuladisplay',
+ new lang_string('formuladisplay', 'qtype_algebra'),
+ '', 'times',
+ array('iframe' => new lang_string('iframe', 'qtype_algebra'),
+ 'dynamic' => new lang_string('dynamic', 'qtype_algebra')
+ )));
}
diff --git a/styles.css b/styles.css
index 11b6fd7..7b90945 100644
--- a/styles.css
+++ b/styles.css
@@ -5,6 +5,16 @@
.que.algebra .answer input {
width: 80%;
}
+.que.algebra .displayformula {
+ padding: 0.3em;
+ display: block;
+ width: 300px;
+ min-height: 70px ! important;
+ background: #fff3bf;
+ padding: 0.5em;
+ margin-top: 1em;
+ box-shadow: 0.5em 0.5em 1em #000;
+}
/* Editing form. */
body#page-question-type-algebra div[id^=fgroup_id_][id*=answeroptions_] {
diff --git a/version.php b/version.php
index 7eb6e41..1db1702 100644
--- a/version.php
+++ b/version.php
@@ -23,7 +23,7 @@
defined('MOODLE_INTERNAL') || die();
$plugin->component = 'qtype_algebra';
-$plugin->version = 2018010400;
+$plugin->version = 2018020100;
$plugin->requires = 2013050100;
$plugin->release = '1.6 for Moodle 2.8, ... 3.5';