Catrope has uploaded a new change for review. https://gerrit.wikimedia.org/r/208323
Change subject: Revert "Get rid over queryMap overrides" ...................................................................... Revert "Get rid over queryMap overrides" This reverts commit 6f72ea39562aeff94636b81185f099e20d9aa871. Change-Id: I204dc80a02e7fb220b4fb6cc5e8b058b6c61fe15 --- M modules/engine/components/board/base/flow-board-api-events.js M modules/engine/components/board/features/flow-board-loadmore.js M modules/engine/components/board/features/flow-board-toc.js M modules/engine/components/common/flow-component-events.js M modules/engine/misc/flow-api.js 5 files changed, 122 insertions(+), 83 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Flow refs/changes/23/208323/1 diff --git a/modules/engine/components/board/base/flow-board-api-events.js b/modules/engine/components/board/base/flow-board-api-events.js index a2ea262..e0de540 100644 --- a/modules/engine/components/board/base/flow-board-api-events.js +++ b/modules/engine/components/board/base/flow-board-api-events.js @@ -34,11 +34,9 @@ * real editor can be anything, depending on the type of editor) * * @param {Event} event - * @param {Object} info - * @param {Object} queryMap * @return {Object} */ - FlowBoardComponentApiEventsMixin.UI.events.globalApiPreHandlers.prepareEditor = function ( event, info, queryMap ) { + FlowBoardComponentApiEventsMixin.UI.events.globalApiPreHandlers.prepareEditor = function ( event ) { var $textareas = $( this ).closest( 'form' ).find( 'textarea' ), override = {}; @@ -61,7 +59,7 @@ // add its own nodes, which may be picked up by serializeArray() } ); - return $.extend( {}, queryMap, override ); + return override; }; /** @@ -70,16 +68,14 @@ * This will prepare the data-to-be-submitted so that the override is * submitted against the most current revision ID. * @param {Event} event - * @param {Object} info - * @param {Object} queryMap * @return {Object} */ - FlowBoardComponentApiEventsMixin.UI.events.globalApiPreHandlers.prepareEditConflict = function ( event, info, queryMap ) { + FlowBoardComponentApiEventsMixin.UI.events.globalApiPreHandlers.prepareEditConflict = function ( event ) { var $form = $( this ).closest( 'form' ), prevRevisionId = $form.data( 'flow-prev-revision' ); if ( !prevRevisionId ) { - return queryMap; + return {}; } // Get rid of the temp-saved new revision ID @@ -91,78 +87,71 @@ * be properly applied for the respective API call; e.g. * epprev_revision (for edit post) */ - return $.extend( {}, queryMap, { + return { flow_prev_revision: prevRevisionId - } ); + }; }; /** * Before activating header, sends an overrideObject to the API to modify the request params. * @param {Event} event - * @param {Object} info - * @param {Object} queryMap * @return {Object} */ - FlowBoardComponentApiEventsMixin.UI.events.apiPreHandlers.activateEditHeader = function ( event, info, queryMap ) { - return $.extend( {}, queryMap, { + FlowBoardComponentApiEventsMixin.UI.events.apiPreHandlers.activateEditHeader = function () { + return { submodule: 'view-header', // href submodule is edit-header vhformat: mw.flow.editor.getFormat() // href does not have this param - } ); + }; }; /** * Before activating topic, sends an overrideObject to the API to modify the request params. * * @param {Event} event - * @param {Object} info - * @param {Object} queryMap * @return {Object} */ - FlowBoardComponentApiEventsMixin.UI.events.apiPreHandlers.activateEditTitle = function ( event, info, queryMap ) { + FlowBoardComponentApiEventsMixin.UI.events.apiPreHandlers.activateEditTitle = function ( event ) { // Use view-post API for topic as well; we only want this on // particular (title) post revision, not the full topic - return $.extend( {}, queryMap, { + return { submodule: "view-post", vppostId: $( this ).closest( '.flow-topic' ).data( 'flow-id' ), vpformat: mw.flow.editor.getFormat() - } ); + }; }; /** * Before activating post, sends an overrideObject to the API to modify the request params. * @param {Event} event - * @param {Object} info - * @param {Object} queryMap * @return {Object} */ - FlowBoardComponentApiEventsMixin.UI.events.apiPreHandlers.activateEditPost = function ( event, info, queryMap ) { - return $.extend( {}, queryMap, { + FlowBoardComponentApiEventsMixin.UI.events.apiPreHandlers.activateEditPost = function ( event ) { + return { submodule: 'view-post', vppostId: $( this ).closest( '.flow-post' ).data( 'flow-id' ), vpformat: mw.flow.editor.getFormat() - } ); + }; }; /** * Adjusts query params to use global watch action, and specifies it should use a watch token. * @param {Event} event - * @param {Object} info - * @param {Object} queryMap - * @returns {Object} + * @returns {Function} */ - FlowBoardComponentApiEventsMixin.UI.events.apiPreHandlers.watchItem = function ( event, info, queryMap ) { - var params = { - action: 'watch', - titles: queryMap.page, - _internal: { - tokenType: 'watch' + FlowBoardComponentApiEventsMixin.UI.events.apiPreHandlers.watchItem = function ( event ) { + return function ( queryMap ) { + var params = { + action: 'watch', + titles: queryMap.page, + _internal: { + tokenType: 'watch' + } + }; + if ( queryMap.submodule === 'unwatch' ) { + params.unwatch = 1; } + return params; }; - if ( queryMap.submodule === 'unwatch' ) { - params.unwatch = 1; - } - - return params; }; /** @@ -170,10 +159,9 @@ * API to modify the request params. * @param {Event} event * @param {Object} info - * @param {Object} queryMap * @return {Object} */ - FlowBoardComponentApiEventsMixin.UI.events.apiPreHandlers.activateSummarizeTopic = function ( event, info, queryMap ) { + FlowBoardComponentApiEventsMixin.UI.events.apiPreHandlers.activateSummarizeTopic = function ( event, info ) { if ( info.$target.find( 'form' ).length ) { // Form already open; cancel the old form var flowBoard = mw.flow.getPrototypeMethod( 'board', 'getInstanceByElement' )( $( this ) ); @@ -181,31 +169,29 @@ return false; } - return $.extend( {}, queryMap, { + return { // href submodule is edit-topic-summary submodule: 'view-topic-summary', // href does not have this param vtsformat: mw.flow.editor.getFormat() - } ); + }; }; /** * Before activating lock/unlock edit form, sends an overrideObject * to the API to modify the request params. * @param {Event} event - * @param {Object} info - * @param {Object} queryMap * @return {Object} */ - FlowBoardComponentApiEventsMixin.UI.events.apiPreHandlers.activateLockTopic = function ( event, info, queryMap ) { - return $.extend( {}, queryMap, { + FlowBoardComponentApiEventsMixin.UI.events.apiPreHandlers.activateLockTopic = function ( event ) { + return { // href submodule is lock-topic submodule: 'view-post', // href does not have this param vpformat: 'wikitext', // request just the data for this topic vppostId: $( this ).data( 'flow-id' ) - } ); + }; }; // diff --git a/modules/engine/components/board/features/flow-board-loadmore.js b/modules/engine/components/board/features/flow-board-loadmore.js index c08c0f8..c7024a5 100644 --- a/modules/engine/components/board/features/flow-board-loadmore.js +++ b/modules/engine/components/board/features/flow-board-loadmore.js @@ -159,10 +159,9 @@ * @param {Event} event * @param {Object} info * @param {jQuery} info.$target - * @param {object} queryMap * @param {FlowBoardComponent} info.component */ - function flowBoardComponentLoadMoreFeatureBoardApiPreHandler( event, info, queryMap ) { + function flowBoardComponentLoadMoreFeatureBoardApiPreHandler( event, info ) { // Backup the topic data info.component.renderedTopicsBackup = info.component.renderedTopics; info.component.topicTitlesByIdBackup = info.component.topicTitlesById; diff --git a/modules/engine/components/board/features/flow-board-toc.js b/modules/engine/components/board/features/flow-board-toc.js index c9019dc..4d64730 100644 --- a/modules/engine/components/board/features/flow-board-toc.js +++ b/modules/engine/components/board/features/flow-board-toc.js @@ -38,10 +38,9 @@ * @param {Event} event * @param {Object} info * @param {jQuery} info.$target - * @param {object} queryMap * @param {FlowBoardComponent} info.component */ - function flowBoardComponentTocFeatureMixinBoardApiPreHandler( event, info, queryMap ) { + function flowBoardComponentTocFeatureMixinBoardApiPreHandler( event, info ) { info.component.topicIdsInTocBackup = info.component.topicIdsInToc; info.component.lastTopicIdInTocBackup = info.component.lastTopicIdInToc; @@ -61,10 +60,9 @@ * @param {Event} event * @param {Object} info * @param {jQuery} info.$target - * @param {object} queryMap * @param {FlowBoardComponent} info.component */ - function flowBoardComponentTocFeatureMixinTopicListApiPreHandler( event, info, queryMap, extraParameters ) { + function flowBoardComponentTocFeatureMixinTopicListApiPreHandler( event, info, extraParameters ) { var $this = $( this ), isLoadMoreButton = $this.data( 'flow-load-handler' ) === 'loadMore', overrides; @@ -101,7 +99,7 @@ delete overrides.topiclist_sortby; } - return $.extend( {}, queryMap, overrides ); + return overrides; } FlowBoardComponentTocFeatureMixin.UI.events.apiPreHandlers.topicList = flowBoardComponentTocFeatureMixinTopicListApiPreHandler; diff --git a/modules/engine/components/common/flow-component-events.js b/modules/engine/components/common/flow-component-events.js index 226fbd4..8a20709 100644 --- a/modules/engine/components/common/flow-component-events.js +++ b/modules/engine/components/common/flow-component-events.js @@ -265,13 +265,13 @@ flowComponent = mw.flow.getPrototypeMethod( 'component', 'getInstanceByElement' )( $this ), dataParams = $this.data(), handlerName = dataParams.flowApiHandler, + preHandlerReturns = [], info = { $target: null, status: null, component: flowComponent }, - args = Array.prototype.slice.call( arguments, 0 ), - queryMap = flowComponent.Api.getQueryMap( self.href || self ); + args = Array.prototype.slice.call( arguments, 0 ); event.preventDefault(); @@ -285,10 +285,8 @@ $target = $this; } - // insert queryMap & info into args for prehandler info.$target = $target; - args.splice( 1, 0, info ); - args.splice( 2, 0, queryMap ); + args.splice( 1, 0, info ); // insert info into args for prehandler // Make sure an API call is not already in progress for this target if ( $target.closest( '.flow-api-inprogress' ).length ) { @@ -303,7 +301,7 @@ // Let generic pre-handler take care of edit conflicts $.each( flowComponent.UI.events.globalApiPreHandlers, function( key, callbackArray ) { $.each( callbackArray, function ( i, callbackFn ) { - queryMap = callbackFn.apply( self, args ); + preHandlerReturns.push( callbackFn.apply( self, args ) ); } ); } ); @@ -315,18 +313,15 @@ if ( flowComponent.UI.events.apiPreHandlers[ handlerName ] ) { // apiPreHandlers can return FALSE to prevent processing, // nothing at all to proceed, - // or new queryMap (= API params) + // or OBJECT to add param overrides to the API + // or FUNCTION to modify API params $.each( flowComponent.UI.events.apiPreHandlers[ handlerName ], function ( i, callbackFn ) { - // make sure queryMap is up to date (may have been altered by - // previous preHandler) - args.splice( 2, 1, queryMap ); preHandlerReturn = callbackFn.apply( self, args ); + preHandlerReturns.push( preHandlerReturn ); if ( preHandlerReturn === false ) { // Callback returned false; break out of this loop return false; - } else { - queryMap = preHandlerReturn; } } ); @@ -335,7 +330,7 @@ flowComponent.debug( false, 'apiPreHandler returned false', handlerName, args ); // Abort any old request in flight; this is normally done automatically by requestFromNode - flowComponent.Api.abortOldRequestFromNode( self, queryMap, null ); + flowComponent.Api.abortOldRequestFromNode( self, null, null, preHandlerReturns ); // @todo support for multiple indicators on same target $target.removeClass( 'flow-api-inprogress' ); @@ -346,7 +341,7 @@ } // Make the request - $deferred = flowComponent.Api.requestFromNode( self, queryMap ); + $deferred = flowComponent.Api.requestFromNode( self, preHandlerReturns ); if ( !$deferred ) { mw.flow.debug( '[FlowApi] [interactiveHandlers] apiRequest element is not anchor or form element' ); $deferred = $.Deferred(); diff --git a/modules/engine/misc/flow-api.js b/modules/engine/misc/flow-api.js index 1949950..d01c6ee 100644 --- a/modules/engine/misc/flow-api.js +++ b/modules/engine/misc/flow-api.js @@ -155,12 +155,39 @@ FlowApi.prototype.setDefaultSubmodule = flowApiSetDefaultSubmodule; /** + * Overrides (values of) queryMap with a provided override, which can come + * in the form of an object (which the queryMap will be extended with) or as + * a function (whose return value will replace queryMap) + * + * @param {Object} [queryMap] + * @param {Function|Object} [override] + * @returns {Object} + */ + function flowOverrideQueryMap( queryMap, override ) { + if ( override ) { + switch ( typeof override ) { + // If given an override object, extend our queryMap with it + case 'object': + $.extend( queryMap, override ); + break; + // If given an override function, call it and make it return the new queryMap + case 'function': + queryMap = override( queryMap ); + break; + } + } + + return queryMap; + } + + /** * With a url (a://b.c/d?e=f&g#h) will return an object of key-value pairs ({e:'f', g:''}). * @param {String|Element} url * @param {Object} [queryMap] + * @param {Array<(Function|Object)>} [overrides] * @returns {Object} */ - function flowApiGetQueryMap( url, queryMap ) { + function flowApiGetQueryMap( url, queryMap, overrides ) { var uri, queryKey, queryValue, @@ -168,6 +195,7 @@ $node, $form, formData; queryMap = queryMap || {}; + overrides = overrides || []; // If URL is an Element... if ( typeof url !== 'string' ) { @@ -233,6 +261,11 @@ // Default action is flow queryMap.action = queryMap.action || 'flow'; + // Override the automatically generated queryMap + for ( i = 0; i < overrides.length; i++ ) { + queryMap = flowOverrideQueryMap( queryMap, overrides[i] ); + } + // Use the API map to transform this data if necessary, eg. queryMap = flowApiTransformMap( queryMap ); @@ -245,13 +278,24 @@ * Using a given form, parses its action, serializes the data, and sends it as GET or POST depending on form method. * With button, its name=value is serialized in. If button is an Event, it will attempt to find the clicked button. * Additional params can be set with data-flow-api-params on both the clicked button or the form. - * @param {Event|Element} button - * @param {Object} queryMap + * @param {Event|Element} [button] + * @param {Array<(Function|Object)>} [overrides] * @return {$.Deferred} */ - function flowApiRequestFromForm( button, queryMap ) { - var $button = $( button ), - method = $button.closest( 'form' ).attr( 'method' ) || 'GET'; + function flowApiRequestFromForm( button, overrides ) { + var $deferred = $.Deferred(), + $button = $( button ), + method = $button.closest( 'form' ).attr( 'method' ) || 'GET', + queryMap; + + // Parse the form action to get the rest of the queryMap + if ( !( queryMap = this.getQueryMap( button, null, overrides ) ) ) { + return $deferred.rejectWith( { error: 'Invalid form action' } ); + } + + if ( !( queryMap.action ) ) { + return $deferred.rejectWith( { error: 'Unknown action for form' } ); + } // Cancel any old form request, and also trigger a new one return this.abortOldRequestFromNode( $button, queryMap, method ); @@ -263,12 +307,20 @@ * Using a given anchor, parses its URL and sends it as a GET (default) or POST depending on data-flow-api-method. * Additional params can be set with data-flow-api-params. * @param {Element} anchor - * @param {Object} queryMap + * @param {Array<(Function|Object)>} [overrides] * @return {$.Deferred} */ - function flowApiRequestFromAnchor( anchor, queryMap ) { + function flowApiRequestFromAnchor( anchor, overrides ) { var $anchor = $( anchor ), + $deferred = $.Deferred(), + queryMap, method = $anchor.data( 'flow-api-method' ) || 'GET'; + + // Build the query map from this anchor's HREF + if ( !( queryMap = this.getQueryMap( anchor.href, null, overrides ) ) ) { + mw.flow.debug( '[FlowApi] requestFromAnchor error: invalid href', arguments ); + return $deferred.rejectWith( { error: 'Invalid href' } ); + } // Abort any old requests, and have it issue a new one via GET or POST return this.abortOldRequestFromNode( $anchor, queryMap, method ); @@ -279,10 +331,10 @@ /** * Automatically calls requestFromAnchor or requestFromForm depending on the type of node given. * @param {Element} node - * @param {Object} queryMap - * @return {$.Deferred} + * @param {Array<(Function|Object)>} [overrides] + * @return {$.Deferred|bool} */ - function flowApiRequestFromNode( node, queryMap ) { + function flowApiRequestFromNode( node, overrides ) { var $node = $( node ); if ( $node.is( 'a' ) ) { @@ -290,7 +342,7 @@ } else if ( $node.is( 'form, input, button, textarea, select, option' ) ) { return this.requestFromForm.apply( this, arguments ); } else { - return $.Deferred().reject(); + return false; } } @@ -300,13 +352,22 @@ * Handles aborting an old in-flight API request. * If startNewMethod is given, this method also STARTS a new API call and stores it for later abortion if needed. * @param {jQuery|Element} $node - * @param {Object} queryMap + * @param {Object} [queryMap] * @param {String} [startNewMethod] If given: starts, stores, and returns a new API call + * @param {Array<(Function|Object)>} [overrides] * @return {undefined|$.Deferred} */ - function flowApiAbortOldRequestFromNode( $node, queryMap, startNewMethod ) { + function flowApiAbortOldRequestFromNode( $node, queryMap, startNewMethod, overrides ) { $node = $( $node ); + if ( !queryMap ) { + // Get the queryMap automatically if one wasn't given + if ( !( queryMap = this.getQueryMap( $node, null, overrides ) ) ) { + mw.flow.debug( '[FlowApi] abortOldRequestFromNode failed to find a queryMap', arguments ); + return; + } + } + // If this anchor already has a request in flight, abort it var str = 'flow-api-query-temp-' + queryMap.action + '-' + queryMap.submodule, prevApiCall = $node.data( str ), -- To view, visit https://gerrit.wikimedia.org/r/208323 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I204dc80a02e7fb220b4fb6cc5e8b058b6c61fe15 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/Flow Gerrit-Branch: master Gerrit-Owner: Catrope <roan.katt...@gmail.com> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits