mirror of
https://gerrit.wikimedia.org/r/mediawiki/skins/Vector.git
synced 2024-11-28 09:30:17 +00:00
090500276d
Not all implementations will need this (e.g. the Wikibase search is based on the Action API, not the REST API), so simplify App and move this bit of complexity into the default search client instead. As far as I can tell from MediaWiki code search [1] and Global Search [2], nothing apart from Wikibase uses wgVectorSearchClient yet, so we should be able to make this breaking change now. [1]: https://codesearch.wmcloud.org/search/?q=wgVectorSearchClient [2]: https://global-search.toolforge.org/?q=wgVectorSearchClient&namespaces=2%2C4%2C8&title=%28Gadgets-definition%7C.*%5C.js%29 Change-Id: I0d52e407c12b3fbf80cd36ed66c67da4cba9acbd
225 lines
5.3 KiB
Vue
225 lines
5.3 KiB
Vue
<template>
|
|
<cdx-typeahead-search
|
|
:id="id"
|
|
ref="searchForm"
|
|
class="vector-typeahead-search"
|
|
:class="rootClasses"
|
|
:search-results-label="$i18n( 'searchresults' ).text()"
|
|
:accesskey="searchAccessKey"
|
|
:autocapitalize="autocapitalizeValue"
|
|
:title="searchTitle"
|
|
:placeholder="searchPlaceholder"
|
|
:aria-label="searchPlaceholder"
|
|
:initial-input-value="searchQuery"
|
|
:button-label="$i18n( 'searchbutton' ).text()"
|
|
:form-action="action"
|
|
:show-thumbnail="showThumbnail"
|
|
:highlight-query="highlightQuery"
|
|
:auto-expand-width="autoExpandWidth"
|
|
:search-results="suggestions"
|
|
:search-footer-url="searchFooterUrl"
|
|
@input="onInput"
|
|
@search-result-click="instrumentation.onSuggestionClick"
|
|
@submit="onSubmit"
|
|
@focus="onFocus"
|
|
@blur="onBlur"
|
|
>
|
|
<template #default>
|
|
<input
|
|
type="hidden"
|
|
name="title"
|
|
:value="searchPageTitle"
|
|
>
|
|
<input
|
|
type="hidden"
|
|
name="wprov"
|
|
:value="wprov"
|
|
>
|
|
</template>
|
|
<!-- eslint-disable-next-line vue/no-template-shadow -->
|
|
<template #search-footer-text="{ searchQuery }">
|
|
<span v-i18n-html:vector-searchsuggest-containing="[ searchQuery ]"></span>
|
|
</template>
|
|
</cdx-typeahead-search>
|
|
</template>
|
|
|
|
<script>
|
|
/* global SearchSubmitEvent */
|
|
const { CdxTypeaheadSearch } = require( '@wikimedia/codex-search' ),
|
|
{ defineComponent, nextTick } = require( 'vue' ),
|
|
client = require( './restSearchClient.js' ),
|
|
restClient = client( mw.config ),
|
|
urlGenerator = require( './urlGenerator.js' )( mw.config ),
|
|
instrumentation = require( './instrumentation.js' );
|
|
|
|
// @vue/component
|
|
module.exports = exports = defineComponent( {
|
|
name: 'App',
|
|
compatConfig: {
|
|
MODE: 3
|
|
},
|
|
compilerOptions: {
|
|
whitespace: 'condense'
|
|
},
|
|
components: { CdxTypeaheadSearch },
|
|
props: {
|
|
id: {
|
|
type: String,
|
|
required: true
|
|
},
|
|
autocapitalizeValue: {
|
|
type: String
|
|
},
|
|
searchPageTitle: {
|
|
type: String,
|
|
default: 'Special:Search'
|
|
},
|
|
autofocusInput: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
action: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
/** The keyboard shortcut to focus search. */
|
|
// eslint-disable-next-line vue/require-default-prop
|
|
searchAccessKey: {
|
|
type: String
|
|
},
|
|
/** The access key informational tip for search. */
|
|
// eslint-disable-next-line vue/require-default-prop
|
|
searchTitle: {
|
|
type: String
|
|
},
|
|
/** The ghost text shown when no search query is entered. */
|
|
// eslint-disable-next-line vue/require-default-prop
|
|
searchPlaceholder: {
|
|
type: String
|
|
},
|
|
/**
|
|
* The search query string taken from the server-side rendered input immediately before
|
|
* client render.
|
|
*/
|
|
// eslint-disable-next-line vue/require-default-prop
|
|
searchQuery: {
|
|
type: String
|
|
},
|
|
showThumbnail: {
|
|
type: Boolean,
|
|
// eslint-disable-next-line vue/no-boolean-default
|
|
default: true
|
|
},
|
|
showDescription: {
|
|
type: Boolean,
|
|
// eslint-disable-next-line vue/no-boolean-default
|
|
default: true
|
|
},
|
|
highlightQuery: {
|
|
type: Boolean,
|
|
// eslint-disable-next-line vue/no-boolean-default
|
|
default: true
|
|
},
|
|
autoExpandWidth: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
// -1 here is the default "active suggestion index".
|
|
wprov: instrumentation.getWprovFromResultIndex( -1 ),
|
|
|
|
// Suggestions to be shown in the TypeaheadSearch menu.
|
|
suggestions: [],
|
|
|
|
// Link to the search page for the current search query.
|
|
searchFooterUrl: '',
|
|
|
|
// The current search query. Used to detect whether a fetch response is stale.
|
|
currentSearchQuery: '',
|
|
|
|
// Whether to apply a CSS class that disables the CSS transitions on the text input
|
|
disableTransitions: this.autofocusInput,
|
|
|
|
instrumentation: instrumentation.listeners,
|
|
|
|
isFocused: false
|
|
};
|
|
},
|
|
computed: {
|
|
rootClasses() {
|
|
return {
|
|
'vector-search-box-disable-transitions': this.disableTransitions,
|
|
'vector-typeahead-search--active': this.isFocused
|
|
};
|
|
}
|
|
},
|
|
methods: {
|
|
/**
|
|
* Fetch suggestions when new input is received.
|
|
*
|
|
* @param {string} value
|
|
*/
|
|
onInput: function ( value ) {
|
|
const query = value.trim();
|
|
|
|
this.currentSearchQuery = query;
|
|
|
|
if ( query === '' ) {
|
|
this.suggestions = [];
|
|
this.searchFooterUrl = '';
|
|
return;
|
|
}
|
|
|
|
instrumentation.listeners.onFetchStart();
|
|
|
|
restClient.fetchByTitle( query, 10, this.showDescription ).fetch
|
|
.then( ( data ) => {
|
|
// Only use these results if they're still relevant
|
|
// If currentSearchQuery !== query, these results are for a previous search
|
|
// and we shouldn't show them.
|
|
if ( this.currentSearchQuery === query ) {
|
|
this.suggestions = instrumentation.addWprovToSearchResultUrls( data.results );
|
|
this.searchFooterUrl = urlGenerator.generateUrl( query );
|
|
}
|
|
|
|
const event = {
|
|
numberOfResults: data.results.length,
|
|
query: query
|
|
};
|
|
instrumentation.listeners.onFetchEnd( event );
|
|
} )
|
|
.catch( () => {
|
|
// TODO: error handling
|
|
} );
|
|
},
|
|
|
|
/**
|
|
* @param {SearchSubmitEvent} event
|
|
*/
|
|
onSubmit( event ) {
|
|
this.wprov = instrumentation.getWprovFromResultIndex( event.index );
|
|
|
|
instrumentation.listeners.onSubmit( event );
|
|
},
|
|
|
|
onFocus() {
|
|
this.isFocused = true;
|
|
},
|
|
|
|
onBlur() {
|
|
this.isFocused = false;
|
|
}
|
|
},
|
|
mounted() {
|
|
if ( this.autofocusInput ) {
|
|
this.$refs.searchForm.focus();
|
|
nextTick( () => {
|
|
this.disableTransitions = false;
|
|
} );
|
|
}
|
|
}
|
|
} );
|
|
</script>
|