1 /* command.js is part of Aloha Editor project http://aloha-editor.org 2 * 3 * Aloha Editor is a WYSIWYG HTML5 inline editing library and editor. 4 * Copyright (c) 2010-2012 Gentics Software GmbH, Vienna, Austria. 5 * Contributors http://aloha-editor.org/contribution.php 6 * 7 * Aloha Editor is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or any later version. 11 * 12 * Aloha Editor is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 * As an additional permission to the GNU GPL version 2, you may distribute 22 * non-source (e.g., minimized or compacted) forms of the Aloha-Editor 23 * source code without the copy of the GNU GPL normally required, 24 * provided you include this license notice and a URL through which 25 * recipients can access the Corresponding Source. 26 */ 27 define([ 28 'aloha/core', 29 'aloha/registry', 30 'aloha/engine', 31 'util/dom', 32 'aloha/contenthandlermanager' 33 ], function ( 34 Aloha, 35 Registry, 36 Engine, 37 Dom, 38 ContentHandlerManager 39 ) { 40 "use strict"; 41 42 // Action: What the command does when executed via execCommand(). Every command defined 43 // in CommandManager specification has an action defined for it in the relevant section. For example, 44 // the bold command's action generally makes the current selection bold, or removes bold if 45 // the selection is already bold. An editing toolbar might provide buttons that execute the 46 // action for a command if clicked, or a script might run an action without user interaction 47 // to achieve some particular effect. 48 // 49 // Indeterminate: A boolean value returned by queryCommandIndeterm(), depending on the 50 // current state of the document. Generally, a command that has a state defined will be 51 // indeterminate if the state is true for part but not all of the current selection, and a 52 // command that has a value defined will be indeterminate if different parts of the 53 // selection have different values. An editing toolbar might display a button or control 54 // in a special way if the command is indeterminate, like showing a "bold" button as 55 // partially depressed, or leaving a font size selector blank instead of showing the font 56 // size of the current selection. As a rule, a command can only be indeterminate if its 57 // state is false, supposing it has a state. 58 // 59 // State: A boolean value returned by queryCommandState(), depending on the current state 60 // of the document. The state of a command is true if it is already in effect, in some 61 // sense specific to the command. Most commands that have a state defined will take opposite 62 // actions depending on whether the state is true or false, such as making the selection 63 // bold if the state is false and removing bold if the state is true. Others will just 64 // have no effect if the state is true, like the justifyCenter command. Still others will 65 // have the same effect regardless, like the styleWithCss command. An editing toolbar might 66 // display a button or control differently depending on the state and indeterminacy of the 67 // command. 68 // 69 // Value: A string returned by queryCommandValue(), depending on the current state of the 70 // document. A command usually has a value instead of a state if the property it modifies 71 // can take more than two different values, like the foreColor command. If the command is 72 // indeterminate, its value is generally based on the start of the selection. Otherwise, 73 // in most cases the value holds true for the entire selection, but see the justifyCenter 74 // command and its three companions for an exception. An editing toolbar might display the 75 // value of a command as selected in a drop-down or filled in in a text box, if the command 76 // isn't indeterminate. 77 // 78 // Relevant CSS property: CommandManager is defined for certain inline formatting commands, and 79 // is used in algorithms specific to those commands. It is an implementation detail, and 80 // is not exposed to authors. If a command does not have a relevant CSS property 81 // specified, it defaults to null. 82 83 var CommandManager = { 84 85 execCommand: function (commandId, showUi, value, range) { 86 var eventData = { 87 commandId: commandId, 88 preventDefault: false 89 }; 90 91 Aloha.trigger('aloha-command-will-execute', eventData); 92 93 if (eventData.preventDefault === true) { 94 return; 95 } 96 97 var selection = Aloha.getSelection(); 98 if (!range) { 99 if (!selection.getRangeCount()) { 100 return; 101 } 102 range = selection.getRangeAt(0); 103 } 104 105 if (commandId.toLowerCase() === 'inserthtml') { 106 value = ContentHandlerManager.handleContent(value, { 107 contenthandler: Aloha.settings.contentHandler.insertHtml, 108 command: 'insertHtml' 109 }); 110 } 111 112 Engine.execCommand(commandId, showUi, value, range); 113 114 // Because there is never a situation where it will be necessary to 115 // do any further cleanup (merging of similar adjacent nodes) 116 if ('insertparagraph' !== commandId.toLowerCase() 117 && selection.getRangeCount()) { 118 119 range = selection.getRangeAt(0); 120 121 // FIX: doCleanup should work with W3C range 122 var start = range.commonAncestorContainer; 123 if (start.parentNode) { 124 start = start.parentNode; 125 } 126 127 var rangeObject = new window.GENTICS.Utils.RangeObject(); 128 rangeObject.startContainer = range.startContainer; 129 rangeObject.startOffset = range.startOffset; 130 rangeObject.endContainer = range.endContainer; 131 rangeObject.endOffset = range.endOffset; 132 133 Dom.doCleanup({ 134 merge: true, 135 removeempty: false 136 }, rangeObject, start); 137 138 rangeObject.select(); 139 } 140 141 Aloha.trigger('aloha-command-executed', commandId); 142 }, 143 144 // If command is available and not disabled or the active range is not null 145 // the command is enabled 146 queryCommandEnabled: function (commandId, range) { 147 148 // Take current selection if not passed 149 if (!range) { 150 if (!Aloha.getSelection().getRangeCount()) { 151 return; 152 } 153 range = Aloha.getSelection().getRangeAt(0); 154 } 155 return Engine.queryCommandEnabled(commandId, range); 156 }, 157 158 // "Return true if command is indeterminate, otherwise false." 159 queryCommandIndeterm: function (commandId, range) { 160 161 // Take current selection if not passed 162 if (!range) { 163 if (!Aloha.getSelection().getRangeCount()) { 164 return; 165 } 166 range = Aloha.getSelection().getRangeAt(0); 167 } 168 return Engine.queryCommandIndeterm(commandId, range); 169 170 }, 171 172 queryCommandState: function (commandId, range) { 173 174 // Take current selection if not passed 175 if (!range) { 176 if (!Aloha.getSelection().getRangeCount()) { 177 return; 178 } 179 range = Aloha.getSelection().getRangeAt(0); 180 } 181 return Engine.queryCommandState(commandId, range); 182 183 }, 184 185 // "When the queryCommandSupported(command) method on the HTMLDocument 186 // interface is invoked, the user agent must return true if command is 187 // supported, and false otherwise." 188 queryCommandSupported: function (commandId) { 189 190 return Engine.queryCommandSupported(commandId); 191 }, 192 193 queryCommandValue: function (commandId, range) { 194 195 // Take current selection if not passed 196 if (!range) { 197 if (!Aloha.getSelection().getRangeCount()) { 198 return; 199 } 200 range = Aloha.getSelection().getRangeAt(0); 201 } 202 203 // "Return command's value." 204 return Engine.queryCommandValue(commandId, range); 205 }, 206 querySupportedCommands: function () { 207 208 var commands = [], 209 command; 210 211 for (command in Engine.commands) { 212 if (Engine.commands.hasOwnProperty(command)) { 213 commands.push(command); 214 } 215 } 216 return commands; 217 }, 218 getStateOverride: Engine.getStateOverride, 219 setStateOverride: Engine.setStateOverride, 220 resetOverrides: Engine.resetOverrides, 221 unsetStateOverride: Engine.unsetStateOverride 222 }; 223 224 // create an instance 225 CommandManager = new (Registry.extend(CommandManager))(); 226 227 /** 228 * Executes a registered command. 229 * http://aryeh.name/spec/editing/editing.html#methods-of-the-htmldocument-interface 230 * @method 231 * @param command name of the command 232 * @param showUI has no effect for Aloha Editor and is only here because in spec... 233 * @param value depends on the used command and it impementation 234 * @range optional a range on which the command will be executed if not specified 235 * the current selection will be used as range 236 */ 237 Aloha.execCommand = CommandManager.execCommand; 238 239 /** 240 * Check wheater the command in enabled. 241 * If command is not supported, raise a NOT_SUPPORTED_ERR exception. 242 * @param command name of the command 243 * @return true if command is enabled, false otherwise. 244 */ 245 Aloha.queryCommandEnabled = CommandManager.queryCommandEnabled; 246 247 /** 248 * Check if the command has an indetermed state. 249 * If command is not supported, a NOT_SUPPORTED_ERR exception is thrown 250 * If command has no indeterminacy, INVALID_ACCESS_ERR exception is thrown 251 * If command is not enabled, return false. 252 * @param command name of the command 253 * @range optional a range on which the command will be executed if not specified 254 * the current selection will be used as range 255 * @return true if command is indeterminate, otherwise false. 256 */ 257 Aloha.queryCommandIndeterm = CommandManager.queryCommandIndeterm; 258 259 /** 260 * Returns the state of a given command 261 * If command is not supported, a NOT_SUPPORTED_ERR exception is thrown 262 * If command has no state, an INVALID_ACCESS_ERR exception is thrown 263 * If command is not enabled, return false 264 * If the state override for command is set, it returns the state 265 * @param command name of the command 266 * @return state override or true if command's state is true, otherwise false. 267 */ 268 Aloha.queryCommandState = CommandManager.queryCommandState; 269 270 /** 271 * Check if a given command is supported 272 * @return true if command is supported, and false otherwise. 273 */ 274 Aloha.queryCommandSupported = CommandManager.queryCommandSupported; 275 276 /** 277 * Returns the Value of a given Command 278 * If command is not supported, a NOT_SUPPORTED_ERR exception is thrown 279 * If command is not enabled, returns an empty string 280 * If command is "fontSize" and its value override is set, an integer 281 * number of pixels is returned as font size for the result. 282 * If the value override for command is set, it returns that. 283 * @return command's value. 284 285 */ 286 Aloha.queryCommandValue = CommandManager.queryCommandValue; 287 288 Aloha.querySupportedCommands = CommandManager.querySupportedCommands; 289 290 return CommandManager; 291 }); 292