aboutsummaryrefslogtreecommitdiff
path: root/sources/core/command.js
blob: c4e8a7ae715eae114f2ef640c23d045bbfa965a2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
/**
 * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
 * For licensing, see LICENSE.md or http://ckeditor.com/license
 */

/**
 * Represents a command that can be executed on an editor instance.
 *
 *		var command = new CKEDITOR.command( editor, {
 *			exec: function( editor ) {
 *				alert( editor.document.getBody().getHtml() );
 *			}
 *		} );
 *
 * @class
 * @extends CKEDITOR.commandDefinition
 * @mixins CKEDITOR.event
 * @constructor Creates a command class instance.
 * @param {CKEDITOR.editor} editor The editor instance this command will be
 * related to.
 * @param {CKEDITOR.commandDefinition} commandDefinition The command
 * definition.
 */
CKEDITOR.command = function( editor, commandDefinition ) {
	/**
	 * Lists UI items that are associated to this command. This list can be
	 * used to interact with the UI on command execution (by the execution code
	 * itself, for example).
	 *
	 *		alert( 'Number of UI items associated to this command: ' + command.uiItems.length );
	 */
	this.uiItems = [];

	/**
	 * Executes the command.
	 *
	 *		command.exec(); // The command gets executed.
	 *
	 * **Note:** You should use the {@link CKEDITOR.editor#execCommand} method instead of calling
	 * `command.exec()` directly.
	 *
	 * @param {Object} [data] Any data to pass to the command. Depends on the
	 * command implementation and requirements.
	 * @returns {Boolean} A boolean indicating that the command has been successfully executed.
	 */
	this.exec = function( data ) {
		if ( this.state == CKEDITOR.TRISTATE_DISABLED || !this.checkAllowed() )
			return false;

		if ( this.editorFocus ) // Give editor focus if necessary (#4355).
			editor.focus();

		if ( this.fire( 'exec' ) === false )
			return true;

		return ( commandDefinition.exec.call( this, editor, data ) !== false );
	};

	/**
	 * Explicitly update the status of the command, by firing the {@link CKEDITOR.command#event-refresh} event,
	 * as well as invoke the {@link CKEDITOR.commandDefinition#refresh} method if defined, this method
	 * is to allow different parts of the editor code to contribute in command status resolution.
	 *
	 * @param {CKEDITOR.editor} editor The editor instance.
	 * @param {CKEDITOR.dom.elementPath} path
	 */
	this.refresh = function( editor, path ) {
		// Do nothing is we're on read-only and this command doesn't support it.
		// We don't need to disabled the command explicitely here, because this
		// is already done by the "readOnly" event listener.
		if ( !this.readOnly && editor.readOnly )
			return true;

		// Disable commands that are not allowed in the current selection path context.
		if ( this.context && !path.isContextFor( this.context ) ) {
			this.disable();
			return true;
		}

		// Disable commands that are not allowed by the active filter.
		if ( !this.checkAllowed( true ) ) {
			this.disable();
			return true;
		}

		// Make the "enabled" state a default for commands enabled from start.
		if ( !this.startDisabled )
			this.enable();

		// Disable commands which shouldn't be enabled in this mode.
		if ( this.modes && !this.modes[ editor.mode ] )
			this.disable();

		if ( this.fire( 'refresh', { editor: editor, path: path } ) === false )
			return true;

		return ( commandDefinition.refresh && commandDefinition.refresh.apply( this, arguments ) !== false );
	};

	var allowed;

	/**
	 * Checks whether this command is allowed by the active allowed
	 * content filter ({@link CKEDITOR.editor#activeFilter}). This means
	 * that if command implements {@link CKEDITOR.feature} interface it will be tested
	 * by the {@link CKEDITOR.filter#checkFeature} method.
	 *
	 * @since 4.1
	 * @param {Boolean} [noCache] Skip cache for example due to active filter change. Since CKEditor 4.2.
	 * @returns {Boolean} Whether this command is allowed.
	 */
	this.checkAllowed = function( noCache ) {
		if ( !noCache && typeof allowed == 'boolean' )
			return allowed;

		return allowed = editor.activeFilter.checkFeature( this );
	};

	CKEDITOR.tools.extend( this, commandDefinition, {
		/**
		 * The editor modes within which the command can be executed. The
		 * execution will have no action if the current mode is not listed
		 * in this property.
		 *
		 *		// Enable the command in both WYSIWYG and Source modes.
		 *		command.modes = { wysiwyg:1,source:1 };
		 *
		 *		// Enable the command in Source mode only.
		 *		command.modes = { source:1 };
		 *
		 * @see CKEDITOR.editor#mode
		 */
		modes: { wysiwyg: 1 },

		/**
		 * Indicates that the editor will get the focus before executing
		 * the command.
		 *
		 *		// Do not force the editor to have focus when executing the command.
		 *		command.editorFocus = false;
		 *
		 * @property {Boolean} [=true]
		 */
		editorFocus: 1,

		/**
		 * Indicates that this command is sensible to the selection context.
		 * If `true`, the {@link CKEDITOR.command#method-refresh} method will be
		 * called for this command on the {@link CKEDITOR.editor#event-selectionChange} event.
		 *
		 * @property {Boolean} [=false]
		 */
		contextSensitive: !!commandDefinition.context,

		/**
		 * Indicates the editor state. Possible values are:
		 *
		 * * {@link CKEDITOR#TRISTATE_DISABLED}: the command is
		 *     disabled. It's execution will have no effect. Same as {@link #disable}.
		 * * {@link CKEDITOR#TRISTATE_ON}: the command is enabled
		 *     and currently active in the editor (for context sensitive commands,	for example).
		 * * {@link CKEDITOR#TRISTATE_OFF}: the command is enabled
		 *     and currently inactive in the editor (for context sensitive	commands, for example).
		 *
		 * Do not set this property directly, using the {@link #setState} method instead.
		 *
		 *		if ( command.state == CKEDITOR.TRISTATE_DISABLED )
		 *			alert( 'This command is disabled' );
		 *
		 * @property {Number} [=CKEDITOR.TRISTATE_DISABLED]
		 */
		state: CKEDITOR.TRISTATE_DISABLED
	} );

	// Call the CKEDITOR.event constructor to initialize this instance.
	CKEDITOR.event.call( this );
};

CKEDITOR.command.prototype = {
	/**
	 * Enables the command for execution. The command state (see
	 * {@link CKEDITOR.command#property-state}) available before disabling it is restored.
	 *
	 *		command.enable();
	 *		command.exec(); // Execute the command.
	 */
	enable: function() {
		if ( this.state == CKEDITOR.TRISTATE_DISABLED && this.checkAllowed() )
			this.setState( ( !this.preserveState || ( typeof this.previousState == 'undefined' ) ) ? CKEDITOR.TRISTATE_OFF : this.previousState );
	},

	/**
	 * Disables the command for execution. The command state (see
	 * {@link CKEDITOR.command#property-state}) will be set to {@link CKEDITOR#TRISTATE_DISABLED}.
	 *
	 *		command.disable();
	 *		command.exec(); // "false" - Nothing happens.
	 */
	disable: function() {
		this.setState( CKEDITOR.TRISTATE_DISABLED );
	},

	/**
	 * Sets the command state.
	 *
	 *		command.setState( CKEDITOR.TRISTATE_ON );
	 *		command.exec(); // Execute the command.
	 *		command.setState( CKEDITOR.TRISTATE_DISABLED );
	 *		command.exec(); // 'false' - Nothing happens.
	 *		command.setState( CKEDITOR.TRISTATE_OFF );
	 *		command.exec(); // Execute the command.
	 *
	 * @param {Number} newState The new state. See {@link #property-state}.
	 * @returns {Boolean} Returns `true` if the command state changed.
	 */
	setState: function( newState ) {
		// Do nothing if there is no state change.
		if ( this.state == newState )
			return false;

		if ( newState != CKEDITOR.TRISTATE_DISABLED && !this.checkAllowed() )
			return false;

		this.previousState = this.state;

		// Set the new state.
		this.state = newState;

		// Fire the "state" event, so other parts of the code can react to the
		// change.
		this.fire( 'state' );

		return true;
	},

	/**
	 * Toggles the on/off (active/inactive) state of the command. This is
	 * mainly used internally by context sensitive commands.
	 *
	 *		command.toggleState();
	 */
	toggleState: function() {
		if ( this.state == CKEDITOR.TRISTATE_OFF )
			this.setState( CKEDITOR.TRISTATE_ON );
		else if ( this.state == CKEDITOR.TRISTATE_ON )
			this.setState( CKEDITOR.TRISTATE_OFF );
	}
};

CKEDITOR.event.implementOn( CKEDITOR.command.prototype );

/**
 * Indicates the previous command state.
 *
 *		alert( command.previousState );
 *
 * @property {Number} previousState
 * @see #state
 */

/**
 * Fired when the command state changes.
 *
 *		command.on( 'state', function() {
 *			// Alerts the new state.
 *			alert( this.state );
 *		} );
 *
 * @event state
 */

 /**
 * @event refresh
 * @todo
 */