mediawiki-skins-Vector/resources/skins.vector.search/skins.vector.search.js
Nicholas Ray 93745e4800 Add search to sticky header
Per T289724#7342741, server renders an anchor tag pointing to #p-search
into the "button-start" bucket of the sticky header.

In the future after T289718, this anchor will then acts as a button when
the search module is loaded and searchToggle executes.

* skins.vector.search was modified to accomodate instantiating multiple
search components (one in the main header and one in the sticky
header).

* searchToggle.js was modified to accept a searchToggle element as a
param which the caller can then instantiate when ideal. For the sticky
header toggle, this needs to happen *after* the search module loads.
Before then, the toggle will act as a link.

* Drops one jQuery usage from searchToggle so that it can be jQuery
free. Because the native .closest method is used, IE11 support is also
dropped. However, the script feature detects and returns early if the
API isn't available.

* Makes App.vue accept an `id` prop so that multiple instances of it can
be created.

Bug: T289724
Change-Id: I1c5e6eee75918a0d06562d07c31fdcbd5a4ed6d5
2021-09-14 16:58:07 -07:00

78 lines
2.3 KiB
JavaScript

/** @module search */
var
Vue = require( 'vue' ).default || require( 'vue' ),
App = require( './App.vue' ),
config = require( './config.json' );
/**
* @param {HTMLElement} searchForm
* @param {NodeList} secondarySearchElements
* @param {HTMLInputElement} search
* @param {string|null} searchPageTitle title of page used for searching e.g. Special:Search
* If null then this will default to Special:Search.
* @return {void}
*/
function initApp( searchForm, secondarySearchElements, search, searchPageTitle ) {
/**
*
* @ignore
* @param {Function} createElement
* @param {string} id
* @return {Vue.VNode}
*/
var renderFn = function ( createElement, id ) {
return createElement( App, {
props: $.extend( {
id: id,
autofocusInput: search === document.activeElement,
action: searchForm.getAttribute( 'action' ),
searchAccessKey: search.getAttribute( 'accessKey' ),
searchPageTitle: searchPageTitle,
searchTitle: search.getAttribute( 'title' ),
searchPlaceholder: search.getAttribute( 'placeholder' ),
searchQuery: search.value
},
// Pass additional config from server.
config
)
} );
};
// eslint-disable-next-line no-new
new Vue( {
el: searchForm,
render: function ( createElement ) {
return renderFn( createElement, 'searchform' );
}
} );
// Initialize secondary search elements like the search in the sticky header.
Array.prototype.forEach.call( secondarySearchElements, function ( secondarySearchElement ) {
// eslint-disable-next-line no-new
new Vue( {
el: secondarySearchElement,
render: function ( createElement ) {
return renderFn( createElement, secondarySearchElement.id );
}
} );
} );
}
/**
* @param {Document} document
* @return {void}
*/
function main( document ) {
var
searchForm = /** @type {HTMLElement} */ ( document.querySelector( '#searchform' ) ),
titleInput = /** @type {HTMLInputElement|null} */ (
searchForm.querySelector( 'input[name=title]' )
),
search = /** @type {HTMLInputElement|null} */ ( document.getElementById( 'searchInput' ) ),
// Since App.vue requires a unique id prop, only query elements with an id attribute.
secondarySearchElements = document.querySelectorAll( '.vector-secondary-search[id]' );
if ( search && searchForm ) {
initApp( searchForm, secondarySearchElements, search, titleInput && titleInput.value );
}
}
main( document );