Skip to content

Commit

Permalink
Merge pull request #387 from mauromascarenhas/autocomplete-function
Browse files Browse the repository at this point in the history
Replacement for standard search function in autocomplete
  • Loading branch information
wuda-io authored Jun 22, 2023
2 parents 807d65b + 0752834 commit 3dcfae8
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 22 deletions.
53 changes: 42 additions & 11 deletions pug/contents/autocomplete_content.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,38 @@

<div id="initialization" class="scrollspy section">
<h3 class="header">Initialization</h3>
<p>The data is a json object where the key is the matching string and the value is an optional image url.</p>
<p>The key must be a text string. If you trust your data, or have properly sanitized your user input, you may
use HTML by setting the option <code class="language-javascript">allowUnsafeHTML: true</code>.</p>
<p>The data is an array of option objects, which supports three different attributes:</p>
<p>
<ul class="collection">
<li class="collection-item">
<p style="margin: 0;">
<b>id</b>: This is the only mandatory attribute: it must be a primitive value that can be
converted to string. If "text" is not provided, it will also be used as "option text" as well;
</p>
</li>
<li class="collection-item">
<p style="margin: 0;">
<b>text</b>: This optional attribute is used as "display value" for the current entry.
When provided, it will also be taken into consideration by the standard search function.
</p>
<P style="margin: 0;">
If you trust your data or have properly sanitized your user input, you may use
use HTML by setting the option <code class="language-javascript">allowUnsafeHTML: true</code>;
</P>
</li>
<li class="collection-item">
<p style="margin: 0;">
<b>image</b>: This optional attribute is used to provide a valid image URL to the current option.
This attribute is ignored by the standard search function.
</p>
</li>
</ul>
</p>
<p>
You may also provide additional attributes to an option object but they will not be taken into
consideration by the standard search function. If you want to use them for option filtering, you
must specify a custom function in "<b>onSearch</b>" option.
</p>
<pre style="padding-top: 0px;">
<span class="copyMessage">Copied!</span>
<i class="material-icons copyButton">content_copy</i>
Expand Down Expand Up @@ -99,7 +128,8 @@ <h3 class="header">Initialization</h3>
{id: 13, text: "Microsoft"},
{id: 42, text: "Google", image: 'http://placehold.it/250x250'}
],
onSearch: function(text, autocomplete) {
// This search function considers every object entry as "search values".
onSearch: (text, autocomplete) => {
const filteredData = autocomplete.options.data.filter(item => {
return Object.keys(item)
.map(key => item[key].toString().toLowerCase().indexOf(text.toLowerCase()) >= 0)
Expand Down Expand Up @@ -188,13 +218,14 @@ <h5 class="method-header">
<span class="copyMessage">Copied!</span>
<i class="material-icons copyButton">content_copy</i>
<code class="language-javascript copiedText">
onSearch: function(text, autocomplete) {
const filteredData = autocomplete.options.data.filter(item => {
return Object.keys(item)
.map(key => item[key].toString().toLowerCase().indexOf(text.toLowerCase()) >= 0)
.some(isMatch => isMatch);
});
autocomplete.setMenuItems(filteredData);
onSearch: (text, autocomplete) => {
const normSearch = text.toLocaleLowerCase();
autocomplete.setMenuItems(
autocomplete.options.data.filter((option) =>
option.id.toString().toLocaleLowerCase().includes(normSearch)
|| option.text?.toLocaleLowerCase().includes(normSearch)
)
);
}
</code>
</pre>
Expand Down
23 changes: 12 additions & 11 deletions src/autocomplete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ let _defaults = {
},
minLength: 1, // Min characters before autocomplete starts
isMultiSelect: false,
onSearch: function(text, autocomplete) {
const filteredData = autocomplete.options.data.filter(item => {
return Object.keys(item)
.map(key => item[key].toString().toLowerCase().indexOf(text.toLowerCase()) >= 0)
.some(isMatch => isMatch);
});
autocomplete.setMenuItems(filteredData);
onSearch: (text: string, autocomplete) => {
const normSearch = text.toLocaleLowerCase();
autocomplete.setMenuItems(
autocomplete.options.data.filter((option) =>
option.id.toString().toLocaleLowerCase().includes(normSearch)
|| option.text?.toLocaleLowerCase().includes(normSearch)
)
);
},
maxDropDownHeight: '300px',
allowUnsafeHTML: false
Expand Down Expand Up @@ -175,7 +176,7 @@ export class Autocomplete extends Component {
_handleInputKeyupAndFocus = (e: KeyboardEvent) => {
if (e.type === 'keyup') Autocomplete._keydown = false;
this.count = 0;
const actualValue = this.el.value.toLowerCase();
const actualValue = this.el.value.toLocaleLowerCase();
// Don't capture enter or arrow key usage.
if (M.keys.ENTER.includes(e.key) || M.keys.ARROW_UP.includes(e.key) || M.keys.ARROW_DOWN.includes(e.key)) return;
// Check if the input isn't empty
Expand Down Expand Up @@ -254,7 +255,7 @@ export class Autocomplete extends Component {
}

_highlightPartialText(input, label) {
const start = label.toLowerCase().indexOf('' + input.toLowerCase() + '');
const start = label.toLocaleLowerCase().indexOf('' + input.toLocaleLowerCase() + '');
const end = start + input.length - 1;
//custom filters may return results where the string does not match any part
if (start == -1 || end == -1) {
Expand Down Expand Up @@ -288,7 +289,7 @@ export class Autocomplete extends Component {
}

// Text
const inputText = this.el.value.toLowerCase();
const inputText = this.el.value.toLocaleLowerCase();
const parts = this._highlightPartialText(inputText, (entry.text || entry.id).toString());
const div = document.createElement('div');
div.setAttribute('style', 'line-height:1.2;font-weight:500;');
Expand Down Expand Up @@ -378,7 +379,7 @@ export class Autocomplete extends Component {
}

open() {
const inputText = this.el.value.toLowerCase();
const inputText = this.el.value.toLocaleLowerCase();
this._resetAutocomplete();
if (inputText.length >= this.options.minLength) {
this.isOpen = true;
Expand Down

0 comments on commit 3dcfae8

Please sign in to comment.