Skip to content

feat: accept dom element #653

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ Add the following code to one of your `HTML` files.

The `hostUrl` and the `apiKey` (_optional_) fields are the credentials of your Meilisearch instance.<br>
`indexUid` is the index identifier in your Meilisearch instance in which your website content is stored.<br>
`inputSelector` is the `id` attribute of the HTML search input tag.
`inputSelector` is the `id` attribute of the HTML search input tag. As an alternative the dom element can be supplied with `inputElement` directly.

_Your documentation content is not indexed yet? Check out [this tutorial](https://docs.meilisearch.com/create/how_to/search_bar_for_docs.html)._

Expand Down
46 changes: 32 additions & 14 deletions src/lib/DocsSearchBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import { constructClientAgents } from './agents'
* @param {string} options.hostUrl URL where Meilisearch instance is hosted
* @param {string} options.apiKey Read-only API key
* @param {string} options.indexUid UID of the index to target
* @param {string} options.inputSelector CSS selector that targets the input
* @param {string} [options.inputSelector] CSS selector that targets the input
* @param {Element} [options.inputElement] Input element
* @param {boolean} [options.debug] When set to true, the dropdown will not be closed on blur
* @param {Object} [options.meilisearchOptions] Options to pass the underlying Meilisearch client
* @param {function} [options.queryDataCallback] This function will be called when querying Meilisearch
Expand All @@ -29,7 +30,8 @@ const usage = `Usage:
hostUrl,
apiKey,
indexUid,
inputSelector,
[ inputSelector ],
[ inputElement ],
[ debug ],
[ meilisearchOptions ],
[ queryDataCallback ],
Expand All @@ -46,7 +48,8 @@ class DocsSearchBar {
hostUrl,
apiKey,
indexUid,
inputSelector,
inputSelector = '',
inputElement = null,
debug = false,
meilisearchOptions = {},
queryDataCallback = null,
Expand All @@ -64,6 +67,7 @@ class DocsSearchBar {
apiKey,
indexUid,
inputSelector,
inputElement,
debug,
meilisearchOptions,
queryDataCallback,
Expand All @@ -80,7 +84,9 @@ class DocsSearchBar {
this.apiKey = apiKey
this.hostUrl = hostUrl
this.indexUid = indexUid
this.input = DocsSearchBar.getInputFromSelector(inputSelector)
this.input = inputElement
? $(inputElement)
: DocsSearchBar.getInputFromSelector(inputSelector)
this.meilisearchOptions = {
limit: 5,
attributesToHighlight: ['*'],
Expand Down Expand Up @@ -121,7 +127,11 @@ class DocsSearchBar {
clientAgents: constructClientAgents(clientAgents),
})

DocsSearchBar.addThemeWrapper(inputSelector, this.enableDarkMode)
DocsSearchBar.addThemeWrapper(
inputElement,
inputSelector,
this.enableDarkMode,
)

if (enhancedSearchInput) {
this.input = DocsSearchBar.injectSearchBox(this.input)
Expand Down Expand Up @@ -176,17 +186,18 @@ class DocsSearchBar {
/**
* Wraps input selector in a docs-searchbar-js div
* @function addThemeWrapper
* @param {Element} inputElement Input Element
* @param {string} inputSelector Selector of the input element
* @param {boolean|'auto'} enableDarkMode Allows you to enforce, light theme, dark theme, or auto mode on the searchbar.
* @returns {void}
*/
static addThemeWrapper(inputSelector, enableDarkMode) {
const inputElement = document.querySelector(inputSelector)
const parent = inputElement.parentNode
static addThemeWrapper(inputElement, inputSelector, enableDarkMode) {
const input = inputElement || document.querySelector(inputSelector)
const parent = input.parentNode
const wrapper = document.createElement('div')
wrapper.className += 'docs-searchbar-js'
parent.replaceChild(wrapper, inputElement)
wrapper.appendChild(inputElement)
parent.replaceChild(wrapper, input)
wrapper.appendChild(input)

let isSystemInDarkMode = Boolean(enableDarkMode)
if (enableDarkMode === 'auto' && window.matchMedia) {
Expand Down Expand Up @@ -219,17 +230,24 @@ class DocsSearchBar {
* @returns {void}
*/
static checkArguments(args) {
if (!args.inputSelector || !args.indexUid || !args.hostUrl) {
if (
(!args.inputSelector && !args.inputElement) ||
!args.indexUid ||
!args.hostUrl
) {
throw new Error(usage)
}

if (typeof args.inputSelector !== 'string') {
if (args.inputSelector !== null && typeof args.inputSelector !== 'string') {
throw new Error(
`Error: inputSelector:${args.inputSelector} must be a string. Each selector must match only one element and separated by ','`,
)
}

if (!DocsSearchBar.getInputFromSelector(args.inputSelector)) {
if (
!args.inputElement &&
!DocsSearchBar.getInputFromSelector(args.inputSelector)
) {
throw new Error(
`Error: No input element in the page matches ${args.inputSelector}`,
)
Expand Down Expand Up @@ -342,7 +360,7 @@ class DocsSearchBar {
* @function getInputFromSelector
* @param {string} selector CSS selector that matches the search
* input of the page
* @returns {void}
* @returns {zepto.Z|null} Matching input or null
*/
static getInputFromSelector(selector) {
const input = $(selector).filter('input')
Expand Down
15 changes: 14 additions & 1 deletion src/lib/__tests__/DocsSearchBar-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,19 @@ describe('DocsSearchBar', () => {
}),
).toBe(true)
})

it('should accept the input element directly', () => {
const inputElement = document.getElementById('input')
const options = { ...defaultOptions, inputElement }
delete options.inputSelector

// When
const actual = new DocsSearchBar(options)

// Then
const $inputs = actual.input
expect($inputs[0]).toEqual(inputElement)
})
})

describe('checkArguments', () => {
Expand Down Expand Up @@ -291,7 +304,7 @@ describe('DocsSearchBar', () => {
checkArguments(options)
}).toThrow(/^Usage:/)
})
it('should throw an error if no inputSelector defined', () => {
it('should throw an error if no inputSelector or inputElement defined', () => {
// Given
const options = defaultOptions
delete options.inputSelector
Expand Down