Merge "Search: Use Codex and Vue 3 instead of WVUI and Vue 2."
This commit is contained in:
commit
3c8796ee04
|
@ -8,6 +8,9 @@
|
|||
"env": {
|
||||
"browser": true
|
||||
},
|
||||
"globals": {
|
||||
"exports": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"sourceType": "module"
|
||||
},
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
"vector-jumptocontent": "Jump to content",
|
||||
"vector-more-actions": "More",
|
||||
"vector-search-loader": "Loading search suggestions",
|
||||
"vector-searchsuggest-containing": "Search for pages containing <strong class=\"wvui-typeahead-search__suggestions__footer__text__query\">$1</strong>",
|
||||
"vector-searchsuggest-containing": "Search for pages containing <strong class=\"cdx-typeahead-search__search-footer__query\">$1</strong>",
|
||||
"vector-intro-page": "Help:Introduction",
|
||||
"vector-toc-heading": "Contents",
|
||||
"vector-toc-beginning": "Beginning",
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
"vector-jumptocontent": "Accessibility link for jumping to the content and skipping the navigation. Visually hidden by default.",
|
||||
"vector-more-actions": "Label in the Vector skin's menu for the less-important or rarer actions which are not shown as tabs (like moving the page, or for sysops deleting or protecting the page), as well as (for users with a narrow viewing window in their browser) the less-important tab actions which the user's browser is unable to fit in. {{Identical|More}}",
|
||||
"vector-search-loader": "Text to display below search input while the search suggestion module is loading",
|
||||
"vector-searchsuggest-containing": "Label used in the special item of the search suggestions list which gives the user an option to perform a full text search for the term. Used in the WVUI typeahead search component.",
|
||||
"vector-searchsuggest-containing": "Label used in the special item of the search suggestions list which gives the user an option to perform a full text search for the term. Used in the Codex typeahead search component.",
|
||||
"vector-intro-page": "Introduction or tutorial page for the wiki. Typically either Project/Help:Introduction ([[d:Q3945]]) or Project/Help:Tutorial ([[d:Q915263]]).",
|
||||
"vector-toc-heading": "Heading of table of contents\n\n{{Identical|Content}}",
|
||||
"vector-toc-beginning": "Shown in the table of contents: Text of link to the beginning of the article.",
|
||||
|
|
|
@ -108,7 +108,7 @@ class Hooks implements
|
|||
* @param Config $config
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
public static function getVectorWvuiSearchResourceLoaderConfig(
|
||||
public static function getVectorSearchResourceLoaderConfig(
|
||||
RL\Context $context,
|
||||
Config $config
|
||||
): array {
|
||||
|
|
|
@ -624,8 +624,8 @@ abstract class SkinVector extends SkinMustache {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns `true` if WVUI is enabled to show thumbnails and `false` otherwise.
|
||||
* Note this is only relevant for WVUI search (not legacy search).
|
||||
* Returns `true` if Vue search is enabled to show thumbnails and `false` otherwise.
|
||||
* Note this is only relevant for Vue search experience (not legacy search).
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
|
|
|
@ -35,15 +35,6 @@ module.exports = {
|
|||
}
|
||||
},
|
||||
|
||||
// A set of global variables that need to be available in all test environments
|
||||
globals: {
|
||||
'vue-jest': {
|
||||
babelConfig: false,
|
||||
hideStyleWarn: true,
|
||||
experimentalCSSCompile: true
|
||||
}
|
||||
},
|
||||
|
||||
// An array of file extensions your modules use
|
||||
moduleFileExtensions: [
|
||||
'js',
|
||||
|
@ -57,7 +48,9 @@ module.exports = {
|
|||
'./jest.setup.js'
|
||||
],
|
||||
|
||||
testEnvironment: 'jsdom',
|
||||
|
||||
transform: {
|
||||
'.*\\.(vue)$': '<rootDir>/node_modules/vue-jest'
|
||||
'.*\\.(vue)$': '<rootDir>/node_modules/@vue/vue3-jest'
|
||||
}
|
||||
};
|
||||
|
|
File diff suppressed because it is too large
Load Diff
19
package.json
19
package.json
|
@ -23,22 +23,24 @@
|
|||
"babel-core": "6.26.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.7.7",
|
||||
"@babel/core": "7.8.0",
|
||||
"@storybook/html": "5.2.8",
|
||||
"@types/jest": "26.0.24",
|
||||
"@types/jest": "27.0.0",
|
||||
"@types/jquery": "3.3.33",
|
||||
"@types/mustache": "4.0.1",
|
||||
"@types/node-fetch": "2.5.7",
|
||||
"@vue/composition-api": "1.4.5",
|
||||
"@vue/test-utils": "1.1.0",
|
||||
"@vue/test-utils": "2.0.1",
|
||||
"@vue/vue3-jest": "27.0.0-alpha.4",
|
||||
"@wikimedia/codex": "0.1.0-alpha.8",
|
||||
"@wikimedia/codex-icons": "0.1.0-alpha.8",
|
||||
"@wikimedia/codex-search": "0.1.0-alpha.8",
|
||||
"@wikimedia/mw-node-qunit": "6.3.0",
|
||||
"@wikimedia/types-wikimedia": "0.3.3",
|
||||
"@wikimedia/wvui": "0.3.5",
|
||||
"babel-loader": "8.0.6",
|
||||
"commander": "9.1.0",
|
||||
"eslint-config-wikimedia": "0.22.1",
|
||||
"grunt-banana-checker": "0.9.0",
|
||||
"jest": "26.4.2",
|
||||
"jest": "27.4.7",
|
||||
"jest-fetch-mock": "3.0.3",
|
||||
"jsdoc": "3.6.10",
|
||||
"jsdoc-wmf-theme": "0.0.5",
|
||||
|
@ -51,9 +53,8 @@
|
|||
"pre-commit": "1.2.2",
|
||||
"stylelint-config-wikimedia": "0.13.0",
|
||||
"svgo": "2.8.0",
|
||||
"ts-jest": "27.1.3",
|
||||
"typescript": "4.5.5",
|
||||
"vue": "2.6.11",
|
||||
"vue-jest": "3.0.7",
|
||||
"vue-template-compiler": "2.6.11"
|
||||
"vue": "3.2.33"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
|
||||
// The search input.
|
||||
// Note that these rules only apply to the non-Vue enabled search input field.
|
||||
// When Vue.js has loaded this element will no longer be in the page and subsituted with
|
||||
// a WVUI element.
|
||||
// When Vue.js has loaded this element will no longer be in the page and substituted with
|
||||
// a Codex element.
|
||||
.vector-search-box-input {
|
||||
background-color: rgba( 255, 255, 255, 0.5 );
|
||||
color: @color-base--emphasized;
|
||||
|
@ -24,7 +24,7 @@
|
|||
// `padding-right` equals to `#searchbutton` width below.
|
||||
padding: 5px @width-search-button 5px 0.4em;
|
||||
box-shadow: @box-shadow-base;
|
||||
// Match WVUI.
|
||||
// Match Codex.
|
||||
font-family: inherit;
|
||||
font-size: @font-size-search-input;
|
||||
direction: ltr;
|
||||
|
|
|
@ -138,8 +138,8 @@
|
|||
@min-width-search-button: 28px;
|
||||
@width-search-button: unit( 28 / @font-size-browser / @font-size-search-input, em );
|
||||
@font-size-search-input: unit( 13 / @font-size-browser, em ); // Equals `0.8125em`.
|
||||
// Derived from @spacing-start-typeahead-search-figure + @spacing-end-typeahead-search-figure in WVUI
|
||||
// https://gerrit.wikimedia.org/g/wvui/+/refs/changes/93/650593/10/src/components/typeahead-search/TypeaheadSearch.vue#645
|
||||
// Derived from @size-typeahead-search-focus-addition in Codex
|
||||
// https://gerrit.wikimedia.org/r/plugins/gitiles/design/codex/+/refs/tags/v0.1.0-alpha.8/packages/codex/src/components/typeahead-search/TypeaheadSearch.vue#703
|
||||
@size-search-expand: 24px;
|
||||
@margin-end-search: 12px;
|
||||
|
||||
|
|
|
@ -107,7 +107,7 @@ function initStickyHeaderABTests( abConfig, isStickyHeaderFeatureAllowed, getEna
|
|||
*/
|
||||
const main = () => {
|
||||
// Initialize the search toggle for the main header only. The sticky header
|
||||
// toggle is initialized after wvui search loads.
|
||||
// toggle is initialized after Codex search loads.
|
||||
const searchToggleElement = document.querySelector( '.mw-header .search-toggle' );
|
||||
if ( searchToggleElement ) {
|
||||
searchToggle( searchToggleElement );
|
||||
|
|
|
@ -18,12 +18,12 @@ function bindSearchBoxHandler( searchBox, header ) {
|
|||
const clickHandler = ( ev ) => {
|
||||
if (
|
||||
ev.target instanceof HTMLElement &&
|
||||
// Check if the click target was a suggestion link. WVUI clears the
|
||||
// Check if the click target was a suggestion link. Codex clears the
|
||||
// suggestion elements from the DOM when a suggestion is clicked so we
|
||||
// can't test if the suggestion is a child of the searchBox.
|
||||
//
|
||||
// Note: The .closest API is feature detected in `initSearchToggle`.
|
||||
!ev.target.closest( '.wvui-typeahead-suggestion' ) &&
|
||||
!ev.target.closest( '.cdx-typeahead-search .cdx-menu-item__content' ) &&
|
||||
!searchBox.contains( ev.target )
|
||||
) {
|
||||
header.classList.remove( SEARCH_VISIBLE_CLASS );
|
||||
|
|
|
@ -1,28 +1,23 @@
|
|||
<template>
|
||||
<!-- eslint-disable-next-line vue/no-undef-components -->
|
||||
<wvui-typeahead-search
|
||||
<cdx-typeahead-search
|
||||
:id="id"
|
||||
ref="searchForm"
|
||||
:client="getClient"
|
||||
:domain="domain"
|
||||
:suggestions-label="$i18n( 'searchresults' ).text()"
|
||||
:class="rootClasses"
|
||||
:search-results-label="$i18n( 'searchresults' ).text()"
|
||||
:accesskey="searchAccessKey"
|
||||
:title="searchTitle"
|
||||
:article-path="articlePath"
|
||||
:placeholder="searchPlaceholder"
|
||||
:aria-label="searchPlaceholder"
|
||||
:search-page-title="searchPageTitle"
|
||||
:initial-input-value="searchQuery"
|
||||
:button-label="$i18n( 'searchbutton' ).text()"
|
||||
:form-action="action"
|
||||
:search-language="language"
|
||||
:show-thumbnail="showThumbnail"
|
||||
:show-description="showDescription"
|
||||
:highlight-query="highlightQuery"
|
||||
:auto-expand-width="autoExpandWidth"
|
||||
@fetch-start="instrumentation.onFetchStart"
|
||||
@fetch-end="instrumentation.onFetchEnd"
|
||||
@suggestion-click="instrumentation.onSuggestionClick"
|
||||
:search-results="suggestions"
|
||||
:search-footer-url="searchFooterUrl"
|
||||
@input="onInput"
|
||||
@search-result-click="instrumentation.onSuggestionClick"
|
||||
@submit="onSubmit"
|
||||
>
|
||||
<template #default>
|
||||
|
@ -41,19 +36,22 @@
|
|||
<template #search-footer-text="{ searchQuery }">
|
||||
<span v-i18n-html:vector-searchsuggest-containing="[ searchQuery ]"></span>
|
||||
</template>
|
||||
</wvui-typeahead-search>
|
||||
</cdx-typeahead-search>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/* global SubmitEvent */
|
||||
const wvui = require( 'wvui-search' ),
|
||||
/* 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 = {
|
||||
module.exports = exports = defineComponent( {
|
||||
name: 'App',
|
||||
components: wvui,
|
||||
components: { CdxTypeaheadSearch },
|
||||
props: {
|
||||
id: {
|
||||
type: String,
|
||||
|
@ -65,7 +63,6 @@ module.exports = {
|
|||
},
|
||||
autofocusInput: {
|
||||
type: Boolean,
|
||||
// eslint-disable-next-line vue/no-boolean-default
|
||||
default: false
|
||||
},
|
||||
action: {
|
||||
|
@ -112,44 +109,69 @@ module.exports = {
|
|||
},
|
||||
autoExpandWidth: {
|
||||
type: Boolean,
|
||||
// eslint-disable-next-line vue/no-boolean-default
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// -1 here is the default "active suggestion index" defined in the
|
||||
// `wvui-typeahead-search` component (see
|
||||
// https://gerrit.wikimedia.org/r/plugins/gitiles/wvui/+/c7af5d6d091ffb3beb4fd2723fdf50dc6bb2789b/src/components/typeahead-search/TypeaheadSearch.vue#167).
|
||||
// -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: '',
|
||||
|
||||
// Whether to apply a CSS class that disables the CSS transitions on the text input
|
||||
disableTransitions: this.autofocusInput,
|
||||
|
||||
instrumentation: instrumentation.listeners
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
/**
|
||||
* @return {string}
|
||||
*/
|
||||
articlePath: () => mw.config.get( 'wgScript' ),
|
||||
/**
|
||||
* Allow wikis eg. Hebrew Wikipedia to replace the default search API client
|
||||
*
|
||||
* @return {module:restSearchClient~SearchClient}
|
||||
*/
|
||||
getClient: () => {
|
||||
return client( mw.config );
|
||||
},
|
||||
language: () => {
|
||||
return mw.config.get( 'wgUserLanguage' );
|
||||
},
|
||||
domain: () => {
|
||||
// It might be helpful to allow this to be configurable in future.
|
||||
return mw.config.get( 'wgVectorSearchHost', location.host );
|
||||
rootClasses() {
|
||||
return {
|
||||
'vector-search-box-disable-transitions': this.disableTransitions
|
||||
};
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* @param {SubmitEvent} event
|
||||
* Fetch suggestions when new input is received.
|
||||
*
|
||||
* @param {string} value
|
||||
*/
|
||||
onInput: function ( value ) {
|
||||
const domain = mw.config.get( 'wgVectorSearchHost', location.host ),
|
||||
query = value.trim();
|
||||
|
||||
if ( query === '' ) {
|
||||
this.suggestions = [];
|
||||
this.searchFooterUrl = '';
|
||||
return;
|
||||
}
|
||||
|
||||
instrumentation.listeners.onFetchStart();
|
||||
|
||||
restClient.fetchByTitle( query, domain, 10, this.showDescription ).fetch
|
||||
.then( ( data ) => {
|
||||
this.suggestions = 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 );
|
||||
|
@ -158,15 +180,12 @@ module.exports = {
|
|||
}
|
||||
},
|
||||
mounted() {
|
||||
// access the element associated with the wvui-typeahead-search component
|
||||
// eslint-disable-next-line no-jquery/variable-pattern
|
||||
const wvuiSearchForm = this.$refs.searchForm.$el;
|
||||
|
||||
if ( this.autofocusInput ) {
|
||||
// TODO: The wvui-typeahead-search component does not accept an autofocus parameter
|
||||
// or directive. This can be removed when its does.
|
||||
wvuiSearchForm.querySelector( 'input' ).focus();
|
||||
this.$refs.searchForm.focus();
|
||||
nextTick( () => {
|
||||
this.disableTransitions = false;
|
||||
} );
|
||||
}
|
||||
}
|
||||
};
|
||||
} );
|
||||
</script>
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
// Placeholder for ResourceLoader Virutal Config which is populated from the server.
|
||||
// Placeholder for ResourceLoader Virtual Config which is populated from the server.
|
||||
// See `VectorWvuiSearchOptions` config in Vector/skin.json for the options that are included.
|
||||
export {};
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
/* global FetchEndEvent, SuggestionClickEvent, SearchSubmitEvent */
|
||||
/** @module Instrumentation */
|
||||
|
||||
/**
|
||||
* The value of the `inputLocation` property of any and all SearchSatisfaction events sent by the
|
||||
* corresponding instrumentation.
|
||||
|
@ -133,7 +131,7 @@ function getWprovFromResultIndex( index ) {
|
|||
*/
|
||||
|
||||
/**
|
||||
* Used by the `wvui-typeahead-search` component to generate URLs for the search results. Adds a
|
||||
* Used by the Vue-enhanced search component to generate URLs for the search results. Adds a
|
||||
* `wprov` paramater to the URL to satisfy the SearchSatisfaction instrumentation.
|
||||
*
|
||||
* @see getWprovFromResultIndex
|
||||
|
@ -155,7 +153,16 @@ function generateUrl( suggestion, meta ) {
|
|||
|
||||
return result.toString();
|
||||
}
|
||||
/**
|
||||
* @typedef {Object} Instrumentation
|
||||
* @property {Object} listeners
|
||||
* @property {Function} getWprovFromResultIndex
|
||||
* @property {Function} generateUrl
|
||||
*/
|
||||
|
||||
/**
|
||||
* @type {Instrumentation}
|
||||
*/
|
||||
module.exports = {
|
||||
listeners: {
|
||||
onFetchStart,
|
||||
|
|
|
@ -1,51 +1,20 @@
|
|||
/* global RestResult, SearchResult */
|
||||
/** @module restSearchClient */
|
||||
|
||||
const fetchJson = require( './fetch.js' );
|
||||
const urlGenerator = require( './urlGenerator.js' );
|
||||
|
||||
/**
|
||||
* @typedef {Object} RestResponse
|
||||
* @property {RestResult[]} pages
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} RestResult
|
||||
* @property {number} id
|
||||
* @property {string} key
|
||||
* @property {string} title
|
||||
* @property {string} [description]
|
||||
* @property {RestThumbnail | null} [thumbnail]
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} RestThumbnail
|
||||
* @property {string} url
|
||||
* @property {number | null} [width]
|
||||
* @property {number | null} [height]
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SearchResponse
|
||||
* @property {string} query
|
||||
* @property {SearchResult[]} results
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SearchResult
|
||||
* @property {number} id
|
||||
* @property {string} key
|
||||
* @property {string} title
|
||||
* @property {string} [description]
|
||||
* @property {SearchResultThumbnail} [thumbnail]
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SearchResultThumbnail
|
||||
* @property {string} url
|
||||
* @property {number} [width]
|
||||
* @property {number} [height]
|
||||
*/
|
||||
|
||||
/**
|
||||
* Nullish coalescing operator (??) helper
|
||||
*
|
||||
|
@ -58,20 +27,26 @@ function nullish( a, b ) {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {MwMap} config
|
||||
* @param {string} query
|
||||
* @param {RestResponse} restResponse
|
||||
* @param {boolean} showDescription
|
||||
* @return {SearchResponse}
|
||||
*/
|
||||
function adaptApiResponse( query, restResponse ) {
|
||||
function adaptApiResponse( config, query, restResponse, showDescription ) {
|
||||
const urlGeneratorInstance = urlGenerator( config );
|
||||
return {
|
||||
query,
|
||||
results: restResponse.pages.map( ( page ) => {
|
||||
const thumbnail = page.thumbnail;
|
||||
return {
|
||||
id: page.id,
|
||||
value: page.id,
|
||||
label: page.title,
|
||||
key: page.key,
|
||||
title: page.title,
|
||||
description: page.description,
|
||||
description: showDescription ? page.description : undefined,
|
||||
url: urlGeneratorInstance.generateUrl( page ),
|
||||
thumbnail: thumbnail ? {
|
||||
url: thumbnail.url,
|
||||
width: nullish( thumbnail.width, undefined ),
|
||||
|
@ -111,7 +86,7 @@ function restSearchClient( config ) {
|
|||
/**
|
||||
* @type {fetchByTitle}
|
||||
*/
|
||||
fetchByTitle: ( q, domain, limit = 10 ) => {
|
||||
fetchByTitle: ( q, domain, limit = 10, showDescription = true ) => {
|
||||
const params = { q, limit };
|
||||
const url = '//' + domain + config.get( 'wgScriptPath' ) + '/rest.php/v1/search/title?' + $.param( params );
|
||||
const result = fetchJson( url, {
|
||||
|
@ -121,7 +96,7 @@ function restSearchClient( config ) {
|
|||
} );
|
||||
const searchResponsePromise = result.fetch
|
||||
.then( ( /** @type {RestResponse} */ res ) => {
|
||||
return adaptApiResponse( q, res );
|
||||
return adaptApiResponse( config, q, res, showDescription );
|
||||
} );
|
||||
return {
|
||||
abort: result.abort,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/** @module search */
|
||||
|
||||
const
|
||||
Vue = require( 'vue' ).default || require( 'vue' ),
|
||||
Vue = require( 'vue' ),
|
||||
App = require( './App.vue' ),
|
||||
config = require( './config.json' );
|
||||
|
||||
|
|
|
@ -14,4 +14,37 @@
|
|||
* @typedef {SuggestionClickEvent} SearchSubmitEvent
|
||||
*/
|
||||
|
||||
/* exported SuggestionClickEvent, SuggestionSubmitEvent, FetchEndEvent */
|
||||
/**
|
||||
* @typedef {Object} RestResult
|
||||
* @property {number} id
|
||||
* @property {string} key
|
||||
* @property {string} title
|
||||
* @property {string} [description]
|
||||
* @property {RestThumbnail | null} [thumbnail]
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} RestThumbnail
|
||||
* @property {string} url
|
||||
* @property {number | null} [width]
|
||||
* @property {number | null} [height]
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SearchResult
|
||||
* @property {number} id
|
||||
* @property {string} key
|
||||
* @property {string} title
|
||||
* @property {string} [description]
|
||||
* @property {SearchResultThumbnail} [thumbnail]
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SearchResultThumbnail
|
||||
* @property {string} url
|
||||
* @property {number} [width]
|
||||
* @property {number} [height]
|
||||
*/
|
||||
|
||||
/* exported SuggestionClickEvent, SearchSubmitEvent, FetchEndEvent, RestResult, SearchResult */
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/* global RestResult, SearchResult */
|
||||
|
||||
/**
|
||||
* @typedef {Object} UrlParams
|
||||
* @param {string} title
|
||||
* @param {string} fulltext
|
||||
*/
|
||||
|
||||
/**
|
||||
* @callback generateUrl
|
||||
* @param {RestResult|SearchResult|string} searchResult
|
||||
* @param {UrlParams} [params]
|
||||
* @param {string} [articlePath]
|
||||
* @return {string}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} UrlGenerator
|
||||
* @property {generateUrl} generateUrl
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generates URLs for suggestions like those in MediaWiki's mediawiki.searchSuggest implementation.
|
||||
*
|
||||
* @param {MwMap} config
|
||||
* @return {UrlGenerator}
|
||||
*/
|
||||
function urlGenerator( config ) {
|
||||
// TODO: This is a placeholder for enabling customization of the URL generator.
|
||||
// wgVectorSearchUrlGenerator has not been defined as a config variable yet.
|
||||
const customGenerator = config.get( 'wgVectorSearchUrlGenerator' );
|
||||
return customGenerator || {
|
||||
/**
|
||||
* @type {generateUrl}
|
||||
*/
|
||||
generateUrl(
|
||||
suggestion,
|
||||
params = {
|
||||
title: 'Special:Search'
|
||||
},
|
||||
articlePath = config.get( 'wgScript' )
|
||||
) {
|
||||
if ( typeof suggestion !== 'string' ) {
|
||||
suggestion = suggestion.title;
|
||||
} else {
|
||||
// Add `fulltext` query param to search within pages and for navigation
|
||||
// to the search results page (prevents being redirected to a certain
|
||||
// article).
|
||||
// @ts-ignore
|
||||
params.fulltext = '1';
|
||||
}
|
||||
|
||||
return articlePath + '?' + $.param( $.extend( {}, params, { search: suggestion } ) );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** @module urlGenerator */
|
||||
module.exports = urlGenerator;
|
|
@ -85,9 +85,17 @@
|
|||
}
|
||||
}
|
||||
|
||||
.wvui-typeahead-search__wrapper {
|
||||
// Make the menu below the search input wider, to match the width of the input+button
|
||||
// rather than just the width of the input
|
||||
.cdx-search-input__input-wrapper {
|
||||
position: static;
|
||||
}
|
||||
|
||||
// Since the end button's corner is now right above the menu's corner, don't use a
|
||||
// rounded corner here (T310525)
|
||||
.cdx-typeahead-search--expanded .cdx-search-input__end-button {
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,12 +14,15 @@
|
|||
|
||||
@import '../../common/variables.less';
|
||||
|
||||
// Derived from @size-search-figure in WVUI.
|
||||
// https://gerrit.wikimedia.org/r/plugins/gitiles/wvui/+/e32b54f3b8d1118b6a25cdc46b5638d6d048533e/src/themes/wikimedia-ui.less#21
|
||||
@size-search-figure: unit( 36px / @font-size-browser / @font-size-base, em );
|
||||
// Derived from @padding-vertical-typeahead-suggestion: 8px in WVUI.
|
||||
// https://gerrit.wikimedia.org/r/plugins/gitiles/wvui/+/e32b54f3b8d1118b6a25cdc46b5638d6d048533e/src/themes/wikimedia-ui.less#27
|
||||
@padding-vertical-typeahead-suggestion: 8px;
|
||||
// Derived from @size-search-figure in Codex.
|
||||
// https://gerrit.wikimedia.org/r/plugins/gitiles/design/codex/+/refs/tags/v0.1.0-alpha.8/packages/codex/src/components/typeahead-search/TypeaheadSearch.vue#676
|
||||
@size-search-figure: 40px;
|
||||
// Derived from text input start icon padding in Codex.
|
||||
// https://gerrit.wikimedia.org/r/plugins/gitiles/design/codex/+/refs/tags/v0.1.0-alpha.8/packages/codex/src/components/text-input/TextInput.vue#257
|
||||
@padding-left-start-icon: 36px;
|
||||
// Derived from @padding-vertical-menu-item: 8px in Codex.
|
||||
// https://gerrit.wikimedia.org/r/plugins/gitiles/design/codex/+/refs/tags/v0.1.0-alpha.8/packages/codex/src/components/typeahead-search/TypeaheadSearch.vue#678
|
||||
@padding-vertical-menu-item: 8px;
|
||||
|
||||
.search-form__loader:after {
|
||||
// Set the i18n message.
|
||||
|
@ -32,7 +35,10 @@
|
|||
position: absolute;
|
||||
top: 100%;
|
||||
width: 100%;
|
||||
height: ~'calc( @{padding-vertical-typeahead-suggestion} + @{size-search-figure} + @{padding-vertical-typeahead-suggestion} )';
|
||||
// Compute the height of a Codex menu item: the height of the thumbnail + the thumbnail's border
|
||||
// + the padding around the thumbnail. Then also add our own border-bottom-width, because we're
|
||||
// using box-sizing: border-box;
|
||||
height: ~'calc( @{size-search-figure} + 2*@{padding-vertical-menu-item} + 3*@{border-width-base} )';
|
||||
//
|
||||
// Ensure the 100% width doesn't extend beyond the input.
|
||||
box-sizing: border-box;
|
||||
|
@ -42,7 +48,7 @@
|
|||
border-top-width: 0; // Hide the top border so it doesn't interfere with focus state.
|
||||
border-radius: 0 0 @border-radius-base @border-radius-base;
|
||||
box-shadow: @box-shadow-base;
|
||||
padding-left: @size-search-figure;
|
||||
padding-left: @padding-left-start-icon;
|
||||
//
|
||||
// Hide text in case it extends beyond the input.
|
||||
overflow: hidden;
|
||||
|
|
|
@ -96,10 +96,14 @@
|
|||
}
|
||||
|
||||
&.vector-header-search-toggled {
|
||||
// .wvui-input__input left padding (36px) - the .wvui-icon svg width (20px)
|
||||
// - the icon left padding (12px [1]) = 4px
|
||||
// [1] see .wvui-typeahead-search--show-thumbnail .wvui-input__input:focus)
|
||||
// .vector-sticky-header-search-toggle left border (1px) + left padding (12px)
|
||||
// - .cdx-text-input__start-icon left offset (9px [1]) = 4px
|
||||
// [1] see https://gerrit.wikimedia.org/r/plugins/gitiles/design/codex/+/refs/tags/v0.1.0-alpha.8/packages/codex/src/components/text-input/TextInput.vue#257
|
||||
@margin-start-search-box: 4px;
|
||||
// .vector-sticky-header-search-toggle left border (1px) + left padding (12px)
|
||||
// - .cdx-text-input__start-icon left offset (22px [2]) = -9px
|
||||
// [2] see https://gerrit.wikimedia.org/r/plugins/gitiles/design/codex/+/refs/tags/v0.1.0-alpha.8/packages/codex/src/components/typeahead-search/TypeaheadSearch.vue#708
|
||||
@margin-start-search-box-with-thumbnail: -9px;
|
||||
|
||||
.vector-sticky-header-search-toggle,
|
||||
.vector-sticky-header-context-bar {
|
||||
|
@ -114,9 +118,9 @@
|
|||
// T296318 Decrease the start margin of the search box to account for the
|
||||
// icon's increased start position when the search component has thumbnails.
|
||||
.vector-search-box-show-thumbnail {
|
||||
margin-left: @margin-start-search-box - ( @size-search-expand / 2 );
|
||||
margin-left: @margin-start-search-box-with-thumbnail;
|
||||
|
||||
.wvui-input__start-icon {
|
||||
.cdx-text-input__start-icon {
|
||||
color: @colorGray2;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,15 +2,14 @@
|
|||
|
||||
/**
|
||||
* Minimal styling for initial no-JS server-rendered
|
||||
* search form, which gets replaced by WVUI on focus.
|
||||
* search form, which gets replaced by Codex on focus.
|
||||
* Most values are hard-coded since they aim to
|
||||
* mimic WVUI-specific variables and disable the
|
||||
* mimic Codex-specific variables and disable the
|
||||
* ResourceLoader LESS transformation of `calc`.
|
||||
*/
|
||||
|
||||
// Derived from @size-base in WVUI
|
||||
// https://gerrit.wikimedia.org/r/plugins/gitiles/wvui/+/e32b54f3b8d1118b6a25cdc46b5638d6d048533e/src/themes/wikimedia-ui.less#7
|
||||
@size-base: unit( 32px / @font-size-browser / @font-size-base, em );
|
||||
// Derived from @size-base design token in Codex
|
||||
@size-base: 32px;
|
||||
|
||||
@min-size-search-button: 30px;
|
||||
@background-size-x-search-button: unit( 20px / @font-size-browser / @font-size-base, em );
|
||||
|
@ -47,34 +46,86 @@
|
|||
background-size: @background-size-x-search-button auto;
|
||||
}
|
||||
|
||||
// Only apply the following WVUI-related rules to clients who have js enabled.
|
||||
// Only apply the following Codex-related rules to clients who have js enabled.
|
||||
.client-js .vector-search-box-vue {
|
||||
// Derived from @size-search-figure in WVUI
|
||||
// https://gerrit.wikimedia.org/r/plugins/gitiles/wvui/+/e32b54f3b8d1118b6a25cdc46b5638d6d048533e/src/themes/wikimedia-ui.less#21
|
||||
@size-search-figure: unit( 36px / @font-size-browser / @font-size-base, em );
|
||||
// Derived from @size-search-figure in Codex.
|
||||
// https://gerrit.wikimedia.org/r/plugins/gitiles/design/codex/+/refs/tags/v0.1.0-alpha.8/packages/codex/src/components/typeahead-search/TypeaheadSearch.vue#676
|
||||
@size-search-figure: 40px;
|
||||
// Derived from text input start icon padding in Codex.
|
||||
// https://gerrit.wikimedia.org/r/plugins/gitiles/design/codex/+/refs/tags/v0.1.0-alpha.8/packages/codex/src/components/text-input/TextInput.vue#257
|
||||
@padding-left-start-icon: 36px;
|
||||
|
||||
.wvui-typeahead-search__suggestion,
|
||||
.wvui-typeahead-search__suggestions__footer {
|
||||
// Remove link underline on hover that is applied by mediawiki.skinning/elements.css.
|
||||
text-decoration: none;
|
||||
}
|
||||
.cdx-typeahead-search {
|
||||
// Hide the button, only show it on hover or when the input or the button itself is focused
|
||||
.cdx-search-input__end-button {
|
||||
opacity: 0;
|
||||
// 250ms transition to match the border-color transition in CdxTextInput
|
||||
transition: opacity 250ms;
|
||||
|
||||
.wvui-typeahead-search__suggestions li {
|
||||
// Remove margin-bottom on li elements that is applied by mediawiki.skinning/elements.css.
|
||||
margin-bottom: 0;
|
||||
&:focus {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Hide the border between the input and the button
|
||||
.cdx-text-input__input:not( :hover ):not( :focus ) {
|
||||
border-right-color: transparent;
|
||||
}
|
||||
|
||||
&--active,
|
||||
&:hover {
|
||||
.cdx-search-input__end-button {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
// Make the text input's right border appear on top of the button's left border,
|
||||
// otherwise the hover transition looks weird
|
||||
.cdx-text-input {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
// Use straight corners instead of rounded corners for the border between the
|
||||
// input and the button. Only apply this on hover, to reduce (but not eliminate) the
|
||||
// tiny gap in the input's border when the button is hidden
|
||||
.cdx-text-input__input {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.cdx-menu-item {
|
||||
// Remove margin-bottom on li elements that is applied by
|
||||
// mediawiki.skinning/elements.css.
|
||||
margin-bottom: 0;
|
||||
|
||||
a {
|
||||
// Remove link underline on hover that is applied by
|
||||
// mediawiki.skinning/elements.css.
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
// Reset Codex. Prevents the input border and the start icon from animating
|
||||
// when the input gets inserted into the DOM while being focused.
|
||||
&.vector-search-box-disable-transitions {
|
||||
.cdx-text-input__input:enabled,
|
||||
.cdx-text-input__start-icon {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.vector-search-box-input {
|
||||
padding-left: @size-search-figure;
|
||||
// Derived from @padding-input-text in WVUI's Input component.
|
||||
padding-left: @padding-left-start-icon;
|
||||
// Derived from @padding-input-text in Codex's TextInput component.
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
// Move & resize search icon to match WVUI.
|
||||
// Move & resize search icon to match Codex.
|
||||
.searchButton {
|
||||
// T270202: Act like a an inert element instead of a submit button before
|
||||
// WVUI loads to discourage people clicking on it since it is a submit
|
||||
// button styled to look like WVUI's inert start icon. Note, ideally these
|
||||
// Codex loads to discourage people clicking on it since it is a submit
|
||||
// button styled to look like Codex's inert start icon. Note, ideally these
|
||||
// submit buttons should be changed to inert elements like span to be
|
||||
// semantically correct.
|
||||
pointer-events: none;
|
||||
|
@ -82,17 +133,17 @@
|
|||
right: auto;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
// Accounts for the 1px input border. Derived from
|
||||
// https://gerrit.wikimedia.org/g/wvui/+/refs/changes/93/650593/10/src/components/input/Input.vue#163
|
||||
// Accounts for the 1px input border.
|
||||
left: @border-width-base;
|
||||
// Increase size to match WVUI.
|
||||
width: @size-search-figure;
|
||||
// Increase size to match Codex.
|
||||
width: @padding-left-start-icon;
|
||||
// Set opacity to match icon color from Codex (0.51 approximates #72777d)
|
||||
opacity: 0.51;
|
||||
}
|
||||
|
||||
// Reset WVUI. Prevents the input border from animating
|
||||
// when it gets inserted into the DOM while being focused.
|
||||
.wvui-input__input:not( [ disabled ] ) {
|
||||
transition: none;
|
||||
.vector-search-box-input:focus ~ .searchButton {
|
||||
// When the input is focused, change icon color to match Codex (0.87 approximates #202122)
|
||||
opacity: 0.87;
|
||||
}
|
||||
|
||||
&.vector-search-box-show-thumbnail {
|
||||
|
@ -113,23 +164,25 @@
|
|||
width: ~'calc( 100% - @{size-search-expand} )';
|
||||
}
|
||||
|
||||
// Recreate WVUI expanding input.
|
||||
// Recreate Codex expanding input.
|
||||
&:not( .vector-search-box-auto-expand-width ) .vector-search-box-input,
|
||||
&.vector-search-box-auto-expand-width .vector-search-box-input:focus {
|
||||
margin-left: 0;
|
||||
// Use ~ and fixed values to disable the LESS transformation in ResourceLoader LESS implementation.
|
||||
padding-left: ~'calc( @{size-search-figure} + @{size-search-expand} )';
|
||||
padding-left: ~'calc( @{padding-left-start-icon} + @{size-search-expand} )';
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
// Reposition search icon for expanded input.
|
||||
&:not( .vector-search-box-auto-expand-width ) .vector-search-box-input ~ .searchButton,
|
||||
&.vector-search-box-auto-expand-width .vector-search-box-input:focus ~ .searchButton {
|
||||
// Derived from
|
||||
// https://gerrit.wikimedia.org/g/wvui/+/refs/changes/93/650593/10/src/components/typeahead-search/TypeaheadSearch.vue#655
|
||||
// (12px of space between the border and the icon) with 1px to account for the focused input border.
|
||||
@space-icon-start: @size-search-expand / 2;
|
||||
left: @space-icon-start + @border-width-base;
|
||||
// Derived from @spacing-start-typeahead-icon in Codex
|
||||
// https://gerrit.wikimedia.org/r/plugins/gitiles/design/codex/+/refs/tags/v0.1.0-alpha.8/packages/codex/src/components/typeahead-search/TypeaheadSearch.vue#708
|
||||
@spacing-start-typeahead-icon: 22px;
|
||||
// Codex uses left: @spacing-start-typeahead-icon, but we have to account for the fact
|
||||
// that we made the search button wider and centered the icon in it
|
||||
@size-icon-px: 20px;
|
||||
left: @spacing-start-typeahead-icon - ( @padding-left-start-icon - @size-icon-px ) / 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -163,17 +163,19 @@
|
|||
"es6": true,
|
||||
"dependencies": [
|
||||
"mediawiki.Uri",
|
||||
"wvui-search"
|
||||
"mediawiki.util",
|
||||
"@wikimedia/codex-search"
|
||||
],
|
||||
"packageFiles": [
|
||||
"resources/skins.vector.search/skins.vector.search.js",
|
||||
"resources/skins.vector.search/instrumentation.js",
|
||||
"resources/skins.vector.search/fetch.js",
|
||||
"resources/skins.vector.search/restSearchClient.js",
|
||||
"resources/skins.vector.search/urlGenerator.js",
|
||||
"resources/skins.vector.search/App.vue",
|
||||
{
|
||||
"name": "resources/skins.vector.search/config.json",
|
||||
"callback": "MediaWiki\\Skins\\Vector\\Hooks::getVectorWvuiSearchResourceLoaderConfig"
|
||||
"callback": "MediaWiki\\Skins\\Vector\\Hooks::getVectorSearchResourceLoaderConfig"
|
||||
}
|
||||
],
|
||||
"messages": [
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import wvui from '@wikimedia/wvui';
|
||||
import Vue from 'vue';
|
||||
import { CdxIcon, CdxButton } from '@wikimedia/codex';
|
||||
import '../node_modules/@wikimedia/codex/dist/codex.style.css';
|
||||
import { h, createApp } from 'vue';
|
||||
import buttonTemplate from '!!raw-loader!../includes/templates/Button.mustache';
|
||||
import '@wikimedia/wvui/dist/wvui.css';
|
||||
import mustache from 'mustache';
|
||||
const wvuiIconAdd = 'M11 9V4H9v5H4v2h5v5h2v-5h5V9z';
|
||||
import { cdxIconAdd } from '@wikimedia/codex-icons';
|
||||
|
||||
export default {
|
||||
title: 'Icon and Buttons'
|
||||
|
@ -52,25 +52,20 @@ function makeButtonLegacy( props, label ) {
|
|||
*/
|
||||
function makeButton( props, text, icon ) {
|
||||
const el = document.createElement( 'div' );
|
||||
const vm = new Vue( {
|
||||
el,
|
||||
render: function ( createElement ) {
|
||||
return createElement( wvui.WvuiButton, {
|
||||
props
|
||||
}, [
|
||||
createElement( wvui.WvuiIcon, {
|
||||
props: {
|
||||
icon
|
||||
}
|
||||
} ),
|
||||
const vm = createApp( {
|
||||
render: function () {
|
||||
// @ts-ignore
|
||||
return h( CdxButton, props, [
|
||||
h( CdxIcon, { icon } ),
|
||||
text
|
||||
] );
|
||||
}
|
||||
} );
|
||||
vm.mount( el );
|
||||
return `
|
||||
<tr>
|
||||
<td>${makeButtonLegacy( props, text )}</td>
|
||||
<td>${vm.$el.outerHTML}</td>
|
||||
<td>${el.outerHTML}</td>
|
||||
</tr>`;
|
||||
}
|
||||
|
||||
|
@ -114,7 +109,7 @@ function makeButtons( btns ) {
|
|||
<tbody>
|
||||
<tr>
|
||||
<th>Legacy</th>
|
||||
<th>WVUI</th>
|
||||
<th>Codex</th>
|
||||
</tr>
|
||||
${btns.join( '\n' )}
|
||||
</tbody>
|
||||
|
@ -128,26 +123,26 @@ export const Button = () => makeButtons( [
|
|||
makeButton( {
|
||||
action: 'default',
|
||||
type: 'quiet'
|
||||
}, 'Quiet button', wvuiIconAdd ),
|
||||
}, 'Quiet button', cdxIconAdd ),
|
||||
makeButton( {
|
||||
action: 'progressive',
|
||||
type: 'quiet'
|
||||
}, 'Quiet progressive', wvuiIconAdd ),
|
||||
}, 'Quiet progressive', cdxIconAdd ),
|
||||
makeButton( {
|
||||
action: 'destructive',
|
||||
type: 'quiet'
|
||||
}, 'Quiet destructive', wvuiIconAdd ),
|
||||
}, 'Quiet destructive', cdxIconAdd ),
|
||||
makeButton( {
|
||||
action: 'default',
|
||||
type: 'normal'
|
||||
}, 'Normal', wvuiIconAdd ),
|
||||
}, 'Normal', cdxIconAdd ),
|
||||
makeButton( {
|
||||
type: 'primary',
|
||||
action: 'progressive'
|
||||
}, 'Progressive primary', wvuiIconAdd ),
|
||||
}, 'Progressive primary', cdxIconAdd ),
|
||||
makeButton( {
|
||||
type: 'primary',
|
||||
action: 'destructive'
|
||||
}, 'Destructive primary', wvuiIconAdd ),
|
||||
}, 'Destructive primary', cdxIconAdd ),
|
||||
makeIcon()
|
||||
] );
|
||||
|
|
|
@ -63,8 +63,8 @@ module.exports = {
|
|||
wait: '500',
|
||||
actions: [
|
||||
'click #searchInput',
|
||||
'wait for .wvui-input__input to be added',
|
||||
'set field .wvui-input__input to Test'
|
||||
'wait for .cdx-text-input__input to be added',
|
||||
'set field .cdx-text-input__input to Test'
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
const Vue = require( 'vue' );
|
||||
const VueTestUtils = require( '@vue/test-utils' );
|
||||
const App = require( '../../resources/skins.vector.search/App.vue' );
|
||||
|
||||
// @ts-ignore
|
||||
Vue.directive( 'i18n-html', () => {} );
|
||||
|
||||
const defaultProps = {
|
||||
id: 'searchform',
|
||||
searchAccessKey: 'f',
|
||||
|
@ -16,11 +12,18 @@ const defaultProps = {
|
|||
const mount = ( /** @type {Object} */ customProps ) => {
|
||||
// @ts-ignore
|
||||
return VueTestUtils.shallowMount( App, {
|
||||
propsData: Object.assign( {}, defaultProps, customProps ),
|
||||
mocks: {
|
||||
$i18n: ( /** @type {string} */ str ) => ( {
|
||||
text: () => str
|
||||
} )
|
||||
props: Object.assign( {}, defaultProps, customProps ),
|
||||
global: {
|
||||
mocks: {
|
||||
$i18n: ( /** @type {string} */ str ) => ( {
|
||||
text: () => str
|
||||
} )
|
||||
},
|
||||
directives: {
|
||||
'i18n-html': ( el, binding ) => {
|
||||
el.innerHTML = `${binding.arg} (${binding.value})`;
|
||||
}
|
||||
}
|
||||
}
|
||||
} );
|
||||
};
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
// Instead of mocking wvui, we ensure it matches the wvui-search module
|
||||
// i.e. https://github.com/wikimedia/mediawiki/blob/master/resources/src/wvui/wvui-search.js
|
||||
// @ts-ignore
|
||||
module.exports = require( '@wikimedia/wvui/dist/commonjs2/wvui-search.commonjs2.js' ).default;
|
|
@ -1,35 +1,22 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`App renders a typeahead search component 1`] = `
|
||||
<wvui-typeahead-search-stub
|
||||
<cdx-typeahead-search-stub
|
||||
accesskey="f"
|
||||
aria-label="Search MediaWiki"
|
||||
autoexpandwidth="false"
|
||||
buttonlabel="searchbutton"
|
||||
client="[object Object]"
|
||||
domain="localhost"
|
||||
class=""
|
||||
debounceinterval="120"
|
||||
formaction=""
|
||||
highlightquery="true"
|
||||
id="searchform"
|
||||
initialinputvalue=""
|
||||
placeholder="Search MediaWiki"
|
||||
searchpagetitle="Special:Search"
|
||||
showdescription="true"
|
||||
searchfooterurl=""
|
||||
searchresults=""
|
||||
searchresultslabel="searchresults"
|
||||
showthumbnail="true"
|
||||
suggestionslabel="searchresults"
|
||||
title="search"
|
||||
urlgenerator="[object Object]"
|
||||
>
|
||||
<input
|
||||
name="title"
|
||||
type="hidden"
|
||||
value="Special:Search"
|
||||
/>
|
||||
|
||||
<input
|
||||
name="wprov"
|
||||
type="hidden"
|
||||
value="acrw1"
|
||||
/>
|
||||
<span />
|
||||
</wvui-typeahead-search-stub>
|
||||
/>
|
||||
`;
|
||||
|
|
|
@ -8,6 +8,9 @@ const configMock = {
|
|||
if ( key === 'wgScriptPath' ) {
|
||||
return '/w';
|
||||
}
|
||||
if ( key === 'wgScript' ) {
|
||||
return '/w/index.php';
|
||||
}
|
||||
return null;
|
||||
} ),
|
||||
set: jest.fn()
|
||||
|
@ -36,20 +39,26 @@ describe( 'restApiSearchClient', () => {
|
|||
{
|
||||
id: 37298,
|
||||
key: 'Media',
|
||||
label: 'Media',
|
||||
title: 'Media',
|
||||
description: 'Wikimedia disambiguation page',
|
||||
thumbnail: null
|
||||
thumbnail: null,
|
||||
url: '/w/index.php?title=Special%3ASearch&search=Media',
|
||||
value: 37298
|
||||
},
|
||||
{
|
||||
id: 323710,
|
||||
key: 'MediaWiki',
|
||||
label: 'MediaWiki',
|
||||
title: 'MediaWiki',
|
||||
description: 'wiki software',
|
||||
thumbnail: {
|
||||
width: 200,
|
||||
height: 189,
|
||||
url: thumbUrl
|
||||
}
|
||||
},
|
||||
url: '/w/index.php?title=Special%3ASearch&search=MediaWiki',
|
||||
value: 323710
|
||||
}
|
||||
]
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue