Updated Branches: refs/heads/master afc7d5d6b -> bc9ff1fde
WICKET-4668 Ajax responses for QUEUE and DROP type channels are not guaranteed to be processed in the order of the requests Rework the way the function executer is used - now it includes the failure and complete handlers as well. Project: http://git-wip-us.apache.org/repos/asf/wicket/repo Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/bc9ff1fd Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/bc9ff1fd Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/bc9ff1fd Branch: refs/heads/master Commit: bc9ff1fde96caebb68e3db2df16dd25229740867 Parents: afc7d5d Author: Martin Tzvetanov Grigorov <[email protected]> Authored: Tue Jul 24 10:55:01 2012 +0300 Committer: Martin Tzvetanov Grigorov <[email protected]> Committed: Tue Jul 24 10:55:01 2012 +0300 ---------------------------------------------------------------------- .../wicket/ajax/res/js/wicket-ajax-jquery.js | 157 ++++++++------- wicket-core/src/test/js/ajax.js | 6 +- wicket-core/src/test/js/channels.js | 2 +- wicket-core/src/test/js/data/test.js | 5 +- 4 files changed, 86 insertions(+), 84 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/wicket/blob/bc9ff1fd/wicket-core/src/main/java/org/apache/wicket/ajax/res/js/wicket-ajax-jquery.js ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/res/js/wicket-ajax-jquery.js b/wicket-core/src/main/java/org/apache/wicket/ajax/res/js/wicket-ajax-jquery.js index f57c5db..7b47440 100644 --- a/wicket-core/src/main/java/org/apache/wicket/ajax/res/js/wicket-ajax-jquery.js +++ b/wicket-core/src/main/java/org/apache/wicket/ajax/res/js/wicket-ajax-jquery.js @@ -134,7 +134,6 @@ } catch (e) { Wicket.Log.error("FunctionsExecuter.processNext: " + e); - jQuery.proxy(this.notify, this); } }; run = jQuery.proxy(run, this); @@ -442,7 +441,6 @@ // the request (extra) parameters data = this._asParamArray(attrs.ep), - // keep a reference to the current context self = this, // the precondition to use if there are no explicit ones @@ -455,7 +453,15 @@ } } return true; - }]; + }], + + // a context that brings the common data for the success/fialure/complete handlers + context = { + attrs: attrs, + + // initialize the array for steps (closures that execute each action) + steps: [] + }; if (Wicket.Focus.lastFocusId) { headers["Wicket-FocusedElementId"] = Wicket.Focus.lastFocusId; @@ -467,7 +473,7 @@ if (attrs.mp) { // multipart form. jQuery doesn't help here ... // TODO Wicket.next - should we execute all handlers ?! // Wicket 1.5 didn't support success/failure handlers for this, but we can do it - return this.submitMultipartForm(attrs); + return this.submitMultipartForm(context); } if (attrs.f) { @@ -563,28 +569,30 @@ success: function(data, textStatus, jqXHR) { if (attrs.wr) { - self.processAjaxResponse(data, textStatus, jqXHR, attrs); + self.processAjaxResponse(data, textStatus, jqXHR, context); } else { self._executeHandlers(attrs.sh, attrs, jqXHR, data, textStatus); + Wicket.Event.publish('/ajax/call/success', attrs, jqXHR, data, textStatus); } - Wicket.Event.publish('/ajax/call/success', attrs, jqXHR, data, textStatus); - }, error: function(jqXHR, textStatus, errorMessage) { - - self.failure(attrs, jqXHR, errorMessage, textStatus); - Wicket.Event.publish('/ajax/call/failure', attrs, jqXHR, errorMessage, textStatus); - + self.failure(context, jqXHR, errorMessage, textStatus); }, complete: function (jqXHR, textStatus) { - if (attrs.i) { - Wicket.DOM.hideIncrementally(attrs.i); - } - self._executeHandlers(attrs.coh, attrs, jqXHR, textStatus); - Wicket.Event.publish('/ajax/call/complete', attrs, jqXHR, textStatus); + context.steps.push(jQuery.proxy(function (notify) { + if (attrs.i) { + Wicket.DOM.hideIncrementally(attrs.i); + } - this.done(); + self._executeHandlers(attrs.coh, attrs, jqXHR, textStatus); + Wicket.Event.publish('/ajax/call/complete', attrs, jqXHR, textStatus); + + self.done(); + }, self)); + + var executer = new FunctionsExecuter(context.steps); + executer.start(); } }); @@ -605,9 +613,9 @@ * @param {XmlDocument} data - the <ajax-response> XML document * @param {String} textStatus - the response status as text (e.g. 'success', 'parsererror', etc.) * @param {Object} jqXHR - the jQuery wrapper around XMLHttpRequest - * @param {Object} attrs - the Ajax request attributes + * @param {Object} context - the request context with the Ajax request attributes and the FunctionExecuter's steps */ - processAjaxResponse: function (data, textStatus, jqXHR, attrs) { + processAjaxResponse: function (data, textStatus, jqXHR, context) { if (jqXHR.readyState === 4) { @@ -666,7 +674,7 @@ } // invoke the loaded callback with an xml document - return this.loadedCallback(data, attrs); + return this.loadedCallback(data, context); } } }, @@ -759,8 +767,8 @@ } // process the response - var attrs = event.data; - this.loadedCallback(envelope, attrs); + var context = event.data; + this.loadedCallback(envelope, context); // stop the event event.stopPropagation(); @@ -772,11 +780,11 @@ window.setTimeout(function () { jQuery('#'+iframe.id + '-btn').remove(); jQuery(iframe).remove(); - }, 250); + }, 1); }, // Processes the response - loadedCallback: function (envelope, attrs) { + loadedCallback: function (envelope, context) { // To process the response, we go through the xml document and add a function for every action (step). // After this is done, a FunctionExecuter object asynchronously executes these functions. // The asynchronous execution is necessary, because some steps might involve loading external javascript, @@ -797,21 +805,13 @@ return; } - // initialize the array for steps (closures that execute each action) - var steps = []; - - // start it a bit later so that the browser does handle the next event - // before the component is or can be replaced. We could do (if (!posponed)) - // because if there is already something in the queue then we could execute that immedietly - steps.push(jQuery.proxy(function (notify) { - window.setTimeout(notify, 2); - }, this)); + var steps = context.steps; // go through the ajax response and execute all priority-invocations first for (var i = 0; i < root.childNodes.length; ++i) { var childNode = root.childNodes[i]; if (childNode.tagName === "priority-evaluate") { - this.processEvaluation(steps, childNode, attrs); + this.processEvaluation(context, childNode); } } @@ -823,16 +823,16 @@ if (node.tagName === "component") { if (stepIndexOfLastReplacedComponent === -1) { - this.processFocusedComponentMark(steps); + this.processFocusedComponentMark(context); } stepIndexOfLastReplacedComponent = steps.length; - this.processComponent(steps, node); + this.processComponent(context, node); } else if (node.tagName === "evaluate") { - this.processEvaluation(steps, node, attrs, attrs.event); + this.processEvaluation(context, node); } else if (node.tagName === "header-contribution") { - this.processHeaderContribution(steps, node); + this.processHeaderContribution(context, node); } else if (node.tagName === "redirect") { - this.processRedirect(steps, node); + this.processRedirect(context, node); } } @@ -841,24 +841,21 @@ } // add the last step, which should trigger the success call the done method on request - this.success(steps, attrs); + this.success(context); - Wicket.Log.info("Response parsed. Now invoking steps..."); - var executer = new FunctionsExecuter(steps); - executer.start(); } catch (exception) { - this.failure(attrs, null, exception); + this.failure(context, null, exception); } }, // Adds a closure to steps that should be invoked after all other steps have been successfully executed - success: function (steps, attrs) { - steps.push(jQuery.proxy(function (notify) { + success: function (context) { + context.steps.push(jQuery.proxy(function (notify) { Wicket.Log.info("Response processed successfully."); - this._executeHandlers(attrs.sh, - ["data", "textStatus", "jqXHR", "attrs"], - null, 'success', null, attrs); + var attrs = context.attrs; + this._executeHandlers(attrs.sh, attrs, null, null, 'success'); + Wicket.Event.publish('/ajax/call/success', attrs, null, null, 'success'); // re-attach the events to the new components (a bit blunt method...) // This should be changed for IE See comments in wicket-event.js add (attachEvent/detachEvent) @@ -868,19 +865,23 @@ // set the focus to the last component window.setTimeout("Wicket.Focus.requestFocus();", 0); - this.done(); - // continue to next step (which should make the processing stop, as success should be the final step) notify(); }, this)); }, // On ajax request failure - failure: function (attrs, jqXHR, errorMessage, textStatus) { - if (errorMessage) { - Wicket.Log.error("Wicket.Ajax.Call.failure: Error while parsing response: " + errorMessage); - } - this._executeHandlers(attrs.fh, attrs, errorMessage); + failure: function (context, jqXHR, errorMessage, textStatus) { + context.steps.push(jQuery.proxy(function (notify) { + if (errorMessage) { + Wicket.Log.error("Wicket.Ajax.Call.failure: Error while parsing response: " + errorMessage); + } + var attrs = context.attrs; + this._executeHandlers(attrs.fh, attrs, errorMessage); + Wicket.Event.publish('/ajax/call/failure', attrs, jqXHR, errorMessage, textStatus); + + notify(); + }, this)); }, done: function () { @@ -888,8 +889,8 @@ }, // Adds a closure that replaces a component - processComponent: function (steps, node) { - steps.push(function (notify) { + processComponent: function (context, node) { + context.steps.push(function (notify) { // get the component id var compId = node.getAttribute("id"); var text = jQuery(node).text(); @@ -924,8 +925,8 @@ * @param attrs {Object} - the attributes used for the Ajax request * @param event {jQuery.Event} - the event that caused this Ajax call */ - processEvaluation: function (steps, node, attrs, event) { - steps.push(function (notify) { + processEvaluation: function (context, node) { + context.steps.push(function (notify) { // get the javascript body var text = jQuery(node).text(); @@ -967,21 +968,21 @@ }, // Adds a closure that processes a header contribution - processHeaderContribution: function (steps, node) { + processHeaderContribution: function (context, node) { var c = Wicket.Head.Contributor; - c.processContribution(steps, node); + c.processContribution(context, node); }, // Adds a closure that processes a redirect - processRedirect: function (steps, node) { + processRedirect: function (context, node) { var text = jQuery(node).text(); Wicket.Log.info("Redirecting to: " + text); window.location = text; }, // mark the focused component so that we know if it has been replaced by response - processFocusedComponentMark: function (steps) { - steps.push(function (notify) { + processFocusedComponentMark: function (context) { + context.steps.push(function (notify) { Wicket.Focus.markFocusedComponent(); // continue to next step @@ -1650,7 +1651,7 @@ }, // Processes the parsed header contribution - processContribution: function (steps, headerNode) { + processContribution: function (context, headerNode) { var xmldoc = this.parse(headerNode); var rootNode = xmldoc.documentElement; @@ -1687,21 +1688,21 @@ // process the element if (name === "link") { - this.processLink(steps, node); + this.processLink(context, node); } else if (name === "script") { - this.processScript(steps, node); + this.processScript(context, node); } else if (name === "style") { - this.processStyle(steps, node); + this.processStyle(context, node); } } else if (node.nodeType === 8) { // comment type - this.processComment(steps, node); + this.processComment(context, node); } } }, // Process an external stylesheet element - processLink: function (steps, node) { - steps.push(function (notify) { + processLink: function (context, node) { + context.steps.push(function (notify) { // if the element is already in head, skip it if (Wicket.Head.containsElement(node, "href")) { notify(); @@ -1742,8 +1743,8 @@ }, // Process an inline style element - processStyle: function (steps, node) { - steps.push(function (notify) { + processStyle: function (context, node) { + context.steps.push(function (notify) { // if element with same id is already in document, skip it if (Wicket.DOM.containsElement(node)) { notify(); @@ -1786,8 +1787,8 @@ }, // Process a script element (both inline and external) - processScript: function (steps, node) { - steps.push(function (notify) { + processScript: function (context, node) { + context.steps.push(function (notify) { // if element with same id is already in document, // or element with same src attribute is in document, skip it if (Wicket.DOM.containsElement(node) || @@ -1860,8 +1861,8 @@ }, // process (conditional) comments - processComment: function (steps, node) { - steps.push(function (notify) { + processComment: function (context, node) { + context.steps.push(function (notify) { var comment = document.createComment(node.nodeValue); Wicket.Head.addElement(comment); notify(); http://git-wip-us.apache.org/repos/asf/wicket/blob/bc9ff1fd/wicket-core/src/test/js/ajax.js ---------------------------------------------------------------------- diff --git a/wicket-core/src/test/js/ajax.js b/wicket-core/src/test/js/ajax.js index 1558735..c01929d 100644 --- a/wicket-core/src/test/js/ajax.js +++ b/wicket-core/src/test/js/ajax.js @@ -71,7 +71,7 @@ jQuery(document).ready(function() { var attrs = { u: 'data/ajax/evaluationId.xml', c: 'evaluationId' - } + }; execute(attrs); }); @@ -82,7 +82,7 @@ jQuery(document).ready(function() { var attrs = { u: 'data/ajax/priorityEvaluationId.xml', c: 'priorityEvaluationId' - } + }; execute(attrs); }); @@ -587,7 +587,7 @@ jQuery(document).ready(function() { pre: [ function () { start(); - ok(true, 'Request 3: Precondition called.') + ok(true, 'Request 3: Precondition called.'); var count = getCurrentCount(); equal(0, count, "'showIncrementallyCount' must be 0 after the executions but is: " + count); http://git-wip-us.apache.org/repos/asf/wicket/blob/bc9ff1fd/wicket-core/src/test/js/channels.js ---------------------------------------------------------------------- diff --git a/wicket-core/src/test/js/channels.js b/wicket-core/src/test/js/channels.js index 6dc99c4..25c36d0 100644 --- a/wicket-core/src/test/js/channels.js +++ b/wicket-core/src/test/js/channels.js @@ -27,7 +27,7 @@ jQuery(document).ready(function() { */ test('queue', function () { - var cm = new Wicket.ChannelManager() + var cm = new Wicket.ChannelManager(), ch = 'name|s', i = 0, result = ''; http://git-wip-us.apache.org/repos/asf/wicket/blob/bc9ff1fd/wicket-core/src/test/js/data/test.js ---------------------------------------------------------------------- diff --git a/wicket-core/src/test/js/data/test.js b/wicket-core/src/test/js/data/test.js index 32e48dd..6e60acc 100644 --- a/wicket-core/src/test/js/data/test.js +++ b/wicket-core/src/test/js/data/test.js @@ -14,5 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -var something = "else"; +(function() { + var something2 = "else"; +})();
