--- a/src/pyams_skin/resources/js/ext/tinymce/dev/classes/EditorCommands.js Sun Jul 19 02:02:20 2020 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,999 +0,0 @@
-/**
- * EditorCommands.js
- *
- * Copyright, Moxiecode Systems AB
- * Released under LGPL License.
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
-
-/**
- * This class enables you to add custom editor commands and it contains
- * overrides for native browser commands to address various bugs and issues.
- *
- * @class tinymce.EditorCommands
- */
-define("tinymce/EditorCommands", [
- "tinymce/html/Serializer",
- "tinymce/Env",
- "tinymce/util/Tools",
- "tinymce/dom/ElementUtils",
- "tinymce/dom/RangeUtils",
- "tinymce/dom/TreeWalker"
-], function(Serializer, Env, Tools, ElementUtils, RangeUtils, TreeWalker) {
- // Added for compression purposes
- var each = Tools.each, extend = Tools.extend;
- var map = Tools.map, inArray = Tools.inArray, explode = Tools.explode;
- var isGecko = Env.gecko, isIE = Env.ie, isOldIE = Env.ie && Env.ie < 11;
- var TRUE = true, FALSE = false;
-
- return function(editor) {
- var dom, selection, formatter,
- commands = {state: {}, exec: {}, value: {}},
- settings = editor.settings,
- bookmark;
-
- editor.on('PreInit', function() {
- dom = editor.dom;
- selection = editor.selection;
- settings = editor.settings;
- formatter = editor.formatter;
- });
-
- /**
- * Executes the specified command.
- *
- * @method execCommand
- * @param {String} command Command to execute.
- * @param {Boolean} ui Optional user interface state.
- * @param {Object} value Optional value for command.
- * @return {Boolean} true/false if the command was found or not.
- */
- function execCommand(command, ui, value, args) {
- var func, customCommand, state = 0;
-
- if (!/^(mceAddUndoLevel|mceEndUndoLevel|mceBeginUndoLevel|mceRepaint)$/.test(command) && (!args || !args.skip_focus)) {
- editor.focus();
- }
-
- args = extend({}, args);
- args = editor.fire('BeforeExecCommand', {command: command, ui: ui, value: value});
- if (args.isDefaultPrevented()) {
- return false;
- }
-
- customCommand = command.toLowerCase();
- if ((func = commands.exec[customCommand])) {
- func(customCommand, ui, value);
- editor.fire('ExecCommand', {command: command, ui: ui, value: value});
- return true;
- }
-
- // Plugin commands
- each(editor.plugins, function(p) {
- if (p.execCommand && p.execCommand(command, ui, value)) {
- editor.fire('ExecCommand', {command: command, ui: ui, value: value});
- state = true;
- return false;
- }
- });
-
- if (state) {
- return state;
- }
-
- // Theme commands
- if (editor.theme && editor.theme.execCommand && editor.theme.execCommand(command, ui, value)) {
- editor.fire('ExecCommand', {command: command, ui: ui, value: value});
- return true;
- }
-
- // Browser commands
- try {
- state = editor.getDoc().execCommand(command, ui, value);
- } catch (ex) {
- // Ignore old IE errors
- }
-
- if (state) {
- editor.fire('ExecCommand', {command: command, ui: ui, value: value});
- return true;
- }
-
- return false;
- }
-
- /**
- * Queries the current state for a command for example if the current selection is "bold".
- *
- * @method queryCommandState
- * @param {String} command Command to check the state of.
- * @return {Boolean/Number} true/false if the selected contents is bold or not, -1 if it's not found.
- */
- function queryCommandState(command) {
- var func;
-
- // Is hidden then return undefined
- if (editor._isHidden()) {
- return;
- }
-
- command = command.toLowerCase();
- if ((func = commands.state[command])) {
- return func(command);
- }
-
- // Browser commands
- try {
- return editor.getDoc().queryCommandState(command);
- } catch (ex) {
- // Fails sometimes see bug: 1896577
- }
-
- return false;
- }
-
- /**
- * Queries the command value for example the current fontsize.
- *
- * @method queryCommandValue
- * @param {String} command Command to check the value of.
- * @return {Object} Command value of false if it's not found.
- */
- function queryCommandValue(command) {
- var func;
-
- // Is hidden then return undefined
- if (editor._isHidden()) {
- return;
- }
-
- command = command.toLowerCase();
- if ((func = commands.value[command])) {
- return func(command);
- }
-
- // Browser commands
- try {
- return editor.getDoc().queryCommandValue(command);
- } catch (ex) {
- // Fails sometimes see bug: 1896577
- }
- }
-
- /**
- * Adds commands to the command collection.
- *
- * @method addCommands
- * @param {Object} command_list Name/value collection with commands to add, the names can also be comma separated.
- * @param {String} type Optional type to add, defaults to exec. Can be value or state as well.
- */
- function addCommands(command_list, type) {
- type = type || 'exec';
-
- each(command_list, function(callback, command) {
- each(command.toLowerCase().split(','), function(command) {
- commands[type][command] = callback;
- });
- });
- }
-
- function addCommand(command, callback, scope) {
- command = command.toLowerCase();
- commands.exec[command] = function(command, ui, value, args) {
- return callback.call(scope || editor, ui, value, args);
- };
- }
-
- /**
- * Returns true/false if the command is supported or not.
- *
- * @method queryCommandSupported
- * @param {String} cmd Command that we check support for.
- * @return {Boolean} true/false if the command is supported or not.
- */
- function queryCommandSupported(command) {
- command = command.toLowerCase();
-
- if (commands.exec[command]) {
- return true;
- }
-
- // Browser commands
- try {
- return editor.getDoc().queryCommandSupported(command);
- } catch (ex) {
- // Fails sometimes see bug: 1896577
- }
-
- return false;
- }
-
- function addQueryStateHandler(command, callback, scope) {
- command = command.toLowerCase();
- commands.state[command] = function() {
- return callback.call(scope || editor);
- };
- }
-
- function addQueryValueHandler(command, callback, scope) {
- command = command.toLowerCase();
- commands.value[command] = function() {
- return callback.call(scope || editor);
- };
- }
-
- function hasCustomCommand(command) {
- command = command.toLowerCase();
- return !!commands.exec[command];
- }
-
- // Expose public methods
- extend(this, {
- execCommand: execCommand,
- queryCommandState: queryCommandState,
- queryCommandValue: queryCommandValue,
- queryCommandSupported: queryCommandSupported,
- addCommands: addCommands,
- addCommand: addCommand,
- addQueryStateHandler: addQueryStateHandler,
- addQueryValueHandler: addQueryValueHandler,
- hasCustomCommand: hasCustomCommand
- });
-
- // Private methods
-
- function execNativeCommand(command, ui, value) {
- if (ui === undefined) {
- ui = FALSE;
- }
-
- if (value === undefined) {
- value = null;
- }
-
- return editor.getDoc().execCommand(command, ui, value);
- }
-
- function isFormatMatch(name) {
- return formatter.match(name);
- }
-
- function toggleFormat(name, value) {
- formatter.toggle(name, value ? {value: value} : undefined);
- editor.nodeChanged();
- }
-
- function storeSelection(type) {
- bookmark = selection.getBookmark(type);
- }
-
- function restoreSelection() {
- selection.moveToBookmark(bookmark);
- }
-
- // Add execCommand overrides
- addCommands({
- // Ignore these, added for compatibility
- 'mceResetDesignMode,mceBeginUndoLevel': function() {},
-
- // Add undo manager logic
- 'mceEndUndoLevel,mceAddUndoLevel': function() {
- editor.undoManager.add();
- },
-
- 'Cut,Copy,Paste': function(command) {
- var doc = editor.getDoc(), failed;
-
- // Try executing the native command
- try {
- execNativeCommand(command);
- } catch (ex) {
- // Command failed
- failed = TRUE;
- }
-
- // Present alert message about clipboard access not being available
- if (failed || !doc.queryCommandSupported(command)) {
- var msg = editor.translate(
- "Your browser doesn't support direct access to the clipboard. " +
- "Please use the Ctrl+X/C/V keyboard shortcuts instead."
- );
-
- if (Env.mac) {
- msg = msg.replace(/Ctrl\+/g, '\u2318+');
- }
-
- editor.windowManager.alert(msg);
- }
- },
-
- // Override unlink command
- unlink: function() {
- if (selection.isCollapsed()) {
- var elm = selection.getNode();
- if (elm.tagName == 'A') {
- editor.dom.remove(elm, true);
- }
-
- return;
- }
-
- formatter.remove("link");
- },
-
- // Override justify commands to use the text formatter engine
- 'JustifyLeft,JustifyCenter,JustifyRight,JustifyFull': function(command) {
- var align = command.substring(7);
-
- if (align == 'full') {
- align = 'justify';
- }
-
- // Remove all other alignments first
- each('left,center,right,justify'.split(','), function(name) {
- if (align != name) {
- formatter.remove('align' + name);
- }
- });
-
- toggleFormat('align' + align);
- execCommand('mceRepaint');
- },
-
- // Override list commands to fix WebKit bug
- 'InsertUnorderedList,InsertOrderedList': function(command) {
- var listElm, listParent;
-
- execNativeCommand(command);
-
- // WebKit produces lists within block elements so we need to split them
- // we will replace the native list creation logic to custom logic later on
- // TODO: Remove this when the list creation logic is removed
- listElm = dom.getParent(selection.getNode(), 'ol,ul');
- if (listElm) {
- listParent = listElm.parentNode;
-
- // If list is within a text block then split that block
- if (/^(H[1-6]|P|ADDRESS|PRE)$/.test(listParent.nodeName)) {
- storeSelection();
- dom.split(listParent, listElm);
- restoreSelection();
- }
- }
- },
-
- // Override commands to use the text formatter engine
- 'Bold,Italic,Underline,Strikethrough,Superscript,Subscript': function(command) {
- toggleFormat(command);
- },
-
- // Override commands to use the text formatter engine
- 'ForeColor,HiliteColor,FontName': function(command, ui, value) {
- toggleFormat(command, value);
- },
-
- FontSize: function(command, ui, value) {
- var fontClasses, fontSizes;
-
- // Convert font size 1-7 to styles
- if (value >= 1 && value <= 7) {
- fontSizes = explode(settings.font_size_style_values);
- fontClasses = explode(settings.font_size_classes);
-
- if (fontClasses) {
- value = fontClasses[value - 1] || value;
- } else {
- value = fontSizes[value - 1] || value;
- }
- }
-
- toggleFormat(command, value);
- },
-
- RemoveFormat: function(command) {
- formatter.remove(command);
- },
-
- mceBlockQuote: function() {
- toggleFormat('blockquote');
- },
-
- FormatBlock: function(command, ui, value) {
- return toggleFormat(value || 'p');
- },
-
- mceCleanup: function() {
- var bookmark = selection.getBookmark();
-
- editor.setContent(editor.getContent({cleanup: TRUE}), {cleanup: TRUE});
-
- selection.moveToBookmark(bookmark);
- },
-
- mceRemoveNode: function(command, ui, value) {
- var node = value || selection.getNode();
-
- // Make sure that the body node isn't removed
- if (node != editor.getBody()) {
- storeSelection();
- editor.dom.remove(node, TRUE);
- restoreSelection();
- }
- },
-
- mceSelectNodeDepth: function(command, ui, value) {
- var counter = 0;
-
- dom.getParent(selection.getNode(), function(node) {
- if (node.nodeType == 1 && counter++ == value) {
- selection.select(node);
- return FALSE;
- }
- }, editor.getBody());
- },
-
- mceSelectNode: function(command, ui, value) {
- selection.select(value);
- },
-
- mceInsertContent: function(command, ui, value) {
- var parser, serializer, parentNode, rootNode, fragment, args;
- var marker, rng, node, node2, bookmarkHtml, merge;
- var textInlineElements = editor.schema.getTextInlineElements();
-
- function trimOrPaddLeftRight(html) {
- var rng, container, offset;
-
- rng = selection.getRng(true);
- container = rng.startContainer;
- offset = rng.startOffset;
-
- function hasSiblingText(siblingName) {
- return container[siblingName] && container[siblingName].nodeType == 3;
- }
-
- if (container.nodeType == 3) {
- if (offset > 0) {
- html = html.replace(/^ /, ' ');
- } else if (!hasSiblingText('previousSibling')) {
- html = html.replace(/^ /, ' ');
- }
-
- if (offset < container.length) {
- html = html.replace(/ (<br>|)$/, ' ');
- } else if (!hasSiblingText('nextSibling')) {
- html = html.replace(/( | )(<br>|)$/, ' ');
- }
- }
-
- return html;
- }
-
- // Removes from a [b] c -> a c -> a c
- function trimNbspAfterDeleteAndPaddValue() {
- var rng, container, offset;
-
- rng = selection.getRng(true);
- container = rng.startContainer;
- offset = rng.startOffset;
-
- if (container.nodeType == 3 && rng.collapsed) {
- if (container.data[offset] === '\u00a0') {
- container.deleteData(offset, 1);
-
- if (!/[\u00a0| ]$/.test(value)) {
- value += ' ';
- }
- } else if (container.data[offset - 1] === '\u00a0') {
- container.deleteData(offset - 1, 1);
-
- if (!/[\u00a0| ]$/.test(value)) {
- value = ' ' + value;
- }
- }
- }
- }
-
- function markInlineFormatElements(fragment) {
- if (merge) {
- for (node = fragment.firstChild; node; node = node.walk(true)) {
- if (textInlineElements[node.name]) {
- node.attr('data-mce-new', "true");
- }
- }
- }
- }
-
- function reduceInlineTextElements() {
- if (merge) {
- var root = editor.getBody(), elementUtils = new ElementUtils(dom);
-
- each(dom.select('*[data-mce-new]'), function(node) {
- node.removeAttribute('data-mce-new');
-
- for (var testNode = node.parentNode; testNode && testNode != root; testNode = testNode.parentNode) {
- if (elementUtils.compare(testNode, node)) {
- dom.remove(node, true);
- }
- }
- });
- }
- }
-
- if (typeof value != 'string') {
- merge = value.merge;
- value = value.content;
- }
-
- // Check for whitespace before/after value
- if (/^ | $/.test(value)) {
- value = trimOrPaddLeftRight(value);
- }
-
- // Setup parser and serializer
- parser = editor.parser;
- serializer = new Serializer({}, editor.schema);
- bookmarkHtml = '<span id="mce_marker" data-mce-type="bookmark">​</span>';
-
- // Run beforeSetContent handlers on the HTML to be inserted
- args = {content: value, format: 'html', selection: true};
- editor.fire('BeforeSetContent', args);
- value = args.content;
-
- // Add caret at end of contents if it's missing
- if (value.indexOf('{$caret}') == -1) {
- value += '{$caret}';
- }
-
- // Replace the caret marker with a span bookmark element
- value = value.replace(/\{\$caret\}/, bookmarkHtml);
-
- // If selection is at <body>|<p></p> then move it into <body><p>|</p>
- rng = selection.getRng();
- var caretElement = rng.startContainer || (rng.parentElement ? rng.parentElement() : null);
- var body = editor.getBody();
- if (caretElement === body && selection.isCollapsed()) {
- if (dom.isBlock(body.firstChild) && dom.isEmpty(body.firstChild)) {
- rng = dom.createRng();
- rng.setStart(body.firstChild, 0);
- rng.setEnd(body.firstChild, 0);
- selection.setRng(rng);
- }
- }
-
- // Insert node maker where we will insert the new HTML and get it's parent
- if (!selection.isCollapsed()) {
- editor.getDoc().execCommand('Delete', false, null);
- trimNbspAfterDeleteAndPaddValue();
- }
-
- parentNode = selection.getNode();
-
- // Parse the fragment within the context of the parent node
- var parserArgs = {context: parentNode.nodeName.toLowerCase()};
- fragment = parser.parse(value, parserArgs);
-
- markInlineFormatElements(fragment);
-
- // Move the caret to a more suitable location
- node = fragment.lastChild;
- if (node.attr('id') == 'mce_marker') {
- marker = node;
-
- for (node = node.prev; node; node = node.walk(true)) {
- if (node.type == 3 || !dom.isBlock(node.name)) {
- if (editor.schema.isValidChild(node.parent.name, 'span')) {
- node.parent.insert(marker, node, node.name === 'br');
- }
- break;
- }
- }
- }
-
- // If parser says valid we can insert the contents into that parent
- if (!parserArgs.invalid) {
- value = serializer.serialize(fragment);
-
- // Check if parent is empty or only has one BR element then set the innerHTML of that parent
- node = parentNode.firstChild;
- node2 = parentNode.lastChild;
- if (!node || (node === node2 && node.nodeName === 'BR')) {
- dom.setHTML(parentNode, value);
- } else {
- selection.setContent(value);
- }
- } else {
- // If the fragment was invalid within that context then we need
- // to parse and process the parent it's inserted into
-
- // Insert bookmark node and get the parent
- selection.setContent(bookmarkHtml);
- parentNode = selection.getNode();
- rootNode = editor.getBody();
-
- // Opera will return the document node when selection is in root
- if (parentNode.nodeType == 9) {
- parentNode = node = rootNode;
- } else {
- node = parentNode;
- }
-
- // Find the ancestor just before the root element
- while (node !== rootNode) {
- parentNode = node;
- node = node.parentNode;
- }
-
- // Get the outer/inner HTML depending on if we are in the root and parser and serialize that
- value = parentNode == rootNode ? rootNode.innerHTML : dom.getOuterHTML(parentNode);
- value = serializer.serialize(
- parser.parse(
- // Need to replace by using a function since $ in the contents would otherwise be a problem
- value.replace(/<span (id="mce_marker"|id=mce_marker).+?<\/span>/i, function() {
- return serializer.serialize(fragment);
- })
- )
- );
-
- // Set the inner/outer HTML depending on if we are in the root or not
- if (parentNode == rootNode) {
- dom.setHTML(rootNode, value);
- } else {
- dom.setOuterHTML(parentNode, value);
- }
- }
-
- reduceInlineTextElements();
-
- marker = dom.get('mce_marker');
- selection.scrollIntoView(marker);
-
- // Move selection before marker and remove it
- rng = dom.createRng();
-
- // If previous sibling is a text node set the selection to the end of that node
- node = marker.previousSibling;
- if (node && node.nodeType == 3) {
- rng.setStart(node, node.nodeValue.length);
-
- // TODO: Why can't we normalize on IE
- if (!isIE) {
- node2 = marker.nextSibling;
- if (node2 && node2.nodeType == 3) {
- node.appendData(node2.data);
- node2.parentNode.removeChild(node2);
- }
- }
- } else {
- // If the previous sibling isn't a text node or doesn't exist set the selection before the marker node
- rng.setStartBefore(marker);
- rng.setEndBefore(marker);
- }
-
- // Remove the marker node and set the new range
- dom.remove(marker);
- selection.setRng(rng);
-
- // Dispatch after event and add any visual elements needed
- editor.fire('SetContent', args);
- editor.addVisual();
- },
-
- mceInsertRawHTML: function(command, ui, value) {
- selection.setContent('tiny_mce_marker');
- editor.setContent(
- editor.getContent().replace(/tiny_mce_marker/g, function() {
- return value;
- })
- );
- },
-
- mceToggleFormat: function(command, ui, value) {
- toggleFormat(value);
- },
-
- mceSetContent: function(command, ui, value) {
- editor.setContent(value);
- },
-
- 'Indent,Outdent': function(command) {
- var intentValue, indentUnit, value;
-
- // Setup indent level
- intentValue = settings.indentation;
- indentUnit = /[a-z%]+$/i.exec(intentValue);
- intentValue = parseInt(intentValue, 10);
-
- if (!queryCommandState('InsertUnorderedList') && !queryCommandState('InsertOrderedList')) {
- // If forced_root_blocks is set to false we don't have a block to indent so lets create a div
- if (!settings.forced_root_block && !dom.getParent(selection.getNode(), dom.isBlock)) {
- formatter.apply('div');
- }
-
- each(selection.getSelectedBlocks(), function(element) {
- if (element.nodeName != "LI") {
- var indentStyleName = editor.getParam('indent_use_margin', false) ? 'margin' : 'padding';
-
- indentStyleName += dom.getStyle(element, 'direction', true) == 'rtl' ? 'Right' : 'Left';
-
- if (command == 'outdent') {
- value = Math.max(0, parseInt(element.style[indentStyleName] || 0, 10) - intentValue);
- dom.setStyle(element, indentStyleName, value ? value + indentUnit : '');
- } else {
- value = (parseInt(element.style[indentStyleName] || 0, 10) + intentValue) + indentUnit;
- dom.setStyle(element, indentStyleName, value);
- }
- }
- });
- } else {
- execNativeCommand(command);
- }
- },
-
- mceRepaint: function() {
- if (isGecko) {
- try {
- storeSelection(TRUE);
-
- if (selection.getSel()) {
- selection.getSel().selectAllChildren(editor.getBody());
- }
-
- selection.collapse(TRUE);
- restoreSelection();
- } catch (ex) {
- // Ignore
- }
- }
- },
-
- InsertHorizontalRule: function() {
- editor.execCommand('mceInsertContent', false, '<hr />');
- },
-
- mceToggleVisualAid: function() {
- editor.hasVisual = !editor.hasVisual;
- editor.addVisual();
- },
-
- mceReplaceContent: function(command, ui, value) {
- editor.execCommand('mceInsertContent', false, value.replace(/\{\$selection\}/g, selection.getContent({format: 'text'})));
- },
-
- mceInsertLink: function(command, ui, value) {
- var anchor;
-
- if (typeof value == 'string') {
- value = {href: value};
- }
-
- anchor = dom.getParent(selection.getNode(), 'a');
-
- // Spaces are never valid in URLs and it's a very common mistake for people to make so we fix it here.
- value.href = value.href.replace(' ', '%20');
-
- // Remove existing links if there could be child links or that the href isn't specified
- if (!anchor || !value.href) {
- formatter.remove('link');
- }
-
- // Apply new link to selection
- if (value.href) {
- formatter.apply('link', value, anchor);
- }
- },
-
- selectAll: function() {
- var root = dom.getRoot(), rng;
-
- if (selection.getRng().setStart) {
- rng = dom.createRng();
- rng.setStart(root, 0);
- rng.setEnd(root, root.childNodes.length);
- selection.setRng(rng);
- } else {
- // IE will render it's own root level block elements and sometimes
- // even put font elements in them when the user starts typing. So we need to
- // move the selection to a more suitable element from this:
- // <body>|<p></p></body> to this: <body><p>|</p></body>
- rng = selection.getRng();
- if (!rng.item) {
- rng.moveToElementText(root);
- rng.select();
- }
- }
- },
-
- "delete": function() {
- execNativeCommand("Delete");
-
- // Check if body is empty after the delete call if so then set the contents
- // to an empty string and move the caret to any block produced by that operation
- // this fixes the issue with root blocks not being properly produced after a delete call on IE
- var body = editor.getBody();
-
- if (dom.isEmpty(body)) {
- editor.setContent('');
-
- if (body.firstChild && dom.isBlock(body.firstChild)) {
- editor.selection.setCursorLocation(body.firstChild, 0);
- } else {
- editor.selection.setCursorLocation(body, 0);
- }
- }
- },
-
- mceNewDocument: function() {
- editor.setContent('');
- },
-
- InsertLineBreak: function(command, ui, value) {
- // We load the current event in from EnterKey.js when appropriate to heed
- // certain event-specific variations such as ctrl-enter in a list
- var evt = value;
- var brElm, extraBr, marker;
- var rng = selection.getRng(true);
- new RangeUtils(dom).normalize(rng);
-
- var offset = rng.startOffset;
- var container = rng.startContainer;
-
- // Resolve node index
- if (container.nodeType == 1 && container.hasChildNodes()) {
- var isAfterLastNodeInContainer = offset > container.childNodes.length - 1;
-
- container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
- if (isAfterLastNodeInContainer && container.nodeType == 3) {
- offset = container.nodeValue.length;
- } else {
- offset = 0;
- }
- }
-
- var parentBlock = dom.getParent(container, dom.isBlock);
- var parentBlockName = parentBlock ? parentBlock.nodeName.toUpperCase() : ''; // IE < 9 & HTML5
- var containerBlock = parentBlock ? dom.getParent(parentBlock.parentNode, dom.isBlock) : null;
- var containerBlockName = containerBlock ? containerBlock.nodeName.toUpperCase() : ''; // IE < 9 & HTML5
-
- // Enter inside block contained within a LI then split or insert before/after LI
- var isControlKey = evt && evt.ctrlKey;
- if (containerBlockName == 'LI' && !isControlKey) {
- parentBlock = containerBlock;
- parentBlockName = containerBlockName;
- }
-
- // Walks the parent block to the right and look for BR elements
- function hasRightSideContent() {
- var walker = new TreeWalker(container, parentBlock), node;
- var nonEmptyElementsMap = editor.schema.getNonEmptyElements();
-
- while ((node = walker.next())) {
- if (nonEmptyElementsMap[node.nodeName.toLowerCase()] || node.length > 0) {
- return true;
- }
- }
- }
-
- if (container && container.nodeType == 3 && offset >= container.nodeValue.length) {
- // Insert extra BR element at the end block elements
- if (!isOldIE && !hasRightSideContent()) {
- brElm = dom.create('br');
- rng.insertNode(brElm);
- rng.setStartAfter(brElm);
- rng.setEndAfter(brElm);
- extraBr = true;
- }
- }
-
- brElm = dom.create('br');
- rng.insertNode(brElm);
-
- // Rendering modes below IE8 doesn't display BR elements in PRE unless we have a \n before it
- var documentMode = dom.doc.documentMode;
- if (isOldIE && parentBlockName == 'PRE' && (!documentMode || documentMode < 8)) {
- brElm.parentNode.insertBefore(dom.doc.createTextNode('\r'), brElm);
- }
-
- // Insert temp marker and scroll to that
- marker = dom.create('span', {}, ' ');
- brElm.parentNode.insertBefore(marker, brElm);
- selection.scrollIntoView(marker);
- dom.remove(marker);
-
- if (!extraBr) {
- rng.setStartAfter(brElm);
- rng.setEndAfter(brElm);
- } else {
- rng.setStartBefore(brElm);
- rng.setEndBefore(brElm);
- }
-
- selection.setRng(rng);
- editor.undoManager.add();
-
- return TRUE;
- }
- });
-
- // Add queryCommandState overrides
- addCommands({
- // Override justify commands
- 'JustifyLeft,JustifyCenter,JustifyRight,JustifyFull': function(command) {
- var name = 'align' + command.substring(7);
- var nodes = selection.isCollapsed() ? [dom.getParent(selection.getNode(), dom.isBlock)] : selection.getSelectedBlocks();
- var matches = map(nodes, function(node) {
- return !!formatter.matchNode(node, name);
- });
- return inArray(matches, TRUE) !== -1;
- },
-
- 'Bold,Italic,Underline,Strikethrough,Superscript,Subscript': function(command) {
- return isFormatMatch(command);
- },
-
- mceBlockQuote: function() {
- return isFormatMatch('blockquote');
- },
-
- Outdent: function() {
- var node;
-
- if (settings.inline_styles) {
- if ((node = dom.getParent(selection.getStart(), dom.isBlock)) && parseInt(node.style.paddingLeft, 10) > 0) {
- return TRUE;
- }
-
- if ((node = dom.getParent(selection.getEnd(), dom.isBlock)) && parseInt(node.style.paddingLeft, 10) > 0) {
- return TRUE;
- }
- }
-
- return (
- queryCommandState('InsertUnorderedList') ||
- queryCommandState('InsertOrderedList') ||
- (!settings.inline_styles && !!dom.getParent(selection.getNode(), 'BLOCKQUOTE'))
- );
- },
-
- 'InsertUnorderedList,InsertOrderedList': function(command) {
- var list = dom.getParent(selection.getNode(), 'ul,ol');
-
- return list &&
- (
- command === 'insertunorderedlist' && list.tagName === 'UL' ||
- command === 'insertorderedlist' && list.tagName === 'OL'
- );
- }
- }, 'state');
-
- // Add queryCommandValue overrides
- addCommands({
- 'FontSize,FontName': function(command) {
- var value = 0, parent;
-
- if ((parent = dom.getParent(selection.getNode(), 'span'))) {
- if (command == 'fontsize') {
- value = parent.style.fontSize;
- } else {
- value = parent.style.fontFamily.replace(/, /g, ',').replace(/[\'\"]/g, '').toLowerCase();
- }
- }
-
- return value;
- }
- }, 'value');
-
- // Add undo manager logic
- addCommands({
- Undo: function() {
- editor.undoManager.undo();
- },
-
- Redo: function() {
- editor.undoManager.redo();
- }
- });
- };
-});