mirror of
https://github.com/moodle/moodle.git
synced 2025-04-15 13:33:52 +02:00
MDL-43855 Atto: Add an equation editor
This equation editor relies on whatever the currently configured filter is to do the rendering. If there is no filter that handles latex ($$ blah $$) - this plugin will not show up. This will not work with the solutions on the forums of adding MathJax in the header of the page, but it will work with a real mathjax filter written for Moodle (work in progress). It works with the existing tex filter.
This commit is contained in:
parent
05843fd3ee
commit
8bf5ad67ea
50
lib/editor/atto/plugins/equation/ajax.php
Normal file
50
lib/editor/atto/plugins/equation/ajax.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Renders text with the active filters and returns it. Used to create previews of equations
|
||||
* using whatever tex filters are enabled.
|
||||
*
|
||||
* @package atto_equation
|
||||
* @copyright 2014 Damyon Wiese
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
define('AJAX_SCRIPT', true);
|
||||
|
||||
require_once(dirname(__FILE__) . '/../../../../../config.php');
|
||||
|
||||
$contextid = required_param('contextid', PARAM_INT);
|
||||
$context = context::instance_by_id($contextid, MUST_EXIST);
|
||||
$PAGE->set_url('/lib/editor/atto/plugins/equation/ajax.php');
|
||||
$PAGE->set_context($context);
|
||||
|
||||
require_login();
|
||||
require_sesskey();
|
||||
|
||||
$action = required_param('action', PARAM_ALPHA);
|
||||
|
||||
if ($action === 'filtertext') {
|
||||
$text = required_param('text', PARAM_RAW);
|
||||
|
||||
$result = filter_manager::instance()->filter_text($text, $context);
|
||||
echo $OUTPUT->header();
|
||||
echo $result;
|
||||
|
||||
die();
|
||||
}
|
||||
|
||||
print_error('invalidarguments');
|
39
lib/editor/atto/plugins/equation/lang/en/atto_equation.php
Normal file
39
lib/editor/atto/plugins/equation/lang/en/atto_equation.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Strings for component 'atto_equation', language 'en'.
|
||||
*
|
||||
* @package atto_equation
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$string['editequation'] = 'Edit equation';
|
||||
$string['editequation_desc'] = 'Equations are written in <a target="_blank" href="http://en.wikibooks.org/wiki/TeX" title="Link to wikipedia">TeX.</a>';
|
||||
$string['librarygroup1'] = 'Operators';
|
||||
$string['librarygroup1_desc'] = 'List of tex commands to list on the operators tab.';
|
||||
$string['librarygroup2'] = 'Arrows';
|
||||
$string['librarygroup2_desc'] = 'List of tex commands to list on the arrows tab.';
|
||||
$string['librarygroup3'] = 'Greek Symbols';
|
||||
$string['librarygroup3_desc'] = 'List of tex commands to list on the greek symbols tab.';
|
||||
$string['librarygroup4'] = 'Advanced';
|
||||
$string['librarygroup4_desc'] = 'List of tex commands to list on the advanced tab.';
|
||||
$string['pluginname'] = 'Equation editor';
|
||||
$string['preview'] = 'Equation preview (cursor position is indicated with a box)';
|
||||
$string['saveequation'] = 'Save equation';
|
||||
$string['settings'] = 'Equation editor settings';
|
||||
$string['update'] = 'Update';
|
73
lib/editor/atto/plugins/equation/lib.php
Normal file
73
lib/editor/atto/plugins/equation/lib.php
Normal file
@ -0,0 +1,73 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Atto text editor integration version file.
|
||||
*
|
||||
* @package atto_equation
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Get the list of strings for this plugin.
|
||||
* @param string $elementid
|
||||
*/
|
||||
function atto_equation_strings_for_js() {
|
||||
global $PAGE;
|
||||
|
||||
$PAGE->requires->strings_for_js(array('saveequation',
|
||||
'editequation',
|
||||
'preview',
|
||||
'editequation_desc',
|
||||
'update',
|
||||
'librarygroup1',
|
||||
'librarygroup2',
|
||||
'librarygroup3',
|
||||
'librarygroup4'),
|
||||
'atto_equation');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set params for this plugin.
|
||||
*
|
||||
* @param string $elementid
|
||||
* @param stdClass $options - the options for the editor, including the context.
|
||||
* @param stdClass $fpoptions - unused.
|
||||
*/
|
||||
function atto_equation_params_for_js($elementid, $options, $fpoptions) {
|
||||
$texexample = '$$\pi$$';
|
||||
|
||||
// Format a string with the active filter set.
|
||||
// If it is modified - we assume that some sort of text filter is working in this context.
|
||||
$result = format_text($texexample, true, $options);
|
||||
|
||||
$texfilteractive = ($texexample !== $result);
|
||||
$context = $options['context'];
|
||||
if (!$context) {
|
||||
$context = context_system::instance();
|
||||
}
|
||||
|
||||
// Tex example librarys.
|
||||
$library = array('group1' => get_config('atto_equation', 'librarygroup1'),
|
||||
'group2' => get_config('atto_equation', 'librarygroup2'),
|
||||
'group3' => get_config('atto_equation', 'librarygroup3'),
|
||||
'group4' => get_config('atto_equation', 'librarygroup4'));
|
||||
|
||||
return array('texfilteractive' => $texfilteractive, 'contextid'=>$context->id, 'library'=>$library);
|
||||
}
|
168
lib/editor/atto/plugins/equation/settings.php
Normal file
168
lib/editor/atto/plugins/equation/settings.php
Normal file
@ -0,0 +1,168 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Settings that allow configuration of the list of tex examples in the equation editor.
|
||||
*
|
||||
* @package atto_equation
|
||||
* @copyright 2013 Damyon Wiese
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$ADMIN->add('editoratto', new admin_category('atto_equation', new lang_string('pluginname', 'atto_equation')));
|
||||
|
||||
$settings = new admin_settingpage('atto_equation_settings', new lang_string('settings', 'atto_equation'));
|
||||
if ($ADMIN->fulltree) {
|
||||
// Group 1
|
||||
$name = new lang_string('librarygroup1', 'atto_equation');
|
||||
$desc = new lang_string('librarygroup1_desc', 'atto_equation');
|
||||
$default = '
|
||||
\cdot
|
||||
\times
|
||||
\ast
|
||||
\div
|
||||
\diamond
|
||||
\pm
|
||||
\mp
|
||||
\oplus
|
||||
\ominus
|
||||
\otimes
|
||||
\oslash
|
||||
\odot
|
||||
\circ
|
||||
\bullet
|
||||
\asymp
|
||||
\equiv
|
||||
\subseteq
|
||||
\supseteq
|
||||
\leq
|
||||
\geq
|
||||
\preceq
|
||||
\succeq
|
||||
\sim
|
||||
\simeq
|
||||
\approx
|
||||
\subset
|
||||
\supset
|
||||
\ll
|
||||
\gg
|
||||
\prec
|
||||
\succ
|
||||
\infty
|
||||
\in
|
||||
\ni
|
||||
\forall
|
||||
\exists
|
||||
\neq
|
||||
';
|
||||
$setting = new admin_setting_configtextarea('atto_equation/librarygroup1',
|
||||
$name,
|
||||
$desc,
|
||||
$default);
|
||||
$settings->add($setting);
|
||||
|
||||
// Group 2
|
||||
$name = new lang_string('librarygroup2', 'atto_equation');
|
||||
$desc = new lang_string('librarygroup2_desc', 'atto_equation');
|
||||
$default = '
|
||||
\leftarrow
|
||||
\rightarrow
|
||||
\uparrow
|
||||
\downarrow
|
||||
\leftrightarrow
|
||||
\nearrow
|
||||
\searrow
|
||||
\swarrow
|
||||
\nwarrow
|
||||
\Leftarrow
|
||||
\Rightarrow
|
||||
\Uparrow
|
||||
\Downarrow
|
||||
\Leftrightarrow
|
||||
';
|
||||
$setting = new admin_setting_configtextarea('atto_equation/librarygroup2',
|
||||
$name,
|
||||
$desc,
|
||||
$default);
|
||||
$settings->add($setting);
|
||||
|
||||
// Group 3
|
||||
$name = new lang_string('librarygroup3', 'atto_equation');
|
||||
$desc = new lang_string('librarygroup3_desc', 'atto_equation');
|
||||
$default = '
|
||||
\alpha
|
||||
\beta
|
||||
\gamma
|
||||
\delta
|
||||
\epsilon
|
||||
\zeta
|
||||
\eta
|
||||
\theta
|
||||
\iota
|
||||
\kappa
|
||||
\lambda
|
||||
\mu
|
||||
\nu
|
||||
\xi
|
||||
\pi
|
||||
\rho
|
||||
\sigma
|
||||
\tau
|
||||
\upsilon
|
||||
\phi
|
||||
\chi
|
||||
\psi
|
||||
\omega
|
||||
\Gamma
|
||||
\Delta
|
||||
\Theta
|
||||
\Lambda
|
||||
\Xi
|
||||
\Pi
|
||||
\Sigma
|
||||
\Upsilon
|
||||
\Phi
|
||||
\Psi
|
||||
\Omega
|
||||
';
|
||||
$setting = new admin_setting_configtextarea('atto_equation/librarygroup3',
|
||||
$name,
|
||||
$desc,
|
||||
$default);
|
||||
$settings->add($setting);
|
||||
|
||||
// Group 4
|
||||
$name = new lang_string('librarygroup4', 'atto_equation');
|
||||
$desc = new lang_string('librarygroup4_desc', 'atto_equation');
|
||||
$default = '
|
||||
\sum{a,b}
|
||||
\int_{a}^{b}{c}
|
||||
\iint_{a}^{b}{c}
|
||||
\iiint_{a}^{b}{c}
|
||||
\oint{a}
|
||||
(a)
|
||||
[a]
|
||||
\lbrace{a}\rbrace
|
||||
\left| \begin{matrix} a_1 & a_2 \\ a_3 & a_4 \end{matrix} \right|
|
||||
';
|
||||
$setting = new admin_setting_configtextarea('atto_equation/librarygroup4',
|
||||
$name,
|
||||
$desc,
|
||||
$default);
|
||||
$settings->add($setting);
|
||||
}
|
21
lib/editor/atto/plugins/equation/styles.css
Normal file
21
lib/editor/atto/plugins/equation/styles.css
Normal file
@ -0,0 +1,21 @@
|
||||
#atto_equation_library .yui3-tabview-list {
|
||||
border: none;
|
||||
}
|
||||
|
||||
#atto_equation_library .yui3-tab-selected .yui3-tab-label, .yui3-skin-sam #atto_equation_library .yui3-tab-selected .yui3-tab-label:focus, .yui3-skin-sam #atto_equation_library .yui3-tab-selected .yui3-tab-label:hover {
|
||||
background: none;
|
||||
color: black;
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
|
||||
#atto_equation_library button {
|
||||
margin: 4px;
|
||||
}
|
||||
|
||||
#page-admin-setting-atto_equation_settings .form-defaultinfo {
|
||||
max-height: 10em;
|
||||
overflow: auto;
|
||||
padding: 5px;
|
||||
min-width: 206px;
|
||||
}
|
29
lib/editor/atto/plugins/equation/version.php
Normal file
29
lib/editor/atto/plugins/equation/version.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Atto text editor integration version file.
|
||||
*
|
||||
* @package atto_equation
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2014012800; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2013110500; // Requires this Moodle version.
|
||||
$plugin->component = 'atto_equation'; // Full name of the plugin (used for diagnostics).
|
@ -0,0 +1,365 @@
|
||||
YUI.add('moodle-atto_equation-button', function (Y, NAME) {
|
||||
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Atto text editor equation plugin.
|
||||
*
|
||||
* @package editor-atto
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
M.atto_equation = M.atto_equation || {
|
||||
/**
|
||||
* The window used to get the equation details.
|
||||
*
|
||||
* @property dialogue
|
||||
* @type M.core.dialogue
|
||||
* @default null
|
||||
*/
|
||||
dialogue : null,
|
||||
|
||||
/**
|
||||
* The selection object returned by the browser.
|
||||
*
|
||||
* @property selection
|
||||
* @type Range
|
||||
* @default null
|
||||
*/
|
||||
selection : null,
|
||||
|
||||
/**
|
||||
* A mapping of elementids to contextids.
|
||||
*
|
||||
* @property contextids
|
||||
* @type Object
|
||||
* @default {}
|
||||
*/
|
||||
contextids : {},
|
||||
|
||||
/**
|
||||
* A nested object containing a the configured list of tex examples.
|
||||
*
|
||||
* @property library
|
||||
* @type Object
|
||||
* @default {}
|
||||
*/
|
||||
library : {},
|
||||
|
||||
/**
|
||||
* The last cursor index in the source.
|
||||
*
|
||||
* @property lastcursor
|
||||
* @type Integer
|
||||
* @default 0
|
||||
*/
|
||||
lastcursor : 0,
|
||||
|
||||
/**
|
||||
* Display the chooser dialogue.
|
||||
*
|
||||
* @method display_chooser
|
||||
* @param Event e
|
||||
* @param string elementid
|
||||
*/
|
||||
display_chooser : function(e, elementid) {
|
||||
e.preventDefault();
|
||||
if (!M.editor_atto.is_active(elementid)) {
|
||||
M.editor_atto.focus(elementid);
|
||||
}
|
||||
M.atto_equation.selection = M.editor_atto.get_selection();
|
||||
if (M.atto_equation.selection !== false && (!M.atto_equation.selection.collapsed)) {
|
||||
var dialogue;
|
||||
if (!M.atto_equation.dialogue) {
|
||||
dialogue = new M.core.dialogue({
|
||||
visible: false,
|
||||
modal: true,
|
||||
close: true,
|
||||
draggable: true,
|
||||
width: '800px'
|
||||
});
|
||||
} else {
|
||||
dialogue = M.atto_equation.dialogue;
|
||||
}
|
||||
|
||||
dialogue.render();
|
||||
dialogue.set('bodyContent', M.atto_equation.get_form_content(elementid));
|
||||
dialogue.set('headerContent', M.util.get_string('pluginname', 'atto_equation'));
|
||||
|
||||
var tabview = new Y.TabView({
|
||||
srcNode: '#atto_equation_library'
|
||||
});
|
||||
|
||||
tabview.render();
|
||||
dialogue.show();
|
||||
M.atto_equation.resolve_equation();
|
||||
M.atto_equation.update_preview(false, elementid);
|
||||
M.atto_equation.dialogue = dialogue;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Add this button to the form.
|
||||
*
|
||||
* @method init
|
||||
* @param {Object} params
|
||||
*/
|
||||
init : function(params) {
|
||||
var iconurl = M.util.image_url('e/math', 'core');
|
||||
|
||||
if (params.texfilteractive) {
|
||||
// Save the elementid/contextid mapping.
|
||||
this.contextids[params.elementid] = params.contextid;
|
||||
// Save the button library.
|
||||
this.library = params.library;
|
||||
|
||||
// Add the button to the toolbar.
|
||||
M.editor_atto.add_toolbar_button(params.elementid, 'equation', iconurl, params.group, this.display_chooser);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* If there is selected text and it is part of an equation,
|
||||
* extract the equation (and set it in the form).
|
||||
*
|
||||
* @method resolve_equation
|
||||
*/
|
||||
resolve_equation : function() {
|
||||
// Find the equation in the surrounding text.
|
||||
var selectednode = M.editor_atto.get_selection_parent_node(),
|
||||
text,
|
||||
equation;
|
||||
|
||||
// Note this is a document fragment and YUI doesn't like them.
|
||||
if (!selectednode) {
|
||||
return;
|
||||
}
|
||||
|
||||
text = Y.one(selectednode).get('text');
|
||||
// We use space or not space because . does not match new lines.
|
||||
pattern = /\$\$[\S\s]*\$\$/;
|
||||
equation = pattern.exec(text);
|
||||
if (equation && equation.length) {
|
||||
equation = equation.pop();
|
||||
// Replace the equation.
|
||||
equation = equation.substring(2, equation.length - 2);
|
||||
Y.one('#atto_equation_equation').set('text', equation);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* The OK button has been pressed - make the changes to the source.
|
||||
*
|
||||
* @method set_equation
|
||||
* @param {Y.Event} e
|
||||
* @param {String} elementid
|
||||
*/
|
||||
set_equation : function(e, elementid) {
|
||||
var input,
|
||||
selectednode,
|
||||
text,
|
||||
pattern,
|
||||
equation,
|
||||
value;
|
||||
|
||||
e.preventDefault();
|
||||
M.atto_equation.dialogue.hide();
|
||||
M.editor_atto.set_selection(M.atto_equation.selection);
|
||||
|
||||
input = e.currentTarget.ancestor('.atto_form').one('textarea');
|
||||
|
||||
value = input.get('value');
|
||||
if (value !== '') {
|
||||
value = '$$ ' + value.trim() + ' $$';
|
||||
selectednode = Y.one(M.editor_atto.get_selection_parent_node()),
|
||||
text = selectednode.get('text');
|
||||
pattern = /\$\$[\S\s]*\$\$/;
|
||||
equation = pattern.exec(text);
|
||||
if (equation && equation.length) {
|
||||
// Replace the equation.
|
||||
equation = equation.pop();
|
||||
text = text.replace(equation, '$$' + value + '$$');
|
||||
selectednode.set('text', text);
|
||||
} else {
|
||||
// Insert the new equation.
|
||||
if (document.selection && document.selection.createRange().pasteHTML) {
|
||||
document.selection.createRange().pasteHTML(value);
|
||||
} else {
|
||||
document.execCommand('insertHTML', false, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Clean the YUI ids from the HTML.
|
||||
M.editor_atto.text_updated(elementid);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the preview div to match the current equation.
|
||||
*
|
||||
* @param Event e - unused
|
||||
* @param String elementid - The editor elementid.
|
||||
* @method update_preview
|
||||
*/
|
||||
update_preview : function(e, elementid) {
|
||||
var textarea = Y.one('#atto_equation_equation');
|
||||
var equation = textarea.get('value'), url, preview;
|
||||
var prefix = '';
|
||||
var cursorlatex = '\\square ' ;
|
||||
|
||||
var currentpos = textarea.get('selectionStart');
|
||||
if (!currentpos) {
|
||||
currentpos = 0;
|
||||
}
|
||||
// Move the cursor so it does not break expressions.
|
||||
//
|
||||
while (equation.charAt(currentpos) === '\\' && currentpos > 0) {
|
||||
currentpos -= 1;
|
||||
}
|
||||
var ischar = /[\w\{\}]/;
|
||||
while (ischar.test(equation.charAt(currentpos)) && currentpos < equation.length) {
|
||||
currentpos += 1;
|
||||
}
|
||||
// Save the cursor position - for insertion from the library.
|
||||
this.lastcursorpos = currentpos;
|
||||
equation = prefix + equation.substring(0, currentpos) + cursorlatex + equation.substring(currentpos);
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
url = M.cfg.wwwroot + '/lib/editor/atto/plugins/equation/ajax.php';
|
||||
params = {
|
||||
sesskey: M.cfg.sesskey,
|
||||
contextid: this.contextids[elementid],
|
||||
action : 'filtertext',
|
||||
text : '$$ ' + equation + ' $$'
|
||||
};
|
||||
|
||||
|
||||
preview = Y.io(url, { sync: true,
|
||||
data: params });
|
||||
if (preview.status === 200) {
|
||||
Y.one('#atto_equation_preview').setHTML(preview.responseText);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the HTML of the form to show in the dialogue.
|
||||
*
|
||||
* @method get_form_content
|
||||
* @param string elementid
|
||||
* @return string
|
||||
*/
|
||||
get_form_content : function(elementid) {
|
||||
var content = Y.Node.create('<form class="atto_form">' +
|
||||
this.get_library_html(elementid) +
|
||||
'<label for="atto_equation_equation">' + M.util.get_string('editequation', 'atto_equation') +
|
||||
'</label>' +
|
||||
'<textarea class="fullwidth" id="atto_equation_equation" rows="8"></textarea><br/>' +
|
||||
'<p>' + M.util.get_string('editequation_desc', 'atto_equation') + '</p>' +
|
||||
'<label for="atto_equation_preview">' + M.util.get_string('preview', 'atto_equation') +
|
||||
'</label>' +
|
||||
'<div class="fullwidth" id="atto_equation_preview"></div>' +
|
||||
'<div class="mdl-align">' +
|
||||
'<br/>' +
|
||||
'<button id="atto_equation_submit">' +
|
||||
M.util.get_string('saveequation', 'atto_equation') +
|
||||
'</button>' +
|
||||
'</div>' +
|
||||
'</form>');
|
||||
|
||||
content.one('#atto_equation_submit').on('click', M.atto_equation.set_equation, this, elementid);
|
||||
content.one('#atto_equation_equation').on('valuechange', M.atto_equation.update_preview, this, elementid);
|
||||
content.one('#atto_equation_equation').on('keyup', M.atto_equation.update_preview, this, elementid);
|
||||
content.one('#atto_equation_equation').on('mouseup', M.atto_equation.update_preview, this, elementid);
|
||||
|
||||
content.delegate('click', M.atto_equation.select_library_item, '#atto_equation_library button', this, elementid);
|
||||
|
||||
return content;
|
||||
},
|
||||
|
||||
/**
|
||||
* Reponse to button presses in the tex library panels.
|
||||
*
|
||||
* @method select_library_item
|
||||
* @param Event event
|
||||
* @param string elementid
|
||||
* @return string
|
||||
*/
|
||||
select_library_item : function(event, elementid) {
|
||||
var tex = event.currentTarget.getAttribute('data-tex');
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
input = event.currentTarget.ancestor('.atto_form').one('textarea');
|
||||
|
||||
value = input.get('value');
|
||||
|
||||
value = value.substring(0, this.lastcursorpos) + tex + value.substring(this.lastcursorpos, value.length);
|
||||
|
||||
input.set('value', value);
|
||||
M.atto_equation.update_preview(false, elementid);
|
||||
input.focus();
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the HTML for rendering the library of predefined buttons.
|
||||
*
|
||||
* @method get_library_html
|
||||
* @param string elementid
|
||||
* @return string
|
||||
*/
|
||||
get_library_html : function(elementid) {
|
||||
var content = '<div id="atto_equation_library">', i = 0, group = 1;
|
||||
content += '<ul>';
|
||||
for (group = 1; group < 5; group++) {
|
||||
content += '<li><a href="#atto_equation_library' + group + '">' + M.util.get_string('librarygroup' + group, 'atto_equation') + '</a></li>';
|
||||
}
|
||||
content += '</ul>';
|
||||
content += '<div>';
|
||||
for (group = 1; group < 5; group++) {
|
||||
content += '<div id="atto_equation_library' + group + '">';
|
||||
var examples = this.library['group' + group].split("\n");
|
||||
for (i = 0; i < examples.length; i++) {
|
||||
if (examples[i]) {
|
||||
examples[i] = Y.Escape.html(examples[i]);
|
||||
content += '<button data-tex="' + examples[i] + '" title="' + examples[i] + '">$$' + examples[i] + '$$</button>';
|
||||
}
|
||||
}
|
||||
content += '</div>';
|
||||
}
|
||||
content += '</div>';
|
||||
content += '</div>';
|
||||
|
||||
var url = M.cfg.wwwroot + '/lib/editor/atto/plugins/equation/ajax.php';
|
||||
var params = {
|
||||
sesskey: M.cfg.sesskey,
|
||||
contextid: this.contextids[elementid],
|
||||
action : 'filtertext',
|
||||
text : content
|
||||
};
|
||||
|
||||
preview = Y.io(url, { sync: true, data: params, method: 'POST'});
|
||||
|
||||
if (preview.status === 200) {
|
||||
content = preview.responseText;
|
||||
}
|
||||
return content;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}, '@VERSION@', {"requires": ["node", "escape", "io", "event-valuechange", "tabview"]});
|
@ -0,0 +1 @@
|
||||
YUI.add("moodle-atto_equation-button",function(e,t){M.atto_equation=M.atto_equation||{dialogue:null,selection:null,contextids:{},library:{},lastcursor:0,display_chooser:function(t,n){t.preventDefault(),M.editor_atto.is_active(n)||M.editor_atto.focus(n),M.atto_equation.selection=M.editor_atto.get_selection();if(M.atto_equation.selection!==!1&&!M.atto_equation.selection.collapsed){var r;M.atto_equation.dialogue?r=M.atto_equation.dialogue:r=new M.core.dialogue({visible:!1,modal:!0,close:!0,draggable:!0,width:"800px"}),r.render(),r.set("bodyContent",M.atto_equation.get_form_content(n)),r.set("headerContent",M.util.get_string("pluginname","atto_equation"));var i=new e.TabView({srcNode:"#atto_equation_library"});i.render(),r.show(),M.atto_equation.resolve_equation(),M.atto_equation.update_preview(!1,n),M.atto_equation.dialogue=r}},init:function(e){var t=M.util.image_url("e/math","core");e.texfilteractive&&(this.contextids[e.elementid]=e.contextid,this.library=e.library,M.editor_atto.add_toolbar_button(e.elementid,"equation",t,e.group,this.display_chooser))},resolve_equation:function(){var t=M.editor_atto.get_selection_parent_node(),n,r;if(!t)return;n=e.one(t).get("text"),pattern=/\$\$[\S\s]*\$\$/,r=pattern.exec(n),r&&r.length&&(r=r.pop(),r=r.substring(2,r.length-2),e.one("#atto_equation_equation").set("text",r))},set_equation:function(t,n){var r,i,s,o,u,a;t.preventDefault(),M.atto_equation.dialogue.hide(),M.editor_atto.set_selection(M.atto_equation.selection),r=t.currentTarget.ancestor(".atto_form").one("textarea"),a=r.get("value"),a!==""&&(a="$$ "+a.trim()+" $$",i=e.one(M.editor_atto.get_selection_parent_node()),s=i.get("text"),o=/\$\$[\S\s]*\$\$/,u=o.exec(s),u&&u.length?(u=u.pop(),s=s.replace(u,"$$"+a+"$$"),i.set("text",s)):document.selection&&document.selection.createRange().pasteHTML?document.selection.createRange().pasteHTML(a):document.execCommand("insertHTML",!1,a),M.editor_atto.text_updated(n))},update_preview:function(t,n){var r=e.one("#atto_equation_equation"),i=r.get("value"),s,o,u="",a="\\square ",f=r.get("selectionStart");f||(f=0);while(i.charAt(f)==="\\"&&f>0)f-=1;var l=/[\w\{\}]/;while(l.test(i.charAt(f))&&f<i.length)f+=1;this.lastcursorpos=f,i=u+i.substring(0,f)+a+i.substring(f),t&&t.preventDefault(),s=M.cfg.wwwroot+"/lib/editor/atto/plugins/equation/ajax.php",params={sesskey:M.cfg.sesskey,contextid:this.contextids[n],action:"filtertext",text:"$$ "+i+" $$"},o=e.io(s,{sync:!0,data:params}),o.status===200&&e.one("#atto_equation_preview").setHTML(o.responseText)},get_form_content:function(t){var n=e.Node.create('<form class="atto_form">'+this.get_library_html(t)+'<label for="atto_equation_equation">'+M.util.get_string("editequation","atto_equation")+"</label>"+'<textarea class="fullwidth" id="atto_equation_equation" rows="8"></textarea><br/>'+"<p>"+M.util.get_string("editequation_desc","atto_equation")+"</p>"+'<label for="atto_equation_preview">'+M.util.get_string("preview","atto_equation")+"</label>"+'<div class="fullwidth" id="atto_equation_preview"></div>'+'<div class="mdl-align">'+"<br/>"+'<button id="atto_equation_submit">'+M.util.get_string("saveequation","atto_equation")+"</button>"+"</div>"+"</form>");return n.one("#atto_equation_submit").on("click",M.atto_equation.set_equation,this,t),n.one("#atto_equation_equation").on("valuechange",M.atto_equation.update_preview,this,t),n.one("#atto_equation_equation").on("keyup",M.atto_equation.update_preview,this,t),n.one("#atto_equation_equation").on("mouseup",M.atto_equation.update_preview,this,t),n.delegate("click",M.atto_equation.select_library_item,"#atto_equation_library button",this,t),n},select_library_item:function(e,t){var n=e.currentTarget.getAttribute("data-tex");e.preventDefault(),input=e.currentTarget.ancestor(".atto_form").one("textarea"),value=input.get("value"),value=value.substring(0,this.lastcursorpos)+n+value.substring(this.lastcursorpos,value.length),input.set("value",value),M.atto_equation.update_preview(!1,t),input.focus()},get_library_html:function(t){var n='<div id="atto_equation_library">',r=0,i=1;n+="<ul>";for(i=1;i<5;i++)n+='<li><a href="#atto_equation_library'+i+'">'+M.util.get_string("librarygroup"+i,"atto_equation")+"</a></li>";n+="</ul>",n+="<div>";for(i=1;i<5;i++){n+='<div id="atto_equation_library'+i+'">';var s=this.library["group"+i].split("\n");for(r=0;r<s.length;r++)s[r]&&(s[r]=e.Escape.html(s[r]),n+='<button data-tex="'+s[r]+'" title="'+s[r]+'">$$'+s[r]+"$$</button>");n+="</div>"}n+="</div>",n+="</div>";var o=M.cfg.wwwroot+"/lib/editor/atto/plugins/equation/ajax.php",u={sesskey:M.cfg.sesskey,contextid:this.contextids[t],action:"filtertext",text:n};return preview=e.io(o,{sync:!0,data:u,method:"POST"}),preview.status===200&&(n=preview.responseText),n}}},"@VERSION@",{requires:["node","escape","io","event-valuechange","tabview"]});
|
@ -0,0 +1,365 @@
|
||||
YUI.add('moodle-atto_equation-button', function (Y, NAME) {
|
||||
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Atto text editor equation plugin.
|
||||
*
|
||||
* @package editor-atto
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
M.atto_equation = M.atto_equation || {
|
||||
/**
|
||||
* The window used to get the equation details.
|
||||
*
|
||||
* @property dialogue
|
||||
* @type M.core.dialogue
|
||||
* @default null
|
||||
*/
|
||||
dialogue : null,
|
||||
|
||||
/**
|
||||
* The selection object returned by the browser.
|
||||
*
|
||||
* @property selection
|
||||
* @type Range
|
||||
* @default null
|
||||
*/
|
||||
selection : null,
|
||||
|
||||
/**
|
||||
* A mapping of elementids to contextids.
|
||||
*
|
||||
* @property contextids
|
||||
* @type Object
|
||||
* @default {}
|
||||
*/
|
||||
contextids : {},
|
||||
|
||||
/**
|
||||
* A nested object containing a the configured list of tex examples.
|
||||
*
|
||||
* @property library
|
||||
* @type Object
|
||||
* @default {}
|
||||
*/
|
||||
library : {},
|
||||
|
||||
/**
|
||||
* The last cursor index in the source.
|
||||
*
|
||||
* @property lastcursor
|
||||
* @type Integer
|
||||
* @default 0
|
||||
*/
|
||||
lastcursor : 0,
|
||||
|
||||
/**
|
||||
* Display the chooser dialogue.
|
||||
*
|
||||
* @method display_chooser
|
||||
* @param Event e
|
||||
* @param string elementid
|
||||
*/
|
||||
display_chooser : function(e, elementid) {
|
||||
e.preventDefault();
|
||||
if (!M.editor_atto.is_active(elementid)) {
|
||||
M.editor_atto.focus(elementid);
|
||||
}
|
||||
M.atto_equation.selection = M.editor_atto.get_selection();
|
||||
if (M.atto_equation.selection !== false && (!M.atto_equation.selection.collapsed)) {
|
||||
var dialogue;
|
||||
if (!M.atto_equation.dialogue) {
|
||||
dialogue = new M.core.dialogue({
|
||||
visible: false,
|
||||
modal: true,
|
||||
close: true,
|
||||
draggable: true,
|
||||
width: '800px'
|
||||
});
|
||||
} else {
|
||||
dialogue = M.atto_equation.dialogue;
|
||||
}
|
||||
|
||||
dialogue.render();
|
||||
dialogue.set('bodyContent', M.atto_equation.get_form_content(elementid));
|
||||
dialogue.set('headerContent', M.util.get_string('pluginname', 'atto_equation'));
|
||||
|
||||
var tabview = new Y.TabView({
|
||||
srcNode: '#atto_equation_library'
|
||||
});
|
||||
|
||||
tabview.render();
|
||||
dialogue.show();
|
||||
M.atto_equation.resolve_equation();
|
||||
M.atto_equation.update_preview(false, elementid);
|
||||
M.atto_equation.dialogue = dialogue;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Add this button to the form.
|
||||
*
|
||||
* @method init
|
||||
* @param {Object} params
|
||||
*/
|
||||
init : function(params) {
|
||||
var iconurl = M.util.image_url('e/math', 'core');
|
||||
|
||||
if (params.texfilteractive) {
|
||||
// Save the elementid/contextid mapping.
|
||||
this.contextids[params.elementid] = params.contextid;
|
||||
// Save the button library.
|
||||
this.library = params.library;
|
||||
|
||||
// Add the button to the toolbar.
|
||||
M.editor_atto.add_toolbar_button(params.elementid, 'equation', iconurl, params.group, this.display_chooser);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* If there is selected text and it is part of an equation,
|
||||
* extract the equation (and set it in the form).
|
||||
*
|
||||
* @method resolve_equation
|
||||
*/
|
||||
resolve_equation : function() {
|
||||
// Find the equation in the surrounding text.
|
||||
var selectednode = M.editor_atto.get_selection_parent_node(),
|
||||
text,
|
||||
equation;
|
||||
|
||||
// Note this is a document fragment and YUI doesn't like them.
|
||||
if (!selectednode) {
|
||||
return;
|
||||
}
|
||||
|
||||
text = Y.one(selectednode).get('text');
|
||||
// We use space or not space because . does not match new lines.
|
||||
pattern = /\$\$[\S\s]*\$\$/;
|
||||
equation = pattern.exec(text);
|
||||
if (equation && equation.length) {
|
||||
equation = equation.pop();
|
||||
// Replace the equation.
|
||||
equation = equation.substring(2, equation.length - 2);
|
||||
Y.one('#atto_equation_equation').set('text', equation);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* The OK button has been pressed - make the changes to the source.
|
||||
*
|
||||
* @method set_equation
|
||||
* @param {Y.Event} e
|
||||
* @param {String} elementid
|
||||
*/
|
||||
set_equation : function(e, elementid) {
|
||||
var input,
|
||||
selectednode,
|
||||
text,
|
||||
pattern,
|
||||
equation,
|
||||
value;
|
||||
|
||||
e.preventDefault();
|
||||
M.atto_equation.dialogue.hide();
|
||||
M.editor_atto.set_selection(M.atto_equation.selection);
|
||||
|
||||
input = e.currentTarget.ancestor('.atto_form').one('textarea');
|
||||
|
||||
value = input.get('value');
|
||||
if (value !== '') {
|
||||
value = '$$ ' + value.trim() + ' $$';
|
||||
selectednode = Y.one(M.editor_atto.get_selection_parent_node()),
|
||||
text = selectednode.get('text');
|
||||
pattern = /\$\$[\S\s]*\$\$/;
|
||||
equation = pattern.exec(text);
|
||||
if (equation && equation.length) {
|
||||
// Replace the equation.
|
||||
equation = equation.pop();
|
||||
text = text.replace(equation, '$$' + value + '$$');
|
||||
selectednode.set('text', text);
|
||||
} else {
|
||||
// Insert the new equation.
|
||||
if (document.selection && document.selection.createRange().pasteHTML) {
|
||||
document.selection.createRange().pasteHTML(value);
|
||||
} else {
|
||||
document.execCommand('insertHTML', false, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Clean the YUI ids from the HTML.
|
||||
M.editor_atto.text_updated(elementid);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the preview div to match the current equation.
|
||||
*
|
||||
* @param Event e - unused
|
||||
* @param String elementid - The editor elementid.
|
||||
* @method update_preview
|
||||
*/
|
||||
update_preview : function(e, elementid) {
|
||||
var textarea = Y.one('#atto_equation_equation');
|
||||
var equation = textarea.get('value'), url, preview;
|
||||
var prefix = '';
|
||||
var cursorlatex = '\\square ' ;
|
||||
|
||||
var currentpos = textarea.get('selectionStart');
|
||||
if (!currentpos) {
|
||||
currentpos = 0;
|
||||
}
|
||||
// Move the cursor so it does not break expressions.
|
||||
//
|
||||
while (equation.charAt(currentpos) === '\\' && currentpos > 0) {
|
||||
currentpos -= 1;
|
||||
}
|
||||
var ischar = /[\w\{\}]/;
|
||||
while (ischar.test(equation.charAt(currentpos)) && currentpos < equation.length) {
|
||||
currentpos += 1;
|
||||
}
|
||||
// Save the cursor position - for insertion from the library.
|
||||
this.lastcursorpos = currentpos;
|
||||
equation = prefix + equation.substring(0, currentpos) + cursorlatex + equation.substring(currentpos);
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
url = M.cfg.wwwroot + '/lib/editor/atto/plugins/equation/ajax.php';
|
||||
params = {
|
||||
sesskey: M.cfg.sesskey,
|
||||
contextid: this.contextids[elementid],
|
||||
action : 'filtertext',
|
||||
text : '$$ ' + equation + ' $$'
|
||||
};
|
||||
|
||||
|
||||
preview = Y.io(url, { sync: true,
|
||||
data: params });
|
||||
if (preview.status === 200) {
|
||||
Y.one('#atto_equation_preview').setHTML(preview.responseText);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the HTML of the form to show in the dialogue.
|
||||
*
|
||||
* @method get_form_content
|
||||
* @param string elementid
|
||||
* @return string
|
||||
*/
|
||||
get_form_content : function(elementid) {
|
||||
var content = Y.Node.create('<form class="atto_form">' +
|
||||
this.get_library_html(elementid) +
|
||||
'<label for="atto_equation_equation">' + M.util.get_string('editequation', 'atto_equation') +
|
||||
'</label>' +
|
||||
'<textarea class="fullwidth" id="atto_equation_equation" rows="8"></textarea><br/>' +
|
||||
'<p>' + M.util.get_string('editequation_desc', 'atto_equation') + '</p>' +
|
||||
'<label for="atto_equation_preview">' + M.util.get_string('preview', 'atto_equation') +
|
||||
'</label>' +
|
||||
'<div class="fullwidth" id="atto_equation_preview"></div>' +
|
||||
'<div class="mdl-align">' +
|
||||
'<br/>' +
|
||||
'<button id="atto_equation_submit">' +
|
||||
M.util.get_string('saveequation', 'atto_equation') +
|
||||
'</button>' +
|
||||
'</div>' +
|
||||
'</form>');
|
||||
|
||||
content.one('#atto_equation_submit').on('click', M.atto_equation.set_equation, this, elementid);
|
||||
content.one('#atto_equation_equation').on('valuechange', M.atto_equation.update_preview, this, elementid);
|
||||
content.one('#atto_equation_equation').on('keyup', M.atto_equation.update_preview, this, elementid);
|
||||
content.one('#atto_equation_equation').on('mouseup', M.atto_equation.update_preview, this, elementid);
|
||||
|
||||
content.delegate('click', M.atto_equation.select_library_item, '#atto_equation_library button', this, elementid);
|
||||
|
||||
return content;
|
||||
},
|
||||
|
||||
/**
|
||||
* Reponse to button presses in the tex library panels.
|
||||
*
|
||||
* @method select_library_item
|
||||
* @param Event event
|
||||
* @param string elementid
|
||||
* @return string
|
||||
*/
|
||||
select_library_item : function(event, elementid) {
|
||||
var tex = event.currentTarget.getAttribute('data-tex');
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
input = event.currentTarget.ancestor('.atto_form').one('textarea');
|
||||
|
||||
value = input.get('value');
|
||||
|
||||
value = value.substring(0, this.lastcursorpos) + tex + value.substring(this.lastcursorpos, value.length);
|
||||
|
||||
input.set('value', value);
|
||||
M.atto_equation.update_preview(false, elementid);
|
||||
input.focus();
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the HTML for rendering the library of predefined buttons.
|
||||
*
|
||||
* @method get_library_html
|
||||
* @param string elementid
|
||||
* @return string
|
||||
*/
|
||||
get_library_html : function(elementid) {
|
||||
var content = '<div id="atto_equation_library">', i = 0, group = 1;
|
||||
content += '<ul>';
|
||||
for (group = 1; group < 5; group++) {
|
||||
content += '<li><a href="#atto_equation_library' + group + '">' + M.util.get_string('librarygroup' + group, 'atto_equation') + '</a></li>';
|
||||
}
|
||||
content += '</ul>';
|
||||
content += '<div>';
|
||||
for (group = 1; group < 5; group++) {
|
||||
content += '<div id="atto_equation_library' + group + '">';
|
||||
var examples = this.library['group' + group].split("\n");
|
||||
for (i = 0; i < examples.length; i++) {
|
||||
if (examples[i]) {
|
||||
examples[i] = Y.Escape.html(examples[i]);
|
||||
content += '<button data-tex="' + examples[i] + '" title="' + examples[i] + '">$$' + examples[i] + '$$</button>';
|
||||
}
|
||||
}
|
||||
content += '</div>';
|
||||
}
|
||||
content += '</div>';
|
||||
content += '</div>';
|
||||
|
||||
var url = M.cfg.wwwroot + '/lib/editor/atto/plugins/equation/ajax.php';
|
||||
var params = {
|
||||
sesskey: M.cfg.sesskey,
|
||||
contextid: this.contextids[elementid],
|
||||
action : 'filtertext',
|
||||
text : content
|
||||
};
|
||||
|
||||
preview = Y.io(url, { sync: true, data: params, method: 'POST'});
|
||||
|
||||
if (preview.status === 200) {
|
||||
content = preview.responseText;
|
||||
}
|
||||
return content;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}, '@VERSION@', {"requires": ["node", "escape", "io", "event-valuechange", "tabview"]});
|
10
lib/editor/atto/plugins/equation/yui/src/button/build.json
Normal file
10
lib/editor/atto/plugins/equation/yui/src/button/build.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "moodle-atto_equation-button",
|
||||
"builds": {
|
||||
"moodle-atto_equation-button": {
|
||||
"jsfiles": [
|
||||
"button.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
360
lib/editor/atto/plugins/equation/yui/src/button/js/button.js
vendored
Normal file
360
lib/editor/atto/plugins/equation/yui/src/button/js/button.js
vendored
Normal file
@ -0,0 +1,360 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Atto text editor equation plugin.
|
||||
*
|
||||
* @package editor-atto
|
||||
* @copyright 2013 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
M.atto_equation = M.atto_equation || {
|
||||
/**
|
||||
* The window used to get the equation details.
|
||||
*
|
||||
* @property dialogue
|
||||
* @type M.core.dialogue
|
||||
* @default null
|
||||
*/
|
||||
dialogue : null,
|
||||
|
||||
/**
|
||||
* The selection object returned by the browser.
|
||||
*
|
||||
* @property selection
|
||||
* @type Range
|
||||
* @default null
|
||||
*/
|
||||
selection : null,
|
||||
|
||||
/**
|
||||
* A mapping of elementids to contextids.
|
||||
*
|
||||
* @property contextids
|
||||
* @type Object
|
||||
* @default {}
|
||||
*/
|
||||
contextids : {},
|
||||
|
||||
/**
|
||||
* A nested object containing a the configured list of tex examples.
|
||||
*
|
||||
* @property library
|
||||
* @type Object
|
||||
* @default {}
|
||||
*/
|
||||
library : {},
|
||||
|
||||
/**
|
||||
* The last cursor index in the source.
|
||||
*
|
||||
* @property lastcursor
|
||||
* @type Integer
|
||||
* @default 0
|
||||
*/
|
||||
lastcursor : 0,
|
||||
|
||||
/**
|
||||
* Display the chooser dialogue.
|
||||
*
|
||||
* @method display_chooser
|
||||
* @param Event e
|
||||
* @param string elementid
|
||||
*/
|
||||
display_chooser : function(e, elementid) {
|
||||
e.preventDefault();
|
||||
if (!M.editor_atto.is_active(elementid)) {
|
||||
M.editor_atto.focus(elementid);
|
||||
}
|
||||
M.atto_equation.selection = M.editor_atto.get_selection();
|
||||
if (M.atto_equation.selection !== false && (!M.atto_equation.selection.collapsed)) {
|
||||
var dialogue;
|
||||
if (!M.atto_equation.dialogue) {
|
||||
dialogue = new M.core.dialogue({
|
||||
visible: false,
|
||||
modal: true,
|
||||
close: true,
|
||||
draggable: true,
|
||||
width: '800px'
|
||||
});
|
||||
} else {
|
||||
dialogue = M.atto_equation.dialogue;
|
||||
}
|
||||
|
||||
dialogue.render();
|
||||
dialogue.set('bodyContent', M.atto_equation.get_form_content(elementid));
|
||||
dialogue.set('headerContent', M.util.get_string('pluginname', 'atto_equation'));
|
||||
|
||||
var tabview = new Y.TabView({
|
||||
srcNode: '#atto_equation_library'
|
||||
});
|
||||
|
||||
tabview.render();
|
||||
dialogue.show();
|
||||
M.atto_equation.resolve_equation();
|
||||
M.atto_equation.update_preview(false, elementid);
|
||||
M.atto_equation.dialogue = dialogue;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Add this button to the form.
|
||||
*
|
||||
* @method init
|
||||
* @param {Object} params
|
||||
*/
|
||||
init : function(params) {
|
||||
var iconurl = M.util.image_url('e/math', 'core');
|
||||
|
||||
if (params.texfilteractive) {
|
||||
// Save the elementid/contextid mapping.
|
||||
this.contextids[params.elementid] = params.contextid;
|
||||
// Save the button library.
|
||||
this.library = params.library;
|
||||
|
||||
// Add the button to the toolbar.
|
||||
M.editor_atto.add_toolbar_button(params.elementid, 'equation', iconurl, params.group, this.display_chooser);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* If there is selected text and it is part of an equation,
|
||||
* extract the equation (and set it in the form).
|
||||
*
|
||||
* @method resolve_equation
|
||||
*/
|
||||
resolve_equation : function() {
|
||||
// Find the equation in the surrounding text.
|
||||
var selectednode = M.editor_atto.get_selection_parent_node(),
|
||||
text,
|
||||
equation;
|
||||
|
||||
// Note this is a document fragment and YUI doesn't like them.
|
||||
if (!selectednode) {
|
||||
return;
|
||||
}
|
||||
|
||||
text = Y.one(selectednode).get('text');
|
||||
// We use space or not space because . does not match new lines.
|
||||
pattern = /\$\$[\S\s]*\$\$/;
|
||||
equation = pattern.exec(text);
|
||||
if (equation && equation.length) {
|
||||
equation = equation.pop();
|
||||
// Replace the equation.
|
||||
equation = equation.substring(2, equation.length - 2);
|
||||
Y.one('#atto_equation_equation').set('text', equation);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* The OK button has been pressed - make the changes to the source.
|
||||
*
|
||||
* @method set_equation
|
||||
* @param {Y.Event} e
|
||||
* @param {String} elementid
|
||||
*/
|
||||
set_equation : function(e, elementid) {
|
||||
var input,
|
||||
selectednode,
|
||||
text,
|
||||
pattern,
|
||||
equation,
|
||||
value;
|
||||
|
||||
e.preventDefault();
|
||||
M.atto_equation.dialogue.hide();
|
||||
M.editor_atto.set_selection(M.atto_equation.selection);
|
||||
|
||||
input = e.currentTarget.ancestor('.atto_form').one('textarea');
|
||||
|
||||
value = input.get('value');
|
||||
if (value !== '') {
|
||||
value = '$$ ' + value.trim() + ' $$';
|
||||
selectednode = Y.one(M.editor_atto.get_selection_parent_node()),
|
||||
text = selectednode.get('text');
|
||||
pattern = /\$\$[\S\s]*\$\$/;
|
||||
equation = pattern.exec(text);
|
||||
if (equation && equation.length) {
|
||||
// Replace the equation.
|
||||
equation = equation.pop();
|
||||
text = text.replace(equation, '$$' + value + '$$');
|
||||
selectednode.set('text', text);
|
||||
} else {
|
||||
// Insert the new equation.
|
||||
if (document.selection && document.selection.createRange().pasteHTML) {
|
||||
document.selection.createRange().pasteHTML(value);
|
||||
} else {
|
||||
document.execCommand('insertHTML', false, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Clean the YUI ids from the HTML.
|
||||
M.editor_atto.text_updated(elementid);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the preview div to match the current equation.
|
||||
*
|
||||
* @param Event e - unused
|
||||
* @param String elementid - The editor elementid.
|
||||
* @method update_preview
|
||||
*/
|
||||
update_preview : function(e, elementid) {
|
||||
var textarea = Y.one('#atto_equation_equation');
|
||||
var equation = textarea.get('value'), url, preview;
|
||||
var prefix = '';
|
||||
var cursorlatex = '\\square ' ;
|
||||
|
||||
var currentpos = textarea.get('selectionStart');
|
||||
if (!currentpos) {
|
||||
currentpos = 0;
|
||||
}
|
||||
// Move the cursor so it does not break expressions.
|
||||
//
|
||||
while (equation.charAt(currentpos) === '\\' && currentpos > 0) {
|
||||
currentpos -= 1;
|
||||
}
|
||||
var ischar = /[\w\{\}]/;
|
||||
while (ischar.test(equation.charAt(currentpos)) && currentpos < equation.length) {
|
||||
currentpos += 1;
|
||||
}
|
||||
// Save the cursor position - for insertion from the library.
|
||||
this.lastcursorpos = currentpos;
|
||||
equation = prefix + equation.substring(0, currentpos) + cursorlatex + equation.substring(currentpos);
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
url = M.cfg.wwwroot + '/lib/editor/atto/plugins/equation/ajax.php';
|
||||
params = {
|
||||
sesskey: M.cfg.sesskey,
|
||||
contextid: this.contextids[elementid],
|
||||
action : 'filtertext',
|
||||
text : '$$ ' + equation + ' $$'
|
||||
};
|
||||
|
||||
|
||||
preview = Y.io(url, { sync: true,
|
||||
data: params });
|
||||
if (preview.status === 200) {
|
||||
Y.one('#atto_equation_preview').setHTML(preview.responseText);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the HTML of the form to show in the dialogue.
|
||||
*
|
||||
* @method get_form_content
|
||||
* @param string elementid
|
||||
* @return string
|
||||
*/
|
||||
get_form_content : function(elementid) {
|
||||
var content = Y.Node.create('<form class="atto_form">' +
|
||||
this.get_library_html(elementid) +
|
||||
'<label for="atto_equation_equation">' + M.util.get_string('editequation', 'atto_equation') +
|
||||
'</label>' +
|
||||
'<textarea class="fullwidth" id="atto_equation_equation" rows="8"></textarea><br/>' +
|
||||
'<p>' + M.util.get_string('editequation_desc', 'atto_equation') + '</p>' +
|
||||
'<label for="atto_equation_preview">' + M.util.get_string('preview', 'atto_equation') +
|
||||
'</label>' +
|
||||
'<div class="fullwidth" id="atto_equation_preview"></div>' +
|
||||
'<div class="mdl-align">' +
|
||||
'<br/>' +
|
||||
'<button id="atto_equation_submit">' +
|
||||
M.util.get_string('saveequation', 'atto_equation') +
|
||||
'</button>' +
|
||||
'</div>' +
|
||||
'</form>');
|
||||
|
||||
content.one('#atto_equation_submit').on('click', M.atto_equation.set_equation, this, elementid);
|
||||
content.one('#atto_equation_equation').on('valuechange', M.atto_equation.update_preview, this, elementid);
|
||||
content.one('#atto_equation_equation').on('keyup', M.atto_equation.update_preview, this, elementid);
|
||||
content.one('#atto_equation_equation').on('mouseup', M.atto_equation.update_preview, this, elementid);
|
||||
|
||||
content.delegate('click', M.atto_equation.select_library_item, '#atto_equation_library button', this, elementid);
|
||||
|
||||
return content;
|
||||
},
|
||||
|
||||
/**
|
||||
* Reponse to button presses in the tex library panels.
|
||||
*
|
||||
* @method select_library_item
|
||||
* @param Event event
|
||||
* @param string elementid
|
||||
* @return string
|
||||
*/
|
||||
select_library_item : function(event, elementid) {
|
||||
var tex = event.currentTarget.getAttribute('data-tex');
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
input = event.currentTarget.ancestor('.atto_form').one('textarea');
|
||||
|
||||
value = input.get('value');
|
||||
|
||||
value = value.substring(0, this.lastcursorpos) + tex + value.substring(this.lastcursorpos, value.length);
|
||||
|
||||
input.set('value', value);
|
||||
M.atto_equation.update_preview(false, elementid);
|
||||
input.focus();
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the HTML for rendering the library of predefined buttons.
|
||||
*
|
||||
* @method get_library_html
|
||||
* @param string elementid
|
||||
* @return string
|
||||
*/
|
||||
get_library_html : function(elementid) {
|
||||
var content = '<div id="atto_equation_library">', i = 0, group = 1;
|
||||
content += '<ul>';
|
||||
for (group = 1; group < 5; group++) {
|
||||
content += '<li><a href="#atto_equation_library' + group + '">' + M.util.get_string('librarygroup' + group, 'atto_equation') + '</a></li>';
|
||||
}
|
||||
content += '</ul>';
|
||||
content += '<div>';
|
||||
for (group = 1; group < 5; group++) {
|
||||
content += '<div id="atto_equation_library' + group + '">';
|
||||
var examples = this.library['group' + group].split("\n");
|
||||
for (i = 0; i < examples.length; i++) {
|
||||
if (examples[i]) {
|
||||
examples[i] = Y.Escape.html(examples[i]);
|
||||
content += '<button data-tex="' + examples[i] + '" title="' + examples[i] + '">$$' + examples[i] + '$$</button>';
|
||||
}
|
||||
}
|
||||
content += '</div>';
|
||||
}
|
||||
content += '</div>';
|
||||
content += '</div>';
|
||||
|
||||
var url = M.cfg.wwwroot + '/lib/editor/atto/plugins/equation/ajax.php';
|
||||
var params = {
|
||||
sesskey: M.cfg.sesskey,
|
||||
contextid: this.contextids[elementid],
|
||||
action : 'filtertext',
|
||||
text : content
|
||||
};
|
||||
|
||||
preview = Y.io(url, { sync: true, data: params, method: 'POST'});
|
||||
|
||||
if (preview.status === 200) {
|
||||
content = preview.responseText;
|
||||
}
|
||||
return content;
|
||||
}
|
||||
};
|
@ -0,0 +1,11 @@
|
||||
{
|
||||
"moodle-atto_equation-button": {
|
||||
"requires": [
|
||||
"node",
|
||||
"escape",
|
||||
"io",
|
||||
"event-valuechange",
|
||||
"tabview"
|
||||
]
|
||||
}
|
||||
}
|
@ -37,7 +37,7 @@ if ($ADMIN->fulltree) {
|
||||
'files = image, media, managefiles' . "\n" .
|
||||
'style2 = underline, strike, subscript, superscript' . "\n" .
|
||||
'indent = indent, outdent' . "\n" .
|
||||
'insert = charmap, table, clear' . "\n" .
|
||||
'insert = equation, charmap, table, clear' . "\n" .
|
||||
'accessibility = accessibilitychecker, accessibilityhelper' . "\n" .
|
||||
'other = html';
|
||||
$setting = new admin_setting_configtextarea('editor_atto/toolbar',
|
||||
@ -46,7 +46,6 @@ if ($ADMIN->fulltree) {
|
||||
$default);
|
||||
|
||||
$settings->add($setting);
|
||||
|
||||
}
|
||||
$ADMIN->add('editoratto', $settings);
|
||||
|
||||
@ -58,3 +57,4 @@ foreach (core_plugin_manager::instance()->get_plugins_of_type('atto') as $plugin
|
||||
// Required or the editor plugininfo will add this section twice.
|
||||
unset($settings);
|
||||
$settings = null;
|
||||
|
||||
|
Before Width: | Height: | Size: 373 B After Width: | Height: | Size: 373 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Loading…
x
Reference in New Issue
Block a user