Skip to content

Commit 2c81cc7

Browse files
committed
TypesenseMinibar class -> tsminibar function
== Size == | | Transfer size | Code size |--------|-----------------|---------------- | Before | 2,319 B | 6,787 B | After | 2,258 B (-2.6%) | 6,178 B (-8.9%)
1 parent e271cd6 commit 2c81cc7

File tree

6 files changed

+170
-167
lines changed

6 files changed

+170
-167
lines changed

.eslintrc.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@
99
"comma-dangle": "off"
1010
},
1111
"globals": {
12-
"TypesenseMinibar": "readonly"
12+
"tsminibar": "readonly"
1313
}
1414
}

CONTRIBUTING.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77
## API
88

99
```js
10-
new TypesenseMinibar(document.querySelector('#myform'))`
10+
tsminibar(document.querySelector('#myform'))`
1111
```
1212

13-
Class parameters:
13+
Function parameters:
1414

1515
* `{HTMLElement} form`: The element must have `data-origin`, `data-collection`, and `data-key`, attributes; and contain a descendent of `<input type="search">`.
16-
* `{Object} [options]`: Optional options:
17-
* `{boolean} [options.slash=true]`: Focus the input field if the `/` slash key is pressed outside any input or textarea element. When enabled, a `keydown` event listener is added to `document`.
16+
* `{Object} [options]`: (Optional)
17+
* `{boolean} [options.slash=true]`: Focus the input field if the `/` slash key is pressed outside any input or textarea element. When enabled, a `keydown` event listener is added to `document`. If multiple search forms are initiatilised on the same page, the first one bound with `slash=true` will "win".
1818

1919
## Development
2020

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646

4747
## Browser support
4848

49+
The below matrix describes support for the _enhanced_ JavaScript experience. The basic HTML experience, which falls back to submitting a form to DuckDuckGo, works in all known browsers (including IE 6, IE 5 for Mac, and Netscape Navigator).
50+
4951
| Browser | Policy | Version
5052
|--|--|--
5153
| Firefox | Current and previous version,<br>Current and previous ESR | Firefox 74+ (2020)

assets/gh-pages.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<link rel="stylesheet" href="./demo/demo.css">
88
<body>
99
<main>
10-
<p align="center"><a href="https://github.com/Krinkle/typesense-minibar/" title="Browse repository"><img src="/assets/logo-text.svg" height="100" alt="minibar"></a></p>
10+
<p align="center"><a href="https://github.com/Krinkle/typesense-minibar/" title="Browse repository"><img src="./assets/logo-text.svg" height="100" alt="minibar"></a></p>
1111
<p><strong>minibar</strong> is a fast 2kB autocomplete search bar. Alternative to Algolia DocSearch, InstantSearch, autocomplete-js, and typesense-js.</p>
1212
<h2>See also</h2>
1313
<ul>

test/test.js

+53-49
Original file line numberDiff line numberDiff line change
@@ -117,19 +117,18 @@ QUnit.module('typesense-minibar', hooks => {
117117
mockFetchResponse = null;
118118
});
119119

120-
let renderDone;
121-
async function expectRender (cb) {
120+
async function expectRender (targetElement, cb) {
121+
let renderDone;
122122
const promise = new Promise(resolve => { renderDone = resolve; });
123+
const observer = new MutationObserver(() => {
124+
renderDone();
125+
});
126+
observer.observe(targetElement, { attributes: true, childList: true, subtree: true });
123127
cb();
128+
await new Promise(resolve => setTimeout(resolve));
129+
observer.disconnect();
124130
return await promise;
125131
}
126-
hooks.before(() => {
127-
const renderSuper = TypesenseMinibar.prototype.render;
128-
TypesenseMinibar.prototype.render = function () {
129-
renderSuper.call(this);
130-
renderDone();
131-
};
132-
});
133132

134133
let bar;
135134
hooks.afterEach(() => {
@@ -141,15 +140,15 @@ QUnit.module('typesense-minibar', hooks => {
141140
document.head.querySelectorAll('link[rel=preconnect]').forEach(link => link.remove());
142141
});
143142

144-
QUnit.test('TypesenseMinibar constructor [fail without input element]', assert => {
143+
QUnit.test('init [fail without input element]', assert => {
145144
const form = parseHTML('<form>');
146145

147146
assert.throws(() => {
148-
bar = new TypesenseMinibar(form);
147+
bar = tsminibar(form);
149148
}, TypeError);
150149
});
151150

152-
QUnit.test.each('TypesenseMinibar input', {
151+
QUnit.test.each('input', {
153152
'no results': {
154153
value: 'something',
155154
resp: API_RESP_EMPTY,
@@ -183,96 +182,101 @@ QUnit.module('typesense-minibar', hooks => {
183182
}, async (assert, { value, resp, expect }) => {
184183
const form = parseHTML('<form><input type="search"></form>');
185184
const input = form.firstChild;
186-
const bar = new TypesenseMinibar(form);
185+
bar = tsminibar(form);
186+
const listbox = form.querySelector('[role=listbox]');
187187

188188
mockFetchResponse = resp;
189189
input.value = value;
190-
await expectRender(() => {
190+
await expectRender(form, () => {
191191
simulate(input, 'input');
192192
});
193193

194-
assert.equal(normalizeHTML(bar.listbox.innerHTML), normalizeHTML(expect), 'listbox HTML');
194+
assert.equal(normalizeHTML(listbox.innerHTML), normalizeHTML(expect), 'listbox HTML');
195195
});
196196

197-
QUnit.test('TypesenseMinibar input [memory cache hit]', async assert => {
197+
QUnit.test('input [memory cache hit]', async assert => {
198198
const form = parseHTML('<form><input type="search"></form>');
199199
const input = form.firstChild;
200-
const bar = new TypesenseMinibar(form);
200+
bar = tsminibar(form);
201+
const listbox = form.querySelector('[role=listbox]');
201202

202203
mockFetchResponse = API_RESP_FULL_MATCH_SOME;
203204
input.value = 'some';
204-
await expectRender(() => {
205+
await expectRender(form, () => {
205206
simulate(input, 'input');
206207
});
207-
assert.equal(bar.listbox.querySelector('.tsmb-suggestion_title').textContent, 'Some', 'result 1');
208+
assert.equal(listbox.querySelector('.tsmb-suggestion_title').textContent, 'Some', 'result 1');
208209

209210
mockFetchResponse = API_RESP_FULL_MATCH_SOMETHING;
210211
input.value = 'something';
211-
await expectRender(() => {
212+
await expectRender(form, () => {
212213
simulate(input, 'input');
213214
});
214-
assert.equal(bar.listbox.querySelector('.tsmb-suggestion_title').textContent, 'Some › Thing', 'result 2');
215+
assert.equal(listbox.querySelector('.tsmb-suggestion_title').textContent, 'Some › Thing', 'result 2');
215216

216217
// expect cache hit, no fetch
217218
mockFetchResponse = null;
218219
input.value = 'some';
219-
await expectRender(() => {
220+
await expectRender(form, () => {
220221
simulate(input, 'input');
221222
});
222-
assert.equal(bar.listbox.querySelector('.tsmb-suggestion_title').textContent, 'Some', 'result 3');
223+
assert.equal(listbox.querySelector('.tsmb-suggestion_title').textContent, 'Some', 'result 3');
223224
});
224225

225-
QUnit.test('TypesenseMinibar listbox [close on empty string or backspace]', async assert => {
226+
QUnit.test('listbox [close on empty string or backspace]', async assert => {
226227
const form = parseHTML('<form><input type="search"></form>');
227228
const input = form.firstChild;
228-
const bar = new TypesenseMinibar(form);
229+
bar = tsminibar(form);
230+
const listbox = form.querySelector('[role=listbox]');
229231

230232
mockFetchResponse = API_RESP_FULL_MATCH_SOMETHING;
231233
input.value = 'something';
232-
await expectRender(() => {
234+
await expectRender(form, () => {
233235
simulate(input, 'input');
234236
});
235-
assert.false(bar.listbox.hidden, 'listbox not hidden');
237+
assert.false(listbox.hidden, 'listbox not hidden');
236238

237239
mockFetchResponse = null; // expect no fetch request for empty query
238240
input.value = '';
239241
simulate(input, 'input');
240242

241-
assert.true(bar.listbox.hidden, 'listbox hidden');
243+
assert.true(listbox.hidden, 'listbox hidden');
242244
});
243245

244-
QUnit.test('TypesenseMinibar listbox [close on Esc]', async assert => {
246+
QUnit.test('listbox [close on Esc]', async assert => {
245247
const form = parseHTML('<form><input type="search"></form>');
246248
const input = form.firstChild;
247-
const bar = new TypesenseMinibar(form);
249+
bar = tsminibar(form);
250+
const listbox = form.querySelector('[role=listbox]');
248251

249252
mockFetchResponse = API_RESP_FULL_MATCH_SOMETHING;
250253
input.value = 'something';
251-
await expectRender(() => {
254+
await expectRender(form, () => {
252255
simulate(input, 'input');
253256
});
254-
assert.false(bar.listbox.hidden, 'listbox not hidden');
255-
assert.equal(bar.listbox.querySelector('mark').outerHTML, '<mark>something</mark>', 'snippet');
257+
assert.false(listbox.hidden, 'listbox not hidden');
258+
assert.equal(listbox.querySelector('mark').outerHTML, '<mark>something</mark>', 'snippet');
256259

257260
mockFetchResponse = null;
258261
simulate(input, 'keydown', { code: 'Escape' });
259262

260-
assert.true(bar.listbox.hidden, 'listbox hidden');
263+
assert.true(listbox.hidden, 'listbox hidden');
261264
});
262265

263-
QUnit.test('TypesenseMinibar listbox [arrow key cursor]', async assert => {
266+
QUnit.test('listbox [arrow key cursor]', async assert => {
264267
const form = parseHTML('<form><input type="search"></form>');
265268
const input = form.firstChild;
266-
const bar = new TypesenseMinibar(form);
269+
bar = tsminibar(form);
270+
const listbox = form.querySelector('[role=listbox]');
267271

268272
mockFetchResponse = API_RESP_MULTIPLE;
269273
input.value = 'tv';
270-
await expectRender(() => {
274+
await expectRender(form, () => {
271275
simulate(input, 'input');
272276
});
273-
assert.false(bar.listbox.hidden, 'listbox not hidden');
277+
assert.false(listbox.hidden, 'listbox not hidden');
274278
assert.equal(
275-
normalizeHTML(bar.listbox.outerHTML),
279+
normalizeHTML(listbox.outerHTML),
276280
normalizeHTML(`<div role="listbox">
277281
<div role="option"><a href="https://example.test/a" tabindex="-1"><div class="tsmb-suggestion_title">Person</div><div class="tsmb-suggestion_content"></div></a></div>
278282
<div role="option"><a href="https://example.test/b" tabindex="-1"><div class="tsmb-suggestion_title">Woman</div><div class="tsmb-suggestion_content"></div></a></div>
@@ -281,11 +285,11 @@ QUnit.module('typesense-minibar', hooks => {
281285
'initial result'
282286
);
283287

284-
await expectRender(() => {
288+
await expectRender(form, () => {
285289
simulate(input, 'keydown', { code: 'ArrowDown' }); // -1 to 0
286290
});
287291
assert.equal(
288-
normalizeHTML(bar.listbox.outerHTML),
292+
normalizeHTML(listbox.outerHTML),
289293
normalizeHTML(`<div role="listbox">
290294
<div role="option" aria-selected="true"><a href="https://example.test/a" tabindex="-1"><div class="tsmb-suggestion_title">Person</div><div class="tsmb-suggestion_content"></div></a></div>
291295
<div role="option"><a href="https://example.test/b" tabindex="-1"><div class="tsmb-suggestion_title">Woman</div><div class="tsmb-suggestion_content"></div></a></div>
@@ -296,11 +300,11 @@ QUnit.module('typesense-minibar', hooks => {
296300

297301
simulate(input, 'keydown', { code: 'ArrowDown' }); // 0 to 1
298302
simulate(input, 'keydown', { code: 'ArrowDown' }); // 1 to 2
299-
await expectRender(() => {
303+
await expectRender(form, () => {
300304
simulate(input, 'keydown', { code: 'ArrowDown' }); // 2 to -1
301305
});
302306
assert.equal(
303-
normalizeHTML(bar.listbox.outerHTML),
307+
normalizeHTML(listbox.outerHTML),
304308
normalizeHTML(`<div role="listbox">
305309
<div role="option"><a href="https://example.test/a" tabindex="-1"><div class="tsmb-suggestion_title">Person</div><div class="tsmb-suggestion_content"></div></a></div>
306310
<div role="option"><a href="https://example.test/b" tabindex="-1"><div class="tsmb-suggestion_title">Woman</div><div class="tsmb-suggestion_content"></div></a></div>
@@ -310,11 +314,11 @@ QUnit.module('typesense-minibar', hooks => {
310314
);
311315

312316
simulate(input, 'keydown', { code: 'ArrowUp' }); // -1 to 2 (wrap around)
313-
await expectRender(() => {
317+
await expectRender(form, () => {
314318
simulate(input, 'keydown', { code: 'ArrowUp' }); // 2 to 1
315319
});
316320
assert.equal(
317-
normalizeHTML(bar.listbox.outerHTML),
321+
normalizeHTML(listbox.outerHTML),
318322
normalizeHTML(`<div role="listbox">
319323
<div role="option"><a href="https://example.test/a" tabindex="-1"><div class="tsmb-suggestion_title">Person</div><div class="tsmb-suggestion_content"></div></a></div>
320324
<div role="option" aria-selected="true"><a href="https://example.test/b" tabindex="-1"><div class="tsmb-suggestion_title">Woman</div><div class="tsmb-suggestion_content"></div></a></div>
@@ -324,24 +328,24 @@ QUnit.module('typesense-minibar', hooks => {
324328
);
325329
});
326330

327-
QUnit.test('TypesenseMinibar focus [slash]', async assert => {
331+
QUnit.test('focus [slash]', async assert => {
328332
const form = parseHTML('<form><input type="search"></form>');
329333
const input = form.firstChild;
330334
document.body.append(form);
331335
assert.true(!document.activeElement || !form.contains(document.activeElement), 'initial focus');
332336

333-
bar = new TypesenseMinibar(form);
337+
bar = tsminibar(form);
334338
assert.true(!document.activeElement || !form.contains(document.activeElement), 'focus after contruct');
335339

336340
simulate(document, 'keydown', { key: '/' });
337341
assert.strictEqual(document.activeElement, input, 'focus after slash');
338342
});
339343

340-
QUnit.test('TypesenseMinibar focus [preconnect]', async assert => {
344+
QUnit.test('focus [preconnect]', async assert => {
341345
const form = parseHTML('<form><input type="search"></form>');
342346
const input = form.firstChild;
343347
document.body.append(form);
344-
bar = new TypesenseMinibar(form);
348+
bar = tsminibar(form);
345349

346350
assert.strictEqual(document.head.querySelectorAll('link[rel=preconnect]').length, 0, 'initial preconnect');
347351

0 commit comments

Comments
 (0)