Type.registerNamespace('Sys.Extended.UI'); Sys.Extended.UI.DeferredOperation = function(delay, context, callback) { // Used to define a cancellable async operation // "delay" - the number of milliseconds to delay execution // "context" - an object used as the context for the callback method // "callback" - the callback method to execute at the end of the delay this._delay = delay; this._context = context; this._callback = callback; this._completeCallback = null; this._errorCallback = null; this._timer = null; this._callArgs = null; this._isComplete = false; this._completedSynchronously = false; this._asyncResult = null; this._exception = null; this._throwExceptions = true; this._oncomplete$delegate = Function.createDelegate(this, this._oncomplete); // post to ensure that attaching it always gets the port as its context this.post = Function.createDelegate(this, this.post); } Sys.Extended.UI.DeferredOperation.prototype = { get_isPending: function() { return (this._timer != null); }, get_isComplete: function() { return this._isComplete; }, get_completedSynchronously: function() { return this._completedSynchronously; }, get_exception: function() { return this._exception; }, get_throwExceptions: function() { return this._throwExceptions; }, set_throwExceptions: function(value) { // Sets whether to throw exceptions this._throwExceptions = value; }, get_delay: function() { // Gets the current delay in milliseconds return this._delay; }, set_delay: function(value) { // Sets the current delay in milliseconds this._delay = value; }, post: function(args) { // A method that can be directly attached to a delegate var ar = []; for(var i = 0; i < arguments.length; i++) ar[i] = arguments[i]; this.beginPost(ar, null, null); }, beginPost: function(args, completeCallback, errorCallback) { // Posts a call to an async operation on this port // cancel any pending post this.cancel(); // cache the call arguments this._callArgs = Array.clone(args || []); this._completeCallback = completeCallback; this._errorCallback = errorCallback; if(this._delay == -1) { // if there is no delay (-1), complete synchronously try { this._oncomplete(); } finally { this._completedSynchronously = true; } } else { // complete the post on a seperate call after a delay this._timer = setTimeout(this._oncomplete$delegate, this._delay); } }, cancel: function() { if(this._timer) { clearTimeout(this._timer); this._timer = null; } this._callArgs = null; this._isComplete = false; this._asyncResult = null; this._completeCallback = null; this._errorCallback = null; this._exception = null; this._completedSynchronously = false; }, call: function(args) { // Executes the deferred operation synchronously var ar = []; for(var i = 0; i < arguments.length; i++) ar[i] = arguments[i]; // cancel any pending post this.cancel(); // cache the call arguments this._callArgs = ar; this._completeCallback = null; this._errorCallback = null; try { this._oncomplete(); } finally { this._completedSynchronously = true; } if(this._exception) throw this._exception; return this._asyncResult; }, complete: function() { // Completes a pending post synchronously if(this._timer) { try { this._oncomplete(); } finally { this._completedSynchronously = true; } return this._asyncResult; } else if(this._isComplete) { return this._asyncResult; } }, _oncomplete: function() { // Completes a pending post asynchronously var args = this._callArgs, completeCallback = this._completeCallback, errorCallback = this._errorCallback; // clear the post state this.cancel(); try { // call the post callback if(args) this._asyncResult = this._callback.apply(this._context, args); else this._asyncResult = this._callback.call(this._context); this._isComplete = true; this._completedSynchronously = false; if(completeCallback) completeCallback(this); } catch(e) { this._isComplete = true; this._completedSynchronously = false; this._exception = e; if(errorCallback) if(errorCallback(this)) return; if(this._throwExceptions) throw e; } } } Sys.Extended.UI.DeferredOperation.registerClass("Sys.Extended.UI.DeferredOperation");