Merge branch 'MDL-45207-master' of git://github.com/andrewnicols/moodle
[moodle.git] / lib / editor / atto / plugins / equation / yui / src / button / js / button.js
CommitLineData
8bf5ad67
DW
1// This file is part of Moodle - http://moodle.org/
2//
3// Moodle is free software: you can redistribute it and/or modify
4// it under the terms of the GNU General Public License as published by
5// the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// Moodle is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU General Public License
14// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
15
16/**
62467795 17 * @package atto_equation
8bf5ad67
DW
18 * @copyright 2013 Damyon Wiese <damyon@moodle.com>
19 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
20 */
62467795
AN
21
22/**
23 * Atto text editor equation plugin.
24 */
25
26/**
27 * Atto equation editor.
28 *
29 * @namespace M.atto_equation
30 * @class Button
31 * @extends M.editor_atto.EditorPlugin
32 */
33
34var COMPONENTNAME = 'atto_equation',
050159dc 35 LOGNAME = 'atto_equation',
62467795
AN
36 CSS = {
37 EQUATION_TEXT: 'atto_equation_equation',
38 EQUATION_PREVIEW: 'atto_equation_preview',
39 SUBMIT: 'atto_equation_submit',
40 LIBRARY: 'atto_equation_library',
050159dc
FM
41 LIBRARY_GROUPS: 'atto_equation_groups',
42 LIBRARY_GROUP_PREFIX: 'atto_equation_group'
62467795
AN
43 },
44 SELECTORS = {
050159dc
FM
45 LIBRARY: '.' + CSS.LIBRARY,
46 LIBRARY_GROUP: '.' + CSS.LIBRARY_GROUPS + ' > div > div',
62467795
AN
47 EQUATION_TEXT: '.' + CSS.EQUATION_TEXT,
48 EQUATION_PREVIEW: '.' + CSS.EQUATION_PREVIEW,
49 SUBMIT: '.' + CSS.SUBMIT,
50 LIBRARY_BUTTON: '.' + CSS.LIBRARY + ' button'
51 },
cc90cedc
DW
52 DELIMITERS = {
53 START: '\\(',
54 END: '\\)'
55 },
62467795
AN
56 TEMPLATES = {
57 FORM: '' +
58 '<form class="atto_form">' +
59 '{{{library}}}' +
36beb828 60 '<label for="{{elementid}}_{{CSS.EQUATION_TEXT}}">{{{get_string "editequation" component texdocsurl}}}</label>' +
62467795 61 '<textarea class="fullwidth {{CSS.EQUATION_TEXT}}" id="{{elementid}}_{{CSS.EQUATION_TEXT}}" rows="8"></textarea><br/>' +
62467795 62 '<label for="{{elementid}}_{{CSS.EQUATION_PREVIEW}}">{{get_string "preview" component}}</label>' +
fcc19a2f 63 '<div class="well well-small fullwidth {{CSS.EQUATION_PREVIEW}}" id="{{elementid}}_{{CSS.EQUATION_PREVIEW}}"></div>' +
62467795
AN
64 '<div class="mdl-align">' +
65 '<br/>' +
66 '<button class="{{CSS.SUBMIT}}">{{get_string "saveequation" component}}</button>' +
67 '</div>' +
68 '</form>',
69 LIBRARY: '' +
70 '<div class="{{CSS.LIBRARY}}">' +
71 '<ul>' +
72 '{{#each library}}' +
050159dc
FM
73 '<li><a href="#{{../elementid}}_{{../CSS.LIBRARY_GROUP_PREFIX}}_{{@key}}">' +
74 '{{get_string groupname ../component}}' +
75 '</a></li>' +
62467795
AN
76 '{{/each}}' +
77 '</ul>' +
050159dc 78 '<div class="{{CSS.LIBRARY_GROUPS}}">' +
62467795 79 '{{#each library}}' +
050159dc
FM
80 '<div id="{{../elementid}}_{{../CSS.LIBRARY_GROUP_PREFIX}}_{{@key}}">' +
81 '<div role="toolbar">' +
82 '{{#split "\n" elements}}' +
0610d2ca
DW
83 '<button tabindex="-1" data-tex="{{this}}" aria-label="{{this}}" title="{{this}}">' +
84 '{{../../DELIMITERS.START}}{{this}}{{../../DELIMITERS.END}}' +
85 '</button>' +
050159dc
FM
86 '{{/split}}' +
87 '</div>' +
62467795
AN
88 '</div>' +
89 '{{/each}}' +
90 '</div>' +
91 '</div>'
92 };
93
94Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], {
8bf5ad67
DW
95
96 /**
97 * The selection object returned by the browser.
98 *
62467795 99 * @property _currentSelection
8bf5ad67
DW
100 * @type Range
101 * @default null
62467795 102 * @private
8bf5ad67 103 */
62467795 104 _currentSelection: null,
8bf5ad67
DW
105
106 /**
62467795 107 * The cursor position in the equation textarea.
8bf5ad67 108 *
62467795
AN
109 * @property _lastCursorPos
110 * @type Number
8bf5ad67 111 * @default 0
62467795 112 * @private
8bf5ad67 113 */
62467795 114 _lastCursorPos: 0,
8bf5ad67
DW
115
116 /**
62467795 117 * A reference to the dialogue content.
8bf5ad67 118 *
62467795
AN
119 * @property _content
120 * @type Node
121 * @private
8bf5ad67 122 */
62467795 123 _content: null,
8bf5ad67 124
cc90cedc
DW
125 /**
126 * The source equation we are editing in the text.
127 *
128 * @property _sourceEquation
ea382dea 129 * @type Object
cc90cedc
DW
130 * @private
131 */
ea382dea 132 _sourceEquation: null,
cc90cedc 133
050159dc
FM
134 /**
135 * A reference to the tab focus set on each group.
136 *
137 * The keys are the IDs of the group, the value is the Node on which the focus is set.
138 *
139 * @property _groupFocus
140 * @type Object
141 * @private
142 */
143 _groupFocus: null,
144
ea382dea
AN
145 /**
146 * Regular Expression patterns used to pick out the equations in a String.
147 *
148 * @property _equationPatterns
149 * @type Array
150 * @private
151 */
152 _equationPatterns: [
153 // We use space or not space because . does not match new lines.
154 // $$ blah $$.
155 /\$\$([\S\s]+?)\$\$/,
156 // E.g. "\( blah \)".
157 /\\\(([\S\s]+?)\\\)/,
158 // E.g. "\[ blah \]".
159 /\\\[([\S\s]+?)\\\]/,
160 // E.g. "[tex] blah [/tex]".
161 /\[tex\]([\S\s]+?)\[\/tex\]/
162 ],
163
62467795 164 initializer: function() {
050159dc 165 this._groupFocus = {};
0610d2ca 166
cc90cedc
DW
167 // If there is a tex filter active - enable this button.
168 if (this.get('texfilteractive')) {
62467795
AN
169 // Add the button to the toolbar.
170 this.addButton({
171 icon: 'e/math',
172 callback: this._displayDialogue
8bf5ad67
DW
173 });
174
62467795
AN
175 // We need custom highlight logic for this button.
176 this.get('host').on('atto:selectionchanged', function() {
177 if (this._resolveEquation()) {
178 this.highlightButtons();
179 } else {
180 this.unHighlightButtons();
181 }
182 }, this);
cc90cedc
DW
183
184 // We need to convert these to a non dom node based format.
185 this.editor.all('tex').each(function (texNode) {
186 var replacement = Y.Node.create('<span>' + DELIMITERS.START + ' ' + texNode.get('text') + ' ' + DELIMITERS.END + '</span>');
187 texNode.replace(replacement);
188 });
8bf5ad67 189 }
cc90cedc 190
8bf5ad67
DW
191 },
192
193 /**
62467795 194 * Display the equation editor.
8bf5ad67 195 *
62467795
AN
196 * @method _displayDialogue
197 * @private
8bf5ad67 198 */
62467795
AN
199 _displayDialogue: function() {
200 this._currentSelection = this.get('host').getSelection();
8bf5ad67 201
62467795
AN
202 if (this._currentSelection === false) {
203 return;
204 }
8bf5ad67 205
62467795
AN
206 var dialogue = this.getDialogue({
207 headerContent: M.util.get_string('pluginname', COMPONENTNAME),
1eb5839c
FM
208 focusAfterHide: true,
209 width: 600
62467795
AN
210 });
211
212 var content = this._getDialogueContent();
213 dialogue.set('bodyContent', content);
214
050159dc 215 var library = content.one(SELECTORS.LIBRARY);
62467795
AN
216
217 var tabview = new Y.TabView({
218 srcNode: library
219 });
220
221 tabview.render();
222 dialogue.show();
cc90cedc
DW
223 // Trigger any JS filters to reprocess the new nodes.
224 Y.fire(M.core.event.FILTER_CONTENT_UPDATED, {nodes: (new Y.NodeList(dialogue.get('boundingBox')))});
62467795
AN
225
226 var equation = this._resolveEquation();
227 if (equation) {
228 content.one(SELECTORS.EQUATION_TEXT).set('text', equation);
8bf5ad67 229 }
62467795 230 this._updatePreview(false);
8bf5ad67
DW
231 },
232
233 /**
234 * If there is selected text and it is part of an equation,
235 * extract the equation (and set it in the form).
236 *
62467795
AN
237 * @method _resolveEquation
238 * @private
3ee53a42 239 * @return {String|Boolean} The equation or false.
8bf5ad67 240 */
62467795
AN
241 _resolveEquation: function() {
242
8bf5ad67 243 // Find the equation in the surrounding text.
62467795 244 var selectedNode = this.get('host').getSelectionParentNode(),
ea382dea 245 selection = this.get('host').getSelection(),
8bf5ad67 246 text,
ea382dea
AN
247 returnValue = false;
248
249 this.sourceEquation = null;
8bf5ad67
DW
250
251 // Note this is a document fragment and YUI doesn't like them.
62467795 252 if (!selectedNode) {
3ee53a42 253 return false;
8bf5ad67
DW
254 }
255
ea382dea
AN
256 // We don't yet have a cursor selection somehow so we can't possible be resolving an equation that has selection.
257 if (!selection || selection.length === 0) {
258 return false;
259 }
260 selection = selection[0];
cc90cedc 261
ea382dea 262 text = Y.one(selectedNode).get('text');
cc90cedc 263
ea382dea
AN
264 // For each of these patterns we have a RegExp which captures the inner component of the equation but also includes the delimiters.
265 // We first run the RegExp adding the global flag ("g"). This ignores the capture, instead matching the entire
266 // equation including delimiters and returning one entry per match of the whole equation.
267 // We have to deal with multiple occurences of the same equation in a String so must be able to loop on the
268 // match results.
269 Y.Array.find(this._equationPatterns, function(pattern) {
270 // For each pattern in turn, find all whole matches (including the delimiters).
271 var patternMatches = text.match(new RegExp(pattern.source, "g"));
272
273 if (patternMatches && patternMatches.length) {
274 // This pattern matches at least once. See if this pattern matches our current position.
275 // Note: We return here to break the Y.Array.find loop - any truthy return will stop any subsequent
276 // searches which is the required behaviour of this function.
277 return Y.Array.find(patternMatches, function(match) {
278 // Check each occurrence of this match.
279 var startIndex = 0;
280 while(text.indexOf(match, startIndex) !== -1) {
281 // Determine whether the cursor is in the current occurrence of this string.
282 // Note: We do not support a selection exceeding the bounds of an equation.
283 var startOuter = text.indexOf(match, startIndex),
284 endOuter = startOuter + match.length,
285 startMatch = (selection.startOffset >= startOuter && selection.startOffset < endOuter),
286 endMatch = (selection.endOffset <= endOuter && selection.endOffset > startOuter);
287
288 if (startMatch && endMatch) {
289 // This match is in our current position - fetch the innerMatch data.
290 var innerMatch = match.match(pattern);
291 if (innerMatch && innerMatch.length) {
292 // We need the start and end of the inner match for later.
293 var startInner = text.indexOf(innerMatch[1], startOuter),
294 endInner = startInner + innerMatch[1].length;
295
296 // We'll be returning the inner match for use in the editor itself.
297 returnValue = innerMatch[1];
298
299 // Save all data for later.
300 this.sourceEquation = {
301 // Outer match data.
302 startOuterPosition: startOuter,
303 endOuterPosition: endOuter,
304 outerMatch: match,
305
306 // Inner match data.
307 startInnerPosition: startInner,
308 endInnerPosition: endInner,
309 innerMatch: innerMatch
310 };
311
312 // This breaks out of both Y.Array.find functions.
313 return true;
314 }
315 }
316
317 // Update the startIndex to match the end of the current match so that we can continue hunting
318 // for further matches.
319 startIndex = endOuter;
320 }
321 }, this);
cc90cedc 322 }
ea382dea 323 }, this);
cc90cedc 324
ea382dea 325 return returnValue;
8bf5ad67
DW
326 },
327
328 /**
62467795 329 * Handle insertion of a new equation, or update of an existing one.
8bf5ad67 330 *
62467795
AN
331 * @method _setEquation
332 * @param {EventFacade} e
333 * @private
8bf5ad67 334 */
62467795 335 _setEquation: function(e) {
8bf5ad67 336 var input,
62467795 337 selectedNode,
8bf5ad67 338 text,
cc90cedc
DW
339 value,
340 host;
8bf5ad67 341
cc90cedc 342 host = this.get('host');
62467795 343
8bf5ad67 344 e.preventDefault();
62467795
AN
345 this.getDialogue({
346 focusAfterHide: null
347 }).hide();
8bf5ad67
DW
348
349 input = e.currentTarget.ancestor('.atto_form').one('textarea');
350
351 value = input.get('value');
352 if (value !== '') {
62467795
AN
353 host.setSelection(this._currentSelection);
354
ea382dea 355 if (this.sourceEquation) {
8bf5ad67 356 // Replace the equation.
cc90cedc
DW
357 selectedNode = Y.one(host.getSelectionParentNode());
358 text = selectedNode.get('text');
ea382dea
AN
359 newText = text.slice(0, this.sourceEquation.startInnerPosition) +
360 value +
361 text.slice(this.sourceEquation.endInnerPosition);
cc90cedc 362
ea382dea 363 selectedNode.set('text', newText);
8bf5ad67
DW
364 } else {
365 // Insert the new equation.
cc90cedc 366 value = DELIMITERS.START + ' ' + value + ' ' + DELIMITERS.END;
62467795 367 host.insertContentAtFocusPoint(value);
8bf5ad67
DW
368 }
369
370 // Clean the YUI ids from the HTML.
62467795 371 this.markUpdated();
8bf5ad67
DW
372 }
373 },
374
cc90cedc
DW
375 /**
376 * Smart throttle, only call a function every delay milli seconds,
441f94b2
DW
377 * and always run the last call. Y.throttle does not work here,
378 * because it calls the function immediately, the first time, and then
379 * ignores repeated calls within X seconds. This does not guarantee
380 * that the last call will be executed (which is required here).
cc90cedc
DW
381 *
382 * @param {function} fn
441f94b2 383 * @param {Number} delay Delay in milliseconds
cc90cedc
DW
384 * @method _throttle
385 * @private
386 */
387 _throttle: function(fn, delay) {
388 var timer = null;
389 return function () {
390 var context = this, args = arguments;
391 clearTimeout(timer);
392 timer = setTimeout(function () {
393 fn.apply(context, args);
394 }, delay);
395 };
396 },
397
8bf5ad67
DW
398 /**
399 * Update the preview div to match the current equation.
400 *
62467795
AN
401 * @param {EventFacade} e
402 * @method _updatePreview
403 * @private
8bf5ad67 404 */
62467795
AN
405 _updatePreview: function(e) {
406 var textarea = this._content.one(SELECTORS.EQUATION_TEXT),
407 equation = textarea.get('value'),
408 url,
409 preview,
410 currentPos = textarea.get('selectionStart'),
411 prefix = '',
412 cursorLatex = '\\square ',
441f94b2
DW
413 isChar,
414 params;
62467795 415
62467795
AN
416 if (e) {
417 e.preventDefault();
418 }
419
420 if (!currentPos) {
421 currentPos = 0;
8bf5ad67
DW
422 }
423 // Move the cursor so it does not break expressions.
424 //
62467795
AN
425 while (equation.charAt(currentPos) === '\\' && currentPos > 0) {
426 currentPos -= 1;
8bf5ad67 427 }
cc90cedc 428 isChar = /[a-zA-Z\{\}]/;
62467795
AN
429 while (isChar.test(equation.charAt(currentPos)) && currentPos < equation.length) {
430 currentPos += 1;
8bf5ad67
DW
431 }
432 // Save the cursor position - for insertion from the library.
62467795
AN
433 this._lastCursorPos = currentPos;
434 equation = prefix + equation.substring(0, currentPos) + cursorLatex + equation.substring(currentPos);
8939ebac
DW
435
436 var previewNode = this._content.one(SELECTORS.EQUATION_PREVIEW);
cc90cedc
DW
437 equation = DELIMITERS.START + ' ' + equation + ' ' + DELIMITERS.END;
438 // Make an ajax request to the filter.
439 url = M.cfg.wwwroot + '/lib/editor/atto/plugins/equation/ajax.php';
440 params = {
441 sesskey: M.cfg.sesskey,
442 contextid: this.get('contextid'),
443 action: 'filtertext',
444 text: equation
445 };
446
441f94b2
DW
447 preview = Y.io(url, {
448 sync: true,
449 data: params
450 });
451
cc90cedc
DW
452 if (preview.status === 200) {
453 previewNode.setHTML(preview.responseText);
454 Y.fire(M.core.event.FILTER_CONTENT_UPDATED, {nodes: (new Y.NodeList(previewNode))});
8bf5ad67
DW
455 }
456 },
457
458 /**
62467795
AN
459 * Return the dialogue content for the tool, attaching any required
460 * events.
8bf5ad67 461 *
62467795
AN
462 * @method _getDialogueContent
463 * @return {Node}
464 * @private
8bf5ad67 465 */
62467795
AN
466 _getDialogueContent: function() {
467 var library = this._getLibraryContent(),
468 template = Y.Handlebars.compile(TEMPLATES.FORM);
469
470 this._content = Y.Node.create(template({
471 elementid: this.get('host').get('elementid'),
472 component: COMPONENTNAME,
473 library: library,
36beb828 474 texdocsurl: this.get('texdocsurl'),
62467795
AN
475 CSS: CSS
476 }));
477
050159dc
FM
478 // Sets the default focus.
479 this._content.all(SELECTORS.LIBRARY_GROUP).each(function(group) {
480 // The first button gets the focus.
481 this._setGroupTabFocus(group, group.one('button'));
482 // Sometimes the filter adds an anchor in the button, no tabindex on that.
483 group.all('button a').setAttribute('tabindex', '-1');
484 }, this);
485
486 // Keyboard navigation in groups.
487 this._content.delegate('key', this._groupNavigation, 'down:37,39', SELECTORS.LIBRARY_BUTTON, this);
488
62467795 489 this._content.one(SELECTORS.SUBMIT).on('click', this._setEquation, this);
cc90cedc
DW
490 this._content.one(SELECTORS.EQUATION_TEXT).on('valuechange', this._throttle(this._updatePreview, 500), this);
491 this._content.one(SELECTORS.EQUATION_TEXT).on('mouseup', this._throttle(this._updatePreview, 500), this);
492 this._content.one(SELECTORS.EQUATION_TEXT).on('keyup', this._throttle(this._updatePreview, 500), this);
62467795
AN
493 this._content.delegate('click', this._selectLibraryItem, SELECTORS.LIBRARY_BUTTON, this);
494
495 return this._content;
8bf5ad67
DW
496 },
497
050159dc
FM
498 /**
499 * Callback handling the keyboard navigation in the groups of the library.
500 *
501 * @param {EventFacade} e The event.
502 * @method _groupNavigation
503 * @private
504 */
505 _groupNavigation: function(e) {
506 e.preventDefault();
507
508 var current = e.currentTarget,
509 parent = current.get('parentNode'), // This must be the <div> containing all the buttons of the group.
510 buttons = parent.all('button'),
511 direction = e.keyCode !== 37 ? 1 : -1,
512 index = buttons.indexOf(current),
513 nextButton;
514
515 if (index < 0) {
516 Y.log('Unable to find the current button in the list of buttons', 'debug', LOGNAME);
517 index = 0;
518 }
519
520 index += direction;
521 if (index < 0) {
522 index = buttons.size() - 1;
523 } else if (index >= buttons.size()) {
524 index = 0;
525 }
526 nextButton = buttons.item(index);
527
528 this._setGroupTabFocus(parent, nextButton);
529 nextButton.focus();
530 },
531
532 /**
533 * Sets tab focus for the group.
534 *
535 * @method _setGroupTabFocus
536 * @param {Node} button The node that focus should now be set to.
537 * @private
538 */
539 _setGroupTabFocus: function(parent, button) {
540 var parentId = parent.generateID();
541
542 // Unset the previous entry.
543 if (typeof this._groupFocus[parentId] !== 'undefined') {
544 this._groupFocus[parentId].setAttribute('tabindex', '-1');
545 }
546
547 // Set on the new entry.
548 this._groupFocus[parentId] = button;
549 button.setAttribute('tabindex', 0);
550 parent.setAttribute('aria-activedescendant', button.generateID());
551 },
552
8bf5ad67 553 /**
62467795 554 * Reponse to button presses in the TeX library panels.
8bf5ad67 555 *
62467795
AN
556 * @method _selectLibraryItem
557 * @param {EventFacade} e
558 * @return {string}
559 * @private
8bf5ad67 560 */
62467795
AN
561 _selectLibraryItem: function(e) {
562 var tex = e.currentTarget.getAttribute('data-tex');
8bf5ad67 563
62467795 564 e.preventDefault();
8bf5ad67 565
050159dc
FM
566 // Set the group focus on the button.
567 this._setGroupTabFocus(e.currentTarget.get('parentNode'), e.currentTarget);
568
62467795 569 input = e.currentTarget.ancestor('.atto_form').one('textarea');
8bf5ad67
DW
570
571 value = input.get('value');
572
62467795 573 value = value.substring(0, this._lastCursorPos) + tex + value.substring(this._lastCursorPos, value.length);
8bf5ad67
DW
574
575 input.set('value', value);
8bf5ad67 576 input.focus();
9ee8a359 577
62467795 578 var focusPoint = this._lastCursorPos + tex.length,
9ee8a359
AN
579 realInput = input.getDOMNode();
580 if (typeof realInput.selectionStart === "number") {
581 // Modern browsers have selectionStart and selectionEnd to control the cursor position.
582 realInput.selectionStart = realInput.selectionEnd = focusPoint;
583 } else if (typeof realInput.createTextRange !== "undefined") {
584 // Legacy browsers (IE<=9) use createTextRange().
585 var range = realInput.createTextRange();
586 range.moveToPoint(focusPoint);
587 range.select();
588 }
589 // Focus must be set before updating the preview for the cursor box to be in the correct location.
62467795 590 this._updatePreview(false);
8bf5ad67
DW
591 },
592
593 /**
594 * Return the HTML for rendering the library of predefined buttons.
595 *
62467795
AN
596 * @method _getLibraryContent
597 * @return {string}
598 * @private
8bf5ad67 599 */
62467795
AN
600 _getLibraryContent: function() {
601 var template = Y.Handlebars.compile(TEMPLATES.LIBRARY),
602 library = this.get('library'),
603 content = '';
604
605 // Helper to iterate over a newline separated string.
606 Y.Handlebars.registerHelper('split', function(delimiter, str, options) {
607 var parts,
608 current,
609 out;
610 if (typeof delimiter === "undefined" || typeof str === "undefined") {
611 Y.log('Handlebars split helper: String and delimiter are required.', 'debug', 'moodle-atto_equation-button');
612 return '';
8bf5ad67 613 }
62467795
AN
614
615 out = '';
616 parts = str.trim().split(delimiter);
617 while (parts.length > 0) {
cc90cedc 618 current = parts.shift().trim();
62467795
AN
619 out += options.fn(current);
620 }
621
622 return out;
623 });
624 content = template({
625 elementid: this.get('host').get('elementid'),
626 component: COMPONENTNAME,
627 library: library,
cc90cedc
DW
628 CSS: CSS,
629 DELIMITERS: DELIMITERS
62467795 630 });
8bf5ad67 631
cc90cedc
DW
632 var url = M.cfg.wwwroot + '/lib/editor/atto/plugins/equation/ajax.php';
633 var params = {
634 sesskey: M.cfg.sesskey,
635 contextid: this.get('contextid'),
636 action: 'filtertext',
637 text: content
638 };
639
640 preview = Y.io(url, {
641 sync: true,
642 data: params,
643 method: 'POST'
644 });
8bf5ad67 645
cc90cedc
DW
646 if (preview.status === 200) {
647 content = preview.responseText;
8bf5ad67
DW
648 }
649 return content;
650 }
62467795
AN
651}, {
652 ATTRS: {
653 /**
654 * Whether the TeX filter is currently active.
655 *
656 * @attribute texfilteractive
657 * @type Boolean
658 */
659 texfilteractive: {
660 value: false
661 },
cc90cedc 662
62467795
AN
663 /**
664 * The contextid to use when generating this preview.
665 *
666 * @attribute contextid
667 * @type String
668 */
669 contextid: {
670 value: null
671 },
672
673 /**
674 * The content of the example library.
675 *
676 * @attribute library
677 * @type object
678 */
679 library: {
680 value: {}
36beb828
FM
681 },
682
683 /**
684 * The link to the Moodle Docs page about TeX.
685 *
686 * @attribute texdocsurl
687 * @type string
688 */
689 texdocsurl: {
690 value: null
62467795 691 }
cc90cedc 692
62467795
AN
693 }
694});