/**
* The base class of all remote {@linkplain Command commands},
* that is, commands executed server-side.
*/
export class RemoteCommand extends Command {
constructor(commandName) {
super();
this._commandName = commandName;
}
get commandName() {
return this._commandName;
}
execute(mode, docView, params, event=null) {
if (mode === EXECUTE_TEST) {
return docView.sendExecuteCommand(mode, this._commandName, params)
}
Command.consumeEvent(event);
return docView.sendExecuteCommand(mode, this._commandName, params)
.then((result) => {
return this.commandExecuted(mode, docView, params, result);
});
// No need to catch errors here. At worst, sendExecuteCommand will
// return a null Promise.
}
/**
* Invoked when, in helper or normal modes, the command execution request
* has been sent to the server.
*/
commandExecuted(mode, docView, params, result) {
if (result === null) {
// Generally means: cannot execute.
// Also happens when sendExecuteCommand fails, in which case an
// error is reported on the console by DocumentView.
return null;
} else {
switch (result.status) {
case COMMAND_RESULT_DONE:
this.executionDone(mode, docView, params, result.value);
break;
case COMMAND_RESULT_STOPPED:
{
let resume = [null, null];
let stoppedValue = result.value;
if (stoppedValue !== null &&
stoppedValue.startsWith("xxeClientExecuteCommand")) {
stoppedValue = stoppedValue.substring(23).trim();
resume = Command.splitCmdString(stoppedValue, ' ');
}
if (resume[0]) {
return docView.executeCommand(EXECUTE_HELPER,
resume[0], resume[1]);
}
}
this.executionStopped(mode, docView, params, result.value);
break;
case COMMAND_RESULT_FAILED:
this.executionFailed(mode, docView, params, result.value);
break;
}
// Otherwise, COMMAND_RESULT_CANCELED.
return result;
}
}
/**
* Invoked after the command execution is successful.
* <p>Default implementation does nothing at all.
*/
executionDone(mode, docView, params, resultValue) {}
/**
* Invoked after the command execution was stopped.
* <p>Default implementation displays <code>resultValue</code>
* (which in principle contains information about how to resume
* the execution of the command) if there;
* a generic error message otherwise.
*/
executionStopped(mode, docView, params, resultValue) {
this.reportExecutionError(docView, params, resultValue,
/*stopped*/ true);
}
/**
* Invoked after the command execution has failed.
* <p>Default implementation displays <code>resultValue</code>
* (which is assumed to be an error message) if there;
* a generic error message otherwise.
*/
executionFailed(mode, docView, params, resultValue) {
this.reportExecutionError(docView, params, resultValue,
/*stopped*/ false);
}
reportExecutionError(docView, params, resultValue, stopped, quiet=true) {
let msg;
if (stopped || resultValue === null) {
if (quiet) {
// Generally there is no need to show an error alert when the
// command was stopped or when the command has failed without
// providing a reason for this failure.
return;
}
// We want a message, even a low-level one, may be to debug the
// command. Make it as detailed as possible.
const cmdString = this.getCommandString(params);
msg = stopped? `Command "${cmdString}" was stopped` :
`Command "${cmdString}" has failed`;
if (resultValue === null) {
msg += ".";
} else {
msg += ":\n";
msg += resultValue;
}
} else {
// Command has failed and returned a hopefully meaningful error
// message. Use it as is.
msg = resultValue;
}
XUI.Alert.showError(msg, docView);
}
}