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 "use strict"; 28 define( [ 'aloha/core', 'aloha/registry', 'aloha/engine', 'util/dom', 'aloha/contenthandlermanager' ], 29 function( Aloha, Registry, Engine, Dom, ContentHandlerManager ) { 30 31 // Action: What the command does when executed via execCommand(). Every command defined 32 // in CommandManager specification has an action defined for it in the relevant section. For example, 33 // the bold command's action generally makes the current selection bold, or removes bold if 34 // the selection is already bold. An editing toolbar might provide buttons that execute the 35 // action for a command if clicked, or a script might run an action without user interaction 36 // to achieve some particular effect. 37 // 38 // Indeterminate: A boolean value returned by queryCommandIndeterm(), depending on the 39 // current state of the document. Generally, a command that has a state defined will be 40 // indeterminate if the state is true for part but not all of the current selection, and a 41 // command that has a value defined will be indeterminate if different parts of the 42 // selection have different values. An editing toolbar might display a button or control 43 // in a special way if the command is indeterminate, like showing a "bold" button as 44 // partially depressed, or leaving a font size selector blank instead of showing the font 45 // size of the current selection. As a rule, a command can only be indeterminate if its 46 // state is false, supposing it has a state. 47 48 // 49 // State: A boolean value returned by queryCommandState(), depending on the current state 50 // of the document. The state of a command is true if it is already in effect, in some 51 // sense specific to the command. Most commands that have a state defined will take opposite 52 // actions depending on whether the state is true or false, such as making the selection 53 // bold if the state is false and removing bold if the state is true. Others will just 54 // have no effect if the state is true, like the justifyCenter command. Still others will 55 // have the same effect regardless, like the styleWithCss command. An editing toolbar might 56 // display a button or control differently depending on the state and indeterminacy of the 57 // command. 58 // 59 // Value: A string returned by queryCommandValue(), depending on the current state of the 60 // document. A command usually has a value instead of a state if the property it modifies 61 // can take more than two different values, like the foreColor command. If the command is 62 // indeterminate, its value is generally based on the start of the selection. Otherwise, 63 // in most cases the value holds true for the entire selection, but see the justifyCenter 64 // command and its three companions for an exception. An editing toolbar might display the 65 // value of a command as selected in a drop-down or filled in in a text box, if the command 66 // isn't indeterminate. 67 // 68 // Relevant CSS property: CommandManager is defined for certain inline formatting commands, and 69 // is used in algorithms specific to those commands. It is an implementation detail, and 70 // is not exposed to authors. If a command does not have a relevant CSS property 71 // specified, it defaults to null. 72 73 var CommandManager = { 74 75 execCommand: function( commandId, showUi, value, range ) { 76 var evtObj = { 77 commandId: commandId, 78 preventDefault: false 79 } 80 Aloha.trigger('aloha-command-will-execute', evtObj); 81 82 if (evtObj.preventDefault === true) { 83 return; 84 } 85 // Read current selection if not passed 86 if ( !range ) { 87 if ( !Aloha.getSelection().getRangeCount() ) { 88 return; 89 } 90 range = Aloha.getSelection().getRangeAt( 0 ); 91 } 92 93 // For the insertHTML command we provide contenthandler API 94 if ( commandId.toLowerCase() === 'inserthtml' ) { 95 //if (typeof Aloha.settings.contentHandler.insertHtml === 'undefined') { 96 // use all registered content handler; used for copy & paste atm (or write log message) 97 // Aloha.settings.contentHandler.insertHtml = Aloha.defaults.contentHandler.insertHtml; 98 //} 99 value = ContentHandlerManager.handleContent( value, { 100 contenthandler: Aloha.settings.contentHandler.insertHtml, 101 command: 'insertHtml' 102 }); 103 } 104 105 Engine.execCommand( commandId, showUi, value, range ); 106 107 if ( Aloha.getSelection().getRangeCount() ) { 108 // Read range after engine modification 109 range = Aloha.getSelection().getRangeAt( 0 ); 110 111 // FIX: doCleanup should work with W3C range 112 var startnode = range.commonAncestorContainer; 113 var rangeObject = new window.GENTICS.Utils.RangeObject(); 114 rangeObject.startContainer = range.startContainer; 115 rangeObject.startOffset = range.startOffset; 116 rangeObject.endContainer = range.endContainer; 117 rangeObject.endOffset = range.endOffset; 118 Dom.doCleanup({merge:true, removeempty: false}, rangeObject, startnode); 119 rangeObject.select(); 120 } 121 122 Aloha.trigger('aloha-command-executed', commandId); 123 }, 124 125 // If command is available and not disabled or the active range is not null 126 // the command is enabled 127 queryCommandEnabled: function( commandId, range ) { 128 129 // Take current selection if not passed 130 if ( !range ) { 131 if ( !Aloha.getSelection().getRangeCount() ) { 132 return; 133 } 134 range = Aloha.getSelection().getRangeAt(0); 135 } 136 return Engine.queryCommandEnabled( commandId, range ); 137 }, 138 139 // "Return true if command is indeterminate, otherwise false." 140 queryCommandIndeterm: function( commandId, range ) { 141 142 // Take current selection if not passed 143 if ( !range ) { 144 if ( !Aloha.getSelection().getRangeCount() ) { 145 return; 146 } 147 range = Aloha.getSelection().getRangeAt(0); 148 } 149 return Engine.queryCommandIndeterm( commandId, range ); 150 151 }, 152 153 queryCommandState: function( commandId, range ) { 154 155 // Take current selection if not passed 156 if ( !range ) { 157 if ( !Aloha.getSelection().getRangeCount() ) { 158 return; 159 } 160 range = Aloha.getSelection().getRangeAt(0); 161 } 162 return Engine.queryCommandState( commandId, range ); 163 164 }, 165 166 // "When the queryCommandSupported(command) method on the HTMLDocument 167 // interface is invoked, the user agent must return true if command is 168 // supported, and false otherwise." 169 queryCommandSupported: function( commandId ) { 170 171 return Engine.queryCommandSupported( commandId ); 172 }, 173 174 queryCommandValue: function( commandId, range ) { 175 176 // Take current selection if not passed 177 if ( !range ) { 178 if ( !Aloha.getSelection().getRangeCount() ) { 179 return; 180 } 181 range = Aloha.getSelection().getRangeAt(0); 182 } 183 184 // "Return command's value." 185 return Engine.queryCommandValue( commandId, range ); 186 }, 187 querySupportedCommands: function() { 188 189 var 190 commands = [], 191 command; 192 193 for ( command in Engine.commands ) { 194 commands.push( command ); 195 } 196 return commands; 197 } 198 }; 199 200 // create an instance 201 CommandManager = new ( Registry.extend( CommandManager ) )(); 202 203 /** 204 * Executes a registered command. 205 * http://aryeh.name/spec/editing/editing.html#methods-of-the-htmldocument-interface 206 * @method 207 * @param command name of the command 208 * @param showUI has no effect for Aloha Editor and is only here because in spec... 209 * @param value depends on the used command and it impementation 210 * @range optional a range on which the command will be executed if not specified 211 * the current selection will be used as range 212 */ 213 Aloha.execCommand = CommandManager.execCommand; 214 215 /** 216 * Check wheater the command in enabled. 217 218 * If command is not supported, raise a NOT_SUPPORTED_ERR exception. 219 * @param command name of the command 220 * @return true if command is enabled, false otherwise. 221 */ 222 Aloha.queryCommandEnabled = CommandManager.queryCommandEnabled; 223 224 /** 225 * Check if the command has an indetermed state. 226 * If command is not supported, a NOT_SUPPORTED_ERR exception is thrown 227 * If command has no indeterminacy, INVALID_ACCESS_ERR exception is thrown 228 * If command is not enabled, return false. 229 * @param command name of the command 230 * @range optional a range on which the command will be executed if not specified 231 * the current selection will be used as range 232 * @return true if command is indeterminate, otherwise false. 233 */ 234 Aloha.queryCommandIndeterm = CommandManager.queryCommandIndeterm; 235 236 /** 237 * Returns the state of a given command 238 * If command is not supported, a NOT_SUPPORTED_ERR exception is thrown 239 * If command has no state, an INVALID_ACCESS_ERR exception is thrown 240 * If command is not enabled, return false 241 * If the state override for command is set, it returns the state 242 * @param command name of the command 243 * @return state override or true if command's state is true, otherwise false. 244 245 */ 246 Aloha.queryCommandState = CommandManager.queryCommandState; 247 248 /** 249 * Check if a given command is supported 250 * @return true if command is supported, and false otherwise. 251 */ 252 Aloha.queryCommandSupported = CommandManager.queryCommandSupported; 253 254 /** 255 * Returns the Value of a given Command 256 * If command is not supported, a NOT_SUPPORTED_ERR exception is thrown 257 * If command is not enabled, returns an empty string 258 * If command is "fontSize" and its value override is set, an integer 259 * number of pixels is returned as font size for the result. 260 * If the value override for command is set, it returns that. 261 * @return command's value. 262 */ 263 Aloha.queryCommandValue = CommandManager.queryCommandValue; 264 265 Aloha.querySupportedCommands = CommandManager.querySupportedCommands; 266 267 return CommandManager; 268 }); 269