Skip to content

Commit 3c969ef

Browse files
committed
Add Autocomplete method buildingListMode parameter
Update JS library version
1 parent 98b85a5 commit 3c969ef

File tree

5 files changed

+93
-58
lines changed

5 files changed

+93
-58
lines changed

example/assets/AutocompleteAddress.js

Lines changed: 81 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* https://www.tldrlegal.com/license/apple-mit-license-aml
99
*
1010
* @author Postcode.nl
11-
* @version 1.4.0
11+
* @version 1.4.1
1212
*/
1313

1414
(function (global, factory) {
@@ -31,7 +31,7 @@
3131
const document = window.document,
3232
$ = function (selector) { return document.querySelectorAll(selector); },
3333
elementData = new WeakMap(),
34-
VERSION = '1.4.0',
34+
VERSION = '1.4.1',
3535
EVENT_NAMESPACE = 'autocomplete-',
3636
PRECISION_ADDRESS = 'Address',
3737
KEY_ESC = 'Escape',
@@ -42,6 +42,7 @@
4242
KEY_UP_LEGACY = 'Up',
4343
KEY_DOWN = 'ArrowDown',
4444
KEY_DOWN_LEGACY = 'Down',
45+
BUILDING_LIST_MODES = { PAGED: 'paged', SHORT: 'short' },
4546

4647
/**
4748
* Default options.
@@ -185,6 +186,27 @@
185186
writable: true,
186187
},
187188

189+
/**
190+
* Set mode for listing buildings in `Street` context. Supported modes:
191+
*
192+
* - 'paged': get a larger list of building results (actual number determined by API). Includes link to view more buildings.
193+
* - 'short': building results are limited to the first few items, similar to matches in other contexts.
194+
*/
195+
buildingListMode: {
196+
set (mode) {
197+
if (Object.values(BUILDING_LIST_MODES).includes(mode))
198+
{
199+
this.mode = mode;
200+
}
201+
else
202+
{
203+
console.error('Invalid mode for option buildingListMode:', mode);
204+
}
205+
},
206+
get () {
207+
return this.mode || BUILDING_LIST_MODES.SHORT;
208+
},
209+
},
188210
});
189211

190212
/**
@@ -235,8 +257,6 @@
235257
return;
236258
}
237259

238-
removeItemFocus();
239-
240260
setValue = setValue || false;
241261
isRelative = isRelative || false;
242262

@@ -265,24 +285,13 @@
265285
&& (index > 0 && toIndex < fromIndex || index < 0 && toIndex > fromIndex) // Wrapping
266286
)
267287
{
268-
item = null;
288+
setActiveItem(null);
269289
inputElement.value = inputValue;
270290
elementData.get(inputElement).context = inputContext;
271291
return;
272292
}
273293

274-
item = ul.children[toIndex];
275-
item.classList.add(classNames.itemFocus);
276-
277-
// Scroll the menu item into view if needed.
278-
if (ul.scrollTop > item.offsetTop)
279-
{
280-
ul.scrollTop = item.offsetTop;
281-
}
282-
else if ((item.offsetHeight + item.offsetTop) > ul.clientHeight)
283-
{
284-
ul.scrollTop = (item.offsetHeight + item.offsetTop) - ul.clientHeight;
285-
}
294+
setActiveItem(ul.children[toIndex]);
286295

287296
const data = elementData.get(item);
288297

@@ -297,6 +306,16 @@
297306
inputElement.value = data.value;
298307
elementData.get(inputElement).context = data.context;
299308
selectedIndex = toIndex;
309+
310+
// Scroll the menu item into view if needed.
311+
if (ul.scrollTop > item.offsetTop)
312+
{
313+
ul.scrollTop = item.offsetTop;
314+
}
315+
else if (item.offsetTop >= (ul.clientHeight + ul.scrollTop))
316+
{
317+
ul.scrollTop = (item.offsetHeight + item.offsetTop) - ul.clientHeight;
318+
}
300319
}
301320
},
302321

@@ -308,6 +327,20 @@
308327
return Array.prototype.indexOf.call(ul.children, element);
309328
},
310329

330+
/**
331+
* Set and focus active item. Removes focus from previous item.
332+
*/
333+
setActiveItem = function (newItem)
334+
{
335+
removeItemFocus();
336+
337+
item = newItem;
338+
if (item)
339+
{
340+
item.classList.add(classNames.itemFocus);
341+
}
342+
},
343+
311344
/**
312345
* Remove the item focus CSS class from the active item, if any.
313346
*/
@@ -391,26 +424,15 @@
391424
return;
392425
}
393426

394-
removeItemFocus();
395-
396427
let target = e.target;
397428

398429
while (target.parentElement !== ul)
399430
{
400431
target = target.parentElement;
401432
}
402433

403-
item = target;
404-
item.classList.add(classNames.itemFocus);
405-
});
406-
407-
ul.addEventListener('mouseout', function () {
408-
self.blur();
409-
410-
if (selectedIndex !== null)
411-
{
412-
moveItemFocus(selectedIndex);
413-
}
434+
setActiveItem(target);
435+
moveItemFocus(indexOf(target));
414436
});
415437

416438
wrapper.addEventListener('mousedown', function () {
@@ -448,16 +470,16 @@
448470
this.setItems = function (matches, renderItem)
449471
{
450472
ul.innerHTML = '';
451-
ul.scrollTop = 0;
452473

453474
for (let i = 0, li, match; (match = matches[i++]);)
454475
{
455476
li = renderItem(ul, match);
456477
elementData.set(li, match);
457478
}
458479

459-
item = null;
480+
setActiveItem(null);
460481
selectedIndex = null;
482+
ul.scrollTop = 0;
461483
}
462484

463485
/**
@@ -533,8 +555,7 @@
533555
*/
534556
this.blur = function ()
535557
{
536-
removeItemFocus();
537-
item = null;
558+
setActiveItem(null);
538559
}
539560

540561
/**
@@ -572,8 +593,7 @@
572593
*/
573594
this.clear = function ()
574595
{
575-
removeItemFocus();
576-
item = null;
596+
setActiveItem(null);
577597
selectedIndex = null;
578598
ul.innerHTML = '';
579599
}
@@ -878,14 +898,23 @@
878898
*/
879899
this.getSuggestions = function (context, term, response)
880900
{
881-
let url = this.options.autocompleteUrl + '/' + encodeURIComponent(context) + '/' + encodeURIComponent(term);
882-
883-
if (typeof options.language !== 'undefined')
901+
const url = [
902+
this.options.autocompleteUrl,
903+
encodeURIComponent(context),
904+
encodeURIComponent(term),
905+
options.language || '',
906+
];
907+
908+
if (options.buildingListMode !== BUILDING_LIST_MODES.SHORT)
884909
{
885-
url += '/' + options.language;
910+
// Only specify when not the API default, for better compatibility with client proxies
911+
url.push(options.buildingListMode);
886912
}
887913

888-
return this.xhrGet(url, response);
914+
return this.xhrGet(
915+
url.join('/').replace(/\/+$/, ''),
916+
response
917+
);
889918
}
890919

891920
/**
@@ -961,12 +990,12 @@
961990
}
962991

963992
/**
964-
* Highlight matched portions in the item label.
965-
*
966-
* @param {string} str - Item label to highlight.
967-
* @param {Array.Array.<number>} indices - Array of character offset pairs.
968-
* @return {string} Highlighted string (using "mark" elements).
969-
*/
993+
* Highlight matched portions in the item label.
994+
*
995+
* @param {string} str - Item label to highlight.
996+
* @param {Array.Array.<number>} indices - Array of character offset pairs.
997+
* @return {string} Highlighted string (using "mark" elements).
998+
*/
970999
this.highlight = function (str, indices)
9711000
{
9721001
if (indices.length === 0)
@@ -1173,7 +1202,7 @@
11731202
}
11741203

11751204
e.preventDefault();
1176-
break;
1205+
break;
11771206

11781207
case KEY_DOWN:
11791208
case KEY_DOWN_LEGACY:
@@ -1187,20 +1216,20 @@
11871216
}
11881217

11891218
e.preventDefault();
1190-
break;
1219+
break;
11911220

11921221
case KEY_ESC:
11931222
case KEY_ESC_LEGACY:
11941223
menu.close(true);
1195-
break;
1224+
break;
11961225

11971226
case KEY_TAB:
11981227
if (menu.hasFocus)
11991228
{
12001229
menu.select();
12011230
e.preventDefault();
12021231
}
1203-
break;
1232+
break;
12041233

12051234
case KEY_ENTER:
12061235
if (menu.hasFocus)
@@ -1212,7 +1241,7 @@
12121241
{
12131242
menu.close();
12141243
}
1215-
break;
1244+
break;
12161245

12171246
default:
12181247
searchDebounced(element);

0 commit comments

Comments
 (0)