jenkins-bot has submitted this change and it was merged. Change subject: Hygiene: SearchApi -> SearchGateway ......................................................................
Hygiene: SearchApi -> SearchGateway Changes: * Deprecate use of abort method on Api given @krinkle's objection to upstreaming it. * Create a SearchApi wrapper for backwards compatiblity with FIXME note to kill as soon as Gather is switched over to use the SearchGateway Bug: T110718 Change-Id: I4d20f940d54c3ee1cfbaf33237e798f2d0646107 --- M includes/Resources.php M resources/mobile.categories.overlays/CategoryAddOverlay.js R resources/mobile.categories.overlays/CategoryGateway.js M resources/mobile.categories.overlays/CategoryLookupInputWidget.js M resources/mobile.categories.overlays/CategoryOverlay.js R resources/mobile.search.api/SearchGateway.js D resources/mobile.search.beta.api/SearchApi.js A resources/mobile.search.beta.api/SearchGateway.js M resources/mobile.search/SearchOverlay.js M resources/skins.minerva.categories/init.js M resources/skins.minerva.scripts/search.js R tests/qunit/mobile.search.api/test_SearchGateway.js R tests/qunit/mobile.search.beta.api/test_SearchApiGateway.js 13 files changed, 140 insertions(+), 117 deletions(-) Approvals: Phuedx: Looks good to me, approved jenkins-bot: Verified diff --git a/includes/Resources.php b/includes/Resources.php index ebac7c5..f30d95e 100644 --- a/includes/Resources.php +++ b/includes/Resources.php @@ -689,7 +689,7 @@ 'mediawiki.Title', ), 'scripts' => array( - 'resources/mobile.search.api/SearchApi.js', + 'resources/mobile.search.api/SearchGateway.js', ), ), @@ -707,7 +707,7 @@ 'mobile.search.api', ), 'scripts' => array( - 'resources/mobile.search.beta.api/SearchApi.js', + 'resources/mobile.search.beta.api/SearchGateway.js', ), ), @@ -832,7 +832,7 @@ 'oojs-ui', ), 'scripts' => array( - 'resources/mobile.categories.overlays/CategoryApi.js', + 'resources/mobile.categories.overlays/CategoryGateway.js', 'resources/mobile.categories.overlays/CategoryLookupInputWidget.js', 'resources/mobile.categories.overlays/CategoryOverlay.js', 'resources/mobile.categories.overlays/CategoryAddOverlay.js', diff --git a/resources/mobile.categories.overlays/CategoryAddOverlay.js b/resources/mobile.categories.overlays/CategoryAddOverlay.js index 282db77..573aff9 100644 --- a/resources/mobile.categories.overlays/CategoryAddOverlay.js +++ b/resources/mobile.categories.overlays/CategoryAddOverlay.js @@ -2,7 +2,7 @@ var CategoryAddOverlay, Overlay = M.require( 'mobile.overlays/Overlay' ), - CategoryApi = M.require( 'mobile.categories.overlays/CategoryApi' ), + CategoryGateway = M.require( 'mobile.categories.overlays/CategoryGateway' ), CategoryLookupInputWidget = M.require( 'mobile.categories.overlays/CategoryLookupInputWidget' ), icons = M.require( 'mobile.startup/icons' ), toast = M.require( 'mobile.toast/toast' ); @@ -11,12 +11,13 @@ * Displays the list of categories for a page * @class CategoryAddOverlay * @extends Overlay - * @uses CategoryApi + * @uses CategoryGateway */ CategoryAddOverlay = Overlay.extend( { /** * @inheritdoc * @cfg {Object} defaults Default options hash. + * @cfg {mw.Api} defaults.api to use to construct gateway * @cfg {String} defaults.waitMsg Text that displays while a page edit is being saved. * @cfg {String} defaults.waitIcon HTML of the icon that displays while a page edit * is being saved. @@ -70,9 +71,9 @@ this.wgCategories = this.options.categories; this.title = this.options.title; - this.api = new CategoryApi(); + this.gateway = new CategoryGateway( this.options.api ); input = new CategoryLookupInputWidget( { - api: this.api, + gateway: this.gateway, suggestions: this.$suggestions, categories: this.wgCategories, saveButton: this.$saveButton @@ -122,7 +123,7 @@ toast.show( mw.msg( 'mobile-frontend-categories-nodata' ), 'toast error' ); } else { // save the new categories - this.api.save( this.title, newCategories ).done( function () { + this.gateway.save( this.title, newCategories ).done( function () { M.emit( 'category-added' ); window.location.hash = '#/categories'; } ).fail( function () { diff --git a/resources/mobile.categories.overlays/CategoryApi.js b/resources/mobile.categories.overlays/CategoryGateway.js similarity index 68% rename from resources/mobile.categories.overlays/CategoryApi.js rename to resources/mobile.categories.overlays/CategoryGateway.js index 636770a..f5c3807 100644 --- a/resources/mobile.categories.overlays/CategoryApi.js +++ b/resources/mobile.categories.overlays/CategoryGateway.js @@ -1,14 +1,16 @@ -( function ( M ) { - - var CategoryApi, - SearchApi = M.require( 'mobile.search.api/SearchApi' ); +( function ( M, $ ) { + var prototype, + SearchGateway = M.require( 'mobile.search.api/SearchGateway' ); /** * Api for CategoryOverlay - * @class CategoryApi - * @extends SearchApi + * @class CategoryGateway + * @extends SearchGateway */ - CategoryApi = SearchApi.extend( { + function CategoryGateway() { + CategoryGateway.parent.apply( this, arguments ); + } + prototype = { /** * @inheritdoc */ @@ -33,7 +35,7 @@ * @returns {jQuery.Deferred} */ save: function ( title, categories ) { - return this.postWithToken( 'edit', { + return this.api.postWithToken( 'edit', { action: 'edit', title: title, appendtext: categories, @@ -47,7 +49,7 @@ * @returns {jQuery.Deferred} */ getCategories: function ( title ) { - return this.get( { + return this.api.get( { action: 'query', prop: 'categories', titles: title, @@ -55,8 +57,10 @@ cllimit: 50 // FIXME: Replace with InfiniteScroll } ); } - } ); + }; + OO.inheritClass( CategoryGateway, SearchGateway ); + $.extend( CategoryGateway.prototype, prototype ); - M.define( 'mobile.categories.overlays/CategoryApi', CategoryApi ); + M.define( 'mobile.categories.overlays/CategoryGateway', CategoryGateway ); }( mw.mobileFrontend, jQuery ) ); diff --git a/resources/mobile.categories.overlays/CategoryLookupInputWidget.js b/resources/mobile.categories.overlays/CategoryLookupInputWidget.js index 53ad774..a2e2d59 100644 --- a/resources/mobile.categories.overlays/CategoryLookupInputWidget.js +++ b/resources/mobile.categories.overlays/CategoryLookupInputWidget.js @@ -3,13 +3,13 @@ * @class CategoryLookupInputWidget * @extends OO.ui.LookupElement * @param {Object} options - * @param {CategoryApi} options.api to use to retrieve search results + * @param {CategoryGateway} options.gateway to use to retrieve search results * @param {jQuery.Object} options.suggestions container element for search suggestions * @param {jQuery.Object} options.saveButton element. Will get disabled when suggested item clicked. */ function CategoryLookupInputWidget( options ) { this.$element = $( '<div>' ); - this.api = options.api; + this.gateway = options.gateway; this.$suggestions = options.suggestions; this.categories = options.categories; this.$saveButton = options.saveButton; @@ -42,7 +42,7 @@ * @return {jQuery.Deferred} */ CategoryLookupInputWidget.prototype.getLookupRequest = function () { - return this.api.search( this.value ); + return this.gateway.search( this.value ); }; /** diff --git a/resources/mobile.categories.overlays/CategoryOverlay.js b/resources/mobile.categories.overlays/CategoryOverlay.js index 2dec1a6..202cff1 100644 --- a/resources/mobile.categories.overlays/CategoryOverlay.js +++ b/resources/mobile.categories.overlays/CategoryOverlay.js @@ -2,18 +2,19 @@ var CategoryOverlay, Overlay = M.require( 'mobile.overlays/Overlay' ), - CategoryApi = M.require( 'mobile.categories.overlays/CategoryApi' ); + CategoryGateway = M.require( 'mobile.categories.overlays/CategoryGateway' ); /** * Displays the list of categories for a page * @class CategoryOverlay * @extends Overlay - * @uses CategoryApi + * @uses CategoryGateway */ CategoryOverlay = Overlay.extend( { /** * @inheritdoc * @cfg {Object} defaults Default options hash. + * @cfg {mw.Api} defaults.api to use to construct gateway * @cfg {String} defaults.heading Title of the list of categories this page is * categorized in. * @cfg {String} defaults.subheading Introduction text for the list of categories, @@ -69,12 +70,12 @@ * @param {Object} options Object passed to the constructor. */ _loadCategories: function ( options ) { - var api = new CategoryApi(), + var gateway = new CategoryGateway( options.api ), self = this; this.$( '.topic-title-list' ).empty(); this.showSpinner(); - api.getCategories( options.title ).done( function ( data ) { + gateway.getCategories( options.title ).done( function ( data ) { if ( data.query && data.query.pages ) { options.items = []; options.hiddenitems = []; diff --git a/resources/mobile.search.api/SearchApi.js b/resources/mobile.search.api/SearchGateway.js similarity index 83% rename from resources/mobile.search.api/SearchApi.js rename to resources/mobile.search.api/SearchGateway.js index 37cc5df..c88f4f7 100644 --- a/resources/mobile.search.api/SearchApi.js +++ b/resources/mobile.search.api/SearchGateway.js @@ -1,25 +1,17 @@ -/** - * API for search - * @extends Api - * @class SearchApi - */ ( function ( M, $ ) { - - var SearchApi, - Page = M.require( 'mobile.startup/Page' ), - Api = M.require( 'mobile.startup/api' ).Api; + var Page = M.require( 'mobile.startup/Page' ); /** - * @class SearchApi - * @extends Api + * @class SearchGateway + * @uses mw.Api + * @param {mw.Api} api */ - SearchApi = Api.extend( { - /** @inheritdoc */ - initialize: function () { - Api.prototype.initialize.apply( this, arguments ); - this.searchCache = {}; - }, + function SearchGateway( api ) { + this.api = api; + this.searchCache = {}; + } + SearchGateway.prototype = { /** * The namespace to search in. * @type {Number} @@ -117,7 +109,7 @@ } ); } if ( data.query.prefixsearch ) { - // some queryies (like CategoryApi) only have prefixsearch + // some queryies (like CategoryGateway) only have prefixsearch if ( data.query.pages ) { // get results into an easily searchable shape $.each( data.query.pages, function ( i, result ) { @@ -177,7 +169,7 @@ self = this; if ( !this.isCached( query ) ) { - request = this.get( this.getApiData( query ) ) + request = this.api.get( this.getApiData( query ) ) .done( function ( data ) { // resolve the Deferred object result.resolve( { @@ -212,8 +204,28 @@ isCached: function ( query ) { return Boolean( this.searchCache[ query ] ); } - } ); + }; - M.define( 'mobile.search.api/SearchApi', SearchApi ); + /** + * A deprecated wrapper which is only here whilst Gather uses it. + * FIXME: Please remove this class as soon as Gather has been updated. + * @class SearchApi + */ + function SearchApi() { + this.gateway = new SearchGateway( new mw.Api() ); + } + /** @ignore */ + SearchApi.prototype.isCached = function () { + return this.gateway.isCached.apply( this.gateway, arguments ); + }; + /** @ignore */ + SearchApi.prototype.abort = $.noop; + /** @ignore */ + SearchApi.prototype.search = function () { + return this.gateway.search.apply( this.gateway, arguments ); + }; + + M.deprecate( 'mobile.search.api/SearchApi', SearchApi, 'SearchGateway' ); + M.define( 'mobile.search.api/SearchGateway', SearchGateway ); }( mw.mobileFrontend, jQuery ) ); diff --git a/resources/mobile.search.beta.api/SearchApi.js b/resources/mobile.search.beta.api/SearchApi.js deleted file mode 100644 index ad5c9c3..0000000 --- a/resources/mobile.search.beta.api/SearchApi.js +++ /dev/null @@ -1,43 +0,0 @@ - -( function ( M ) { - var SearchApi = M.require( 'mobile.search.api/SearchApi' ), - SearchApiBeta; - - /** - * The Api renders pages with Wikidata descriptions - * @class SearchApiBeta - * @extends SearchApi - * @inheritdoc - */ - SearchApiBeta = SearchApi.extend( { - /** - * In addition to the base data, we need to get Wikidata description for the page too - * @inheritdoc - */ - getApiData: function ( query ) { - var data = SearchApi.prototype.getApiData.call( this, query ); - data.prop = data.prop + '|pageterms'; - data.wbptterms = 'description'; - return data; - }, - - /** - * Add wikidataDescription (if it exists) to the page data - * @inheritdoc - * @returns {Object} data needed to create a {Page} - * @private - */ - _getPageData: function ( query, info ) { - var data = SearchApi.prototype._getPageData.call( this, query, info ), - terms = info.terms; - - if ( terms && terms.description && terms.description.length ) { - data.wikidataDescription = terms.description[0]; - } - return data; - } - } ); - - M.define( 'mobile.search.beta.api/SearchApi', SearchApiBeta ); - -}( mw.mobileFrontend ) ); diff --git a/resources/mobile.search.beta.api/SearchGateway.js b/resources/mobile.search.beta.api/SearchGateway.js new file mode 100644 index 0000000..fd78ae8 --- /dev/null +++ b/resources/mobile.search.beta.api/SearchGateway.js @@ -0,0 +1,43 @@ +( function ( M ) { + var SearchGateway = M.require( 'mobile.search.api/SearchGateway' ); + + /** + * The Api renders pages with Wikidata descriptions + * @class SearchGatewayBeta + * @extends SearchGateway + * @inheritdoc + */ + function SearchGatewayBeta() { + SearchGatewayBeta.parent.apply( this, arguments ); + } + OO.inheritClass( SearchGatewayBeta, SearchGateway ); + /** + * In addition to the base data, we need to get Wikidata description for the page too + * @inheritdoc + */ + SearchGatewayBeta.prototype.getApiData = function ( query ) { + var data = SearchGateway.prototype.getApiData.call( this, query ); + data.prop = data.prop + '|pageterms'; + data.wbptterms = 'description'; + return data; + }; + + /** + * Add wikidataDescription (if it exists) to the page data + * @inheritdoc + * @returns {Object} data needed to create a {Page} + * @private + */ + SearchGatewayBeta.prototype._getPageData = function ( query, info ) { + var data = SearchGateway.prototype._getPageData.call( this, query, info ), + terms = info.terms; + + if ( terms && terms.description && terms.description.length ) { + data.wikidataDescription = terms.description[0]; + } + return data; + }; + + M.define( 'mobile.search.beta.api/SearchGateway', SearchGatewayBeta ); + +}( mw.mobileFrontend ) ); diff --git a/resources/mobile.search/SearchOverlay.js b/resources/mobile.search/SearchOverlay.js index b5fe7e2..ea91af5 100644 --- a/resources/mobile.search/SearchOverlay.js +++ b/resources/mobile.search/SearchOverlay.js @@ -15,7 +15,7 @@ * Overlay displaying search results * @class SearchOverlay * @extends Overlay - * @uses SearchApi + * @uses SearchGateway * @uses Icon */ SearchOverlay = Overlay.extend( { @@ -28,6 +28,7 @@ /** * @inheritdoc * @cfg {Object} defaults Default options hash. + * @cfg {SearchGateway} defaults.gateway An API gateway to use to retrieve search results * @cfg {Object} defaults.clearIcon options for the button that clears the search text. * @cfg {Object} defaults.searchContentIcon options for the button that allows you to search within content * @cfg {String} defaults.searchTerm Search text. @@ -102,8 +103,7 @@ initialize: function ( options ) { var self = this; Overlay.prototype.initialize.call( this, options ); - // use the given api module or use the default SearchApi - this.api = options.api || new M.require( 'mobile.search.api/SearchApi' ); + this.gateway = options.gateway; // FIXME: Remove when search registers route with overlay manager // we need this because of the focus/delay hack in search.js @@ -286,6 +286,8 @@ /** * Perform search and render results inside current view. + * FIXME: Much of the logic for caching and pending queries inside this function should + * actually live in SearchGateway, please move out. * @method */ performSearch: function () { @@ -298,7 +300,9 @@ // it seems the input event can be fired when virtual keyboard is closed // (Chrome for Android) if ( query !== this.lastQuery ) { - this.api.abort(); + if ( self._pendingQuery ) { + self._pendingQuery.abort(); + } clearTimeout( this.timer ); self.$searchContent.hide(); self.$searchFeedback.hide(); @@ -316,7 +320,7 @@ */ M.emit( 'search-start' ); - self.api.search( query ).done( function ( data ) { + self._pendingQuery = self.gateway.search( query ).done( function ( data ) { // check if we're getting the rights response in case of out of // order responses (need to get the current value of the input) if ( data.query === self.$input.val() ) { @@ -348,7 +352,7 @@ } ); } } ); - }, this.api.isCached( query ) ? 0 : SEARCH_DELAY ); + }, this.gateway.isCached( query ) ? 0 : SEARCH_DELAY ); } else { self.$( '.spinner' ).hide(); } diff --git a/resources/skins.minerva.categories/init.js b/resources/skins.minerva.categories/init.js index b8c90c4..dedf3e1 100644 --- a/resources/skins.minerva.categories/init.js +++ b/resources/skins.minerva.categories/init.js @@ -15,6 +15,7 @@ loadingOverlay.hide(); result.resolve( new CategoryOverlay( { + api: new mw.Api(), isAnon: user.isAnon(), title: M.getCurrentPage().title } ) ); @@ -31,6 +32,7 @@ loadingOverlay.hide(); result.resolve( new CategoryAddOverlay( { + api: new mw.Api(), categories: mw.config.get( 'wgCategories' ), isAnon: user.isAnon(), title: M.getCurrentPage().title diff --git a/resources/skins.minerva.scripts/search.js b/resources/skins.minerva.scripts/search.js index cec2e8e..4eb100a 100644 --- a/resources/skins.minerva.scripts/search.js +++ b/resources/skins.minerva.scripts/search.js @@ -1,5 +1,6 @@ ( function ( M, $ ) { - var searchPlaceholderMsg = 'mobile-frontend-placeholder', + var SearchOverlay, SearchGateway, + searchPlaceholderMsg = 'mobile-frontend-placeholder', SchemaMobileWebClickTracking = M.require( 'mobile.loggingSchemas/SchemaMobileWebClickTracking' ), uiSchema = new SchemaMobileWebClickTracking( {}, 'MobileWebUIClickTracking' ), context = M.require( 'mobile.context/context' ), @@ -7,16 +8,14 @@ browser = M.require( 'mobile.browser/browser' ), moduleConfig = { modules: [ 'mobile.search.api', 'mobile.search' ], - api: 'mobile.search.api/SearchApi', + api: 'mobile.search.api/SearchGateway', overlay: 'mobile.search/SearchOverlay' - }, - SearchOverlay, - SearchApi; + }; if ( context.isBetaGroupMember() ) { moduleConfig = $.extend( moduleConfig, { modules: [ 'mobile.search.beta.api', 'mobile.search.beta' ], - api: 'mobile.search.beta.api/SearchApi' + api: 'mobile.search.beta.api/SearchGateway' } ); } @@ -37,11 +36,11 @@ } ); mw.loader.using( moduleConfig.modules ).done( function () { - SearchApi = M.require( moduleConfig.api ); + SearchGateway = M.require( moduleConfig.api ); SearchOverlay = M.require( moduleConfig.overlay ); new SearchOverlay( { - api: new SearchApi(), + gateway: new SearchGateway( new mw.Api() ), searchTerm: searchTerm, placeholderMsg: placeholder } ).show(); diff --git a/tests/qunit/mobile.search/test_SearchApi.js b/tests/qunit/mobile.search.api/test_SearchGateway.js similarity index 87% rename from tests/qunit/mobile.search/test_SearchApi.js rename to tests/qunit/mobile.search.api/test_SearchGateway.js index d3198ef..8807e7a 100644 --- a/tests/qunit/mobile.search/test_SearchApi.js +++ b/tests/qunit/mobile.search.api/test_SearchGateway.js @@ -1,12 +1,11 @@ ( function ( $, M ) { - var SearchApi = M.require( 'mobile.search.api/SearchApi' ), - api; + var SearchGateway = M.require( 'mobile.search.api/SearchGateway' ); QUnit.module( 'MobileFrontend: SearchApi', { setup: function () { - api = new SearchApi(); - this.sandbox.stub( SearchApi.prototype, 'get', function () { + this.gateway = new SearchGateway( new mw.Api() ); + this.sandbox.stub( this.gateway.api, 'get', function () { return $.Deferred().resolve( { warnings: { query: { @@ -70,7 +69,10 @@ } ); QUnit.test( '._highlightSearchTerm', 14, function ( assert ) { - var data = [ + var data, + gateway = this.gateway; + + data = [ [ 'Hello World', 'Hel', '<strong>Hel</strong>lo World' ], [ 'Hello kitty', 'el', 'Hello kitty' ], // not at start [ 'Hello worl', 'hel', '<strong>Hel</strong>lo worl' ], @@ -87,14 +89,13 @@ [ '<script>alert("FAIL")</script> should be safe', '<script>alert("FAIL"', '<strong><script>alert("FAIL"</strong>)</script> should be safe' ] ]; - $.each( data, function ( i, item ) { - assert.strictEqual( api._highlightSearchTerm( item[ 0 ], item[ 1 ] ), item[ 2 ], 'highlightSearchTerm test ' + i ); + assert.strictEqual( gateway._highlightSearchTerm( item[ 0 ], item[ 1 ] ), item[ 2 ], 'highlightSearchTerm test ' + i ); } ); } ); QUnit.test( 'show redirect targets', 6, function ( assert ) { - api.search( 'barack' ).done( function ( response ) { + this.gateway.search( 'barack' ).done( function ( response ) { assert.strictEqual( response.query, 'barack' ); assert.strictEqual( response.results.length, 2 ); assert.strictEqual( response.results[ 0 ].displayTitle, 'Claude Monet' ); diff --git a/tests/qunit/mobile.search.beta/test_SearchApi.js b/tests/qunit/mobile.search.beta.api/test_SearchApiGateway.js similarity index 83% rename from tests/qunit/mobile.search.beta/test_SearchApi.js rename to tests/qunit/mobile.search.beta.api/test_SearchApiGateway.js index df9ba7f..b6312ac 100644 --- a/tests/qunit/mobile.search.beta/test_SearchApi.js +++ b/tests/qunit/mobile.search.beta.api/test_SearchApiGateway.js @@ -1,8 +1,7 @@ ( function ( $, M ) { + var SearchGateway = M.require( 'mobile.search.beta.api/SearchGateway' ); - var SearchApi = M.require( 'mobile.search.beta.api/SearchApi' ); - - QUnit.module( 'MobileFrontend SearchApi', { + QUnit.module( 'MobileFrontend SearchGateway', { setup: function () { var data = { query: { @@ -51,12 +50,12 @@ ] } }; - this.stub( SearchApi.prototype, 'get' ).returns( $.Deferred().resolve( data ) ); + this.sandbox.stub( mw.Api.prototype, 'get' ).returns( $.Deferred().resolve( data ) ); } } ); QUnit.asyncTest( 'Wikidata Description in search results', 3, function ( assert ) { - var searchApi = new SearchApi(); + var searchApi = new SearchGateway( new mw.Api() ); searchApi.search( 'brad' ).done( function ( resp ) { var results = resp.results; QUnit.start(); -- To view, visit https://gerrit.wikimedia.org/r/237491 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I4d20f940d54c3ee1cfbaf33237e798f2d0646107 Gerrit-PatchSet: 16 Gerrit-Project: mediawiki/extensions/MobileFrontend Gerrit-Branch: master Gerrit-Owner: Jdlrobson <jrob...@wikimedia.org> Gerrit-Reviewer: Jdlrobson <jrob...@wikimedia.org> Gerrit-Reviewer: Phuedx <g...@samsmith.io> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits