Table of contents
Command basics
The EPiServer user interface makes use of the command pattern to encapsulate
interface actions into reusable objects. This allows the logic, for executing an
action and whether the application is in a state to execute the action, to be separated
away from concrete widgets or objects into its own testable unit. This abstraction
means that for one command we could have several UI objects that cause it to execute.
The command base class is epi/shell/command/_Command.
Methods
The command base has a public execute method which executes the action
if canExecute is true. This can be called explicitly, but will in general
be called by the interface objects associated with the command.
The command base also has two protected methods which should be overridden by implementing
classes. The first is _execute, which is call by execute after it has
checked that the command is in an executable state. This method is where the executional
logic for the command should be defined. The second is _onModelChange,
which is called when the model is set on the command. It is intended that this method
update the state of canExecute based on the new model object.
Stateful
Commands are stateful so it is possible to watch for changes to their properties.
For example, canExecute can be watched; this allows the display state
(e.g. enabled/disabled) of interface objects, which represent the command, to be
updated when canExecute changes. It also means that the model, on which
the command executes or determines it state, can be set using set("model",
value). This will cause the protected _onModelChange method
to be called on the command, which should in turn cause the state of canExecute
to be updated for the new model.
Sample command implementation
JavaScript
define([
"dojo/_base/declare",
"epi/dependency",
"epi/shell/command/_Command"
], function (declare, dependency, _Command) {
return declare([_Command], {
constructor: function () {
var registry = dependency.resolve("epi.storeregistry");
this.store = registry.get("epi.cms.contentdata");
},
_execute: function () {
var model = this.model;
model.isCommonDraft = true;
return this.store.put(model);
},
_onModelChange: function () {
var model = this.model,
canExecute = model && !model.isCommonDraft;
this.set("canExecute", canExecute);
}
});
});
Command providers and consumers
A provider and consumer pattern has also been implemented for commands in order
to extend the principle of separating concerns to where the commands are used as
well.
A common situation when using commands is that the widget or object providing the
commands shouldn't be responsible for displaying them or rather the commands it
provides need to be shown somewhere else in the interface. For example, the page
tree has commands such as create page, translate page, etc. but the page tree shouldn't
be responsible for displaying these since it has no knowledge of where or how they
should be displayed. Instead the generic component chrome that the page tree resides
within is responsible for this and has this knowledge. However the problem is that
the page tree has no knowledge of the component chrome. A generic method is need
to get the commands from the page tree to the component chrome.
To solve this both epi/shell/command/_CommandProviderMixin> and
epi/shell/command/_CommandConsumerMixin have been created.
These two classes provide the link between the commands source and where they should
be displayed. Simply, the provider has a list of commands and the consumer has a
list of command providers and displays the commands for those providers.