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 				if (startnode.parentNode) {
114 					startnode = startnode.parentNode;
115 				}
116 				var rangeObject = new window.GENTICS.Utils.RangeObject();
117 				rangeObject.startContainer = range.startContainer;
118 				rangeObject.startOffset = range.startOffset;
119 				rangeObject.endContainer = range.endContainer;
120 				rangeObject.endOffset = range.endOffset;
121 				Dom.doCleanup({merge:true, removeempty: false}, rangeObject, startnode);
122 				rangeObject.select();
123 			}
124 
125 			Aloha.trigger('aloha-command-executed', commandId);
126 		},
127 		
128 		// If command is available and not disabled or the active range is not null 
129 		// the command is enabled
130 		queryCommandEnabled: function( commandId, range ) {
131 
132 			// Take current selection if not passed
133 			if ( !range ) {
134 				if ( !Aloha.getSelection().getRangeCount() ) {
135 					return;
136 				}
137 				range = Aloha.getSelection().getRangeAt(0);
138 			}
139 			return Engine.queryCommandEnabled( commandId, range );
140 		},
141 
142 		// "Return true if command is indeterminate, otherwise false."
143 		queryCommandIndeterm: function( commandId, range ) {
144 
145 			// Take current selection if not passed
146 			if ( !range ) {
147 				if ( !Aloha.getSelection().getRangeCount() ) {
148 					return;
149 				}
150 				range = Aloha.getSelection().getRangeAt(0);
151 			}
152 			return Engine.queryCommandIndeterm( commandId, range );
153 
154 		},
155 		
156 		queryCommandState: function( commandId, range ) {
157 
158 			// Take current selection if not passed
159 			if ( !range ) {
160 				if ( !Aloha.getSelection().getRangeCount() ) {
161 					return;
162 				}
163 				range = Aloha.getSelection().getRangeAt(0);
164 			}
165 			return Engine.queryCommandState( commandId, range );
166 
167 		},
168 		
169 		// "When the queryCommandSupported(command) method on the HTMLDocument
170 		// interface is invoked, the user agent must return true if command is
171 		// supported, and false otherwise."
172 		queryCommandSupported: function( commandId ) {
173 
174 			return Engine.queryCommandSupported( commandId );		
175 		},
176 		
177 		queryCommandValue: function( commandId, range ) {
178 
179 			// Take current selection if not passed
180 			if ( !range ) {
181 				if ( !Aloha.getSelection().getRangeCount() ) {
182 					return;
183 				}
184 				range = Aloha.getSelection().getRangeAt(0);
185 			}
186 
187 			// "Return command's value."
188 			return Engine.queryCommandValue( commandId, range );
189 		},
190 		querySupportedCommands: function() {
191 
192 			var 
193 				commands = [],
194 				command;
195 			
196 			for ( command in Engine.commands ) {
197 				commands.push( command );
198 			}
199 			return commands;
200 		}
201 	};
202 	
203 	// create an instance
204 	CommandManager = new ( Registry.extend( CommandManager ) )();
205 	
206 	/**
207 	 * Executes a registered command.
208 	 * http://aryeh.name/spec/editing/editing.html#methods-of-the-htmldocument-interface
209 	 * @method
210 	 * @param command name of the command
211 	 * @param showUI has no effect for Aloha Editor and is only here because in spec...
212 	 * @param value depends on the used command and it impementation 
213 	 * @range optional a range on which the command will be executed if not specified 
214 	 * 		  the current selection will be used as range
215 	 */
216 	Aloha.execCommand = CommandManager.execCommand;
217 	
218 	/**
219 	 * Check wheater the command in enabled.
220 	 * If command is not supported, raise a NOT_SUPPORTED_ERR exception.
221 	 * @param command name of the command
222 	 * @return true if command is enabled, false otherwise.
223 	 */
224 	Aloha.queryCommandEnabled = CommandManager.queryCommandEnabled;
225 	
226 	/**
227 	 * Check if the command has an indetermed state. 
228 	 * If command is not supported, a NOT_SUPPORTED_ERR exception is thrown
229 	 * If command has no indeterminacy, INVALID_ACCESS_ERR exception is thrown
230 	 * If command is not enabled, return false.
231 	 * @param command name of the command
232 	 * @range optional a range on which the command will be executed if not specified 
233 	 * 		  the current selection will be used as range
234 	 * @return true if command is indeterminate, otherwise false.
235 	 */
236 	Aloha.queryCommandIndeterm = CommandManager.queryCommandIndeterm;
237 	
238 	/**
239 	 * Returns the state of a given command
240 	 * If command is not supported, a NOT_SUPPORTED_ERR exception is thrown
241 	 * If command has no state, an INVALID_ACCESS_ERR exception is thrown
242 	 * If command is not enabled, return false
243 	 * If the state override for command is set, it returns the state
244 	 * @param command name of the command
245 	 * @return state override or true if command's state is true, otherwise false.
246 	 */
247 	Aloha.queryCommandState = CommandManager.queryCommandState;
248 
249 	/**
250 	 * Check if a given command is supported
251 	 * @return true if command is supported, and false otherwise.
252 	 */
253 	Aloha.queryCommandSupported = CommandManager.queryCommandSupported;
254 
255 	/**
256 	 * Returns the Value of a given Command
257 	 * If command is not supported, a NOT_SUPPORTED_ERR exception is thrown
258 	 * If command is not enabled, returns an empty string
259 	 * If command is "fontSize" and its value override is set, an integer 
260 	 * number of pixels is returned as font size for the result.
261 	 * If the value override for command is set, it returns that.
262 263 	 * @return command's value.
264 	 */
265 	Aloha.queryCommandValue = CommandManager.queryCommandValue;
266 	
267 	Aloha.querySupportedCommands = CommandManager.querySupportedCommands;
268 	
269 	return CommandManager;
270 });
271