summaryrefslogtreecommitdiff
path: root/vendor/oojs/oojs-ui/src/Process.js
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/oojs/oojs-ui/src/Process.js')
-rw-r--r--vendor/oojs/oojs-ui/src/Process.js166
1 files changed, 166 insertions, 0 deletions
diff --git a/vendor/oojs/oojs-ui/src/Process.js b/vendor/oojs/oojs-ui/src/Process.js
new file mode 100644
index 00000000..649ffb99
--- /dev/null
+++ b/vendor/oojs/oojs-ui/src/Process.js
@@ -0,0 +1,166 @@
+/**
+ * A Process is a list of steps that are called in sequence. The step can be a number, a jQuery promise,
+ * or a function:
+ *
+ * - **number**: the process will wait for the specified number of milliseconds before proceeding.
+ * - **promise**: the process will continue to the next step when the promise is successfully resolved
+ * or stop if the promise is rejected.
+ * - **function**: the process will execute the function. The process will stop if the function returns
+ * either a boolean `false` or a promise that is rejected; if the function returns a number, the process
+ * will wait for that number of milliseconds before proceeding.
+ *
+ * If the process fails, an {@link OO.ui.Error error} is generated. Depending on how the error is
+ * configured, users can dismiss the error and try the process again, or not. If a process is stopped,
+ * its remaining steps will not be performed.
+ *
+ * @class
+ *
+ * @constructor
+ * @param {number|jQuery.Promise|Function} step Number of miliseconds to wait before proceeding, promise
+ * that must be resolved before proceeding, or a function to execute. See #createStep for more information. see #createStep for more information
+ * @param {Object} [context=null] Execution context of the function. The context is ignored if the step is
+ * a number or promise.
+ * @return {Object} Step object, with `callback` and `context` properties
+ */
+OO.ui.Process = function ( step, context ) {
+ // Properties
+ this.steps = [];
+
+ // Initialization
+ if ( step !== undefined ) {
+ this.next( step, context );
+ }
+};
+
+/* Setup */
+
+OO.initClass( OO.ui.Process );
+
+/* Methods */
+
+/**
+ * Start the process.
+ *
+ * @return {jQuery.Promise} Promise that is resolved when all steps have successfully completed.
+ * If any of the steps return a promise that is rejected or a boolean false, this promise is rejected
+ * and any remaining steps are not performed.
+ */
+OO.ui.Process.prototype.execute = function () {
+ var i, len, promise;
+
+ /**
+ * Continue execution.
+ *
+ * @ignore
+ * @param {Array} step A function and the context it should be called in
+ * @return {Function} Function that continues the process
+ */
+ function proceed( step ) {
+ return function () {
+ // Execute step in the correct context
+ var deferred,
+ result = step.callback.call( step.context );
+
+ if ( result === false ) {
+ // Use rejected promise for boolean false results
+ return $.Deferred().reject( [] ).promise();
+ }
+ if ( typeof result === 'number' ) {
+ if ( result < 0 ) {
+ throw new Error( 'Cannot go back in time: flux capacitor is out of service' );
+ }
+ // Use a delayed promise for numbers, expecting them to be in milliseconds
+ deferred = $.Deferred();
+ setTimeout( deferred.resolve, result );
+ return deferred.promise();
+ }
+ if ( result instanceof OO.ui.Error ) {
+ // Use rejected promise for error
+ return $.Deferred().reject( [ result ] ).promise();
+ }
+ if ( Array.isArray( result ) && result.length && result[ 0 ] instanceof OO.ui.Error ) {
+ // Use rejected promise for list of errors
+ return $.Deferred().reject( result ).promise();
+ }
+ // Duck-type the object to see if it can produce a promise
+ if ( result && $.isFunction( result.promise ) ) {
+ // Use a promise generated from the result
+ return result.promise();
+ }
+ // Use resolved promise for other results
+ return $.Deferred().resolve().promise();
+ };
+ }
+
+ if ( this.steps.length ) {
+ // Generate a chain reaction of promises
+ promise = proceed( this.steps[ 0 ] )();
+ for ( i = 1, len = this.steps.length; i < len; i++ ) {
+ promise = promise.then( proceed( this.steps[ i ] ) );
+ }
+ } else {
+ promise = $.Deferred().resolve().promise();
+ }
+
+ return promise;
+};
+
+/**
+ * Create a process step.
+ *
+ * @private
+ * @param {number|jQuery.Promise|Function} step
+ *
+ * - Number of milliseconds to wait before proceeding
+ * - Promise that must be resolved before proceeding
+ * - Function to execute
+ * - If the function returns a boolean false the process will stop
+ * - If the function returns a promise, the process will continue to the next
+ * step when the promise is resolved or stop if the promise is rejected
+ * - If the function returns a number, the process will wait for that number of
+ * milliseconds before proceeding
+ * @param {Object} [context=null] Execution context of the function. The context is
+ * ignored if the step is a number or promise.
+ * @return {Object} Step object, with `callback` and `context` properties
+ */
+OO.ui.Process.prototype.createStep = function ( step, context ) {
+ if ( typeof step === 'number' || $.isFunction( step.promise ) ) {
+ return {
+ callback: function () {
+ return step;
+ },
+ context: null
+ };
+ }
+ if ( $.isFunction( step ) ) {
+ return {
+ callback: step,
+ context: context
+ };
+ }
+ throw new Error( 'Cannot create process step: number, promise or function expected' );
+};
+
+/**
+ * Add step to the beginning of the process.
+ *
+ * @inheritdoc #createStep
+ * @return {OO.ui.Process} this
+ * @chainable
+ */
+OO.ui.Process.prototype.first = function ( step, context ) {
+ this.steps.unshift( this.createStep( step, context ) );
+ return this;
+};
+
+/**
+ * Add step to the end of the process.
+ *
+ * @inheritdoc #createStep
+ * @return {OO.ui.Process} this
+ * @chainable
+ */
+OO.ui.Process.prototype.next = function ( step, context ) {
+ this.steps.push( this.createStep( step, context ) );
+ return this;
+};