diff --git a/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-debug.js b/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-debug.js
index fa1adb2c69b..2392b18b7a7 100644
--- a/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-debug.js
+++ b/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-debug.js
@@ -128,10 +128,10 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto.
* The source equation we are editing in the text.
*
* @property _sourceEquation
- * @type String
+ * @type Object
* @private
*/
- _sourceEquation: '',
+ _sourceEquation: null,
/**
* A reference to the tab focus set on each group.
@@ -144,6 +144,25 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto.
*/
_groupFocus: null,
+ /**
+ * Regular Expression patterns used to pick out the equations in a String.
+ *
+ * @property _equationPatterns
+ * @type Array
+ * @private
+ */
+ _equationPatterns: [
+ // We use space or not space because . does not match new lines.
+ // $$ blah $$.
+ /\$\$([\S\s]+?)\$\$/,
+ // E.g. "\( blah \)".
+ /\\\(([\S\s]+?)\\\)/,
+ // E.g. "\[ blah \]".
+ /\\\[([\S\s]+?)\\\]/,
+ // E.g. "[tex] blah [/tex]".
+ /\[tex\]([\S\s]+?)\[\/tex\]/
+ ],
+
initializer: function() {
this._groupFocus = {};
@@ -225,39 +244,87 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto.
// Find the equation in the surrounding text.
var selectedNode = this.get('host').getSelectionParentNode(),
+ selection = this.get('host').getSelection(),
text,
- equation,
- patterns = [], i;
+ returnValue = false;
+
+ this.sourceEquation = null;
// Note this is a document fragment and YUI doesn't like them.
if (!selectedNode) {
return false;
}
- text = Y.one(selectedNode).get('text');
- // We use space or not space because . does not match new lines.
- // $$ blah $$.
- patterns.push(/\$\$([\S\s]*)\$\$/);
- // E.g. "\( blah \)".
- patterns.push(/\\\(([\S\s]*)\\\)/);
- // E.g. "\[ blah \]".
- patterns.push(/\\\[([\S\s]*)\\\]/);
- // E.g. "[tex] blah [/tex]".
- patterns.push(/\[tex\]([\S\s]*)\[\/tex\]/);
-
- for (i = 0; i < patterns.length; i++) {
- pattern = patterns[i];
- equation = pattern.exec(text);
- if (equation && equation.length) {
- // Remember the inner match so we can replace it later.
- this.sourceEquation = equation = equation[1];
-
- return equation;
- }
+ // We don't yet have a cursor selection somehow so we can't possible be resolving an equation that has selection.
+ if (!selection || selection.length === 0) {
+ return false;
}
+ selection = selection[0];
- this.sourceEquation = '';
- return false;
+ text = Y.one(selectedNode).get('text');
+
+ // For each of these patterns we have a RegExp which captures the inner component of the equation but also includes the delimiters.
+ // We first run the RegExp adding the global flag ("g"). This ignores the capture, instead matching the entire
+ // equation including delimiters and returning one entry per match of the whole equation.
+ // We have to deal with multiple occurences of the same equation in a String so must be able to loop on the
+ // match results.
+ Y.Array.find(this._equationPatterns, function(pattern) {
+ // For each pattern in turn, find all whole matches (including the delimiters).
+ var patternMatches = text.match(new RegExp(pattern.source, "g"));
+
+ if (patternMatches && patternMatches.length) {
+ // This pattern matches at least once. See if this pattern matches our current position.
+ // Note: We return here to break the Y.Array.find loop - any truthy return will stop any subsequent
+ // searches which is the required behaviour of this function.
+ return Y.Array.find(patternMatches, function(match) {
+ // Check each occurrence of this match.
+ var startIndex = 0;
+ while(text.indexOf(match, startIndex) !== -1) {
+ // Determine whether the cursor is in the current occurrence of this string.
+ // Note: We do not support a selection exceeding the bounds of an equation.
+ var startOuter = text.indexOf(match, startIndex),
+ endOuter = startOuter + match.length,
+ startMatch = (selection.startOffset >= startOuter && selection.startOffset < endOuter),
+ endMatch = (selection.endOffset <= endOuter && selection.endOffset > startOuter);
+
+ if (startMatch && endMatch) {
+ // This match is in our current position - fetch the innerMatch data.
+ var innerMatch = match.match(pattern);
+ if (innerMatch && innerMatch.length) {
+ // We need the start and end of the inner match for later.
+ var startInner = text.indexOf(innerMatch[1], startOuter),
+ endInner = startInner + innerMatch[1].length;
+
+ // We'll be returning the inner match for use in the editor itself.
+ returnValue = innerMatch[1];
+
+ // Save all data for later.
+ this.sourceEquation = {
+ // Outer match data.
+ startOuterPosition: startOuter,
+ endOuterPosition: endOuter,
+ outerMatch: match,
+
+ // Inner match data.
+ startInnerPosition: startInner,
+ endInnerPosition: endInner,
+ innerMatch: innerMatch
+ };
+
+ // This breaks out of both Y.Array.find functions.
+ return true;
+ }
+ }
+
+ // Update the startIndex to match the end of the current match so that we can continue hunting
+ // for further matches.
+ startIndex = endOuter;
+ }
+ }, this);
+ }
+ }, this);
+
+ return returnValue;
},
/**
@@ -287,13 +354,15 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto.
if (value !== '') {
host.setSelection(this._currentSelection);
- if (this.sourceEquation.length) {
+ if (this.sourceEquation) {
// Replace the equation.
selectedNode = Y.one(host.getSelectionParentNode());
text = selectedNode.get('text');
+ newText = text.slice(0, this.sourceEquation.startInnerPosition) +
+ value +
+ text.slice(this.sourceEquation.endInnerPosition);
- text = text.replace(this.sourceEquation, value);
- selectedNode.set('text', text);
+ selectedNode.set('text', newText);
} else {
// Insert the new equation.
value = DELIMITERS.START + ' ' + value + ' ' + DELIMITERS.END;
@@ -627,4 +696,13 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto.
});
-}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin", "moodle-core-event", "io", "event-valuechange", "tabview"]});
+}, '@VERSION@', {
+ "requires": [
+ "moodle-editor_atto-plugin",
+ "moodle-core-event",
+ "io",
+ "event-valuechange",
+ "tabview",
+ "array-extras"
+ ]
+});
diff --git a/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-min.js b/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-min.js
index 2e681ed435f..8db10819068 100644
--- a/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-min.js
+++ b/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button-min.js
@@ -1,2 +1,2 @@
-YUI.add("moodle-atto_equation-button",function(e,t){var n="atto_equation",r="atto_equation",i={EQUATION_TEXT:"atto_equation_equation",EQUATION_PREVIEW:"atto_equation_preview",SUBMIT:"atto_equation_submit",LIBRARY:"atto_equation_library",LIBRARY_GROUPS:"atto_equation_groups",LIBRARY_GROUP_PREFIX:"atto_equation_group"},s={LIBRARY:"."+i.LIBRARY,LIBRARY_GROUP:"."+i.LIBRARY_GROUPS+" > div > div",EQUATION_TEXT:"."+i.EQUATION_TEXT,EQUATION_PREVIEW:"."+i.EQUATION_PREVIEW,SUBMIT:"."+i.SUBMIT,LIBRARY_BUTTON:"."+i.LIBRARY+" button"},o={START:"\\(",END:"\\)"},u={FORM:'
'};e.namespace("M.atto_equation").Button=e.Base.create("button",e.M.editor_atto.EditorPlugin,[],{_currentSelection:null,_lastCursorPos:0,_content:null,_sourceEquation:null,_groupFocus:null,_equationPatterns:[/\$\$([\S\s]+?)\$\$/,/\\\(([\S\s]+?)\\\)/,/\\\[([\S\s]+?)\\\]/,/\[tex\]([\S\s]+?)\[\/tex\]/],initializer:function(){this._groupFocus={},this.get("texfilteractive")&&(this.addButton({icon:"e/math",callback:this._displayDialogue}),this.get("host").on("atto:selectionchanged",function(){this._resolveEquation()?this.highlightButtons():this.unHighlightButtons()},this),this.editor.all("tex").each(function(t){var n=e.Node.create(""+o.START+" "+t.get("text")+" "+o.END+"");t.replace(n)}))},_displayDialogue:function(){this._currentSelection=this.get("host").getSelection();if(this._currentSelection===!1)return;var t=this.getDialogue({headerContent:M.util.get_string("pluginname",n),focusAfterHide:!0,width:600}),r=this._getDialogueContent();t.set("bodyContent",r);var i=r.one(s.LIBRARY),o=new e.TabView({srcNode:i});o.render(),t.show(),e.fire(M.core.event.FILTER_CONTENT_UPDATED,{nodes:new e.NodeList(t.get("boundingBox"))});var u=this._resolveEquation();u&&r.one(s.EQUATION_TEXT).set("text",u),this._updatePreview(!1)},_resolveEquation:function(){var t=this.get("host").getSelectionParentNode(),n=this.get("host").getSelection(),r,i=!1;return this.sourceEquation=null,t?!n||n.length===0?!1:(n=n[0],r=e.one(t).get("text"),e.Array.find(this._equationPatterns,function(t){var s=r.match(new RegExp(t.source,"g"));if(s&&s.length)return e.Array.find(s,function(e){var s=0;while(r.indexOf(e,s)!==-1){var o=r.indexOf(e,s),u=o+e.length,a=n.startOffset>=o&&n.startOffseto;if(a&&f){var l=e.match(t);if(l&&l.length){var c=r.indexOf(l[1],o),h=c+l[1].length;return i=l[1],this.sourceEquation={startOuterPosition:o,endOuterPosition:u,outerMatch:e,startInnerPosition:c,endInnerPosition:h,innerMatch:l},!0}}s=u}},this)},this),i):!1},_setEquation:function(t){var n,r,i,s,u;u=this.get("host"),t.preventDefault(),this.getDialogue({focusAfterHide:null}).hide(),n=t.currentTarget.ancestor(".atto_form").one("textarea"),s=n.get("value"),s!==""&&(u.setSelection(this._currentSelection),this.sourceEquation?(r=e.one(u.getSelectionParentNode()),i=r.get("text"),newText=i.slice(0,this.sourceEquation.startInnerPosition)+s+i.slice(this.sourceEquation.endInnerPosition),r.set("text",newText)):(s=o.START+" "+s+" "+o.END,u.insertContentAtFocusPoint(s)),this.markUpdated())},_throttle:function(e,t){var n=null;return function(){var r=this,i=arguments;clearTimeout(n),n=setTimeout(function(){e.apply(r,i)},t)}},_updatePreview:function(t){var n=this._content.one(s.EQUATION_TEXT),r=n.get("value"),i,u,a=n.get("selectionStart"),f="",l="\\square ",c,h;t&&t.preventDefault(),a||(a=0);while(r.charAt(a)==="\\"&&a>0)a-=1;c=/[a-zA-Z\{\}]/;while(c.test(r.charAt(a))&&a=r.size()&&(s=0),o=r.item(s),this._setGroupTabFocus(n,o),o.focus()},_setGroupTabFocus:function(e,t){var n=e.generateID();typeof this._groupFocus[n]!="undefined"&&this._groupFocus[n].setAttribute("tabindex","-1"),this._groupFocus[n]=t,t.setAttribute("tabindex",0),e.setAttribute("aria-activedescendant",t.generateID())},_selectLibraryItem:function(e){var t=e.currentTarget.getAttribute("data-tex");e.preventDefault(),this._setGroupTabFocus(e.currentTarget.get("parentNode"),e.currentTarget),input=e.currentTarget.ancestor(".atto_form").one("textarea"),value=input.get("value"),value=value.substring(0,this._lastCursorPos)+t+value.substring(this._lastCursorPos,value.length),input.set("value",value),input.focus();var n=this._lastCursorPos+t.length,r=input.getDOMNode();if(typeof r.selectionStart=="number")r.selectionStart=r.selectionEnd=n;else if(typeof r.createTextRange!="undefined"){var i=r.createTextRange();i.moveToPoint(n),i.select()}this._updatePreview(!1)},_getLibraryContent:function(){var t=e.Handlebars.compile(u.LIBRARY),r=this.get("library"),s="";e.Handlebars.registerHelper("split",function(e,t,n){var r,i,s;if(typeof e=="undefined"||typeof t=="undefined")return"";s="",r=t.trim().split(e);while(r.length>0)i=r.shift().trim(),s+=n.fn(i);return s}),s=t({elementid:this.get("host").get("elementid"),component:n,library:r,CSS:i,DELIMITERS:o});var a=M.cfg.wwwroot+"/lib/editor/atto/plugins/equation/ajax.php",f={sesskey:M.cfg.sesskey,contextid:this.get("contextid"),action:"filtertext",text:s};return preview=e.io(a,{sync:!0,data:f,method:"POST"}),preview.status===200&&(s=preview.responseText),s}},{ATTRS:{texfilteractive:{value:!1},contextid:{value:null},library:{value:{}},texdocsurl:{value:null}}})},"@VERSION@",{requires:["moodle-editor_atto-plugin","moodle-core-event","io","event-valuechange","tabview","array-extras"]});
diff --git a/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button.js b/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button.js
index b47ca72d3ec..e6bd1110fe1 100644
--- a/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button.js
+++ b/lib/editor/atto/plugins/equation/yui/build/moodle-atto_equation-button/moodle-atto_equation-button.js
@@ -128,10 +128,10 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto.
* The source equation we are editing in the text.
*
* @property _sourceEquation
- * @type String
+ * @type Object
* @private
*/
- _sourceEquation: '',
+ _sourceEquation: null,
/**
* A reference to the tab focus set on each group.
@@ -144,6 +144,25 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto.
*/
_groupFocus: null,
+ /**
+ * Regular Expression patterns used to pick out the equations in a String.
+ *
+ * @property _equationPatterns
+ * @type Array
+ * @private
+ */
+ _equationPatterns: [
+ // We use space or not space because . does not match new lines.
+ // $$ blah $$.
+ /\$\$([\S\s]+?)\$\$/,
+ // E.g. "\( blah \)".
+ /\\\(([\S\s]+?)\\\)/,
+ // E.g. "\[ blah \]".
+ /\\\[([\S\s]+?)\\\]/,
+ // E.g. "[tex] blah [/tex]".
+ /\[tex\]([\S\s]+?)\[\/tex\]/
+ ],
+
initializer: function() {
this._groupFocus = {};
@@ -225,39 +244,87 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto.
// Find the equation in the surrounding text.
var selectedNode = this.get('host').getSelectionParentNode(),
+ selection = this.get('host').getSelection(),
text,
- equation,
- patterns = [], i;
+ returnValue = false;
+
+ this.sourceEquation = null;
// Note this is a document fragment and YUI doesn't like them.
if (!selectedNode) {
return false;
}
- text = Y.one(selectedNode).get('text');
- // We use space or not space because . does not match new lines.
- // $$ blah $$.
- patterns.push(/\$\$([\S\s]*)\$\$/);
- // E.g. "\( blah \)".
- patterns.push(/\\\(([\S\s]*)\\\)/);
- // E.g. "\[ blah \]".
- patterns.push(/\\\[([\S\s]*)\\\]/);
- // E.g. "[tex] blah [/tex]".
- patterns.push(/\[tex\]([\S\s]*)\[\/tex\]/);
-
- for (i = 0; i < patterns.length; i++) {
- pattern = patterns[i];
- equation = pattern.exec(text);
- if (equation && equation.length) {
- // Remember the inner match so we can replace it later.
- this.sourceEquation = equation = equation[1];
-
- return equation;
- }
+ // We don't yet have a cursor selection somehow so we can't possible be resolving an equation that has selection.
+ if (!selection || selection.length === 0) {
+ return false;
}
+ selection = selection[0];
- this.sourceEquation = '';
- return false;
+ text = Y.one(selectedNode).get('text');
+
+ // For each of these patterns we have a RegExp which captures the inner component of the equation but also includes the delimiters.
+ // We first run the RegExp adding the global flag ("g"). This ignores the capture, instead matching the entire
+ // equation including delimiters and returning one entry per match of the whole equation.
+ // We have to deal with multiple occurences of the same equation in a String so must be able to loop on the
+ // match results.
+ Y.Array.find(this._equationPatterns, function(pattern) {
+ // For each pattern in turn, find all whole matches (including the delimiters).
+ var patternMatches = text.match(new RegExp(pattern.source, "g"));
+
+ if (patternMatches && patternMatches.length) {
+ // This pattern matches at least once. See if this pattern matches our current position.
+ // Note: We return here to break the Y.Array.find loop - any truthy return will stop any subsequent
+ // searches which is the required behaviour of this function.
+ return Y.Array.find(patternMatches, function(match) {
+ // Check each occurrence of this match.
+ var startIndex = 0;
+ while(text.indexOf(match, startIndex) !== -1) {
+ // Determine whether the cursor is in the current occurrence of this string.
+ // Note: We do not support a selection exceeding the bounds of an equation.
+ var startOuter = text.indexOf(match, startIndex),
+ endOuter = startOuter + match.length,
+ startMatch = (selection.startOffset >= startOuter && selection.startOffset < endOuter),
+ endMatch = (selection.endOffset <= endOuter && selection.endOffset > startOuter);
+
+ if (startMatch && endMatch) {
+ // This match is in our current position - fetch the innerMatch data.
+ var innerMatch = match.match(pattern);
+ if (innerMatch && innerMatch.length) {
+ // We need the start and end of the inner match for later.
+ var startInner = text.indexOf(innerMatch[1], startOuter),
+ endInner = startInner + innerMatch[1].length;
+
+ // We'll be returning the inner match for use in the editor itself.
+ returnValue = innerMatch[1];
+
+ // Save all data for later.
+ this.sourceEquation = {
+ // Outer match data.
+ startOuterPosition: startOuter,
+ endOuterPosition: endOuter,
+ outerMatch: match,
+
+ // Inner match data.
+ startInnerPosition: startInner,
+ endInnerPosition: endInner,
+ innerMatch: innerMatch
+ };
+
+ // This breaks out of both Y.Array.find functions.
+ return true;
+ }
+ }
+
+ // Update the startIndex to match the end of the current match so that we can continue hunting
+ // for further matches.
+ startIndex = endOuter;
+ }
+ }, this);
+ }
+ }, this);
+
+ return returnValue;
},
/**
@@ -287,13 +354,15 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto.
if (value !== '') {
host.setSelection(this._currentSelection);
- if (this.sourceEquation.length) {
+ if (this.sourceEquation) {
// Replace the equation.
selectedNode = Y.one(host.getSelectionParentNode());
text = selectedNode.get('text');
+ newText = text.slice(0, this.sourceEquation.startInnerPosition) +
+ value +
+ text.slice(this.sourceEquation.endInnerPosition);
- text = text.replace(this.sourceEquation, value);
- selectedNode.set('text', text);
+ selectedNode.set('text', newText);
} else {
// Insert the new equation.
value = DELIMITERS.START + ' ' + value + ' ' + DELIMITERS.END;
@@ -625,4 +694,13 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto.
});
-}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin", "moodle-core-event", "io", "event-valuechange", "tabview"]});
+}, '@VERSION@', {
+ "requires": [
+ "moodle-editor_atto-plugin",
+ "moodle-core-event",
+ "io",
+ "event-valuechange",
+ "tabview",
+ "array-extras"
+ ]
+});
diff --git a/lib/editor/atto/plugins/equation/yui/src/button/js/button.js b/lib/editor/atto/plugins/equation/yui/src/button/js/button.js
index 2bb932d6708..e57555d87d5 100644
--- a/lib/editor/atto/plugins/equation/yui/src/button/js/button.js
+++ b/lib/editor/atto/plugins/equation/yui/src/button/js/button.js
@@ -126,10 +126,10 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto.
* The source equation we are editing in the text.
*
* @property _sourceEquation
- * @type String
+ * @type Object
* @private
*/
- _sourceEquation: '',
+ _sourceEquation: null,
/**
* A reference to the tab focus set on each group.
@@ -142,6 +142,25 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto.
*/
_groupFocus: null,
+ /**
+ * Regular Expression patterns used to pick out the equations in a String.
+ *
+ * @property _equationPatterns
+ * @type Array
+ * @private
+ */
+ _equationPatterns: [
+ // We use space or not space because . does not match new lines.
+ // $$ blah $$.
+ /\$\$([\S\s]+?)\$\$/,
+ // E.g. "\( blah \)".
+ /\\\(([\S\s]+?)\\\)/,
+ // E.g. "\[ blah \]".
+ /\\\[([\S\s]+?)\\\]/,
+ // E.g. "[tex] blah [/tex]".
+ /\[tex\]([\S\s]+?)\[\/tex\]/
+ ],
+
initializer: function() {
this._groupFocus = {};
@@ -223,39 +242,87 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto.
// Find the equation in the surrounding text.
var selectedNode = this.get('host').getSelectionParentNode(),
+ selection = this.get('host').getSelection(),
text,
- equation,
- patterns = [], i;
+ returnValue = false;
+
+ this.sourceEquation = null;
// Note this is a document fragment and YUI doesn't like them.
if (!selectedNode) {
return false;
}
- text = Y.one(selectedNode).get('text');
- // We use space or not space because . does not match new lines.
- // $$ blah $$.
- patterns.push(/\$\$([\S\s]*)\$\$/);
- // E.g. "\( blah \)".
- patterns.push(/\\\(([\S\s]*)\\\)/);
- // E.g. "\[ blah \]".
- patterns.push(/\\\[([\S\s]*)\\\]/);
- // E.g. "[tex] blah [/tex]".
- patterns.push(/\[tex\]([\S\s]*)\[\/tex\]/);
-
- for (i = 0; i < patterns.length; i++) {
- pattern = patterns[i];
- equation = pattern.exec(text);
- if (equation && equation.length) {
- // Remember the inner match so we can replace it later.
- this.sourceEquation = equation = equation[1];
-
- return equation;
- }
+ // We don't yet have a cursor selection somehow so we can't possible be resolving an equation that has selection.
+ if (!selection || selection.length === 0) {
+ return false;
}
+ selection = selection[0];
- this.sourceEquation = '';
- return false;
+ text = Y.one(selectedNode).get('text');
+
+ // For each of these patterns we have a RegExp which captures the inner component of the equation but also includes the delimiters.
+ // We first run the RegExp adding the global flag ("g"). This ignores the capture, instead matching the entire
+ // equation including delimiters and returning one entry per match of the whole equation.
+ // We have to deal with multiple occurences of the same equation in a String so must be able to loop on the
+ // match results.
+ Y.Array.find(this._equationPatterns, function(pattern) {
+ // For each pattern in turn, find all whole matches (including the delimiters).
+ var patternMatches = text.match(new RegExp(pattern.source, "g"));
+
+ if (patternMatches && patternMatches.length) {
+ // This pattern matches at least once. See if this pattern matches our current position.
+ // Note: We return here to break the Y.Array.find loop - any truthy return will stop any subsequent
+ // searches which is the required behaviour of this function.
+ return Y.Array.find(patternMatches, function(match) {
+ // Check each occurrence of this match.
+ var startIndex = 0;
+ while(text.indexOf(match, startIndex) !== -1) {
+ // Determine whether the cursor is in the current occurrence of this string.
+ // Note: We do not support a selection exceeding the bounds of an equation.
+ var startOuter = text.indexOf(match, startIndex),
+ endOuter = startOuter + match.length,
+ startMatch = (selection.startOffset >= startOuter && selection.startOffset < endOuter),
+ endMatch = (selection.endOffset <= endOuter && selection.endOffset > startOuter);
+
+ if (startMatch && endMatch) {
+ // This match is in our current position - fetch the innerMatch data.
+ var innerMatch = match.match(pattern);
+ if (innerMatch && innerMatch.length) {
+ // We need the start and end of the inner match for later.
+ var startInner = text.indexOf(innerMatch[1], startOuter),
+ endInner = startInner + innerMatch[1].length;
+
+ // We'll be returning the inner match for use in the editor itself.
+ returnValue = innerMatch[1];
+
+ // Save all data for later.
+ this.sourceEquation = {
+ // Outer match data.
+ startOuterPosition: startOuter,
+ endOuterPosition: endOuter,
+ outerMatch: match,
+
+ // Inner match data.
+ startInnerPosition: startInner,
+ endInnerPosition: endInner,
+ innerMatch: innerMatch
+ };
+
+ // This breaks out of both Y.Array.find functions.
+ return true;
+ }
+ }
+
+ // Update the startIndex to match the end of the current match so that we can continue hunting
+ // for further matches.
+ startIndex = endOuter;
+ }
+ }, this);
+ }
+ }, this);
+
+ return returnValue;
},
/**
@@ -285,13 +352,15 @@ Y.namespace('M.atto_equation').Button = Y.Base.create('button', Y.M.editor_atto.
if (value !== '') {
host.setSelection(this._currentSelection);
- if (this.sourceEquation.length) {
+ if (this.sourceEquation) {
// Replace the equation.
selectedNode = Y.one(host.getSelectionParentNode());
text = selectedNode.get('text');
+ newText = text.slice(0, this.sourceEquation.startInnerPosition) +
+ value +
+ text.slice(this.sourceEquation.endInnerPosition);
- text = text.replace(this.sourceEquation, value);
- selectedNode.set('text', text);
+ selectedNode.set('text', newText);
} else {
// Insert the new equation.
value = DELIMITERS.START + ' ' + value + ' ' + DELIMITERS.END;
diff --git a/lib/editor/atto/plugins/equation/yui/src/button/meta/button.json b/lib/editor/atto/plugins/equation/yui/src/button/meta/button.json
index 6103cb338de..144f41791d8 100644
--- a/lib/editor/atto/plugins/equation/yui/src/button/meta/button.json
+++ b/lib/editor/atto/plugins/equation/yui/src/button/meta/button.json
@@ -5,7 +5,8 @@
"moodle-core-event",
"io",
"event-valuechange",
- "tabview"
+ "tabview",
+ "array-extras"
]
}
}