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