Merge branch 'MDL-46387-m29-master' of https://github.com/dthies/moodle into MOODLE_29_STABLE
This commit is contained in:
@@ -19,3 +19,20 @@ Feature: Atto subscript button
|
||||
And I follow "Edit profile"
|
||||
Then I should see "<sub>Submarine</sub>"
|
||||
|
||||
@javascript
|
||||
Scenario: Subscript some text in enclosed in superscript
|
||||
Given I log in as "admin"
|
||||
And I follow "Profile" in the user menu
|
||||
And I follow "Edit profile"
|
||||
And I set the field "Description" to "<sup>Submarine</sup>"
|
||||
And I select the text in the "Description" Atto editor
|
||||
And I click on "Show more buttons" "button"
|
||||
When I click on "Subscript" "button"
|
||||
And I press "Update profile"
|
||||
And I follow "Preferences" in the user menu
|
||||
And I follow "Editor preferences"
|
||||
And I set the field "Text editor" to "Plain text area"
|
||||
And I press "Save changes"
|
||||
And I follow "Edit profile"
|
||||
Then I should see "<sub>Submarine</sub>"
|
||||
|
||||
|
||||
+44
-2
@@ -34,13 +34,55 @@ YUI.add('moodle-atto_subscript-button', function (Y, NAME) {
|
||||
*/
|
||||
|
||||
Y.namespace('M.atto_subscript').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], {
|
||||
/**
|
||||
* A rangy object to alter CSS classes.
|
||||
*
|
||||
* @property _subscriptApplier
|
||||
* @type Object
|
||||
* @private
|
||||
*/
|
||||
_subscriptApplier: null,
|
||||
|
||||
/**
|
||||
* A rangy object to alter CSS classes.
|
||||
*
|
||||
* @property _superscriptApplier
|
||||
* @type Object
|
||||
* @private
|
||||
*/
|
||||
_superscriptApplier: null,
|
||||
|
||||
initializer: function() {
|
||||
this.addBasicButton({
|
||||
exec: 'subscript',
|
||||
this.addButton({
|
||||
buttonName: 'subscript',
|
||||
callback: this.toggleSubscript,
|
||||
icon: 'e/subscript',
|
||||
inlineFormat: true,
|
||||
|
||||
// Watch the following tags and add/remove highlighting as appropriate:
|
||||
tags: 'sub'
|
||||
});
|
||||
this._subscriptApplier = window.rangy.createCssClassApplier("editor-subscript");
|
||||
this._superscriptApplier = window.rangy.createCssClassApplier("editor-superscript");
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggle subscripts in selection
|
||||
*
|
||||
* @method toggleSubscript
|
||||
*/
|
||||
toggleSubscript: function() {
|
||||
// Replace all the sub and sup tags.
|
||||
this.get('host').changeToCSS('sup', 'editor-superscript');
|
||||
this.get('host').changeToCSS('sub', 'editor-subscript');
|
||||
|
||||
// Remove all superscripts inselection and toggle subscript.
|
||||
this._superscriptApplier.undoToSelection();
|
||||
this._subscriptApplier.toggleSelection();
|
||||
|
||||
// Replace CSS classes with tags.
|
||||
this.get('host').changeToTags('editor-subscript', 'sub');
|
||||
this.get('host').changeToTags('editor-superscript', 'sup');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
YUI.add("moodle-atto_subscript-button",function(e,t){e.namespace("M.atto_subscript").Button=e.Base.create("button",e.M.editor_atto.EditorPlugin,[],{initializer:function(){this.addBasicButton({exec:"subscript",tags:"sub"})}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]});
|
||||
YUI.add("moodle-atto_subscript-button",function(e,t){e.namespace("M.atto_subscript").Button=e.Base.create("button",e.M.editor_atto.EditorPlugin,[],{_subscriptApplier:null,_superscriptApplier:null,initializer:function(){this.addButton({buttonName:"subscript",callback:this.toggleSubscript,icon:"e/subscript",inlineFormat:!0,tags:"sub"}),this._subscriptApplier=window.rangy.createCssClassApplier("editor-subscript"),this._superscriptApplier=window.rangy.createCssClassApplier("editor-superscript")},toggleSubscript:function(){this.get("host").changeToCSS("sup","editor-superscript"),this.get("host").changeToCSS("sub","editor-subscript"),this._superscriptApplier.undoToSelection(),this._subscriptApplier.toggleSelection(),this.get("host").changeToTags("editor-subscript","sub"),this.get("host").changeToTags("editor-superscript","sup")}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]});
|
||||
|
||||
+44
-2
@@ -34,13 +34,55 @@ YUI.add('moodle-atto_subscript-button', function (Y, NAME) {
|
||||
*/
|
||||
|
||||
Y.namespace('M.atto_subscript').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], {
|
||||
/**
|
||||
* A rangy object to alter CSS classes.
|
||||
*
|
||||
* @property _subscriptApplier
|
||||
* @type Object
|
||||
* @private
|
||||
*/
|
||||
_subscriptApplier: null,
|
||||
|
||||
/**
|
||||
* A rangy object to alter CSS classes.
|
||||
*
|
||||
* @property _superscriptApplier
|
||||
* @type Object
|
||||
* @private
|
||||
*/
|
||||
_superscriptApplier: null,
|
||||
|
||||
initializer: function() {
|
||||
this.addBasicButton({
|
||||
exec: 'subscript',
|
||||
this.addButton({
|
||||
buttonName: 'subscript',
|
||||
callback: this.toggleSubscript,
|
||||
icon: 'e/subscript',
|
||||
inlineFormat: true,
|
||||
|
||||
// Watch the following tags and add/remove highlighting as appropriate:
|
||||
tags: 'sub'
|
||||
});
|
||||
this._subscriptApplier = window.rangy.createCssClassApplier("editor-subscript");
|
||||
this._superscriptApplier = window.rangy.createCssClassApplier("editor-superscript");
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggle subscripts in selection
|
||||
*
|
||||
* @method toggleSubscript
|
||||
*/
|
||||
toggleSubscript: function() {
|
||||
// Replace all the sub and sup tags.
|
||||
this.get('host').changeToCSS('sup', 'editor-superscript');
|
||||
this.get('host').changeToCSS('sub', 'editor-subscript');
|
||||
|
||||
// Remove all superscripts inselection and toggle subscript.
|
||||
this._superscriptApplier.undoToSelection();
|
||||
this._subscriptApplier.toggleSelection();
|
||||
|
||||
// Replace CSS classes with tags.
|
||||
this.get('host').changeToTags('editor-subscript', 'sub');
|
||||
this.get('host').changeToTags('editor-superscript', 'sup');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -32,12 +32,54 @@
|
||||
*/
|
||||
|
||||
Y.namespace('M.atto_subscript').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], {
|
||||
/**
|
||||
* A rangy object to alter CSS classes.
|
||||
*
|
||||
* @property _subscriptApplier
|
||||
* @type Object
|
||||
* @private
|
||||
*/
|
||||
_subscriptApplier: null,
|
||||
|
||||
/**
|
||||
* A rangy object to alter CSS classes.
|
||||
*
|
||||
* @property _superscriptApplier
|
||||
* @type Object
|
||||
* @private
|
||||
*/
|
||||
_superscriptApplier: null,
|
||||
|
||||
initializer: function() {
|
||||
this.addBasicButton({
|
||||
exec: 'subscript',
|
||||
this.addButton({
|
||||
buttonName: 'subscript',
|
||||
callback: this.toggleSubscript,
|
||||
icon: 'e/subscript',
|
||||
inlineFormat: true,
|
||||
|
||||
// Watch the following tags and add/remove highlighting as appropriate:
|
||||
tags: 'sub'
|
||||
});
|
||||
this._subscriptApplier = window.rangy.createCssClassApplier("editor-subscript");
|
||||
this._superscriptApplier = window.rangy.createCssClassApplier("editor-superscript");
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggle subscripts in selection
|
||||
*
|
||||
* @method toggleSubscript
|
||||
*/
|
||||
toggleSubscript: function() {
|
||||
// Replace all the sub and sup tags.
|
||||
this.get('host').changeToCSS('sup', 'editor-superscript');
|
||||
this.get('host').changeToCSS('sub', 'editor-subscript');
|
||||
|
||||
// Remove all superscripts inselection and toggle subscript.
|
||||
this._superscriptApplier.undoToSelection();
|
||||
this._subscriptApplier.toggleSelection();
|
||||
|
||||
// Replace CSS classes with tags.
|
||||
this.get('host').changeToTags('editor-subscript', 'sub');
|
||||
this.get('host').changeToTags('editor-superscript', 'sup');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -19,3 +19,20 @@ Feature: Atto superscript button
|
||||
And I follow "Edit profile"
|
||||
Then I should see "<sup>Helicopter</sup>"
|
||||
|
||||
@javascript
|
||||
Scenario: Superscript some text that is enclosed in subscript
|
||||
Given I log in as "admin"
|
||||
And I follow "Profile" in the user menu
|
||||
And I follow "Edit profile"
|
||||
And I set the field "Description" to "<sub>Helicopter</sub>"
|
||||
And I select the text in the "Description" Atto editor
|
||||
And I click on "Show more buttons" "button"
|
||||
When I click on "Superscript" "button"
|
||||
And I press "Update profile"
|
||||
And I follow "Preferences" in the user menu
|
||||
And I follow "Editor preferences"
|
||||
And I set the field "Text editor" to "Plain text area"
|
||||
And I press "Save changes"
|
||||
And I follow "Edit profile"
|
||||
Then I should see "<sup>Helicopter</sup>"
|
||||
|
||||
|
||||
+44
-2
@@ -34,13 +34,55 @@ YUI.add('moodle-atto_superscript-button', function (Y, NAME) {
|
||||
*/
|
||||
|
||||
Y.namespace('M.atto_superscript').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], {
|
||||
/**
|
||||
* A rangy object to alter CSS classes.
|
||||
*
|
||||
* @property _subscriptApplier
|
||||
* @type Object
|
||||
* @private
|
||||
*/
|
||||
_subscriptApplier: null,
|
||||
|
||||
/**
|
||||
* A rangy object to alter CSS classes.
|
||||
*
|
||||
* @property _superscriptApplier
|
||||
* @type Object
|
||||
* @private
|
||||
*/
|
||||
_superscriptApplier: null,
|
||||
|
||||
initializer: function() {
|
||||
this.addBasicButton({
|
||||
exec: 'superscript',
|
||||
this.addButton({
|
||||
buttonName: 'superscript',
|
||||
inlineFormat: true,
|
||||
callback: this.toggleSuperscript,
|
||||
icon: 'e/superscript',
|
||||
|
||||
// Watch the following tags and add/remove highlighting as appropriate:
|
||||
tags: 'sup'
|
||||
});
|
||||
this._subscriptApplier = window.rangy.createCssClassApplier("editor-subscript");
|
||||
this._superscriptApplier = window.rangy.createCssClassApplier("editor-superscript");
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggle superscripts in selection
|
||||
*
|
||||
* @method toggleSuperscript
|
||||
*/
|
||||
toggleSuperscript: function() {
|
||||
// Replace all the sub and sup tags.
|
||||
this.get('host').changeToCSS('sub', 'editor-subscript');
|
||||
this.get('host').changeToCSS('sup', 'editor-superscript');
|
||||
|
||||
// Remove all subscripts inselection and toggle superscript.
|
||||
this._superscriptApplier.toggleSelection();
|
||||
this._subscriptApplier.undoToSelection();
|
||||
|
||||
// Replace CSS classes with tags.
|
||||
this.get('host').changeToTags('editor-superscript', 'sup');
|
||||
this.get('host').changeToTags('editor-subscript', 'sub');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
YUI.add("moodle-atto_superscript-button",function(e,t){e.namespace("M.atto_superscript").Button=e.Base.create("button",e.M.editor_atto.EditorPlugin,[],{initializer:function(){this.addBasicButton({exec:"superscript",tags:"sup"})}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]});
|
||||
YUI.add("moodle-atto_superscript-button",function(e,t){e.namespace("M.atto_superscript").Button=e.Base.create("button",e.M.editor_atto.EditorPlugin,[],{_subscriptApplier:null,_superscriptApplier:null,initializer:function(){this.addButton({buttonName:"superscript",inlineFormat:!0,callback:this.toggleSuperscript,icon:"e/superscript",tags:"sup"}),this._subscriptApplier=window.rangy.createCssClassApplier("editor-subscript"),this._superscriptApplier=window.rangy.createCssClassApplier("editor-superscript")},toggleSuperscript:function(){this.get("host").changeToCSS("sub","editor-subscript"),this.get("host").changeToCSS("sup","editor-superscript"),this._superscriptApplier.toggleSelection(),this._subscriptApplier.undoToSelection(),this.get("host").changeToTags("editor-superscript","sup"),this.get("host").changeToTags("editor-subscript","sub")}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]});
|
||||
|
||||
+44
-2
@@ -34,13 +34,55 @@ YUI.add('moodle-atto_superscript-button', function (Y, NAME) {
|
||||
*/
|
||||
|
||||
Y.namespace('M.atto_superscript').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], {
|
||||
/**
|
||||
* A rangy object to alter CSS classes.
|
||||
*
|
||||
* @property _subscriptApplier
|
||||
* @type Object
|
||||
* @private
|
||||
*/
|
||||
_subscriptApplier: null,
|
||||
|
||||
/**
|
||||
* A rangy object to alter CSS classes.
|
||||
*
|
||||
* @property _superscriptApplier
|
||||
* @type Object
|
||||
* @private
|
||||
*/
|
||||
_superscriptApplier: null,
|
||||
|
||||
initializer: function() {
|
||||
this.addBasicButton({
|
||||
exec: 'superscript',
|
||||
this.addButton({
|
||||
buttonName: 'superscript',
|
||||
inlineFormat: true,
|
||||
callback: this.toggleSuperscript,
|
||||
icon: 'e/superscript',
|
||||
|
||||
// Watch the following tags and add/remove highlighting as appropriate:
|
||||
tags: 'sup'
|
||||
});
|
||||
this._subscriptApplier = window.rangy.createCssClassApplier("editor-subscript");
|
||||
this._superscriptApplier = window.rangy.createCssClassApplier("editor-superscript");
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggle superscripts in selection
|
||||
*
|
||||
* @method toggleSuperscript
|
||||
*/
|
||||
toggleSuperscript: function() {
|
||||
// Replace all the sub and sup tags.
|
||||
this.get('host').changeToCSS('sub', 'editor-subscript');
|
||||
this.get('host').changeToCSS('sup', 'editor-superscript');
|
||||
|
||||
// Remove all subscripts inselection and toggle superscript.
|
||||
this._superscriptApplier.toggleSelection();
|
||||
this._subscriptApplier.undoToSelection();
|
||||
|
||||
// Replace CSS classes with tags.
|
||||
this.get('host').changeToTags('editor-superscript', 'sup');
|
||||
this.get('host').changeToTags('editor-subscript', 'sub');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -32,12 +32,54 @@
|
||||
*/
|
||||
|
||||
Y.namespace('M.atto_superscript').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], {
|
||||
/**
|
||||
* A rangy object to alter CSS classes.
|
||||
*
|
||||
* @property _subscriptApplier
|
||||
* @type Object
|
||||
* @private
|
||||
*/
|
||||
_subscriptApplier: null,
|
||||
|
||||
/**
|
||||
* A rangy object to alter CSS classes.
|
||||
*
|
||||
* @property _superscriptApplier
|
||||
* @type Object
|
||||
* @private
|
||||
*/
|
||||
_superscriptApplier: null,
|
||||
|
||||
initializer: function() {
|
||||
this.addBasicButton({
|
||||
exec: 'superscript',
|
||||
this.addButton({
|
||||
buttonName: 'superscript',
|
||||
callback: this.toggleSuperscript,
|
||||
icon: 'e/superscript',
|
||||
inlineFormat: true,
|
||||
|
||||
// Watch the following tags and add/remove highlighting as appropriate:
|
||||
tags: 'sup'
|
||||
});
|
||||
this._subscriptApplier = window.rangy.createCssClassApplier("editor-subscript");
|
||||
this._superscriptApplier = window.rangy.createCssClassApplier("editor-superscript");
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggle superscripts in selection
|
||||
*
|
||||
* @method toggleSuperscript
|
||||
*/
|
||||
toggleSuperscript: function() {
|
||||
// Replace all the sub and sup tags.
|
||||
this.get('host').changeToCSS('sub', 'editor-subscript');
|
||||
this.get('host').changeToCSS('sup', 'editor-superscript');
|
||||
|
||||
// Remove all subscripts inselection and toggle superscript.
|
||||
this._superscriptApplier.toggleSelection();
|
||||
this._subscriptApplier.undoToSelection();
|
||||
|
||||
// Replace CSS classes with tags.
|
||||
this.get('host').changeToTags('editor-superscript', 'sup');
|
||||
this.get('host').changeToTags('editor-subscript', 'sub');
|
||||
}
|
||||
});
|
||||
|
||||
+170
@@ -1410,6 +1410,175 @@ Y.Base.mix(Y.M.editor_atto.Editor, [EditorClean]);
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* @module moodle-editor_atto-editor
|
||||
* @submodule commands
|
||||
*/
|
||||
|
||||
/**
|
||||
* Selection functions for the Atto editor.
|
||||
*
|
||||
* See {{#crossLink "M.editor_atto.Editor"}}{{/crossLink}} for details.
|
||||
*
|
||||
* @namespace M.editor_atto
|
||||
* @class EditorCommand
|
||||
*/
|
||||
|
||||
function EditorCommand() {}
|
||||
|
||||
EditorCommand.ATTRS= {
|
||||
};
|
||||
|
||||
EditorCommand.prototype = {
|
||||
/**
|
||||
* Applies a callback method to editor if selection is uncollapsed or waits for input to select first.
|
||||
* @method applyFormat
|
||||
* @param e EventTarget Event to be passed to callback if selection is uncollapsed
|
||||
* @param method callback A callback method which changes editor when text is selected.
|
||||
* @param object context Context to be used for callback method
|
||||
* @param array args Array of arguments to pass to callback
|
||||
*/
|
||||
applyFormat: function(e, callback, context, args) {
|
||||
function handleInsert(e, callback, context, args, anchorNode, anchorOffset) {
|
||||
// After something is inputed, select it and apply the formating function.
|
||||
Y.soon(Y.bind(function(e, callback, context, args, anchorNode, anchorOffset) {
|
||||
var selection = window.rangy.getSelection();
|
||||
|
||||
// Set the start of the selection to where it was when the method was first called.
|
||||
var range = selection.getRangeAt(0);
|
||||
range.setStart(anchorNode, anchorOffset);
|
||||
selection.setSingleRange(range);
|
||||
|
||||
// Now apply callback to the new text that is selected.
|
||||
callback.apply(context, [e, args]);
|
||||
|
||||
// Collapse selection so cursor is at end of inserted material.
|
||||
selection.collapseToEnd();
|
||||
}, this, e, callback, context, args, anchorNode, anchorOffset));
|
||||
}
|
||||
|
||||
// Set default context for the method.
|
||||
context = context || this;
|
||||
|
||||
// Check whether range is collapsed.
|
||||
var selection = window.rangy.getSelection();
|
||||
|
||||
if (selection.isCollapsed) {
|
||||
// Selection is collapsed so listen for input into editor.
|
||||
var handle = this.editor.once('input', handleInsert, this, callback, context, args,
|
||||
selection.anchorNode, selection.anchorOffset);
|
||||
|
||||
// Cancel if selection changes before input.
|
||||
this.editor.onceAfter(['click', 'selectstart'], handle.detach, handle);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// The range is not collapsed; so apply callback method immediately.
|
||||
callback.apply(context, [e, args]);
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Replaces all the tags in a node list with new type.
|
||||
* @method replaceTags
|
||||
* @param NodeList nodelist
|
||||
* @param String tag
|
||||
*/
|
||||
replaceTags: function(nodelist, tag) {
|
||||
// We mark elements in the node list for iterations.
|
||||
nodelist.setAttribute('data-iterate', true);
|
||||
var node = this.editor.one('[data-iterate="true"]');
|
||||
while (node) {
|
||||
var clone = Y.Node.create('<' + tag + ' />')
|
||||
.setAttrs(node.getAttrs())
|
||||
.removeAttribute('data-iterate');
|
||||
// Copy class and style if not blank.
|
||||
if (node.getAttribute('style')) {
|
||||
clone.setAttribute('style', node.getAttribute('style'));
|
||||
}
|
||||
if (node.getAttribute('class')) {
|
||||
clone.setAttribute('class', node.getAttribute('class'));
|
||||
}
|
||||
// We use childNodes here because we are interested in both type 1 and 3 child nodes.
|
||||
var children = node.getDOMNode().childNodes, child;
|
||||
child = children[0];
|
||||
while (typeof child !== "undefined") {
|
||||
clone.append(child);
|
||||
child = children[0];
|
||||
}
|
||||
node.replace(clone);
|
||||
node = this.editor.one('[data-iterate="true"]');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Change all tags with given type to a span with CSS class attribute.
|
||||
* @method changeToCSS
|
||||
* @param String tag Tag type to be changed to span
|
||||
* @param String markerClass CSS class that corresponds to desired tag
|
||||
*/
|
||||
changeToCSS: function(tag, markerClass) {
|
||||
// Save the selection.
|
||||
var selection = window.rangy.saveSelection();
|
||||
|
||||
// Remove display:none from rangy markers so browser doesn't delete them.
|
||||
this.editor.all('.rangySelectionBoundary').setStyle('display', null);
|
||||
|
||||
// Replace tags with CSS classes.
|
||||
this.editor.all(tag).addClass(markerClass);
|
||||
this.replaceTags(this.editor.all('.' + markerClass), 'span');
|
||||
|
||||
// Restore selection and toggle class.
|
||||
window.rangy.restoreSelection(selection);
|
||||
},
|
||||
|
||||
/**
|
||||
* Change spans with CSS classes in editor into elements with given tag.
|
||||
* @method changeToCSS
|
||||
* @param String markerClass CSS class that corresponds to desired tag
|
||||
* @param String tag New tag type to be created
|
||||
*/
|
||||
changeToTags: function(markerClass, tag) {
|
||||
// Save the selection.
|
||||
var selection = window.rangy.saveSelection();
|
||||
|
||||
// Remove display:none from rangy markers so browser doesn't delete them.
|
||||
this.editor.all('.rangySelectionBoundary').setStyle('display', null);
|
||||
|
||||
// Replace spans with given tag.
|
||||
this.replaceTags(this.editor.all('span[class="' + markerClass + '"]'), tag);
|
||||
this.editor.all(tag + '[class="' + markerClass + '"]').removeAttribute('class');
|
||||
this.editor.all('.' + markerClass).each(function(n) {
|
||||
n.wrap('<' + tag + '/>');
|
||||
n.removeClass(markerClass);
|
||||
});
|
||||
|
||||
// Remove CSS classes.
|
||||
this.editor.all('[class="' + markerClass + '"]').removeAttribute('class');
|
||||
this.editor.all(tag).removeClass(markerClass);
|
||||
|
||||
// Restore selection.
|
||||
window.rangy.restoreSelection(selection);
|
||||
}
|
||||
};
|
||||
|
||||
Y.Base.mix(Y.M.editor_atto.Editor, [EditorCommand]);
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* @module moodle-editor_atto-editor
|
||||
* @submodule toolbar
|
||||
@@ -2392,6 +2561,7 @@ Y.Base.mix(Y.M.editor_atto.Editor, [EditorFilepicker]);
|
||||
"event",
|
||||
"event-simulate",
|
||||
"event-custom",
|
||||
"node-event-html5",
|
||||
"yui-throttle",
|
||||
"moodle-core-notification-dialogue",
|
||||
"moodle-core-notification-confirm",
|
||||
|
||||
+4
-4
File diff suppressed because one or more lines are too long
+170
@@ -1399,6 +1399,175 @@ Y.Base.mix(Y.M.editor_atto.Editor, [EditorClean]);
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* @module moodle-editor_atto-editor
|
||||
* @submodule commands
|
||||
*/
|
||||
|
||||
/**
|
||||
* Selection functions for the Atto editor.
|
||||
*
|
||||
* See {{#crossLink "M.editor_atto.Editor"}}{{/crossLink}} for details.
|
||||
*
|
||||
* @namespace M.editor_atto
|
||||
* @class EditorCommand
|
||||
*/
|
||||
|
||||
function EditorCommand() {}
|
||||
|
||||
EditorCommand.ATTRS= {
|
||||
};
|
||||
|
||||
EditorCommand.prototype = {
|
||||
/**
|
||||
* Applies a callback method to editor if selection is uncollapsed or waits for input to select first.
|
||||
* @method applyFormat
|
||||
* @param e EventTarget Event to be passed to callback if selection is uncollapsed
|
||||
* @param method callback A callback method which changes editor when text is selected.
|
||||
* @param object context Context to be used for callback method
|
||||
* @param array args Array of arguments to pass to callback
|
||||
*/
|
||||
applyFormat: function(e, callback, context, args) {
|
||||
function handleInsert(e, callback, context, args, anchorNode, anchorOffset) {
|
||||
// After something is inputed, select it and apply the formating function.
|
||||
Y.soon(Y.bind(function(e, callback, context, args, anchorNode, anchorOffset) {
|
||||
var selection = window.rangy.getSelection();
|
||||
|
||||
// Set the start of the selection to where it was when the method was first called.
|
||||
var range = selection.getRangeAt(0);
|
||||
range.setStart(anchorNode, anchorOffset);
|
||||
selection.setSingleRange(range);
|
||||
|
||||
// Now apply callback to the new text that is selected.
|
||||
callback.apply(context, [e, args]);
|
||||
|
||||
// Collapse selection so cursor is at end of inserted material.
|
||||
selection.collapseToEnd();
|
||||
}, this, e, callback, context, args, anchorNode, anchorOffset));
|
||||
}
|
||||
|
||||
// Set default context for the method.
|
||||
context = context || this;
|
||||
|
||||
// Check whether range is collapsed.
|
||||
var selection = window.rangy.getSelection();
|
||||
|
||||
if (selection.isCollapsed) {
|
||||
// Selection is collapsed so listen for input into editor.
|
||||
var handle = this.editor.once('input', handleInsert, this, callback, context, args,
|
||||
selection.anchorNode, selection.anchorOffset);
|
||||
|
||||
// Cancel if selection changes before input.
|
||||
this.editor.onceAfter(['click', 'selectstart'], handle.detach, handle);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// The range is not collapsed; so apply callback method immediately.
|
||||
callback.apply(context, [e, args]);
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Replaces all the tags in a node list with new type.
|
||||
* @method replaceTags
|
||||
* @param NodeList nodelist
|
||||
* @param String tag
|
||||
*/
|
||||
replaceTags: function(nodelist, tag) {
|
||||
// We mark elements in the node list for iterations.
|
||||
nodelist.setAttribute('data-iterate', true);
|
||||
var node = this.editor.one('[data-iterate="true"]');
|
||||
while (node) {
|
||||
var clone = Y.Node.create('<' + tag + ' />')
|
||||
.setAttrs(node.getAttrs())
|
||||
.removeAttribute('data-iterate');
|
||||
// Copy class and style if not blank.
|
||||
if (node.getAttribute('style')) {
|
||||
clone.setAttribute('style', node.getAttribute('style'));
|
||||
}
|
||||
if (node.getAttribute('class')) {
|
||||
clone.setAttribute('class', node.getAttribute('class'));
|
||||
}
|
||||
// We use childNodes here because we are interested in both type 1 and 3 child nodes.
|
||||
var children = node.getDOMNode().childNodes, child;
|
||||
child = children[0];
|
||||
while (typeof child !== "undefined") {
|
||||
clone.append(child);
|
||||
child = children[0];
|
||||
}
|
||||
node.replace(clone);
|
||||
node = this.editor.one('[data-iterate="true"]');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Change all tags with given type to a span with CSS class attribute.
|
||||
* @method changeToCSS
|
||||
* @param String tag Tag type to be changed to span
|
||||
* @param String markerClass CSS class that corresponds to desired tag
|
||||
*/
|
||||
changeToCSS: function(tag, markerClass) {
|
||||
// Save the selection.
|
||||
var selection = window.rangy.saveSelection();
|
||||
|
||||
// Remove display:none from rangy markers so browser doesn't delete them.
|
||||
this.editor.all('.rangySelectionBoundary').setStyle('display', null);
|
||||
|
||||
// Replace tags with CSS classes.
|
||||
this.editor.all(tag).addClass(markerClass);
|
||||
this.replaceTags(this.editor.all('.' + markerClass), 'span');
|
||||
|
||||
// Restore selection and toggle class.
|
||||
window.rangy.restoreSelection(selection);
|
||||
},
|
||||
|
||||
/**
|
||||
* Change spans with CSS classes in editor into elements with given tag.
|
||||
* @method changeToCSS
|
||||
* @param String markerClass CSS class that corresponds to desired tag
|
||||
* @param String tag New tag type to be created
|
||||
*/
|
||||
changeToTags: function(markerClass, tag) {
|
||||
// Save the selection.
|
||||
var selection = window.rangy.saveSelection();
|
||||
|
||||
// Remove display:none from rangy markers so browser doesn't delete them.
|
||||
this.editor.all('.rangySelectionBoundary').setStyle('display', null);
|
||||
|
||||
// Replace spans with given tag.
|
||||
this.replaceTags(this.editor.all('span[class="' + markerClass + '"]'), tag);
|
||||
this.editor.all(tag + '[class="' + markerClass + '"]').removeAttribute('class');
|
||||
this.editor.all('.' + markerClass).each(function(n) {
|
||||
n.wrap('<' + tag + '/>');
|
||||
n.removeClass(markerClass);
|
||||
});
|
||||
|
||||
// Remove CSS classes.
|
||||
this.editor.all('[class="' + markerClass + '"]').removeAttribute('class');
|
||||
this.editor.all(tag).removeClass(markerClass);
|
||||
|
||||
// Restore selection.
|
||||
window.rangy.restoreSelection(selection);
|
||||
}
|
||||
};
|
||||
|
||||
Y.Base.mix(Y.M.editor_atto.Editor, [EditorCommand]);
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* @module moodle-editor_atto-editor
|
||||
* @submodule toolbar
|
||||
@@ -2379,6 +2548,7 @@ Y.Base.mix(Y.M.editor_atto.Editor, [EditorFilepicker]);
|
||||
"event",
|
||||
"event-simulate",
|
||||
"event-custom",
|
||||
"node-event-html5",
|
||||
"yui-throttle",
|
||||
"moodle-core-notification-dialogue",
|
||||
"moodle-core-notification-confirm",
|
||||
|
||||
+10
-1
@@ -690,9 +690,18 @@ EditorPluginButtons.prototype = {
|
||||
inheritFrom = {};
|
||||
}
|
||||
|
||||
|
||||
// First we wrap the callback in function to handle formating of text inserted into collapsed selection.
|
||||
config.inlineFormat = config.inlineFormat || inheritFrom.inlineFormat;
|
||||
config._inlineCallback = config.callback || inheritFrom.callback;
|
||||
config._callback = config.callback || inheritFrom.callback;
|
||||
if (config.inlineFormat && typeof config._inlineCallback === 'function') {
|
||||
config._callback = function(e, args) {
|
||||
this.get('host').applyFormat(e, config._inlineCallback, this, args);
|
||||
};
|
||||
}
|
||||
// We wrap the callback in function to prevent the default action, check whether the editor is
|
||||
// active and focus it, and then mark the field as updated.
|
||||
config._callback = config.callback || inheritFrom.callback;
|
||||
config.callback = Y.rbind(this._callbackWrapper, this, config._callback, config.callbackArgs);
|
||||
|
||||
config._callbackNormalized = true;
|
||||
|
||||
+2
-2
File diff suppressed because one or more lines are too long
+10
-1
@@ -688,9 +688,18 @@ EditorPluginButtons.prototype = {
|
||||
inheritFrom = {};
|
||||
}
|
||||
|
||||
|
||||
// First we wrap the callback in function to handle formating of text inserted into collapsed selection.
|
||||
config.inlineFormat = config.inlineFormat || inheritFrom.inlineFormat;
|
||||
config._inlineCallback = config.callback || inheritFrom.callback;
|
||||
config._callback = config.callback || inheritFrom.callback;
|
||||
if (config.inlineFormat && typeof config._inlineCallback === 'function') {
|
||||
config._callback = function(e, args) {
|
||||
this.get('host').applyFormat(e, config._inlineCallback, this, args);
|
||||
};
|
||||
}
|
||||
// We wrap the callback in function to prevent the default action, check whether the editor is
|
||||
// active and focus it, and then mark the field as updated.
|
||||
config._callback = config.callback || inheritFrom.callback;
|
||||
config.callback = Y.rbind(this._callbackWrapper, this, config._callback, config.callbackArgs);
|
||||
|
||||
config._callbackNormalized = true;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"textarea.js",
|
||||
"autosave.js",
|
||||
"clean.js",
|
||||
"commands.js",
|
||||
"toolbar.js",
|
||||
"toolbar-keyboardnav.js",
|
||||
"selection.js",
|
||||
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* @module moodle-editor_atto-editor
|
||||
* @submodule commands
|
||||
*/
|
||||
|
||||
/**
|
||||
* Selection functions for the Atto editor.
|
||||
*
|
||||
* See {{#crossLink "M.editor_atto.Editor"}}{{/crossLink}} for details.
|
||||
*
|
||||
* @namespace M.editor_atto
|
||||
* @class EditorCommand
|
||||
*/
|
||||
|
||||
function EditorCommand() {}
|
||||
|
||||
EditorCommand.ATTRS= {
|
||||
};
|
||||
|
||||
EditorCommand.prototype = {
|
||||
/**
|
||||
* Applies a callback method to editor if selection is uncollapsed or waits for input to select first.
|
||||
* @method applyFormat
|
||||
* @param e EventTarget Event to be passed to callback if selection is uncollapsed
|
||||
* @param method callback A callback method which changes editor when text is selected.
|
||||
* @param object context Context to be used for callback method
|
||||
* @param array args Array of arguments to pass to callback
|
||||
*/
|
||||
applyFormat: function(e, callback, context, args) {
|
||||
function handleInsert(e, callback, context, args, anchorNode, anchorOffset) {
|
||||
// After something is inputed, select it and apply the formating function.
|
||||
Y.soon(Y.bind(function(e, callback, context, args, anchorNode, anchorOffset) {
|
||||
var selection = window.rangy.getSelection();
|
||||
|
||||
// Set the start of the selection to where it was when the method was first called.
|
||||
var range = selection.getRangeAt(0);
|
||||
range.setStart(anchorNode, anchorOffset);
|
||||
selection.setSingleRange(range);
|
||||
|
||||
// Now apply callback to the new text that is selected.
|
||||
callback.apply(context, [e, args]);
|
||||
|
||||
// Collapse selection so cursor is at end of inserted material.
|
||||
selection.collapseToEnd();
|
||||
}, this, e, callback, context, args, anchorNode, anchorOffset));
|
||||
}
|
||||
|
||||
// Set default context for the method.
|
||||
context = context || this;
|
||||
|
||||
// Check whether range is collapsed.
|
||||
var selection = window.rangy.getSelection();
|
||||
|
||||
if (selection.isCollapsed) {
|
||||
// Selection is collapsed so listen for input into editor.
|
||||
var handle = this.editor.once('input', handleInsert, this, callback, context, args,
|
||||
selection.anchorNode, selection.anchorOffset);
|
||||
|
||||
// Cancel if selection changes before input.
|
||||
this.editor.onceAfter(['click', 'selectstart'], handle.detach, handle);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// The range is not collapsed; so apply callback method immediately.
|
||||
callback.apply(context, [e, args]);
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Replaces all the tags in a node list with new type.
|
||||
* @method replaceTags
|
||||
* @param NodeList nodelist
|
||||
* @param String tag
|
||||
*/
|
||||
replaceTags: function(nodelist, tag) {
|
||||
// We mark elements in the node list for iterations.
|
||||
nodelist.setAttribute('data-iterate', true);
|
||||
var node = this.editor.one('[data-iterate="true"]');
|
||||
while (node) {
|
||||
var clone = Y.Node.create('<' + tag + ' />')
|
||||
.setAttrs(node.getAttrs())
|
||||
.removeAttribute('data-iterate');
|
||||
// Copy class and style if not blank.
|
||||
if (node.getAttribute('style')) {
|
||||
clone.setAttribute('style', node.getAttribute('style'));
|
||||
}
|
||||
if (node.getAttribute('class')) {
|
||||
clone.setAttribute('class', node.getAttribute('class'));
|
||||
}
|
||||
// We use childNodes here because we are interested in both type 1 and 3 child nodes.
|
||||
var children = node.getDOMNode().childNodes, child;
|
||||
child = children[0];
|
||||
while (typeof child !== "undefined") {
|
||||
clone.append(child);
|
||||
child = children[0];
|
||||
}
|
||||
node.replace(clone);
|
||||
node = this.editor.one('[data-iterate="true"]');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Change all tags with given type to a span with CSS class attribute.
|
||||
* @method changeToCSS
|
||||
* @param String tag Tag type to be changed to span
|
||||
* @param String markerClass CSS class that corresponds to desired tag
|
||||
*/
|
||||
changeToCSS: function(tag, markerClass) {
|
||||
// Save the selection.
|
||||
var selection = window.rangy.saveSelection();
|
||||
|
||||
// Remove display:none from rangy markers so browser doesn't delete them.
|
||||
this.editor.all('.rangySelectionBoundary').setStyle('display', null);
|
||||
|
||||
// Replace tags with CSS classes.
|
||||
this.editor.all(tag).addClass(markerClass);
|
||||
this.replaceTags(this.editor.all('.' + markerClass), 'span');
|
||||
|
||||
// Restore selection and toggle class.
|
||||
window.rangy.restoreSelection(selection);
|
||||
},
|
||||
|
||||
/**
|
||||
* Change spans with CSS classes in editor into elements with given tag.
|
||||
* @method changeToCSS
|
||||
* @param String markerClass CSS class that corresponds to desired tag
|
||||
* @param String tag New tag type to be created
|
||||
*/
|
||||
changeToTags: function(markerClass, tag) {
|
||||
// Save the selection.
|
||||
var selection = window.rangy.saveSelection();
|
||||
|
||||
// Remove display:none from rangy markers so browser doesn't delete them.
|
||||
this.editor.all('.rangySelectionBoundary').setStyle('display', null);
|
||||
|
||||
// Replace spans with given tag.
|
||||
this.replaceTags(this.editor.all('span[class="' + markerClass + '"]'), tag);
|
||||
this.editor.all(tag + '[class="' + markerClass + '"]').removeAttribute('class');
|
||||
this.editor.all('.' + markerClass).each(function(n) {
|
||||
n.wrap('<' + tag + '/>');
|
||||
n.removeClass(markerClass);
|
||||
});
|
||||
|
||||
// Remove CSS classes.
|
||||
this.editor.all('[class="' + markerClass + '"]').removeAttribute('class');
|
||||
this.editor.all(tag).removeClass(markerClass);
|
||||
|
||||
// Restore selection.
|
||||
window.rangy.restoreSelection(selection);
|
||||
}
|
||||
};
|
||||
|
||||
Y.Base.mix(Y.M.editor_atto.Editor, [EditorCommand]);
|
||||
+10
-1
@@ -540,9 +540,18 @@ EditorPluginButtons.prototype = {
|
||||
inheritFrom = {};
|
||||
}
|
||||
|
||||
|
||||
// First we wrap the callback in function to handle formating of text inserted into collapsed selection.
|
||||
config.inlineFormat = config.inlineFormat || inheritFrom.inlineFormat;
|
||||
config._inlineCallback = config.callback || inheritFrom.callback;
|
||||
config._callback = config.callback || inheritFrom.callback;
|
||||
if (config.inlineFormat && typeof config._inlineCallback === 'function') {
|
||||
config._callback = function(e, args) {
|
||||
this.get('host').applyFormat(e, config._inlineCallback, this, args);
|
||||
};
|
||||
}
|
||||
// We wrap the callback in function to prevent the default action, check whether the editor is
|
||||
// active and focus it, and then mark the field as updated.
|
||||
config._callback = config.callback || inheritFrom.callback;
|
||||
config.callback = Y.rbind(this._callbackWrapper, this, config._callback, config.callbackArgs);
|
||||
|
||||
config._callbackNormalized = true;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"event",
|
||||
"event-simulate",
|
||||
"event-custom",
|
||||
"node-event-html5",
|
||||
"yui-throttle",
|
||||
"moodle-core-notification-dialogue",
|
||||
"moodle-core-notification-confirm",
|
||||
|
||||
Reference in New Issue
Block a user